~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-omap2/prm33xx.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php