Merge branch 'imx6/pm' into next/pm
* imx6/pm: ARM: imx6q: resume PL310 only when CACHE_L2X0 defined ARM: imx6q: build pm code only when CONFIG_PM selected ARM: mx5: use generic irq chip pm interface for pm functions on
This commit is contained in:
Коммит
038485ea9b
|
@ -595,6 +595,7 @@ comment "i.MX6 family:"
|
||||||
|
|
||||||
config SOC_IMX6Q
|
config SOC_IMX6Q
|
||||||
bool "i.MX6 Quad support"
|
bool "i.MX6 Quad support"
|
||||||
|
select ARM_CPU_SUSPEND if PM
|
||||||
select ARM_GIC
|
select ARM_GIC
|
||||||
select CACHE_L2X0
|
select CACHE_L2X0
|
||||||
select CPU_V7
|
select CPU_V7
|
||||||
|
|
|
@ -70,4 +70,8 @@ AFLAGS_head-v7.o :=-Wa,-march=armv7-a
|
||||||
obj-$(CONFIG_SMP) += platsmp.o
|
obj-$(CONFIG_SMP) += platsmp.o
|
||||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||||
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
|
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
|
||||||
obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o pm-imx6q.o
|
obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PM),y)
|
||||||
|
obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o
|
||||||
|
endif
|
||||||
|
|
|
@ -71,6 +71,7 @@ ENTRY(v7_secondary_startup)
|
||||||
ENDPROC(v7_secondary_startup)
|
ENDPROC(v7_secondary_startup)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
/*
|
/*
|
||||||
* The following code is located into the .data section. This is to
|
* The following code is located into the .data section. This is to
|
||||||
* allow phys_l2x0_saved_regs to be accessed with a relative load
|
* allow phys_l2x0_saved_regs to be accessed with a relative load
|
||||||
|
@ -79,6 +80,7 @@ ENDPROC(v7_secondary_startup)
|
||||||
.data
|
.data
|
||||||
.align
|
.align
|
||||||
|
|
||||||
|
#ifdef CONFIG_CACHE_L2X0
|
||||||
.macro pl310_resume
|
.macro pl310_resume
|
||||||
ldr r2, phys_l2x0_saved_regs
|
ldr r2, phys_l2x0_saved_regs
|
||||||
ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0
|
ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0
|
||||||
|
@ -88,12 +90,17 @@ ENDPROC(v7_secondary_startup)
|
||||||
str r1, [r0, #L2X0_CTRL] @ re-enable L2
|
str r1, [r0, #L2X0_CTRL] @ re-enable L2
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.globl phys_l2x0_saved_regs
|
||||||
|
phys_l2x0_saved_regs:
|
||||||
|
.long 0
|
||||||
|
#else
|
||||||
|
.macro pl310_resume
|
||||||
|
.endm
|
||||||
|
#endif
|
||||||
|
|
||||||
ENTRY(v7_cpu_resume)
|
ENTRY(v7_cpu_resume)
|
||||||
bl v7_invalidate_l1
|
bl v7_invalidate_l1
|
||||||
pl310_resume
|
pl310_resume
|
||||||
b cpu_resume
|
b cpu_resume
|
||||||
ENDPROC(v7_cpu_resume)
|
ENDPROC(v7_cpu_resume)
|
||||||
|
#endif
|
||||||
.globl phys_l2x0_saved_regs
|
|
||||||
phys_l2x0_saved_regs:
|
|
||||||
.long 0
|
|
||||||
|
|
|
@ -64,7 +64,9 @@ void __init imx6q_pm_init(void)
|
||||||
* address of the data structure used by l2x0 core to save registers,
|
* address of the data structure used by l2x0 core to save registers,
|
||||||
* and later restore the necessary ones in imx6q resume entry.
|
* and later restore the necessary ones in imx6q resume entry.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_CACHE_L2X0
|
||||||
phys_l2x0_saved_regs = __pa(&l2x0_saved_regs);
|
phys_l2x0_saved_regs = __pa(&l2x0_saved_regs);
|
||||||
|
#endif
|
||||||
|
|
||||||
suspend_set_ops(&imx6q_pm_ops);
|
suspend_set_ops(&imx6q_pm_ops);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
|
||||||
#include <asm/mach/map.h>
|
#include <asm/mach/map.h>
|
||||||
|
|
||||||
|
@ -21,10 +22,26 @@
|
||||||
#include <mach/devices-common.h>
|
#include <mach/devices-common.h>
|
||||||
#include <mach/iomux-v3.h>
|
#include <mach/iomux-v3.h>
|
||||||
|
|
||||||
|
static struct clk *gpc_dvfs_clk;
|
||||||
|
|
||||||
static void imx5_idle(void)
|
static void imx5_idle(void)
|
||||||
{
|
{
|
||||||
if (!need_resched())
|
if (!need_resched()) {
|
||||||
|
/* gpc clock is needed for SRPG */
|
||||||
|
if (gpc_dvfs_clk == NULL) {
|
||||||
|
gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
|
||||||
|
if (IS_ERR(gpc_dvfs_clk))
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
clk_enable(gpc_dvfs_clk);
|
||||||
mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
|
mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
|
||||||
|
if (tzic_enable_wake())
|
||||||
|
goto err1;
|
||||||
|
cpu_do_idle();
|
||||||
|
err1:
|
||||||
|
clk_disable(gpc_dvfs_clk);
|
||||||
|
}
|
||||||
|
err0:
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
|
||||||
stop_mode = 1;
|
stop_mode = 1;
|
||||||
}
|
}
|
||||||
arm_srpgcr |= MXC_SRPGCR_PCR;
|
arm_srpgcr |= MXC_SRPGCR_PCR;
|
||||||
|
|
||||||
if (tzic_enable_wake(1) != 0)
|
|
||||||
return;
|
|
||||||
break;
|
break;
|
||||||
case STOP_POWER_ON:
|
case STOP_POWER_ON:
|
||||||
ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
|
ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
|
||||||
|
|
|
@ -130,6 +130,12 @@ extern void imx53_evk_common_init(void);
|
||||||
extern void imx53_qsb_common_init(void);
|
extern void imx53_qsb_common_init(void);
|
||||||
extern void imx53_smd_common_init(void);
|
extern void imx53_smd_common_init(void);
|
||||||
extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
|
extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
|
||||||
extern void imx6q_pm_init(void);
|
|
||||||
extern void imx6q_clock_map_io(void);
|
extern void imx6q_clock_map_io(void);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
extern void imx6q_pm_init(void);
|
||||||
|
#else
|
||||||
|
static inline void imx6q_pm_init(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -168,7 +168,7 @@ struct cpu_op {
|
||||||
u32 cpu_rate;
|
u32 cpu_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
int tzic_enable_wake(int is_idle);
|
int tzic_enable_wake(void);
|
||||||
|
|
||||||
extern struct cpu_op *(*get_cpu_op)(int *op);
|
extern struct cpu_op *(*get_cpu_op)(int *op);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -73,7 +73,28 @@ static int tzic_set_irq_fiq(unsigned int irq, unsigned int type)
|
||||||
#define tzic_set_irq_fiq NULL
|
#define tzic_set_irq_fiq NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned int *wakeup_intr[4];
|
#ifdef CONFIG_PM
|
||||||
|
static void tzic_irq_suspend(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||||
|
int idx = gc->irq_base >> 5;
|
||||||
|
|
||||||
|
__raw_writel(gc->wake_active, tzic_base + TZIC_WAKEUP0(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tzic_irq_resume(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||||
|
int idx = gc->irq_base >> 5;
|
||||||
|
|
||||||
|
__raw_writel(__raw_readl(tzic_base + TZIC_ENSET0(idx)),
|
||||||
|
tzic_base + TZIC_WAKEUP0(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define tzic_irq_suspend NULL
|
||||||
|
#define tzic_irq_resume NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct mxc_extra_irq tzic_extra_irq = {
|
static struct mxc_extra_irq tzic_extra_irq = {
|
||||||
#ifdef CONFIG_FIQ
|
#ifdef CONFIG_FIQ
|
||||||
|
@ -91,12 +112,13 @@ static __init void tzic_init_gc(unsigned int irq_start)
|
||||||
handle_level_irq);
|
handle_level_irq);
|
||||||
gc->private = &tzic_extra_irq;
|
gc->private = &tzic_extra_irq;
|
||||||
gc->wake_enabled = IRQ_MSK(32);
|
gc->wake_enabled = IRQ_MSK(32);
|
||||||
wakeup_intr[idx] = &gc->wake_active;
|
|
||||||
|
|
||||||
ct = gc->chip_types;
|
ct = gc->chip_types;
|
||||||
ct->chip.irq_mask = irq_gc_mask_disable_reg;
|
ct->chip.irq_mask = irq_gc_mask_disable_reg;
|
||||||
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
|
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
|
||||||
ct->chip.irq_set_wake = irq_gc_set_wake;
|
ct->chip.irq_set_wake = irq_gc_set_wake;
|
||||||
|
ct->chip.irq_suspend = tzic_irq_suspend;
|
||||||
|
ct->chip.irq_resume = tzic_irq_resume;
|
||||||
ct->regs.disable = TZIC_ENCLEAR0(idx);
|
ct->regs.disable = TZIC_ENCLEAR0(idx);
|
||||||
ct->regs.enable = TZIC_ENSET0(idx);
|
ct->regs.enable = TZIC_ENSET0(idx);
|
||||||
|
|
||||||
|
@ -167,23 +189,19 @@ void __init tzic_init_irq(void __iomem *irqbase)
|
||||||
/**
|
/**
|
||||||
* tzic_enable_wake() - enable wakeup interrupt
|
* tzic_enable_wake() - enable wakeup interrupt
|
||||||
*
|
*
|
||||||
* @param is_idle 1 if called in idle loop (ENSET0 register);
|
|
||||||
* 0 to be used when called from low power entry
|
|
||||||
* @return 0 if successful; non-zero otherwise
|
* @return 0 if successful; non-zero otherwise
|
||||||
*/
|
*/
|
||||||
int tzic_enable_wake(int is_idle)
|
int tzic_enable_wake(void)
|
||||||
{
|
{
|
||||||
unsigned int i, v;
|
unsigned int i;
|
||||||
|
|
||||||
__raw_writel(1, tzic_base + TZIC_DSMINT);
|
__raw_writel(1, tzic_base + TZIC_DSMINT);
|
||||||
if (unlikely(__raw_readl(tzic_base + TZIC_DSMINT) == 0))
|
if (unlikely(__raw_readl(tzic_base + TZIC_DSMINT) == 0))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++)
|
||||||
v = is_idle ? __raw_readl(tzic_base + TZIC_ENSET0(i)) :
|
__raw_writel(__raw_readl(tzic_base + TZIC_ENSET0(i)),
|
||||||
*wakeup_intr[i];
|
tzic_base + TZIC_WAKEUP0(i));
|
||||||
__raw_writel(v, tzic_base + TZIC_WAKEUP0(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче