1 // SPDX-License-Identifier: GPL-2.0+
3 * Texas Instruments power domain driver
5 * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
13 #include <power-domain-uclass.h>
16 #include <linux/iopoll.h>
18 #define PSC_PTCMD 0x120
19 #define PSC_PTCMD_H 0x124
20 #define PSC_PTSTAT 0x128
21 #define PSC_PTSTAT_H 0x12C
22 #define PSC_PDSTAT 0x200
23 #define PSC_PDCTL 0x300
24 #define PSC_MDSTAT 0x800
25 #define PSC_MDCTL 0xa00
27 #define PDCTL_STATE_MASK 0x1
28 #define PDCTL_STATE_OFF 0x0
29 #define PDCTL_STATE_ON 0x1
31 #define MDSTAT_STATE_MASK 0x3f
32 #define MDSTAT_BUSY_MASK 0x30
33 #define MDSTAT_STATE_SWRSTDISABLE 0x0
34 #define MDSTAT_STATE_ENABLE 0x3
36 #define LPSC_TIMEOUT 1000
37 #define PD_TIMEOUT 1000
39 static u32 psc_read(struct ti_psc *psc, u32 reg)
43 val = readl(psc->base + reg);
44 debug("%s: 0x%x from %p\n", __func__, val, psc->base + reg);
48 static void psc_write(u32 val, struct ti_psc *psc, u32 reg)
50 debug("%s: 0x%x to %p\n", __func__, val, psc->base + reg);
51 writel(val, psc->base + reg);
54 static u32 pd_read(struct ti_pd *pd, u32 reg)
56 return psc_read(pd->psc, reg + 4 * pd->id);
59 static void pd_write(u32 val, struct ti_pd *pd, u32 reg)
61 psc_write(val, pd->psc, reg + 4 * pd->id);
64 static u32 lpsc_read(struct ti_lpsc *lpsc, u32 reg)
66 return psc_read(lpsc->psc, reg + 4 * lpsc->id);
69 static void lpsc_write(u32 val, struct ti_lpsc *lpsc, u32 reg)
71 psc_write(val, lpsc->psc, reg + 4 * lpsc->id);
74 static const struct soc_attr ti_k3_soc_pd_data[] = {
75 #if IS_ENABLED(CONFIG_SOC_K3_J721E)
78 .data = &j721e_pd_platdata,
82 .data = &j7200_pd_platdata,
84 #elif CONFIG_SOC_K3_J721S2
87 .data = &j721s2_pd_platdata,
90 #ifdef CONFIG_SOC_K3_AM625
93 .data = &am62x_pd_platdata,
99 static int ti_power_domain_probe(struct udevice *dev)
101 struct ti_k3_pd_platdata *data = dev_get_priv(dev);
102 const struct soc_attr *soc_match_data;
103 const struct ti_k3_pd_platdata *pdata;
105 printf("%s(dev=%p)\n", __func__, dev);
110 soc_match_data = soc_device_match(ti_k3_soc_pd_data);
114 pdata = (const struct ti_k3_pd_platdata *)soc_match_data->data;
116 data->psc = pdata->psc;
117 data->pd = pdata->pd;
118 data->lpsc = pdata->lpsc;
119 data->devs = pdata->devs;
120 data->num_psc = pdata->num_psc;
121 data->num_pd = pdata->num_pd;
122 data->num_lpsc = pdata->num_lpsc;
123 data->num_devs = pdata->num_devs;
128 static int ti_pd_wait(struct ti_pd *pd)
132 u32 ptstatreg = PSC_PTSTAT;
137 ptstatreg = PSC_PTSTAT_H;
140 ret = readl_poll_timeout(pd->psc->base + ptstatreg, ptstat,
141 !(ptstat & BIT(pd->id - pdoffset)), PD_TIMEOUT);
144 printf("%s: psc%d, pd%d failed to transition.\n", __func__,
145 pd->psc->id, pd->id);
150 static void ti_pd_transition(struct ti_pd *pd)
153 u32 ptcmdreg = PSC_PTCMD;
157 ptcmdreg = PSC_PTCMD_H;
160 psc_write(BIT(pd->id - pdoffset), pd->psc, ptcmdreg);
163 u8 ti_pd_state(struct ti_pd *pd)
165 return pd_read(pd, PSC_PDCTL) & PDCTL_STATE_MASK;
168 static int ti_pd_get(struct ti_pd *pd)
175 if (pd->usecount > 1)
179 ret = ti_pd_get(pd->depend);
182 ti_pd_transition(pd->depend);
183 ret = ti_pd_wait(pd->depend);
188 pdctl = pd_read(pd, PSC_PDCTL);
190 if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_ON)
193 debug("%s: enabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
195 pdctl &= ~PDCTL_STATE_MASK;
196 pdctl |= PDCTL_STATE_ON;
198 pd_write(pdctl, pd, PSC_PDCTL);
203 static int ti_pd_put(struct ti_pd *pd)
210 if (pd->usecount > 0)
213 pdctl = pd_read(pd, PSC_PDCTL);
214 if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_OFF)
217 pdctl &= ~PDCTL_STATE_MASK;
218 pdctl |= PDCTL_STATE_OFF;
220 debug("%s: disabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
222 pd_write(pdctl, pd, PSC_PDCTL);
225 ti_pd_transition(pd);
226 ret = ti_pd_wait(pd);
230 ret = ti_pd_put(pd->depend);
233 ti_pd_transition(pd->depend);
234 ret = ti_pd_wait(pd->depend);
242 static int ti_lpsc_wait(struct ti_lpsc *lpsc)
247 ret = readl_poll_timeout(lpsc->psc->base + PSC_MDSTAT + lpsc->id * 4,
249 !(mdstat & MDSTAT_BUSY_MASK), LPSC_TIMEOUT);
252 printf("%s: module %d failed to transition.\n", __func__,
258 u8 lpsc_get_state(struct ti_lpsc *lpsc)
260 return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
263 int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
265 struct ti_pd *psc_pd;
271 if (state == MDSTAT_STATE_ENABLE) {
273 if (lpsc->usecount > 1)
277 if (lpsc->usecount >= 1)
281 debug("%s: transitioning psc:%d, lpsc:%d to %x\n", __func__,
282 lpsc->psc->id, lpsc->id, state);
285 ti_lpsc_transition(lpsc->depend, state);
287 mdctl = lpsc_read(lpsc, PSC_MDCTL);
288 if ((mdctl & MDSTAT_STATE_MASK) == state)
291 if (state == MDSTAT_STATE_ENABLE)
296 mdctl &= ~MDSTAT_STATE_MASK;
299 lpsc_write(mdctl, lpsc, PSC_MDCTL);
301 ti_pd_transition(psc_pd);
302 ret = ti_pd_wait(psc_pd);
306 return ti_lpsc_wait(lpsc);
309 static int ti_power_domain_transition(struct power_domain *pd, u8 state)
311 struct ti_lpsc *lpsc = pd->priv;
313 return ti_lpsc_transition(lpsc, state);
316 static int ti_power_domain_on(struct power_domain *pd)
318 debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
320 return ti_power_domain_transition(pd, MDSTAT_STATE_ENABLE);
323 static int ti_power_domain_off(struct power_domain *pd)
325 debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
327 return ti_power_domain_transition(pd, MDSTAT_STATE_SWRSTDISABLE);
330 static struct ti_lpsc *lpsc_lookup(struct ti_k3_pd_platdata *data, int id)
334 for (idx = 0; idx < data->num_devs; idx++)
335 if (data->devs[idx].id == id)
336 return data->devs[idx].lpsc;
341 static int ti_power_domain_of_xlate(struct power_domain *pd,
342 struct ofnode_phandle_args *args)
344 struct ti_k3_pd_platdata *data = dev_get_priv(pd->dev);
345 struct ti_lpsc *lpsc;
347 debug("%s(power_domain=%p, id=%d)\n", __func__, pd, args->args[0]);
349 if (args->args_count < 1) {
350 printf("Invalid args_count: %d\n", args->args_count);
354 lpsc = lpsc_lookup(data, args->args[0]);
356 printf("%s: invalid dev-id: %d\n", __func__, args->args[0]);
365 static const struct udevice_id ti_power_domain_of_match[] = {
366 { .compatible = "ti,sci-pm-domain" },
370 static struct power_domain_ops ti_power_domain_ops = {
371 .on = ti_power_domain_on,
372 .off = ti_power_domain_off,
373 .of_xlate = ti_power_domain_of_xlate,
376 U_BOOT_DRIVER(ti_pm_domains) = {
377 .name = "ti-pm-domains",
378 .id = UCLASS_POWER_DOMAIN,
379 .of_match = ti_power_domain_of_match,
380 .probe = ti_power_domain_probe,
381 .priv_auto = sizeof(struct ti_k3_pd_platdata),
382 .ops = &ti_power_domain_ops,