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