]> Git Repo - J-u-boot.git/blob - drivers/power/domain/ti-power-domain.c
a7f64d04f5c20c7272a28f1bc4708b5c2f5584a7
[J-u-boot.git] / drivers / power / domain / ti-power-domain.c
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 <[email protected]>
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_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
26
27 #define PDCTL_STATE_MASK                0x1
28 #define PDCTL_STATE_OFF                 0x0
29 #define PDCTL_STATE_ON                  0x1
30
31 #define MDSTAT_STATE_MASK               0x3f
32 #define MDSTAT_BUSY_MASK                0x30
33 #define MDSTAT_STATE_SWRSTDISABLE       0x0
34 #define MDSTAT_STATE_ENABLE             0x3
35
36 #define LPSC_TIMEOUT            1000
37 #define PD_TIMEOUT              1000
38
39 static u32 psc_read(struct ti_psc *psc, u32 reg)
40 {
41         u32 val;
42
43         val = readl(psc->base + reg);
44         debug("%s: 0x%x from %p\n", __func__, val, psc->base + reg);
45         return val;
46 }
47
48 static void psc_write(u32 val, struct ti_psc *psc, u32 reg)
49 {
50         debug("%s: 0x%x to %p\n", __func__, val, psc->base + reg);
51         writel(val, psc->base + reg);
52 }
53
54 static u32 pd_read(struct ti_pd *pd, u32 reg)
55 {
56         return psc_read(pd->psc, reg + 4 * pd->id);
57 }
58
59 static void pd_write(u32 val, struct ti_pd *pd, u32 reg)
60 {
61         psc_write(val, pd->psc, reg + 4 * pd->id);
62 }
63
64 static u32 lpsc_read(struct ti_lpsc *lpsc, u32 reg)
65 {
66         return psc_read(lpsc->psc, reg + 4 * lpsc->id);
67 }
68
69 static void lpsc_write(u32 val, struct ti_lpsc *lpsc, u32 reg)
70 {
71         psc_write(val, lpsc->psc, reg + 4 * lpsc->id);
72 }
73
74 static const struct soc_attr ti_k3_soc_pd_data[] = {
75 #if IS_ENABLED(CONFIG_SOC_K3_J721E)
76         {
77                 .family = "J721E",
78                 .data = &j721e_pd_platdata,
79         },
80         {
81                 .family = "J7200",
82                 .data = &j7200_pd_platdata,
83         },
84 #elif CONFIG_SOC_K3_J721S2
85         {
86                 .family = "J721S2",
87                 .data = &j721s2_pd_platdata,
88         },
89 #endif
90 #ifdef CONFIG_SOC_K3_AM625
91         {
92                 .family = "AM62X",
93                 .data = &am62x_pd_platdata,
94         },
95 #endif
96         { /* sentinel */ }
97 };
98
99 static int ti_power_domain_probe(struct udevice *dev)
100 {
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;
104
105         printf("%s(dev=%p)\n", __func__, dev);
106
107         if (!data)
108                 return -ENOMEM;
109
110         soc_match_data = soc_device_match(ti_k3_soc_pd_data);
111         if (!soc_match_data)
112                 return -ENODEV;
113
114         pdata = (const struct ti_k3_pd_platdata *)soc_match_data->data;
115
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;
124
125         return 0;
126 }
127
128 static int ti_pd_wait(struct ti_pd *pd)
129 {
130         u32 ptstat;
131         u32 pdoffset = 0;
132         u32 ptstatreg = PSC_PTSTAT;
133         int ret;
134
135         if (pd->id > 31) {
136                 pdoffset = 32;
137                 ptstatreg = PSC_PTSTAT_H;
138         }
139
140         ret = readl_poll_timeout(pd->psc->base + ptstatreg, ptstat,
141                                  !(ptstat & BIT(pd->id - pdoffset)), PD_TIMEOUT);
142
143         if (ret)
144                 printf("%s: psc%d, pd%d failed to transition.\n", __func__,
145                        pd->psc->id, pd->id);
146
147         return ret;
148 }
149
150 static void ti_pd_transition(struct ti_pd *pd)
151 {
152         u32 pdoffset = 0;
153         u32 ptcmdreg = PSC_PTCMD;
154
155         if (pd->id > 31) {
156                 pdoffset = 32;
157                 ptcmdreg = PSC_PTCMD_H;
158         }
159
160         psc_write(BIT(pd->id - pdoffset), pd->psc, ptcmdreg);
161 }
162
163 u8 ti_pd_state(struct ti_pd *pd)
164 {
165         return pd_read(pd, PSC_PDCTL) & PDCTL_STATE_MASK;
166 }
167
168 static int ti_pd_get(struct ti_pd *pd)
169 {
170         u32 pdctl;
171         int ret;
172
173         pd->usecount++;
174
175         if (pd->usecount > 1)
176                 return 0;
177
178         if (pd->depend) {
179                 ret = ti_pd_get(pd->depend);
180                 if (ret)
181                         return ret;
182                 ti_pd_transition(pd->depend);
183                 ret = ti_pd_wait(pd->depend);
184                 if (ret)
185                         return ret;
186         }
187
188         pdctl = pd_read(pd, PSC_PDCTL);
189
190         if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_ON)
191                 return 0;
192
193         debug("%s: enabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
194
195         pdctl &= ~PDCTL_STATE_MASK;
196         pdctl |= PDCTL_STATE_ON;
197
198         pd_write(pdctl, pd, PSC_PDCTL);
199
200         return 0;
201 }
202
203 static int ti_pd_put(struct ti_pd *pd)
204 {
205         u32 pdctl;
206         int ret;
207
208         pd->usecount--;
209
210         if (pd->usecount > 0)
211                 return 0;
212
213         pdctl = pd_read(pd, PSC_PDCTL);
214         if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_OFF)
215                 return 0;
216
217         pdctl &= ~PDCTL_STATE_MASK;
218         pdctl |= PDCTL_STATE_OFF;
219
220         debug("%s: disabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
221
222         pd_write(pdctl, pd, PSC_PDCTL);
223
224         if (pd->depend) {
225                 ti_pd_transition(pd);
226                 ret = ti_pd_wait(pd);
227                 if (ret)
228                         return ret;
229
230                 ret = ti_pd_put(pd->depend);
231                 if (ret)
232                         return ret;
233                 ti_pd_transition(pd->depend);
234                 ret = ti_pd_wait(pd->depend);
235                 if (ret)
236                         return ret;
237         }
238
239         return 0;
240 }
241
242 static int ti_lpsc_wait(struct ti_lpsc *lpsc)
243 {
244         u32 mdstat;
245         int ret;
246
247         ret = readl_poll_timeout(lpsc->psc->base + PSC_MDSTAT + lpsc->id * 4,
248                                  mdstat,
249                                  !(mdstat & MDSTAT_BUSY_MASK), LPSC_TIMEOUT);
250
251         if (ret)
252                 printf("%s: module %d failed to transition.\n", __func__,
253                        lpsc->id);
254
255         return ret;
256 }
257
258 u8 lpsc_get_state(struct ti_lpsc *lpsc)
259 {
260         return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
261 }
262
263 int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
264 {
265         struct ti_pd *psc_pd;
266         int ret;
267         u32 mdctl;
268
269         psc_pd = lpsc->pd;
270
271         if (state == MDSTAT_STATE_ENABLE) {
272                 lpsc->usecount++;
273                 if (lpsc->usecount > 1)
274                         return 0;
275         } else {
276                 lpsc->usecount--;
277                 if (lpsc->usecount >= 1)
278                         return 0;
279         }
280
281         debug("%s: transitioning psc:%d, lpsc:%d to %x\n", __func__,
282               lpsc->psc->id, lpsc->id, state);
283
284         if (lpsc->depend)
285                 ti_lpsc_transition(lpsc->depend, state);
286
287         mdctl = lpsc_read(lpsc, PSC_MDCTL);
288         if ((mdctl & MDSTAT_STATE_MASK) == state)
289                 return 0;
290
291         if (state == MDSTAT_STATE_ENABLE)
292                 ti_pd_get(psc_pd);
293         else
294                 ti_pd_put(psc_pd);
295
296         mdctl &= ~MDSTAT_STATE_MASK;
297         mdctl |= state;
298
299         lpsc_write(mdctl, lpsc, PSC_MDCTL);
300
301         ti_pd_transition(psc_pd);
302         ret = ti_pd_wait(psc_pd);
303         if (ret)
304                 return ret;
305
306         return ti_lpsc_wait(lpsc);
307 }
308
309 static int ti_power_domain_transition(struct power_domain *pd, u8 state)
310 {
311         struct ti_lpsc *lpsc = pd->priv;
312
313         return ti_lpsc_transition(lpsc, state);
314 }
315
316 static int ti_power_domain_on(struct power_domain *pd)
317 {
318         debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
319
320         return ti_power_domain_transition(pd, MDSTAT_STATE_ENABLE);
321 }
322
323 static int ti_power_domain_off(struct power_domain *pd)
324 {
325         debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
326
327         return ti_power_domain_transition(pd, MDSTAT_STATE_SWRSTDISABLE);
328 }
329
330 static struct ti_lpsc *lpsc_lookup(struct ti_k3_pd_platdata *data, int id)
331 {
332         int idx;
333
334         for (idx = 0; idx < data->num_devs; idx++)
335                 if (data->devs[idx].id == id)
336                         return data->devs[idx].lpsc;
337
338         return NULL;
339 }
340
341 static int ti_power_domain_of_xlate(struct power_domain *pd,
342                                     struct ofnode_phandle_args *args)
343 {
344         struct ti_k3_pd_platdata *data = dev_get_priv(pd->dev);
345         struct ti_lpsc *lpsc;
346
347         debug("%s(power_domain=%p, id=%d)\n", __func__, pd, args->args[0]);
348
349         if (args->args_count < 1) {
350                 printf("Invalid args_count: %d\n", args->args_count);
351                 return -EINVAL;
352         }
353
354         lpsc = lpsc_lookup(data, args->args[0]);
355         if (!lpsc) {
356                 printf("%s: invalid dev-id: %d\n", __func__, args->args[0]);
357                 return -ENOENT;
358         }
359
360         pd->id = lpsc->id;
361         pd->priv = lpsc;
362
363         return 0;
364 }
365 static const struct udevice_id ti_power_domain_of_match[] = {
366         { .compatible = "ti,sci-pm-domain" },
367         { /* sentinel */ }
368 };
369
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,
374 };
375
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,
383 };
This page took 0.037404 seconds and 2 git commands to generate.