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