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