0067-soc-ti-pruss-Add-helper-function-to-enable-OCP-maste.patch 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. From dcd56dcacc780840539cea865b89fcedcb63d56e Mon Sep 17 00:00:00 2001
  2. From: Suman Anna <s-anna@ti.com>
  3. Date: Fri, 26 Mar 2021 16:38:11 -0500
  4. Subject: [PATCH] soc: ti: pruss: Add helper function to enable OCP master
  5. ports
  6. The PRU-ICSS subsystem on OMAP-architecture based SoCS (AM33xx, AM437x
  7. and AM57xx SoCs) has a control bit STANDBY_INIT in the PRUSS_CFG register
  8. to initiate a Standby sequence (when set) and trigger a MStandby request
  9. to the SoC's PRCM module. This same bit is also used to enable the OCP
  10. master ports (when cleared). The clearing of the STANDBY_INIT bit requires
  11. an acknowledgment from PRCM and is done through the monitoring of the
  12. PRUSS_SYSCFG.SUB_MWAIT bit.
  13. Add a helper function pruss_cfg_ocp_master_ports() to allow the PRU
  14. client drivers to control this bit and enable or disable the firmware
  15. running on PRU cores access to any peripherals or memory to achieve
  16. desired functionality. The access is disabled by default on power-up
  17. and on any suspend (context is not maintained).
  18. Signed-off-by: Suman Anna <s-anna@ti.com>
  19. Co-developed-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
  20. Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
  21. ---
  22. drivers/soc/ti/pruss.c | 81 ++++++++++++++++++++++++++++++++++++++++--
  23. include/linux/pruss.h | 6 ++++
  24. 2 files changed, 85 insertions(+), 2 deletions(-)
  25. diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
  26. index 8841d85a0a0d..1254495b7c45 100644
  27. --- a/drivers/soc/ti/pruss.c
  28. +++ b/drivers/soc/ti/pruss.c
  29. @@ -22,14 +22,19 @@
  30. #include <linux/remoteproc.h>
  31. #include <linux/slab.h>
  32. +#define SYSCFG_STANDBY_INIT BIT(4)
  33. +#define SYSCFG_SUB_MWAIT_READY BIT(5)
  34. +
  35. /**
  36. * struct pruss_private_data - PRUSS driver private data
  37. * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM
  38. * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock
  39. + * @has_ocp_syscfg: flag to indicate if OCP SYSCFG is present
  40. */
  41. struct pruss_private_data {
  42. bool has_no_sharedram;
  43. bool has_core_mux_clock;
  44. + bool has_ocp_syscfg;
  45. };
  46. /**
  47. @@ -206,6 +211,72 @@ int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
  48. }
  49. EXPORT_SYMBOL_GPL(pruss_cfg_update);
  50. +/**
  51. + * pruss_cfg_ocp_master_ports() - configure PRUSS OCP master ports
  52. + * @pruss: the pruss instance handle
  53. + * @enable: set to true for enabling or false for disabling the OCP master ports
  54. + *
  55. + * This function programs the PRUSS_SYSCFG.STANDBY_INIT bit either to enable or
  56. + * disable the OCP master ports (applicable only on SoCs using OCP interconnect
  57. + * like the OMAP family). Clearing the bit achieves dual functionalities - one
  58. + * is to deassert the MStandby signal to the device PRCM, and the other is to
  59. + * enable OCP master ports to allow accesses outside of the PRU-ICSS. The
  60. + * function has to wait for the PRCM to acknowledge through the monitoring of
  61. + * the PRUSS_SYSCFG.SUB_MWAIT bit when enabling master ports. Setting the bit
  62. + * disables the master access, and also signals the PRCM that the PRUSS is ready
  63. + * for Standby.
  64. + *
  65. + * Return: 0 on success, or an error code otherwise. ETIMEDOUT is returned
  66. + * when the ready-state fails.
  67. + */
  68. +int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable)
  69. +{
  70. + int ret;
  71. + u32 syscfg_val, i;
  72. + const struct pruss_private_data *data;
  73. +
  74. + if (IS_ERR_OR_NULL(pruss))
  75. + return -EINVAL;
  76. +
  77. + data = of_device_get_match_data(pruss->dev);
  78. +
  79. + /* nothing to do on non OMAP-SoCs */
  80. + if (!data || !data->has_ocp_syscfg)
  81. + return 0;
  82. +
  83. + /* assert the MStandby signal during disable path */
  84. + if (!enable)
  85. + return pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG,
  86. + SYSCFG_STANDBY_INIT,
  87. + SYSCFG_STANDBY_INIT);
  88. +
  89. + /* enable the OCP master ports and disable MStandby */
  90. + ret = pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, SYSCFG_STANDBY_INIT, 0);
  91. + if (ret)
  92. + return ret;
  93. +
  94. + /* wait till we are ready for transactions - delay is arbitrary */
  95. + for (i = 0; i < 10; i++) {
  96. + ret = pruss_cfg_read(pruss, PRUSS_CFG_SYSCFG, &syscfg_val);
  97. + if (ret)
  98. + goto disable;
  99. +
  100. + if (!(syscfg_val & SYSCFG_SUB_MWAIT_READY))
  101. + return 0;
  102. +
  103. + udelay(5);
  104. + }
  105. +
  106. + dev_err(pruss->dev, "timeout waiting for SUB_MWAIT_READY\n");
  107. + ret = -ETIMEDOUT;
  108. +
  109. +disable:
  110. + pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, SYSCFG_STANDBY_INIT,
  111. + SYSCFG_STANDBY_INIT);
  112. + return ret;
  113. +}
  114. +EXPORT_SYMBOL_GPL(pruss_cfg_ocp_master_ports);
  115. +
  116. static void pruss_of_free_clk_provider(void *data)
  117. {
  118. struct device_node *clk_mux_np = data;
  119. @@ -497,10 +568,16 @@ static int pruss_remove(struct platform_device *pdev)
  120. /* instance-specific driver private data */
  121. static const struct pruss_private_data am437x_pruss1_data = {
  122. .has_no_sharedram = false,
  123. + .has_ocp_syscfg = true,
  124. };
  125. static const struct pruss_private_data am437x_pruss0_data = {
  126. .has_no_sharedram = true,
  127. + .has_ocp_syscfg = false,
  128. +};
  129. +
  130. +static const struct pruss_private_data am33xx_am57xx_data = {
  131. + .has_ocp_syscfg = true,
  132. };
  133. static const struct pruss_private_data am65x_j721e_pruss_data = {
  134. @@ -508,10 +585,10 @@ static const struct pruss_private_data am65x_j721e_pruss_data = {
  135. };
  136. static const struct of_device_id pruss_of_match[] = {
  137. - { .compatible = "ti,am3356-pruss" },
  138. + { .compatible = "ti,am3356-pruss", .data = &am33xx_am57xx_data },
  139. { .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, },
  140. { .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, },
  141. - { .compatible = "ti,am5728-pruss" },
  142. + { .compatible = "ti,am5728-pruss", .data = &am33xx_am57xx_data },
  143. { .compatible = "ti,k2g-pruss" },
  144. { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
  145. { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
  146. diff --git a/include/linux/pruss.h b/include/linux/pruss.h
  147. index ba5b728d5015..5fdd6f03446d 100644
  148. --- a/include/linux/pruss.h
  149. +++ b/include/linux/pruss.h
  150. @@ -163,6 +163,7 @@ int pruss_release_mem_region(struct pruss *pruss,
  151. int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val);
  152. int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
  153. unsigned int mask, unsigned int val);
  154. +int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable);
  155. #else
  156. @@ -198,6 +199,11 @@ static inline int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
  157. return -EOPNOTSUPP;
  158. }
  159. +static inline int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable)
  160. +{
  161. + return -EOPNOTSUPP;
  162. +}
  163. +
  164. #endif /* CONFIG_TI_PRUSS */
  165. #if IS_ENABLED(CONFIG_PRU_REMOTEPROC)