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 | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License version 2 as | |
11 | * published by the Free Software Foundation. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/errno.h> | |
16 | #include <linux/err.h> | |
17 | #include <linux/io.h> | |
18 | #include <linux/irq.h> | |
19 | ||
20 | #include "common.h" | |
21 | #include <plat/cpu.h> | |
22 | #include <plat/prcm.h> | |
23 | ||
24 | #include "vp.h" | |
25 | ||
26 | #include "prm3xxx.h" | |
27 | #include "cm2xxx_3xxx.h" | |
28 | #include "prm-regbits-34xx.h" | |
29 | ||
30 | static const struct omap_prcm_irq omap3_prcm_irqs[] = { | |
31 | OMAP_PRCM_IRQ("wkup", 0, 0), | |
32 | OMAP_PRCM_IRQ("io", 9, 1), | |
33 | }; | |
34 | ||
35 | static struct omap_prcm_irq_setup omap3_prcm_irq_setup = { | |
36 | .ack = OMAP3_PRM_IRQSTATUS_MPU_OFFSET, | |
37 | .mask = OMAP3_PRM_IRQENABLE_MPU_OFFSET, | |
38 | .nr_regs = 1, | |
39 | .irqs = omap3_prcm_irqs, | |
40 | .nr_irqs = ARRAY_SIZE(omap3_prcm_irqs), | |
41 | .irq = 11 + OMAP_INTC_START, | |
42 | .read_pending_irqs = &omap3xxx_prm_read_pending_irqs, | |
43 | .ocp_barrier = &omap3xxx_prm_ocp_barrier, | |
44 | .save_and_clear_irqen = &omap3xxx_prm_save_and_clear_irqen, | |
45 | .restore_irqen = &omap3xxx_prm_restore_irqen, | |
46 | }; | |
47 | ||
48 | /* PRM VP */ | |
49 | ||
50 | /* | |
51 | * struct omap3_vp - OMAP3 VP register access description. | |
52 | * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg | |
53 | */ | |
54 | struct omap3_vp { | |
55 | u32 tranxdone_status; | |
56 | }; | |
57 | ||
58 | static struct omap3_vp omap3_vp[] = { | |
59 | [OMAP3_VP_VDD_MPU_ID] = { | |
60 | .tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK, | |
61 | }, | |
62 | [OMAP3_VP_VDD_CORE_ID] = { | |
63 | .tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK, | |
64 | }, | |
65 | }; | |
66 | ||
67 | #define MAX_VP_ID ARRAY_SIZE(omap3_vp); | |
68 | ||
69 | u32 omap3_prm_vp_check_txdone(u8 vp_id) | |
70 | { | |
71 | struct omap3_vp *vp = &omap3_vp[vp_id]; | |
72 | u32 irqstatus; | |
73 | ||
74 | irqstatus = omap2_prm_read_mod_reg(OCP_MOD, | |
75 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
76 | return irqstatus & vp->tranxdone_status; | |
77 | } | |
78 | ||
79 | void omap3_prm_vp_clear_txdone(u8 vp_id) | |
80 | { | |
81 | struct omap3_vp *vp = &omap3_vp[vp_id]; | |
82 | ||
83 | omap2_prm_write_mod_reg(vp->tranxdone_status, | |
84 | OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
85 | } | |
86 | ||
87 | u32 omap3_prm_vcvp_read(u8 offset) | |
88 | { | |
89 | return omap2_prm_read_mod_reg(OMAP3430_GR_MOD, offset); | |
90 | } | |
91 | ||
92 | void omap3_prm_vcvp_write(u32 val, u8 offset) | |
93 | { | |
94 | omap2_prm_write_mod_reg(val, OMAP3430_GR_MOD, offset); | |
95 | } | |
96 | ||
97 | u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) | |
98 | { | |
99 | return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset); | |
100 | } | |
101 | ||
102 | /** | |
103 | * omap3xxx_prm_read_pending_irqs - read pending PRM MPU IRQs into @events | |
104 | * @events: ptr to a u32, preallocated by caller | |
105 | * | |
106 | * Read PRM_IRQSTATUS_MPU bits, AND'ed with the currently-enabled PRM | |
107 | * MPU IRQs, and store the result into the u32 pointed to by @events. | |
108 | * No return value. | |
109 | */ | |
110 | void omap3xxx_prm_read_pending_irqs(unsigned long *events) | |
111 | { | |
112 | u32 mask, st; | |
113 | ||
114 | /* XXX Can the mask read be avoided (e.g., can it come from RAM?) */ | |
115 | mask = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
116 | st = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | |
117 | ||
118 | events[0] = mask & st; | |
119 | } | |
120 | ||
121 | /** | |
122 | * omap3xxx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete | |
123 | * | |
124 | * Force any buffered writes to the PRM IP block to complete. Needed | |
125 | * by the PRM IRQ handler, which reads and writes directly to the IP | |
126 | * block, to avoid race conditions after acknowledging or clearing IRQ | |
127 | * bits. No return value. | |
128 | */ | |
129 | void omap3xxx_prm_ocp_barrier(void) | |
130 | { | |
131 | omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); | |
132 | } | |
133 | ||
134 | /** | |
135 | * omap3xxx_prm_save_and_clear_irqen - save/clear PRM_IRQENABLE_MPU reg | |
136 | * @saved_mask: ptr to a u32 array to save IRQENABLE bits | |
137 | * | |
138 | * Save the PRM_IRQENABLE_MPU register to @saved_mask. @saved_mask | |
139 | * must be allocated by the caller. Intended to be used in the PRM | |
140 | * interrupt handler suspend callback. The OCP barrier is needed to | |
141 | * ensure the write to disable PRM interrupts reaches the PRM before | |
142 | * returning; otherwise, spurious interrupts might occur. No return | |
143 | * value. | |
144 | */ | |
145 | void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) | |
146 | { | |
147 | saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD, | |
148 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
149 | omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
150 | ||
151 | /* OCP barrier */ | |
152 | omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); | |
153 | } | |
154 | ||
155 | /** | |
156 | * omap3xxx_prm_restore_irqen - set PRM_IRQENABLE_MPU register from args | |
157 | * @saved_mask: ptr to a u32 array of IRQENABLE bits saved previously | |
158 | * | |
159 | * Restore the PRM_IRQENABLE_MPU register from @saved_mask. Intended | |
160 | * to be used in the PRM interrupt handler resume callback to restore | |
161 | * values saved by omap3xxx_prm_save_and_clear_irqen(). No OCP | |
162 | * barrier should be needed here; any pending PRM interrupts will fire | |
163 | * once the writes reach the PRM. No return value. | |
164 | */ | |
165 | void omap3xxx_prm_restore_irqen(u32 *saved_mask) | |
166 | { | |
167 | omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, | |
168 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | |
169 | } | |
170 | ||
171 | /** | |
172 | * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain | |
173 | * | |
174 | * Clear any previously-latched I/O wakeup events and ensure that the | |
175 | * I/O wakeup gates are aligned with the current mux settings. Works | |
176 | * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then | |
177 | * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No | |
178 | * return value. | |
179 | */ | |
180 | void omap3xxx_prm_reconfigure_io_chain(void) | |
181 | { | |
182 | int i = 0; | |
183 | ||
184 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | |
185 | PM_WKEN); | |
186 | ||
187 | omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & | |
188 | OMAP3430_ST_IO_CHAIN_MASK, | |
189 | MAX_IOPAD_LATCH_TIME, i); | |
190 | if (i == MAX_IOPAD_LATCH_TIME) | |
191 | pr_warn("PRM: I/O chain clock line assertion timed out\n"); | |
192 | ||
193 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | |
194 | PM_WKEN); | |
195 | ||
196 | omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD, | |
197 | PM_WKST); | |
198 | ||
199 | omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST); | |
200 | } | |
201 | ||
202 | /** | |
203 | * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches | |
204 | * | |
205 | * Activates the I/O wakeup event latches and allows events logged by | |
206 | * those latches to signal a wakeup event to the PRCM. For I/O | |
207 | * wakeups to occur, WAKEUPENABLE bits must be set in the pad mux | |
208 | * registers, and omap3xxx_prm_reconfigure_io_chain() must be called. | |
209 | * No return value. | |
210 | */ | |
211 | static void __init omap3xxx_prm_enable_io_wakeup(void) | |
212 | { | |
213 | if (omap3_has_io_wakeup()) | |
214 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, | |
215 | PM_WKEN); | |
216 | } | |
217 | ||
218 | static int __init omap3xxx_prm_init(void) | |
219 | { | |
220 | int ret; | |
221 | ||
222 | if (!cpu_is_omap34xx()) | |
223 | return 0; | |
224 | ||
225 | omap3xxx_prm_enable_io_wakeup(); | |
226 | ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); | |
227 | if (!ret) | |
228 | irq_set_status_flags(omap_prcm_event_to_irq("io"), | |
229 | IRQ_NOAUTOEN); | |
230 | ||
231 | return ret; | |
232 | } | |
233 | subsys_initcall(omap3xxx_prm_init); |