efi_loader: simplify efi_serialize_load_option()
[platform/kernel/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 <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
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
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
52 static u32 pd_read(struct ti_pd *pd, u32 reg)
53 {
54         return psc_read(pd->psc, reg + 4 * pd->id);
55 }
56
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
62 static u32 lpsc_read(struct ti_lpsc *lpsc, u32 reg)
63 {
64         return psc_read(lpsc->psc, reg + 4 * lpsc->id);
65 }
66
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 #elif CONFIG_SOC_K3_J721S2
83         {
84                 .family = "J721S2",
85                 .data = &j721s2_pd_platdata,
86         },
87 #endif
88         { /* sentinel */ }
89 };
90
91 static int ti_power_domain_probe(struct udevice *dev)
92 {
93         struct ti_k3_pd_platdata *data = dev_get_priv(dev);
94         const struct soc_attr *soc_match_data;
95         const struct ti_k3_pd_platdata *pdata;
96
97         printf("%s(dev=%p)\n", __func__, dev);
98
99         if (!data)
100                 return -ENOMEM;
101
102         soc_match_data = soc_device_match(ti_k3_soc_pd_data);
103         if (!soc_match_data)
104                 return -ENODEV;
105
106         pdata = (const struct ti_k3_pd_platdata *)soc_match_data->data;
107
108         data->psc = pdata->psc;
109         data->pd = pdata->pd;
110         data->lpsc = pdata->lpsc;
111         data->devs = pdata->devs;
112         data->num_psc = pdata->num_psc;
113         data->num_pd = pdata->num_pd;
114         data->num_lpsc = pdata->num_lpsc;
115         data->num_devs = pdata->num_devs;
116
117         return 0;
118 }
119
120 static int ti_pd_wait(struct ti_pd *pd)
121 {
122         u32 ptstat;
123         int ret;
124
125         ret = readl_poll_timeout(pd->psc->base + PSC_PTSTAT, ptstat,
126                                  !(ptstat & BIT(pd->id)), PD_TIMEOUT);
127
128         if (ret)
129                 printf("%s: psc%d, pd%d failed to transition.\n", __func__,
130                        pd->psc->id, pd->id);
131
132         return ret;
133 }
134
135 static void ti_pd_transition(struct ti_pd *pd)
136 {
137         psc_write(BIT(pd->id), pd->psc, PSC_PTCMD);
138 }
139
140 u8 ti_pd_state(struct ti_pd *pd)
141 {
142         return pd_read(pd, PSC_PDCTL) & PDCTL_STATE_MASK;
143 }
144
145 static int ti_pd_get(struct ti_pd *pd)
146 {
147         u32 pdctl;
148         int ret;
149
150         pd->usecount++;
151
152         if (pd->usecount > 1)
153                 return 0;
154
155         if (pd->depend) {
156                 ret = ti_pd_get(pd->depend);
157                 if (ret)
158                         return ret;
159                 ti_pd_transition(pd->depend);
160                 ret = ti_pd_wait(pd->depend);
161                 if (ret)
162                         return ret;
163         }
164
165         pdctl = pd_read(pd, PSC_PDCTL);
166
167         if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_ON)
168                 return 0;
169
170         debug("%s: enabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
171
172         pdctl &= ~PDCTL_STATE_MASK;
173         pdctl |= PDCTL_STATE_ON;
174
175         pd_write(pdctl, pd, PSC_PDCTL);
176
177         return 0;
178 }
179
180 static int ti_pd_put(struct ti_pd *pd)
181 {
182         u32 pdctl;
183         int ret;
184
185         pd->usecount--;
186
187         if (pd->usecount > 0)
188                 return 0;
189
190         pdctl = pd_read(pd, PSC_PDCTL);
191         if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_OFF)
192                 return 0;
193
194         pdctl &= ~PDCTL_STATE_MASK;
195         pdctl |= PDCTL_STATE_OFF;
196
197         debug("%s: disabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
198
199         pd_write(pdctl, pd, PSC_PDCTL);
200
201         if (pd->depend) {
202                 ti_pd_transition(pd);
203                 ret = ti_pd_wait(pd);
204                 if (ret)
205                         return ret;
206
207                 ret = ti_pd_put(pd->depend);
208                 if (ret)
209                         return ret;
210                 ti_pd_transition(pd->depend);
211                 ret = ti_pd_wait(pd->depend);
212                 if (ret)
213                         return ret;
214         }
215
216         return 0;
217 }
218
219 static int ti_lpsc_wait(struct ti_lpsc *lpsc)
220 {
221         u32 mdstat;
222         int ret;
223
224         ret = readl_poll_timeout(lpsc->psc->base + PSC_MDSTAT + lpsc->id * 4,
225                                  mdstat,
226                                  !(mdstat & MDSTAT_BUSY_MASK), LPSC_TIMEOUT);
227
228         if (ret)
229                 printf("%s: module %d failed to transition.\n", __func__,
230                        lpsc->id);
231
232         return ret;
233 }
234
235 u8 lpsc_get_state(struct ti_lpsc *lpsc)
236 {
237         return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
238 }
239
240 int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
241 {
242         struct ti_pd *psc_pd;
243         int ret;
244         u32 mdctl;
245
246         psc_pd = lpsc->pd;
247
248         if (state == MDSTAT_STATE_ENABLE) {
249                 lpsc->usecount++;
250                 if (lpsc->usecount > 1)
251                         return 0;
252         } else {
253                 lpsc->usecount--;
254                 if (lpsc->usecount >= 1)
255                         return 0;
256         }
257
258         debug("%s: transitioning psc:%d, lpsc:%d to %x\n", __func__,
259               lpsc->psc->id, lpsc->id, state);
260
261         if (lpsc->depend)
262                 ti_lpsc_transition(lpsc->depend, state);
263
264         mdctl = lpsc_read(lpsc, PSC_MDCTL);
265         if ((mdctl & MDSTAT_STATE_MASK) == state)
266                 return 0;
267
268         if (state == MDSTAT_STATE_ENABLE)
269                 ti_pd_get(psc_pd);
270         else
271                 ti_pd_put(psc_pd);
272
273         mdctl &= ~MDSTAT_STATE_MASK;
274         mdctl |= state;
275
276         lpsc_write(mdctl, lpsc, PSC_MDCTL);
277
278         ti_pd_transition(psc_pd);
279         ret = ti_pd_wait(psc_pd);
280         if (ret)
281                 return ret;
282
283         return ti_lpsc_wait(lpsc);
284 }
285
286 static int ti_power_domain_transition(struct power_domain *pd, u8 state)
287 {
288         struct ti_lpsc *lpsc = pd->priv;
289
290         return ti_lpsc_transition(lpsc, state);
291 }
292
293 static int ti_power_domain_on(struct power_domain *pd)
294 {
295         debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
296
297         return ti_power_domain_transition(pd, MDSTAT_STATE_ENABLE);
298 }
299
300 static int ti_power_domain_off(struct power_domain *pd)
301 {
302         debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
303
304         return ti_power_domain_transition(pd, MDSTAT_STATE_SWRSTDISABLE);
305 }
306
307 static struct ti_lpsc *lpsc_lookup(struct ti_k3_pd_platdata *data, int id)
308 {
309         int idx;
310
311         for (idx = 0; idx < data->num_devs; idx++)
312                 if (data->devs[idx].id == id)
313                         return data->devs[idx].lpsc;
314
315         return NULL;
316 }
317
318 static int ti_power_domain_of_xlate(struct power_domain *pd,
319                                     struct ofnode_phandle_args *args)
320 {
321         struct ti_k3_pd_platdata *data = dev_get_priv(pd->dev);
322         struct ti_lpsc *lpsc;
323
324         debug("%s(power_domain=%p, id=%d)\n", __func__, pd, args->args[0]);
325
326         if (args->args_count < 1) {
327                 printf("Invalid args_count: %d\n", args->args_count);
328                 return -EINVAL;
329         }
330
331         lpsc = lpsc_lookup(data, args->args[0]);
332         if (!lpsc) {
333                 printf("%s: invalid dev-id: %d\n", __func__, args->args[0]);
334                 return -ENOENT;
335         }
336
337         pd->id = lpsc->id;
338         pd->priv = lpsc;
339
340         return 0;
341 }
342
343 static int ti_power_domain_request(struct power_domain *pd)
344 {
345         return 0;
346 }
347
348 static int ti_power_domain_free(struct power_domain *pd)
349 {
350         return 0;
351 }
352
353 static const struct udevice_id ti_power_domain_of_match[] = {
354         { .compatible = "ti,sci-pm-domain" },
355         { /* sentinel */ }
356 };
357
358 static struct power_domain_ops ti_power_domain_ops = {
359         .on = ti_power_domain_on,
360         .off = ti_power_domain_off,
361         .of_xlate = ti_power_domain_of_xlate,
362         .request = ti_power_domain_request,
363         .rfree = ti_power_domain_free,
364 };
365
366 U_BOOT_DRIVER(ti_pm_domains) = {
367         .name = "ti-pm-domains",
368         .id = UCLASS_POWER_DOMAIN,
369         .of_match = ti_power_domain_of_match,
370         .probe = ti_power_domain_probe,
371         .priv_auto = sizeof(struct ti_k3_pd_platdata),
372         .ops = &ti_power_domain_ops,
373 };