da8xx-mstpri.c 6.1 KB

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