1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Texas Instruments power domain driver
4  *
5  * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
6  *	Tero Kristo <t-kristo@ti.com>
7  */
8 
9 #include <asm/io.h>
10 #include <common.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <power-domain-uclass.h>
14 #include <soc.h>
15 #include <k3-dev.h>
16 #include <linux/iopoll.h>
17 
18 #define PSC_PTCMD		0x120
19 #define PSC_PTSTAT		0x128
20 #define PSC_PDSTAT		0x200
21 #define PSC_PDCTL		0x300
22 #define PSC_MDSTAT		0x800
23 #define PSC_MDCTL		0xa00
24 
25 #define PDCTL_STATE_MASK		0x1
26 #define PDCTL_STATE_OFF			0x0
27 #define PDCTL_STATE_ON			0x1
28 
29 #define MDSTAT_STATE_MASK		0x3f
30 #define MDSTAT_BUSY_MASK		0x30
31 #define MDSTAT_STATE_SWRSTDISABLE	0x0
32 #define MDSTAT_STATE_ENABLE		0x3
33 
34 #define LPSC_TIMEOUT		1000
35 #define PD_TIMEOUT		1000
36 
psc_read(struct ti_psc * psc,u32 reg)37 static u32 psc_read(struct ti_psc *psc, u32 reg)
38 {
39 	u32 val;
40 
41 	val = readl(psc->base + reg);
42 	debug("%s: 0x%x from %p\n", __func__, val, psc->base + reg);
43 	return val;
44 }
45 
psc_write(u32 val,struct ti_psc * psc,u32 reg)46 static void psc_write(u32 val, struct ti_psc *psc, u32 reg)
47 {
48 	debug("%s: 0x%x to %p\n", __func__, val, psc->base + reg);
49 	writel(val, psc->base + reg);
50 }
51 
pd_read(struct ti_pd * pd,u32 reg)52 static u32 pd_read(struct ti_pd *pd, u32 reg)
53 {
54 	return psc_read(pd->psc, reg + 4 * pd->id);
55 }
56 
pd_write(u32 val,struct ti_pd * pd,u32 reg)57 static void pd_write(u32 val, struct ti_pd *pd, u32 reg)
58 {
59 	psc_write(val, pd->psc, reg + 4 * pd->id);
60 }
61 
lpsc_read(struct ti_lpsc * lpsc,u32 reg)62 static u32 lpsc_read(struct ti_lpsc *lpsc, u32 reg)
63 {
64 	return psc_read(lpsc->psc, reg + 4 * lpsc->id);
65 }
66 
lpsc_write(u32 val,struct ti_lpsc * lpsc,u32 reg)67 static void lpsc_write(u32 val, struct ti_lpsc *lpsc, u32 reg)
68 {
69 	psc_write(val, lpsc->psc, reg + 4 * lpsc->id);
70 }
71 
72 static const struct soc_attr ti_k3_soc_pd_data[] = {
73 #if IS_ENABLED(CONFIG_SOC_K3_J721E)
74 	{
75 		.family = "J721E",
76 		.data = &j721e_pd_platdata,
77 	},
78 	{
79 		.family = "J7200",
80 		.data = &j7200_pd_platdata,
81 	},
82 #endif
83 	{ /* sentinel */ }
84 };
85 
ti_power_domain_probe(struct udevice * dev)86 static int ti_power_domain_probe(struct udevice *dev)
87 {
88 	struct ti_k3_pd_platdata *data = dev_get_priv(dev);
89 	const struct soc_attr *soc_match_data;
90 	const struct ti_k3_pd_platdata *pdata;
91 
92 	printf("%s(dev=%p)\n", __func__, dev);
93 
94 	if (!data)
95 		return -ENOMEM;
96 
97 	soc_match_data = soc_device_match(ti_k3_soc_pd_data);
98 	if (!soc_match_data)
99 		return -ENODEV;
100 
101 	pdata = (const struct ti_k3_pd_platdata *)soc_match_data->data;
102 
103 	data->psc = pdata->psc;
104 	data->pd = pdata->pd;
105 	data->lpsc = pdata->lpsc;
106 	data->devs = pdata->devs;
107 	data->num_psc = pdata->num_psc;
108 	data->num_pd = pdata->num_pd;
109 	data->num_lpsc = pdata->num_lpsc;
110 	data->num_devs = pdata->num_devs;
111 
112 	return 0;
113 }
114 
ti_pd_wait(struct ti_pd * pd)115 static int ti_pd_wait(struct ti_pd *pd)
116 {
117 	u32 ptstat;
118 	int ret;
119 
120 	ret = readl_poll_timeout(pd->psc->base + PSC_PTSTAT, ptstat,
121 				 !(ptstat & BIT(pd->id)), PD_TIMEOUT);
122 
123 	if (ret)
124 		printf("%s: psc%d, pd%d failed to transition.\n", __func__,
125 		       pd->psc->id, pd->id);
126 
127 	return ret;
128 }
129 
ti_pd_transition(struct ti_pd * pd)130 static void ti_pd_transition(struct ti_pd *pd)
131 {
132 	psc_write(BIT(pd->id), pd->psc, PSC_PTCMD);
133 }
134 
ti_pd_state(struct ti_pd * pd)135 u8 ti_pd_state(struct ti_pd *pd)
136 {
137 	return pd_read(pd, PSC_PDCTL) & PDCTL_STATE_MASK;
138 }
139 
ti_pd_get(struct ti_pd * pd)140 static int ti_pd_get(struct ti_pd *pd)
141 {
142 	u32 pdctl;
143 	int ret;
144 
145 	pd->usecount++;
146 
147 	if (pd->usecount > 1)
148 		return 0;
149 
150 	if (pd->depend) {
151 		ret = ti_pd_get(pd->depend);
152 		if (ret)
153 			return ret;
154 		ti_pd_transition(pd->depend);
155 		ret = ti_pd_wait(pd->depend);
156 		if (ret)
157 			return ret;
158 	}
159 
160 	pdctl = pd_read(pd, PSC_PDCTL);
161 
162 	if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_ON)
163 		return 0;
164 
165 	debug("%s: enabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
166 
167 	pdctl &= ~PDCTL_STATE_MASK;
168 	pdctl |= PDCTL_STATE_ON;
169 
170 	pd_write(pdctl, pd, PSC_PDCTL);
171 
172 	return 0;
173 }
174 
ti_pd_put(struct ti_pd * pd)175 static int ti_pd_put(struct ti_pd *pd)
176 {
177 	u32 pdctl;
178 	int ret;
179 
180 	pd->usecount--;
181 
182 	if (pd->usecount > 0)
183 		return 0;
184 
185 	pdctl = pd_read(pd, PSC_PDCTL);
186 	if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_OFF)
187 		return 0;
188 
189 	pdctl &= ~PDCTL_STATE_MASK;
190 	pdctl |= PDCTL_STATE_OFF;
191 
192 	debug("%s: disabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
193 
194 	pd_write(pdctl, pd, PSC_PDCTL);
195 
196 	if (pd->depend) {
197 		ti_pd_transition(pd);
198 		ret = ti_pd_wait(pd);
199 		if (ret)
200 			return ret;
201 
202 		ret = ti_pd_put(pd->depend);
203 		if (ret)
204 			return ret;
205 		ti_pd_transition(pd->depend);
206 		ret = ti_pd_wait(pd->depend);
207 		if (ret)
208 			return ret;
209 	}
210 
211 	return 0;
212 }
213 
ti_lpsc_wait(struct ti_lpsc * lpsc)214 static int ti_lpsc_wait(struct ti_lpsc *lpsc)
215 {
216 	u32 mdstat;
217 	int ret;
218 
219 	ret = readl_poll_timeout(lpsc->psc->base + PSC_MDSTAT + lpsc->id * 4,
220 				 mdstat,
221 				 !(mdstat & MDSTAT_BUSY_MASK), LPSC_TIMEOUT);
222 
223 	if (ret)
224 		printf("%s: module %d failed to transition.\n", __func__,
225 		       lpsc->id);
226 
227 	return ret;
228 }
229 
lpsc_get_state(struct ti_lpsc * lpsc)230 u8 lpsc_get_state(struct ti_lpsc *lpsc)
231 {
232 	return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
233 }
234 
ti_lpsc_transition(struct ti_lpsc * lpsc,u8 state)235 int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
236 {
237 	struct ti_pd *psc_pd;
238 	int ret;
239 	u32 mdctl;
240 
241 	psc_pd = lpsc->pd;
242 
243 	if (state == MDSTAT_STATE_ENABLE) {
244 		lpsc->usecount++;
245 		if (lpsc->usecount > 1)
246 			return 0;
247 	} else {
248 		lpsc->usecount--;
249 		if (lpsc->usecount >= 1)
250 			return 0;
251 	}
252 
253 	debug("%s: transitioning psc:%d, lpsc:%d to %x\n", __func__,
254 	      lpsc->psc->id, lpsc->id, state);
255 
256 	if (lpsc->depend)
257 		ti_lpsc_transition(lpsc->depend, state);
258 
259 	mdctl = lpsc_read(lpsc, PSC_MDCTL);
260 	if ((mdctl & MDSTAT_STATE_MASK) == state)
261 		return 0;
262 
263 	if (state == MDSTAT_STATE_ENABLE)
264 		ti_pd_get(psc_pd);
265 	else
266 		ti_pd_put(psc_pd);
267 
268 	mdctl &= ~MDSTAT_STATE_MASK;
269 	mdctl |= state;
270 
271 	lpsc_write(mdctl, lpsc, PSC_MDCTL);
272 
273 	ti_pd_transition(psc_pd);
274 	ret = ti_pd_wait(psc_pd);
275 	if (ret)
276 		return ret;
277 
278 	return ti_lpsc_wait(lpsc);
279 }
280 
ti_power_domain_transition(struct power_domain * pd,u8 state)281 static int ti_power_domain_transition(struct power_domain *pd, u8 state)
282 {
283 	struct ti_lpsc *lpsc = pd->priv;
284 
285 	return ti_lpsc_transition(lpsc, state);
286 }
287 
ti_power_domain_on(struct power_domain * pd)288 static int ti_power_domain_on(struct power_domain *pd)
289 {
290 	debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
291 
292 	return ti_power_domain_transition(pd, MDSTAT_STATE_ENABLE);
293 }
294 
ti_power_domain_off(struct power_domain * pd)295 static int ti_power_domain_off(struct power_domain *pd)
296 {
297 	debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
298 
299 	return ti_power_domain_transition(pd, MDSTAT_STATE_SWRSTDISABLE);
300 }
301 
lpsc_lookup(struct ti_k3_pd_platdata * data,int id)302 static struct ti_lpsc *lpsc_lookup(struct ti_k3_pd_platdata *data, int id)
303 {
304 	int idx;
305 
306 	for (idx = 0; idx < data->num_devs; idx++)
307 		if (data->devs[idx].id == id)
308 			return data->devs[idx].lpsc;
309 
310 	return NULL;
311 }
312 
ti_power_domain_of_xlate(struct power_domain * pd,struct ofnode_phandle_args * args)313 static int ti_power_domain_of_xlate(struct power_domain *pd,
314 				    struct ofnode_phandle_args *args)
315 {
316 	struct ti_k3_pd_platdata *data = dev_get_priv(pd->dev);
317 	struct ti_lpsc *lpsc;
318 
319 	debug("%s(power_domain=%p, id=%d)\n", __func__, pd, args->args[0]);
320 
321 	if (args->args_count < 1) {
322 		printf("Invalid args_count: %d\n", args->args_count);
323 		return -EINVAL;
324 	}
325 
326 	lpsc = lpsc_lookup(data, args->args[0]);
327 	if (!lpsc) {
328 		printf("%s: invalid dev-id: %d\n", __func__, args->args[0]);
329 		return -ENOENT;
330 	}
331 
332 	pd->id = lpsc->id;
333 	pd->priv = lpsc;
334 
335 	return 0;
336 }
337 
ti_power_domain_request(struct power_domain * pd)338 static int ti_power_domain_request(struct power_domain *pd)
339 {
340 	return 0;
341 }
342 
ti_power_domain_free(struct power_domain * pd)343 static int ti_power_domain_free(struct power_domain *pd)
344 {
345 	return 0;
346 }
347 
348 static const struct udevice_id ti_power_domain_of_match[] = {
349 	{ .compatible = "ti,sci-pm-domain" },
350 	{ /* sentinel */ }
351 };
352 
353 static struct power_domain_ops ti_power_domain_ops = {
354 	.on = ti_power_domain_on,
355 	.off = ti_power_domain_off,
356 	.of_xlate = ti_power_domain_of_xlate,
357 	.request = ti_power_domain_request,
358 	.rfree = ti_power_domain_free,
359 };
360 
361 U_BOOT_DRIVER(ti_pm_domains) = {
362 	.name = "ti-pm-domains",
363 	.id = UCLASS_POWER_DOMAIN,
364 	.of_match = ti_power_domain_of_match,
365 	.probe = ti_power_domain_probe,
366 	.priv_auto = sizeof(struct ti_k3_pd_platdata),
367 	.ops = &ti_power_domain_ops,
368 };
369