1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * PRU-ICSS SoC bus driver for various TI SoCs
4 *
5 * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Suman Anna <s-anna@ti.com>
7 * Keerthy <j-keerthy@ti.com>
8 */
10 #include <linux/delay.h>
11 #include <linux/io.h>
12 #include <linux/module.h>
13 #include <linux/of_platform.h>
14 #include <linux/of_address.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
18 #include <linux/platform_data/ti-pruss.h>
20 #define SYSCFG_STANDBY_INIT BIT(4)
21 #define SYSCFG_SUB_MWAIT_READY BIT(5)
23 #define SYSCFG_STANDBY_MODE_FORCE (0 << 2)
24 #define SYSCFG_STANDBY_MODE_NO (1 << 2)
25 #define SYSCFG_STANDBY_MODE_SMART (2 << 2)
26 #define SYSCFG_STANDBY_MODE_MASK (3 << 2)
28 #define SYSCFG_IDLE_MODE_FORCE 0
29 #define SYSCFG_IDLE_MODE_NO 1
30 #define SYSCFG_IDLE_MODE_SMART 2
31 #define SYSCFG_IDLE_MODE_MASK 3
33 /**
34 * struct pruss_soc_bus - PRUSS SoC bus structure
35 * @syscfg: kernel mapped address for SYSCFG register
36 * @in_standby: flag for storing standby status
37 * @has_reset: cached variable for storing global module reset flag
38 */
39 struct pruss_soc_bus {
40 void __iomem *syscfg;
41 bool in_standby;
42 bool has_reset;
43 };
45 /**
46 * struct pruss_soc_bus_match_data - PRUSS SoC bus driver match data
47 * @has_reset: flag to indicate the presence of global module reset
48 */
49 struct pruss_soc_bus_match_data {
50 bool has_reset;
51 };
53 static inline void pruss_soc_bus_rmw(void __iomem *reg, u32 mask, u32 set)
54 {
55 u32 val;
57 val = readl_relaxed(reg);
58 val &= ~mask;
59 val |= (set & mask);
60 writel_relaxed(val, reg);
61 }
63 /*
64 * This function programs the PRUSS_SYSCFG.STANDBY_INIT bit to achieve dual
65 * functionalities - one is to deassert the MStandby signal to the device
66 * PRCM, and the other is to enable OCP master ports to allow accesses
67 * outside of the PRU-ICSS. The function has to wait for the PRCM to
68 * acknowledge through the monitoring of the PRUSS_SYSCFG.SUB_MWAIT bit.
69 */
70 static
71 int __maybe_unused pruss_soc_bus_enable_ocp_master_ports(struct device *dev)
72 {
73 struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
74 u32 syscfg_val, i;
75 bool ready = false;
77 pruss_soc_bus_rmw(psoc_bus->syscfg, SYSCFG_STANDBY_INIT, 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->syscfg);
82 ready = !(syscfg_val & SYSCFG_SUB_MWAIT_READY);
83 if (ready)
84 break;
85 udelay(5);
86 }
88 if (!ready) {
89 dev_err(dev, "timeout waiting for SUB_MWAIT_READY\n");
90 return -ETIMEDOUT;
91 }
93 return 0;
94 }
96 static int __maybe_unused pruss_soc_bus_suspend(struct device *dev)
97 {
98 struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
99 u32 syscfg_val;
101 syscfg_val = readl_relaxed(psoc_bus->syscfg);
102 psoc_bus->in_standby = syscfg_val & SYSCFG_STANDBY_INIT;
104 /* initiate MStandby, undo the MStandby config in probe */
105 if (!psoc_bus->in_standby) {
106 pruss_soc_bus_rmw(psoc_bus->syscfg, SYSCFG_STANDBY_INIT,
107 SYSCFG_STANDBY_INIT);
108 }
110 return 0;
111 }
113 static int __maybe_unused pruss_soc_bus_resume(struct device *dev)
114 {
115 struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
116 int ret = 0;
118 /* re-enable OCP master ports/disable MStandby */
119 if (!psoc_bus->in_standby) {
120 ret = pruss_soc_bus_enable_ocp_master_ports(dev);
121 if (ret)
122 dev_err(dev, "%s failed\n", __func__);
123 }
125 return ret;
126 }
128 /* firmware must be idle when calling this function */
129 static void pruss_disable_module(struct device *dev)
130 {
131 struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
133 /* configure Smart Standby */
134 pruss_soc_bus_rmw(psoc_bus->syscfg, SYSCFG_STANDBY_MODE_MASK,
135 SYSCFG_STANDBY_MODE_SMART);
137 /* initiate MStandby */
138 pruss_soc_bus_rmw(psoc_bus->syscfg, SYSCFG_STANDBY_INIT,
139 SYSCFG_STANDBY_INIT);
141 /* tell PRCM to initiate IDLE request */
142 pm_runtime_put_sync(dev);
143 }
145 static int pruss_enable_module(struct device *dev)
146 {
147 struct pruss_soc_bus *psoc_bus = dev_get_drvdata(dev);
148 int ret;
150 /* tell PRCM to de-assert IDLE request */
151 ret = pm_runtime_get_sync(dev);
152 if (ret < 0) {
153 pm_runtime_put_noidle(dev);
154 return ret;
155 }
157 /* configure for Smart Idle & Smart Standby */
158 pruss_soc_bus_rmw(psoc_bus->syscfg, SYSCFG_IDLE_MODE_MASK,
159 SYSCFG_IDLE_MODE_SMART);
160 pruss_soc_bus_rmw(psoc_bus->syscfg, SYSCFG_STANDBY_MODE_MASK,
161 SYSCFG_STANDBY_MODE_SMART);
163 return ret;
164 }
166 static int pruss_soc_bus_probe(struct platform_device *pdev)
167 {
168 struct device *dev = &pdev->dev;
169 struct device_node *node = dev->of_node;
170 struct pruss_platform_data *pdata = dev_get_platdata(dev);
171 struct pruss_soc_bus *psoc_bus;
172 const struct pruss_soc_bus_match_data *data;
173 int ret;
175 psoc_bus = devm_kzalloc(dev, sizeof(*psoc_bus), GFP_KERNEL);
176 if (!psoc_bus)
177 return -ENOMEM;
179 psoc_bus->syscfg = of_iomap(node, 0);
180 if (!psoc_bus->syscfg)
181 return -ENOMEM;
183 data = of_device_get_match_data(dev);
184 if (!data) {
185 dev_err(dev, "missing match data\n");
186 return -ENODEV;
187 }
189 if (data->has_reset && (!pdata || !pdata->deassert_reset ||
190 !pdata->assert_reset || !pdata->reset_name)) {
191 dev_err(dev, "platform data (reset configuration information) missing\n");
192 return -ENODEV;
193 }
194 psoc_bus->has_reset = data->has_reset;
195 platform_set_drvdata(pdev, psoc_bus);
197 if (psoc_bus->has_reset) {
198 ret = pdata->deassert_reset(pdev, pdata->reset_name);
199 if (ret) {
200 dev_err(dev, "deassert_reset failed: %d\n", ret);
201 goto fail_reset;
202 }
203 }
205 pm_runtime_enable(dev);
206 ret = pruss_enable_module(dev);
207 if (ret < 0) {
208 dev_err(dev, "couldn't enable module\n");
209 goto fail_module;
210 }
212 ret = of_platform_populate(node, NULL, NULL, dev);
213 if (ret)
214 goto fail_of;
216 return 0;
218 fail_of:
219 pruss_disable_module(dev);
220 fail_module:
221 pm_runtime_disable(dev);
222 if (psoc_bus->has_reset)
223 pdata->assert_reset(pdev, pdata->reset_name);
224 fail_reset:
225 iounmap(psoc_bus->syscfg);
226 return ret;
227 }
229 static int pruss_soc_bus_remove(struct platform_device *pdev)
230 {
231 struct device *dev = &pdev->dev;
232 struct pruss_platform_data *pdata = dev_get_platdata(dev);
233 struct pruss_soc_bus *psoc_bus = platform_get_drvdata(pdev);
235 of_platform_depopulate(dev);
237 pruss_disable_module(dev);
238 pm_runtime_disable(dev);
240 if (psoc_bus->has_reset)
241 pdata->assert_reset(pdev, pdata->reset_name);
242 iounmap(psoc_bus->syscfg);
244 return 0;
245 }
247 /* instance-specific driver private data */
248 static const struct pruss_soc_bus_match_data am335x_data = {
249 .has_reset = true,
250 };
252 static const struct pruss_soc_bus_match_data am437x_data = {
253 .has_reset = true,
254 };
256 static const struct pruss_soc_bus_match_data am57xx_data = {
257 .has_reset = false,
258 };
260 static const struct of_device_id pruss_soc_bus_of_match[] = {
261 { .compatible = "ti,am3356-pruss-soc-bus", .data = &am335x_data, },
262 { .compatible = "ti,am4376-pruss-soc-bus", .data = &am437x_data, },
263 { .compatible = "ti,am5728-pruss-soc-bus", .data = &am57xx_data, },
264 { /* sentinel */ },
265 };
266 MODULE_DEVICE_TABLE(of, pruss_soc_bus_of_match);
268 static SIMPLE_DEV_PM_OPS(pruss_soc_bus_pm_ops,
269 pruss_soc_bus_suspend, pruss_soc_bus_resume);
271 static struct platform_driver pruss_soc_bus_driver = {
272 .driver = {
273 .name = "pruss-soc-bus",
274 .pm = &pruss_soc_bus_pm_ops,
275 .of_match_table = pruss_soc_bus_of_match,
276 },
277 .probe = pruss_soc_bus_probe,
278 .remove = pruss_soc_bus_remove,
279 };
280 module_platform_driver(pruss_soc_bus_driver);
282 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
283 MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>");
284 MODULE_DESCRIPTION("PRU-ICSS SoC Bus Driver for TI SoCs");
285 MODULE_LICENSE("GPL v2");