1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * OMAP2xxx PRM module functions |
4 | * |
5 | * Copyright (C) 2010-2012 Texas Instruments, Inc. |
6 | * Copyright (C) 2010 Nokia Corporation |
7 | * BenoƮt Cousson |
8 | * Paul Walmsley |
9 | * Rajendra Nayak <rnayak@ti.com> |
10 | */ |
11 | |
12 | #include <linux/kernel.h> |
13 | #include <linux/errno.h> |
14 | #include <linux/err.h> |
15 | #include <linux/io.h> |
16 | #include <linux/irq.h> |
17 | |
18 | #include "powerdomain.h" |
19 | #include "clockdomain.h" |
20 | #include "prm2xxx.h" |
21 | #include "cm2xxx_3xxx.h" |
22 | #include "prm-regbits-24xx.h" |
23 | |
24 | /* |
25 | * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits - |
26 | * these are reversed from the bits used on OMAP3+ |
27 | */ |
28 | #define OMAP24XX_PWRDM_POWER_ON 0x0 |
29 | #define OMAP24XX_PWRDM_POWER_RET 0x1 |
30 | #define OMAP24XX_PWRDM_POWER_OFF 0x3 |
31 | |
32 | /* |
33 | * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP |
34 | * hardware register (which are specific to the OMAP2xxx SoCs) to |
35 | * reset source ID bit shifts (which is an OMAP SoC-independent |
36 | * enumeration) |
37 | */ |
38 | static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = { |
39 | { OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT }, |
40 | { OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT }, |
41 | { OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT }, |
42 | { OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, |
43 | { OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT }, |
44 | { OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT }, |
45 | { -1, -1 }, |
46 | }; |
47 | |
48 | /** |
49 | * omap2xxx_prm_read_reset_sources - return the last SoC reset source |
50 | * |
51 | * Return a u32 representing the last reset sources of the SoC. The |
52 | * returned reset source bits are standardized across OMAP SoCs. |
53 | */ |
54 | static u32 omap2xxx_prm_read_reset_sources(void) |
55 | { |
56 | struct prm_reset_src_map *p; |
57 | u32 r = 0; |
58 | u32 v; |
59 | |
60 | v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST); |
61 | |
62 | p = omap2xxx_prm_reset_src_map; |
63 | while (p->reg_shift >= 0 && p->std_shift >= 0) { |
64 | if (v & (1 << p->reg_shift)) |
65 | r |= 1 << p->std_shift; |
66 | p++; |
67 | } |
68 | |
69 | return r; |
70 | } |
71 | |
72 | /** |
73 | * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst |
74 | * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert |
75 | * |
76 | * Return the common power state bits corresponding to the OMAP2xxx |
77 | * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error. |
78 | */ |
79 | static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) |
80 | { |
81 | u8 pwrst; |
82 | |
83 | switch (omap2xxx_pwrst) { |
84 | case OMAP24XX_PWRDM_POWER_OFF: |
85 | pwrst = PWRDM_POWER_OFF; |
86 | break; |
87 | case OMAP24XX_PWRDM_POWER_RET: |
88 | pwrst = PWRDM_POWER_RET; |
89 | break; |
90 | case OMAP24XX_PWRDM_POWER_ON: |
91 | pwrst = PWRDM_POWER_ON; |
92 | break; |
93 | default: |
94 | return -EINVAL; |
95 | } |
96 | |
97 | return pwrst; |
98 | } |
99 | |
100 | /** |
101 | * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC |
102 | * |
103 | * Set the DPLL reset bit, which should reboot the SoC. This is the |
104 | * recommended way to restart the SoC. No return value. |
105 | */ |
106 | static void omap2xxx_prm_dpll_reset(void) |
107 | { |
108 | omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, |
109 | OMAP2_RM_RSTCTRL); |
110 | /* OCP barrier */ |
111 | omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL); |
112 | } |
113 | |
114 | /** |
115 | * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module |
116 | * @module: PRM module to clear wakeups from |
117 | * @regs: register offset to clear |
118 | * @wkst_mask: wakeup status mask to clear |
119 | * |
120 | * Clears wakeup status bits for a given module, so that the device can |
121 | * re-enter idle. |
122 | */ |
123 | static int omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) |
124 | { |
125 | u32 wkst; |
126 | |
127 | wkst = omap2_prm_read_mod_reg(module, idx: regs); |
128 | wkst &= wkst_mask; |
129 | omap2_prm_write_mod_reg(val: wkst, module, idx: regs); |
130 | return 0; |
131 | } |
132 | |
133 | int omap2xxx_clkdm_sleep(struct clockdomain *clkdm) |
134 | { |
135 | omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, |
136 | module: clkdm->pwrdm.ptr->prcm_offs, |
137 | OMAP2_PM_PWSTCTRL); |
138 | return 0; |
139 | } |
140 | |
141 | int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm) |
142 | { |
143 | omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, |
144 | module: clkdm->pwrdm.ptr->prcm_offs, |
145 | OMAP2_PM_PWSTCTRL); |
146 | return 0; |
147 | } |
148 | |
149 | static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) |
150 | { |
151 | u8 omap24xx_pwrst; |
152 | |
153 | switch (pwrst) { |
154 | case PWRDM_POWER_OFF: |
155 | omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF; |
156 | break; |
157 | case PWRDM_POWER_RET: |
158 | omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET; |
159 | break; |
160 | case PWRDM_POWER_ON: |
161 | omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON; |
162 | break; |
163 | default: |
164 | return -EINVAL; |
165 | } |
166 | |
167 | omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, |
168 | bits: (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT), |
169 | module: pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); |
170 | return 0; |
171 | } |
172 | |
173 | static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) |
174 | { |
175 | u8 omap2xxx_pwrst; |
176 | |
177 | omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(domain: pwrdm->prcm_offs, |
178 | OMAP2_PM_PWSTCTRL, |
179 | OMAP_POWERSTATE_MASK); |
180 | |
181 | return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); |
182 | } |
183 | |
184 | static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm) |
185 | { |
186 | u8 omap2xxx_pwrst; |
187 | |
188 | omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(domain: pwrdm->prcm_offs, |
189 | OMAP2_PM_PWSTST, |
190 | OMAP_POWERSTATEST_MASK); |
191 | |
192 | return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); |
193 | } |
194 | |
195 | struct pwrdm_ops omap2_pwrdm_operations = { |
196 | .pwrdm_set_next_pwrst = omap2xxx_pwrdm_set_next_pwrst, |
197 | .pwrdm_read_next_pwrst = omap2xxx_pwrdm_read_next_pwrst, |
198 | .pwrdm_read_pwrst = omap2xxx_pwrdm_read_pwrst, |
199 | .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, |
200 | .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, |
201 | .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst, |
202 | .pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst, |
203 | .pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst, |
204 | .pwrdm_wait_transition = omap2_pwrdm_wait_transition, |
205 | }; |
206 | |
207 | /* |
208 | * |
209 | */ |
210 | |
211 | static struct prm_ll_data omap2xxx_prm_ll_data = { |
212 | .read_reset_sources = &omap2xxx_prm_read_reset_sources, |
213 | .assert_hardreset = &omap2_prm_assert_hardreset, |
214 | .deassert_hardreset = &omap2_prm_deassert_hardreset, |
215 | .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, |
216 | .reset_system = &omap2xxx_prm_dpll_reset, |
217 | .clear_mod_irqs = &omap2xxx_prm_clear_mod_irqs, |
218 | }; |
219 | |
220 | int __init omap2xxx_prm_init(const struct omap_prcm_init_data *data) |
221 | { |
222 | return prm_register(pld: &omap2xxx_prm_ll_data); |
223 | } |
224 | |
225 | static void __exit omap2xxx_prm_exit(void) |
226 | { |
227 | prm_unregister(pld: &omap2xxx_prm_ll_data); |
228 | } |
229 | __exitcall(omap2xxx_prm_exit); |
230 | |