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; | |
4ae46efc CIK |
322 | } else { |
323 | en_uart4_mask = 0; | |
324 | grpsel_uart4_mask = 0; | |
c5180a2b TK |
325 | } |
326 | ||
327 | /* Enable wakeups in PER */ | |
328 | omap2_prm_write_mod_reg(en_uart4_mask | | |
329 | OMAP3430_EN_GPIO2_MASK | | |
330 | OMAP3430_EN_GPIO3_MASK | | |
331 | OMAP3430_EN_GPIO4_MASK | | |
332 | OMAP3430_EN_GPIO5_MASK | | |
333 | OMAP3430_EN_GPIO6_MASK | | |
334 | OMAP3430_EN_UART3_MASK | | |
335 | OMAP3430_EN_MCBSP2_MASK | | |
336 | OMAP3430_EN_MCBSP3_MASK | | |
337 | OMAP3430_EN_MCBSP4_MASK, | |
338 | OMAP3430_PER_MOD, PM_WKEN); | |
339 | ||
340 | /* and allow them to wake up MPU */ | |
341 | omap2_prm_write_mod_reg(grpsel_uart4_mask | | |
342 | OMAP3430_GRPSEL_GPIO2_MASK | | |
343 | OMAP3430_GRPSEL_GPIO3_MASK | | |
344 | OMAP3430_GRPSEL_GPIO4_MASK | | |
345 | OMAP3430_GRPSEL_GPIO5_MASK | | |
346 | OMAP3430_GRPSEL_GPIO6_MASK | | |
347 | OMAP3430_GRPSEL_UART3_MASK | | |
348 | OMAP3430_GRPSEL_MCBSP2_MASK | | |
349 | OMAP3430_GRPSEL_MCBSP3_MASK | | |
350 | OMAP3430_GRPSEL_MCBSP4_MASK, | |
351 | OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); | |
352 | ||
353 | /* Don't attach IVA interrupts */ | |
354 | if (has_iva) { | |
355 | omap2_prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL); | |
356 | omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1); | |
357 | omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); | |
358 | omap2_prm_write_mod_reg(0, OMAP3430_PER_MOD, | |
359 | OMAP3430_PM_IVAGRPSEL); | |
360 | } | |
361 | ||
362 | /* Clear any pending 'reset' flags */ | |
363 | omap2_prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST); | |
364 | omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST); | |
365 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST); | |
366 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST); | |
367 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST); | |
368 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST); | |
369 | omap2_prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, | |
370 | OMAP2_RM_RSTST); | |
371 | ||
372 | /* Clear any pending PRCM interrupts */ | |
373 | omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
c2148e59 TK |
374 | |
375 | /* We need to idle iva2_pwrdm even on am3703 with no iva2. */ | |
376 | omap3xxx_prm_iva_idle(); | |
377 | ||
c2148e59 | 378 | omap3_prm_reset_modem(); |
c5180a2b TK |
379 | } |
380 | ||
139563ad | 381 | /** |
7db143b8 TL |
382 | * omap3430_pre_es3_1_reconfigure_io_chain - restart wake-up daisy chain |
383 | * | |
384 | * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only | |
385 | * thing we can do is toggle EN_IO bit for earlier omaps. | |
386 | */ | |
4984eeaf | 387 | static void omap3430_pre_es3_1_reconfigure_io_chain(void) |
7db143b8 TL |
388 | { |
389 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, | |
390 | PM_WKEN); | |
391 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, | |
392 | PM_WKEN); | |
393 | omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN); | |
394 | } | |
395 | ||
396 | /** | |
397 | * omap3_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain | |
139563ad PW |
398 | * |
399 | * Clear any previously-latched I/O wakeup events and ensure that the | |
400 | * I/O wakeup gates are aligned with the current mux settings. Works | |
401 | * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then | |
402 | * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No | |
7db143b8 | 403 | * return value. These registers are only available in 3430 es3.1 and later. |
139563ad | 404 | */ |
4984eeaf | 405 | static void omap3_prm_reconfigure_io_chain(void) |
139563ad PW |
406 | { |
407 | int i = 0; | |
408 | ||
409 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | |
410 | PM_WKEN); | |
411 | ||
412 | omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & | |
413 | OMAP3430_ST_IO_CHAIN_MASK, | |
414 | MAX_IOPAD_LATCH_TIME, i); | |
415 | if (i == MAX_IOPAD_LATCH_TIME) | |
416 | pr_warn("PRM: I/O chain clock line assertion timed out\n"); | |
417 | ||
418 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | |
419 | PM_WKEN); | |
420 | ||
421 | omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD, | |
422 | PM_WKST); | |
423 | ||
424 | omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST); | |
425 | } | |
426 | ||
427 | /** | |
428 | * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches | |
429 | * | |
430 | * Activates the I/O wakeup event latches and allows events logged by | |
431 | * those latches to signal a wakeup event to the PRCM. For I/O | |
432 | * wakeups to occur, WAKEUPENABLE bits must be set in the pad mux | |
433 | * registers, and omap3xxx_prm_reconfigure_io_chain() must be called. | |
434 | * No return value. | |
435 | */ | |
436 | static void __init omap3xxx_prm_enable_io_wakeup(void) | |
437 | { | |
2541d15f | 438 | if (prm_features & PRM_HAS_IO_WAKEUP) |
139563ad PW |
439 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, |
440 | PM_WKEN); | |
441 | } | |
442 | ||
2bb2a5d3 PW |
443 | /** |
444 | * omap3xxx_prm_read_reset_sources - return the last SoC reset source | |
445 | * | |
446 | * Return a u32 representing the last reset sources of the SoC. The | |
447 | * returned reset source bits are standardized across OMAP SoCs. | |
448 | */ | |
449 | static u32 omap3xxx_prm_read_reset_sources(void) | |
450 | { | |
451 | struct prm_reset_src_map *p; | |
452 | u32 r = 0; | |
453 | u32 v; | |
454 | ||
455 | v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST); | |
456 | ||
457 | p = omap3xxx_prm_reset_src_map; | |
458 | while (p->reg_shift >= 0 && p->std_shift >= 0) { | |
459 | if (v & (1 << p->reg_shift)) | |
460 | r |= 1 << p->std_shift; | |
461 | p++; | |
462 | } | |
463 | ||
464 | return r; | |
465 | } | |
466 | ||
9de367fa TK |
467 | /** |
468 | * omap3xxx_prm_iva_idle - ensure IVA is in idle so it can be put into retention | |
469 | * | |
470 | * In cases where IVA2 is activated by bootcode, it may prevent | |
471 | * full-chip retention or off-mode because it is not idle. This | |
472 | * function forces the IVA2 into idle state so it can go | |
473 | * into retention/off and thus allow full-chip retention/off. | |
474 | */ | |
475 | void omap3xxx_prm_iva_idle(void) | |
476 | { | |
477 | /* ensure IVA2 clock is disabled */ | |
478 | omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); | |
479 | ||
480 | /* if no clock activity, nothing else to do */ | |
481 | if (!(omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) & | |
482 | OMAP3430_CLKACTIVITY_IVA2_MASK)) | |
483 | return; | |
484 | ||
485 | /* Reset IVA2 */ | |
486 | omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK | | |
487 | OMAP3430_RST2_IVA2_MASK | | |
488 | OMAP3430_RST3_IVA2_MASK, | |
489 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | |
490 | ||
491 | /* Enable IVA2 clock */ | |
492 | omap2_cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK, | |
493 | OMAP3430_IVA2_MOD, CM_FCLKEN); | |
494 | ||
9de367fa TK |
495 | /* Un-reset IVA2 */ |
496 | omap2_prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | |
497 | ||
498 | /* Disable IVA2 clock */ | |
499 | omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); | |
500 | ||
501 | /* Reset IVA2 */ | |
502 | omap2_prm_write_mod_reg(OMAP3430_RST1_IVA2_MASK | | |
503 | OMAP3430_RST2_IVA2_MASK | | |
504 | OMAP3430_RST3_IVA2_MASK, | |
505 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | |
506 | } | |
507 | ||
9efcea09 TK |
508 | /** |
509 | * omap3xxx_prm_clear_global_cold_reset - checks the global cold reset status | |
510 | * and clears it if asserted | |
511 | * | |
512 | * Checks if cold-reset has occurred and clears the status bit if yes. Returns | |
513 | * 1 if cold-reset has occurred, 0 otherwise. | |
514 | */ | |
515 | int omap3xxx_prm_clear_global_cold_reset(void) | |
516 | { | |
517 | if (omap2_prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) & | |
518 | OMAP3430_GLOBAL_COLD_RST_MASK) { | |
519 | omap2_prm_set_mod_reg_bits(OMAP3430_GLOBAL_COLD_RST_MASK, | |
520 | OMAP3430_GR_MOD, | |
521 | OMAP3_PRM_RSTST_OFFSET); | |
522 | return 1; | |
523 | } | |
524 | ||
525 | return 0; | |
526 | } | |
527 | ||
7e28b465 TK |
528 | void omap3_prm_save_scratchpad_contents(u32 *ptr) |
529 | { | |
530 | *ptr++ = omap2_prm_read_mod_reg(OMAP3430_GR_MOD, | |
531 | OMAP3_PRM_CLKSRC_CTRL_OFFSET); | |
532 | ||
533 | *ptr++ = omap2_prm_read_mod_reg(OMAP3430_GR_MOD, | |
534 | OMAP3_PRM_CLKSEL_OFFSET); | |
535 | } | |
536 | ||
49815399 PW |
537 | /* Powerdomain low-level functions */ |
538 | ||
7e7fff82 PW |
539 | static int omap3_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) |
540 | { | |
541 | omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, | |
542 | (pwrst << OMAP_POWERSTATE_SHIFT), | |
543 | pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); | |
544 | return 0; | |
545 | } | |
546 | ||
547 | static int omap3_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) | |
548 | { | |
549 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
550 | OMAP2_PM_PWSTCTRL, | |
551 | OMAP_POWERSTATE_MASK); | |
552 | } | |
553 | ||
554 | static int omap3_pwrdm_read_pwrst(struct powerdomain *pwrdm) | |
555 | { | |
556 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
557 | OMAP2_PM_PWSTST, | |
558 | OMAP_POWERSTATEST_MASK); | |
559 | } | |
560 | ||
49815399 PW |
561 | /* Applicable only for OMAP3. Not supported on OMAP2 */ |
562 | static int omap3_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) | |
563 | { | |
564 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
565 | OMAP3430_PM_PREPWSTST, | |
566 | OMAP3430_LASTPOWERSTATEENTERED_MASK); | |
567 | } | |
568 | ||
569 | static int omap3_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) | |
570 | { | |
571 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
572 | OMAP2_PM_PWSTST, | |
573 | OMAP3430_LOGICSTATEST_MASK); | |
574 | } | |
575 | ||
576 | static int omap3_pwrdm_read_logic_retst(struct powerdomain *pwrdm) | |
577 | { | |
578 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
579 | OMAP2_PM_PWSTCTRL, | |
580 | OMAP3430_LOGICSTATEST_MASK); | |
581 | } | |
582 | ||
583 | static int omap3_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm) | |
584 | { | |
585 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
586 | OMAP3430_PM_PREPWSTST, | |
587 | OMAP3430_LASTLOGICSTATEENTERED_MASK); | |
588 | } | |
589 | ||
590 | static int omap3_get_mem_bank_lastmemst_mask(u8 bank) | |
591 | { | |
592 | switch (bank) { | |
593 | case 0: | |
594 | return OMAP3430_LASTMEM1STATEENTERED_MASK; | |
595 | case 1: | |
596 | return OMAP3430_LASTMEM2STATEENTERED_MASK; | |
597 | case 2: | |
598 | return OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK; | |
599 | case 3: | |
600 | return OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK; | |
601 | default: | |
602 | WARN_ON(1); /* should never happen */ | |
603 | return -EEXIST; | |
604 | } | |
605 | return 0; | |
606 | } | |
607 | ||
608 | static int omap3_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank) | |
609 | { | |
610 | u32 m; | |
611 | ||
612 | m = omap3_get_mem_bank_lastmemst_mask(bank); | |
613 | ||
614 | return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, | |
615 | OMAP3430_PM_PREPWSTST, m); | |
616 | } | |
617 | ||
618 | static int omap3_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) | |
619 | { | |
620 | omap2_prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST); | |
621 | return 0; | |
622 | } | |
623 | ||
624 | static int omap3_pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm) | |
625 | { | |
626 | return omap2_prm_rmw_mod_reg_bits(0, | |
627 | 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, | |
628 | pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); | |
629 | } | |
630 | ||
631 | static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm) | |
632 | { | |
633 | return omap2_prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, | |
634 | 0, pwrdm->prcm_offs, | |
635 | OMAP2_PM_PWSTCTRL); | |
636 | } | |
637 | ||
638 | struct pwrdm_ops omap3_pwrdm_operations = { | |
7e7fff82 PW |
639 | .pwrdm_set_next_pwrst = omap3_pwrdm_set_next_pwrst, |
640 | .pwrdm_read_next_pwrst = omap3_pwrdm_read_next_pwrst, | |
641 | .pwrdm_read_pwrst = omap3_pwrdm_read_pwrst, | |
49815399 PW |
642 | .pwrdm_read_prev_pwrst = omap3_pwrdm_read_prev_pwrst, |
643 | .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, | |
644 | .pwrdm_read_logic_pwrst = omap3_pwrdm_read_logic_pwrst, | |
645 | .pwrdm_read_logic_retst = omap3_pwrdm_read_logic_retst, | |
646 | .pwrdm_read_prev_logic_pwrst = omap3_pwrdm_read_prev_logic_pwrst, | |
647 | .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, | |
648 | .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst, | |
649 | .pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst, | |
650 | .pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst, | |
651 | .pwrdm_read_prev_mem_pwrst = omap3_pwrdm_read_prev_mem_pwrst, | |
652 | .pwrdm_clear_all_prev_pwrst = omap3_pwrdm_clear_all_prev_pwrst, | |
653 | .pwrdm_enable_hdwr_sar = omap3_pwrdm_enable_hdwr_sar, | |
654 | .pwrdm_disable_hdwr_sar = omap3_pwrdm_disable_hdwr_sar, | |
655 | .pwrdm_wait_transition = omap2_pwrdm_wait_transition, | |
656 | }; | |
657 | ||
658 | /* | |
659 | * | |
660 | */ | |
661 | ||
b550e47f TK |
662 | static int omap3xxx_prm_late_init(void); |
663 | ||
2bb2a5d3 PW |
664 | static struct prm_ll_data omap3xxx_prm_ll_data = { |
665 | .read_reset_sources = &omap3xxx_prm_read_reset_sources, | |
b550e47f | 666 | .late_init = &omap3xxx_prm_late_init, |
efd44dc3 | 667 | .assert_hardreset = &omap2_prm_assert_hardreset, |
37fb59d7 | 668 | .deassert_hardreset = &omap2_prm_deassert_hardreset, |
1bc28b34 | 669 | .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, |
61c8621e | 670 | .reset_system = &omap3xxx_prm_dpll3_reset, |
9cb6d363 | 671 | .clear_mod_irqs = &omap3xxx_prm_clear_mod_irqs, |
e9f1ddcd TK |
672 | .vp_check_txdone = &omap3_prm_vp_check_txdone, |
673 | .vp_clear_txdone = &omap3_prm_vp_clear_txdone, | |
2bb2a5d3 PW |
674 | }; |
675 | ||
ab7b2ffc | 676 | int __init omap3xxx_prm_init(const struct omap_prcm_init_data *data) |
63a293e0 | 677 | { |
ae521d4d TK |
678 | omap2_clk_legacy_provider_init(TI_CLKM_PRM, |
679 | prm_base + OMAP3430_IVA2_MOD); | |
2541d15f TK |
680 | if (omap3_has_io_wakeup()) |
681 | prm_features |= PRM_HAS_IO_WAKEUP; | |
63a293e0 PW |
682 | |
683 | return prm_register(&omap3xxx_prm_ll_data); | |
684 | } | |
685 | ||
444d2d33 | 686 | static const struct of_device_id omap3_prm_dt_match_table[] = { |
1e037794 NM |
687 | { .compatible = "ti,omap3-prm" }, |
688 | { } | |
689 | }; | |
690 | ||
ea351c16 | 691 | static int omap3xxx_prm_late_init(void) |
139563ad PW |
692 | { |
693 | int ret; | |
694 | ||
2541d15f | 695 | if (!(prm_features & PRM_HAS_IO_WAKEUP)) |
139563ad PW |
696 | return 0; |
697 | ||
7db143b8 TL |
698 | if (omap3_has_io_chain_ctrl()) |
699 | omap3_prcm_irq_setup.reconfigure_io_chain = | |
700 | omap3_prm_reconfigure_io_chain; | |
701 | else | |
702 | omap3_prcm_irq_setup.reconfigure_io_chain = | |
703 | omap3430_pre_es3_1_reconfigure_io_chain; | |
704 | ||
1e037794 NM |
705 | if (of_have_populated_dt()) { |
706 | struct device_node *np; | |
707 | int irq_num; | |
708 | ||
709 | np = of_find_matching_node(NULL, omap3_prm_dt_match_table); | |
710 | if (np) { | |
711 | irq_num = of_irq_get(np, 0); | |
712 | if (irq_num >= 0) | |
713 | omap3_prcm_irq_setup.irq = irq_num; | |
714 | } | |
715 | } | |
716 | ||
139563ad PW |
717 | omap3xxx_prm_enable_io_wakeup(); |
718 | ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); | |
719 | if (!ret) | |
720 | irq_set_status_flags(omap_prcm_event_to_irq("io"), | |
721 | IRQ_NOAUTOEN); | |
722 | ||
723 | return ret; | |
724 | } | |
2bb2a5d3 PW |
725 | |
726 | static void __exit omap3xxx_prm_exit(void) | |
727 | { | |
d8871cd2 | 728 | prm_unregister(&omap3xxx_prm_ll_data); |
2bb2a5d3 PW |
729 | } |
730 | __exitcall(omap3xxx_prm_exit); |