X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=arch%2Farm%2Fmach-pxa%2Fpxa3xx.c;h=b02d4544dc956d98b065760dbd6975208bc527b8;hb=6d36110e1ce5663705d765ea38dd0f705e9ae6bc;hp=0b2a15ed39992f271df1e5b645820331ff7db430;hpb=7b5dea12346f98b0624e00ef585246bfec8b0959;p=safe%2Fjmp%2Flinux-2.6 diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 0b2a15e..b02d454 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -20,13 +20,17 @@ #include #include #include - -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "generic.h" #include "devices.h" @@ -39,6 +43,7 @@ #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, }; @@ -87,7 +92,7 @@ unsigned int pxa3xx_get_clk_frequency_khz(int info) HSS / 1000000, (HSS % 1000000) / 10000); } - return CLK; + return CLK / 1000; } /* @@ -107,6 +112,31 @@ unsigned int pxa3xx_get_memclk_frequency_10khz(void) 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 */ @@ -123,35 +153,27 @@ static unsigned long clk_pxa3xx_hsio_getrate(struct clk *clk) return hsio_clk; } -static void clk_pxa3xx_cken_enable(struct clk *clk) +void clk_pxa3xx_cken_enable(struct clk *clk) { unsigned long mask = 1ul << (clk->cken & 0x1f); - local_irq_disable(); - if (clk->cken < 32) CKENA |= mask; else CKENB |= mask; - - local_irq_enable(); } -static void clk_pxa3xx_cken_disable(struct clk *clk) +void clk_pxa3xx_cken_disable(struct clk *clk) { unsigned long mask = 1ul << (clk->cken & 0x1f); - local_irq_disable(); - if (clk->cken < 32) CKENA &= ~mask; else CKENB &= ~mask; - - local_irq_enable(); } -static const struct clkops clk_pxa3xx_cken_ops = { +const struct clkops clk_pxa3xx_cken_ops = { .enable = clk_pxa3xx_cken_enable, .disable = clk_pxa3xx_cken_disable, }; @@ -162,48 +184,95 @@ static const struct clkops clk_pxa3xx_hsio_ops = { .getrate = clk_pxa3xx_hsio_getrate, }; -#define PXA3xx_CKEN(_name, _cken, _rate, _delay, _dev) \ - { \ - .name = _name, \ - .dev = _dev, \ - .ops = &clk_pxa3xx_cken_ops, \ - .rate = _rate, \ - .cken = CKEN_##_cken, \ - .delay = _delay, \ - } +static const struct clkops clk_pxa3xx_ac97_ops = { + .enable = clk_pxa3xx_cken_enable, + .disable = clk_pxa3xx_cken_disable, + .getrate = clk_pxa3xx_ac97_getrate, +}; -#define PXA3xx_CK(_name, _cken, _ops, _dev) \ - { \ - .name = _name, \ - .dev = _dev, \ - .ops = _ops, \ - .cken = CKEN_##_cken, \ - } +static void clk_pout_enable(struct clk *clk) +{ + OSCC |= OSCC_PEN; +} -static struct clk pxa3xx_clks[] = { - PXA3xx_CK("LCDCLK", LCD, &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev), - PXA3xx_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL), +static void clk_pout_disable(struct clk *clk) +{ + OSCC &= ~OSCC_PEN; +} - PXA3xx_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev), - PXA3xx_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev), - PXA3xx_CKEN("UARTCLK", STUART, 14857000, 1, NULL), +static const struct clkops clk_pout_ops = { + .enable = clk_pout_enable, + .disable = clk_pout_disable, +}; - PXA3xx_CKEN("I2CCLK", I2C, 32842000, 0, &pxa_device_i2c.dev), - PXA3xx_CKEN("UDCCLK", UDC, 48000000, 5, &pxa_device_udc.dev), - PXA3xx_CKEN("USBCLK", USBH, 48000000, 0, &pxa27x_device_ohci.dev), +static void clk_dummy_enable(struct clk *clk) +{ +} - PXA3xx_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev), - PXA3xx_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev), - PXA3xx_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev), - PXA3xx_CKEN("SSPCLK", SSP4, 13000000, 0, &pxa3xx_device_ssp4.dev), +static void clk_dummy_disable(struct clk *clk) +{ +} + +static const struct clkops clk_dummy_ops = { + .enable = clk_dummy_enable, + .disable = clk_dummy_disable, +}; + +static struct clk clk_pxa3xx_pout = { + .ops = &clk_pout_ops, + .rate = 13000000, + .delay = 70, +}; - PXA3xx_CKEN("MMCCLK", MMC1, 19500000, 0, &pxa_device_mci.dev), - PXA3xx_CKEN("MMCCLK", MMC2, 19500000, 0, &pxa3xx_device_mci2.dev), - PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev), +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_keypad, KEYPAD, 32768, 0); +static DEFINE_PXA3_CKEN(pxa3xx_ssp1, SSP1, 13000000, 0); +static DEFINE_PXA3_CKEN(pxa3xx_ssp2, SSP2, 13000000, 0); +static DEFINE_PXA3_CKEN(pxa3xx_ssp3, SSP3, 13000000, 0); +static DEFINE_PXA3_CKEN(pxa3xx_ssp4, SSP4, 13000000, 0); +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 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_pxa3xx_lcd, "pxa2xx-fb", NULL), + INIT_CLKREG(&clk_pxa3xx_camera, NULL, "CAMCLK"), + INIT_CLKREG(&clk_pxa3xx_ac97, NULL, "AC97CLK"), + INIT_CLKREG(&clk_pxa3xx_ffuart, "pxa2xx-uart.0", NULL), + INIT_CLKREG(&clk_pxa3xx_btuart, "pxa2xx-uart.1", NULL), + INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-uart.2", NULL), + INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-ir", "UARTCLK"), + 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_keypad, "pxa27x-keypad", NULL), + INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL), + INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL), + INIT_CLKREG(&clk_pxa3xx_ssp3, "pxa27x-ssp.2", NULL), + INIT_CLKREG(&clk_pxa3xx_ssp4, "pxa27x-ssp.3", NULL), + INIT_CLKREG(&clk_pxa3xx_pwm0, "pxa27x-pwm.0", NULL), + 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), }; #ifdef CONFIG_PM -#define SLEEP_SAVE_SIZE 4 #define ISRAM_START 0x5c000000 #define ISRAM_SIZE SZ_256K @@ -211,25 +280,28 @@ static struct clk pxa3xx_clks[] = { static void __iomem *sram; static unsigned long wakeup_src; -static void pxa3xx_cpu_pm_save(unsigned long *sleep_save) -{ - pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB); +#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x +#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] - if (CKENA & (1 << CKEN_USBH)) { - printk(KERN_ERR "PM: USB host clock not stopped?\n"); - CKENA &= ~(1 << CKEN_USBH); - } -// CKENA |= 1 << (CKEN_ISC & 31); +enum { SLEEP_SAVE_CKENA, + SLEEP_SAVE_CKENB, + SLEEP_SAVE_ACCR, - /* - * Low power modes require the HSIO2 clock to be enabled. - */ - CKENB |= 1 << (CKEN_HSIO2 & 31); + 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) { - CKENB &= ~(1 << (CKEN_HSIO2 & 31)); + RESTORE(ACCR); + RESTORE(CKENA); + RESTORE(CKENB); } /* @@ -261,8 +333,46 @@ static void pxa3xx_cpu_standby(unsigned int pwrmode) AD2D0ER = 0; AD2D1ER = 0; +} + +/* + * NOTE: currently, the OBM (OEM Boot Module) binary comes along with + * PXA3xx development kits assumes that the resuming process continues + * with the address stored within the first 4 bytes of SDRAM. The PSPR + * register is used privately by BootROM and OBM, and _must_ be set to + * 0x5c014000 for the moment. + */ +static void pxa3xx_cpu_pm_suspend(void) +{ + volatile unsigned long *p = (volatile void *)0xc0000000; + unsigned long saved_data = *p; + + extern void pxa3xx_cpu_suspend(void); + extern void pxa3xx_cpu_resume(void); + + /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ + CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM); + CKENB |= 1 << (CKEN_HSIO2 & 0x1f); + + /* clear and setup wakeup source */ + AD3SR = ~0; + AD3ER = wakeup_src; + ASCR = ASCR; + ARSR = ARSR; + + PCFR |= (1u << 13); /* L1_DIS */ + PCFR &= ~((1u << 12) | (1u << 1)); /* L0_EN | SL_ROD */ + + PSPR = 0x5c014000; + + /* overwrite with the resume address */ + *p = virt_to_phys(pxa3xx_cpu_resume); - printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR); + pxa3xx_cpu_suspend(); + + *p = saved_data; + + AD3ER = 0; } static void pxa3xx_cpu_pm_enter(suspend_state_t state) @@ -270,8 +380,10 @@ static void pxa3xx_cpu_pm_enter(suspend_state_t state) /* * Don't sleep if no wakeup sources are defined */ - if (wakeup_src == 0) + if (wakeup_src == 0) { + printk(KERN_ERR "Not suspending: no wakeup sources\n"); return; + } switch (state) { case PM_SUSPEND_STANDBY: @@ -279,6 +391,7 @@ static void pxa3xx_cpu_pm_enter(suspend_state_t state) break; case PM_SUSPEND_MEM: + pxa3xx_cpu_pm_suspend(); break; } } @@ -289,7 +402,7 @@ static int pxa3xx_cpu_pm_valid(suspend_state_t state) } static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = { - .save_size = SLEEP_SAVE_SIZE, + .save_count = SLEEP_SAVE_COUNT, .save = pxa3xx_cpu_pm_save, .restore = pxa3xx_cpu_pm_restore, .valid = pxa3xx_cpu_pm_valid, @@ -399,6 +512,8 @@ static int pxa3xx_set_wake(unsigned int irq, unsigned int on) case IRQ_MMC3: mask = ADXER_MFP_GEN12; break; + default: + return -EINVAL; } local_irq_save(flags); @@ -410,15 +525,9 @@ static int pxa3xx_set_wake(unsigned int irq, unsigned int on) return 0; } - -static void pxa3xx_init_irq_pm(void) -{ - pxa_init_irq_set_wake(pxa3xx_set_wake); -} - #else static inline void pxa3xx_init_pm(void) {} -static inline void pxa3xx_init_irq_pm(void) {} +#define pxa3xx_set_wake NULL #endif void __init pxa3xx_init_irq(void) @@ -429,44 +538,78 @@ void __init pxa3xx_init_irq(void) value |= (1 << 6); __asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value)); - pxa_init_irq_low(); - pxa_init_irq_high(); - pxa_init_irq_gpio(128); - pxa3xx_init_irq_pm(); + pxa_init_irq(56, pxa3xx_set_wake); + pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL); } /* * device registration specific to PXA3xx. */ +void __init pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info) +{ + pxa_register_device(&pxa3xx_device_i2c_power, info); +} + static struct platform_device *devices[] __initdata = { - &pxa_device_udc, +/* &pxa_device_udc, The UDC driver is PXA25x only */ &pxa_device_ffuart, &pxa_device_btuart, &pxa_device_stuart, &pxa_device_i2s, + &sa1100_device_rtc, &pxa_device_rtc, &pxa27x_device_ssp1, &pxa27x_device_ssp2, &pxa27x_device_ssp3, &pxa3xx_device_ssp4, + &pxa27x_device_pwm0, + &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 ret = 0; + int i, ret = 0; if (cpu_is_pxa3xx()) { - clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks)); - if ((ret = pxa_init_dma(32))) + reset_status = ARSR; + + /* + * clear RDH bit every time after reset + * + * Note: the last 3 bits DxS are write-1-to-clear so carefully + * preserve them here in case they will be referenced later + */ + ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); + + clks_register(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs)); + + if ((ret = pxa_init_dma(IRQ_DMA, 32))) return ret; pxa3xx_init_pm(); - return platform_add_devices(devices, ARRAY_SIZE(devices)); + 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); + } + + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } - return 0; + + return ret; } -subsys_initcall(pxa3xx_init); +postcore_initcall(pxa3xx_init);