pruss_soc_bus.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * PRU-ICSS SoC bus driver for various TI SoCs
  3. *
  4. * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
  5. * Suman Anna <s-anna@ti.com>
  6. * Keerthy <j-keerthy@ti.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * version 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include <linux/delay.h>
  18. #include <linux/io.h>
  19. #include <linux/module.h>
  20. #include <linux/of_platform.h>
  21. #include <linux/of_address.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/pm_runtime.h>
  24. #include <linux/platform_data/remoteproc-pruss.h>
  25. #define SYSCFG_OFFSET 0x4
  26. #define SYSCFG_STANDBY_INIT BIT(4)
  27. #define SYSCFG_SUB_MWAIT_READY BIT(5)
  28. #define SYSCFG_STANDBY_MODE_FORCE (0 << 2)
  29. #define SYSCFG_STANDBY_MODE_NO (1 << 2)
  30. #define SYSCFG_STANDBY_MODE_SMART (2 << 2)
  31. #define SYSCFG_STANDBY_MODE_MASK (3 << 2)
  32. #define SYSCFG_IDLE_MODE_FORCE 0
  33. #define SYSCFG_IDLE_MODE_NO 1
  34. #define SYSCFG_IDLE_MODE_SMART 2
  35. #define SYSCFG_IDLE_MODE_MASK 3
  36. /**
  37. * struct pruss_soc_bus - PRUSS SoC bus structure
  38. * @base: kernel mapped address for bus register base
  39. * @in_standby: flag for storing standby status
  40. * @has_reset: cached variable for storing global module reset flag
  41. * @skip_syscfg: flag to indicate if PRCM master standby/slave idle is needed
  42. */
  43. struct pruss_soc_bus {
  44. void __iomem *base;
  45. bool in_standby;
  46. bool has_reset;
  47. bool skip_syscfg;
  48. };
  49. /**
  50. * struct pruss_soc_bus_match_data - PRUSS SoC bus driver match data
  51. * @has_reset: flag to indicate the presence of global module reset
  52. */
  53. struct pruss_soc_bus_match_data {
  54. bool has_reset;
  55. };
  56. static inline void pruss_soc_bus_rmw(void __iomem *base, unsigned int offset,
  57. u32 mask, u32 set)
  58. {
  59. u32 val;
  60. val = readl_relaxed(base + offset);
  61. val &= ~mask;
  62. val |= (set & mask);
  63. writel_relaxed(val, base + offset);
  64. }
  65. /*
  66. * This function programs the PRUSS_SYSCFG.STANDBY_INIT bit to achieve dual
  67. * functionalities - one is to deassert the MStandby signal to the device
  68. * PRCM, and the other is to enable OCP master ports to allow accesses
  69. * outside of the PRU-ICSS. The function has to wait for the PRCM to
  70. * acknowledge through the monitoring of the PRUSS_SYSCFG.SUB_MWAIT bit.
  71. */
  72. static int pruss_soc_bus_enable_ocp_master_ports(struct device *dev)
  73. {
  74. struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
  75. u32 syscfg_val, i;
  76. bool ready = false;
  77. pruss_soc_bus_rmw(psoc_bus->base, SYSCFG_OFFSET, SYSCFG_STANDBY_INIT,
  78. 0);
  79. /* wait till we are ready for transactions - delay is arbitrary */
  80. for (i = 0; i < 10; i++) {
  81. syscfg_val = readl_relaxed(psoc_bus->base + SYSCFG_OFFSET);
  82. ready = !(syscfg_val & SYSCFG_SUB_MWAIT_READY);
  83. if (ready)
  84. break;
  85. udelay(5);
  86. }
  87. if (!ready) {
  88. dev_err(dev, "timeout waiting for SUB_MWAIT_READY\n");
  89. return -ETIMEDOUT;
  90. }
  91. return 0;
  92. }
  93. #ifdef CONFIG_PM_SLEEP
  94. static int pruss_soc_bus_suspend(struct device *dev)
  95. {
  96. struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
  97. u32 syscfg_val;
  98. if (psoc_bus->skip_syscfg)
  99. return 0;
  100. syscfg_val = readl_relaxed(psoc_bus->base + SYSCFG_OFFSET);
  101. psoc_bus->in_standby = syscfg_val & SYSCFG_STANDBY_INIT;
  102. /* initiate MStandby, undo the MStandby config in probe */
  103. if (!psoc_bus->in_standby) {
  104. pruss_soc_bus_rmw(psoc_bus->base, SYSCFG_OFFSET,
  105. SYSCFG_STANDBY_INIT, SYSCFG_STANDBY_INIT);
  106. }
  107. return 0;
  108. }
  109. static int pruss_soc_bus_resume(struct device *dev)
  110. {
  111. struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
  112. int ret = 0;
  113. /* re-enable OCP master ports/disable MStandby */
  114. if (!psoc_bus->skip_syscfg && !psoc_bus->in_standby) {
  115. ret = pruss_soc_bus_enable_ocp_master_ports(dev);
  116. if (ret)
  117. dev_err(dev, "%s failed\n", __func__);
  118. }
  119. return ret;
  120. }
  121. #endif /* CONFIG_PM_SLEEP */
  122. /* firmware must be idle when calling this function */
  123. static void pruss_disable_module(struct device *dev)
  124. {
  125. struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
  126. if (psoc_bus->skip_syscfg)
  127. goto put_sync;
  128. /* configure Smart Standby */
  129. pruss_soc_bus_rmw(psoc_bus->base, SYSCFG_OFFSET,
  130. SYSCFG_STANDBY_MODE_MASK, SYSCFG_STANDBY_MODE_SMART);
  131. /* initiate MStandby */
  132. pruss_soc_bus_rmw(psoc_bus->base, SYSCFG_OFFSET,
  133. SYSCFG_STANDBY_INIT, SYSCFG_STANDBY_INIT);
  134. put_sync:
  135. /* initiate IDLE request, disable clocks */
  136. pm_runtime_put_sync(dev);
  137. }
  138. static int pruss_enable_module(struct device *dev)
  139. {
  140. struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
  141. int ret;
  142. /* enable clocks, de-assert IDLE request */
  143. ret = pm_runtime_get_sync(dev);
  144. if (ret < 0) {
  145. pm_runtime_put_noidle(dev);
  146. return ret;
  147. }
  148. if (psoc_bus->skip_syscfg)
  149. return ret;
  150. /* configure for Smart Idle & Smart Standby */
  151. pruss_soc_bus_rmw(psoc_bus->base, SYSCFG_OFFSET,
  152. SYSCFG_IDLE_MODE_MASK, SYSCFG_IDLE_MODE_SMART);
  153. pruss_soc_bus_rmw(psoc_bus->base, SYSCFG_OFFSET,
  154. SYSCFG_STANDBY_MODE_MASK, SYSCFG_STANDBY_MODE_SMART);
  155. /* enable OCP master ports/disable MStandby */
  156. ret = pruss_soc_bus_enable_ocp_master_ports(dev);
  157. if (ret)
  158. pruss_disable_module(dev);
  159. return ret;
  160. }
  161. static const struct of_device_id pruss_soc_bus_of_match[];
  162. static const struct pruss_soc_bus_match_data *pruss_soc_bus_get_match_data(
  163. struct platform_device *pdev)
  164. {
  165. const struct of_device_id *match;
  166. match = of_match_device(pruss_soc_bus_of_match, &pdev->dev);
  167. if (!match)
  168. return ERR_PTR(-ENODEV);
  169. return match->data;
  170. }
  171. static int pruss_soc_bus_probe(struct platform_device *pdev)
  172. {
  173. struct device *dev = &pdev->dev;
  174. struct device_node *node = dev->of_node;
  175. struct pruss_platform_data *pdata = dev_get_platdata(dev);
  176. struct pruss_soc_bus *psoc_bus;
  177. const struct pruss_soc_bus_match_data *data;
  178. int ret;
  179. psoc_bus = devm_kzalloc(dev, sizeof(*psoc_bus), GFP_KERNEL);
  180. if (!psoc_bus)
  181. return -ENOMEM;
  182. psoc_bus->base = of_iomap(node, 0);
  183. if (!psoc_bus->base)
  184. return -ENOMEM;
  185. data = pruss_soc_bus_get_match_data(pdev);
  186. if (IS_ERR_OR_NULL(data)) {
  187. dev_err(dev, "missing match data\n");
  188. return -ENODEV;
  189. }
  190. if (data->has_reset && (!pdata || !pdata->deassert_reset ||
  191. !pdata->assert_reset || !pdata->reset_name)) {
  192. dev_err(dev, "platform data (reset configuration information) missing\n");
  193. return -ENODEV;
  194. }
  195. psoc_bus->has_reset = data->has_reset;
  196. psoc_bus->skip_syscfg =
  197. !!of_device_is_compatible(node, "ti,k2g-pruss-soc-bus");
  198. platform_set_drvdata(pdev, psoc_bus);
  199. if (psoc_bus->has_reset) {
  200. ret = pdata->deassert_reset(pdev, pdata->reset_name);
  201. if (ret) {
  202. dev_err(dev, "deassert_reset failed: %d\n", ret);
  203. goto fail_reset;
  204. }
  205. }
  206. pm_runtime_enable(dev);
  207. ret = pruss_enable_module(dev);
  208. if (ret < 0) {
  209. dev_err(dev, "couldn't enable module\n");
  210. goto fail_module;
  211. }
  212. ret = of_platform_populate(node, NULL, NULL, dev);
  213. if (ret)
  214. goto fail_of;
  215. return 0;
  216. fail_of:
  217. pruss_disable_module(dev);
  218. fail_module:
  219. pm_runtime_disable(dev);
  220. if (psoc_bus->has_reset)
  221. pdata->assert_reset(pdev, pdata->reset_name);
  222. fail_reset:
  223. iounmap(psoc_bus->base);
  224. return ret;
  225. }
  226. static int pruss_soc_bus_remove(struct platform_device *pdev)
  227. {
  228. struct device *dev = &pdev->dev;
  229. struct pruss_platform_data *pdata = dev_get_platdata(dev);
  230. struct pruss_soc_bus *psoc_bus = platform_get_drvdata(pdev);
  231. of_platform_depopulate(dev);
  232. pruss_disable_module(dev);
  233. pm_runtime_disable(dev);
  234. if (psoc_bus->has_reset)
  235. pdata->assert_reset(pdev, pdata->reset_name);
  236. iounmap(psoc_bus->base);
  237. return 0;
  238. }
  239. /* instance-specific driver private data */
  240. static struct pruss_soc_bus_match_data am335x_data = {
  241. .has_reset = true,
  242. };
  243. static struct pruss_soc_bus_match_data am437x_data = {
  244. .has_reset = true,
  245. };
  246. static struct pruss_soc_bus_match_data am57xx_data = {
  247. .has_reset = false,
  248. };
  249. static struct pruss_soc_bus_match_data k2g_data = {
  250. .has_reset = false,
  251. };
  252. static const struct of_device_id pruss_soc_bus_of_match[] = {
  253. { .compatible = "ti,am3356-pruss-soc-bus", .data = &am335x_data, },
  254. { .compatible = "ti,am4376-pruss-soc-bus", .data = &am437x_data, },
  255. { .compatible = "ti,am5728-pruss-soc-bus", .data = &am57xx_data, },
  256. { .compatible = "ti,k2g-pruss-soc-bus", .data = &k2g_data, },
  257. { /* sentinel */ },
  258. };
  259. MODULE_DEVICE_TABLE(of, pruss_soc_bus_of_match);
  260. static SIMPLE_DEV_PM_OPS(pruss_soc_bus_pm_ops,
  261. pruss_soc_bus_suspend, pruss_soc_bus_resume);
  262. static struct platform_driver pruss_soc_bus_driver = {
  263. .driver = {
  264. .name = "pruss-soc-bus",
  265. .pm = &pruss_soc_bus_pm_ops,
  266. .of_match_table = pruss_soc_bus_of_match,
  267. },
  268. .probe = pruss_soc_bus_probe,
  269. .remove = pruss_soc_bus_remove,
  270. };
  271. module_platform_driver(pruss_soc_bus_driver);
  272. MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
  273. MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>");
  274. MODULE_DESCRIPTION("PRU-ICSS SoC Bus Driver for TI SoCs");
  275. MODULE_LICENSE("GPL v2");