1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/arch/arm/mach-pxa/pxa25x.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Nicolas Pitre
6*4882a593Smuzhiyun * Created: Jun 15, 2001
7*4882a593Smuzhiyun * Copyright: MontaVista Software Inc.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Code specific to PXA21x/25x/26x variants.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Since this file should be linked before any other machine specific file,
12*4882a593Smuzhiyun * the __initcall() here will be executed first. This serves as default
13*4882a593Smuzhiyun * initialization stuff for PXA machines which can be overridden later if
14*4882a593Smuzhiyun * need be.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun #include <linux/dmaengine.h>
17*4882a593Smuzhiyun #include <linux/dma/pxa-dma.h>
18*4882a593Smuzhiyun #include <linux/gpio.h>
19*4882a593Smuzhiyun #include <linux/gpio-pxa.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/kernel.h>
22*4882a593Smuzhiyun #include <linux/init.h>
23*4882a593Smuzhiyun #include <linux/platform_device.h>
24*4882a593Smuzhiyun #include <linux/suspend.h>
25*4882a593Smuzhiyun #include <linux/syscore_ops.h>
26*4882a593Smuzhiyun #include <linux/irq.h>
27*4882a593Smuzhiyun #include <linux/irqchip.h>
28*4882a593Smuzhiyun #include <linux/platform_data/mmp_dma.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include <asm/mach/map.h>
31*4882a593Smuzhiyun #include <asm/suspend.h>
32*4882a593Smuzhiyun #include <mach/hardware.h>
33*4882a593Smuzhiyun #include <mach/irqs.h>
34*4882a593Smuzhiyun #include "pxa25x.h"
35*4882a593Smuzhiyun #include <mach/reset.h>
36*4882a593Smuzhiyun #include "pm.h"
37*4882a593Smuzhiyun #include <mach/dma.h>
38*4882a593Smuzhiyun #include <mach/smemc.h>
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #include "generic.h"
41*4882a593Smuzhiyun #include "devices.h"
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /*
44*4882a593Smuzhiyun * Various clock factors driven by the CCCR register.
45*4882a593Smuzhiyun */
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #ifdef CONFIG_PM
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
50*4882a593Smuzhiyun #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * List of global PXA peripheral registers to preserve.
54*4882a593Smuzhiyun * More ones like CP and general purpose register values are preserved
55*4882a593Smuzhiyun * with the stack pointer in sleep.S.
56*4882a593Smuzhiyun */
57*4882a593Smuzhiyun enum {
58*4882a593Smuzhiyun SLEEP_SAVE_PSTR,
59*4882a593Smuzhiyun SLEEP_SAVE_COUNT
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun
pxa25x_cpu_pm_save(unsigned long * sleep_save)63*4882a593Smuzhiyun static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun SAVE(PSTR);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
pxa25x_cpu_pm_restore(unsigned long * sleep_save)68*4882a593Smuzhiyun static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun RESTORE(PSTR);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
pxa25x_cpu_pm_enter(suspend_state_t state)73*4882a593Smuzhiyun static void pxa25x_cpu_pm_enter(suspend_state_t state)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun /* Clear reset status */
76*4882a593Smuzhiyun RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun switch (state) {
79*4882a593Smuzhiyun case PM_SUSPEND_MEM:
80*4882a593Smuzhiyun cpu_suspend(PWRMODE_SLEEP, pxa25x_finish_suspend);
81*4882a593Smuzhiyun break;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
pxa25x_cpu_pm_prepare(void)85*4882a593Smuzhiyun static int pxa25x_cpu_pm_prepare(void)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun /* set resume return address */
88*4882a593Smuzhiyun PSPR = __pa_symbol(cpu_resume);
89*4882a593Smuzhiyun return 0;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
pxa25x_cpu_pm_finish(void)92*4882a593Smuzhiyun static void pxa25x_cpu_pm_finish(void)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun /* ensure not to come back here if it wasn't intended */
95*4882a593Smuzhiyun PSPR = 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = {
99*4882a593Smuzhiyun .save_count = SLEEP_SAVE_COUNT,
100*4882a593Smuzhiyun .valid = suspend_valid_only_mem,
101*4882a593Smuzhiyun .save = pxa25x_cpu_pm_save,
102*4882a593Smuzhiyun .restore = pxa25x_cpu_pm_restore,
103*4882a593Smuzhiyun .enter = pxa25x_cpu_pm_enter,
104*4882a593Smuzhiyun .prepare = pxa25x_cpu_pm_prepare,
105*4882a593Smuzhiyun .finish = pxa25x_cpu_pm_finish,
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun
pxa25x_init_pm(void)108*4882a593Smuzhiyun static void __init pxa25x_init_pm(void)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun #else
pxa25x_init_pm(void)113*4882a593Smuzhiyun static inline void pxa25x_init_pm(void) {}
114*4882a593Smuzhiyun #endif
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /* PXA25x: supports wakeup from GPIO0..GPIO15 and RTC alarm
117*4882a593Smuzhiyun */
118*4882a593Smuzhiyun
pxa25x_set_wake(struct irq_data * d,unsigned int on)119*4882a593Smuzhiyun static int pxa25x_set_wake(struct irq_data *d, unsigned int on)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun int gpio = pxa_irq_to_gpio(d->irq);
122*4882a593Smuzhiyun uint32_t mask = 0;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (gpio >= 0 && gpio < 85)
125*4882a593Smuzhiyun return gpio_set_wake(gpio, on);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (d->irq == IRQ_RTCAlrm) {
128*4882a593Smuzhiyun mask = PWER_RTC;
129*4882a593Smuzhiyun goto set_pwer;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun return -EINVAL;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun set_pwer:
135*4882a593Smuzhiyun if (on)
136*4882a593Smuzhiyun PWER |= mask;
137*4882a593Smuzhiyun else
138*4882a593Smuzhiyun PWER &=~mask;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun return 0;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
pxa25x_init_irq(void)143*4882a593Smuzhiyun void __init pxa25x_init_irq(void)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun pxa_init_irq(32, pxa25x_set_wake);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun #ifdef CONFIG_CPU_PXA26x
pxa26x_init_irq(void)149*4882a593Smuzhiyun void __init pxa26x_init_irq(void)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun pxa_init_irq(32, pxa25x_set_wake);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun #endif
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun static int __init __init
pxa25x_dt_init_irq(struct device_node * node,struct device_node * parent)156*4882a593Smuzhiyun pxa25x_dt_init_irq(struct device_node *node, struct device_node *parent)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun pxa_dt_irq_init(pxa25x_set_wake);
159*4882a593Smuzhiyun set_handle_irq(icip_handle_irq);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun return 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun IRQCHIP_DECLARE(pxa25x_intc, "marvell,pxa-intc", pxa25x_dt_init_irq);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun static struct map_desc pxa25x_io_desc[] __initdata = {
166*4882a593Smuzhiyun { /* Mem Ctl */
167*4882a593Smuzhiyun .virtual = (unsigned long)SMEMC_VIRT,
168*4882a593Smuzhiyun .pfn = __phys_to_pfn(PXA2XX_SMEMC_BASE),
169*4882a593Smuzhiyun .length = SMEMC_SIZE,
170*4882a593Smuzhiyun .type = MT_DEVICE
171*4882a593Smuzhiyun }, { /* UNCACHED_PHYS_0 */
172*4882a593Smuzhiyun .virtual = UNCACHED_PHYS_0,
173*4882a593Smuzhiyun .pfn = __phys_to_pfn(0x00000000),
174*4882a593Smuzhiyun .length = UNCACHED_PHYS_0_SIZE,
175*4882a593Smuzhiyun .type = MT_DEVICE
176*4882a593Smuzhiyun },
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun
pxa25x_map_io(void)179*4882a593Smuzhiyun void __init pxa25x_map_io(void)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun pxa_map_io();
182*4882a593Smuzhiyun iotable_init(ARRAY_AND_SIZE(pxa25x_io_desc));
183*4882a593Smuzhiyun pxa25x_get_clk_frequency_khz(1);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun static struct pxa_gpio_platform_data pxa25x_gpio_info __initdata = {
187*4882a593Smuzhiyun .irq_base = PXA_GPIO_TO_IRQ(0),
188*4882a593Smuzhiyun .gpio_set_wake = gpio_set_wake,
189*4882a593Smuzhiyun };
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun static struct platform_device *pxa25x_devices[] __initdata = {
192*4882a593Smuzhiyun &pxa25x_device_udc,
193*4882a593Smuzhiyun &pxa_device_pmu,
194*4882a593Smuzhiyun &pxa_device_i2s,
195*4882a593Smuzhiyun &sa1100_device_rtc,
196*4882a593Smuzhiyun &pxa25x_device_ssp,
197*4882a593Smuzhiyun &pxa25x_device_nssp,
198*4882a593Smuzhiyun &pxa25x_device_assp,
199*4882a593Smuzhiyun &pxa25x_device_pwm0,
200*4882a593Smuzhiyun &pxa25x_device_pwm1,
201*4882a593Smuzhiyun &pxa_device_asoc_platform,
202*4882a593Smuzhiyun };
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun static const struct dma_slave_map pxa25x_slave_map[] = {
205*4882a593Smuzhiyun /* PXA25x, PXA27x and PXA3xx common entries */
206*4882a593Smuzhiyun { "pxa2xx-ac97", "pcm_pcm_mic_mono", PDMA_FILTER_PARAM(LOWEST, 8) },
207*4882a593Smuzhiyun { "pxa2xx-ac97", "pcm_pcm_aux_mono_in", PDMA_FILTER_PARAM(LOWEST, 9) },
208*4882a593Smuzhiyun { "pxa2xx-ac97", "pcm_pcm_aux_mono_out",
209*4882a593Smuzhiyun PDMA_FILTER_PARAM(LOWEST, 10) },
210*4882a593Smuzhiyun { "pxa2xx-ac97", "pcm_pcm_stereo_in", PDMA_FILTER_PARAM(LOWEST, 11) },
211*4882a593Smuzhiyun { "pxa2xx-ac97", "pcm_pcm_stereo_out", PDMA_FILTER_PARAM(LOWEST, 12) },
212*4882a593Smuzhiyun { "pxa-ssp-dai.1", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
213*4882a593Smuzhiyun { "pxa-ssp-dai.1", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
214*4882a593Smuzhiyun { "pxa-ssp-dai.2", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
215*4882a593Smuzhiyun { "pxa-ssp-dai.2", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
216*4882a593Smuzhiyun { "pxa2xx-ir", "rx", PDMA_FILTER_PARAM(LOWEST, 17) },
217*4882a593Smuzhiyun { "pxa2xx-ir", "tx", PDMA_FILTER_PARAM(LOWEST, 18) },
218*4882a593Smuzhiyun { "pxa2xx-mci.0", "rx", PDMA_FILTER_PARAM(LOWEST, 21) },
219*4882a593Smuzhiyun { "pxa2xx-mci.0", "tx", PDMA_FILTER_PARAM(LOWEST, 22) },
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /* PXA25x specific map */
222*4882a593Smuzhiyun { "pxa25x-ssp.0", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
223*4882a593Smuzhiyun { "pxa25x-ssp.0", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
224*4882a593Smuzhiyun { "pxa25x-nssp.1", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
225*4882a593Smuzhiyun { "pxa25x-nssp.1", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
226*4882a593Smuzhiyun { "pxa25x-nssp.2", "rx", PDMA_FILTER_PARAM(LOWEST, 23) },
227*4882a593Smuzhiyun { "pxa25x-nssp.2", "tx", PDMA_FILTER_PARAM(LOWEST, 24) },
228*4882a593Smuzhiyun };
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun static struct mmp_dma_platdata pxa25x_dma_pdata = {
231*4882a593Smuzhiyun .dma_channels = 16,
232*4882a593Smuzhiyun .nb_requestors = 40,
233*4882a593Smuzhiyun .slave_map = pxa25x_slave_map,
234*4882a593Smuzhiyun .slave_map_cnt = ARRAY_SIZE(pxa25x_slave_map),
235*4882a593Smuzhiyun };
236*4882a593Smuzhiyun
pxa25x_init(void)237*4882a593Smuzhiyun static int __init pxa25x_init(void)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun int ret = 0;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (cpu_is_pxa25x()) {
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun reset_status = RCSR;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun pxa25x_init_pm();
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun register_syscore_ops(&pxa_irq_syscore_ops);
248*4882a593Smuzhiyun register_syscore_ops(&pxa2xx_mfp_syscore_ops);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun if (!of_have_populated_dt()) {
251*4882a593Smuzhiyun pxa2xx_set_dmac_info(&pxa25x_dma_pdata);
252*4882a593Smuzhiyun pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info);
253*4882a593Smuzhiyun ret = platform_add_devices(pxa25x_devices,
254*4882a593Smuzhiyun ARRAY_SIZE(pxa25x_devices));
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun return ret;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun postcore_initcall(pxa25x_init);
262