aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2012-11-06 20:47:02 -0500
committerTony Lindgren <tony@atomide.com>2012-11-06 20:47:02 -0500
commitb1d2037a6c3c754ef7f527249ab2e1dee51e73dd (patch)
treedeaa9a4ccac205b288aff709f39c0b622d0b91b7
parent3d70f8c617a436c7146ecb81df2265b4626dfe89 (diff)
parentcd8ce159031813eb870a5f3d5b27c3be36cd6e3a (diff)
Merge tag 'for_3.8-fixes-pm' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm into omap-for-v3.8/fixes-non-critical-v2
Some non-regression fixes for OMAP4460 PM support.
-rw-r--r--arch/arm/mach-omap2/common.h4
-rw-r--r--arch/arm/mach-omap2/omap-headsmp.S38
-rw-r--r--arch/arm/mach-omap2/omap-mpuss-lowpower.c9
-rw-r--r--arch/arm/mach-omap2/omap-smp.c39
-rw-r--r--arch/arm/mach-omap2/omap4-common.c42
-rw-r--r--arch/arm/mach-omap2/pm.h9
-rw-r--r--arch/arm/mach-omap2/pm44xx.c1
7 files changed, 139 insertions, 3 deletions
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 7045e4d61ac3..d29dbaa29621 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -275,6 +275,9 @@ static inline void __iomem *omap4_get_scu_base(void)
275#endif 275#endif
276 276
277extern void __init gic_init_irq(void); 277extern void __init gic_init_irq(void);
278extern void gic_dist_disable(void);
279extern bool gic_dist_disabled(void);
280extern void gic_timer_retrigger(void);
278extern void omap_smc1(u32 fn, u32 arg); 281extern void omap_smc1(u32 fn, u32 arg);
279extern void __iomem *omap4_get_sar_ram_base(void); 282extern void __iomem *omap4_get_sar_ram_base(void);
280extern void omap_do_wfi(void); 283extern void omap_do_wfi(void);
@@ -282,6 +285,7 @@ extern void omap_do_wfi(void);
282#ifdef CONFIG_SMP 285#ifdef CONFIG_SMP
283/* Needed for secondary core boot */ 286/* Needed for secondary core boot */
284extern void omap_secondary_startup(void); 287extern void omap_secondary_startup(void);
288extern void omap_secondary_startup_4460(void);
285extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask); 289extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
286extern void omap_auxcoreboot_addr(u32 cpu_addr); 290extern void omap_auxcoreboot_addr(u32 cpu_addr);
287extern u32 omap_read_auxcoreboot0(void); 291extern u32 omap_read_auxcoreboot0(void);
diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
index 502e3135aad3..0ea09faf327b 100644
--- a/arch/arm/mach-omap2/omap-headsmp.S
+++ b/arch/arm/mach-omap2/omap-headsmp.S
@@ -18,6 +18,8 @@
18#include <linux/linkage.h> 18#include <linux/linkage.h>
19#include <linux/init.h> 19#include <linux/init.h>
20 20
21#include "omap44xx.h"
22
21 __CPUINIT 23 __CPUINIT
22 24
23/* Physical address needed since MMU not enabled yet on secondary core */ 25/* Physical address needed since MMU not enabled yet on secondary core */
@@ -64,3 +66,39 @@ hold: ldr r12,=0x103
64 b secondary_startup 66 b secondary_startup
65ENDPROC(omap_secondary_startup) 67ENDPROC(omap_secondary_startup)
66 68
69ENTRY(omap_secondary_startup_4460)
70hold_2: ldr r12,=0x103
71 dsb
72 smc #0 @ read from AuxCoreBoot0
73 mov r0, r0, lsr #9
74 mrc p15, 0, r4, c0, c0, 5
75 and r4, r4, #0x0f
76 cmp r0, r4
77 bne hold_2
78
79 /*
80 * GIC distributor control register has changed between
81 * CortexA9 r1pX and r2pX. The Control Register secure
82 * banked version is now composed of 2 bits:
83 * bit 0 == Secure Enable
84 * bit 1 == Non-Secure Enable
85 * The Non-Secure banked register has not changed
86 * Because the ROM Code is based on the r1pX GIC, the CPU1
87 * GIC restoration will cause a problem to CPU0 Non-Secure SW.
88 * The workaround must be:
89 * 1) Before doing the CPU1 wakeup, CPU0 must disable
90 * the GIC distributor
91 * 2) CPU1 must re-enable the GIC distributor on
92 * it's wakeup path.
93 */
94 ldr r1, =OMAP44XX_GIC_DIST_BASE
95 ldr r0, [r1]
96 orr r0, #1
97 str r0, [r1]
98
99 /*
100 * we've been released from the wait loop,secondary_stack
101 * should now contain the SVC stack for this core
102 */
103 b secondary_startup
104ENDPROC(omap_secondary_startup_4460)
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index ff4e6a0e9c7c..c8bc3ad85f68 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -67,6 +67,7 @@ struct omap4_cpu_pm_info {
67 void __iomem *scu_sar_addr; 67 void __iomem *scu_sar_addr;
68 void __iomem *wkup_sar_addr; 68 void __iomem *wkup_sar_addr;
69 void __iomem *l2x0_sar_addr; 69 void __iomem *l2x0_sar_addr;
70 void (*secondary_startup)(void);
70}; 71};
71 72
72static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); 73static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
@@ -299,6 +300,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
299int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) 300int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
300{ 301{
301 unsigned int cpu_state = 0; 302 unsigned int cpu_state = 0;
303 struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
302 304
303 if (omap_rev() == OMAP4430_REV_ES1_0) 305 if (omap_rev() == OMAP4430_REV_ES1_0)
304 return -ENXIO; 306 return -ENXIO;
@@ -308,7 +310,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
308 310
309 clear_cpu_prev_pwrst(cpu); 311 clear_cpu_prev_pwrst(cpu);
310 set_cpu_next_pwrst(cpu, power_state); 312 set_cpu_next_pwrst(cpu, power_state);
311 set_cpu_wakeup_addr(cpu, virt_to_phys(omap_secondary_startup)); 313 set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup));
312 scu_pwrst_prepare(cpu, power_state); 314 scu_pwrst_prepare(cpu, power_state);
313 315
314 /* 316 /*
@@ -359,6 +361,11 @@ int __init omap4_mpuss_init(void)
359 pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; 361 pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
360 pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET; 362 pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
361 pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1; 363 pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
364 if (cpu_is_omap446x())
365 pm_info->secondary_startup = omap_secondary_startup_4460;
366 else
367 pm_info->secondary_startup = omap_secondary_startup;
368
362 pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); 369 pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
363 if (!pm_info->pwrdm) { 370 if (!pm_info->pwrdm) {
364 pr_err("Lookup failed for CPU1 pwrdm\n"); 371 pr_err("Lookup failed for CPU1 pwrdm\n");
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 4d05fa8a4e48..49a08dfe8d88 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -32,6 +32,7 @@
32#include "iomap.h" 32#include "iomap.h"
33#include "common.h" 33#include "common.h"
34#include "clockdomain.h" 34#include "clockdomain.h"
35#include "pm.h"
35 36
36#define CPU_MASK 0xff0ffff0 37#define CPU_MASK 0xff0ffff0
37#define CPU_CORTEX_A9 0x410FC090 38#define CPU_CORTEX_A9 0x410FC090
@@ -118,8 +119,37 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
118 * 4.3.4.2 Power States of CPU0 and CPU1 119 * 4.3.4.2 Power States of CPU0 and CPU1
119 */ 120 */
120 if (booted) { 121 if (booted) {
122 /*
123 * GIC distributor control register has changed between
124 * CortexA9 r1pX and r2pX. The Control Register secure
125 * banked version is now composed of 2 bits:
126 * bit 0 == Secure Enable
127 * bit 1 == Non-Secure Enable
128 * The Non-Secure banked register has not changed
129 * Because the ROM Code is based on the r1pX GIC, the CPU1
130 * GIC restoration will cause a problem to CPU0 Non-Secure SW.
131 * The workaround must be:
132 * 1) Before doing the CPU1 wakeup, CPU0 must disable
133 * the GIC distributor
134 * 2) CPU1 must re-enable the GIC distributor on
135 * it's wakeup path.
136 */
137 if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
138 local_irq_disable();
139 gic_dist_disable();
140 }
141
121 clkdm_wakeup(cpu1_clkdm); 142 clkdm_wakeup(cpu1_clkdm);
122 clkdm_allow_idle(cpu1_clkdm); 143 clkdm_allow_idle(cpu1_clkdm);
144
145 if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
146 while (gic_dist_disabled()) {
147 udelay(1);
148 cpu_relax();
149 }
150 gic_timer_retrigger();
151 local_irq_enable();
152 }
123 } else { 153 } else {
124 dsb_sev(); 154 dsb_sev();
125 booted = true; 155 booted = true;
@@ -138,7 +168,14 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
138 168
139static void __init wakeup_secondary(void) 169static void __init wakeup_secondary(void)
140{ 170{
171 void *startup_addr = omap_secondary_startup;
141 void __iomem *base = omap_get_wakeupgen_base(); 172 void __iomem *base = omap_get_wakeupgen_base();
173
174 if (cpu_is_omap446x()) {
175 startup_addr = omap_secondary_startup_4460;
176 pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD;
177 }
178
142 /* 179 /*
143 * Write the address of secondary startup routine into the 180 * Write the address of secondary startup routine into the
144 * AuxCoreBoot1 where ROM code will jump and start executing 181 * AuxCoreBoot1 where ROM code will jump and start executing
@@ -146,7 +183,7 @@ static void __init wakeup_secondary(void)
146 * A barrier is added to ensure that write buffer is drained 183 * A barrier is added to ensure that write buffer is drained
147 */ 184 */
148 if (omap_secure_apis_support()) 185 if (omap_secure_apis_support())
149 omap_auxcoreboot_addr(virt_to_phys(omap_secondary_startup)); 186 omap_auxcoreboot_addr(virt_to_phys(startup_addr));
150 else 187 else
151 __raw_writel(virt_to_phys(omap5_secondary_startup), 188 __raw_writel(virt_to_phys(omap5_secondary_startup),
152 base + OMAP_AUX_CORE_BOOT_1); 189 base + OMAP_AUX_CORE_BOOT_1);
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index e1f289748c5d..6f94b4e7b18d 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -14,6 +14,7 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/irq.h>
17#include <linux/platform_device.h> 18#include <linux/platform_device.h>
18#include <linux/memblock.h> 19#include <linux/memblock.h>
19#include <linux/of_irq.h> 20#include <linux/of_irq.h>
@@ -24,6 +25,7 @@
24#include <asm/hardware/cache-l2x0.h> 25#include <asm/hardware/cache-l2x0.h>
25#include <asm/mach/map.h> 26#include <asm/mach/map.h>
26#include <asm/memblock.h> 27#include <asm/memblock.h>
28#include <asm/smp_twd.h>
27 29
28#include <plat/sram.h> 30#include <plat/sram.h>
29#include <plat/omap-secure.h> 31#include <plat/omap-secure.h>
@@ -41,6 +43,10 @@ static void __iomem *l2cache_base;
41#endif 43#endif
42 44
43static void __iomem *sar_ram_base; 45static void __iomem *sar_ram_base;
46static void __iomem *gic_dist_base_addr;
47static void __iomem *twd_base;
48
49#define IRQ_LOCALTIMER 29
44 50
45#ifdef CONFIG_OMAP4_ERRATA_I688 51#ifdef CONFIG_OMAP4_ERRATA_I688
46/* Used to implement memory barrier on DRAM path */ 52/* Used to implement memory barrier on DRAM path */
@@ -95,12 +101,14 @@ void __init omap_barriers_init(void)
95void __init gic_init_irq(void) 101void __init gic_init_irq(void)
96{ 102{
97 void __iomem *omap_irq_base; 103 void __iomem *omap_irq_base;
98 void __iomem *gic_dist_base_addr;
99 104
100 /* Static mapping, never released */ 105 /* Static mapping, never released */
101 gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K); 106 gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
102 BUG_ON(!gic_dist_base_addr); 107 BUG_ON(!gic_dist_base_addr);
103 108
109 twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_4K);
110 BUG_ON(!twd_base);
111
104 /* Static mapping, never released */ 112 /* Static mapping, never released */
105 omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512); 113 omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512);
106 BUG_ON(!omap_irq_base); 114 BUG_ON(!omap_irq_base);
@@ -110,6 +118,38 @@ void __init gic_init_irq(void)
110 gic_init(0, 29, gic_dist_base_addr, omap_irq_base); 118 gic_init(0, 29, gic_dist_base_addr, omap_irq_base);
111} 119}
112 120
121void gic_dist_disable(void)
122{
123 if (gic_dist_base_addr)
124 __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
125}
126
127bool gic_dist_disabled(void)
128{
129 return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1);
130}
131
132void gic_timer_retrigger(void)
133{
134 u32 twd_int = __raw_readl(twd_base + TWD_TIMER_INTSTAT);
135 u32 gic_int = __raw_readl(gic_dist_base_addr + GIC_DIST_PENDING_SET);
136 u32 twd_ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
137
138 if (twd_int && !(gic_int & BIT(IRQ_LOCALTIMER))) {
139 /*
140 * The local timer interrupt got lost while the distributor was
141 * disabled. Ack the pending interrupt, and retrigger it.
142 */
143 pr_warn("%s: lost localtimer interrupt\n", __func__);
144 __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
145 if (!(twd_ctrl & TWD_TIMER_CONTROL_PERIODIC)) {
146 __raw_writel(1, twd_base + TWD_TIMER_COUNTER);
147 twd_ctrl |= TWD_TIMER_CONTROL_ENABLE;
148 __raw_writel(twd_ctrl, twd_base + TWD_TIMER_CONTROL);
149 }
150 }
151}
152
113#ifdef CONFIG_CACHE_L2X0 153#ifdef CONFIG_CACHE_L2X0
114 154
115void __iomem *omap4_get_l2cache_base(void) 155void __iomem *omap4_get_l2cache_base(void)
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 67d66131cfa7..fc3c96d5e013 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -102,6 +102,15 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
102static inline void enable_omap3630_toggle_l2_on_restore(void) { } 102static inline void enable_omap3630_toggle_l2_on_restore(void) { }
103#endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */ 103#endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
104 104
105#define PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD (1 << 0)
106
107#if defined(CONFIG_ARCH_OMAP4)
108extern u16 pm44xx_errata;
109#define IS_PM44XX_ERRATUM(id) (pm44xx_errata & (id))
110#else
111#define IS_PM44XX_ERRATUM(id) 0
112#endif
113
105#ifdef CONFIG_POWER_AVS_OMAP 114#ifdef CONFIG_POWER_AVS_OMAP
106extern int omap_devinit_smartreflex(void); 115extern int omap_devinit_smartreflex(void);
107extern void omap_enable_smartreflex_on_init(void); 116extern void omap_enable_smartreflex_on_init(void);
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 04922d149068..0adbd7d81ce8 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -34,6 +34,7 @@ struct power_state {
34}; 34};
35 35
36static LIST_HEAD(pwrst_list); 36static LIST_HEAD(pwrst_list);
37u16 pm44xx_errata;
37 38
38#ifdef CONFIG_SUSPEND 39#ifdef CONFIG_SUSPEND
39static int omap4_pm_suspend(void) 40static int omap4_pm_suspend(void)