diff options
-rw-r--r-- | Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt | 20 | ||||
-rw-r--r-- | drivers/bus/Kconfig | 9 | ||||
-rw-r--r-- | drivers/bus/Makefile | 2 | ||||
-rw-r--r-- | drivers/bus/da8xx-mstpri.c | 269 |
4 files changed, 300 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt b/Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt new file mode 100644 index 000000000000..72daefc6b4a1 --- /dev/null +++ b/Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt | |||
@@ -0,0 +1,20 @@ | |||
1 | * Device tree bindings for Texas Instruments da8xx master peripheral | ||
2 | priority driver | ||
3 | |||
4 | DA8XX SoCs feature a set of registers allowing to change the priority of all | ||
5 | peripherals classified as masters. | ||
6 | |||
7 | Documentation: | ||
8 | OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf | ||
9 | |||
10 | Required properties: | ||
11 | |||
12 | - compatible: "ti,da850-mstpri" - for da850 based boards | ||
13 | - reg: offset and length of the mstpri registers | ||
14 | |||
15 | Example for da850-lcdk is shown below. | ||
16 | |||
17 | mstpri { | ||
18 | compatible = "ti,da850-mstpri"; | ||
19 | reg = <0x14110 0x0c>; | ||
20 | }; | ||
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 7010dcac9328..ed6a89c06481 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig | |||
@@ -166,4 +166,13 @@ config VEXPRESS_CONFIG | |||
166 | help | 166 | help |
167 | Platform configuration infrastructure for the ARM Ltd. | 167 | Platform configuration infrastructure for the ARM Ltd. |
168 | Versatile Express. | 168 | Versatile Express. |
169 | |||
170 | config DA8XX_MSTPRI | ||
171 | bool "TI da8xx master peripheral priority driver" | ||
172 | depends on ARCH_DAVINCI_DA8XX | ||
173 | help | ||
174 | Driver for Texas Instruments da8xx master peripheral priority | ||
175 | configuration. Allows to adjust the priorities of all master | ||
176 | peripherals. | ||
177 | |||
169 | endmenu | 178 | endmenu |
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c6cfa6b2606e..2adb5401ff0a 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile | |||
@@ -21,3 +21,5 @@ obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o | |||
21 | obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o | 21 | obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o |
22 | obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o | 22 | obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o |
23 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o | 23 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o |
24 | |||
25 | obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o | ||
diff --git a/drivers/bus/da8xx-mstpri.c b/drivers/bus/da8xx-mstpri.c new file mode 100644 index 000000000000..85f0b533f8e4 --- /dev/null +++ b/drivers/bus/da8xx-mstpri.c | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * TI da8xx master peripheral priority driver | ||
3 | * | ||
4 | * Copyright (C) 2016 BayLibre SAS | ||
5 | * | ||
6 | * Author: | ||
7 | * Bartosz Golaszewski <bgolaszewski@baylibre.com.com> | ||
8 | * | ||
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. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/of_fdt.h> | ||
20 | |||
21 | /* | ||
22 | * REVISIT: Linux doesn't have a good framework for the kind of performance | ||
23 | * knobs this driver controls. We can't use device tree properties as it deals | ||
24 | * with hardware configuration rather than description. We also don't want to | ||
25 | * commit to maintaining some random sysfs attributes. | ||
26 | * | ||
27 | * For now we just hardcode the register values for the boards that need | ||
28 | * some changes (as is the case for the LCD controller on da850-lcdk - the | ||
29 | * first board we support here). When linux gets an appropriate framework, | ||
30 | * we'll easily convert the driver to it. | ||
31 | */ | ||
32 | |||
33 | #define DA8XX_MSTPRI0_OFFSET 0 | ||
34 | #define DA8XX_MSTPRI1_OFFSET 4 | ||
35 | #define DA8XX_MSTPRI2_OFFSET 8 | ||
36 | |||
37 | enum { | ||
38 | DA8XX_MSTPRI_ARM_I = 0, | ||
39 | DA8XX_MSTPRI_ARM_D, | ||
40 | DA8XX_MSTPRI_UPP, | ||
41 | DA8XX_MSTPRI_SATA, | ||
42 | DA8XX_MSTPRI_PRU0, | ||
43 | DA8XX_MSTPRI_PRU1, | ||
44 | DA8XX_MSTPRI_EDMA30TC0, | ||
45 | DA8XX_MSTPRI_EDMA30TC1, | ||
46 | DA8XX_MSTPRI_EDMA31TC0, | ||
47 | DA8XX_MSTPRI_VPIF_DMA_0, | ||
48 | DA8XX_MSTPRI_VPIF_DMA_1, | ||
49 | DA8XX_MSTPRI_EMAC, | ||
50 | DA8XX_MSTPRI_USB0CFG, | ||
51 | DA8XX_MSTPRI_USB0CDMA, | ||
52 | DA8XX_MSTPRI_UHPI, | ||
53 | DA8XX_MSTPRI_USB1, | ||
54 | DA8XX_MSTPRI_LCDC, | ||
55 | }; | ||
56 | |||
57 | struct da8xx_mstpri_descr { | ||
58 | int reg; | ||
59 | int shift; | ||
60 | int mask; | ||
61 | }; | ||
62 | |||
63 | static const struct da8xx_mstpri_descr da8xx_mstpri_priority_list[] = { | ||
64 | [DA8XX_MSTPRI_ARM_I] = { | ||
65 | .reg = DA8XX_MSTPRI0_OFFSET, | ||
66 | .shift = 0, | ||
67 | .mask = 0x0000000f, | ||
68 | }, | ||
69 | [DA8XX_MSTPRI_ARM_D] = { | ||
70 | .reg = DA8XX_MSTPRI0_OFFSET, | ||
71 | .shift = 4, | ||
72 | .mask = 0x000000f0, | ||
73 | }, | ||
74 | [DA8XX_MSTPRI_UPP] = { | ||
75 | .reg = DA8XX_MSTPRI0_OFFSET, | ||
76 | .shift = 16, | ||
77 | .mask = 0x000f0000, | ||
78 | }, | ||
79 | [DA8XX_MSTPRI_SATA] = { | ||
80 | .reg = DA8XX_MSTPRI0_OFFSET, | ||
81 | .shift = 20, | ||
82 | .mask = 0x00f00000, | ||
83 | }, | ||
84 | [DA8XX_MSTPRI_PRU0] = { | ||
85 | .reg = DA8XX_MSTPRI1_OFFSET, | ||
86 | .shift = 0, | ||
87 | .mask = 0x0000000f, | ||
88 | }, | ||
89 | [DA8XX_MSTPRI_PRU1] = { | ||
90 | .reg = DA8XX_MSTPRI1_OFFSET, | ||
91 | .shift = 4, | ||
92 | .mask = 0x000000f0, | ||
93 | }, | ||
94 | [DA8XX_MSTPRI_EDMA30TC0] = { | ||
95 | .reg = DA8XX_MSTPRI1_OFFSET, | ||
96 | .shift = 8, | ||
97 | .mask = 0x00000f00, | ||
98 | }, | ||
99 | [DA8XX_MSTPRI_EDMA30TC1] = { | ||
100 | .reg = DA8XX_MSTPRI1_OFFSET, | ||
101 | .shift = 12, | ||
102 | .mask = 0x0000f000, | ||
103 | }, | ||
104 | [DA8XX_MSTPRI_EDMA31TC0] = { | ||
105 | .reg = DA8XX_MSTPRI1_OFFSET, | ||
106 | .shift = 16, | ||
107 | .mask = 0x000f0000, | ||
108 | }, | ||
109 | [DA8XX_MSTPRI_VPIF_DMA_0] = { | ||
110 | .reg = DA8XX_MSTPRI1_OFFSET, | ||
111 | .shift = 24, | ||
112 | .mask = 0x0f000000, | ||
113 | }, | ||
114 | [DA8XX_MSTPRI_VPIF_DMA_1] = { | ||
115 | .reg = DA8XX_MSTPRI1_OFFSET, | ||
116 | .shift = 28, | ||
117 | .mask = 0xf0000000, | ||
118 | }, | ||
119 | [DA8XX_MSTPRI_EMAC] = { | ||
120 | .reg = DA8XX_MSTPRI2_OFFSET, | ||
121 | .shift = 0, | ||
122 | .mask = 0x0000000f, | ||
123 | }, | ||
124 | [DA8XX_MSTPRI_USB0CFG] = { | ||
125 | .reg = DA8XX_MSTPRI2_OFFSET, | ||
126 | .shift = 8, | ||
127 | .mask = 0x00000f00, | ||
128 | }, | ||
129 | [DA8XX_MSTPRI_USB0CDMA] = { | ||
130 | .reg = DA8XX_MSTPRI2_OFFSET, | ||
131 | .shift = 12, | ||
132 | .mask = 0x0000f000, | ||
133 | }, | ||
134 | [DA8XX_MSTPRI_UHPI] = { | ||
135 | .reg = DA8XX_MSTPRI2_OFFSET, | ||
136 | .shift = 20, | ||
137 | .mask = 0x00f00000, | ||
138 | }, | ||
139 | [DA8XX_MSTPRI_USB1] = { | ||
140 | .reg = DA8XX_MSTPRI2_OFFSET, | ||
141 | .shift = 24, | ||
142 | .mask = 0x0f000000, | ||
143 | }, | ||
144 | [DA8XX_MSTPRI_LCDC] = { | ||
145 | .reg = DA8XX_MSTPRI2_OFFSET, | ||
146 | .shift = 28, | ||
147 | .mask = 0xf0000000, | ||
148 | }, | ||
149 | }; | ||
150 | |||
151 | struct da8xx_mstpri_priority { | ||
152 | int which; | ||
153 | u32 val; | ||
154 | }; | ||
155 | |||
156 | struct da8xx_mstpri_board_priorities { | ||
157 | const char *board; | ||
158 | const struct da8xx_mstpri_priority *priorities; | ||
159 | size_t numprio; | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * Default memory settings of da850 do not meet the throughput/latency | ||
164 | * requirements of tilcdc. This results in the image displayed being | ||
165 | * incorrect and the following warning being displayed by the LCDC | ||
166 | * drm driver: | ||
167 | * | ||
168 | * tilcdc da8xx_lcdc.0: tilcdc_crtc_irq(0x00000020): FIFO underfow | ||
169 | */ | ||
170 | static const struct da8xx_mstpri_priority da850_lcdk_priorities[] = { | ||
171 | { | ||
172 | .which = DA8XX_MSTPRI_LCDC, | ||
173 | .val = 0, | ||
174 | }, | ||
175 | { | ||
176 | .which = DA8XX_MSTPRI_EDMA30TC1, | ||
177 | .val = 0, | ||
178 | }, | ||
179 | { | ||
180 | .which = DA8XX_MSTPRI_EDMA30TC0, | ||
181 | .val = 1, | ||
182 | }, | ||
183 | }; | ||
184 | |||
185 | static const struct da8xx_mstpri_board_priorities da8xx_mstpri_board_confs[] = { | ||
186 | { | ||
187 | .board = "ti,da850-lcdk", | ||
188 | .priorities = da850_lcdk_priorities, | ||
189 | .numprio = ARRAY_SIZE(da850_lcdk_priorities), | ||
190 | }, | ||
191 | }; | ||
192 | |||
193 | static const struct da8xx_mstpri_board_priorities * | ||
194 | da8xx_mstpri_get_board_prio(void) | ||
195 | { | ||
196 | const struct da8xx_mstpri_board_priorities *board_prio; | ||
197 | int i; | ||
198 | |||
199 | for (i = 0; i < ARRAY_SIZE(da8xx_mstpri_board_confs); i++) { | ||
200 | board_prio = &da8xx_mstpri_board_confs[i]; | ||
201 | |||
202 | if (of_machine_is_compatible(board_prio->board)) | ||
203 | return board_prio; | ||
204 | } | ||
205 | |||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | static int da8xx_mstpri_probe(struct platform_device *pdev) | ||
210 | { | ||
211 | const struct da8xx_mstpri_board_priorities *prio_list; | ||
212 | const struct da8xx_mstpri_descr *prio_descr; | ||
213 | const struct da8xx_mstpri_priority *prio; | ||
214 | struct device *dev = &pdev->dev; | ||
215 | struct resource *res; | ||
216 | void __iomem *mstpri; | ||
217 | u32 reg; | ||
218 | int i; | ||
219 | |||
220 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
221 | mstpri = devm_ioremap_resource(dev, res); | ||
222 | if (IS_ERR(mstpri)) { | ||
223 | dev_err(dev, "unable to map MSTPRI registers\n"); | ||
224 | return PTR_ERR(mstpri); | ||
225 | } | ||
226 | |||
227 | prio_list = da8xx_mstpri_get_board_prio(); | ||
228 | if (!prio_list) { | ||
229 | dev_err(dev, "no master priotities defined for board '%s'\n", | ||
230 | of_flat_dt_get_machine_name()); | ||
231 | return -EINVAL; | ||
232 | } | ||
233 | |||
234 | for (i = 0; i < prio_list->numprio; i++) { | ||
235 | prio = &prio_list->priorities[i]; | ||
236 | prio_descr = &da8xx_mstpri_priority_list[prio->which]; | ||
237 | |||
238 | if (prio_descr->reg + sizeof(u32) > resource_size(res)) { | ||
239 | dev_warn(dev, "register offset out of range\n"); | ||
240 | continue; | ||
241 | } | ||
242 | |||
243 | reg = readl(mstpri + prio_descr->reg); | ||
244 | reg &= ~prio_descr->mask; | ||
245 | reg |= prio->val << prio_descr->shift; | ||
246 | |||
247 | writel(reg, mstpri + prio_descr->reg); | ||
248 | } | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static const struct of_device_id da8xx_mstpri_of_match[] = { | ||
254 | { .compatible = "ti,da850-mstpri", }, | ||
255 | { }, | ||
256 | }; | ||
257 | |||
258 | static struct platform_driver da8xx_mstpri_driver = { | ||
259 | .probe = da8xx_mstpri_probe, | ||
260 | .driver = { | ||
261 | .name = "da8xx-mstpri", | ||
262 | .of_match_table = da8xx_mstpri_of_match, | ||
263 | }, | ||
264 | }; | ||
265 | module_platform_driver(da8xx_mstpri_driver); | ||
266 | |||
267 | MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); | ||
268 | MODULE_DESCRIPTION("TI da8xx master peripheral priority driver"); | ||
269 | MODULE_LICENSE("GPL v2"); | ||