From: Roger Quadros <rogerq@xxxxxx> Updates OCP master port configuration to enable memory access outside of the PRU-ICSS subsystem. This set of changes configures PRUSS_SYSCFG.STANDBY_INIT bit either to enable or disable the OCP master ports (applicable only on SoCs using OCP interconnect like the OMAP family). Signed-off-by: Roger Quadros <rogerq@xxxxxx> Signed-off-by: Andrew F. Davis <afd@xxxxxx> Signed-off-by: Parvathi Pudi <parvathi@xxxxxxxxxxx> Signed-off-by: Basharath Hussain Khaja <basharath@xxxxxxxxxxx> --- drivers/soc/ti/pruss.c | 77 +++++++++++++++++++++++++++++++++++- include/linux/pruss_driver.h | 6 +++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index d7634bf5413a..a0e233da052c 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -25,14 +25,19 @@ #include <linux/slab.h> #include "pruss.h" +#define SYSCFG_STANDBY_INIT BIT(4) +#define SYSCFG_SUB_MWAIT_READY BIT(5) + /** * struct pruss_private_data - PRUSS driver private data * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock + * @has_ocp_syscfg: flag to indicate if OCP SYSCFG is present */ struct pruss_private_data { bool has_no_sharedram; bool has_core_mux_clock; + bool has_ocp_syscfg; }; /** @@ -286,6 +291,72 @@ int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type, } EXPORT_SYMBOL_GPL(pruss_cfg_xfr_enable); +/** + * pruss_cfg_ocp_master_ports() - configure PRUSS OCP master ports + * @pruss: the pruss instance handle + * @enable: set to true for enabling or false for disabling the OCP master ports + * + * This function programs the PRUSS_SYSCFG.STANDBY_INIT bit either to enable or + * disable the OCP master ports (applicable only on SoCs using OCP interconnect + * like the OMAP family). Clearing the bit achieves dual functionalities - one + * is to deassert the MStandby signal to the device PRCM, and the other is to + * enable OCP master ports to allow accesses outside of the PRU-ICSS. The + * function has to wait for the PRCM to acknowledge through the monitoring of + * the PRUSS_SYSCFG.SUB_MWAIT bit when enabling master ports. Setting the bit + * disables the master access, and also signals the PRCM that the PRUSS is ready + * for Standby. + * + * Return: 0 on success, or an error code otherwise. ETIMEDOUT is returned + * when the ready-state fails. + */ +int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable) +{ + const struct pruss_private_data *data; + u32 syscfg_val, i; + int ret; + + if (IS_ERR_OR_NULL(pruss)) + return -EINVAL; + + data = of_device_get_match_data(pruss->dev); + + /* nothing to do on non OMAP-SoCs */ + if (!data || !data->has_ocp_syscfg) + return 0; + + /* assert the MStandby signal during disable path */ + if (!enable) + return pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, + SYSCFG_STANDBY_INIT, + SYSCFG_STANDBY_INIT); + + /* enable the OCP master ports and disable MStandby */ + ret = pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, SYSCFG_STANDBY_INIT, 0); + if (ret) + return ret; + + /* wait till we are ready for transactions - delay is arbitrary */ + for (i = 0; i < 10; i++) { + ret = pruss_cfg_read(pruss, PRUSS_CFG_SYSCFG, &syscfg_val); + if (ret) + goto disable; + + if (!(syscfg_val & SYSCFG_SUB_MWAIT_READY)) + return 0; + + udelay(5); + } + + dev_err(pruss->dev, "timeout waiting for SUB_MWAIT_READY\n"); + ret = -ETIMEDOUT; + +disable: + pruss_cfg_update(pruss, PRUSS_CFG_SYSCFG, SYSCFG_STANDBY_INIT, + SYSCFG_STANDBY_INIT); + return ret; +} +EXPORT_SYMBOL_GPL(pruss_cfg_ocp_master_ports); + static void pruss_of_free_clk_provider(void *data) { struct device_node *clk_mux_np = data; @@ -570,6 +641,10 @@ static const struct pruss_private_data am437x_pruss0_data = { .has_no_sharedram = true, }; +static const struct pruss_private_data am57xx_data = { + .has_ocp_syscfg = true, +}; + static const struct pruss_private_data am65x_j721e_pruss_data = { .has_core_mux_clock = true, }; @@ -578,7 +653,7 @@ static const struct of_device_id pruss_of_match[] = { { .compatible = "ti,am3356-pruss" }, { .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, }, { .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, }, - { .compatible = "ti,am5728-pruss" }, + { .compatible = "ti,am5728-pruss", .data = &am57xx_data, }, { .compatible = "ti,k2g-pruss" }, { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, }, { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, }, diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h index 2e18fef1a2e1..15b3c9c58539 100644 --- a/include/linux/pruss_driver.h +++ b/include/linux/pruss_driver.h @@ -118,6 +118,7 @@ int pruss_cfg_gpimode(struct pruss *pruss, enum pruss_pru_id pru_id, int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable); int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type, bool enable); +int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable); #else @@ -172,6 +173,11 @@ static inline int pruss_cfg_xfr_enable(struct pruss *pruss, return -EOPNOTSUPP; } +static int pruss_cfg_ocp_master_ports(struct pruss *pruss, bool enable) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_TI_PRUSS */ #endif /* _PRUSS_DRIVER_H_ */ -- 2.34.1