Commit b1d2037a authored by Tony Lindgren's avatar Tony Lindgren

Merge tag 'for_3.8-fixes-pm' of...

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.
parents 3d70f8c6 cd8ce159
...@@ -275,6 +275,9 @@ static inline void __iomem *omap4_get_scu_base(void) ...@@ -275,6 +275,9 @@ static inline void __iomem *omap4_get_scu_base(void)
#endif #endif
extern void __init gic_init_irq(void); extern void __init gic_init_irq(void);
extern void gic_dist_disable(void);
extern bool gic_dist_disabled(void);
extern void gic_timer_retrigger(void);
extern void omap_smc1(u32 fn, u32 arg); extern void omap_smc1(u32 fn, u32 arg);
extern void __iomem *omap4_get_sar_ram_base(void); extern void __iomem *omap4_get_sar_ram_base(void);
extern void omap_do_wfi(void); extern void omap_do_wfi(void);
...@@ -282,6 +285,7 @@ extern void omap_do_wfi(void); ...@@ -282,6 +285,7 @@ extern void omap_do_wfi(void);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Needed for secondary core boot */ /* Needed for secondary core boot */
extern void omap_secondary_startup(void); extern void omap_secondary_startup(void);
extern void omap_secondary_startup_4460(void);
extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask); extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
extern void omap_auxcoreboot_addr(u32 cpu_addr); extern void omap_auxcoreboot_addr(u32 cpu_addr);
extern u32 omap_read_auxcoreboot0(void); extern u32 omap_read_auxcoreboot0(void);
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#include "omap44xx.h"
__CPUINIT __CPUINIT
/* Physical address needed since MMU not enabled yet on secondary core */ /* Physical address needed since MMU not enabled yet on secondary core */
...@@ -64,3 +66,39 @@ hold: ldr r12,=0x103 ...@@ -64,3 +66,39 @@ hold: ldr r12,=0x103
b secondary_startup b secondary_startup
ENDPROC(omap_secondary_startup) ENDPROC(omap_secondary_startup)
ENTRY(omap_secondary_startup_4460)
hold_2: ldr r12,=0x103
dsb
smc #0 @ read from AuxCoreBoot0
mov r0, r0, lsr #9
mrc p15, 0, r4, c0, c0, 5
and r4, r4, #0x0f
cmp r0, r4
bne hold_2
/*
* GIC distributor control register has changed between
* CortexA9 r1pX and r2pX. The Control Register secure
* banked version is now composed of 2 bits:
* bit 0 == Secure Enable
* bit 1 == Non-Secure Enable
* The Non-Secure banked register has not changed
* Because the ROM Code is based on the r1pX GIC, the CPU1
* GIC restoration will cause a problem to CPU0 Non-Secure SW.
* The workaround must be:
* 1) Before doing the CPU1 wakeup, CPU0 must disable
* the GIC distributor
* 2) CPU1 must re-enable the GIC distributor on
* it's wakeup path.
*/
ldr r1, =OMAP44XX_GIC_DIST_BASE
ldr r0, [r1]
orr r0, #1
str r0, [r1]
/*
* we've been released from the wait loop,secondary_stack
* should now contain the SVC stack for this core
*/
b secondary_startup
ENDPROC(omap_secondary_startup_4460)
...@@ -67,6 +67,7 @@ struct omap4_cpu_pm_info { ...@@ -67,6 +67,7 @@ struct omap4_cpu_pm_info {
void __iomem *scu_sar_addr; void __iomem *scu_sar_addr;
void __iomem *wkup_sar_addr; void __iomem *wkup_sar_addr;
void __iomem *l2x0_sar_addr; void __iomem *l2x0_sar_addr;
void (*secondary_startup)(void);
}; };
static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); static 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) ...@@ -299,6 +300,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
{ {
unsigned int cpu_state = 0; unsigned int cpu_state = 0;
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
if (omap_rev() == OMAP4430_REV_ES1_0) if (omap_rev() == OMAP4430_REV_ES1_0)
return -ENXIO; return -ENXIO;
...@@ -308,7 +310,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) ...@@ -308,7 +310,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
clear_cpu_prev_pwrst(cpu); clear_cpu_prev_pwrst(cpu);
set_cpu_next_pwrst(cpu, power_state); set_cpu_next_pwrst(cpu, power_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(omap_secondary_startup)); set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup));
scu_pwrst_prepare(cpu, power_state); scu_pwrst_prepare(cpu, power_state);
/* /*
...@@ -359,6 +361,11 @@ int __init omap4_mpuss_init(void) ...@@ -359,6 +361,11 @@ int __init omap4_mpuss_init(void)
pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET; pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1; pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
if (cpu_is_omap446x())
pm_info->secondary_startup = omap_secondary_startup_4460;
else
pm_info->secondary_startup = omap_secondary_startup;
pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
if (!pm_info->pwrdm) { if (!pm_info->pwrdm) {
pr_err("Lookup failed for CPU1 pwrdm\n"); pr_err("Lookup failed for CPU1 pwrdm\n");
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "iomap.h" #include "iomap.h"
#include "common.h" #include "common.h"
#include "clockdomain.h" #include "clockdomain.h"
#include "pm.h"
#define CPU_MASK 0xff0ffff0 #define CPU_MASK 0xff0ffff0
#define CPU_CORTEX_A9 0x410FC090 #define CPU_CORTEX_A9 0x410FC090
...@@ -118,8 +119,37 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct * ...@@ -118,8 +119,37 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
* 4.3.4.2 Power States of CPU0 and CPU1 * 4.3.4.2 Power States of CPU0 and CPU1
*/ */
if (booted) { if (booted) {
/*
* GIC distributor control register has changed between
* CortexA9 r1pX and r2pX. The Control Register secure
* banked version is now composed of 2 bits:
* bit 0 == Secure Enable
* bit 1 == Non-Secure Enable
* The Non-Secure banked register has not changed
* Because the ROM Code is based on the r1pX GIC, the CPU1
* GIC restoration will cause a problem to CPU0 Non-Secure SW.
* The workaround must be:
* 1) Before doing the CPU1 wakeup, CPU0 must disable
* the GIC distributor
* 2) CPU1 must re-enable the GIC distributor on
* it's wakeup path.
*/
if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
local_irq_disable();
gic_dist_disable();
}
clkdm_wakeup(cpu1_clkdm); clkdm_wakeup(cpu1_clkdm);
clkdm_allow_idle(cpu1_clkdm); clkdm_allow_idle(cpu1_clkdm);
if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
while (gic_dist_disabled()) {
udelay(1);
cpu_relax();
}
gic_timer_retrigger();
local_irq_enable();
}
} else { } else {
dsb_sev(); dsb_sev();
booted = true; booted = true;
...@@ -138,7 +168,14 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct * ...@@ -138,7 +168,14 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
static void __init wakeup_secondary(void) static void __init wakeup_secondary(void)
{ {
void *startup_addr = omap_secondary_startup;
void __iomem *base = omap_get_wakeupgen_base(); void __iomem *base = omap_get_wakeupgen_base();
if (cpu_is_omap446x()) {
startup_addr = omap_secondary_startup_4460;
pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD;
}
/* /*
* Write the address of secondary startup routine into the * Write the address of secondary startup routine into the
* AuxCoreBoot1 where ROM code will jump and start executing * AuxCoreBoot1 where ROM code will jump and start executing
...@@ -146,7 +183,7 @@ static void __init wakeup_secondary(void) ...@@ -146,7 +183,7 @@ static void __init wakeup_secondary(void)
* A barrier is added to ensure that write buffer is drained * A barrier is added to ensure that write buffer is drained
*/ */
if (omap_secure_apis_support()) if (omap_secure_apis_support())
omap_auxcoreboot_addr(virt_to_phys(omap_secondary_startup)); omap_auxcoreboot_addr(virt_to_phys(startup_addr));
else else
__raw_writel(virt_to_phys(omap5_secondary_startup), __raw_writel(virt_to_phys(omap5_secondary_startup),
base + OMAP_AUX_CORE_BOOT_1); base + OMAP_AUX_CORE_BOOT_1);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
#include <asm/hardware/cache-l2x0.h> #include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/memblock.h> #include <asm/memblock.h>
#include <asm/smp_twd.h>
#include <plat/sram.h> #include <plat/sram.h>
#include <plat/omap-secure.h> #include <plat/omap-secure.h>
...@@ -41,6 +43,10 @@ static void __iomem *l2cache_base; ...@@ -41,6 +43,10 @@ static void __iomem *l2cache_base;
#endif #endif
static void __iomem *sar_ram_base; static void __iomem *sar_ram_base;
static void __iomem *gic_dist_base_addr;
static void __iomem *twd_base;
#define IRQ_LOCALTIMER 29
#ifdef CONFIG_OMAP4_ERRATA_I688 #ifdef CONFIG_OMAP4_ERRATA_I688
/* Used to implement memory barrier on DRAM path */ /* Used to implement memory barrier on DRAM path */
...@@ -95,12 +101,14 @@ void __init omap_barriers_init(void) ...@@ -95,12 +101,14 @@ void __init omap_barriers_init(void)
void __init gic_init_irq(void) void __init gic_init_irq(void)
{ {
void __iomem *omap_irq_base; void __iomem *omap_irq_base;
void __iomem *gic_dist_base_addr;
/* Static mapping, never released */ /* Static mapping, never released */
gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K); gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
BUG_ON(!gic_dist_base_addr); BUG_ON(!gic_dist_base_addr);
twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_4K);
BUG_ON(!twd_base);
/* Static mapping, never released */ /* Static mapping, never released */
omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512); omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512);
BUG_ON(!omap_irq_base); BUG_ON(!omap_irq_base);
...@@ -110,6 +118,38 @@ void __init gic_init_irq(void) ...@@ -110,6 +118,38 @@ void __init gic_init_irq(void)
gic_init(0, 29, gic_dist_base_addr, omap_irq_base); gic_init(0, 29, gic_dist_base_addr, omap_irq_base);
} }
void gic_dist_disable(void)
{
if (gic_dist_base_addr)
__raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
}
bool gic_dist_disabled(void)
{
return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1);
}
void gic_timer_retrigger(void)
{
u32 twd_int = __raw_readl(twd_base + TWD_TIMER_INTSTAT);
u32 gic_int = __raw_readl(gic_dist_base_addr + GIC_DIST_PENDING_SET);
u32 twd_ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
if (twd_int && !(gic_int & BIT(IRQ_LOCALTIMER))) {
/*
* The local timer interrupt got lost while the distributor was
* disabled. Ack the pending interrupt, and retrigger it.
*/
pr_warn("%s: lost localtimer interrupt\n", __func__);
__raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
if (!(twd_ctrl & TWD_TIMER_CONTROL_PERIODIC)) {
__raw_writel(1, twd_base + TWD_TIMER_COUNTER);
twd_ctrl |= TWD_TIMER_CONTROL_ENABLE;
__raw_writel(twd_ctrl, twd_base + TWD_TIMER_CONTROL);
}
}
}
#ifdef CONFIG_CACHE_L2X0 #ifdef CONFIG_CACHE_L2X0
void __iomem *omap4_get_l2cache_base(void) void __iomem *omap4_get_l2cache_base(void)
......
...@@ -102,6 +102,15 @@ extern void enable_omap3630_toggle_l2_on_restore(void); ...@@ -102,6 +102,15 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
static inline void enable_omap3630_toggle_l2_on_restore(void) { } static inline void enable_omap3630_toggle_l2_on_restore(void) { }
#endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */ #endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
#define PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD (1 << 0)
#if defined(CONFIG_ARCH_OMAP4)
extern u16 pm44xx_errata;
#define IS_PM44XX_ERRATUM(id) (pm44xx_errata & (id))
#else
#define IS_PM44XX_ERRATUM(id) 0
#endif
#ifdef CONFIG_POWER_AVS_OMAP #ifdef CONFIG_POWER_AVS_OMAP
extern int omap_devinit_smartreflex(void); extern int omap_devinit_smartreflex(void);
extern void omap_enable_smartreflex_on_init(void); extern void omap_enable_smartreflex_on_init(void);
......
...@@ -34,6 +34,7 @@ struct power_state { ...@@ -34,6 +34,7 @@ struct power_state {
}; };
static LIST_HEAD(pwrst_list); static LIST_HEAD(pwrst_list);
u16 pm44xx_errata;
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
static int omap4_pm_suspend(void) static int omap4_pm_suspend(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment