From a2d3e7bad82dcfb67924849e2063238a1ae51b6e Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:47:33 +0530 Subject: [PATCH 01/32] OMAP3: PM: GPMC context save/restore This patch adds the context save and restore functions for GPMC to enable off-mode. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/gpmc.c | 98 +++++++++++++++++++++++++- arch/arm/plat-omap/include/plat/gpmc.h | 3 + 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 004da696ace7..7d687845f391 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -62,6 +62,33 @@ #define ENABLE_PREFETCH (0x1 << 7) #define DMA_MPU_MODE 2 +/* Structure to save gpmc cs context */ +struct gpmc_cs_config { + u32 config1; + u32 config2; + u32 config3; + u32 config4; + u32 config5; + u32 config6; + u32 config7; + int is_valid; +}; + +/* + * Structure to save/restore gpmc context + * to support core off on OMAP3 + */ +struct omap3_gpmc_regs { + u32 sysconfig; + u32 irqenable; + u32 timeout_ctrl; + u32 config; + u32 prefetch_config1; + u32 prefetch_config2; + u32 prefetch_control; + struct gpmc_cs_config cs_context[GPMC_CS_NUM]; +}; + static struct resource gpmc_mem_root; static struct resource gpmc_cs_mem[GPMC_CS_NUM]; static DEFINE_SPINLOCK(gpmc_mem_lock); @@ -261,7 +288,7 @@ static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) l = (base >> GPMC_CHUNK_SHIFT) & 0x3f; l &= ~(0x0f << 8); l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; - l |= 1 << 6; /* CSVALID */ + l |= GPMC_CONFIG7_CSVALID; gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); } @@ -270,7 +297,7 @@ static void gpmc_cs_disable_mem(int cs) u32 l; l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); - l &= ~(1 << 6); /* CSVALID */ + l &= ~GPMC_CONFIG7_CSVALID; gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); } @@ -290,7 +317,7 @@ static int gpmc_cs_mem_enabled(int cs) u32 l; l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); - return l & (1 << 6); + return l & GPMC_CONFIG7_CSVALID; } int gpmc_cs_set_reserved(int cs, int reserved) @@ -516,3 +543,68 @@ void __init gpmc_init(void) gpmc_write_reg(GPMC_SYSCONFIG, l); gpmc_mem_init(); } + +#ifdef CONFIG_ARCH_OMAP3 +static struct omap3_gpmc_regs gpmc_context; + +void omap3_gpmc_save_context() +{ + int i; + gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG); + gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE); + gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL); + gpmc_context.config = gpmc_read_reg(GPMC_CONFIG); + gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1); + gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2); + gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL); + for (i = 0; i < GPMC_CS_NUM; i++) { + gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i); + if (gpmc_context.cs_context[i].is_valid) { + gpmc_context.cs_context[i].config1 = + gpmc_cs_read_reg(i, GPMC_CS_CONFIG1); + gpmc_context.cs_context[i].config2 = + gpmc_cs_read_reg(i, GPMC_CS_CONFIG2); + gpmc_context.cs_context[i].config3 = + gpmc_cs_read_reg(i, GPMC_CS_CONFIG3); + gpmc_context.cs_context[i].config4 = + gpmc_cs_read_reg(i, GPMC_CS_CONFIG4); + gpmc_context.cs_context[i].config5 = + gpmc_cs_read_reg(i, GPMC_CS_CONFIG5); + gpmc_context.cs_context[i].config6 = + gpmc_cs_read_reg(i, GPMC_CS_CONFIG6); + gpmc_context.cs_context[i].config7 = + gpmc_cs_read_reg(i, GPMC_CS_CONFIG7); + } + } +} + +void omap3_gpmc_restore_context() +{ + int i; + gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig); + gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable); + gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl); + gpmc_write_reg(GPMC_CONFIG, gpmc_context.config); + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1); + gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2); + gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control); + for (i = 0; i < GPMC_CS_NUM; i++) { + if (gpmc_context.cs_context[i].is_valid) { + gpmc_cs_write_reg(i, GPMC_CS_CONFIG1, + gpmc_context.cs_context[i].config1); + gpmc_cs_write_reg(i, GPMC_CS_CONFIG2, + gpmc_context.cs_context[i].config2); + gpmc_cs_write_reg(i, GPMC_CS_CONFIG3, + gpmc_context.cs_context[i].config3); + gpmc_cs_write_reg(i, GPMC_CS_CONFIG4, + gpmc_context.cs_context[i].config4); + gpmc_cs_write_reg(i, GPMC_CS_CONFIG5, + gpmc_context.cs_context[i].config5); + gpmc_cs_write_reg(i, GPMC_CS_CONFIG6, + gpmc_context.cs_context[i].config6); + gpmc_cs_write_reg(i, GPMC_CS_CONFIG7, + gpmc_context.cs_context[i].config7); + } + } +} +#endif /* CONFIG_ARCH_OMAP3 */ diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h index 9c99cda77ba6..696e0ca051b7 100644 --- a/arch/arm/plat-omap/include/plat/gpmc.h +++ b/arch/arm/plat-omap/include/plat/gpmc.h @@ -52,6 +52,7 @@ #define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1)) #define GPMC_CONFIG1_FCLK_DIV3 (GPMC_CONFIG1_FCLK_DIV(2)) #define GPMC_CONFIG1_FCLK_DIV4 (GPMC_CONFIG1_FCLK_DIV(3)) +#define GPMC_CONFIG7_CSVALID (1 << 6) /* * Note that all values in this struct are in nanoseconds, while @@ -107,6 +108,8 @@ extern int gpmc_prefetch_enable(int cs, int dma_mode, unsigned int u32_count, int is_write); extern void gpmc_prefetch_reset(void); extern int gpmc_prefetch_status(void); +extern void omap3_gpmc_save_context(void); +extern void omap3_gpmc_restore_context(void); extern void __init gpmc_init(void); #endif From 40c670f0314c3c9463ce9c2f2b9b1085884837f6 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:47:48 +0530 Subject: [PATCH 02/32] OMAP3: PM: GPIO context save/restore Add context save and restore to enable off-mode. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/plat-omap/gpio.c | 92 ++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/gpio.h | 3 +- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 35a59ce5a2b4..b71052c6581b 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -290,6 +290,23 @@ static struct gpio_bank gpio_bank_34xx[6] = { METHOD_GPIO_24XX }, }; +struct omap3_gpio_regs { + u32 sysconfig; + u32 irqenable1; + u32 irqenable2; + u32 wake_en; + u32 ctrl; + u32 oe; + u32 leveldetect0; + u32 leveldetect1; + u32 risingdetect; + u32 fallingdetect; + u32 dataout; + u32 setwkuena; + u32 setdataout; +}; + +static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS]; #endif #ifdef CONFIG_ARCH_OMAP4 @@ -2036,6 +2053,81 @@ void omap2_gpio_resume_after_retention(void) #endif +#ifdef CONFIG_ARCH_OMAP34XX +/* save the registers of bank 2-6 */ +void omap_gpio_save_context(void) +{ + int i; + + /* saving banks from 2-6 only since GPIO1 is in WKUP */ + for (i = 1; i < gpio_bank_count; i++) { + struct gpio_bank *bank = &gpio_bank[i]; + gpio_context[i].sysconfig = + __raw_readl(bank->base + OMAP24XX_GPIO_SYSCONFIG); + gpio_context[i].irqenable1 = + __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); + gpio_context[i].irqenable2 = + __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); + gpio_context[i].wake_en = + __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); + gpio_context[i].ctrl = + __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); + gpio_context[i].oe = + __raw_readl(bank->base + OMAP24XX_GPIO_OE); + gpio_context[i].leveldetect0 = + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); + gpio_context[i].leveldetect1 = + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + gpio_context[i].risingdetect = + __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); + gpio_context[i].fallingdetect = + __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); + gpio_context[i].dataout = + __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); + gpio_context[i].setwkuena = + __raw_readl(bank->base + OMAP24XX_GPIO_SETWKUENA); + gpio_context[i].setdataout = + __raw_readl(bank->base + OMAP24XX_GPIO_SETDATAOUT); + } +} + +/* restore the required registers of bank 2-6 */ +void omap_gpio_restore_context(void) +{ + int i; + + for (i = 1; i < gpio_bank_count; i++) { + struct gpio_bank *bank = &gpio_bank[i]; + __raw_writel(gpio_context[i].sysconfig, + bank->base + OMAP24XX_GPIO_SYSCONFIG); + __raw_writel(gpio_context[i].irqenable1, + bank->base + OMAP24XX_GPIO_IRQENABLE1); + __raw_writel(gpio_context[i].irqenable2, + bank->base + OMAP24XX_GPIO_IRQENABLE2); + __raw_writel(gpio_context[i].wake_en, + bank->base + OMAP24XX_GPIO_WAKE_EN); + __raw_writel(gpio_context[i].ctrl, + bank->base + OMAP24XX_GPIO_CTRL); + __raw_writel(gpio_context[i].oe, + bank->base + OMAP24XX_GPIO_OE); + __raw_writel(gpio_context[i].leveldetect0, + bank->base + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(gpio_context[i].leveldetect1, + bank->base + OMAP24XX_GPIO_LEVELDETECT1); + __raw_writel(gpio_context[i].risingdetect, + bank->base + OMAP24XX_GPIO_RISINGDETECT); + __raw_writel(gpio_context[i].fallingdetect, + bank->base + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(gpio_context[i].dataout, + bank->base + OMAP24XX_GPIO_DATAOUT); + __raw_writel(gpio_context[i].setwkuena, + bank->base + OMAP24XX_GPIO_SETWKUENA); + __raw_writel(gpio_context[i].setdataout, + bank->base + OMAP24XX_GPIO_SETDATAOUT); + } +} +#endif + /* * This may get called early from board specific init * for boards that have interrupts routed via FPGA. diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h index 633ff688b928..de7c54731cbe 100644 --- a/arch/arm/plat-omap/include/plat/gpio.h +++ b/arch/arm/plat-omap/include/plat/gpio.h @@ -76,7 +76,8 @@ extern void omap2_gpio_prepare_for_retention(void); extern void omap2_gpio_resume_after_retention(void); extern void omap_set_gpio_debounce(int gpio, int enable); extern void omap_set_gpio_debounce_time(int gpio, int enable); - +extern void omap_gpio_save_context(void); +extern void omap_gpio_restore_context(void); /*-------------------------------------------------------------------------*/ /* Wrappers for "new style" GPIO calls, using the new infrastructure From 0addd61bc2028842bdcbd92c622d1110fc29c5a3 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:48:20 +0530 Subject: [PATCH 03/32] OMAP3: PM: INTC context save/restore Add context save and restore for the INTC module to support off-mode. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/irq.c | 66 ++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/irqs.h | 5 ++ 2 files changed, 71 insertions(+) diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index 1db121f437d2..ebd3538bd1d4 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -25,6 +25,10 @@ #define INTC_SYSSTATUS 0x0014 #define INTC_SIR 0x0040 #define INTC_CONTROL 0x0048 +#define INTC_PROTECTION 0x004C +#define INTC_IDLE 0x0050 +#define INTC_THRESHOLD 0x0068 +#define INTC_MIR0 0x0084 #define INTC_MIR_CLEAR0 0x0088 #define INTC_MIR_SET0 0x008c #define INTC_PENDING_IRQ0 0x0098 @@ -48,6 +52,18 @@ static struct omap_irq_bank { }, }; +/* Structure to save interrupt controller context */ +struct omap3_intc_regs { + u32 sysconfig; + u32 protection; + u32 idle; + u32 threshold; + u32 ilr[INTCPS_NR_IRQS]; + u32 mir[INTCPS_NR_MIR_REGS]; +}; + +static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)]; + /* INTC bank register get/set */ static void intc_bank_write_reg(u32 val, struct omap_irq_bank *bank, u16 reg) @@ -209,3 +225,53 @@ void __init omap_init_irq(void) } } +#ifdef CONFIG_ARCH_OMAP3 +void omap_intc_save_context(void) +{ + int ind = 0, i = 0; + for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) { + struct omap_irq_bank *bank = irq_banks + ind; + intc_context[ind].sysconfig = + intc_bank_read_reg(bank, INTC_SYSCONFIG); + intc_context[ind].protection = + intc_bank_read_reg(bank, INTC_PROTECTION); + intc_context[ind].idle = + intc_bank_read_reg(bank, INTC_IDLE); + intc_context[ind].threshold = + intc_bank_read_reg(bank, INTC_THRESHOLD); + for (i = 0; i < INTCPS_NR_IRQS; i++) + intc_context[ind].ilr[i] = + intc_bank_read_reg(bank, (0x100 + 0x4*ind)); + for (i = 0; i < INTCPS_NR_MIR_REGS; i++) + intc_context[ind].mir[i] = + intc_bank_read_reg(&irq_banks[0], INTC_MIR0 + + (0x20 * i)); + } +} + +void omap_intc_restore_context(void) +{ + int ind = 0, i = 0; + + for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) { + struct omap_irq_bank *bank = irq_banks + ind; + intc_bank_write_reg(intc_context[ind].sysconfig, + bank, INTC_SYSCONFIG); + intc_bank_write_reg(intc_context[ind].sysconfig, + bank, INTC_SYSCONFIG); + intc_bank_write_reg(intc_context[ind].protection, + bank, INTC_PROTECTION); + intc_bank_write_reg(intc_context[ind].idle, + bank, INTC_IDLE); + intc_bank_write_reg(intc_context[ind].threshold, + bank, INTC_THRESHOLD); + for (i = 0; i < INTCPS_NR_IRQS; i++) + intc_bank_write_reg(intc_context[ind].ilr[i], + bank, (0x100 + 0x4*ind)); + for (i = 0; i < INTCPS_NR_MIR_REGS; i++) + intc_bank_write_reg(intc_context[ind].mir[i], + &irq_banks[0], INTC_MIR0 + (0x20 * i)); + } + /* MIRs are saved and restore with other PRCM registers */ +} +#endif /* CONFIG_ARCH_OMAP3 */ diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h index 6a6d0281e1d5..ce5dd2d1dc21 100644 --- a/arch/arm/plat-omap/include/plat/irqs.h +++ b/arch/arm/plat-omap/include/plat/irqs.h @@ -477,9 +477,14 @@ #define OMAP_IRQ_BIT(irq) (1 << ((irq) % 32)) +#define INTCPS_NR_MIR_REGS 3 +#define INTCPS_NR_IRQS 96 + #ifndef __ASSEMBLY__ extern void omap_init_irq(void); extern int omap_irq_pending(void); +void omap_intc_save_context(void); +void omap_intc_restore_context(void); #endif #include From c171a2586161c623253186c394ca456947ec6a66 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:48:31 +0530 Subject: [PATCH 04/32] OMAP3: PM: PRCM context save/restore Add context save and restore for PRCM module to support off-mode. Additional registers (CM_CLKSEL4, CM_CLKEN, CM_CLKEN2) added by Tero Kristo. Missing CM_CLKEN_PLL_IVA2 register added by Kalle Jokiniemi. Signed-off-by: Rajendra Nayak Signed-off-by: Tero Kristo Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/prcm.c | 389 ++++++++++++++++++++++ arch/arm/plat-omap/include/plat/control.h | 2 + arch/arm/plat-omap/include/plat/prcm.h | 8 +- 3 files changed, 397 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index b0d3ad05be2e..56f77df1ffac 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -7,6 +7,9 @@ * * Written by Tony Lindgren * + * Copyright (C) 2007 Texas Instruments, Inc. + * Rajendra Nayak + * * Some pieces of code Copyright (C) 2005 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify @@ -21,8 +24,11 @@ #include #include +#include +#include #include "clock.h" +#include "cm.h" #include "prm.h" #include "prm-regbits-24xx.h" @@ -31,6 +37,88 @@ static void __iomem *cm_base; #define MAX_MODULE_ENABLE_WAIT 100000 +struct omap3_prcm_regs { + u32 control_padconf_sys_nirq; + u32 iva2_cm_clksel2; + u32 cm_sysconfig; + u32 sgx_cm_clksel; + u32 wkup_cm_clksel; + u32 dss_cm_clksel; + u32 cam_cm_clksel; + u32 per_cm_clksel; + u32 emu_cm_clksel; + u32 emu_cm_clkstctrl; + u32 pll_cm_autoidle2; + u32 pll_cm_clksel4; + u32 pll_cm_clksel5; + u32 pll_cm_clken; + u32 pll_cm_clken2; + u32 cm_polctrl; + u32 iva2_cm_fclken; + u32 iva2_cm_clken_pll; + u32 core_cm_fclken1; + u32 core_cm_fclken3; + u32 sgx_cm_fclken; + u32 wkup_cm_fclken; + u32 dss_cm_fclken; + u32 cam_cm_fclken; + u32 per_cm_fclken; + u32 usbhost_cm_fclken; + u32 core_cm_iclken1; + u32 core_cm_iclken2; + u32 core_cm_iclken3; + u32 sgx_cm_iclken; + u32 wkup_cm_iclken; + u32 dss_cm_iclken; + u32 cam_cm_iclken; + u32 per_cm_iclken; + u32 usbhost_cm_iclken; + u32 iva2_cm_autiidle2; + u32 mpu_cm_autoidle2; + u32 pll_cm_autoidle; + u32 iva2_cm_clkstctrl; + u32 mpu_cm_clkstctrl; + u32 core_cm_clkstctrl; + u32 sgx_cm_clkstctrl; + u32 dss_cm_clkstctrl; + u32 cam_cm_clkstctrl; + u32 per_cm_clkstctrl; + u32 neon_cm_clkstctrl; + u32 usbhost_cm_clkstctrl; + u32 core_cm_autoidle1; + u32 core_cm_autoidle2; + u32 core_cm_autoidle3; + u32 wkup_cm_autoidle; + u32 dss_cm_autoidle; + u32 cam_cm_autoidle; + u32 per_cm_autoidle; + u32 usbhost_cm_autoidle; + u32 sgx_cm_sleepdep; + u32 dss_cm_sleepdep; + u32 cam_cm_sleepdep; + u32 per_cm_sleepdep; + u32 usbhost_cm_sleepdep; + u32 cm_clkout_ctrl; + u32 prm_clkout_ctrl; + u32 sgx_pm_wkdep; + u32 dss_pm_wkdep; + u32 cam_pm_wkdep; + u32 per_pm_wkdep; + u32 neon_pm_wkdep; + u32 usbhost_pm_wkdep; + u32 core_pm_mpugrpsel1; + u32 iva2_pm_ivagrpsel1; + u32 core_pm_mpugrpsel3; + u32 core_pm_ivagrpsel3; + u32 wkup_pm_mpugrpsel; + u32 wkup_pm_ivagrpsel; + u32 per_pm_mpugrpsel; + u32 per_pm_ivagrpsel; + u32 wkup_pm_wken; +}; + +struct omap3_prcm_regs prcm_context; + u32 omap_prcm_get_reset_sources(void) { /* XXX This presumably needs modification for 34XX */ @@ -168,3 +256,304 @@ void __init omap2_set_globals_prcm(struct omap_globals *omap2_globals) prm_base = omap2_globals->prm; cm_base = omap2_globals->cm; } + +#ifdef CONFIG_ARCH_OMAP3 +void omap3_prcm_save_context(void) +{ + prcm_context.control_padconf_sys_nirq = + omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_SYSNIRQ); + prcm_context.iva2_cm_clksel2 = + cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL2); + prcm_context.cm_sysconfig = __raw_readl(OMAP3430_CM_SYSCONFIG); + prcm_context.sgx_cm_clksel = + cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSEL); + prcm_context.wkup_cm_clksel = cm_read_mod_reg(WKUP_MOD, CM_CLKSEL); + prcm_context.dss_cm_clksel = + cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSEL); + prcm_context.cam_cm_clksel = + cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSEL); + prcm_context.per_cm_clksel = + cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSEL); + prcm_context.emu_cm_clksel = + cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1); + prcm_context.emu_cm_clkstctrl = + cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSTCTRL); + prcm_context.pll_cm_autoidle2 = + cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2); + prcm_context.pll_cm_clksel4 = + cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4); + prcm_context.pll_cm_clksel5 = + cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5); + prcm_context.pll_cm_clken = + cm_read_mod_reg(PLL_MOD, CM_CLKEN); + prcm_context.pll_cm_clken2 = + cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2); + prcm_context.cm_polctrl = __raw_readl(OMAP3430_CM_POLCTRL); + prcm_context.iva2_cm_fclken = + cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_FCLKEN); + prcm_context.iva2_cm_clken_pll = cm_read_mod_reg(OMAP3430_IVA2_MOD, + OMAP3430_CM_CLKEN_PLL); + prcm_context.core_cm_fclken1 = + cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); + prcm_context.core_cm_fclken3 = + cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3); + prcm_context.sgx_cm_fclken = + cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_FCLKEN); + prcm_context.wkup_cm_fclken = + cm_read_mod_reg(WKUP_MOD, CM_FCLKEN); + prcm_context.dss_cm_fclken = + cm_read_mod_reg(OMAP3430_DSS_MOD, CM_FCLKEN); + prcm_context.cam_cm_fclken = + cm_read_mod_reg(OMAP3430_CAM_MOD, CM_FCLKEN); + prcm_context.per_cm_fclken = + cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN); + prcm_context.usbhost_cm_fclken = + cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN); + prcm_context.core_cm_iclken1 = + cm_read_mod_reg(CORE_MOD, CM_ICLKEN1); + prcm_context.core_cm_iclken2 = + cm_read_mod_reg(CORE_MOD, CM_ICLKEN2); + prcm_context.core_cm_iclken3 = + cm_read_mod_reg(CORE_MOD, CM_ICLKEN3); + prcm_context.sgx_cm_iclken = + cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_ICLKEN); + prcm_context.wkup_cm_iclken = + cm_read_mod_reg(WKUP_MOD, CM_ICLKEN); + prcm_context.dss_cm_iclken = + cm_read_mod_reg(OMAP3430_DSS_MOD, CM_ICLKEN); + prcm_context.cam_cm_iclken = + cm_read_mod_reg(OMAP3430_CAM_MOD, CM_ICLKEN); + prcm_context.per_cm_iclken = + cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN); + prcm_context.usbhost_cm_iclken = + cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN); + prcm_context.iva2_cm_autiidle2 = + cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_AUTOIDLE2); + prcm_context.mpu_cm_autoidle2 = + cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2); + prcm_context.pll_cm_autoidle = + cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); + prcm_context.iva2_cm_clkstctrl = + cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSTCTRL); + prcm_context.mpu_cm_clkstctrl = + cm_read_mod_reg(MPU_MOD, CM_CLKSTCTRL); + prcm_context.core_cm_clkstctrl = + cm_read_mod_reg(CORE_MOD, CM_CLKSTCTRL); + prcm_context.sgx_cm_clkstctrl = + cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSTCTRL); + prcm_context.dss_cm_clkstctrl = + cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSTCTRL); + prcm_context.cam_cm_clkstctrl = + cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSTCTRL); + prcm_context.per_cm_clkstctrl = + cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSTCTRL); + prcm_context.neon_cm_clkstctrl = + cm_read_mod_reg(OMAP3430_NEON_MOD, CM_CLKSTCTRL); + prcm_context.usbhost_cm_clkstctrl = + cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL); + prcm_context.core_cm_autoidle1 = + cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE1); + prcm_context.core_cm_autoidle2 = + cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE2); + prcm_context.core_cm_autoidle3 = + cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE3); + prcm_context.wkup_cm_autoidle = + cm_read_mod_reg(WKUP_MOD, CM_AUTOIDLE); + prcm_context.dss_cm_autoidle = + cm_read_mod_reg(OMAP3430_DSS_MOD, CM_AUTOIDLE); + prcm_context.cam_cm_autoidle = + cm_read_mod_reg(OMAP3430_CAM_MOD, CM_AUTOIDLE); + prcm_context.per_cm_autoidle = + cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE); + prcm_context.usbhost_cm_autoidle = + cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE); + prcm_context.sgx_cm_sleepdep = + cm_read_mod_reg(OMAP3430ES2_SGX_MOD, OMAP3430_CM_SLEEPDEP); + prcm_context.dss_cm_sleepdep = + cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP3430_CM_SLEEPDEP); + prcm_context.cam_cm_sleepdep = + cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP3430_CM_SLEEPDEP); + prcm_context.per_cm_sleepdep = + cm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_CM_SLEEPDEP); + prcm_context.usbhost_cm_sleepdep = + cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP); + prcm_context.cm_clkout_ctrl = cm_read_mod_reg(OMAP3430_CCR_MOD, + OMAP3_CM_CLKOUT_CTRL_OFFSET); + prcm_context.prm_clkout_ctrl = prm_read_mod_reg(OMAP3430_CCR_MOD, + OMAP3_PRM_CLKOUT_CTRL_OFFSET); + prcm_context.sgx_pm_wkdep = + prm_read_mod_reg(OMAP3430ES2_SGX_MOD, PM_WKDEP); + prcm_context.dss_pm_wkdep = + prm_read_mod_reg(OMAP3430_DSS_MOD, PM_WKDEP); + prcm_context.cam_pm_wkdep = + prm_read_mod_reg(OMAP3430_CAM_MOD, PM_WKDEP); + prcm_context.per_pm_wkdep = + prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKDEP); + prcm_context.neon_pm_wkdep = + prm_read_mod_reg(OMAP3430_NEON_MOD, PM_WKDEP); + prcm_context.usbhost_pm_wkdep = + prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKDEP); + prcm_context.core_pm_mpugrpsel1 = + prm_read_mod_reg(CORE_MOD, OMAP3430_PM_MPUGRPSEL1); + prcm_context.iva2_pm_ivagrpsel1 = + prm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_PM_IVAGRPSEL1); + prcm_context.core_pm_mpugrpsel3 = + prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_MPUGRPSEL3); + prcm_context.core_pm_ivagrpsel3 = + prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); + prcm_context.wkup_pm_mpugrpsel = + prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_MPUGRPSEL); + prcm_context.wkup_pm_ivagrpsel = + prm_read_mod_reg(WKUP_MOD, OMAP3430_PM_IVAGRPSEL); + prcm_context.per_pm_mpugrpsel = + prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); + prcm_context.per_pm_ivagrpsel = + prm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); + prcm_context.wkup_pm_wken = prm_read_mod_reg(WKUP_MOD, PM_WKEN); + return; +} + +void omap3_prcm_restore_context(void) +{ + omap_ctrl_writel(prcm_context.control_padconf_sys_nirq, + OMAP343X_CONTROL_PADCONF_SYSNIRQ); + cm_write_mod_reg(prcm_context.iva2_cm_clksel2, OMAP3430_IVA2_MOD, + CM_CLKSEL2); + __raw_writel(prcm_context.cm_sysconfig, OMAP3430_CM_SYSCONFIG); + cm_write_mod_reg(prcm_context.sgx_cm_clksel, OMAP3430ES2_SGX_MOD, + CM_CLKSEL); + cm_write_mod_reg(prcm_context.wkup_cm_clksel, WKUP_MOD, CM_CLKSEL); + cm_write_mod_reg(prcm_context.dss_cm_clksel, OMAP3430_DSS_MOD, + CM_CLKSEL); + cm_write_mod_reg(prcm_context.cam_cm_clksel, OMAP3430_CAM_MOD, + CM_CLKSEL); + cm_write_mod_reg(prcm_context.per_cm_clksel, OMAP3430_PER_MOD, + CM_CLKSEL); + cm_write_mod_reg(prcm_context.emu_cm_clksel, OMAP3430_EMU_MOD, + CM_CLKSEL1); + cm_write_mod_reg(prcm_context.emu_cm_clkstctrl, OMAP3430_EMU_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.pll_cm_autoidle2, PLL_MOD, + CM_AUTOIDLE2); + cm_write_mod_reg(prcm_context.pll_cm_clksel4, PLL_MOD, + OMAP3430ES2_CM_CLKSEL4); + cm_write_mod_reg(prcm_context.pll_cm_clksel5, PLL_MOD, + OMAP3430ES2_CM_CLKSEL5); + cm_write_mod_reg(prcm_context.pll_cm_clken, PLL_MOD, CM_CLKEN); + cm_write_mod_reg(prcm_context.pll_cm_clken2, PLL_MOD, + OMAP3430ES2_CM_CLKEN2); + __raw_writel(prcm_context.cm_polctrl, OMAP3430_CM_POLCTRL); + cm_write_mod_reg(prcm_context.iva2_cm_fclken, OMAP3430_IVA2_MOD, + CM_FCLKEN); + cm_write_mod_reg(prcm_context.iva2_cm_clken_pll, OMAP3430_IVA2_MOD, + OMAP3430_CM_CLKEN_PLL); + cm_write_mod_reg(prcm_context.core_cm_fclken1, CORE_MOD, CM_FCLKEN1); + cm_write_mod_reg(prcm_context.core_cm_fclken3, CORE_MOD, + OMAP3430ES2_CM_FCLKEN3); + cm_write_mod_reg(prcm_context.sgx_cm_fclken, OMAP3430ES2_SGX_MOD, + CM_FCLKEN); + cm_write_mod_reg(prcm_context.wkup_cm_fclken, WKUP_MOD, CM_FCLKEN); + cm_write_mod_reg(prcm_context.dss_cm_fclken, OMAP3430_DSS_MOD, + CM_FCLKEN); + cm_write_mod_reg(prcm_context.cam_cm_fclken, OMAP3430_CAM_MOD, + CM_FCLKEN); + cm_write_mod_reg(prcm_context.per_cm_fclken, OMAP3430_PER_MOD, + CM_FCLKEN); + cm_write_mod_reg(prcm_context.usbhost_cm_fclken, + OMAP3430ES2_USBHOST_MOD, CM_FCLKEN); + cm_write_mod_reg(prcm_context.core_cm_iclken1, CORE_MOD, CM_ICLKEN1); + cm_write_mod_reg(prcm_context.core_cm_iclken2, CORE_MOD, CM_ICLKEN2); + cm_write_mod_reg(prcm_context.core_cm_iclken3, CORE_MOD, CM_ICLKEN3); + cm_write_mod_reg(prcm_context.sgx_cm_iclken, OMAP3430ES2_SGX_MOD, + CM_ICLKEN); + cm_write_mod_reg(prcm_context.wkup_cm_iclken, WKUP_MOD, CM_ICLKEN); + cm_write_mod_reg(prcm_context.dss_cm_iclken, OMAP3430_DSS_MOD, + CM_ICLKEN); + cm_write_mod_reg(prcm_context.cam_cm_iclken, OMAP3430_CAM_MOD, + CM_ICLKEN); + cm_write_mod_reg(prcm_context.per_cm_iclken, OMAP3430_PER_MOD, + CM_ICLKEN); + cm_write_mod_reg(prcm_context.usbhost_cm_iclken, + OMAP3430ES2_USBHOST_MOD, CM_ICLKEN); + cm_write_mod_reg(prcm_context.iva2_cm_autiidle2, OMAP3430_IVA2_MOD, + CM_AUTOIDLE2); + cm_write_mod_reg(prcm_context.mpu_cm_autoidle2, MPU_MOD, CM_AUTOIDLE2); + cm_write_mod_reg(prcm_context.pll_cm_autoidle, PLL_MOD, CM_AUTOIDLE); + cm_write_mod_reg(prcm_context.iva2_cm_clkstctrl, OMAP3430_IVA2_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.mpu_cm_clkstctrl, MPU_MOD, CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.core_cm_clkstctrl, CORE_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.sgx_cm_clkstctrl, OMAP3430ES2_SGX_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.dss_cm_clkstctrl, OMAP3430_DSS_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.cam_cm_clkstctrl, OMAP3430_CAM_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.per_cm_clkstctrl, OMAP3430_PER_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.neon_cm_clkstctrl, OMAP3430_NEON_MOD, + CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.usbhost_cm_clkstctrl, + OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL); + cm_write_mod_reg(prcm_context.core_cm_autoidle1, CORE_MOD, + CM_AUTOIDLE1); + cm_write_mod_reg(prcm_context.core_cm_autoidle2, CORE_MOD, + CM_AUTOIDLE2); + cm_write_mod_reg(prcm_context.core_cm_autoidle3, CORE_MOD, + CM_AUTOIDLE3); + cm_write_mod_reg(prcm_context.wkup_cm_autoidle, WKUP_MOD, CM_AUTOIDLE); + cm_write_mod_reg(prcm_context.dss_cm_autoidle, OMAP3430_DSS_MOD, + CM_AUTOIDLE); + cm_write_mod_reg(prcm_context.cam_cm_autoidle, OMAP3430_CAM_MOD, + CM_AUTOIDLE); + cm_write_mod_reg(prcm_context.per_cm_autoidle, OMAP3430_PER_MOD, + CM_AUTOIDLE); + cm_write_mod_reg(prcm_context.usbhost_cm_autoidle, + OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE); + cm_write_mod_reg(prcm_context.sgx_cm_sleepdep, OMAP3430ES2_SGX_MOD, + OMAP3430_CM_SLEEPDEP); + cm_write_mod_reg(prcm_context.dss_cm_sleepdep, OMAP3430_DSS_MOD, + OMAP3430_CM_SLEEPDEP); + cm_write_mod_reg(prcm_context.cam_cm_sleepdep, OMAP3430_CAM_MOD, + OMAP3430_CM_SLEEPDEP); + cm_write_mod_reg(prcm_context.per_cm_sleepdep, OMAP3430_PER_MOD, + OMAP3430_CM_SLEEPDEP); + cm_write_mod_reg(prcm_context.usbhost_cm_sleepdep, + OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP); + cm_write_mod_reg(prcm_context.cm_clkout_ctrl, OMAP3430_CCR_MOD, + OMAP3_CM_CLKOUT_CTRL_OFFSET); + prm_write_mod_reg(prcm_context.prm_clkout_ctrl, OMAP3430_CCR_MOD, + OMAP3_PRM_CLKOUT_CTRL_OFFSET); + prm_write_mod_reg(prcm_context.sgx_pm_wkdep, OMAP3430ES2_SGX_MOD, + PM_WKDEP); + prm_write_mod_reg(prcm_context.dss_pm_wkdep, OMAP3430_DSS_MOD, + PM_WKDEP); + prm_write_mod_reg(prcm_context.cam_pm_wkdep, OMAP3430_CAM_MOD, + PM_WKDEP); + prm_write_mod_reg(prcm_context.per_pm_wkdep, OMAP3430_PER_MOD, + PM_WKDEP); + prm_write_mod_reg(prcm_context.neon_pm_wkdep, OMAP3430_NEON_MOD, + PM_WKDEP); + prm_write_mod_reg(prcm_context.usbhost_pm_wkdep, + OMAP3430ES2_USBHOST_MOD, PM_WKDEP); + prm_write_mod_reg(prcm_context.core_pm_mpugrpsel1, CORE_MOD, + OMAP3430_PM_MPUGRPSEL1); + prm_write_mod_reg(prcm_context.iva2_pm_ivagrpsel1, OMAP3430_IVA2_MOD, + OMAP3430_PM_IVAGRPSEL1); + prm_write_mod_reg(prcm_context.core_pm_mpugrpsel3, CORE_MOD, + OMAP3430ES2_PM_MPUGRPSEL3); + prm_write_mod_reg(prcm_context.core_pm_ivagrpsel3, CORE_MOD, + OMAP3430ES2_PM_IVAGRPSEL3); + prm_write_mod_reg(prcm_context.wkup_pm_mpugrpsel, WKUP_MOD, + OMAP3430_PM_MPUGRPSEL); + prm_write_mod_reg(prcm_context.wkup_pm_ivagrpsel, WKUP_MOD, + OMAP3430_PM_IVAGRPSEL); + prm_write_mod_reg(prcm_context.per_pm_mpugrpsel, OMAP3430_PER_MOD, + OMAP3430_PM_MPUGRPSEL); + prm_write_mod_reg(prcm_context.per_pm_ivagrpsel, OMAP3430_PER_MOD, + OMAP3430_PM_IVAGRPSEL); + prm_write_mod_reg(prcm_context.wkup_pm_wken, WKUP_MOD, PM_WKEN); + return; +} +#endif diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h index 805819f3a868..835f5b7aa4b6 100644 --- a/arch/arm/plat-omap/include/plat/control.h +++ b/arch/arm/plat-omap/include/plat/control.h @@ -112,6 +112,8 @@ #define OMAP24XX_CONTROL_TEST_KEY_8 (OMAP2_CONTROL_GENERAL + 0x00e0) #define OMAP24XX_CONTROL_TEST_KEY_9 (OMAP2_CONTROL_GENERAL + 0x00e4) +#define OMAP343X_CONTROL_PADCONF_SYSNIRQ (OMAP2_CONTROL_INTERFACE + 0x01b0) + /* 34xx-only CONTROL_GENERAL register offsets */ #define OMAP343X_CONTROL_PADCONF_OFF (OMAP2_CONTROL_GENERAL + 0x0000) #define OMAP343X_CONTROL_MEM_DFTRW0 (OMAP2_CONTROL_GENERAL + 0x0008) diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h index cda2a70397b4..e63e94e18975 100644 --- a/arch/arm/plat-omap/include/plat/prcm.h +++ b/arch/arm/plat-omap/include/plat/prcm.h @@ -27,9 +27,13 @@ u32 omap_prcm_get_reset_sources(void); void omap_prcm_arch_reset(char mode); int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, const char *name); +#define START_PADCONF_SAVE 0x2 +#define PADCONF_SAVE_DONE 0x1 + +void omap3_prcm_save_context(void); +void omap3_prcm_restore_context(void); + #endif - - From 8014078684377257e3a83ac45db95711929850c5 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:48:46 +0530 Subject: [PATCH 05/32] OMAP3: PM: Populate scratchpad contents This patch populates the scratchpad contents as expected by the bootROM code. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/control.c | 203 ++++++++++++++++++++++ arch/arm/plat-omap/include/plat/control.h | 10 ++ 2 files changed, 213 insertions(+) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 6adb360c6d45..03e1bce3b3bb 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -17,9 +17,81 @@ #include #include +#include +#include "cm-regbits-34xx.h" +#include "prm-regbits-34xx.h" +#include "cm.h" +#include "prm.h" +#include "sdrc.h" static void __iomem *omap2_ctrl_base; +struct omap3_scratchpad { + u32 boot_config_ptr; + u32 public_restore_ptr; + u32 secure_ram_restore_ptr; + u32 sdrc_module_semaphore; + u32 prcm_block_offset; + u32 sdrc_block_offset; +}; + +struct omap3_scratchpad_prcm_block { + u32 prm_clksrc_ctrl; + u32 prm_clksel; + u32 cm_clksel_core; + u32 cm_clksel_wkup; + u32 cm_clken_pll; + u32 cm_autoidle_pll; + u32 cm_clksel1_pll; + u32 cm_clksel2_pll; + u32 cm_clksel3_pll; + u32 cm_clken_pll_mpu; + u32 cm_autoidle_pll_mpu; + u32 cm_clksel1_pll_mpu; + u32 cm_clksel2_pll_mpu; + u32 prcm_block_size; +}; + +struct omap3_scratchpad_sdrc_block { + u16 sysconfig; + u16 cs_cfg; + u16 sharing; + u16 err_type; + u32 dll_a_ctrl; + u32 dll_b_ctrl; + u32 power; + u32 cs_0; + u32 mcfg_0; + u16 mr_0; + u16 emr_1_0; + u16 emr_2_0; + u16 emr_3_0; + u32 actim_ctrla_0; + u32 actim_ctrlb_0; + u32 rfr_ctrl_0; + u32 cs_1; + u32 mcfg_1; + u16 mr_1; + u16 emr_1_1; + u16 emr_2_1; + u16 emr_3_1; + u32 actim_ctrla_1; + u32 actim_ctrlb_1; + u32 rfr_ctrl_1; + u16 dcdl_1_ctrl; + u16 dcdl_2_ctrl; + u32 flags; + u32 block_size; +}; + +/* + * This is used to store ARM registers in SDRAM before attempting + * an MPU OFF. The save and restore happens from the SRAM sleep code. + * The address is stored in scratchpad, so that it can be used + * during the restore path. + */ +u32 omap3_arm_context[128]; + #define OMAP_CTRL_REGADDR(reg) (omap2_ctrl_base + (reg)) void __init omap2_set_globals_control(struct omap_globals *omap2_globals) @@ -62,3 +134,134 @@ void omap_ctrl_writel(u32 val, u16 offset) __raw_writel(val, OMAP_CTRL_REGADDR(offset)); } +#ifdef CONFIG_ARCH_OMAP3 +/* + * Clears the scratchpad contents in case of cold boot- + * called during bootup + */ +void omap3_clear_scratchpad_contents(void) +{ + u32 max_offset = OMAP343X_SCRATCHPAD_ROM_OFFSET; + u32 *v_addr; + u32 offset = 0; + v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM); + if (prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) & + OMAP3430_GLOBAL_COLD_RST) { + for ( ; offset <= max_offset; offset += 0x4) + __raw_writel(0x0, (v_addr + offset)); + prm_set_mod_reg_bits(OMAP3430_GLOBAL_COLD_RST, OMAP3430_GR_MOD, + OMAP3_PRM_RSTST_OFFSET); + } +} + +/* Populate the scratchpad structure with restore structure */ +void omap3_save_scratchpad_contents(void) +{ + void * __iomem scratchpad_address; + u32 arm_context_addr; + struct omap3_scratchpad scratchpad_contents; + struct omap3_scratchpad_prcm_block prcm_block_contents; + struct omap3_scratchpad_sdrc_block sdrc_block_contents; + + /* Populate the Scratchpad contents */ + scratchpad_contents.boot_config_ptr = 0x0; + scratchpad_contents.public_restore_ptr = + virt_to_phys(get_restore_pointer()); + scratchpad_contents.secure_ram_restore_ptr = 0x0; + scratchpad_contents.sdrc_module_semaphore = 0x0; + scratchpad_contents.prcm_block_offset = 0x2C; + scratchpad_contents.sdrc_block_offset = 0x64; + + /* Populate the PRCM block contents */ + prcm_block_contents.prm_clksrc_ctrl = prm_read_mod_reg(OMAP3430_GR_MOD, + OMAP3_PRM_CLKSRC_CTRL_OFFSET); + prcm_block_contents.prm_clksel = prm_read_mod_reg(OMAP3430_CCR_MOD, + OMAP3_PRM_CLKSEL_OFFSET); + prcm_block_contents.cm_clksel_core = + cm_read_mod_reg(CORE_MOD, CM_CLKSEL); + prcm_block_contents.cm_clksel_wkup = + cm_read_mod_reg(WKUP_MOD, CM_CLKSEL); + prcm_block_contents.cm_clken_pll = + cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKEN_PLL); + prcm_block_contents.cm_autoidle_pll = + cm_read_mod_reg(PLL_MOD, OMAP3430_CM_AUTOIDLE_PLL); + prcm_block_contents.cm_clksel1_pll = + cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL); + prcm_block_contents.cm_clksel2_pll = + cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL2_PLL); + prcm_block_contents.cm_clksel3_pll = + cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL3); + prcm_block_contents.cm_clken_pll_mpu = + cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKEN_PLL); + prcm_block_contents.cm_autoidle_pll_mpu = + cm_read_mod_reg(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL); + prcm_block_contents.cm_clksel1_pll_mpu = + cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL); + prcm_block_contents.cm_clksel2_pll_mpu = + cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL); + prcm_block_contents.prcm_block_size = 0x0; + + /* Populate the SDRC block contents */ + sdrc_block_contents.sysconfig = + (sdrc_read_reg(SDRC_SYSCONFIG) & 0xFFFF); + sdrc_block_contents.cs_cfg = + (sdrc_read_reg(SDRC_CS_CFG) & 0xFFFF); + sdrc_block_contents.sharing = + (sdrc_read_reg(SDRC_SHARING) & 0xFFFF); + sdrc_block_contents.err_type = + (sdrc_read_reg(SDRC_ERR_TYPE) & 0xFFFF); + sdrc_block_contents.dll_a_ctrl = sdrc_read_reg(SDRC_DLLA_CTRL); + sdrc_block_contents.dll_b_ctrl = 0x0; + sdrc_block_contents.power = sdrc_read_reg(SDRC_POWER); + sdrc_block_contents.cs_0 = 0x0; + sdrc_block_contents.mcfg_0 = sdrc_read_reg(SDRC_MCFG_0); + sdrc_block_contents.mr_0 = (sdrc_read_reg(SDRC_MR_0) & 0xFFFF); + sdrc_block_contents.emr_1_0 = 0x0; + sdrc_block_contents.emr_2_0 = 0x0; + sdrc_block_contents.emr_3_0 = 0x0; + sdrc_block_contents.actim_ctrla_0 = + sdrc_read_reg(SDRC_ACTIM_CTRL_A_0); + sdrc_block_contents.actim_ctrlb_0 = + sdrc_read_reg(SDRC_ACTIM_CTRL_B_0); + sdrc_block_contents.rfr_ctrl_0 = + sdrc_read_reg(SDRC_RFR_CTRL_0); + sdrc_block_contents.cs_1 = 0x0; + sdrc_block_contents.mcfg_1 = sdrc_read_reg(SDRC_MCFG_1); + sdrc_block_contents.mr_1 = sdrc_read_reg(SDRC_MR_1) & 0xFFFF; + sdrc_block_contents.emr_1_1 = 0x0; + sdrc_block_contents.emr_2_1 = 0x0; + sdrc_block_contents.emr_3_1 = 0x0; + sdrc_block_contents.actim_ctrla_1 = + sdrc_read_reg(SDRC_ACTIM_CTRL_A_1); + sdrc_block_contents.actim_ctrlb_1 = + sdrc_read_reg(SDRC_ACTIM_CTRL_B_1); + sdrc_block_contents.rfr_ctrl_1 = + sdrc_read_reg(SDRC_RFR_CTRL_1); + sdrc_block_contents.dcdl_1_ctrl = 0x0; + sdrc_block_contents.dcdl_2_ctrl = 0x0; + sdrc_block_contents.flags = 0x0; + sdrc_block_contents.block_size = 0x0; + + arm_context_addr = virt_to_phys(omap3_arm_context); + + /* Copy all the contents to the scratchpad location */ + scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); + memcpy_toio(scratchpad_address, &scratchpad_contents, + sizeof(scratchpad_contents)); + /* Scratchpad contents being 32 bits, a divide by 4 done here */ + memcpy_toio(scratchpad_address + + scratchpad_contents.prcm_block_offset, + &prcm_block_contents, sizeof(prcm_block_contents)); + memcpy_toio(scratchpad_address + + scratchpad_contents.sdrc_block_offset, + &sdrc_block_contents, sizeof(sdrc_block_contents)); + /* + * Copies the address of the location in SDRAM where ARM + * registers get saved during a MPU OFF transition. + */ + memcpy_toio(scratchpad_address + + scratchpad_contents.sdrc_block_offset + + sizeof(sdrc_block_contents), &arm_context_addr, 4); +} + +#endif /* CONFIG_ARCH_OMAP3 */ diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h index 835f5b7aa4b6..1076dd967390 100644 --- a/arch/arm/plat-omap/include/plat/control.h +++ b/arch/arm/plat-omap/include/plat/control.h @@ -207,6 +207,10 @@ #define OMAP3_PADCONF_WAKEUPEVENT0 (1 << 15) #define OMAP3_PADCONF_WAKEUPENABLE0 (1 << 14) +#define OMAP343X_SCRATCHPAD_ROM (OMAP343X_CTRL_BASE + 0x860) +#define OMAP343X_SCRATCHPAD (OMAP343X_CTRL_BASE + 0x910) +#define OMAP343X_SCRATCHPAD_ROM_OFFSET 0x19C + #ifndef __ASSEMBLY__ #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ defined(CONFIG_ARCH_OMAP4) @@ -217,6 +221,12 @@ extern u32 omap_ctrl_readl(u16 offset); extern void omap_ctrl_writeb(u8 val, u16 offset); extern void omap_ctrl_writew(u16 val, u16 offset); extern void omap_ctrl_writel(u32 val, u16 offset); + +extern void omap3_save_scratchpad_contents(void); +extern void omap3_clear_scratchpad_contents(void); +extern u32 *get_restore_pointer(void); +extern u32 omap3_arm_context[128]; + #else #define omap_ctrl_base_get() 0 #define omap_ctrl_readb(x) 0 From c96631e13888e9be3a80aae291ed671d4d573ec9 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:49:02 +0530 Subject: [PATCH 06/32] OMAP3: PM: SCM context save/restore Add context save and restore for the System Control Module to suport off-mode. ETK and debobs definitions added by Peter De Schrijver. Signed-off-by: Rajendra Nayak Signed-off-by: Peter 'p2' De Schrijver Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/control.c | 157 +++++++++++++++++++++- arch/arm/plat-omap/include/plat/control.h | 49 ++++++- 2 files changed, 202 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 03e1bce3b3bb..3ea417d7a1b5 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -26,6 +26,7 @@ static void __iomem *omap2_ctrl_base; +#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) struct omap3_scratchpad { u32 boot_config_ptr; u32 public_restore_ptr; @@ -92,6 +93,47 @@ struct omap3_scratchpad_sdrc_block { */ u32 omap3_arm_context[128]; +struct omap3_control_regs { + u32 sysconfig; + u32 devconf0; + u32 mem_dftrw0; + u32 mem_dftrw1; + u32 msuspendmux_0; + u32 msuspendmux_1; + u32 msuspendmux_2; + u32 msuspendmux_3; + u32 msuspendmux_4; + u32 msuspendmux_5; + u32 sec_ctrl; + u32 devconf1; + u32 csirxfe; + u32 iva2_bootaddr; + u32 iva2_bootmod; + u32 debobs_0; + u32 debobs_1; + u32 debobs_2; + u32 debobs_3; + u32 debobs_4; + u32 debobs_5; + u32 debobs_6; + u32 debobs_7; + u32 debobs_8; + u32 prog_io0; + u32 prog_io1; + u32 dss_dpll_spreading; + u32 core_dpll_spreading; + u32 per_dpll_spreading; + u32 usbhost_dpll_spreading; + u32 pbias_lite; + u32 temp_sensor; + u32 sramldo4; + u32 sramldo5; + u32 csi; +}; + +static struct omap3_control_regs control_context; +#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */ + #define OMAP_CTRL_REGADDR(reg) (omap2_ctrl_base + (reg)) void __init omap2_set_globals_control(struct omap_globals *omap2_globals) @@ -134,7 +176,7 @@ void omap_ctrl_writel(u32 val, u16 offset) __raw_writel(val, OMAP_CTRL_REGADDR(offset)); } -#ifdef CONFIG_ARCH_OMAP3 +#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) /* * Clears the scratchpad contents in case of cold boot- * called during bootup @@ -264,4 +306,115 @@ void omap3_save_scratchpad_contents(void) sizeof(sdrc_block_contents), &arm_context_addr, 4); } -#endif /* CONFIG_ARCH_OMAP3 */ +void omap3_control_save_context(void) +{ + control_context.sysconfig = omap_ctrl_readl(OMAP2_CONTROL_SYSCONFIG); + control_context.devconf0 = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); + control_context.mem_dftrw0 = + omap_ctrl_readl(OMAP343X_CONTROL_MEM_DFTRW0); + control_context.mem_dftrw1 = + omap_ctrl_readl(OMAP343X_CONTROL_MEM_DFTRW1); + control_context.msuspendmux_0 = + omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_0); + control_context.msuspendmux_1 = + omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_1); + control_context.msuspendmux_2 = + omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_2); + control_context.msuspendmux_3 = + omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_3); + control_context.msuspendmux_4 = + omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_4); + control_context.msuspendmux_5 = + omap_ctrl_readl(OMAP2_CONTROL_MSUSPENDMUX_5); + control_context.sec_ctrl = omap_ctrl_readl(OMAP2_CONTROL_SEC_CTRL); + control_context.devconf1 = omap_ctrl_readl(OMAP343X_CONTROL_DEVCONF1); + control_context.csirxfe = omap_ctrl_readl(OMAP343X_CONTROL_CSIRXFE); + control_context.iva2_bootaddr = + omap_ctrl_readl(OMAP343X_CONTROL_IVA2_BOOTADDR); + control_context.iva2_bootmod = + omap_ctrl_readl(OMAP343X_CONTROL_IVA2_BOOTMOD); + control_context.debobs_0 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(0)); + control_context.debobs_1 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(1)); + control_context.debobs_2 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(2)); + control_context.debobs_3 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(3)); + control_context.debobs_4 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(4)); + control_context.debobs_5 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(5)); + control_context.debobs_6 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(6)); + control_context.debobs_7 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(7)); + control_context.debobs_8 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(8)); + control_context.prog_io0 = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO0); + control_context.prog_io1 = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1); + control_context.dss_dpll_spreading = + omap_ctrl_readl(OMAP343X_CONTROL_DSS_DPLL_SPREADING); + control_context.core_dpll_spreading = + omap_ctrl_readl(OMAP343X_CONTROL_CORE_DPLL_SPREADING); + control_context.per_dpll_spreading = + omap_ctrl_readl(OMAP343X_CONTROL_PER_DPLL_SPREADING); + control_context.usbhost_dpll_spreading = + omap_ctrl_readl(OMAP343X_CONTROL_USBHOST_DPLL_SPREADING); + control_context.pbias_lite = + omap_ctrl_readl(OMAP343X_CONTROL_PBIAS_LITE); + control_context.temp_sensor = + omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR); + control_context.sramldo4 = omap_ctrl_readl(OMAP343X_CONTROL_SRAMLDO4); + control_context.sramldo5 = omap_ctrl_readl(OMAP343X_CONTROL_SRAMLDO5); + control_context.csi = omap_ctrl_readl(OMAP343X_CONTROL_CSI); + return; +} + +void omap3_control_restore_context(void) +{ + omap_ctrl_writel(control_context.sysconfig, OMAP2_CONTROL_SYSCONFIG); + omap_ctrl_writel(control_context.devconf0, OMAP2_CONTROL_DEVCONF0); + omap_ctrl_writel(control_context.mem_dftrw0, + OMAP343X_CONTROL_MEM_DFTRW0); + omap_ctrl_writel(control_context.mem_dftrw1, + OMAP343X_CONTROL_MEM_DFTRW1); + omap_ctrl_writel(control_context.msuspendmux_0, + OMAP2_CONTROL_MSUSPENDMUX_0); + omap_ctrl_writel(control_context.msuspendmux_1, + OMAP2_CONTROL_MSUSPENDMUX_1); + omap_ctrl_writel(control_context.msuspendmux_2, + OMAP2_CONTROL_MSUSPENDMUX_2); + omap_ctrl_writel(control_context.msuspendmux_3, + OMAP2_CONTROL_MSUSPENDMUX_3); + omap_ctrl_writel(control_context.msuspendmux_4, + OMAP2_CONTROL_MSUSPENDMUX_4); + omap_ctrl_writel(control_context.msuspendmux_5, + OMAP2_CONTROL_MSUSPENDMUX_5); + omap_ctrl_writel(control_context.sec_ctrl, OMAP2_CONTROL_SEC_CTRL); + omap_ctrl_writel(control_context.devconf1, OMAP343X_CONTROL_DEVCONF1); + omap_ctrl_writel(control_context.csirxfe, OMAP343X_CONTROL_CSIRXFE); + omap_ctrl_writel(control_context.iva2_bootaddr, + OMAP343X_CONTROL_IVA2_BOOTADDR); + omap_ctrl_writel(control_context.iva2_bootmod, + OMAP343X_CONTROL_IVA2_BOOTMOD); + omap_ctrl_writel(control_context.debobs_0, OMAP343X_CONTROL_DEBOBS(0)); + omap_ctrl_writel(control_context.debobs_1, OMAP343X_CONTROL_DEBOBS(1)); + omap_ctrl_writel(control_context.debobs_2, OMAP343X_CONTROL_DEBOBS(2)); + omap_ctrl_writel(control_context.debobs_3, OMAP343X_CONTROL_DEBOBS(3)); + omap_ctrl_writel(control_context.debobs_4, OMAP343X_CONTROL_DEBOBS(4)); + omap_ctrl_writel(control_context.debobs_5, OMAP343X_CONTROL_DEBOBS(5)); + omap_ctrl_writel(control_context.debobs_6, OMAP343X_CONTROL_DEBOBS(6)); + omap_ctrl_writel(control_context.debobs_7, OMAP343X_CONTROL_DEBOBS(7)); + omap_ctrl_writel(control_context.debobs_8, OMAP343X_CONTROL_DEBOBS(8)); + omap_ctrl_writel(control_context.prog_io0, OMAP343X_CONTROL_PROG_IO0); + omap_ctrl_writel(control_context.prog_io1, OMAP343X_CONTROL_PROG_IO1); + omap_ctrl_writel(control_context.dss_dpll_spreading, + OMAP343X_CONTROL_DSS_DPLL_SPREADING); + omap_ctrl_writel(control_context.core_dpll_spreading, + OMAP343X_CONTROL_CORE_DPLL_SPREADING); + omap_ctrl_writel(control_context.per_dpll_spreading, + OMAP343X_CONTROL_PER_DPLL_SPREADING); + omap_ctrl_writel(control_context.usbhost_dpll_spreading, + OMAP343X_CONTROL_USBHOST_DPLL_SPREADING); + omap_ctrl_writel(control_context.pbias_lite, + OMAP343X_CONTROL_PBIAS_LITE); + omap_ctrl_writel(control_context.temp_sensor, + OMAP343X_CONTROL_TEMP_SENSOR); + omap_ctrl_writel(control_context.sramldo4, OMAP343X_CONTROL_SRAMLDO4); + omap_ctrl_writel(control_context.sramldo5, OMAP343X_CONTROL_SRAMLDO5); + omap_ctrl_writel(control_context.csi, OMAP343X_CONTROL_CSI); + return; +} +#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */ diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h index 1076dd967390..8ca73471ba45 100644 --- a/arch/arm/plat-omap/include/plat/control.h +++ b/arch/arm/plat-omap/include/plat/control.h @@ -146,8 +146,51 @@ #define OMAP343X_CONTROL_TEST_KEY_13 (OMAP2_CONTROL_GENERAL + 0x00fc) #define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190) #define OMAP343X_CONTROL_IVA2_BOOTMOD (OMAP2_CONTROL_GENERAL + 0x0194) -#define OMAP343X_CONTROL_PBIAS_LITE (OMAP2_CONTROL_GENERAL + 0x02b0) -#define OMAP343X_CONTROL_TEMP_SENSOR (OMAP2_CONTROL_GENERAL + 0x02b4) +#define OMAP343X_CONTROL_DEBOBS(i) (OMAP2_CONTROL_GENERAL + 0x01B0 \ + + ((i) >> 1) * 4 + (!(i) & 1) * 2) +#define OMAP343X_CONTROL_PROG_IO0 (OMAP2_CONTROL_GENERAL + 0x01D4) +#define OMAP343X_CONTROL_PROG_IO1 (OMAP2_CONTROL_GENERAL + 0x01D8) +#define OMAP343X_CONTROL_DSS_DPLL_SPREADING (OMAP2_CONTROL_GENERAL + 0x01E0) +#define OMAP343X_CONTROL_CORE_DPLL_SPREADING (OMAP2_CONTROL_GENERAL + 0x01E4) +#define OMAP343X_CONTROL_PER_DPLL_SPREADING (OMAP2_CONTROL_GENERAL + 0x01E8) +#define OMAP343X_CONTROL_USBHOST_DPLL_SPREADING (OMAP2_CONTROL_GENERAL + 0x01EC) +#define OMAP343X_CONTROL_PBIAS_LITE (OMAP2_CONTROL_GENERAL + 0x02B0) +#define OMAP343X_CONTROL_TEMP_SENSOR (OMAP2_CONTROL_GENERAL + 0x02B4) +#define OMAP343X_CONTROL_SRAMLDO4 (OMAP2_CONTROL_GENERAL + 0x02B8) +#define OMAP343X_CONTROL_SRAMLDO5 (OMAP2_CONTROL_GENERAL + 0x02C0) +#define OMAP343X_CONTROL_CSI (OMAP2_CONTROL_GENERAL + 0x02C4) + + +/* 34xx PADCONF register offsets */ +#define OMAP343X_PADCONF_ETK(i) (OMAP2_CONTROL_PADCONFS + 0x5a8 + \ + (i)*2) +#define OMAP343X_PADCONF_ETK_CLK OMAP343X_PADCONF_ETK(0) +#define OMAP343X_PADCONF_ETK_CTL OMAP343X_PADCONF_ETK(1) +#define OMAP343X_PADCONF_ETK_D0 OMAP343X_PADCONF_ETK(2) +#define OMAP343X_PADCONF_ETK_D1 OMAP343X_PADCONF_ETK(3) +#define OMAP343X_PADCONF_ETK_D2 OMAP343X_PADCONF_ETK(4) +#define OMAP343X_PADCONF_ETK_D3 OMAP343X_PADCONF_ETK(5) +#define OMAP343X_PADCONF_ETK_D4 OMAP343X_PADCONF_ETK(6) +#define OMAP343X_PADCONF_ETK_D5 OMAP343X_PADCONF_ETK(7) +#define OMAP343X_PADCONF_ETK_D6 OMAP343X_PADCONF_ETK(8) +#define OMAP343X_PADCONF_ETK_D7 OMAP343X_PADCONF_ETK(9) +#define OMAP343X_PADCONF_ETK_D8 OMAP343X_PADCONF_ETK(10) +#define OMAP343X_PADCONF_ETK_D9 OMAP343X_PADCONF_ETK(11) +#define OMAP343X_PADCONF_ETK_D10 OMAP343X_PADCONF_ETK(12) +#define OMAP343X_PADCONF_ETK_D11 OMAP343X_PADCONF_ETK(13) +#define OMAP343X_PADCONF_ETK_D12 OMAP343X_PADCONF_ETK(14) +#define OMAP343X_PADCONF_ETK_D13 OMAP343X_PADCONF_ETK(15) +#define OMAP343X_PADCONF_ETK_D14 OMAP343X_PADCONF_ETK(16) +#define OMAP343X_PADCONF_ETK_D15 OMAP343X_PADCONF_ETK(17) + +/* 34xx GENERAL_WKUP regist offsets */ +#define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \ + 0x008 + (i)) +#define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008) +#define OMAP343X_CONTROL_WKUP_DEBOBS1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x00C) +#define OMAP343X_CONTROL_WKUP_DEBOBS2 (OMAP343X_CONTROL_GENERAL_WKUP + 0x010) +#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014) +#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018) /* 34xx D2D idle-related pins, handled by PM core */ #define OMAP3_PADCONF_SAD2D_MSTANDBY 0x250 @@ -226,6 +269,8 @@ extern void omap3_save_scratchpad_contents(void); extern void omap3_clear_scratchpad_contents(void); extern u32 *get_restore_pointer(void); extern u32 omap3_arm_context[128]; +extern void omap3_control_save_context(void); +extern void omap3_control_restore_context(void); #else #define omap_ctrl_base_get() 0 From 3231fc889c114870ca830041fcdeb5d4745304cf Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:49:14 +0530 Subject: [PATCH 07/32] OMAP3: PM: restore SRAM functions after off-mode. Generalize the copy of SRAM functions into omap_push_sram_idle() so it can be used on init but also after off-mode transitions. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 10 +++++++--- arch/arm/plat-omap/include/plat/sram.h | 6 ++++++ arch/arm/plat-omap/sram.c | 8 +++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 391054900a6a..b88da1bcb66c 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -749,6 +749,12 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) return 0; } +void omap_push_sram_idle(void) +{ + _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, + omap34xx_cpu_suspend_sz); +} + static int __init omap3_pm_init(void) { struct power_state *pwrst, *tmp; @@ -786,9 +792,7 @@ static int __init omap3_pm_init(void) goto err2; } - _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, - omap34xx_cpu_suspend_sz); - + omap_push_sram_idle(); #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); #endif /* CONFIG_SUSPEND */ diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h index 8974e3fc2691..77799d576bc8 100644 --- a/arch/arm/plat-omap/include/plat/sram.h +++ b/arch/arm/plat-omap/include/plat/sram.h @@ -68,4 +68,10 @@ extern u32 omap3_sram_configure_core_dpll( u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1); extern unsigned long omap3_sram_configure_core_dpll_sz; +#ifdef CONFIG_PM +extern void omap_push_sram_idle(void); +#else +static inline void omap_push_sram_idle(void) {} +#endif /* CONFIG_PM */ + #endif diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index a53aa8541730..3e923668778d 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -396,22 +396,24 @@ u32 omap3_configure_core_dpll(u32 m2, u32 unlock_dll, u32 f, u32 inc, sdrc_actim_ctrl_b_1, sdrc_mr_1); } -/* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */ -void restore_sram_functions(void) +#ifdef CONFIG_PM +void omap3_sram_restore_context(void) { omap_sram_ceil = omap_sram_base + omap_sram_size; _omap3_sram_configure_core_dpll = omap_sram_push(omap3_sram_configure_core_dpll, omap3_sram_configure_core_dpll_sz); + omap_push_sram_idle(); } +#endif /* CONFIG_PM */ int __init omap34xx_sram_init(void) { _omap3_sram_configure_core_dpll = omap_sram_push(omap3_sram_configure_core_dpll, omap3_sram_configure_core_dpll_sz); - + omap_push_sram_idle(); return 0; } #else From fa3c2a4fc99fd7f8c245020303d7e11feadbbac9 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:49:22 +0530 Subject: [PATCH 08/32] OMAP3: PM: handle PER/NEON/CORE in idle Expand the powerdomains handled in the idle path to include PER, NEON and CORE. This includes properly clearing the previous powerstates, linking NEON state to MPU state and calling the UART prepare functions for only the appropraite powerdomain transitions (CORE for UART1,2, PER for UART3.) Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 64 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index b88da1bcb66c..05ee05f012ad 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -49,7 +49,10 @@ static LIST_HEAD(pwrst_list); static void (*_omap_sram_idle)(u32 *addr, int save_state); -static struct powerdomain *mpu_pwrdm; +static struct powerdomain *mpu_pwrdm, *neon_pwrdm; +static struct powerdomain *core_pwrdm, *per_pwrdm; + +static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); /* * PRCM Interrupt Handler Helper Function @@ -169,13 +172,22 @@ static void omap_sram_idle(void) /* save_state = 1 => Only L1 and logic lost */ /* save_state = 2 => Only L2 lost */ /* save_state = 3 => L1, L2 and logic lost */ - int save_state = 0, mpu_next_state; + int save_state = 0; + int mpu_next_state = PWRDM_POWER_ON; + int per_next_state = PWRDM_POWER_ON; + int core_next_state = PWRDM_POWER_ON; if (!_omap_sram_idle) return; + pwrdm_clear_all_prev_pwrst(mpu_pwrdm); + pwrdm_clear_all_prev_pwrst(neon_pwrdm); + pwrdm_clear_all_prev_pwrst(core_pwrdm); + pwrdm_clear_all_prev_pwrst(per_pwrdm); + mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { + case PWRDM_POWER_ON: case PWRDM_POWER_RET: /* No need to save context */ save_state = 0; @@ -187,18 +199,37 @@ static void omap_sram_idle(void) } pwrdm_pre_transition(); - omap2_gpio_prepare_for_retention(); - omap_uart_prepare_idle(0); - omap_uart_prepare_idle(1); - omap_uart_prepare_idle(2); + /* NEON control */ + if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) + set_pwrdm_state(neon_pwrdm, mpu_next_state); + + /* CORE & PER */ + core_next_state = pwrdm_read_next_pwrst(core_pwrdm); + if (core_next_state < PWRDM_POWER_ON) { + omap2_gpio_prepare_for_retention(); + omap_uart_prepare_idle(0); + omap_uart_prepare_idle(1); + /* PER changes only with core */ + per_next_state = pwrdm_read_next_pwrst(per_pwrdm); + if (per_next_state < PWRDM_POWER_ON) + omap_uart_prepare_idle(2); + /* Enable IO-PAD wakeup */ + prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + } _omap_sram_idle(NULL, save_state); cpu_init(); - omap_uart_resume_idle(2); - omap_uart_resume_idle(1); - omap_uart_resume_idle(0); - omap2_gpio_resume_after_retention(); + if (core_next_state < PWRDM_POWER_ON) { + if (per_next_state < PWRDM_POWER_ON) + omap_uart_resume_idle(2); + omap_uart_resume_idle(1); + omap_uart_resume_idle(0); + + /* Disable IO-PAD wakeup */ + prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap2_gpio_resume_after_retention(); + } pwrdm_post_transition(); @@ -792,6 +823,10 @@ static int __init omap3_pm_init(void) goto err2; } + neon_pwrdm = pwrdm_lookup("neon_pwrdm"); + per_pwrdm = pwrdm_lookup("per_pwrdm"); + core_pwrdm = pwrdm_lookup("core_pwrdm"); + omap_push_sram_idle(); #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); @@ -799,6 +834,15 @@ static int __init omap3_pm_init(void) pm_idle = omap3_pm_idle; + pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm); + /* + * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for + * IO-pad wakeup. Otherwise it will unnecessarily waste power + * waking up PER with every CORE wakeup - see + * http://marc.info/?l=linux-omap&m=121852150710062&w=2 + */ + pwrdm_add_wkdep(per_pwrdm, core_pwrdm); + err1: return ret; err2: From 57f277b0122722ffa1de1b53aceb70646ce9a8e1 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:49:34 +0530 Subject: [PATCH 09/32] OMAP3: PM: Restore MMU table entry During the MMU restoration on the restore path from MPU OFF, the page table entry for the page consisting of the code being executed is modified to make MMU return VA=PA. The MMU is then enabled and the original entry is being stored in scratchpad. This patch reads the original values stored in scratchpad, and restores them back. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 05ee05f012ad..8b5bf91dc070 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -29,6 +29,8 @@ #include #include +#include + #include "cm.h" #include "cm-regbits-34xx.h" #include "prm-regbits-34xx.h" @@ -164,6 +166,35 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) return IRQ_HANDLED; } +static void restore_control_register(u32 val) +{ + __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val)); +} + +/* Function to restore the table entry that was modified for enabling MMU */ +static void restore_table_entry(void) +{ + u32 *scratchpad_address; + u32 previous_value, control_reg_value; + u32 *address; + + scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); + + /* Get address of entry that was modified */ + address = (u32 *)__raw_readl(scratchpad_address + + OMAP343X_TABLE_ADDRESS_OFFSET); + /* Get the previous value which needs to be restored */ + previous_value = __raw_readl(scratchpad_address + + OMAP343X_TABLE_VALUE_OFFSET); + address = __va(address); + *address = previous_value; + flush_tlb_all(); + control_reg_value = __raw_readl(scratchpad_address + + OMAP343X_CONTROL_REG_VALUE_OFFSET); + /* This will enable caches and prediction */ + restore_control_register(control_reg_value); +} + static void omap_sram_idle(void) { /* Variable to tell what needs to be saved and restored @@ -220,6 +251,10 @@ static void omap_sram_idle(void) _omap_sram_idle(NULL, save_state); cpu_init(); + /* Restore table entry modified during MMU restoration */ + if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) + restore_table_entry(); + if (core_next_state < PWRDM_POWER_ON) { if (per_next_state < PWRDM_POWER_ON) omap_uart_resume_idle(2); From 61255ab9e853ddbbe092328c30921d2ba9434134 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:49:56 +0530 Subject: [PATCH 10/32] OMAP3: PM: MPU off-mode support Adds a 'save_state' option when calling into SRAM idle function and adds some minor cleanups of SRAM asm code. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 11 ++++++++++- arch/arm/mach-omap2/sleep34xx.S | 11 ++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 8b5bf91dc070..9fb087607e76 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -223,6 +224,9 @@ static void omap_sram_idle(void) /* No need to save context */ save_state = 0; break; + case PWRDM_POWER_OFF: + save_state = 3; + break; default: /* Invalid state */ printk(KERN_ERR "Invalid mpu state in sram_idle\n"); @@ -248,7 +252,12 @@ static void omap_sram_idle(void) prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); } - _omap_sram_idle(NULL, save_state); + /* + * omap3_arm_context is the location where ARM registers + * get saved. The restore path then reads from this + * location and restores them back. + */ + _omap_sram_idle(omap3_arm_context, save_state); cpu_init(); /* Restore table entry modified during MMU restoration */ diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index 6a749f2fea63..f8d3834bf681 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -36,12 +36,11 @@ OMAP3430_PM_PREPWSTST) #define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \ OMAP3430_PM_PREPWSTST) -#define PM_PWSTCTRL_MPU_P OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL) +#define PM_PWSTCTRL_MPU_P OMAP3430_PRM_BASE + MPU_MOD + PM_PWSTCTRL #define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is * available */ -#define SCRATCHPAD_BASE_P OMAP343X_CTRL_REGADDR(\ - OMAP343X_CONTROL_MEM_WKUP +\ - SCRATCHPAD_MEM_OFFS) +#define SCRATCHPAD_BASE_P (OMAP343X_CTRL_BASE + OMAP343X_CONTROL_MEM_WKUP\ + + SCRATCHPAD_MEM_OFFS) #define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER) .text @@ -96,7 +95,7 @@ loop: ldmfd sp!, {r0-r12, pc} @ restore regs and return restore: - /* b restore*/ @ Enable to debug restore code + /* b restore*/ @ Enable to debug restore code /* Check what was the reason for mpu reset and store the reason in r9*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost - In this case, we wont be here */ @@ -416,8 +415,6 @@ scratchpad_base: .word SCRATCHPAD_BASE_P sdrc_power: .word SDRC_POWER_V -context_mem: - .word 0x803E3E14 clk_stabilize_delay: .word 0x000001FF assoc_mask: From 2f5939c3ec9440a9c3a0baf4d0e1b2cc043aad46 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 26 Sep 2008 17:50:07 +0530 Subject: [PATCH 11/32] OMAP3: PM: CORE domain off-mode support Add context save and restore for CORE powerdomain resources in order to support off-mode. Signed-off-by: Rajendra Nayak Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 73 +++++++++++++++++++++++++- arch/arm/plat-omap/include/plat/sram.h | 1 + 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 9fb087607e76..bab9b480a089 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -5,6 +5,9 @@ * Tony Lindgren * Jouni Hogander * + * Copyright (C) 2007 Texas Instruments, Inc. + * Rajendra Nayak + * * Copyright (C) 2005 Texas Instruments, Inc. * Richard Woodruff * @@ -29,6 +32,8 @@ #include #include #include +#include +#include #include @@ -39,6 +44,11 @@ #include "prm.h" #include "pm.h" +/* Scratchpad offsets */ +#define OMAP343X_TABLE_ADDRESS_OFFSET 0x31 +#define OMAP343X_TABLE_VALUE_OFFSET 0x30 +#define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32 + struct power_state { struct powerdomain *pwrdm; u32 next_state; @@ -57,6 +67,46 @@ static struct powerdomain *core_pwrdm, *per_pwrdm; static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); +static inline void omap3_per_save_context(void) +{ + omap_gpio_save_context(); +} + +static inline void omap3_per_restore_context(void) +{ + omap_gpio_restore_context(); +} + +static void omap3_core_save_context(void) +{ + u32 control_padconf_off; + + /* Save the padconf registers */ + control_padconf_off = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF); + control_padconf_off |= START_PADCONF_SAVE; + omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF); + /* wait for the save to complete */ + while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS) + & PADCONF_SAVE_DONE) + ; + /* Save the Interrupt controller context */ + omap_intc_save_context(); + /* Save the GPMC context */ + omap3_gpmc_save_context(); + /* Save the system control module context, padconf already save above*/ + omap3_control_save_context(); +} + +static void omap3_core_restore_context(void) +{ + /* Restore the control module context, padconf restored by h/w */ + omap3_control_restore_context(); + /* Restore the GPMC context */ + omap3_gpmc_restore_context(); + /* Restore the interrupt controller context */ + omap_intc_restore_context(); +} + /* * PRCM Interrupt Handler Helper Function * @@ -208,6 +258,7 @@ static void omap_sram_idle(void) int mpu_next_state = PWRDM_POWER_ON; int per_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON; + int core_prev_state, per_prev_state; if (!_omap_sram_idle) return; @@ -246,8 +297,15 @@ static void omap_sram_idle(void) omap_uart_prepare_idle(1); /* PER changes only with core */ per_next_state = pwrdm_read_next_pwrst(per_pwrdm); - if (per_next_state < PWRDM_POWER_ON) + if (per_next_state < PWRDM_POWER_ON) { omap_uart_prepare_idle(2); + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); + } + if (core_next_state == PWRDM_POWER_OFF) { + omap3_core_save_context(); + omap3_prcm_save_context(); + } /* Enable IO-PAD wakeup */ prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); } @@ -272,6 +330,18 @@ static void omap_sram_idle(void) /* Disable IO-PAD wakeup */ prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); + if (core_prev_state == PWRDM_POWER_OFF) { + omap3_core_restore_context(); + omap3_prcm_restore_context(); + omap3_sram_restore_context(); + } + if (per_next_state < PWRDM_POWER_ON) { + per_prev_state = + pwrdm_read_prev_pwrst(per_pwrdm); + if (per_prev_state == PWRDM_POWER_OFF) + omap3_per_restore_context(); + } omap2_gpio_resume_after_retention(); } @@ -843,6 +913,7 @@ static int __init omap3_pm_init(void) /* XXX prcm_setup_regs needs to be before enabling hw * supervised mode for powerdomains */ prcm_setup_regs(); + omap3_save_scratchpad_contents(); ret = request_irq(INT_34XX_PRCM_MPU_IRQ, (irq_handler_t)prcm_interrupt_handler, diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h index 77799d576bc8..16a1b458d53c 100644 --- a/arch/arm/plat-omap/include/plat/sram.h +++ b/arch/arm/plat-omap/include/plat/sram.h @@ -27,6 +27,7 @@ extern u32 omap3_configure_core_dpll( u32 sdrc_actim_ctrl_b_0, u32 sdrc_mr_0, u32 sdrc_rfr_ctrl_1, u32 sdrc_actim_ctrl_a_1, u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1); +extern void omap3_sram_restore_context(void); /* Do not use these */ extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl); From f2d1185824fd3ed631f3164daeff59d0b4e55d79 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 28 Aug 2008 13:13:31 +0000 Subject: [PATCH 12/32] OMAP: PM: DMA context save/restore for off-mode support For HS/EMU devices, these additional features are also used: - DMA interrupt disable routine added - Added DMA controller reset to DMA context restore Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 3 +++ arch/arm/plat-omap/dma.c | 39 +++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/dma.h | 5 ++++ 3 files changed, 47 insertions(+) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index bab9b480a089..54fea79b1720 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -95,6 +96,7 @@ static void omap3_core_save_context(void) omap3_gpmc_save_context(); /* Save the system control module context, padconf already save above*/ omap3_control_save_context(); + omap_dma_global_context_save(); } static void omap3_core_restore_context(void) @@ -105,6 +107,7 @@ static void omap3_core_restore_context(void) omap3_gpmc_restore_context(); /* Restore the interrupt controller context */ omap_intc_restore_context(); + omap_dma_global_context_restore(); } /* diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 3edffde7f439..3105aaa95d75 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -54,6 +54,12 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED }; static int enable_1510_mode; +static struct omap_dma_global_context_registers { + u32 dma_irqenable_l0; + u32 dma_ocp_sysconfig; + u32 dma_gcr; +} omap_dma_global_context; + struct omap_dma_lch { int next_lch; int dev_id; @@ -2341,6 +2347,39 @@ void omap_stop_lcd_dma(void) } EXPORT_SYMBOL(omap_stop_lcd_dma); +void omap_dma_global_context_save(void) +{ + omap_dma_global_context.dma_irqenable_l0 = + dma_read(IRQENABLE_L0); + omap_dma_global_context.dma_ocp_sysconfig = + dma_read(OCP_SYSCONFIG); + omap_dma_global_context.dma_gcr = dma_read(GCR); +} + +void omap_dma_global_context_restore(void) +{ + dma_write(0x2, OCP_SYSCONFIG); + while (!__raw_readl(omap_dma_base + OMAP_DMA4_SYSSTATUS)) + ; + dma_write(omap_dma_global_context.dma_gcr, GCR); + dma_write(omap_dma_global_context.dma_ocp_sysconfig, + OCP_SYSCONFIG); + dma_write(omap_dma_global_context.dma_irqenable_l0, + IRQENABLE_L0); +} + +void omap_dma_disable_irq(int lch) +{ + u32 val; + + if (cpu_class_is_omap2()) { + /* Disable interrupts */ + val = dma_read(IRQENABLE_L0); + val &= ~(1 << lch); + dma_write(val, IRQENABLE_L0); + } +} + /*----------------------------------------------------------------------------*/ static int __init omap_init_dma(void) diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h index 72f680b7180d..1c017b29b7e9 100644 --- a/arch/arm/plat-omap/include/plat/dma.h +++ b/arch/arm/plat-omap/include/plat/dma.h @@ -633,6 +633,11 @@ extern void omap_set_dma_dst_endian_type(int lch, enum end_type etype); extern void omap_set_dma_src_endian_type(int lch, enum end_type etype); extern int omap_get_dma_index(int lch, int *ei, int *fi); +void omap_dma_global_context_save(void); +void omap_dma_global_context_restore(void); + +extern void omap_dma_disable_irq(int lch); + /* Chaining APIs */ #ifndef CONFIG_ARCH_OMAP1 extern int omap_request_dma_chain(int dev_id, const char *dev_name, From 27d59a4a2def42307349079f2e3538d96934c379 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 13 Oct 2008 13:15:00 +0300 Subject: [PATCH 13/32] OMAP3 PM: off-mode support for HS/EMU devices For HS/EMU devices, some additional resources need to be saved/restored for off-mode support. Namely, saving the secure RAM and a pointer to it in the scratchpad. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/control.c | 8 +++- arch/arm/mach-omap2/pm.h | 3 ++ arch/arm/mach-omap2/pm34xx.c | 43 ++++++++++++++++++- arch/arm/mach-omap2/sleep34xx.S | 75 ++++++++++++++++++++++++++++++++- 4 files changed, 126 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 3ea417d7a1b5..b84cff7087b0 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -85,6 +85,8 @@ struct omap3_scratchpad_sdrc_block { u32 block_size; }; +void *omap3_secure_ram_storage; + /* * This is used to store ARM registers in SDRAM before attempting * an MPU OFF. The save and restore happens from the SRAM sleep code. @@ -209,7 +211,11 @@ void omap3_save_scratchpad_contents(void) scratchpad_contents.boot_config_ptr = 0x0; scratchpad_contents.public_restore_ptr = virt_to_phys(get_restore_pointer()); - scratchpad_contents.secure_ram_restore_ptr = 0x0; + if (omap_type() == OMAP2_DEVICE_TYPE_GP) + scratchpad_contents.secure_ram_restore_ptr = 0x0; + else + scratchpad_contents.secure_ram_restore_ptr = + (u32) __pa(omap3_secure_ram_storage); scratchpad_contents.sdrc_module_semaphore = 0x0; scratchpad_contents.prcm_block_offset = 0x2C; scratchpad_contents.sdrc_block_offset = 0x64; diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 85b6face5392..45cafac716d1 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -13,6 +13,8 @@ #include +extern void *omap3_secure_ram_storage; + extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); @@ -36,6 +38,7 @@ extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl, void __iomem *sdrc_power); extern void omap34xx_cpu_suspend(u32 *addr, int save_state); extern void save_secure_ram_context(u32 *addr); +extern void omap3_save_scratchpad_contents(void); extern unsigned int omap24xx_idle_loop_suspend_sz; extern unsigned int omap34xx_suspend_sz; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 54fea79b1720..ebb88f3aae31 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -63,6 +63,8 @@ static LIST_HEAD(pwrst_list); static void (*_omap_sram_idle)(u32 *addr, int save_state); +static int (*_omap_save_secure_sram)(u32 *addr); + static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; @@ -110,6 +112,33 @@ static void omap3_core_restore_context(void) omap_dma_global_context_restore(); } +static void omap3_save_secure_ram_context(u32 target_mpu_state) +{ + u32 ret; + + if (omap_type() != OMAP2_DEVICE_TYPE_GP) { + /* Disable dma irq before calling secure rom code API */ + omap_dma_disable_irq(0); + omap_dma_disable_irq(1); + /* + * MPU next state must be set to POWER_ON temporarily, + * otherwise the WFI executed inside the ROM code + * will hang the system. + */ + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); + ret = _omap_save_secure_sram((u32 *) + __pa(omap3_secure_ram_storage)); + pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state); + /* Following is for error tracking, it should not happen */ + if (ret) { + printk(KERN_ERR "save_secure_sram() returns %08x\n", + ret); + while (1) + ; + } + } +} + /* * PRCM Interrupt Handler Helper Function * @@ -308,6 +337,7 @@ static void omap_sram_idle(void) if (core_next_state == PWRDM_POWER_OFF) { omap3_core_save_context(); omap3_prcm_save_context(); + omap3_save_secure_ram_context(mpu_next_state); } /* Enable IO-PAD wakeup */ prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); @@ -901,6 +931,9 @@ void omap_push_sram_idle(void) { _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, omap34xx_cpu_suspend_sz); + if (omap_type() != OMAP2_DEVICE_TYPE_GP) + _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, + save_secure_ram_context_sz); } static int __init omap3_pm_init(void) @@ -916,7 +949,6 @@ static int __init omap3_pm_init(void) /* XXX prcm_setup_regs needs to be before enabling hw * supervised mode for powerdomains */ prcm_setup_regs(); - omap3_save_scratchpad_contents(); ret = request_irq(INT_34XX_PRCM_MPU_IRQ, (irq_handler_t)prcm_interrupt_handler, @@ -961,6 +993,15 @@ static int __init omap3_pm_init(void) */ pwrdm_add_wkdep(per_pwrdm, core_pwrdm); + if (omap_type() != OMAP2_DEVICE_TYPE_GP) { + omap3_secure_ram_storage = + kmalloc(0x803F, GFP_KERNEL); + if (!omap3_secure_ram_storage) + printk(KERN_ERR "Memory allocation failed when" + "allocating for secure sram context\n"); + } + omap3_save_scratchpad_contents(); + err1: return ret; err2: diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index f8d3834bf681..db75167bc52d 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -37,6 +37,8 @@ #define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \ OMAP3430_PM_PREPWSTST) #define PM_PWSTCTRL_MPU_P OMAP3430_PRM_BASE + MPU_MOD + PM_PWSTCTRL +#define SRAM_BASE_P 0x40200000 +#define CONTROL_STAT 0x480022F0 #define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is * available */ #define SCRATCHPAD_BASE_P (OMAP343X_CTRL_BASE + OMAP343X_CONTROL_MEM_WKUP\ @@ -51,6 +53,40 @@ ENTRY(get_restore_pointer) ldmfd sp!, {pc} @ restore regs and return ENTRY(get_restore_pointer_sz) .word . - get_restore_pointer_sz + +/* Function to call rom code to save secure ram context */ +ENTRY(save_secure_ram_context) + stmfd sp!, {r1-r12, lr} @ save registers on stack +save_secure_ram_debug: + /* b save_secure_ram_debug */ @ enable to debug save code + adr r3, api_params @ r3 points to parameters + str r0, [r3,#0x4] @ r0 has sdram address + ldr r12, high_mask + and r3, r3, r12 + ldr r12, sram_phy_addr_mask + orr r3, r3, r12 + mov r0, #25 @ set service ID for PPA + mov r12, r0 @ copy secure service ID in r12 + mov r1, #0 @ set task id for ROM code in r1 + mov r2, #7 @ set some flags in r2, r6 + mov r6, #0xff + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 @ data memory barrier + .word 0xE1600071 @ call SMI monitor (smi #1) + nop + nop + nop + nop + ldmfd sp!, {r1-r12, pc} +sram_phy_addr_mask: + .word SRAM_BASE_P +high_mask: + .word 0xffff +api_params: + .word 0x4, 0x0, 0x0, 0x1, 0x1 +ENTRY(save_secure_ram_context_sz) + .word . - save_secure_ram_context + /* * Forces OMAP into idle state * @@ -107,9 +143,44 @@ restore: moveq r9, #0x3 @ MPU OFF => L1 and L2 lost movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation bne logic_l1_restore + ldr r0, control_stat + ldr r1, [r0] + and r1, #0x700 + cmp r1, #0x300 + beq l2_inv_gp + mov r0, #40 @ set service ID for PPA + mov r12, r0 @ copy secure Service ID in r12 + mov r1, #0 @ set task id for ROM code in r1 + mov r2, #4 @ set some flags in r2, r6 + mov r6, #0xff + adr r3, l2_inv_api_params @ r3 points to dummy parameters + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 @ data memory barrier + .word 0xE1600071 @ call SMI monitor (smi #1) + /* Write to Aux control register to set some bits */ + mov r0, #42 @ set service ID for PPA + mov r12, r0 @ copy secure Service ID in r12 + mov r1, #0 @ set task id for ROM code in r1 + mov r2, #4 @ set some flags in r2, r6 + mov r6, #0xff + adr r3, write_aux_control_params @ r3 points to parameters + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 @ data memory barrier + .word 0xE1600071 @ call SMI monitor (smi #1) + + b logic_l1_restore +l2_inv_api_params: + .word 0x1, 0x00 +write_aux_control_params: + .word 0x1, 0x72 +l2_inv_gp: /* Execute smi to invalidate L2 cache */ mov r12, #0x1 @ set up to invalide L2 -smi: .word 0xE1600070 @ Call SMI monitor (smieq) +smi: .word 0xE1600070 @ Call SMI monitor (smieq) + /* Write to Aux control register to set some bits */ + mov r0, #0x72 + mov r12, #0x3 + .word 0xE1600070 @ Call SMI monitor (smieq) logic_l1_restore: mov r1, #0 /* Invalidate all instruction caches to PoU @@ -429,5 +500,7 @@ table_entry: .word 0x00000C02 cache_pred_disable_mask: .word 0xFFFFE7FB +control_stat: + .word CONTROL_STAT ENTRY(omap34xx_cpu_suspend_sz) .word . - omap34xx_cpu_suspend From 9d97140bd0c5da55f174a81dafd2bbef135f5748 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 12 Dec 2008 11:20:05 +0200 Subject: [PATCH 14/32] OMAP3: PM: save secure RAM only during init The function omap3_save_secure_ram() is now called only once during the initialization of the device and consequent sleep cycles will re-use the same saved contents for secure RAM. Users who need secure services should do secure RAM saving before entering off-mode, if a secure service has been accessed after last save. There are both latency and reliability issues with saving secure RAM context in the idle path. The context save uses a hardware resource which takes an order of hundreds of milliseconds to initialize after a wake up from off-mode, and also there is no way of checking whether it is ready from kernel side or not. It just crashes if you use it too quickly Additional fix to ensure scratchpad save is done after secure RAM by Roger Quadros. Signed-off-by: Tero Kristo Signed-off-by: Roger Quadros Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index ebb88f3aae31..310c189efb5d 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -112,6 +112,12 @@ static void omap3_core_restore_context(void) omap_dma_global_context_restore(); } +/* + * FIXME: This function should be called before entering off-mode after + * OMAP3 secure services have been accessed. Currently it is only called + * once during boot sequence, but this works as we are not using secure + * services. + */ static void omap3_save_secure_ram_context(u32 target_mpu_state) { u32 ret; @@ -337,7 +343,6 @@ static void omap_sram_idle(void) if (core_next_state == PWRDM_POWER_OFF) { omap3_core_save_context(); omap3_prcm_save_context(); - omap3_save_secure_ram_context(mpu_next_state); } /* Enable IO-PAD wakeup */ prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); @@ -999,9 +1004,19 @@ static int __init omap3_pm_init(void) if (!omap3_secure_ram_storage) printk(KERN_ERR "Memory allocation failed when" "allocating for secure sram context\n"); - } - omap3_save_scratchpad_contents(); + local_irq_disable(); + local_fiq_disable(); + + omap_dma_global_context_save(); + omap3_save_secure_ram_context(PWRDM_POWER_ON); + omap_dma_global_context_restore(); + + local_irq_enable(); + local_fiq_enable(); + } + + omap3_save_scratchpad_contents(); err1: return ret; err2: From 13a6fe0f6adf62bf73be055322197507761d160a Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 13 Oct 2008 13:17:06 +0300 Subject: [PATCH 15/32] OMAP3: PM: Enable SDRAM auto-refresh during sleep Fix for ES3.0 bug: SDRC not sending auto-refresh when OMAP wakes-up from OFF mode (warning for HS devices.) Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 310c189efb5d..3f1f656348fc 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -44,6 +44,13 @@ #include "prm.h" #include "pm.h" +#include "sdrc.h" + +#define SDRC_POWER_AUTOCOUNT_SHIFT 8 +#define SDRC_POWER_AUTOCOUNT_MASK (0xffff << SDRC_POWER_AUTOCOUNT_SHIFT) +#define SDRC_POWER_CLKCTRL_SHIFT 4 +#define SDRC_POWER_CLKCTRL_MASK (0x3 << SDRC_POWER_CLKCTRL_SHIFT) +#define SDRC_SELF_REFRESH_ON_AUTOCOUNT (0x2 << SDRC_POWER_CLKCTRL_SHIFT) /* Scratchpad offsets */ #define OMAP343X_TABLE_ADDRESS_OFFSET 0x31 @@ -297,6 +304,7 @@ static void omap_sram_idle(void) int per_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; + u32 sdrc_pwr = 0; if (!_omap_sram_idle) return; @@ -348,6 +356,21 @@ static void omap_sram_idle(void) prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); } + /* + * Force SDRAM controller to self-refresh mode after timeout on + * autocount. This is needed on ES3.0 to avoid SDRAM controller + * hang-ups. + */ + if (omap_rev() >= OMAP3430_REV_ES3_0 && + omap_type() != OMAP2_DEVICE_TYPE_GP && + core_next_state == PWRDM_POWER_OFF) { + sdrc_pwr = sdrc_read_reg(SDRC_POWER); + sdrc_write_reg((sdrc_pwr & + ~(SDRC_POWER_AUTOCOUNT_MASK|SDRC_POWER_CLKCTRL_MASK)) | + (1 << SDRC_POWER_AUTOCOUNT_SHIFT) | + SDRC_SELF_REFRESH_ON_AUTOCOUNT, SDRC_POWER); + } + /* * omap3_arm_context is the location where ARM registers * get saved. The restore path then reads from this @@ -356,6 +379,12 @@ static void omap_sram_idle(void) _omap_sram_idle(omap3_arm_context, save_state); cpu_init(); + /* Restore normal SDRAM settings */ + if (omap_rev() >= OMAP3430_REV_ES3_0 && + omap_type() != OMAP2_DEVICE_TYPE_GP && + core_next_state == PWRDM_POWER_OFF) + sdrc_write_reg(sdrc_pwr, SDRC_POWER); + /* Restore table entry modified during MMU restoration */ if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) restore_table_entry(); From 133464dc30846282b5f852433d7b6a31f292f886 Mon Sep 17 00:00:00 2001 From: Jouni Hogander Date: Thu, 5 Feb 2009 13:34:01 +0200 Subject: [PATCH 16/32] OMAP3: PM: Save and restore also CM_CLKSEL1_PLL_IVA2 CM_CLKSEL1_PLL_IVA2 is not saved/restored currently. This patch is adding save and restore for it. Signed-off-by: Jouni Hogander Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/prcm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index 56f77df1ffac..221eed11b73f 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -39,6 +39,7 @@ static void __iomem *cm_base; struct omap3_prcm_regs { u32 control_padconf_sys_nirq; + u32 iva2_cm_clksel1; u32 iva2_cm_clksel2; u32 cm_sysconfig; u32 sgx_cm_clksel; @@ -262,6 +263,8 @@ void omap3_prcm_save_context(void) { prcm_context.control_padconf_sys_nirq = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_SYSNIRQ); + prcm_context.iva2_cm_clksel1 = + cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL1); prcm_context.iva2_cm_clksel2 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL2); prcm_context.cm_sysconfig = __raw_readl(OMAP3430_CM_SYSCONFIG); @@ -417,6 +420,8 @@ void omap3_prcm_restore_context(void) { omap_ctrl_writel(prcm_context.control_padconf_sys_nirq, OMAP343X_CONTROL_PADCONF_SYSNIRQ); + cm_write_mod_reg(prcm_context.iva2_cm_clksel1, OMAP3430_IVA2_MOD, + CM_CLKSEL1); cm_write_mod_reg(prcm_context.iva2_cm_clksel2, OMAP3430_IVA2_MOD, CM_CLKSEL2); __raw_writel(prcm_context.cm_sysconfig, OMAP3430_CM_SYSCONFIG); From ba50ea7eb9ce663511013b35608cf0753c9ab674 Mon Sep 17 00:00:00 2001 From: Kalle Jokiniemi Date: Thu, 26 Mar 2009 15:59:00 +0200 Subject: [PATCH 17/32] OMAP3: PM: Fix secure SRAM context save/restore The secure sram context save uses dma channels 0 and 1. In order to avoid collision between kernel DMA transfers and ROM code dma transfers, we need to reserve DMA channels 0 1 on high security devices. A bug in ROM code leaves dma irq status bits uncleared. Hence those irq status bits need to be cleared when restoring DMA context after off mode. There was also a faulty parameter given to PPA in the secure ram context save assembly code, which caused interrupts to be enabled during secure ram context save. This caused the save to fail sometimes, which resulted the saved context to be corrupted, but also left DMA channels in secure mode. The secure mode DMA channels caused "DMA secure error with device 0" errors to be displayed. Signed-off-by: Kalle Jokiniemi Signed-off-by: Jouni Hogander Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 3 --- arch/arm/mach-omap2/sleep34xx.S | 2 +- arch/arm/plat-omap/dma.c | 31 ++++++++++++++++--------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 3f1f656348fc..a9f4034aa70a 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -130,9 +130,6 @@ static void omap3_save_secure_ram_context(u32 target_mpu_state) u32 ret; if (omap_type() != OMAP2_DEVICE_TYPE_GP) { - /* Disable dma irq before calling secure rom code API */ - omap_dma_disable_irq(0); - omap_dma_disable_irq(1); /* * MPU next state must be set to POWER_ON temporarily, * otherwise the WFI executed inside the ROM code diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index db75167bc52d..b6abadccb1c6 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -68,7 +68,7 @@ save_secure_ram_debug: mov r0, #25 @ set service ID for PPA mov r12, r0 @ copy secure service ID in r12 mov r1, #0 @ set task id for ROM code in r1 - mov r2, #7 @ set some flags in r2, r6 + mov r2, #4 @ set some flags in r2, r6 mov r6, #0xff mcr p15, 0, r0, c7, c10, 4 @ data write barrier mcr p15, 0, r0, c7, c10, 5 @ data memory barrier diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 3105aaa95d75..1b5216f1e78d 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -2358,26 +2358,20 @@ void omap_dma_global_context_save(void) void omap_dma_global_context_restore(void) { - dma_write(0x2, OCP_SYSCONFIG); - while (!__raw_readl(omap_dma_base + OMAP_DMA4_SYSSTATUS)) - ; dma_write(omap_dma_global_context.dma_gcr, GCR); dma_write(omap_dma_global_context.dma_ocp_sysconfig, OCP_SYSCONFIG); dma_write(omap_dma_global_context.dma_irqenable_l0, IRQENABLE_L0); -} -void omap_dma_disable_irq(int lch) -{ - u32 val; - - if (cpu_class_is_omap2()) { - /* Disable interrupts */ - val = dma_read(IRQENABLE_L0); - val &= ~(1 << lch); - dma_write(val, IRQENABLE_L0); - } + /* + * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared + * after secure sram context save and restore. Hence we need to + * manually clear those IRQs to avoid spurious interrupts. This + * affects only secure devices. + */ + if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) + dma_write(0x3 , IRQSTATUS_L0); } /*----------------------------------------------------------------------------*/ @@ -2515,8 +2509,8 @@ static int __init omap_init_dma(void) setup_irq(irq, &omap24xx_dma_irq); } - /* Enable smartidle idlemodes and autoidle */ if (cpu_is_omap34xx()) { + /* Enable smartidle idlemodes and autoidle */ u32 v = dma_read(OCP_SYSCONFIG); v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK | DMA_SYSCONFIG_SIDLEMODE_MASK | @@ -2525,6 +2519,13 @@ static int __init omap_init_dma(void) DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) | DMA_SYSCONFIG_AUTOIDLE); dma_write(v , OCP_SYSCONFIG); + /* reserve dma channels 0 and 1 in high security devices */ + if (omap_type() != OMAP2_DEVICE_TYPE_GP) { + printk(KERN_INFO "Reserving DMA channels 0 and 1 for " + "HS ROM code\n"); + dma_chan[0].dev_id = 0; + dma_chan[1].dev_id = 1; + } } From 8a917d2fc80b7c45ce0146ff134168646274a9bd Mon Sep 17 00:00:00 2001 From: Kalle Jokiniemi Date: Wed, 13 May 2009 13:32:11 +0300 Subject: [PATCH 18/32] ARM: OMAP: SMS: save/restore of SMS_SYSCONFIG for off-mode The SMS_SYSCONFIG register gets reset in off mode, added a save/restore mechanism for that. Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 1 + arch/arm/mach-omap2/sdrc.c | 27 ++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/sdrc.h | 2 ++ 3 files changed, 30 insertions(+) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index a9f4034aa70a..90d1dc5884ef 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -399,6 +399,7 @@ static void omap_sram_idle(void) omap3_core_restore_context(); omap3_prcm_restore_context(); omap3_sram_restore_context(); + omap2_sms_restore_context(); } if (per_next_state < PWRDM_POWER_ON) { per_prev_state = diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c index 07000de48f34..9a592199321c 100644 --- a/arch/arm/mach-omap2/sdrc.c +++ b/arch/arm/mach-omap2/sdrc.c @@ -37,11 +37,37 @@ static struct omap_sdrc_params *sdrc_init_params_cs0, *sdrc_init_params_cs1; void __iomem *omap2_sdrc_base; void __iomem *omap2_sms_base; +struct omap2_sms_regs { + u32 sms_sysconfig; +}; + +static struct omap2_sms_regs sms_context; + /* SDRC_POWER register bits */ #define SDRC_POWER_EXTCLKDIS_SHIFT 3 #define SDRC_POWER_PWDENA_SHIFT 2 #define SDRC_POWER_PAGEPOLICY_SHIFT 0 +/** + * omap2_sms_save_context - Save SMS registers + * + * Save SMS registers that need to be restored after off mode. + */ +void omap2_sms_save_context(void) +{ + sms_context.sms_sysconfig = sms_read_reg(SMS_SYSCONFIG); +} + +/** + * omap2_sms_restore_context - Restore SMS registers + * + * Restore SMS registers that need to be Restored after off mode. + */ +void omap2_sms_restore_context(void) +{ + sms_write_reg(sms_context.sms_sysconfig, SMS_SYSCONFIG); +} + /** * omap2_sdrc_get_params - return SDRC register values for a given clock rate * @r: SDRC clock rate (in Hz) @@ -132,4 +158,5 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0, l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) | (1 << SDRC_POWER_PAGEPOLICY_SHIFT); sdrc_write_reg(l, SDRC_POWER); + omap2_sms_save_context(); } diff --git a/arch/arm/plat-omap/include/plat/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h index 7b58a5f78ce4..772b71e8b44f 100644 --- a/arch/arm/plat-omap/include/plat/sdrc.h +++ b/arch/arm/plat-omap/include/plat/sdrc.h @@ -120,6 +120,8 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0, int omap2_sdrc_get_params(unsigned long r, struct omap_sdrc_params **sdrc_cs0, struct omap_sdrc_params **sdrc_cs1); +void omap2_sms_save_context(void); +void omap2_sms_restore_context(void); #ifdef CONFIG_ARCH_OMAP2 From cb0cb2b815bf073dc0211ab224682a6caf6c89ce Mon Sep 17 00:00:00 2001 From: Kalle Jokiniemi Date: Tue, 12 May 2009 14:02:16 +0300 Subject: [PATCH 19/32] OMAP3: PM: Fix PLL_MOD CLKEN offset in scratchpad The CM_CLKEN_PLL register saved in scratchpad memory was wrongly using offset of 0x0004 instead of 0x0000. The effect of this was that boot ROM code would restore the wrong value when waking up from off mode. This wrong value, however, will be overwritten by prcm context restore. Still, a short period of wrong clock settings in CM_CLKEN_PLL remained between ROM code and prcm context restore. This is fixed by the patch. Problem reported by: Jouni Hogander Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index b84cff7087b0..c41565ec16e3 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -230,7 +230,7 @@ void omap3_save_scratchpad_contents(void) prcm_block_contents.cm_clksel_wkup = cm_read_mod_reg(WKUP_MOD, CM_CLKSEL); prcm_block_contents.cm_clken_pll = - cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKEN_PLL); + cm_read_mod_reg(PLL_MOD, CM_CLKEN); prcm_block_contents.cm_autoidle_pll = cm_read_mod_reg(PLL_MOD, OMAP3430_CM_AUTOIDLE_PLL); prcm_block_contents.cm_clksel1_pll = From bf07c9f2d869077cc918b4cda861eadac6df6283 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 20 May 2009 16:58:30 +0300 Subject: [PATCH 20/32] OMAP: PM: Clear DMA channel state after a wakeup Clear DMA channel states so that users can assume a known initial state. Signed-off-by: Aaro Koskinen Signed-off-by: Kevin Hilman --- arch/arm/plat-omap/dma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 1b5216f1e78d..8836da32d63b 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -2358,6 +2358,8 @@ void omap_dma_global_context_save(void) void omap_dma_global_context_restore(void) { + int ch; + dma_write(omap_dma_global_context.dma_gcr, GCR); dma_write(omap_dma_global_context.dma_ocp_sysconfig, OCP_SYSCONFIG); @@ -2372,6 +2374,10 @@ void omap_dma_global_context_restore(void) */ if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) dma_write(0x3 , IRQSTATUS_L0); + + for (ch = 0; ch < dma_chan_count; ch++) + if (dma_chan[ch].dev_id != -1) + omap_clear_dma(ch); } /*----------------------------------------------------------------------------*/ From 692ec4abb96174c0e4b3aef6d2b71f36a4a14c8b Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Mon, 9 Mar 2009 21:21:01 +0000 Subject: [PATCH 21/32] OMAP: Store reboot mode in scratchpad on OMAP34xx The reboot mode can be communicated to a bootloader (or the kernel itself) with a scratchpad register. This functionality is especially useful, if userspace is allowed to change the reboot mode. Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/prcm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index 221eed11b73f..029d376198d4 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -135,9 +135,18 @@ void omap_prcm_arch_reset(char mode) if (cpu_is_omap24xx()) prcm_offs = WKUP_MOD; - else if (cpu_is_omap34xx()) + else if (cpu_is_omap34xx()) { + u32 l; + prcm_offs = OMAP3430_GR_MOD; - else + l = ('B' << 24) | ('M' << 16) | mode; + /* Reserve the first word in scratchpad for communicating + * with the boot ROM. A pointer to a data structure + * describing the boot process can be stored there, + * cf. OMAP34xx TRM, Initialization / Software Booting + * Configuration. */ + omap_writel(l, OMAP343X_SCRATCHPAD + 4); + } else WARN_ON(1); prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL); From 0795a75a369b931150074a14473f024359b7f25c Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 13 Oct 2008 17:58:50 +0300 Subject: [PATCH 22/32] OMAP3: PM: SDRC auto-refresh workaround for off-mode Errata: ES3.0, ES3.1 SDRC not sending auto-refresh when OMAP wakes-up from OFF mode Signed-off-by: Tero Kristo Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/control.c | 9 ++- arch/arm/mach-omap2/sleep34xx.S | 84 ++++++++++++++++++++++- arch/arm/plat-omap/include/plat/control.h | 1 + 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index c41565ec16e3..2ff8d7cc60a2 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -209,8 +209,13 @@ void omap3_save_scratchpad_contents(void) /* Populate the Scratchpad contents */ scratchpad_contents.boot_config_ptr = 0x0; - scratchpad_contents.public_restore_ptr = - virt_to_phys(get_restore_pointer()); + if (omap_rev() != OMAP3430_REV_ES3_0 && + omap_rev() != OMAP3430_REV_ES3_1) + scratchpad_contents.public_restore_ptr = + virt_to_phys(get_restore_pointer()); + else + scratchpad_contents.public_restore_ptr = + virt_to_phys(get_es3_restore_pointer()); if (omap_type() == OMAP2_DEVICE_TYPE_GP) scratchpad_contents.secure_ram_restore_ptr = 0x0; else diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index b6abadccb1c6..dedfa0e6c639 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -34,6 +34,7 @@ #define PM_PREPWSTST_CORE_V OMAP34XX_PRM_REGADDR(CORE_MOD, \ OMAP3430_PM_PREPWSTST) +#define PM_PREPWSTST_CORE_P 0x48306AE8 #define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \ OMAP3430_PM_PREPWSTST) #define PM_PWSTCTRL_MPU_P OMAP3430_PRM_BASE + MPU_MOD + PM_PWSTCTRL @@ -44,6 +45,13 @@ #define SCRATCHPAD_BASE_P (OMAP343X_CTRL_BASE + OMAP343X_CONTROL_MEM_WKUP\ + SCRATCHPAD_MEM_OFFS) #define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER) +#define SDRC_SYSCONFIG_P (OMAP343X_SDRC_BASE + SDRC_SYSCONFIG) +#define SDRC_MR_0_P (OMAP343X_SDRC_BASE + SDRC_MR_0) +#define SDRC_EMR2_0_P (OMAP343X_SDRC_BASE + SDRC_EMR2_0) +#define SDRC_MANUAL_0_P (OMAP343X_SDRC_BASE + SDRC_MANUAL_0) +#define SDRC_MR_1_P (OMAP343X_SDRC_BASE + SDRC_MR_1) +#define SDRC_EMR2_1_P (OMAP343X_SDRC_BASE + SDRC_EMR2_1) +#define SDRC_MANUAL_1_P (OMAP343X_SDRC_BASE + SDRC_MANUAL_1) .text /* Function call to get the restore pointer for resume from OFF */ @@ -52,7 +60,59 @@ ENTRY(get_restore_pointer) adr r0, restore ldmfd sp!, {pc} @ restore regs and return ENTRY(get_restore_pointer_sz) - .word . - get_restore_pointer_sz + .word . - get_restore_pointer + + .text +/* Function call to get the restore pointer for for ES3 to resume from OFF */ +ENTRY(get_es3_restore_pointer) + stmfd sp!, {lr} @ save registers on stack + adr r0, restore_es3 + ldmfd sp!, {pc} @ restore regs and return +ENTRY(get_es3_restore_pointer_sz) + .word . - get_es3_restore_pointer + +ENTRY(es3_sdrc_fix) + ldr r4, sdrc_syscfg @ get config addr + ldr r5, [r4] @ get value + tst r5, #0x100 @ is part access blocked + it eq + biceq r5, r5, #0x100 @ clear bit if set + str r5, [r4] @ write back change + ldr r4, sdrc_mr_0 @ get config addr + ldr r5, [r4] @ get value + str r5, [r4] @ write back change + ldr r4, sdrc_emr2_0 @ get config addr + ldr r5, [r4] @ get value + str r5, [r4] @ write back change + ldr r4, sdrc_manual_0 @ get config addr + mov r5, #0x2 @ autorefresh command + str r5, [r4] @ kick off refreshes + ldr r4, sdrc_mr_1 @ get config addr + ldr r5, [r4] @ get value + str r5, [r4] @ write back change + ldr r4, sdrc_emr2_1 @ get config addr + ldr r5, [r4] @ get value + str r5, [r4] @ write back change + ldr r4, sdrc_manual_1 @ get config addr + mov r5, #0x2 @ autorefresh command + str r5, [r4] @ kick off refreshes + bx lr +sdrc_syscfg: + .word SDRC_SYSCONFIG_P +sdrc_mr_0: + .word SDRC_MR_0_P +sdrc_emr2_0: + .word SDRC_EMR2_0_P +sdrc_manual_0: + .word SDRC_MANUAL_0_P +sdrc_mr_1: + .word SDRC_MR_1_P +sdrc_emr2_1: + .word SDRC_EMR2_1_P +sdrc_manual_1: + .word SDRC_MANUAL_1_P +ENTRY(es3_sdrc_fix_sz) + .word . - es3_sdrc_fix /* Function to call rom code to save secure ram context */ ENTRY(save_secure_ram_context) @@ -130,6 +190,24 @@ loop: bl i_dll_wait ldmfd sp!, {r0-r12, pc} @ restore regs and return +restore_es3: + /*b restore_es3*/ @ Enable to debug restore code + ldr r5, pm_prepwstst_core_p + ldr r4, [r5] + and r4, r4, #0x3 + cmp r4, #0x0 @ Check if previous power state of CORE is OFF + bne restore + adr r0, es3_sdrc_fix + ldr r1, sram_base + ldr r2, es3_sdrc_fix_sz + mov r2, r2, ror #2 +copy_to_sram: + ldmia r0!, {r3} @ val = *src + stmia r1!, {r3} @ *dst = val + subs r2, r2, #0x1 @ num_words-- + bne copy_to_sram + ldr r1, sram_base + blx r1 restore: /* b restore*/ @ Enable to debug restore code /* Check what was the reason for mpu reset and store the reason in r9*/ @@ -478,12 +556,16 @@ i_dll_delay: bx lr pm_prepwstst_core: .word PM_PREPWSTST_CORE_V +pm_prepwstst_core_p: + .word PM_PREPWSTST_CORE_P pm_prepwstst_mpu: .word PM_PREPWSTST_MPU_V pm_pwstctrl_mpu: .word PM_PWSTCTRL_MPU_P scratchpad_base: .word SCRATCHPAD_BASE_P +sram_base: + .word SRAM_BASE_P + 0x8000 sdrc_power: .word SDRC_POWER_V clk_stabilize_delay: diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h index 8ca73471ba45..8237cb9e74fd 100644 --- a/arch/arm/plat-omap/include/plat/control.h +++ b/arch/arm/plat-omap/include/plat/control.h @@ -268,6 +268,7 @@ extern void omap_ctrl_writel(u32 val, u16 offset); extern void omap3_save_scratchpad_contents(void); extern void omap3_clear_scratchpad_contents(void); extern u32 *get_restore_pointer(void); +extern u32 *get_es3_restore_pointer(void); extern u32 omap3_arm_context[128]; extern void omap3_control_save_context(void); extern void omap3_control_restore_context(void); From 2329e7cc0de3de499d0a0f4e2f73c8f02acbc117 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 12 Mar 2009 18:12:29 +0200 Subject: [PATCH 23/32] OMAP3: PM: Fix INTC context save/restore Wrong index was used for ILR. Signed-off-by: Aaro Koskinen Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index ebd3538bd1d4..e9bc782fa414 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -241,7 +241,7 @@ void omap_intc_save_context(void) intc_bank_read_reg(bank, INTC_THRESHOLD); for (i = 0; i < INTCPS_NR_IRQS; i++) intc_context[ind].ilr[i] = - intc_bank_read_reg(bank, (0x100 + 0x4*ind)); + intc_bank_read_reg(bank, (0x100 + 0x4*i)); for (i = 0; i < INTCPS_NR_MIR_REGS; i++) intc_context[ind].mir[i] = intc_bank_read_reg(&irq_banks[0], INTC_MIR0 + @@ -267,7 +267,7 @@ void omap_intc_restore_context(void) bank, INTC_THRESHOLD); for (i = 0; i < INTCPS_NR_IRQS; i++) intc_bank_write_reg(intc_context[ind].ilr[i], - bank, (0x100 + 0x4*ind)); + bank, (0x100 + 0x4*i)); for (i = 0; i < INTCPS_NR_MIR_REGS; i++) intc_bank_write_reg(intc_context[ind].mir[i], &irq_banks[0], INTC_MIR0 + (0x20 * i)); From 867d320b6c30d2478358eafeca0e1a6c60cf06c3 Mon Sep 17 00:00:00 2001 From: Kalle Jokiniemi Date: Thu, 23 Apr 2009 13:58:51 +0300 Subject: [PATCH 24/32] PM: Disable usb host HW save and restore The hardware SAVEANDRESTORE mechanism seems to leave USB HOST power domain permanently into active state after one transition from off to active state. Disabling for now. Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/powerdomains34xx.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index f70eb2da17e7..fd09b0827df0 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -338,7 +338,13 @@ static struct powerdomain usbhost_pwrdm = { .sleepdep_srcs = dss_per_usbhost_sleepdeps, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRDM_POWER_RET, - .flags = PWRDM_HAS_HDWR_SAR, /* for USBHOST ctrlr only */ + /* + * REVISIT: Enabling usb host save and restore mechanism seems to + * leave the usb host domain permanently in ACTIVE mode after + * changing the usb host power domain state from OFF to active once. + * Disabling for now. + */ + /*.flags = PWRDM_HAS_HDWR_SAR,*/ /* for USBHOST ctrlr only */ .banks = 1, .pwrsts_mem_ret = { [0] = PWRDM_POWER_RET, /* MEMRETSTATE */ From 89139dce8a0060d97a46cebde570a8f55c314712 Mon Sep 17 00:00:00 2001 From: Peter 'p2' De Schrijver Date: Fri, 16 Jan 2009 18:53:48 +0200 Subject: [PATCH 25/32] OMAP3: PM: Wait for SDRC ready iso a blind delay This patch improves the wakeup SRAM code polling the SDRC to become ready instead of just waiting for a fixed amount of time. Signed-off-by: Peter 'p2' De Schrijver Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/sleep34xx.S | 48 ++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index dedfa0e6c639..15268f8b61de 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -29,6 +29,7 @@ #include #include +#include "cm.h" #include "prm.h" #include "sdrc.h" @@ -38,6 +39,7 @@ #define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \ OMAP3430_PM_PREPWSTST) #define PM_PWSTCTRL_MPU_P OMAP3430_PRM_BASE + MPU_MOD + PM_PWSTCTRL +#define CM_IDLEST1_CORE_V OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST1) #define SRAM_BASE_P 0x40200000 #define CONTROL_STAT 0x480022F0 #define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is @@ -52,6 +54,8 @@ #define SDRC_MR_1_P (OMAP343X_SDRC_BASE + SDRC_MR_1) #define SDRC_EMR2_1_P (OMAP343X_SDRC_BASE + SDRC_EMR2_1) #define SDRC_MANUAL_1_P (OMAP343X_SDRC_BASE + SDRC_MANUAL_1) +#define SDRC_DLLA_STATUS_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) +#define SDRC_DLLA_CTRL_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL) .text /* Function call to get the restore pointer for resume from OFF */ @@ -187,7 +191,7 @@ loop: nop nop nop - bl i_dll_wait + bl wait_sdrc_ok ldmfd sp!, {r0-r12, pc} @ restore regs and return restore_es3: @@ -539,21 +543,41 @@ skip_l2_inval: nop nop nop - bl i_dll_wait + bl wait_sdrc_ok /* restore regs and return */ ldmfd sp!, {r0-r12, pc} -i_dll_wait: - ldr r4, clk_stabilize_delay +/* Make sure SDRC accesses are ok */ +wait_sdrc_ok: + ldr r4, cm_idlest1_core + ldr r5, [r4] + and r5, r5, #0x2 + cmp r5, #0 + bne wait_sdrc_ok + ldr r4, sdrc_power + ldr r5, [r4] + bic r5, r5, #0x40 + str r5, [r4] +wait_dll_lock: + /* Is dll in lock mode? */ + ldr r4, sdrc_dlla_ctrl + ldr r5, [r4] + tst r5, #0x4 + bxne lr + /* wait till dll locks */ + ldr r4, sdrc_dlla_status + ldr r5, [r4] + and r5, r5, #0x4 + cmp r5, #0x4 + bne wait_dll_lock + bx lr -i_dll_delay: - subs r4, r4, #0x1 - bne i_dll_delay - ldr r4, sdrc_power - ldr r5, [r4] - bic r5, r5, #0x40 - str r5, [r4] - bx lr +cm_idlest1_core: + .word CM_IDLEST1_CORE_V +sdrc_dlla_status: + .word SDRC_DLLA_STATUS_V +sdrc_dlla_ctrl: + .word SDRC_DLLA_CTRL_V pm_prepwstst_core: .word PM_PREPWSTST_CORE_V pm_prepwstst_core_p: From c40552bc82166adb21a1a7fcb1dc4e76352b1b79 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 6 Oct 2009 14:25:09 -0700 Subject: [PATCH 26/32] OMAP3: PM debug: allow runtime toggle of PM features Allow enable/disable of low-power states during idle. To enable low-power idle: echo 1 > /debug/pm_debug/sleep_while_idle to disable: echo 0 > /debug/pm_debug/sleep_while_idle Also allow enable/disable of OFF-mode. To enable: echo 1 > /debug/pm_debug/enable_off_mode to disable: echo 0 > /debug/pm_debug/enable_off_mode Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm-debug.c | 27 +++++++++++++++++++++++++++ arch/arm/mach-omap2/pm.h | 4 ++++ arch/arm/mach-omap2/pm34xx.c | 22 ++++++++++++++++++++++ arch/arm/mach-omap2/serial.c | 2 -- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 7eb2c12c8b7c..1725da3f4e18 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -527,6 +527,29 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) return 0; } +static int option_get(void *data, u64 *val) +{ + u32 *option = data; + + *val = *option; + + return 0; +} + +static int option_set(void *data, u64 val) +{ + u32 *option = data; + + *option = val; + + if (option == &enable_off_mode) + omap3_pm_off_mode_enable(val); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n"); + static int __init pm_dbg_init(void) { int i; @@ -569,6 +592,10 @@ static int __init pm_dbg_init(void) } + (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUGO, d, + &enable_off_mode, &pm_dbg_option_fops); + (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUGO, d, + &sleep_while_idle, &pm_dbg_option_fops); pm_dbg_init_done = 1; return 0; diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 45cafac716d1..9582793ce82d 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -13,7 +13,11 @@ #include +extern u32 enable_off_mode; +extern u32 sleep_while_idle; + extern void *omap3_secure_ram_storage; +extern void omap3_pm_off_mode_enable(int); extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 90d1dc5884ef..ade2e4a6bb7d 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,9 @@ #define OMAP343X_TABLE_VALUE_OFFSET 0x30 #define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32 +u32 enable_off_mode; +u32 sleep_while_idle; + struct power_state { struct powerdomain *pwrdm; u32 next_state; @@ -456,6 +460,8 @@ static int omap3_fclks_active(void) static int omap3_can_sleep(void) { + if (!sleep_while_idle) + return 0; if (!omap_uart_can_sleep()) return 0; if (omap3_fclks_active()) @@ -900,6 +906,22 @@ static void __init prcm_setup_regs(void) omap3_d2d_idle(); } +void omap3_pm_off_mode_enable(int enable) +{ + struct power_state *pwrst; + u32 state; + + if (enable) + state = PWRDM_POWER_OFF; + else + state = PWRDM_POWER_RET; + + list_for_each_entry(pwrst, &pwrst_list, node) { + pwrst->next_state = state; + set_pwrdm_state(pwrst->pwrdm, state); + } +} + int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) { struct power_state *pwrst; diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index a5aecffe03ff..72df1b188135 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -155,8 +155,6 @@ static inline void __init omap_uart_reset(struct omap_uart_state *uart) #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) -static int enable_off_mode; /* to be removed by full off-mode patches */ - static void omap_uart_save_context(struct omap_uart_state *uart) { u16 lcr = 0; From d7814e4df6e9c54680a30de3f439c66a2a55ce94 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 6 Oct 2009 14:30:23 -0700 Subject: [PATCH 27/32] PM debug: allow configurable wakeup from suspend on OMAP GPtimer Using debugfs, export a configurable wakeup timer to be used to wakeup system from suspend. If a non-zero value is written to /debug/pm_debug/wakeup_timer_seconds, A timer wakeup event will wake the system and resume after the configured number of seconds. Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm-debug.c | 2 ++ arch/arm/mach-omap2/pm.h | 3 +++ arch/arm/mach-omap2/pm34xx.c | 21 +++++++++++++++++++++ arch/arm/mach-omap2/timer-gp.c | 2 ++ 4 files changed, 28 insertions(+) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 1725da3f4e18..8baa30d2acfb 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -596,6 +596,8 @@ static int __init pm_dbg_init(void) &enable_off_mode, &pm_dbg_option_fops); (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUGO, d, &sleep_while_idle, &pm_dbg_option_fops); + (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d, + &wakeup_timer_seconds, &pm_dbg_option_fops); pm_dbg_init_done = 1; return 0; diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 9582793ce82d..7eb769f4ef30 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -22,6 +22,9 @@ extern void omap3_pm_off_mode_enable(int); extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); +extern u32 wakeup_timer_seconds; +extern struct omap_dm_timer *gptimer_wakeup; + #ifdef CONFIG_PM_DEBUG extern void omap2_pm_dump(int mode, int resume, unsigned int us); extern int omap2_pm_debug; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index ade2e4a6bb7d..ff818aaec6c5 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -60,6 +61,7 @@ u32 enable_off_mode; u32 sleep_while_idle; +u32 wakeup_timer_seconds; struct power_state { struct powerdomain *pwrdm; @@ -535,6 +537,22 @@ out: #ifdef CONFIG_SUSPEND static suspend_state_t suspend_state; +static void omap2_pm_wakeup_on_timer(u32 seconds) +{ + u32 tick_rate, cycles; + + if (!seconds) + return; + + tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup)); + cycles = tick_rate * seconds; + omap_dm_timer_stop(gptimer_wakeup); + omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles); + + pr_info("PM: Resume timer in %d secs (%d ticks at %d ticks/sec.)\n", + seconds, cycles, tick_rate); +} + static int omap3_pm_prepare(void) { disable_hlt(); @@ -546,6 +564,9 @@ static int omap3_pm_suspend(void) struct power_state *pwrst; int state, ret = 0; + if (wakeup_timer_seconds) + omap2_pm_wakeup_on_timer(wakeup_timer_seconds); + /* Read current next_pwrsts */ list_for_each_entry(pwrst, &pwrst_list, node) pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index df2b7094de98..cd04deaa88c5 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -47,6 +47,7 @@ static struct omap_dm_timer *gptimer; static struct clock_event_device clockevent_gpt; static u8 __initdata gptimer_id = 1; static u8 __initdata inited; +struct omap_dm_timer *gptimer_wakeup; static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) { @@ -134,6 +135,7 @@ static void __init omap2_gp_clockevent_init(void) gptimer = omap_dm_timer_request_specific(gptimer_id); BUG_ON(gptimer == NULL); + gptimer_wakeup = gptimer; #if defined(CONFIG_OMAP_32K_TIMER) src = OMAP_TIMER_SRC_32_KHZ; From 658ce97ef57f4c0737bfcb76050400b53389ed6b Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 4 Nov 2008 20:50:52 -0800 Subject: [PATCH 28/32] OMAP3: PM: decouple PER and CORE context save and restore Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 51 ++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index ff818aaec6c5..d8a6e10ac315 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -338,19 +338,20 @@ static void omap_sram_idle(void) if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) set_pwrdm_state(neon_pwrdm, mpu_next_state); - /* CORE & PER */ + /* PER */ + per_next_state = pwrdm_read_next_pwrst(per_pwrdm); + if (per_next_state < PWRDM_POWER_ON) { + omap2_gpio_prepare_for_retention(); + omap_uart_prepare_idle(2); + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); + } + + /* CORE */ core_next_state = pwrdm_read_next_pwrst(core_pwrdm); if (core_next_state < PWRDM_POWER_ON) { - omap2_gpio_prepare_for_retention(); omap_uart_prepare_idle(0); omap_uart_prepare_idle(1); - /* PER changes only with core */ - per_next_state = pwrdm_read_next_pwrst(per_pwrdm); - if (per_next_state < PWRDM_POWER_ON) { - omap_uart_prepare_idle(2); - if (per_next_state == PWRDM_POWER_OFF) - omap3_per_save_context(); - } if (core_next_state == PWRDM_POWER_OFF) { omap3_core_save_context(); omap3_prcm_save_context(); @@ -392,14 +393,8 @@ static void omap_sram_idle(void) if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) restore_table_entry(); + /* CORE */ if (core_next_state < PWRDM_POWER_ON) { - if (per_next_state < PWRDM_POWER_ON) - omap_uart_resume_idle(2); - omap_uart_resume_idle(1); - omap_uart_resume_idle(0); - - /* Disable IO-PAD wakeup */ - prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); if (core_prev_state == PWRDM_POWER_OFF) { omap3_core_restore_context(); @@ -407,15 +402,27 @@ static void omap_sram_idle(void) omap3_sram_restore_context(); omap2_sms_restore_context(); } - if (per_next_state < PWRDM_POWER_ON) { - per_prev_state = - pwrdm_read_prev_pwrst(per_pwrdm); - if (per_prev_state == PWRDM_POWER_OFF) - omap3_per_restore_context(); - } + omap_uart_resume_idle(0); + omap_uart_resume_idle(1); + if (core_next_state == PWRDM_POWER_OFF) + prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF, + OMAP3430_GR_MOD, + OMAP3_PRM_VOLTCTRL_OFFSET); + } + + /* PER */ + if (per_next_state < PWRDM_POWER_ON) { + per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); + omap_uart_resume_idle(2); + if (per_prev_state == PWRDM_POWER_OFF) + omap3_per_restore_context(); omap2_gpio_resume_after_retention(); } + /* Disable IO-PAD wakeup */ + if (core_next_state < PWRDM_POWER_ON) + prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + pwrdm_post_transition(); } From ecf157d0b38953cdefa2c8fb7ccb5a62db242aef Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 1 Dec 2008 13:17:29 +0200 Subject: [PATCH 29/32] OMAP3: PM: Prevent PER from going OFF when CORE is going INA OMAP3 can't generate wakeups in this state, thus it is not permitted. Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index d8a6e10ac315..55567bf5ccbf 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -308,6 +308,7 @@ static void omap_sram_idle(void) int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; + int per_state_modified = 0; if (!_omap_sram_idle) return; @@ -340,15 +341,21 @@ static void omap_sram_idle(void) /* PER */ per_next_state = pwrdm_read_next_pwrst(per_pwrdm); + core_next_state = pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state < PWRDM_POWER_ON) { - omap2_gpio_prepare_for_retention(); omap_uart_prepare_idle(2); - if (per_next_state == PWRDM_POWER_OFF) - omap3_per_save_context(); + omap2_gpio_prepare_for_retention(); + if (per_next_state == PWRDM_POWER_OFF) { + if (core_next_state == PWRDM_POWER_ON) { + per_next_state = PWRDM_POWER_RET; + pwrdm_set_next_pwrst(per_pwrdm, per_next_state); + per_state_modified = 1; + } else + omap3_per_save_context(); + } } /* CORE */ - core_next_state = pwrdm_read_next_pwrst(core_pwrdm); if (core_next_state < PWRDM_POWER_ON) { omap_uart_prepare_idle(0); omap_uart_prepare_idle(1); @@ -413,10 +420,12 @@ static void omap_sram_idle(void) /* PER */ if (per_next_state < PWRDM_POWER_ON) { per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); - omap_uart_resume_idle(2); if (per_prev_state == PWRDM_POWER_OFF) omap3_per_restore_context(); omap2_gpio_resume_after_retention(); + omap_uart_resume_idle(2); + if (per_state_modified) + pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } /* Disable IO-PAD wakeup */ From c16c3f672defb7aca1276065375fe1ee5ca003dc Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 11 Dec 2008 16:46:57 +0200 Subject: [PATCH 30/32] OMAP3: PM: MPU and CORE should stay awake if there is CAM domain ACTIVE MPU and CORE should stay awake if there is CAM domain ACTIVE. This is because that module doesn't have wake-up capability. This should replace the patch that is currently in the PM branch. Signed-off-by: Jouni Hogander Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 55567bf5ccbf..7623edabc419 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -80,6 +80,7 @@ static int (*_omap_save_secure_sram)(u32 *addr); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; +static struct powerdomain *cam_pwrdm; static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); @@ -355,6 +356,9 @@ static void omap_sram_idle(void) } } + if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) + omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]); + /* CORE */ if (core_next_state < PWRDM_POWER_ON) { omap_uart_prepare_idle(0); @@ -434,6 +438,7 @@ static void omap_sram_idle(void) pwrdm_post_transition(); + omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); } /* @@ -1067,6 +1072,7 @@ static int __init omap3_pm_init(void) neon_pwrdm = pwrdm_lookup("neon_pwrdm"); per_pwrdm = pwrdm_lookup("per_pwrdm"); core_pwrdm = pwrdm_lookup("core_pwrdm"); + cam_pwrdm = pwrdm_lookup("cam_pwrdm"); omap_push_sram_idle(); #ifdef CONFIG_SUSPEND From 3a7ec26bb44988051d97479f6dfcfd4942a99049 Mon Sep 17 00:00:00 2001 From: Kalle Jokiniemi Date: Thu, 26 Mar 2009 15:59:01 +0200 Subject: [PATCH 31/32] OMAP3: PM: Enable IO-CHAIN wakeup OMAP 3430 ES3.1 chips have a separate bit for IO daisy-chain wake up enabling. It needs to be enabled when entering retention or off state, otherwise waking up might not work in all situations. Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 38 ++++++++++++++++++++++++-- arch/arm/mach-omap2/prm-regbits-34xx.h | 2 ++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 7623edabc419..511a57dc7015 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -94,6 +94,35 @@ static inline void omap3_per_restore_context(void) omap_gpio_restore_context(); } +static void omap3_enable_io_chain(void) +{ + int timeout = 0; + + if (omap_rev() >= OMAP3430_REV_ES3_1) { + prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); + /* Do a readback to assure write has been done */ + prm_read_mod_reg(WKUP_MOD, PM_WKEN); + + while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) & + OMAP3430_ST_IO_CHAIN)) { + timeout++; + if (timeout > 1000) { + printk(KERN_ERR "Wake up daisy chain " + "activation failed.\n"); + return; + } + prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN, + WKUP_MOD, PM_WKST); + } + } +} + +static void omap3_disable_io_chain(void) +{ + if (omap_rev() >= OMAP3430_REV_ES3_1) + prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); +} + static void omap3_core_save_context(void) { u32 control_padconf_off; @@ -367,8 +396,9 @@ static void omap_sram_idle(void) omap3_core_save_context(); omap3_prcm_save_context(); } - /* Enable IO-PAD wakeup */ + /* Enable IO-PAD and IO-CHAIN wakeups */ prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_enable_io_chain(); } /* @@ -432,9 +462,11 @@ static void omap_sram_idle(void) pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } - /* Disable IO-PAD wakeup */ - if (core_next_state < PWRDM_POWER_ON) + /* Disable IO-PAD and IO-CHAIN wakeup */ + if (core_next_state < PWRDM_POWER_ON) { prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_disable_io_chain(); + } pwrdm_post_transition(); diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h index 9fd03a2ec95c..8f21bae6dc1c 100644 --- a/arch/arm/mach-omap2/prm-regbits-34xx.h +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h @@ -365,6 +365,7 @@ /* PM_PREPWSTST_GFX specific bits */ /* PM_WKEN_WKUP specific bits */ +#define OMAP3430_EN_IO_CHAIN (1 << 16) #define OMAP3430_EN_IO (1 << 8) #define OMAP3430_EN_GPIO1 (1 << 3) @@ -373,6 +374,7 @@ /* PM_IVA2GRPSEL_WKUP specific bits */ /* PM_WKST_WKUP specific bits */ +#define OMAP3430_ST_IO_CHAIN (1 << 16) #define OMAP3430_ST_IO (1 << 8) /* PRM_CLKSEL */ From f265dc4c5d39f2bd369d97c87a7bd89061b159d4 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 9 Jun 2009 22:30:41 +0530 Subject: [PATCH 32/32] OMAP3: PM: Program SDRC to send self refresh on timeout of AUTO_CNT Due to an OMAP3 errata (1.142), on HS/EMU devices SDRC should be programed to issue automatic self refresh on timeout of AUTO_CNT = 1 prior to any transition to OFF mode. This is needed only on sil rev's ES3.0 and above. This patch enables the above needed WA in the SDRC power register value stored in scratchpad, so that ROM code restores this value in SDRC POWER on the wakeup path. The original SDRC POWER register value is stored and restored back in omap_sram_idle() function. This fixes some random crashes observed while stressing suspend on HS/EMU devices. Signed-off-by: Rajendra Nayak Signed-off-by: Kalle Jokiniemi Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/control.c | 16 +++++++++++++++- arch/arm/mach-omap2/pm34xx.c | 24 +++++++----------------- arch/arm/plat-omap/include/plat/sdrc.h | 6 ++++++ 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 2ff8d7cc60a2..cdd1f35636dd 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -265,7 +265,21 @@ void omap3_save_scratchpad_contents(void) (sdrc_read_reg(SDRC_ERR_TYPE) & 0xFFFF); sdrc_block_contents.dll_a_ctrl = sdrc_read_reg(SDRC_DLLA_CTRL); sdrc_block_contents.dll_b_ctrl = 0x0; - sdrc_block_contents.power = sdrc_read_reg(SDRC_POWER); + /* + * Due to a OMAP3 errata (1.142), on EMU/HS devices SRDC should + * be programed to issue automatic self refresh on timeout + * of AUTO_CNT = 1 prior to any transition to OFF mode. + */ + if ((omap_type() != OMAP2_DEVICE_TYPE_GP) + && (omap_rev() >= OMAP3430_REV_ES3_0)) + sdrc_block_contents.power = (sdrc_read_reg(SDRC_POWER) & + ~(SDRC_POWER_AUTOCOUNT_MASK| + SDRC_POWER_CLKCTRL_MASK)) | + (1 << SDRC_POWER_AUTOCOUNT_SHIFT) | + SDRC_SELF_REFRESH_ON_AUTOCOUNT; + else + sdrc_block_contents.power = sdrc_read_reg(SDRC_POWER); + sdrc_block_contents.cs_0 = 0x0; sdrc_block_contents.mcfg_0 = sdrc_read_reg(SDRC_MCFG_0); sdrc_block_contents.mr_0 = (sdrc_read_reg(SDRC_MR_0) & 0xFFFF); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 511a57dc7015..01b95eaae75a 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -48,12 +48,6 @@ #include "pm.h" #include "sdrc.h" -#define SDRC_POWER_AUTOCOUNT_SHIFT 8 -#define SDRC_POWER_AUTOCOUNT_MASK (0xffff << SDRC_POWER_AUTOCOUNT_SHIFT) -#define SDRC_POWER_CLKCTRL_SHIFT 4 -#define SDRC_POWER_CLKCTRL_MASK (0x3 << SDRC_POWER_CLKCTRL_SHIFT) -#define SDRC_SELF_REFRESH_ON_AUTOCOUNT (0x2 << SDRC_POWER_CLKCTRL_SHIFT) - /* Scratchpad offsets */ #define OMAP343X_TABLE_ADDRESS_OFFSET 0x31 #define OMAP343X_TABLE_VALUE_OFFSET 0x30 @@ -402,19 +396,15 @@ static void omap_sram_idle(void) } /* - * Force SDRAM controller to self-refresh mode after timeout on - * autocount. This is needed on ES3.0 to avoid SDRAM controller - * hang-ups. - */ + * On EMU/HS devices ROM code restores a SRDC value + * from scratchpad which has automatic self refresh on timeout + * of AUTO_CNT = 1 enabled. This takes care of errata 1.142. + * Hence store/restore the SDRC_POWER register here. + */ if (omap_rev() >= OMAP3430_REV_ES3_0 && omap_type() != OMAP2_DEVICE_TYPE_GP && - core_next_state == PWRDM_POWER_OFF) { + core_next_state == PWRDM_POWER_OFF) sdrc_pwr = sdrc_read_reg(SDRC_POWER); - sdrc_write_reg((sdrc_pwr & - ~(SDRC_POWER_AUTOCOUNT_MASK|SDRC_POWER_CLKCTRL_MASK)) | - (1 << SDRC_POWER_AUTOCOUNT_SHIFT) | - SDRC_SELF_REFRESH_ON_AUTOCOUNT, SDRC_POWER); - } /* * omap3_arm_context is the location where ARM registers @@ -424,7 +414,7 @@ static void omap_sram_idle(void) _omap_sram_idle(omap3_arm_context, save_state); cpu_init(); - /* Restore normal SDRAM settings */ + /* Restore normal SDRC POWER settings */ if (omap_rev() >= OMAP3430_REV_ES3_0 && omap_type() != OMAP2_DEVICE_TYPE_GP && core_next_state == PWRDM_POWER_OFF) diff --git a/arch/arm/plat-omap/include/plat/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h index 772b71e8b44f..f704030d2a70 100644 --- a/arch/arm/plat-omap/include/plat/sdrc.h +++ b/arch/arm/plat-omap/include/plat/sdrc.h @@ -44,6 +44,12 @@ #define SDRC_RFR_CTRL_1 0x0D4 #define SDRC_MANUAL_1 0x0D8 +#define SDRC_POWER_AUTOCOUNT_SHIFT 8 +#define SDRC_POWER_AUTOCOUNT_MASK (0xffff << SDRC_POWER_AUTOCOUNT_SHIFT) +#define SDRC_POWER_CLKCTRL_SHIFT 4 +#define SDRC_POWER_CLKCTRL_MASK (0x3 << SDRC_POWER_CLKCTRL_SHIFT) +#define SDRC_SELF_REFRESH_ON_AUTOCOUNT (0x2 << SDRC_POWER_CLKCTRL_SHIFT) + /* * These values represent the number of memory clock cycles between * autorefresh initiation. They assume 1 refresh per 64 ms (JEDEC), 8192