Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bus: davinci: add support for da8xx bus master priority control

Create the driver for the da8xx master peripheral priority
configuration and implement support for writing to the three
Master Priority registers on da850 SoCs.

Reviewed-by: Kevin Hilman <khilman@baylibre.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
[nsekhar@ti.com: subject line adjustment]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>

authored by

Bartosz Golaszewski and committed by
Sekhar Nori
8e7223fc 62a8a739

+300
+20
Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt
··· 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 + };
+9
drivers/bus/Kconfig
··· 166 166 help 167 167 Platform configuration infrastructure for the ARM Ltd. 168 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 178 endmenu
+2
drivers/bus/Makefile
··· 21 21 obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o 22 22 obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o 23 23 obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o 24 + 25 + obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o
+269
drivers/bus/da8xx-mstpri.c
··· 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");