diff options
Diffstat (limited to 'arch/arm/mach-pxa/pxa3xx.c')
| -rw-r--r-- | arch/arm/mach-pxa/pxa3xx.c | 404 |
1 files changed, 148 insertions, 256 deletions
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index b02d4544dc9..87011f3de69 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -12,231 +12,45 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/gpio-pxa.h> #include <linux/pm.h> #include <linux/platform_device.h> #include <linux/irq.h> #include <linux/io.h> -#include <linux/sysdev.h> +#include <linux/of.h> +#include <linux/syscore_ops.h> +#include <linux/i2c/pxa-i2c.h> +#include <asm/mach/map.h> +#include <asm/suspend.h> #include <mach/hardware.h> -#include <mach/gpio.h> #include <mach/pxa3xx-regs.h> #include <mach/reset.h> -#include <mach/ohci.h> +#include <linux/platform_data/usb-ohci-pxa27x.h> #include <mach/pm.h> #include <mach/dma.h> -#include <mach/ssp.h> -#include <mach/i2c.h> +#include <mach/smemc.h> +#include <mach/irqs.h> #include "generic.h" #include "devices.h" #include "clock.h" -/* Crystal clock: 13MHz */ -#define BASE_CLK 13000000 - -/* Ring Oscillator Clock: 60MHz */ -#define RO_CLK 60000000 - -#define ACCR_D0CS (1 << 26) -#define ACCR_PCCE (1 << 11) - -/* crystal frequency to static memory controller multiplier (SMCFS) */ -static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, }; - -/* crystal frequency to HSIO bus frequency multiplier (HSS) */ -static unsigned char hss_mult[4] = { 8, 12, 16, 0 }; - -/* - * Get the clock frequency as reflected by CCSR and the turbo flag. - * We assume these values have been applied via a fcs. - * If info is not 0 we also display the current settings. - */ -unsigned int pxa3xx_get_clk_frequency_khz(int info) -{ - unsigned long acsr, xclkcfg; - unsigned int t, xl, xn, hss, ro, XL, XN, CLK, HSS; - - /* Read XCLKCFG register turbo bit */ - __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg)); - t = xclkcfg & 0x1; - - acsr = ACSR; - - xl = acsr & 0x1f; - xn = (acsr >> 8) & 0x7; - hss = (acsr >> 14) & 0x3; - - XL = xl * BASE_CLK; - XN = xn * XL; - - ro = acsr & ACCR_D0CS; - - CLK = (ro) ? RO_CLK : ((t) ? XN : XL); - HSS = (ro) ? RO_CLK : hss_mult[hss] * BASE_CLK; - - if (info) { - pr_info("RO Mode clock: %d.%02dMHz (%sactive)\n", - RO_CLK / 1000000, (RO_CLK % 1000000) / 10000, - (ro) ? "" : "in"); - pr_info("Run Mode clock: %d.%02dMHz (*%d)\n", - XL / 1000000, (XL % 1000000) / 10000, xl); - pr_info("Turbo Mode clock: %d.%02dMHz (*%d, %sactive)\n", - XN / 1000000, (XN % 1000000) / 10000, xn, - (t) ? "" : "in"); - pr_info("HSIO bus clock: %d.%02dMHz\n", - HSS / 1000000, (HSS % 1000000) / 10000); - } - - return CLK / 1000; -} - -/* - * Return the current static memory controller clock frequency - * in units of 10kHz - */ -unsigned int pxa3xx_get_memclk_frequency_10khz(void) -{ - unsigned long acsr; - unsigned int smcfs, clk = 0; - - acsr = ACSR; - - smcfs = (acsr >> 23) & 0x7; - clk = (acsr & ACCR_D0CS) ? RO_CLK : smcfs_mult[smcfs] * BASE_CLK; - - return (clk / 10000); -} - -void pxa3xx_clear_reset_status(unsigned int mask) -{ - /* RESET_STATUS_* has a 1:1 mapping with ARSR */ - ARSR = mask; -} - -/* - * Return the current AC97 clock frequency. - */ -static unsigned long clk_pxa3xx_ac97_getrate(struct clk *clk) -{ - unsigned long rate = 312000000; - unsigned long ac97_div; - - ac97_div = AC97_DIV; - - /* This may loose precision for some rates but won't for the - * standard 24.576MHz. - */ - rate /= (ac97_div >> 12) & 0x7fff; - rate *= (ac97_div & 0xfff); - - return rate; -} - -/* - * Return the current HSIO bus clock frequency - */ -static unsigned long clk_pxa3xx_hsio_getrate(struct clk *clk) -{ - unsigned long acsr; - unsigned int hss, hsio_clk; - - acsr = ACSR; - - hss = (acsr >> 14) & 0x3; - hsio_clk = (acsr & ACCR_D0CS) ? RO_CLK : hss_mult[hss] * BASE_CLK; - - return hsio_clk; -} - -void clk_pxa3xx_cken_enable(struct clk *clk) -{ - unsigned long mask = 1ul << (clk->cken & 0x1f); - - if (clk->cken < 32) - CKENA |= mask; - else - CKENB |= mask; -} - -void clk_pxa3xx_cken_disable(struct clk *clk) -{ - unsigned long mask = 1ul << (clk->cken & 0x1f); - - if (clk->cken < 32) - CKENA &= ~mask; - else - CKENB &= ~mask; -} - -const struct clkops clk_pxa3xx_cken_ops = { - .enable = clk_pxa3xx_cken_enable, - .disable = clk_pxa3xx_cken_disable, -}; - -static const struct clkops clk_pxa3xx_hsio_ops = { - .enable = clk_pxa3xx_cken_enable, - .disable = clk_pxa3xx_cken_disable, - .getrate = clk_pxa3xx_hsio_getrate, -}; - -static const struct clkops clk_pxa3xx_ac97_ops = { - .enable = clk_pxa3xx_cken_enable, - .disable = clk_pxa3xx_cken_disable, - .getrate = clk_pxa3xx_ac97_getrate, -}; - -static void clk_pout_enable(struct clk *clk) -{ - OSCC |= OSCC_PEN; -} - -static void clk_pout_disable(struct clk *clk) -{ - OSCC &= ~OSCC_PEN; -} - -static const struct clkops clk_pout_ops = { - .enable = clk_pout_enable, - .disable = clk_pout_disable, -}; - -static void clk_dummy_enable(struct clk *clk) -{ -} - -static void clk_dummy_disable(struct clk *clk) -{ -} +#define PECR_IE(n) ((1 << ((n) * 2)) << 28) +#define PECR_IS(n) ((1 << ((n) * 2)) << 29) -static const struct clkops clk_dummy_ops = { - .enable = clk_dummy_enable, - .disable = clk_dummy_disable, -}; +extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)); -static struct clk clk_pxa3xx_pout = { - .ops = &clk_pout_ops, - .rate = 13000000, - .delay = 70, -}; - -static struct clk clk_dummy = { - .ops = &clk_dummy_ops, -}; - -static DEFINE_PXA3_CK(pxa3xx_lcd, LCD, &clk_pxa3xx_hsio_ops); -static DEFINE_PXA3_CK(pxa3xx_camera, CAMERA, &clk_pxa3xx_hsio_ops); -static DEFINE_PXA3_CK(pxa3xx_ac97, AC97, &clk_pxa3xx_ac97_ops); static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1); static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1); static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1); static DEFINE_PXA3_CKEN(pxa3xx_i2c, I2C, 32842000, 0); static DEFINE_PXA3_CKEN(pxa3xx_udc, UDC, 48000000, 5); static DEFINE_PXA3_CKEN(pxa3xx_usbh, USBH, 48000000, 0); +static DEFINE_PXA3_CKEN(pxa3xx_u2d, USB2, 48000000, 0); static DEFINE_PXA3_CKEN(pxa3xx_keypad, KEYPAD, 32768, 0); static DEFINE_PXA3_CKEN(pxa3xx_ssp1, SSP1, 13000000, 0); static DEFINE_PXA3_CKEN(pxa3xx_ssp2, SSP2, 13000000, 0); @@ -246,11 +60,18 @@ static DEFINE_PXA3_CKEN(pxa3xx_pwm0, PWM0, 13000000, 0); static DEFINE_PXA3_CKEN(pxa3xx_pwm1, PWM1, 13000000, 0); static DEFINE_PXA3_CKEN(pxa3xx_mmc1, MMC1, 19500000, 0); static DEFINE_PXA3_CKEN(pxa3xx_mmc2, MMC2, 19500000, 0); +static DEFINE_PXA3_CKEN(pxa3xx_gpio, GPIO, 13000000, 0); + +static DEFINE_CK(pxa3xx_lcd, LCD, &clk_pxa3xx_hsio_ops); +static DEFINE_CK(pxa3xx_smemc, SMC, &clk_pxa3xx_smemc_ops); +static DEFINE_CK(pxa3xx_camera, CAMERA, &clk_pxa3xx_hsio_ops); +static DEFINE_CK(pxa3xx_ac97, AC97, &clk_pxa3xx_ac97_ops); +static DEFINE_CLK(pxa3xx_pout, &clk_pxa3xx_pout_ops, 13000000, 70); static struct clk_lookup pxa3xx_clkregs[] = { INIT_CLKREG(&clk_pxa3xx_pout, NULL, "CLK_POUT"), /* Power I2C clock is always on */ - INIT_CLKREG(&clk_dummy, "pxa2xx-i2c.1", NULL), + INIT_CLKREG(&clk_dummy, "pxa3xx-pwri2c.1", NULL), INIT_CLKREG(&clk_pxa3xx_lcd, "pxa2xx-fb", NULL), INIT_CLKREG(&clk_pxa3xx_camera, NULL, "CAMCLK"), INIT_CLKREG(&clk_pxa3xx_ac97, NULL, "AC97CLK"), @@ -261,6 +82,7 @@ static struct clk_lookup pxa3xx_clkregs[] = { INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL), INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL), INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL), + INIT_CLKREG(&clk_pxa3xx_u2d, "pxa3xx-u2d", NULL), INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL), INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL), INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL), @@ -270,6 +92,10 @@ static struct clk_lookup pxa3xx_clkregs[] = { INIT_CLKREG(&clk_pxa3xx_pwm1, "pxa27x-pwm.1", NULL), INIT_CLKREG(&clk_pxa3xx_mmc1, "pxa2xx-mci.0", NULL), INIT_CLKREG(&clk_pxa3xx_mmc2, "pxa2xx-mci.1", NULL), + INIT_CLKREG(&clk_pxa3xx_smemc, "pxa2xx-pcmcia", NULL), + INIT_CLKREG(&clk_pxa3xx_gpio, "pxa3xx-gpio", NULL), + INIT_CLKREG(&clk_pxa3xx_gpio, "pxa93x-gpio", NULL), + INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL), }; #ifdef CONFIG_PM @@ -280,30 +106,6 @@ static struct clk_lookup pxa3xx_clkregs[] = { static void __iomem *sram; static unsigned long wakeup_src; -#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x -#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] - -enum { SLEEP_SAVE_CKENA, - SLEEP_SAVE_CKENB, - SLEEP_SAVE_ACCR, - - SLEEP_SAVE_COUNT, -}; - -static void pxa3xx_cpu_pm_save(unsigned long *sleep_save) -{ - SAVE(CKENA); - SAVE(CKENB); - SAVE(ACCR); -} - -static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save) -{ - RESTORE(ACCR); - RESTORE(CKENA); - RESTORE(CKENB); -} - /* * Enter a standby mode (S0D1C2 or S0D2C2). Upon wakeup, the dynamic * memory controller has to be reinitialised, so we place some code @@ -346,9 +148,13 @@ static void pxa3xx_cpu_pm_suspend(void) { volatile unsigned long *p = (volatile void *)0xc0000000; unsigned long saved_data = *p; +#ifndef CONFIG_IWMMXT + u64 acc0; - extern void pxa3xx_cpu_suspend(void); - extern void pxa3xx_cpu_resume(void); + asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); +#endif + + extern int pxa3xx_finish_suspend(unsigned long); /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM); @@ -366,13 +172,17 @@ static void pxa3xx_cpu_pm_suspend(void) PSPR = 0x5c014000; /* overwrite with the resume address */ - *p = virt_to_phys(pxa3xx_cpu_resume); + *p = virt_to_phys(cpu_resume); - pxa3xx_cpu_suspend(); + cpu_suspend(0, pxa3xx_finish_suspend); *p = saved_data; AD3ER = 0; + +#ifndef CONFIG_IWMMXT + asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0)); +#endif } static void pxa3xx_cpu_pm_enter(suspend_state_t state) @@ -402,9 +212,6 @@ static int pxa3xx_cpu_pm_valid(suspend_state_t state) } static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = { - .save_count = SLEEP_SAVE_COUNT, - .save = pxa3xx_cpu_pm_save, - .restore = pxa3xx_cpu_pm_restore, .valid = pxa3xx_cpu_pm_valid, .enter = pxa3xx_cpu_pm_enter, }; @@ -437,11 +244,11 @@ static void __init pxa3xx_init_pm(void) pxa_cpu_pm_fns = &pxa3xx_cpu_pm_fns; } -static int pxa3xx_set_wake(unsigned int irq, unsigned int on) +static int pxa3xx_set_wake(struct irq_data *d, unsigned int on) { unsigned long flags, mask = 0; - switch (irq) { + switch (d->irq) { case IRQ_SSP3: mask = ADXER_MFP_WSSP3; break; @@ -530,7 +337,57 @@ static inline void pxa3xx_init_pm(void) {} #define pxa3xx_set_wake NULL #endif -void __init pxa3xx_init_irq(void) +static void pxa_ack_ext_wakeup(struct irq_data *d) +{ + PECR |= PECR_IS(d->irq - IRQ_WAKEUP0); +} + +static void pxa_mask_ext_wakeup(struct irq_data *d) +{ + pxa_mask_irq(d); + PECR &= ~PECR_IE(d->irq - IRQ_WAKEUP0); +} + +static void pxa_unmask_ext_wakeup(struct irq_data *d) +{ + pxa_unmask_irq(d); + PECR |= PECR_IE(d->irq - IRQ_WAKEUP0); +} + +static int pxa_set_ext_wakeup_type(struct irq_data *d, unsigned int flow_type) +{ + if (flow_type & IRQ_TYPE_EDGE_RISING) + PWER |= 1 << (d->irq - IRQ_WAKEUP0); + + if (flow_type & IRQ_TYPE_EDGE_FALLING) + PWER |= 1 << (d->irq - IRQ_WAKEUP0 + 2); + + return 0; +} + +static struct irq_chip pxa_ext_wakeup_chip = { + .name = "WAKEUP", + .irq_ack = pxa_ack_ext_wakeup, + .irq_mask = pxa_mask_ext_wakeup, + .irq_unmask = pxa_unmask_ext_wakeup, + .irq_set_type = pxa_set_ext_wakeup_type, +}; + +static void __init pxa_init_ext_wakeup_irq(int (*fn)(struct irq_data *, + unsigned int)) +{ + int irq; + + for (irq = IRQ_WAKEUP0; irq <= IRQ_WAKEUP1; irq++) { + irq_set_chip_and_handler(irq, &pxa_ext_wakeup_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID); + } + + pxa_ext_wakeup_chip.irq_set_wake = fn; +} + +static void __init __pxa3xx_init_irq(void) { /* enable CP6 access */ u32 value; @@ -538,8 +395,37 @@ void __init pxa3xx_init_irq(void) value |= (1 << 6); __asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value)); + pxa_init_ext_wakeup_irq(pxa3xx_set_wake); +} + +void __init pxa3xx_init_irq(void) +{ + __pxa3xx_init_irq(); pxa_init_irq(56, pxa3xx_set_wake); - pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL); +} + +#ifdef CONFIG_OF +void __init pxa3xx_dt_init_irq(void) +{ + __pxa3xx_init_irq(); + pxa_dt_irq_init(pxa3xx_set_wake); +} +#endif /* CONFIG_OF */ + +static struct map_desc pxa3xx_io_desc[] __initdata = { + { /* Mem Ctl */ + .virtual = (unsigned long)SMEMC_VIRT, + .pfn = __phys_to_pfn(PXA3XX_SMEMC_BASE), + .length = 0x00200000, + .type = MT_DEVICE + } +}; + +void __init pxa3xx_map_io(void) +{ + pxa_map_io(); + iotable_init(ARRAY_AND_SIZE(pxa3xx_io_desc)); + pxa3xx_get_clk_frequency_khz(1); } /* @@ -551,12 +437,19 @@ void __init pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info) pxa_register_device(&pxa3xx_device_i2c_power, info); } +static struct pxa_gpio_platform_data pxa3xx_gpio_pdata = { + .irq_base = PXA_GPIO_TO_IRQ(0), +}; + static struct platform_device *devices[] __initdata = { -/* &pxa_device_udc, The UDC driver is PXA25x only */ - &pxa_device_ffuart, - &pxa_device_btuart, - &pxa_device_stuart, + &pxa27x_device_udc, + &pxa_device_pmu, &pxa_device_i2s, + &pxa_device_asoc_ssp1, + &pxa_device_asoc_ssp2, + &pxa_device_asoc_ssp3, + &pxa_device_asoc_ssp4, + &pxa_device_asoc_platform, &sa1100_device_rtc, &pxa_device_rtc, &pxa27x_device_ssp1, @@ -567,19 +460,9 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_pwm1, }; -static struct sys_device pxa3xx_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa3xx_mfp_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, -}; - static int __init pxa3xx_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa3xx()) { @@ -593,20 +476,29 @@ static int __init pxa3xx_init(void) */ ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); - clks_register(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs)); + clkdev_add_table(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs)); if ((ret = pxa_init_dma(IRQ_DMA, 32))) return ret; pxa3xx_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) { - ret = sysdev_register(&pxa3xx_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa3xx_mfp_syscore_ops); + register_syscore_ops(&pxa3xx_clock_syscore_ops); + + if (of_have_populated_dt()) + return 0; ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + if (ret) + return ret; + if (cpu_is_pxa300() || cpu_is_pxa310() || cpu_is_pxa320()) { + platform_device_add_data(&pxa3xx_device_gpio, + &pxa3xx_gpio_pdata, + sizeof(pxa3xx_gpio_pdata)); + ret = platform_device_register(&pxa3xx_device_gpio); + } } return ret; |
