From 1315b4a45e84cd82839b21d8caa060ab4f0a31d9 Mon Sep 17 00:00:00 2001 From: Chen-Hui Zhao Date: Tue, 20 Nov 2012 18:15:22 +0000 Subject: powerpc/rcpm: add sleep support for T4/B4 chips RCPM unit controls the power managment of T4/B4 chips. Software can access RCPM registers to put specific thread/core in PH10/PH15/PH20/PH30 state or put the device in LPM10/LPM20/LPM40 mode. The RCPM unit supports several wake up sources through internal timers and internal and external interrupts. When the device enter sleep state, it will be put in LPM20 mode. The command is "echo standby > /sys/power/state". Signed-off-by: Zhao Chenhui Signed-off-by: Li Yang Signed-off-by: Andy Fleming (cherry picked from commit 8b6d17409699ecac9799b9a68fdfeeb299f5f3a8) Change-Id: Id456db72f2d3af5c1638ab271f6cdabcc3794ded Reviewed-on: http://git.am.freescale.net:8181/1181 Reviewed-by: Wood Scott-B07421 Tested-by: Fleming Andrew-AFLEMING Reviewed-by: Fleming Andrew-AFLEMING diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c index bf74be8..2526378 100644 --- a/arch/powerpc/sysdev/fsl_rcpm.c +++ b/arch/powerpc/sysdev/fsl_rcpm.c @@ -20,7 +20,8 @@ #include #include -static struct ccsr_rcpm __iomem *rcpm_regs; +struct ccsr_rcpm __iomem *rcpm1_regs; +struct ccsr_rcpm_v2 __iomem *rcpm2_regs; static int rcpm_suspend_enter(suspend_state_t state) { @@ -32,12 +33,12 @@ static int rcpm_suspend_enter(suspend_state_t state) flush_dcache_L1(); flush_backside_L2_cache(); - setbits32(&rcpm_regs->powmgtcsr, RCPM_POWMGTCSR_SLP); + setbits32(&rcpm1_regs->powmgtcsr, RCPM_POWMGTCSR_SLP); /* At this point, the device is in sleep mode. */ /* Upon resume, wait for SLP bit to be clear. */ ret = spin_event_timeout( - (in_be32(&rcpm_regs->powmgtcsr) & RCPM_POWMGTCSR_SLP) == 0, + (in_be32(&rcpm1_regs->powmgtcsr) & RCPM_POWMGTCSR_SLP) == 0, 10000, 10); if (!ret) { pr_err("%s: timeout waiting for SLP bit " @@ -53,6 +54,41 @@ static int rcpm_suspend_enter(suspend_state_t state) return ret; } +static int rcpm_v2_suspend_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + + /* clear previous LPM20 status */ + setbits32(&rcpm2_regs->powmgtcsr, RCPM_POWMGTCSR_P_LPM20_ST); + /* enter LPM20 status */ + setbits32(&rcpm2_regs->powmgtcsr, RCPM_POWMGTCSR_LPM20_RQ); + + /* At this point, the device is in LPM20 status. */ + + /* resume ... */ + ret = spin_event_timeout( + (in_be32(&rcpm2_regs->powmgtcsr) & RCPM_POWMGTCSR_LPM20_ST) + == 0, 10000, 10); + if (!ret) { + pr_err("%s: timeout waiting for LPM20 bit to be cleared\n", + __func__); + ret = -EINVAL; + } + + break; + + default: + ret = -EINVAL; + + } + + return ret; + +} + static int rcpm_suspend_valid(suspend_state_t state) { if (state == PM_SUSPEND_STANDBY) @@ -61,18 +97,27 @@ static int rcpm_suspend_valid(suspend_state_t state) return 0; } -static const struct platform_suspend_ops rcpm_suspend_ops = { +static struct platform_suspend_ops rcpm_suspend_ops = { .valid = rcpm_suspend_valid, - .enter = rcpm_suspend_enter, }; static int rcpm_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - rcpm_regs = of_iomap(np, 0); - if (!rcpm_regs) - return -ENOMEM; + if (of_device_is_compatible(np, "fsl,qoriq-rcpm-2.0")) { + rcpm2_regs = of_iomap(np, 0); + if (!rcpm2_regs) + return -ENOMEM; + + rcpm_suspend_ops.enter = rcpm_v2_suspend_enter; + } else { + rcpm1_regs= of_iomap(np, 0); + if (!rcpm1_regs) + return -ENOMEM; + + rcpm_suspend_ops.enter = rcpm_suspend_enter; + } suspend_set_ops(&rcpm_suspend_ops); @@ -82,6 +127,7 @@ static int rcpm_probe(struct platform_device *pdev) static const struct of_device_id rcpm_ids[] = { { .compatible = "fsl,qoriq-rcpm-1.0", }, + { .compatible = "fsl,qoriq-rcpm-2.0", }, { }, }; -- cgit v0.10.2