summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorChenhui Zhao <chenhui.zhao@freescale.com>2015-01-23 11:29:06 (GMT)
committerZhengxiong Jin <Jason.Jin@freescale.com>2015-02-05 08:28:52 (GMT)
commited45606fb6f0737605ee84aee8495bdc76753cdc (patch)
treed4657a7bddc1f4c7771b08313a85d847c5667f6a /arch/arm
parent6b65e3958ca5486b49048c86a3f824c603674392 (diff)
downloadlinux-fsl-qoriq-ed45606fb6f0737605ee84aee8495bdc76753cdc.tar.xz
arm: ls1021a: set wakeup devices dynamically for sleep/deep sleep
If a device works as a wakeup source, it will keep working in the peroid of sleep/deep sleep. This patch sets the wakeup devices according to the wakeup attribute of device. Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com> Change-Id: If49a8ad282115ac415fb03d0197964c5ae10c86d Reviewed-on: http://git.am.freescale.net:8181/29152 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Dongsheng Wang <dongsheng.wang@freescale.com> Reviewed-by: Zhengxiong Jin <Jason.Jin@freescale.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/boot/dts/ls1021a.dtsi5
-rw-r--r--arch/arm/mach-imx/pm-ls1.c86
2 files changed, 83 insertions, 8 deletions
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 67909b1..4c1c670 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -128,6 +128,7 @@
sdhci,auto-cmd12;
big-endian;
bus-width = <4>;
+ sleep = <&rcpm 0x00000080 0x0>;
status = "disabled";
};
@@ -391,6 +392,7 @@
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sysclk>;
clock-names = "ipg";
+ sleep = <&rcpm 0x0 0x40000000>;
status = "disabled";
};
@@ -447,6 +449,7 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ sleep = <&rcpm 0x00000040 0x0>;
};
gpio2: gpio@2310000 {
@@ -484,6 +487,7 @@
reg = <0x0 0x29d0000 0x0 0x10000>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
big-endian;
+ sleep = <&rcpm 0x0 0x20000000>;
status = "disabled";
};
@@ -606,6 +610,7 @@
fsl,dma-endian-le;
fsl,magic-packet;
fsl,wake-on-filer;
+ sleep = <&rcpm 0x80000000 0x0>;
fsl,num_rx_queues = <0x1>;
fsl,num_tx_queues = <0x1>;
local-mac-address = [ 00 00 00 00 00 00 ];
diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c
index 827a486..b5d0f7d 100644
--- a/arch/arm/mach-imx/pm-ls1.c
+++ b/arch/arm/mach-imx/pm-ls1.c
@@ -35,6 +35,13 @@
#define CCSR_SCFG_DPSLPCR 0
#define CCSR_SCFG_DPSLPCR_VAL 0x1
#define CCSR_SCFG_PMCINTECR 0x160
+#define CCSR_SCFG_PMCINTECR_LPUART 0x40000000
+#define CCSR_SCFG_PMCINTECR_FTM 0x20000000
+#define CCSR_SCFG_PMCINTECR_GPIO 0x10000000
+#define CCSR_SCFG_PMCINTECR_IRQ0 0x08000000
+#define CCSR_SCFG_PMCINTECR_IRQ1 0x04000000
+#define CCSR_SCFG_PMCINTECR_ETSECRXG0 0x00800000
+#define CCSR_SCFG_PMCINTECR_ETSECRXG1 0x00400000
#define CCSR_SCFG_PMCINTLECR 0x164
#define CCSR_SCFG_PMCINTSR 0x168
#define CCSR_SCFG_SPARECR2 0x504
@@ -50,7 +57,11 @@
#define CCSR_RCPM_CLPCL10SETR 0x1c4
#define CCSR_RCPM_CLPCL10SETR_C0 0x1
#define CCSR_RCPM_IPPDEXPCR0 0x140
+#define CCSR_RCPM_IPPDEXPCR0_ETSEC 0x80000000
+#define CCSR_RCPM_IPPDEXPCR0_GPIO 0x00000040
#define CCSR_RCPM_IPPDEXPCR1 0x144
+#define CCSR_RCPM_IPPDEXPCR1_LPUART 0x40000000
+#define CCSR_RCPM_IPPDEXPCR1_FLEXTIMER 0x20000000
#define QIXIS_CTL_SYS 0x5
#define QIXIS_CTL_SYS_EVTSW_MASK 0x0c
@@ -64,6 +75,10 @@
/* use the last page of SRAM */
#define SRAM_CODE_BASE_PHY (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE)
+#define SLEEP_ARRAY_SIZE 3
+
+static u32 ippdexpcr0, ippdexpcr1;
+
struct ls1_pm_baseaddr {
void __iomem *epu;
void __iomem *dcsr_rcpm1;
@@ -132,17 +147,35 @@ static void ls1_pm_uniomap(void)
iounmap(ls1_pm_base.sram);
}
-
-static void ls1_setup_wakeup_source(void)
+static void ls1_setup_pmc_int(void)
{
+ u32 pmcintecr;
+
+ pmcintecr = 0;
+ if (ippdexpcr0 & CCSR_RCPM_IPPDEXPCR0_ETSEC)
+ pmcintecr |= CCSR_SCFG_PMCINTECR_ETSECRXG0 |
+ CCSR_SCFG_PMCINTECR_ETSECRXG1;
+
+ if (ippdexpcr0 & CCSR_RCPM_IPPDEXPCR0_GPIO)
+ pmcintecr |= CCSR_SCFG_PMCINTECR_GPIO;
+
+ if (ippdexpcr1 & CCSR_RCPM_IPPDEXPCR1_LPUART)
+ pmcintecr |= CCSR_SCFG_PMCINTECR_LPUART;
+
+ if (ippdexpcr1 & CCSR_RCPM_IPPDEXPCR1_FLEXTIMER)
+ pmcintecr |= CCSR_SCFG_PMCINTECR_FTM;
+
+ /* always set external IRQ pins as wakeup source */
+ pmcintecr |= CCSR_SCFG_PMCINTECR_IRQ0 | CCSR_SCFG_PMCINTECR_IRQ1;
+
/* enable wakeup interrupt during deep sleep */
- iowrite32be(0xfcfc0000, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR);
+ iowrite32be(pmcintecr, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR);
iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTLECR);
/* clear PMC interrupt status */
iowrite32be(0xffffffff, ls1_pm_base.scfg + CCSR_SCFG_PMCINTSR);
}
-static void ls1_clear_wakeup_source(void)
+static void ls1_clear_pmc_int(void)
{
/* disable wakeup interrupt during deep sleep */
iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR);
@@ -153,8 +186,8 @@ static void ls1_clear_wakeup_source(void)
/* set IP powerdown exception, make them work during sleep/deep sleep */
static void ls1_set_powerdown(void)
{
- iowrite32be(0x8000c000, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR0);
- iowrite32be(0xf0000000, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR1);
+ iowrite32be(ippdexpcr0, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR0);
+ iowrite32be(ippdexpcr1, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR1);
}
static void ls1_save_ddr(void *base)
@@ -276,11 +309,11 @@ static void ls1_enter_deepsleep(void)
/* copy the last stage code to sram */
ls1_copy_sram_code();
- ls1_setup_wakeup_source();
+ ls1_setup_pmc_int();
cpu_suspend(SRAM_CODE_BASE_PHY, ls1_start_deepsleep);
- ls1_clear_wakeup_source();
+ ls1_clear_pmc_int();
/* disable Warm Device Reset */
ls1_clrsetbits_be32(ls1_pm_base.scfg + CCSR_SCFG_DPSLPCR,
@@ -291,6 +324,39 @@ static void ls1_enter_deepsleep(void)
iowrite8(tmp & ~QIXIS_PWR_CTL2_PCTL, ls1_pm_base.fpga + QIXIS_PWR_CTL2);
}
+static void ls1_set_power_except(struct device *dev, int on)
+{
+ int ret;
+ u32 value[SLEEP_ARRAY_SIZE];
+
+ /*
+ * Get the values in the "sleep" property. There are three values.
+ * The first points to the RCPM node, the second is the value of
+ * the ippdexpcr0 register, and the third is the value of
+ * the ippdexpcr1 register.
+ */
+ ret = of_property_read_u32_array(dev->of_node, "sleep",
+ value, SLEEP_ARRAY_SIZE);
+ if (ret) {
+ dev_err(dev, "%s: Can not find the \"sleep\" property.\n",
+ __func__);
+ return;
+ }
+
+ ippdexpcr0 |= value[1];
+ ippdexpcr1 |= value[2];
+
+ pr_debug("%s: set %s as a wakeup source", __func__,
+ dev->of_node->full_name);
+}
+
+static void ls1_set_wakeup_device(struct device *dev, void *enable)
+{
+ /* set each device which can act as wakeup source */
+ if (device_may_wakeup(dev))
+ ls1_set_power_except(dev, *((int *)enable));
+}
+
static int ls1_suspend_enter(suspend_state_t state)
{
int ret = 0;
@@ -333,6 +399,10 @@ static int ls1_suspend_begin(suspend_state_t state)
{
ls1_pm_state = state;
+ ippdexpcr0 = 0;
+ ippdexpcr1 = 0;
+ dpm_for_each_dev(NULL, ls1_set_wakeup_device);
+
if (ls1_pm_state == PM_SUSPEND_MEM)
ls1_pm_iomap();