2 * TI da8xx master peripheral priority driver
4 * Copyright (C) 2016 BayLibre SAS
7 * Bartosz Golaszewski <bgolaszewski@baylibre.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/module.h>
16 #include <linux/platform_device.h>
18 #include <linux/regmap.h>
21 * REVISIT: Linux doesn't have a good framework for the kind of performance
22 * knobs this driver controls. We can't use device tree properties as it deals
23 * with hardware configuration rather than description. We also don't want to
24 * commit to maintaining some random sysfs attributes.
26 * For now we just hardcode the register values for the boards that need
27 * some changes (as is the case for the LCD controller on da850-lcdk - the
28 * first board we support here). When linux gets an appropriate framework,
29 * we'll easily convert the driver to it.
32 #define DA8XX_MSTPRI0_OFFSET 0
33 #define DA8XX_MSTPRI1_OFFSET 4
34 #define DA8XX_MSTPRI2_OFFSET 8
37 DA8XX_MSTPRI_ARM_I
= 0,
43 DA8XX_MSTPRI_EDMA30TC0
,
44 DA8XX_MSTPRI_EDMA30TC1
,
45 DA8XX_MSTPRI_EDMA31TC0
,
46 DA8XX_MSTPRI_VPIF_DMA_0
,
47 DA8XX_MSTPRI_VPIF_DMA_1
,
50 DA8XX_MSTPRI_USB0CDMA
,
56 struct da8xx_mstpri_descr
{
62 static const struct da8xx_mstpri_descr da8xx_mstpri_priority_list
[] = {
63 [DA8XX_MSTPRI_ARM_I
] = {
64 .reg
= DA8XX_MSTPRI0_OFFSET
,
68 [DA8XX_MSTPRI_ARM_D
] = {
69 .reg
= DA8XX_MSTPRI0_OFFSET
,
73 [DA8XX_MSTPRI_UPP
] = {
74 .reg
= DA8XX_MSTPRI0_OFFSET
,
78 [DA8XX_MSTPRI_SATA
] = {
79 .reg
= DA8XX_MSTPRI0_OFFSET
,
83 [DA8XX_MSTPRI_PRU0
] = {
84 .reg
= DA8XX_MSTPRI1_OFFSET
,
88 [DA8XX_MSTPRI_PRU1
] = {
89 .reg
= DA8XX_MSTPRI1_OFFSET
,
93 [DA8XX_MSTPRI_EDMA30TC0
] = {
94 .reg
= DA8XX_MSTPRI1_OFFSET
,
98 [DA8XX_MSTPRI_EDMA30TC1
] = {
99 .reg
= DA8XX_MSTPRI1_OFFSET
,
103 [DA8XX_MSTPRI_EDMA31TC0
] = {
104 .reg
= DA8XX_MSTPRI1_OFFSET
,
108 [DA8XX_MSTPRI_VPIF_DMA_0
] = {
109 .reg
= DA8XX_MSTPRI1_OFFSET
,
113 [DA8XX_MSTPRI_VPIF_DMA_1
] = {
114 .reg
= DA8XX_MSTPRI1_OFFSET
,
118 [DA8XX_MSTPRI_EMAC
] = {
119 .reg
= DA8XX_MSTPRI2_OFFSET
,
123 [DA8XX_MSTPRI_USB0CFG
] = {
124 .reg
= DA8XX_MSTPRI2_OFFSET
,
128 [DA8XX_MSTPRI_USB0CDMA
] = {
129 .reg
= DA8XX_MSTPRI2_OFFSET
,
133 [DA8XX_MSTPRI_UHPI
] = {
134 .reg
= DA8XX_MSTPRI2_OFFSET
,
138 [DA8XX_MSTPRI_USB1
] = {
139 .reg
= DA8XX_MSTPRI2_OFFSET
,
143 [DA8XX_MSTPRI_LCDC
] = {
144 .reg
= DA8XX_MSTPRI2_OFFSET
,
150 struct da8xx_mstpri_priority
{
155 struct da8xx_mstpri_board_priorities
{
157 const struct da8xx_mstpri_priority
*priorities
;
162 * Default memory settings of da850 do not meet the throughput/latency
163 * requirements of tilcdc. This results in the image displayed being
164 * incorrect and the following warning being displayed by the LCDC
167 * tilcdc da8xx_lcdc.0: tilcdc_crtc_irq(0x00000020): FIFO underfow
169 static const struct da8xx_mstpri_priority da850_lcdk_priorities
[] = {
171 .which
= DA8XX_MSTPRI_LCDC
,
175 .which
= DA8XX_MSTPRI_EDMA30TC1
,
179 .which
= DA8XX_MSTPRI_EDMA30TC0
,
184 static const struct da8xx_mstpri_board_priorities da8xx_mstpri_board_confs
[] = {
186 .board
= "ti,da850-lcdk",
187 .priorities
= da850_lcdk_priorities
,
188 .numprio
= ARRAY_SIZE(da850_lcdk_priorities
),
192 static const struct da8xx_mstpri_board_priorities
*
193 da8xx_mstpri_get_board_prio(void)
195 const struct da8xx_mstpri_board_priorities
*board_prio
;
198 for (i
= 0; i
< ARRAY_SIZE(da8xx_mstpri_board_confs
); i
++) {
199 board_prio
= &da8xx_mstpri_board_confs
[i
];
201 if (of_machine_is_compatible(board_prio
->board
))
208 static int da8xx_mstpri_probe(struct platform_device
*pdev
)
210 const struct da8xx_mstpri_board_priorities
*prio_list
;
211 const struct da8xx_mstpri_descr
*prio_descr
;
212 const struct da8xx_mstpri_priority
*prio
;
213 struct device
*dev
= &pdev
->dev
;
214 struct resource
*res
;
215 void __iomem
*mstpri
;
219 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
220 mstpri
= devm_ioremap_resource(dev
, res
);
221 if (IS_ERR(mstpri
)) {
222 dev_err(dev
, "unable to map MSTPRI registers\n");
223 return PTR_ERR(mstpri
);
226 prio_list
= da8xx_mstpri_get_board_prio();
228 dev_err(dev
, "no master priorities defined for this board\n");
232 for (i
= 0; i
< prio_list
->numprio
; i
++) {
233 prio
= &prio_list
->priorities
[i
];
234 prio_descr
= &da8xx_mstpri_priority_list
[prio
->which
];
236 if (prio_descr
->reg
+ sizeof(u32
) > resource_size(res
)) {
237 dev_warn(dev
, "register offset out of range\n");
241 reg
= readl(mstpri
+ prio_descr
->reg
);
242 reg
&= ~prio_descr
->mask
;
243 reg
|= prio
->val
<< prio_descr
->shift
;
245 writel(reg
, mstpri
+ prio_descr
->reg
);
251 static const struct of_device_id da8xx_mstpri_of_match
[] = {
252 { .compatible
= "ti,da850-mstpri", },
256 static struct platform_driver da8xx_mstpri_driver
= {
257 .probe
= da8xx_mstpri_probe
,
259 .name
= "da8xx-mstpri",
260 .of_match_table
= da8xx_mstpri_of_match
,
263 module_platform_driver(da8xx_mstpri_driver
);
265 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
266 MODULE_DESCRIPTION("TI da8xx master peripheral priority driver");
267 MODULE_LICENSE("GPL v2");