From 1fb9026344ea9ecc7c5860240104109112384a61 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Sat, 10 Sep 2011 11:30:28 +0530 Subject: ARM: Enable CPU_PM notifiers on ARM machines. Signed-off-by: Santosh Shilimkar Tested-and-Acked-by: Shawn Guo Tested-by: Vishwanath BS --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3269576dbfa8..247d0bc1119b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -29,6 +29,7 @@ config ARM select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQ select GENERIC_IRQ_SHOW + select CPU_PM if (SUSPEND || CPU_IDLE) help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and -- cgit v1.2.3 From 254056f3b12563c11e6dbcfad2fbfce20a4f3302 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 10 Feb 2011 12:54:10 -0800 Subject: ARM: gic: Use cpu pm notifiers to save gic state When the cpu is powered down in a low power mode, the gic cpu interface may be reset, and when the cpu cluster is powered down, the gic distributor may also be reset. This patch uses CPU_PM_ENTER and CPU_PM_EXIT notifiers to save and restore the gic cpu interface registers, and the CPU_CLUSTER_PM_ENTER and CPU_CLUSTER_PM_EXIT notifiers to save and restore the gic distributor registers. Original-author: Gary King Signed-off-by: Colin Cross Signed-off-by: Santosh Shilimkar Tested-and-Acked-by: Shawn Guo Tested-by: Vishwanath BS --- arch/arm/common/gic.c | 187 ++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/hardware/gic.h | 8 ++ 2 files changed, 195 insertions(+) (limited to 'arch') diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 3227ca952a12..66c7c4820108 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -276,6 +277,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic, if (gic_irqs > 1020) gic_irqs = 1020; + gic->gic_irqs = gic_irqs; + /* * Set all global interrupts to be level triggered, active low. */ @@ -343,6 +346,189 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) writel_relaxed(1, base + GIC_CPU_CTRL); } +#ifdef CONFIG_CPU_PM +/* + * Saves the GIC distributor registers during suspend or idle. Must be called + * with interrupts disabled but before powering down the GIC. After calling + * this function, no interrupts will be delivered by the GIC, and another + * platform-specific wakeup source must be enabled. + */ +static void gic_dist_save(unsigned int gic_nr) +{ + unsigned int gic_irqs; + void __iomem *dist_base; + int i; + + if (gic_nr >= MAX_GIC_NR) + BUG(); + + gic_irqs = gic_data[gic_nr].gic_irqs; + dist_base = gic_data[gic_nr].dist_base; + + if (!dist_base) + return; + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++) + gic_data[gic_nr].saved_spi_conf[i] = + readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) + gic_data[gic_nr].saved_spi_target[i] = + readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) + gic_data[gic_nr].saved_spi_enable[i] = + readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); +} + +/* + * Restores the GIC distributor registers during resume or when coming out of + * idle. Must be called before enabling interrupts. If a level interrupt + * that occured while the GIC was suspended is still present, it will be + * handled normally, but any edge interrupts that occured will not be seen by + * the GIC and need to be handled by the platform-specific wakeup source. + */ +static void gic_dist_restore(unsigned int gic_nr) +{ + unsigned int gic_irqs; + unsigned int i; + void __iomem *dist_base; + + if (gic_nr >= MAX_GIC_NR) + BUG(); + + gic_irqs = gic_data[gic_nr].gic_irqs; + dist_base = gic_data[gic_nr].dist_base; + + if (!dist_base) + return; + + writel_relaxed(0, dist_base + GIC_DIST_CTRL); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++) + writel_relaxed(gic_data[gic_nr].saved_spi_conf[i], + dist_base + GIC_DIST_CONFIG + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) + writel_relaxed(0xa0a0a0a0, + dist_base + GIC_DIST_PRI + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) + writel_relaxed(gic_data[gic_nr].saved_spi_target[i], + dist_base + GIC_DIST_TARGET + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) + writel_relaxed(gic_data[gic_nr].saved_spi_enable[i], + dist_base + GIC_DIST_ENABLE_SET + i * 4); + + writel_relaxed(1, dist_base + GIC_DIST_CTRL); +} + +static void gic_cpu_save(unsigned int gic_nr) +{ + int i; + u32 *ptr; + void __iomem *dist_base; + void __iomem *cpu_base; + + if (gic_nr >= MAX_GIC_NR) + BUG(); + + dist_base = gic_data[gic_nr].dist_base; + cpu_base = gic_data[gic_nr].cpu_base; + + if (!dist_base || !cpu_base) + return; + + ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable); + for (i = 0; i < DIV_ROUND_UP(32, 32); i++) + ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); + + ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); + for (i = 0; i < DIV_ROUND_UP(32, 16); i++) + ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4); + +} + +static void gic_cpu_restore(unsigned int gic_nr) +{ + int i; + u32 *ptr; + void __iomem *dist_base; + void __iomem *cpu_base; + + if (gic_nr >= MAX_GIC_NR) + BUG(); + + dist_base = gic_data[gic_nr].dist_base; + cpu_base = gic_data[gic_nr].cpu_base; + + if (!dist_base || !cpu_base) + return; + + ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable); + for (i = 0; i < DIV_ROUND_UP(32, 32); i++) + writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); + + ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); + for (i = 0; i < DIV_ROUND_UP(32, 16); i++) + writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4); + + for (i = 0; i < DIV_ROUND_UP(32, 4); i++) + writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4); + + writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK); + writel_relaxed(1, cpu_base + GIC_CPU_CTRL); +} + +static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) +{ + int i; + + for (i = 0; i < MAX_GIC_NR; i++) { + switch (cmd) { + case CPU_PM_ENTER: + gic_cpu_save(i); + break; + case CPU_PM_ENTER_FAILED: + case CPU_PM_EXIT: + gic_cpu_restore(i); + break; + case CPU_CLUSTER_PM_ENTER: + gic_dist_save(i); + break; + case CPU_CLUSTER_PM_ENTER_FAILED: + case CPU_CLUSTER_PM_EXIT: + gic_dist_restore(i); + break; + } + } + + return NOTIFY_OK; +} + +static struct notifier_block gic_notifier_block = { + .notifier_call = gic_notifier, +}; + +static void __init gic_pm_init(struct gic_chip_data *gic) +{ + gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, + sizeof(u32)); + BUG_ON(!gic->saved_ppi_enable); + + gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4, + sizeof(u32)); + BUG_ON(!gic->saved_ppi_conf); + + cpu_pm_register_notifier(&gic_notifier_block); +} +#else +static void __init gic_pm_init(struct gic_chip_data *gic) +{ +} +#endif + void __init gic_init(unsigned int gic_nr, unsigned int irq_start, void __iomem *dist_base, void __iomem *cpu_base) { @@ -360,6 +546,7 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, gic_dist_init(gic, irq_start); gic_cpu_init(gic); + gic_pm_init(gic); } void __cpuinit gic_secondary_init(unsigned int gic_nr) diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 435d3f86c708..c5627057b1c7 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -46,6 +46,14 @@ struct gic_chip_data { unsigned int irq_offset; void __iomem *dist_base; void __iomem *cpu_base; +#ifdef CONFIG_CPU_PM + u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; + u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; + u32 saved_spi_target[DIV_ROUND_UP(1020, 4)]; + u32 __percpu *saved_ppi_enable; + u32 __percpu *saved_ppi_conf; +#endif + unsigned int gic_irqs; }; #endif -- cgit v1.2.3 From 746a9d1963f1c7a3cd22662065d7dcd3d93ee62e Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 10 Feb 2011 02:08:32 -0800 Subject: ARM: vfp: Use cpu pm notifiers to save vfp state When the cpu is powered down in a low power mode, the vfp registers may be reset. This patch uses CPU_PM_ENTER and CPU_PM_EXIT notifiers to save and restore the cpu's vfp registers. Signed-off-by: Colin Cross Signed-off-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Tested-and-Acked-by: Shawn Guo Tested-by: Vishwanath BS --- arch/arm/vfp/vfpmodule.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 79bcb4316930..fe4b60b1e6c7 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -436,9 +437,7 @@ static void vfp_enable(void *unused) set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11)); } -#ifdef CONFIG_PM -#include - +#ifdef CONFIG_CPU_PM static int vfp_pm_suspend(void) { struct thread_info *ti = current_thread_info(); @@ -468,19 +467,33 @@ static void vfp_pm_resume(void) fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); } -static struct syscore_ops vfp_pm_syscore_ops = { - .suspend = vfp_pm_suspend, - .resume = vfp_pm_resume, +static int vfp_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd, + void *v) +{ + switch (cmd) { + case CPU_PM_ENTER: + vfp_pm_suspend(); + break; + case CPU_PM_ENTER_FAILED: + case CPU_PM_EXIT: + vfp_pm_resume(); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block vfp_cpu_pm_notifier_block = { + .notifier_call = vfp_cpu_pm_notifier, }; static void vfp_pm_init(void) { - register_syscore_ops(&vfp_pm_syscore_ops); + cpu_pm_register_notifier(&vfp_cpu_pm_notifier_block); } #else static inline void vfp_pm_init(void) { } -#endif /* CONFIG_PM */ +#endif /* CONFIG_CPU_PM */ /* * Ensure that the VFP state stored in 'thread->vfpstate' is up to date -- cgit v1.2.3 From 9c12845ee49716209cb2b087c0b47c3e37096bde Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 13 Jun 2011 00:45:59 +0000 Subject: ARM: gic: Allow gic arch extensions to provide irqchip flags Tegra can benefit from the IRQCHIP_MASK_ON_SUSPEND flag, allow it to be passed to the gic irq chip. Signed-off-by: Colin Cross Signed-off-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Tested-and-Acked-by: Shawn Guo Tested-by: Vishwanath BS --- arch/arm/common/gic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 66c7c4820108..734db99eaee7 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -544,6 +544,7 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, if (gic_nr == 0) gic_cpu_base_addr = cpu_base; + gic_chip.flags |= gic_arch_extn.flags; gic_dist_init(gic, irq_start); gic_cpu_init(gic); gic_pm_init(gic); -- cgit v1.2.3 From 48af9feab5e3bdf21af3a929ecc7c0b79d9a4a4e Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Fri, 2 Sep 2011 21:12:36 +0530 Subject: ARM: vfp: Fix the comment to make it consistent with the code. Function vfp_force_reload() clears vfp_current_hw_state, so update the comment accordingly. Signed-off-by: Santosh Shilimkar --- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index fe4b60b1e6c7..0cbd5a0a9332 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -69,7 +69,7 @@ static bool vfp_state_in_hw(unsigned int cpu, struct thread_info *thread) /* * Force a reload of the VFP context from the thread structure. We do * this by ensuring that access to the VFP hardware is disabled, and - * clear last_VFP_context. Must be called from non-preemptible context. + * clear vfp_current_hw_state. Must be called from non-preemptible context. */ static void vfp_force_reload(unsigned int cpu, struct thread_info *thread) { -- cgit v1.2.3 From 8fb54284ba6aa1f0d832ec015fde64ecf4bb0f4f Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Tue, 28 Jun 2011 12:42:56 -0700 Subject: ARM: mm: Add strongly ordered descriptor support. On certain architectures, there might be a need to mark certain addresses with strongly ordered memory attributes to avoid ordering issues at the interconnect level. On OMAP4, the asynchronous bridge buffers can only be drained with strongly ordered accesses and hence the need to mark the memory strongly ordered. Signed-off-by: Santosh Shilimkar Signed-off-by: Woodruff Richard Tested-by: Vishwanath BS --- arch/arm/include/asm/mach/map.h | 1 + arch/arm/include/asm/pgtable.h | 3 +++ arch/arm/mm/mmu.c | 8 ++++++++ 3 files changed, 12 insertions(+) (limited to 'arch') diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index d2fedb5aeb1f..b36f3654bf54 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -29,6 +29,7 @@ struct map_desc { #define MT_MEMORY_NONCACHED 11 #define MT_MEMORY_DTCM 12 #define MT_MEMORY_ITCM 13 +#define MT_MEMORY_SO 14 #ifdef CONFIG_MMU extern void iotable_init(struct map_desc *, int); diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 5750704e0271..f1956b27ae5a 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -232,6 +232,9 @@ extern pgprot_t pgprot_kernel; #define pgprot_writecombine(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE) +#define pgprot_stronglyordered(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED) + #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE #define pgprot_dmacoherent(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 594d677b92c8..ea9c9f3e48bf 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -273,6 +273,14 @@ static struct mem_type mem_types[] = { .prot_l1 = PMD_TYPE_TABLE, .domain = DOMAIN_KERNEL, }, + [MT_MEMORY_SO] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_MT_UNCACHED, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_S | + PMD_SECT_UNCACHED | PMD_SECT_XN, + .domain = DOMAIN_KERNEL, + }, }; const struct mem_type *get_mem_type(unsigned int type) -- cgit v1.2.3