Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
139563ad PW |
2 | /* |
3 | * OMAP3xxx PRM module functions | |
4 | * | |
5 | * Copyright (C) 2010-2012 Texas Instruments, Inc. | |
6 | * Copyright (C) 2010 Nokia Corporation | |
7 | * Benoît Cousson | |
8 | * Paul Walmsley | |
49815399 | 9 | * Rajendra Nayak <rnayak@ti.com> |
139563ad PW |
10 | */ |
11 | ||
12 | #include <linux/kernel.h> | |
13 | #include <linux/errno.h> | |
14 | #include <linux/err.h> | |
15 | #include <linux/io.h> | |
16 | #include <linux/irq.h> | |
1e037794 | 17 | #include <linux/of_irq.h> |
139563ad | 18 | |
e8d3d47a | 19 | #include "soc.h" |
139563ad | 20 | #include "common.h" |
139563ad | 21 | #include "vp.h" |
49815399 | 22 | #include "powerdomain.h" |
139563ad | 23 | #include "prm3xxx.h" |
49815399 | 24 | #include "prm2xxx_3xxx.h" |
139563ad PW |
25 | #include "cm2xxx_3xxx.h" |
26 | #include "prm-regbits-34xx.h" | |
0efc0f6e TK |
27 | #include "cm3xxx.h" |
28 | #include "cm-regbits-34xx.h" | |
ae521d4d | 29 | #include "clock.h" |
139563ad | 30 | |
c8e069d7 TK |
31 | static void omap3xxx_prm_read_pending_irqs(unsigned long *events); |
32 | static void omap3xxx_prm_ocp_barrier(void); | |
33 | static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); | |
34 | static void omap3xxx_prm_restore_irqen(u32 *saved_mask); | |
6aeb51c1 | 35 | static void omap3xxx_prm_iva_idle(void); |
c8e069d7 | 36 | |
139563ad PW |
37 | static const struct omap_prcm_irq omap3_prcm_irqs[] = { |
38 | OMAP_PRCM_IRQ("wkup", 0, 0), | |
39 | OMAP_PRCM_IRQ("io", 9, 1), | |
40 | }; | |
41 | ||
42 | static struct omap_prcm_irq_setup omap3_prcm_irq_setup = { | |
43 | .ack = OMAP3_PRM_IRQSTATUS_MPU_OFFSET, | |
44 | .mask = OMAP3_PRM_IRQENABLE_MPU_OFFSET, | |
45 | .nr_regs = 1, | |
46 | .irqs = omap3_prcm_irqs, | |
47 | .nr_irqs = ARRAY_SIZE(omap3_prcm_irqs), | |
48 | .irq = 11 + OMAP_INTC_START, | |
49 | .read_pending_irqs = &omap3xxx_prm_read_pending_irqs, | |
50 | .ocp_barrier = &omap3xxx_prm_ocp_barrier, | |
51 | .save_and_clear_irqen = &omap3xxx_prm_save_and_clear_irqen, | |
52 | .restore_irqen = &omap3xxx_prm_restore_irqen, | |
7db143b8 | 53 | .reconfigure_io_chain = NULL, |
139563ad PW |
54 | }; |
55 | ||
2bb2a5d3 PW |
56 | /* |
57 | * omap3_prm_reset_src_map - map from bits in the PRM_RSTST hardware | |
58 | * register (which are specific to OMAP3xxx SoCs) to reset source ID | |
59 | * bit shifts (which is an OMAP SoC-independent enumeration) | |
60 | */ | |
61 | static struct prm_reset_src_map omap3xxx_prm_reset_src_map[] = { | |
62 | { OMAP3430_GLOBAL_COLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT }, | |
63 | { OMAP3430_GLOBAL_SW_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT }, | |
64 | { OMAP3430_SECURITY_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT }, | |
65 | { OMAP3430_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, | |
66 | { OMAP3430_SECURE_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, | |
67 | { OMAP3430_EXTERNAL_WARM_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT }, | |
68 | { OMAP3430_VDD1_VOLTAGE_MANAGER_RST_SHIFT, | |
69 | OMAP_VDD_MPU_VM_RST_SRC_ID_SHIFT }, | |
70 | { OMAP3430_VDD2_VOLTAGE_MANAGER_RST_SHIFT, | |
71 | OMAP_VDD_CORE_VM_RST_SRC_ID_SHIFT }, | |
72 | { OMAP3430_ICEPICK_RST_SHIFT, OMAP_ICEPICK_RST_SRC_ID_SHIFT }, | |
73 | { OMAP3430_ICECRUSHER_RST_SHIFT, OMAP_ICECRUSHER_RST_SRC_ID_SHIFT }, | |
74 | { -1, -1 }, | |
75 | }; | |
76 | ||
139563ad PW |
77 | /* PRM VP */ |
78 | ||
79 | /* | |
80 | * struct omap3_vp - OMAP3 VP register access description. | |
81 | * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg | |
82 | */ | |
83 | struct omap3_vp { | |
84 | u32 tranxdone_status; | |
85 | }; | |
86 | ||
87 | static struct omap3_vp omap3_vp[] = { | |
88 | [OMAP3_VP_VDD_MPU_ID] = { | |
89 | .tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK, | |
90 | }, | |
91 | [OMAP3_VP_VDD_CORE_ID] = { | |
92 | .tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK, | |
93 | }, | |
94 | }; | |
95 | ||
96 | #define MAX_VP_ID ARRAY_SIZE(omap3_vp); | |
97 | ||
e9f1ddcd | 98 | static u32 omap3_prm_vp_check_txdone(u8 vp_id) |
139563ad PW |
99 | { |
100 | struct omap3_vp *vp = &omap3_vp[vp_id]; | |
101 | u32 irqstatus; | |
102 | ||
103 | irqstatus = omap2_prm_read_mod_reg(OCP_MOD, | |
104 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
105 | return irqstatus & vp->tranxdone_status; | |
106 | } | |
107 | ||
e9f1ddcd | 108 | static void omap3_prm_vp_clear_txdone(u8 vp_id) |
139563ad PW |
109 | { |
110 | struct omap3_vp *vp = &omap3_vp[vp_id]; | |
111 | ||
112 | omap2_prm_write_mod_reg(vp->tranxdone_status, | |
113 | OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
114 | } | |
115 | ||
116 | u32 omap3_prm_vcvp_read(u8 offset) | |
117 | { | |
118 | return omap2_prm_read_mod_reg(OMAP3430_GR_MOD, offset); | |
119 | } | |
120 | ||
121 | void omap3_prm_vcvp_write(u32 val, u8 offset) | |
122 | { | |
123 | omap2_prm_write_mod_reg(val, OMAP3430_GR_MOD, offset); | |
124 | } | |
125 | ||
126 | u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) | |
127 | { | |
128 | return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset); | |
129 | } | |
130 | ||
d08cce6a PW |
131 | /** |
132 | * omap3xxx_prm_dpll3_reset - use DPLL3 reset to reboot the OMAP SoC | |
133 | * | |
134 | * Set the DPLL3 reset bit, which should reboot the SoC. This is the | |
135 | * recommended way to restart the SoC, considering Errata i520. No | |
136 | * return value. | |
137 | */ | |
61c8621e | 138 | static void omap3xxx_prm_dpll3_reset(void) |
d08cce6a PW |
139 | { |
140 | omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, OMAP3430_GR_MOD, | |
141 | OMAP2_RM_RSTCTRL); | |
142 | /* OCP barrier */ | |
143 | omap2_prm_read_mod_reg(OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL); | |
144 | } | |
145 | ||
139563ad PW |
146 | /** |
147 | * omap3xxx_prm_read_pending_irqs - read pending PRM MPU IRQs into @events | |
148 | * @events: ptr to a u32, preallocated by caller | |
149 | * | |
150 | * Read PRM_IRQSTATUS_MPU bits, AND'ed with the currently-enabled PRM | |
151 | * MPU IRQs, and store the result into the u32 pointed to by @events. | |
152 | * No return value. | |
153 | */ | |
c8e069d7 | 154 | static void omap3xxx_prm_read_pending_irqs(unsigned long *events) |
139563ad PW |
155 | { |
156 | u32 mask, st; | |
157 | ||
158 | /* XXX Can the mask read be avoided (e.g., can it come from RAM?) */ | |
159 | mask = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
160 | st = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
161 | ||
162 | events[0] = mask & st; | |
163 | } | |
164 | ||
165 | /** | |
166 | * omap3xxx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete | |
167 | * | |
168 | * Force any buffered writes to the PRM IP block to complete. Needed | |
169 | * by the PRM IRQ handler, which reads and writes directly to the IP | |
170 | * block, to avoid race conditions after acknowledging or clearing IRQ | |
171 | * bits. No return value. | |
172 | */ | |
c8e069d7 | 173 | static void omap3xxx_prm_ocp_barrier(void) |
139563ad PW |
174 | { |
175 | omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); | |
176 | } | |
177 | ||
178 | /** | |
179 | * omap3xxx_prm_save_and_clear_irqen - save/clear PRM_IRQENABLE_MPU reg | |
180 | * @saved_mask: ptr to a u32 array to save IRQENABLE bits | |
181 | * | |
182 | * Save the PRM_IRQENABLE_MPU register to @saved_mask. @saved_mask | |
183 | * must be allocated by the caller. Intended to be used in the PRM | |
184 | * interrupt handler suspend callback. The OCP barrier is needed to | |
185 | * ensure the write to disable PRM interrupts reaches the PRM before | |
186 | * returning; otherwise, spurious interrupts might occur. No return | |
187 | * value. | |
188 | */ | |
c8e069d7 | 189 | static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) |
139563ad PW |
190 | { |
191 | saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD, | |
192 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
193 | omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
194 | ||
195 | /* OCP barrier */ | |
196 | omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); | |
197 | } | |
198 | ||
199 | /** | |
200 | * omap3xxx_prm_restore_irqen - set PRM_IRQENABLE_MPU register from args | |
201 | * @saved_mask: ptr to a u32 array of IRQENABLE bits saved previously | |
202 | * | |
203 | * Restore the PRM_IRQENABLE_MPU register from @saved_mask. Intended | |
204 | * to be used in the PRM interrupt handler resume callback to restore | |
205 | * values saved by omap3xxx_prm_save_and_clear_irqen(). No OCP | |
206 | * barrier should be needed here; any pending PRM interrupts will fire | |
207 | * once the writes reach the PRM. No return value. | |
208 | */ | |
c8e069d7 | 209 | static void omap3xxx_prm_restore_irqen(u32 *saved_mask) |
139563ad PW |
210 | { |
211 | omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, | |
212 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
213 | } | |
214 | ||
0efc0f6e TK |
215 | /** |
216 | * omap3xxx_prm_clear_mod_irqs - clear wake-up events from PRCM interrupt | |
217 | * @module: PRM module to clear wakeups from | |
218 | * @regs: register set to clear, 1 or 3 | |
f0caa527 | 219 | * @wkst_mask: wkst bits to clear |
0efc0f6e TK |
220 | * |
221 | * The purpose of this function is to clear any wake-up events latched | |
222 | * in the PRCM PM_WKST_x registers. It is possible that a wake-up event | |
223 | * may occur whilst attempting to clear a PM_WKST_x register and thus | |
224 | * set another bit in this register. A while loop is used to ensure | |
225 | * that any peripheral wake-up events occurring while attempting to | |
226 | * clear the PM_WKST_x are detected and cleared. | |
227 | */ | |
9cb6d363 | 228 | static int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) |
0efc0f6e TK |
229 | { |
230 | u32 wkst, fclk, iclk, clken; | |
231 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; | |
232 | u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1; | |
233 | u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1; | |
234 | u16 grpsel_off = (regs == 3) ? | |
235 | OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL; | |
236 | int c = 0; | |
237 | ||
238 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | |
239 | wkst &= omap2_prm_read_mod_reg(module, grpsel_off); | |
f0caa527 | 240 | wkst &= wkst_mask; |
0efc0f6e TK |
241 | if (wkst) { |
242 | iclk = omap2_cm_read_mod_reg(module, iclk_off); | |
243 | fclk = omap2_cm_read_mod_reg(module, fclk_off); | |
244 | while (wkst) { | |
245 | clken = wkst; | |
246 | omap2_cm_set_mod_reg_bits(clken, module, iclk_off); | |
247 | /* | |
248 | * For USBHOST, we don't know whether HOST1 or | |
249 | * HOST2 woke us up, so enable both f-clocks | |
250 | */ | |
251 | if (module == OMAP3430ES2_USBHOST_MOD) | |
252 | clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT; | |
253 | omap2_cm_set_mod_reg_bits(clken, module, fclk_off); | |
254 | omap2_prm_write_mod_reg(wkst, module, wkst_off); | |
255 | wkst = omap2_prm_read_mod_reg(module, wkst_off); | |
f0caa527 | 256 | wkst &= wkst_mask; |
0efc0f6e TK |
257 | c++; |
258 | } | |
259 | omap2_cm_write_mod_reg(iclk, module, iclk_off); | |
260 | omap2_cm_write_mod_reg(fclk, module, fclk_off); | |
261 | } | |
262 | ||
263 | return c; | |
264 | } | |
265 | ||
55c6c3ad TK |
266 | /** |
267 | * omap3_prm_reset_modem - toggle reset signal for modem | |
268 | * | |
269 | * Toggles the reset signal to modem IP block. Required to allow | |
270 | * OMAP3430 without stacked modem to idle properly. | |
271 | */ | |
6aeb51c1 | 272 | static void __init omap3_prm_reset_modem(void) |
55c6c3ad TK |
273 | { |
274 | omap2_prm_write_mod_reg( | |
275 | OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON_MASK | | |
276 | OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST_MASK, | |
277 | CORE_MOD, OMAP2_RM_RSTCTRL); | |
278 | omap2_prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL); | |
279 | } | |
280 | ||
c5180a2b TK |
281 | /** |
282 | * omap3_prm_init_pm - initialize PM related registers for PRM | |
283 | * @has_uart4: SoC has UART4 | |
284 | * @has_iva: SoC has IVA | |
285 | * | |
286 | * Initializes PRM registers for PM use. Called from PM init. | |
287 | */ | |
288 | void __init omap3_prm_init_pm(bool has_uart4, bool has_iva) | |
289 | { | |
290 | u32 en_uart4_mask; | |
291 | u32 grpsel_uart4_mask; | |
292 | ||
293 | /* | |
294 | * Enable control of expternal oscillator through | |
295 | * sys_clkreq. In the long run clock framework should | |
296 | * take care of this. | |
297 | */ | |
298 | omap2_prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, | |
299 | 1 << OMAP_AUTOEXTCLKMODE_SHIFT, | |
300 | OMAP3430_GR_MOD, | |
301 | OMAP3_PRM_CLKSRC_CTRL_OFFSET); | |
302 | ||
303 | /* setup wakup source */ | |
304 | omap2_prm_write_mod_reg(OMAP3430_EN_IO_MASK | OMAP3430_EN_GPIO1_MASK | | |
305 | OMAP3430_EN_GPT1_MASK | OMAP3430_EN_GPT12_MASK, | |
306 | WKUP_MOD, PM_WKEN); | |
307 | /* No need to write EN_IO, that is always enabled */ | |
308 | omap2_prm_write_mod_reg(OMAP3430_GRPSEL_GPIO1_MASK | | |
309 | OMAP3430_GRPSEL_GPT1_MASK | | |
310 | OMAP3430_GRPSEL_GPT12_MASK, | |
311 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); | |
312 | ||
313 | /* Enable PM_WKEN to support DSS LPR */ | |
314 | omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK, | |
315 | OMAP3430_DSS_MOD, PM_WKEN); | |
316 | ||
317 | if (has_uart4) { | |
318 | en_uart4_mask = OMAP3630_EN_UART4_MASK; | |
319 | grpsel_uart4_mask = OMAP3630_GRPSEL_UART4_MASK; | |
4ae46efc CIK |
320 | } else { |
321 | en_uart4_mask = 0; | |
322 | grpsel_uart4_mask = 0; | |
c5180a2b TK |
323 | } |
324 | ||
325 | /* Enable wakeups in PER */ | |
326 | omap2_prm_write_mod_reg(en_uart4_mask | | |
327 | OMAP3430_EN_GPIO2_MASK | | |
328 | OMAP3430_EN_GPIO3_MASK | | |
329 | OMAP3430_EN_GPIO4_MASK | | |
330 | OMAP3430_EN_GPIO5_MASK | | |
331 | OMAP3430_EN_GPIO6_MASK | | |
332 | OMAP3430_EN_UART3_MASK | | |
333 | OMAP3430_EN_MCBSP2_MASK | | |
334 | OMAP3430_EN_MCBSP3_MASK | | |
335 | OMAP3430_EN_MCBSP4_MASK, | |
336 | OMAP3430_PER_MOD, PM_WKEN); | |
337 | ||
338 | /* and allow them to wake up MPU */ | |
339 | omap2_prm_write_mod_reg(grpsel_uart4_mask | | |
340 | OMAP3430_GRPSEL_GPIO2_MASK | | |
341 | OMAP3430_GRPSEL_GPIO3_MASK | | |
342 | OMAP3430_GRPSEL_GPIO4_MASK | | |
343 | OMAP3430_GRPSEL_GPIO5_MASK | | |
344 | OMAP3430_GRPSEL_GPIO6_MASK | | |
345 | OMAP3430_GRPSEL_UART3_MASK | | |
346 | OMAP3430_GRPSEL_MCBSP2_MASK | | |
347 | OMAP3430_GRPSEL_MCBSP3_MASK | | |
348 | OMAP3430_GRPSEL_MCBSP4_MASK, | |
349 | OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); | |
350 | ||
351 | /* Don't attach IVA interrupts */ | |
352 | if (has_iva) { | |
353 | omap2_prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL); | |
354 | omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1); | |
355 | omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); | |
356 | omap2_prm_write_mod_reg(0, OMAP3430_PER_MOD, | |
357 | OMAP3430_PM_IVAGRPSEL); | |
358 | } | |
359 | ||
360 | /* Clear any pending 'reset' flags */ | |
361 | omap2_prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST); | |
362 | omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST); | |
363 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST); | |
364 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST); | |
365 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST); | |
366 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST); | |
367 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, | |
368 | OMAP2_RM_RSTST); | |
369 | ||
370 | /* Clear any pending PRCM interrupts */ | |
371 | omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
c2148e59 TK |
372 | |
373 | /* We need to idle iva2_pwrdm even on am3703 with no iva2. */ | |
374 | omap3xxx_prm_iva_idle(); | |
375 | ||
c2148e59 | 376 | omap3_prm_reset_modem(); |
c5180a2b TK |
377 | } |
378 | ||
139563ad | 379 | /** |
7db143b8 TL |
380 | * omap3430_pre_es3_1_reconfigure_io_chain - restart wake-up daisy chain |
381 | * | |
382 | * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only | |
383 | * thing we can do is toggle EN_IO bit for earlier omaps. | |
384 | */ | |
4984eeaf | 385 | static void omap3430_pre_es3_1_reconfigure_io_chain(void) |
7db143b8 TL |
386 | { |
387 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, | |
388 | PM_WKEN); | |
389 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, | |
390 | PM_WKEN); | |
391 | omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN); | |
392 | } | |
393 | ||
394 | /** | |
395 | * omap3_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain | |
139563ad PW |
396 | * |
397 | * Clear any previously-latched I/O wakeup events and ensure that the | |
398 | * I/O wakeup gates are aligned with the current mux settings. Works | |
399 | * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then | |
400 | * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No | |
7db143b8 | 401 | * return value. These registers are only available in 3430 es3.1 and later. |
139563ad | 402 | */ |
4984eeaf | 403 | static void omap3_prm_reconfigure_io_chain(void) |
139563ad PW |
404 | { |
405 | int i = 0; | |
406 | ||
407 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | |
408 | PM_WKEN); | |
409 | ||
410 | omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & | |
411 | OMAP3430_ST_IO_CHAIN_MASK, | |
412 | MAX_IOPAD_LATCH_TIME, i); | |
413 | if (i == MAX_IOPAD_LATCH_TIME) | |
414 | pr_warn("PRM: I/O chain clock line assertion timed out\n"); | |
415 | ||
416 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | |
417 | PM_WKEN); | |
418 | ||
419 | omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD, | |
420 | PM_WKST); | |
421 | ||
422 | omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST); | |
423 | } | |
424 | ||
425 | /** | |
426 | * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches | |
427 | * | |
428 | * Activates the I/O wakeup event latches and allows events logged by | |
429 | * those latches to signal a wakeup event to the PRCM. For I/O | |
430 | * wakeups to occur, WAKEUPENABLE bits must be set in the pad mux | |
431 | * registers, and omap3xxx_prm_reconfigure_io_chain() must be called. | |
432 | * No return value. | |
433 | */ | |
27e23d89 | 434 | static void omap3xxx_prm_enable_io_wakeup(void) |
139563ad | 435 | { |
2541d15f | 436 | if (prm_features & PRM_HAS_IO_WAKEUP) |
139563ad PW |
437 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, |
438 | PM_WKEN); | |
439 | } | |
440 | ||
2bb2a5d3 PW |
441 | /** |
442 | * omap3xxx_prm_read_reset_sources - return the last SoC reset source | |
443 | * | |
444 | * Return a u32 representing the last reset sources of the SoC. The | |
445 | * returned reset source bits are standardized across OMAP SoCs. | |
446 | */ | |
447 | static u32 omap3xxx_prm_read_reset_sources(void) | |
448 | { | |
449 | struct prm_reset_src_map *p; | |
450 | u32 r = 0; | |
451 | u32 v; | |
452 | ||
453 | v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST); | |
454 | ||
455 | p = omap3xxx_prm_reset_src_map; | |
456 | while (p->reg_shift >= 0 && p->std_shift >= 0) { | |
457 | if (v & (1 << p->reg_shift)) | |
458 | r |= 1 << p->std_shift; | |
459 | p++; | |
460 | } | |
461 | ||
462 | return r; | |
463 | } | |
464 | ||
9de367fa TK |
465 | /** |
466 | * omap3xxx_prm_iva_idle - ensure IVA is in idle so it can be put into retention | |
467 | * | |
468 | * In cases where IVA2 is activated by bootcode, it may prevent | |
469 | * full-chip retention or off-mode because it is not idle. This | |
470 | * function forces the IVA2 into idle state so it can go | |
471 | * into retention/off and thus allow full-chip retention/off. | |
472 | */ | |
6aeb51c1 | 473 | static void omap3xxx_prm_iva_idle(void) |
9de367fa TK |
474 | { |
475 | /* ensure IVA2 clock is disabled */ | |
476 | omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); | |
477 | ||
478 | /* if no clock activity, nothing else to do */ | |
479 | if (!(omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) & | |
480 | OMAP3430_CLKACTIVITY_IVA2_MASK)) | |
481 | return; | |
482 | ||
483 | /* Reset IVA2 */ | |
484 | omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK | | |
485 | OMAP3430_RST2_IVA2_MASK | | |
486 | OMAP3430_RST3_IVA2_MASK, | |
487 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | |
488 | ||
489 | /* Enable IVA2 clock */ | |
490 | omap2_cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK, | |
491 | OMAP3430_IVA2_MOD, CM_FCLKEN); | |
492 | ||
9de367fa TK |
493 | /* Un-reset IVA2 */ |
494 | omap2_prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | |
495 | ||
496 | /* Disable IVA2 clock */ | |
497 | omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); | |
498 | ||
499 | /* Reset IVA2 */ | |
500 | omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK | | |
501 | OMAP3430_RST2_IVA2_MASK | | |
502 | OMAP3430_RST3_IVA2_MASK, | |
503 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | |
504 | } | |
505 | ||
9efcea09 TK |
506 | /** |
507 | * omap3xxx_prm_clear_global_cold_reset - checks the global cold reset status | |
508 | * and clears it if asserted | |
509 | * | |
510 | * Checks if cold-reset has occurred and clears the status bit if yes. Returns | |
511 | * 1 if cold-reset has occurred, 0 otherwise. | |
512 | */ | |
513 | int omap3xxx_prm_clear_global_cold_reset(void) | |
514 | { | |
515 | if (omap2_prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) & | |
516 | OMAP3430_GLOBAL_COLD_RST_MASK) { | |
517 | omap2_prm_set_mod_reg_bits(OMAP3430_GLOBAL_COLD_RST_MASK, | |
518 | OMAP3430_GR_MOD, | |
519 | OMAP3_PRM_RSTST_OFFSET); | |
520 | return 1; | |
521 | } | |
522 | ||
523 | return 0; | |
524 | } | |
525 | ||
7e28b465 TK |
526 | void omap3_prm_save_scratchpad_contents(u32 *ptr) |
527 | { | |
528 | *ptr++ = omap2_prm_read_mod_reg(OMAP3430_GR_MOD, | |
529 | OMAP3_PRM_CLKSRC_CTRL_OFFSET); | |
530 | ||
531 | *ptr++ = omap2_prm_read_mod_reg(OMAP3430_GR_MOD, | |
532 | OMAP3_PRM_CLKSEL_OFFSET); | |
533 | } | |
534 | ||
49815399 PW |
535 | /* Powerdomain low-level functions */ |
536 | ||
7e7fff82 PW |
537 | static int omap3_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) |
538 | { | |
539 | omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, | |
540 | (pwrst << OMAP_POWERSTATE_SHIFT), | |
541 | pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); | |
542 | return 0; | |
543 | } | |
544 | ||
545 | static int omap3_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) | |
546 | { | |
547 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
548 | OMAP2_PM_PWSTCTRL, | |
549 | OMAP_POWERSTATE_MASK); | |
550 | } | |
551 | ||
552 | static int omap3_pwrdm_read_pwrst(struct powerdomain *pwrdm) | |
553 | { | |
554 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
555 | OMAP2_PM_PWSTST, | |
556 | OMAP_POWERSTATEST_MASK); | |
557 | } | |
558 | ||
49815399 PW |
559 | /* Applicable only for OMAP3. Not supported on OMAP2 */ |
560 | static int omap3_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) | |
561 | { | |
562 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
563 | OMAP3430_PM_PREPWSTST, | |
564 | OMAP3430_LASTPOWERSTATEENTERED_MASK); | |
565 | } | |
566 | ||
567 | static int omap3_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) | |
568 | { | |
569 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
570 | OMAP2_PM_PWSTST, | |
571 | OMAP3430_LOGICSTATEST_MASK); | |
572 | } | |
573 | ||
574 | static int omap3_pwrdm_read_logic_retst(struct powerdomain *pwrdm) | |
575 | { | |
576 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
577 | OMAP2_PM_PWSTCTRL, | |
578 | OMAP3430_LOGICSTATEST_MASK); | |
579 | } | |
580 | ||
581 | static int omap3_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm) | |
582 | { | |
583 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
584 | OMAP3430_PM_PREPWSTST, | |
585 | OMAP3430_LASTLOGICSTATEENTERED_MASK); | |
586 | } | |
587 | ||
588 | static int omap3_get_mem_bank_lastmemst_mask(u8 bank) | |
589 | { | |
590 | switch (bank) { | |
591 | case 0: | |
592 | return OMAP3430_LASTMEM1STATEENTERED_MASK; | |
593 | case 1: | |
594 | return OMAP3430_LASTMEM2STATEENTERED_MASK; | |
595 | case 2: | |
596 | return OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK; | |
597 | case 3: | |
598 | return OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK; | |
599 | default: | |
600 | WARN_ON(1); /* should never happen */ | |
601 | return -EEXIST; | |
602 | } | |
603 | return 0; | |
604 | } | |
605 | ||
606 | static int omap3_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank) | |
607 | { | |
608 | u32 m; | |
609 | ||
610 | m = omap3_get_mem_bank_lastmemst_mask(bank); | |
611 | ||
612 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
613 | OMAP3430_PM_PREPWSTST, m); | |
614 | } | |
615 | ||
616 | static int omap3_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) | |
617 | { | |
618 | omap2_prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST); | |
619 | return 0; | |
620 | } | |
621 | ||
622 | static int omap3_pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm) | |
623 | { | |
624 | return omap2_prm_rmw_mod_reg_bits(0, | |
625 | 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, | |
626 | pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); | |
627 | } | |
628 | ||
629 | static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm) | |
630 | { | |
631 | return omap2_prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, | |
632 | 0, pwrdm->prcm_offs, | |
633 | OMAP2_PM_PWSTCTRL); | |
634 | } | |
635 | ||
636 | struct pwrdm_ops omap3_pwrdm_operations = { | |
7e7fff82 PW |
637 | .pwrdm_set_next_pwrst = omap3_pwrdm_set_next_pwrst, |
638 | .pwrdm_read_next_pwrst = omap3_pwrdm_read_next_pwrst, | |
639 | .pwrdm_read_pwrst = omap3_pwrdm_read_pwrst, | |
49815399 PW |
640 | .pwrdm_read_prev_pwrst = omap3_pwrdm_read_prev_pwrst, |
641 | .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, | |
642 | .pwrdm_read_logic_pwrst = omap3_pwrdm_read_logic_pwrst, | |
643 | .pwrdm_read_logic_retst = omap3_pwrdm_read_logic_retst, | |
644 | .pwrdm_read_prev_logic_pwrst = omap3_pwrdm_read_prev_logic_pwrst, | |
645 | .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, | |
646 | .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst, | |
647 | .pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst, | |
648 | .pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst, | |
649 | .pwrdm_read_prev_mem_pwrst = omap3_pwrdm_read_prev_mem_pwrst, | |
650 | .pwrdm_clear_all_prev_pwrst = omap3_pwrdm_clear_all_prev_pwrst, | |
651 | .pwrdm_enable_hdwr_sar = omap3_pwrdm_enable_hdwr_sar, | |
652 | .pwrdm_disable_hdwr_sar = omap3_pwrdm_disable_hdwr_sar, | |
653 | .pwrdm_wait_transition = omap2_pwrdm_wait_transition, | |
654 | }; | |
655 | ||
656 | /* | |
657 | * | |
658 | */ | |
659 | ||
b550e47f TK |
660 | static int omap3xxx_prm_late_init(void); |
661 | ||
2bb2a5d3 PW |
662 | static struct prm_ll_data omap3xxx_prm_ll_data = { |
663 | .read_reset_sources = &omap3xxx_prm_read_reset_sources, | |
b550e47f | 664 | .late_init = &omap3xxx_prm_late_init, |
efd44dc3 | 665 | .assert_hardreset = &omap2_prm_assert_hardreset, |
37fb59d7 | 666 | .deassert_hardreset = &omap2_prm_deassert_hardreset, |
1bc28b34 | 667 | .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, |
61c8621e | 668 | .reset_system = &omap3xxx_prm_dpll3_reset, |
9cb6d363 | 669 | .clear_mod_irqs = &omap3xxx_prm_clear_mod_irqs, |
e9f1ddcd TK |
670 | .vp_check_txdone = &omap3_prm_vp_check_txdone, |
671 | .vp_clear_txdone = &omap3_prm_vp_clear_txdone, | |
2bb2a5d3 PW |
672 | }; |
673 | ||
ab7b2ffc | 674 | int __init omap3xxx_prm_init(const struct omap_prcm_init_data *data) |
63a293e0 | 675 | { |
ae521d4d | 676 | omap2_clk_legacy_provider_init(TI_CLKM_PRM, |
90129336 | 677 | prm_base.va + OMAP3430_IVA2_MOD); |
2541d15f TK |
678 | if (omap3_has_io_wakeup()) |
679 | prm_features |= PRM_HAS_IO_WAKEUP; | |
63a293e0 PW |
680 | |
681 | return prm_register(&omap3xxx_prm_ll_data); | |
682 | } | |
683 | ||
444d2d33 | 684 | static const struct of_device_id omap3_prm_dt_match_table[] = { |
1e037794 NM |
685 | { .compatible = "ti,omap3-prm" }, |
686 | { } | |
687 | }; | |
688 | ||
ea351c16 | 689 | static int omap3xxx_prm_late_init(void) |
139563ad | 690 | { |
2a26d31b TL |
691 | struct device_node *np; |
692 | int irq_num; | |
139563ad | 693 | |
2541d15f | 694 | if (!(prm_features & PRM_HAS_IO_WAKEUP)) |
139563ad PW |
695 | return 0; |
696 | ||
7db143b8 TL |
697 | if (omap3_has_io_chain_ctrl()) |
698 | omap3_prcm_irq_setup.reconfigure_io_chain = | |
699 | omap3_prm_reconfigure_io_chain; | |
700 | else | |
701 | omap3_prcm_irq_setup.reconfigure_io_chain = | |
702 | omap3430_pre_es3_1_reconfigure_io_chain; | |
703 | ||
2a26d31b | 704 | np = of_find_matching_node(NULL, omap3_prm_dt_match_table); |
82e5051b TL |
705 | if (!np) { |
706 | pr_err("PRM: no device tree node for interrupt?\n"); | |
707 | ||
708 | return -ENODEV; | |
1e037794 NM |
709 | } |
710 | ||
82e5051b | 711 | irq_num = of_irq_get(np, 0); |
942228fb | 712 | of_node_put(np); |
82e5051b TL |
713 | if (irq_num == -EPROBE_DEFER) |
714 | return irq_num; | |
715 | ||
716 | omap3_prcm_irq_setup.irq = irq_num; | |
717 | ||
139563ad | 718 | omap3xxx_prm_enable_io_wakeup(); |
139563ad | 719 | |
324dd7a6 | 720 | return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); |
139563ad | 721 | } |
2bb2a5d3 PW |
722 | |
723 | static void __exit omap3xxx_prm_exit(void) | |
724 | { | |
d8871cd2 | 725 | prm_unregister(&omap3xxx_prm_ll_data); |
2bb2a5d3 PW |
726 | } |
727 | __exitcall(omap3xxx_prm_exit); |