1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/arch/arm/mach-pxa/pxa27x.c |
4 | * |
5 | * Author: Nicolas Pitre |
6 | * Created: Nov 05, 2002 |
7 | * Copyright: MontaVista Software Inc. |
8 | * |
9 | * Code specific to PXA27x aka Bulverde. |
10 | */ |
11 | #include <linux/dmaengine.h> |
12 | #include <linux/dma/pxa-dma.h> |
13 | #include <linux/gpio.h> |
14 | #include <linux/gpio-pxa.h> |
15 | #include <linux/module.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/init.h> |
18 | #include <linux/irqchip.h> |
19 | #include <linux/suspend.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/syscore_ops.h> |
22 | #include <linux/io.h> |
23 | #include <linux/irq.h> |
24 | #include <linux/platform_data/i2c-pxa.h> |
25 | #include <linux/platform_data/mmp_dma.h> |
26 | #include <linux/soc/pxa/cpu.h> |
27 | #include <linux/soc/pxa/smemc.h> |
28 | |
29 | #include <asm/mach/map.h> |
30 | #include <asm/irq.h> |
31 | #include <asm/suspend.h> |
32 | #include "irqs.h" |
33 | #include "pxa27x.h" |
34 | #include "reset.h" |
35 | #include <linux/platform_data/pxa2xx_udc.h> |
36 | #include <linux/platform_data/usb-ohci-pxa27x.h> |
37 | #include <linux/platform_data/asoc-pxa.h> |
38 | #include "pm.h" |
39 | #include "addr-map.h" |
40 | #include "smemc.h" |
41 | |
42 | #include "generic.h" |
43 | #include "devices.h" |
44 | #include <linux/clk-provider.h> |
45 | #include <linux/clkdev.h> |
46 | |
47 | void pxa27x_clear_otgph(void) |
48 | { |
49 | if (cpu_is_pxa27x() && (PSSR & PSSR_OTGPH)) |
50 | PSSR |= PSSR_OTGPH; |
51 | } |
52 | EXPORT_SYMBOL(pxa27x_clear_otgph); |
53 | |
54 | static unsigned long ac97_reset_config[] = { |
55 | GPIO113_AC97_nRESET_GPIO_HIGH, |
56 | GPIO113_AC97_nRESET, |
57 | GPIO95_AC97_nRESET_GPIO_HIGH, |
58 | GPIO95_AC97_nRESET, |
59 | }; |
60 | |
61 | void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio) |
62 | { |
63 | /* |
64 | * This helper function is used to work around a bug in the pxa27x's |
65 | * ac97 controller during a warm reset. The configuration of the |
66 | * reset_gpio is changed as follows: |
67 | * to_gpio == true: configured to generic output gpio and driven high |
68 | * to_gpio == false: configured to ac97 controller alt fn AC97_nRESET |
69 | */ |
70 | |
71 | if (reset_gpio == 113) |
72 | pxa2xx_mfp_config(mfp_cfgs: to_gpio ? &ac97_reset_config[0] : |
73 | &ac97_reset_config[1], num: 1); |
74 | |
75 | if (reset_gpio == 95) |
76 | pxa2xx_mfp_config(mfp_cfgs: to_gpio ? &ac97_reset_config[2] : |
77 | &ac97_reset_config[3], num: 1); |
78 | } |
79 | EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset); |
80 | |
81 | #ifdef CONFIG_PM |
82 | |
83 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x |
84 | #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] |
85 | |
86 | /* |
87 | * allow platforms to override default PWRMODE setting used for PM_SUSPEND_MEM |
88 | */ |
89 | static unsigned int pwrmode = PWRMODE_SLEEP; |
90 | |
91 | /* |
92 | * List of global PXA peripheral registers to preserve. |
93 | * More ones like CP and general purpose register values are preserved |
94 | * with the stack pointer in sleep.S. |
95 | */ |
96 | enum { |
97 | SLEEP_SAVE_PSTR, |
98 | SLEEP_SAVE_MDREFR, |
99 | SLEEP_SAVE_PCFR, |
100 | SLEEP_SAVE_COUNT |
101 | }; |
102 | |
103 | static void pxa27x_cpu_pm_save(unsigned long *sleep_save) |
104 | { |
105 | sleep_save[SLEEP_SAVE_MDREFR] = __raw_readl(MDREFR); |
106 | SAVE(PCFR); |
107 | |
108 | SAVE(PSTR); |
109 | } |
110 | |
111 | static void pxa27x_cpu_pm_restore(unsigned long *sleep_save) |
112 | { |
113 | __raw_writel(val: sleep_save[SLEEP_SAVE_MDREFR], MDREFR); |
114 | RESTORE(PCFR); |
115 | |
116 | PSSR = PSSR_RDH | PSSR_PH; |
117 | |
118 | RESTORE(PSTR); |
119 | } |
120 | |
121 | static void pxa27x_cpu_pm_enter(suspend_state_t state) |
122 | { |
123 | extern void pxa_cpu_standby(void); |
124 | #ifndef CONFIG_IWMMXT |
125 | u64 acc0; |
126 | |
127 | #ifndef CONFIG_AS_IS_LLVM |
128 | asm volatile(".arch_extension xscale\n\t" |
129 | "mra %Q0, %R0, acc0" : "=r" (acc0)); |
130 | #else |
131 | asm volatile("mrrc p0, 0, %Q0, %R0, c0" : "=r" (acc0)); |
132 | #endif |
133 | #endif |
134 | |
135 | /* ensure voltage-change sequencer not initiated, which hangs */ |
136 | PCFR &= ~PCFR_FVC; |
137 | |
138 | /* Clear edge-detect status register. */ |
139 | PEDR = 0xDF12FE1B; |
140 | |
141 | /* Clear reset status */ |
142 | RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; |
143 | |
144 | switch (state) { |
145 | case PM_SUSPEND_STANDBY: |
146 | pxa_cpu_standby(); |
147 | break; |
148 | case PM_SUSPEND_MEM: |
149 | cpu_suspend(pwrmode, pxa27x_finish_suspend); |
150 | #ifndef CONFIG_IWMMXT |
151 | #ifndef CONFIG_AS_IS_LLVM |
152 | asm volatile(".arch_extension xscale\n\t" |
153 | "mar acc0, %Q0, %R0" : "=r" (acc0)); |
154 | #else |
155 | asm volatile("mcrr p0, 0, %Q0, %R0, c0" :: "r" (acc0)); |
156 | #endif |
157 | #endif |
158 | break; |
159 | } |
160 | } |
161 | |
162 | static int pxa27x_cpu_pm_valid(suspend_state_t state) |
163 | { |
164 | return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; |
165 | } |
166 | |
167 | static int pxa27x_cpu_pm_prepare(void) |
168 | { |
169 | /* set resume return address */ |
170 | PSPR = __pa_symbol(cpu_resume); |
171 | return 0; |
172 | } |
173 | |
174 | static void pxa27x_cpu_pm_finish(void) |
175 | { |
176 | /* ensure not to come back here if it wasn't intended */ |
177 | PSPR = 0; |
178 | } |
179 | |
180 | static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = { |
181 | .save_count = SLEEP_SAVE_COUNT, |
182 | .save = pxa27x_cpu_pm_save, |
183 | .restore = pxa27x_cpu_pm_restore, |
184 | .valid = pxa27x_cpu_pm_valid, |
185 | .enter = pxa27x_cpu_pm_enter, |
186 | .prepare = pxa27x_cpu_pm_prepare, |
187 | .finish = pxa27x_cpu_pm_finish, |
188 | }; |
189 | |
190 | static void __init pxa27x_init_pm(void) |
191 | { |
192 | pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns; |
193 | } |
194 | #else |
195 | static inline void pxa27x_init_pm(void) {} |
196 | #endif |
197 | |
198 | /* PXA27x: Various gpios can issue wakeup events. This logic only |
199 | * handles the simple cases, not the WEMUX2 and WEMUX3 options |
200 | */ |
201 | static int pxa27x_set_wake(struct irq_data *d, unsigned int on) |
202 | { |
203 | int gpio = pxa_irq_to_gpio(irq: d->irq); |
204 | uint32_t mask; |
205 | |
206 | if (gpio >= 0 && gpio < 128) |
207 | return gpio_set_wake(gpio, on); |
208 | |
209 | if (d->irq == IRQ_KEYPAD) |
210 | return keypad_set_wake(on); |
211 | |
212 | switch (d->irq) { |
213 | case IRQ_RTCAlrm: |
214 | mask = PWER_RTC; |
215 | break; |
216 | case IRQ_USB: |
217 | mask = 1u << 26; |
218 | break; |
219 | default: |
220 | return -EINVAL; |
221 | } |
222 | |
223 | if (on) |
224 | PWER |= mask; |
225 | else |
226 | PWER &=~mask; |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | void __init pxa27x_init_irq(void) |
232 | { |
233 | pxa_init_irq(irq_nr: 34, set_wake: pxa27x_set_wake); |
234 | set_handle_irq(pxa27x_handle_irq); |
235 | } |
236 | |
237 | static int __init |
238 | pxa27x_dt_init_irq(struct device_node *node, struct device_node *parent) |
239 | { |
240 | pxa_dt_irq_init(fn: pxa27x_set_wake); |
241 | set_handle_irq(ichp_handle_irq); |
242 | |
243 | return 0; |
244 | } |
245 | IRQCHIP_DECLARE(pxa27x_intc, "marvell,pxa-intc" , pxa27x_dt_init_irq); |
246 | |
247 | static struct map_desc pxa27x_io_desc[] __initdata = { |
248 | { /* Mem Ctl */ |
249 | .virtual = (unsigned long)SMEMC_VIRT, |
250 | .pfn = __phys_to_pfn(PXA2XX_SMEMC_BASE), |
251 | .length = SMEMC_SIZE, |
252 | .type = MT_DEVICE |
253 | }, { /* UNCACHED_PHYS_0 */ |
254 | .virtual = UNCACHED_PHYS_0, |
255 | .pfn = __phys_to_pfn(0x00000000), |
256 | .length = UNCACHED_PHYS_0_SIZE, |
257 | .type = MT_DEVICE |
258 | }, |
259 | }; |
260 | |
261 | void __init pxa27x_map_io(void) |
262 | { |
263 | pxa_map_io(); |
264 | iotable_init(ARRAY_AND_SIZE(pxa27x_io_desc)); |
265 | pxa27x_get_clk_frequency_khz(1); |
266 | } |
267 | |
268 | /* |
269 | * device registration specific to PXA27x. |
270 | */ |
271 | void __init pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info) |
272 | { |
273 | local_irq_disable(); |
274 | PCFR |= PCFR_PI2CEN; |
275 | local_irq_enable(); |
276 | pxa_register_device(dev: &pxa27x_device_i2c_power, data: info); |
277 | } |
278 | |
279 | static struct pxa_gpio_platform_data pxa27x_gpio_info __initdata = { |
280 | .irq_base = PXA_GPIO_TO_IRQ(0), |
281 | .gpio_set_wake = gpio_set_wake, |
282 | }; |
283 | |
284 | static struct platform_device *devices[] __initdata = { |
285 | &pxa27x_device_udc, |
286 | &pxa_device_pmu, |
287 | &pxa_device_i2s, |
288 | &pxa_device_asoc_ssp1, |
289 | &pxa_device_asoc_ssp2, |
290 | &pxa_device_asoc_ssp3, |
291 | &pxa_device_asoc_platform, |
292 | &pxa_device_rtc, |
293 | &pxa27x_device_ssp1, |
294 | &pxa27x_device_ssp2, |
295 | &pxa27x_device_ssp3, |
296 | &pxa27x_device_pwm0, |
297 | &pxa27x_device_pwm1, |
298 | }; |
299 | |
300 | static const struct dma_slave_map pxa27x_slave_map[] = { |
301 | /* PXA25x, PXA27x and PXA3xx common entries */ |
302 | { "pxa2xx-ac97" , "pcm_pcm_mic_mono" , PDMA_FILTER_PARAM(LOWEST, 8) }, |
303 | { "pxa2xx-ac97" , "pcm_pcm_aux_mono_in" , PDMA_FILTER_PARAM(LOWEST, 9) }, |
304 | { "pxa2xx-ac97" , "pcm_pcm_aux_mono_out" , |
305 | PDMA_FILTER_PARAM(LOWEST, 10) }, |
306 | { "pxa2xx-ac97" , "pcm_pcm_stereo_in" , PDMA_FILTER_PARAM(LOWEST, 11) }, |
307 | { "pxa2xx-ac97" , "pcm_pcm_stereo_out" , PDMA_FILTER_PARAM(LOWEST, 12) }, |
308 | { "pxa-ssp-dai.0" , "rx" , PDMA_FILTER_PARAM(LOWEST, 13) }, |
309 | { "pxa-ssp-dai.0" , "tx" , PDMA_FILTER_PARAM(LOWEST, 14) }, |
310 | { "pxa-ssp-dai.1" , "rx" , PDMA_FILTER_PARAM(LOWEST, 15) }, |
311 | { "pxa-ssp-dai.1" , "tx" , PDMA_FILTER_PARAM(LOWEST, 16) }, |
312 | { "pxa2xx-ir" , "rx" , PDMA_FILTER_PARAM(LOWEST, 17) }, |
313 | { "pxa2xx-ir" , "tx" , PDMA_FILTER_PARAM(LOWEST, 18) }, |
314 | { "pxa2xx-mci.0" , "rx" , PDMA_FILTER_PARAM(LOWEST, 21) }, |
315 | { "pxa2xx-mci.0" , "tx" , PDMA_FILTER_PARAM(LOWEST, 22) }, |
316 | { "pxa-ssp-dai.2" , "rx" , PDMA_FILTER_PARAM(LOWEST, 66) }, |
317 | { "pxa-ssp-dai.2" , "tx" , PDMA_FILTER_PARAM(LOWEST, 67) }, |
318 | |
319 | /* PXA27x specific map */ |
320 | { "pxa2xx-i2s" , "rx" , PDMA_FILTER_PARAM(LOWEST, 2) }, |
321 | { "pxa2xx-i2s" , "tx" , PDMA_FILTER_PARAM(LOWEST, 3) }, |
322 | { "pxa27x-camera.0" , "CI_Y" , PDMA_FILTER_PARAM(HIGHEST, 68) }, |
323 | { "pxa27x-camera.0" , "CI_U" , PDMA_FILTER_PARAM(HIGHEST, 69) }, |
324 | { "pxa27x-camera.0" , "CI_V" , PDMA_FILTER_PARAM(HIGHEST, 70) }, |
325 | }; |
326 | |
327 | static struct mmp_dma_platdata pxa27x_dma_pdata = { |
328 | .dma_channels = 32, |
329 | .nb_requestors = 75, |
330 | .slave_map = pxa27x_slave_map, |
331 | .slave_map_cnt = ARRAY_SIZE(pxa27x_slave_map), |
332 | }; |
333 | |
334 | static int __init pxa27x_init(void) |
335 | { |
336 | int ret = 0; |
337 | |
338 | if (cpu_is_pxa27x()) { |
339 | |
340 | pxa_register_wdt(RCSR); |
341 | |
342 | pxa27x_init_pm(); |
343 | |
344 | register_syscore_ops(ops: &pxa_irq_syscore_ops); |
345 | register_syscore_ops(ops: &pxa2xx_mfp_syscore_ops); |
346 | |
347 | if (!of_have_populated_dt()) { |
348 | pxa_register_device(dev: &pxa27x_device_gpio, |
349 | data: &pxa27x_gpio_info); |
350 | pxa2xx_set_dmac_info(dma_pdata: &pxa27x_dma_pdata); |
351 | ret = platform_add_devices(devices, |
352 | ARRAY_SIZE(devices)); |
353 | } |
354 | } |
355 | |
356 | return ret; |
357 | } |
358 | |
359 | postcore_initcall(pxa27x_init); |
360 | |