GNU Linux-libre 6.7.9-gnu
[releases.git] / arch / arm / mach-omap2 / prm33xx.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * AM33XX PRM functions
4  *
5  * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/types.h>
10 #include <linux/errno.h>
11 #include <linux/err.h>
12 #include <linux/io.h>
13
14 #include "powerdomain.h"
15 #include "prm33xx.h"
16 #include "prm-regbits-33xx.h"
17
18 #define AM33XX_PRM_RSTCTRL_OFFSET               0x0000
19
20 #define AM33XX_RST_GLOBAL_WARM_SW_MASK          (1 << 0)
21
22 /* Read a register in a PRM instance */
23 static u32 am33xx_prm_read_reg(s16 inst, u16 idx)
24 {
25         return readl_relaxed(prm_base.va + inst + idx);
26 }
27
28 /* Write into a register in a PRM instance */
29 static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx)
30 {
31         writel_relaxed(val, prm_base.va + inst + idx);
32 }
33
34 /* Read-modify-write a register in PRM. Caller must lock */
35 static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
36 {
37         u32 v;
38
39         v = am33xx_prm_read_reg(inst, idx);
40         v &= ~mask;
41         v |= bits;
42         am33xx_prm_write_reg(v, inst, idx);
43
44         return v;
45 }
46
47 /**
48  * am33xx_prm_is_hardreset_asserted - read the HW reset line state of
49  * submodules contained in the hwmod module
50  * @shift: register bit shift corresponding to the reset line to check
51  * @part: PRM partition, ignored for AM33xx
52  * @inst: CM instance register offset (*_INST macro)
53  * @rstctrl_offs: RM_RSTCTRL register address offset for this module
54  *
55  * Returns 1 if the (sub)module hardreset line is currently asserted,
56  * 0 if the (sub)module hardreset line is not currently asserted, or
57  * -EINVAL upon parameter error.
58  */
59 static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
60                                             u16 rstctrl_offs)
61 {
62         u32 v;
63
64         v = am33xx_prm_read_reg(inst, rstctrl_offs);
65         v &= 1 << shift;
66         v >>= shift;
67
68         return v;
69 }
70
71 /**
72  * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule
73  * @shift: register bit shift corresponding to the reset line to assert
74  * @part: CM partition, ignored for AM33xx
75  * @inst: CM instance register offset (*_INST macro)
76  * @rstctrl_reg: RM_RSTCTRL register address for this module
77  *
78  * Some IPs like dsp, ipu or iva contain processors that require an HW
79  * reset line to be asserted / deasserted in order to fully enable the
80  * IP.  These modules may have multiple hard-reset lines that reset
81  * different 'submodules' inside the IP block.  This function will
82  * place the submodule into reset.  Returns 0 upon success or -EINVAL
83  * upon an argument error.
84  */
85 static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst,
86                                        u16 rstctrl_offs)
87 {
88         u32 mask = 1 << shift;
89
90         am33xx_prm_rmw_reg_bits(mask, mask, inst, rstctrl_offs);
91
92         return 0;
93 }
94
95 /**
96  * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and
97  * wait
98  * @shift: register bit shift corresponding to the reset line to deassert
99  * @st_shift: reset status register bit shift corresponding to the reset line
100  * @part: PRM partition, not used for AM33xx
101  * @inst: CM instance register offset (*_INST macro)
102  * @rstctrl_reg: RM_RSTCTRL register address for this module
103  * @rstst_reg: RM_RSTST register address for this module
104  *
105  * Some IPs like dsp, ipu or iva contain processors that require an HW
106  * reset line to be asserted / deasserted in order to fully enable the
107  * IP.  These modules may have multiple hard-reset lines that reset
108  * different 'submodules' inside the IP block.  This function will
109  * take the submodule out of reset and wait until the PRCM indicates
110  * that the reset has completed before returning.  Returns 0 upon success or
111  * -EINVAL upon an argument error, -EEXIST if the submodule was already out
112  * of reset, or -EBUSY if the submodule did not exit reset promptly.
113  */
114 static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
115                                          s16 inst, u16 rstctrl_offs,
116                                          u16 rstst_offs)
117 {
118         int c;
119         u32 mask = 1 << st_shift;
120
121         /* Check the current status to avoid  de-asserting the line twice */
122         if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0)
123                 return -EEXIST;
124
125         /* Clear the reset status by writing 1 to the status bit */
126         am33xx_prm_rmw_reg_bits(0xffffffff, mask, inst, rstst_offs);
127
128         /* de-assert the reset control line */
129         mask = 1 << shift;
130
131         am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs);
132
133         /* wait the status to be set */
134         omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst,
135                                                            rstst_offs),
136                           MAX_MODULE_HARDRESET_WAIT, c);
137
138         return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
139 }
140
141 static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
142 {
143         am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK,
144                                 (pwrst << OMAP_POWERSTATE_SHIFT),
145                                 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
146         return 0;
147 }
148
149 static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
150 {
151         u32 v;
152
153         v = am33xx_prm_read_reg(pwrdm->prcm_offs,  pwrdm->pwrstctrl_offs);
154         v &= OMAP_POWERSTATE_MASK;
155         v >>= OMAP_POWERSTATE_SHIFT;
156
157         return v;
158 }
159
160 static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
161 {
162         u32 v;
163
164         v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
165         v &= OMAP_POWERSTATEST_MASK;
166         v >>= OMAP_POWERSTATEST_SHIFT;
167
168         return v;
169 }
170
171 static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
172 {
173         am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
174                                 (1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT),
175                                 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
176         return 0;
177 }
178
179 static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
180 {
181         am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK,
182                                 AM33XX_LASTPOWERSTATEENTERED_MASK,
183                                 pwrdm->prcm_offs, pwrdm->pwrstst_offs);
184         return 0;
185 }
186
187 static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
188 {
189         u32 m;
190
191         m = pwrdm->logicretstate_mask;
192         if (!m)
193                 return -EINVAL;
194
195         am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
196                                 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
197
198         return 0;
199 }
200
201 static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
202 {
203         u32 v;
204
205         v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
206         v &= AM33XX_LOGICSTATEST_MASK;
207         v >>= AM33XX_LOGICSTATEST_SHIFT;
208
209         return v;
210 }
211
212 static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
213 {
214         u32 v, m;
215
216         m = pwrdm->logicretstate_mask;
217         if (!m)
218                 return -EINVAL;
219
220         v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
221         v &= m;
222         v >>= __ffs(m);
223
224         return v;
225 }
226
227 static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
228                 u8 pwrst)
229 {
230         u32 m;
231
232         m = pwrdm->mem_on_mask[bank];
233         if (!m)
234                 return -EINVAL;
235
236         am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
237                                 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
238
239         return 0;
240 }
241
242 static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
243                                         u8 pwrst)
244 {
245         u32 m;
246
247         m = pwrdm->mem_ret_mask[bank];
248         if (!m)
249                 return -EINVAL;
250
251         am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
252                                 pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
253
254         return 0;
255 }
256
257 static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
258 {
259         u32 m, v;
260
261         m = pwrdm->mem_pwrst_mask[bank];
262         if (!m)
263                 return -EINVAL;
264
265         v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
266         v &= m;
267         v >>= __ffs(m);
268
269         return v;
270 }
271
272 static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
273 {
274         u32 m, v;
275
276         m = pwrdm->mem_retst_mask[bank];
277         if (!m)
278                 return -EINVAL;
279
280         v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
281         v &= m;
282         v >>= __ffs(m);
283
284         return v;
285 }
286
287 static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm)
288 {
289         u32 c = 0;
290
291         /*
292          * REVISIT: pwrdm_wait_transition() may be better implemented
293          * via a callback and a periodic timer check -- how long do we expect
294          * powerdomain transitions to take?
295          */
296
297         /* XXX Is this udelay() value meaningful? */
298         while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs)
299                         & OMAP_INTRANSITION_MASK) &&
300                         (c++ < PWRDM_TRANSITION_BAILOUT))
301                 udelay(1);
302
303         if (c > PWRDM_TRANSITION_BAILOUT) {
304                 pr_err("powerdomain: %s: waited too long to complete transition\n",
305                        pwrdm->name);
306                 return -EAGAIN;
307         }
308
309         pr_debug("powerdomain: completed transition in %d loops\n", c);
310
311         return 0;
312 }
313
314 static int am33xx_check_vcvp(void)
315 {
316         /* No VC/VP on am33xx devices */
317         return 0;
318 }
319
320 /**
321  * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset
322  *
323  * Immediately reboots the device through warm reset.
324  */
325 static void am33xx_prm_global_warm_sw_reset(void)
326 {
327         am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK,
328                                 AM33XX_RST_GLOBAL_WARM_SW_MASK,
329                                 AM33XX_PRM_DEVICE_MOD,
330                                 AM33XX_PRM_RSTCTRL_OFFSET);
331
332         /* OCP barrier */
333         (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD,
334                                   AM33XX_PRM_RSTCTRL_OFFSET);
335 }
336
337 static void am33xx_pwrdm_save_context(struct powerdomain *pwrdm)
338 {
339         pwrdm->context = am33xx_prm_read_reg(pwrdm->prcm_offs,
340                                                 pwrdm->pwrstctrl_offs);
341         /*
342          * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
343          * reading back a 1 indicates a request in progress.
344          */
345         pwrdm->context &= ~AM33XX_LOWPOWERSTATECHANGE_MASK;
346 }
347
348 static void am33xx_pwrdm_restore_context(struct powerdomain *pwrdm)
349 {
350         int st, ctrl;
351
352         st = am33xx_prm_read_reg(pwrdm->prcm_offs,
353                                  pwrdm->pwrstst_offs);
354
355         am33xx_prm_write_reg(pwrdm->context, pwrdm->prcm_offs,
356                              pwrdm->pwrstctrl_offs);
357
358         /* Make sure we only wait for a transition if there is one */
359         st &= OMAP_POWERSTATEST_MASK;
360         ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
361
362         if (st != ctrl)
363                 am33xx_pwrdm_wait_transition(pwrdm);
364 }
365
366 struct pwrdm_ops am33xx_pwrdm_operations = {
367         .pwrdm_set_next_pwrst           = am33xx_pwrdm_set_next_pwrst,
368         .pwrdm_read_next_pwrst          = am33xx_pwrdm_read_next_pwrst,
369         .pwrdm_read_pwrst               = am33xx_pwrdm_read_pwrst,
370         .pwrdm_set_logic_retst          = am33xx_pwrdm_set_logic_retst,
371         .pwrdm_read_logic_pwrst         = am33xx_pwrdm_read_logic_pwrst,
372         .pwrdm_read_logic_retst         = am33xx_pwrdm_read_logic_retst,
373         .pwrdm_clear_all_prev_pwrst     = am33xx_pwrdm_clear_all_prev_pwrst,
374         .pwrdm_set_lowpwrstchange       = am33xx_pwrdm_set_lowpwrstchange,
375         .pwrdm_read_mem_pwrst           = am33xx_pwrdm_read_mem_pwrst,
376         .pwrdm_read_mem_retst           = am33xx_pwrdm_read_mem_retst,
377         .pwrdm_set_mem_onst             = am33xx_pwrdm_set_mem_onst,
378         .pwrdm_set_mem_retst            = am33xx_pwrdm_set_mem_retst,
379         .pwrdm_wait_transition          = am33xx_pwrdm_wait_transition,
380         .pwrdm_has_voltdm               = am33xx_check_vcvp,
381         .pwrdm_save_context             = am33xx_pwrdm_save_context,
382         .pwrdm_restore_context          = am33xx_pwrdm_restore_context,
383 };
384
385 static struct prm_ll_data am33xx_prm_ll_data = {
386         .assert_hardreset               = am33xx_prm_assert_hardreset,
387         .deassert_hardreset             = am33xx_prm_deassert_hardreset,
388         .is_hardreset_asserted          = am33xx_prm_is_hardreset_asserted,
389         .reset_system                   = am33xx_prm_global_warm_sw_reset,
390 };
391
392 int __init am33xx_prm_init(const struct omap_prcm_init_data *data)
393 {
394         return prm_register(&am33xx_prm_ll_data);
395 }
396
397 static void __exit am33xx_prm_exit(void)
398 {
399         prm_unregister(&am33xx_prm_ll_data);
400 }
401 __exitcall(am33xx_prm_exit);