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