From 6c529c499fecfe65da6429917bd9cb319040c69e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 25 Apr 2015 15:44:10 +0800 Subject: ARM: imx: use dynamic mapping for timer Pass physical address of timer block to mxc_timer_init() call, which in turn does dynamic mapping within the function. Thus, we can avoid using static mapping in clock drivers. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 0f04e30b726d..5cddd1534265 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -44,7 +44,7 @@ void imx27_soc_init(void); void imx31_soc_init(void); void imx35_soc_init(void); void epit_timer_init(void __iomem *base, int irq); -void mxc_timer_init(void __iomem *, int); +void mxc_timer_init(unsigned long, int); int mx1_clocks_init(unsigned long fref); int mx21_clocks_init(unsigned long lref, unsigned long fref); int mx27_clocks_init(unsigned long fref); -- cgit v1.2.3 From 9bbef18750b34fa1d476e46a7833867b49f856c4 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 25 Apr 2015 21:03:15 +0800 Subject: ARM: imx: move revision definitions and declarations into a header The revision definitions and declarations are widely used by clock drivers. As a step of moving clock drivers out of arch/arm/mach-imx, let's create header include/soc/imx/revision.h to accommodate them. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 4 ---- arch/arm/mach-imx/hardware.h | 1 + arch/arm/mach-imx/mx27.h | 4 ---- arch/arm/mach-imx/mx3x.h | 7 ------- arch/arm/mach-imx/mxc.h | 16 ---------------- include/soc/imx/revision.h | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 38 insertions(+), 31 deletions(-) create mode 100644 include/soc/imx/revision.h (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 5cddd1534265..3682d094a259 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -56,13 +56,10 @@ struct platform_device *mxc_register_gpio(char *name, int id, void mxc_set_cpu_type(unsigned int type); void mxc_restart(enum reboot_mode, const char *); void mxc_arch_reset_init(void __iomem *); -int mx51_revision(void); -int mx53_revision(void); void imx_set_aips(void __iomem *); void imx_aips_allow_unprivileged_access(const char *compat); int mxc_device_init(void); void imx_set_soc_revision(unsigned int rev); -unsigned int imx_get_soc_revision(void); void imx_init_revision_from_anatop(void); struct device *imx_soc_device_init(void); void imx6_enable_rbc(bool enable); @@ -87,7 +84,6 @@ enum mx3_cpu_pwr_mode { }; void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode); -void imx_print_silicon_rev(const char *cpu, int srev); void imx_enable_cpu(int cpu, bool enable); void imx_set_cpu_jump(int cpu, void *jump_addr); diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h index 76af2c03c241..d737f95ebb07 100644 --- a/arch/arm/mach-imx/hardware.h +++ b/arch/arm/mach-imx/hardware.h @@ -22,6 +22,7 @@ #ifndef __ASSEMBLY__ #include +#include #endif #include diff --git a/arch/arm/mach-imx/mx27.h b/arch/arm/mach-imx/mx27.h index 8a65f192e7f3..f96bb2642677 100644 --- a/arch/arm/mach-imx/mx27.h +++ b/arch/arm/mach-imx/mx27.h @@ -231,8 +231,4 @@ #define MX27_DMA_REQ_SDHC3 36 #define MX27_DMA_REQ_NFC 37 -#ifndef __ASSEMBLY__ -extern int mx27_revision(void); -#endif - #endif /* ifndef __MACH_MX27_H__ */ diff --git a/arch/arm/mach-imx/mx3x.h b/arch/arm/mach-imx/mx3x.h index 96fb4fbc8ad7..6fec6114c2f1 100644 --- a/arch/arm/mach-imx/mx3x.h +++ b/arch/arm/mach-imx/mx3x.h @@ -185,11 +185,4 @@ #define MX3x_PROD_SIGNATURE 0x1 /* For MX31 */ -/* Mandatory defines used globally */ - -#if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS) -extern int mx35_revision(void); -extern int mx31_revision(void); -#endif - #endif /* ifndef __MACH_MX3x_H__ */ diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 4c1343df2ba4..8726051fcfca 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -39,22 +39,6 @@ #define MXC_CPU_IMX6SX 0x62 #define MXC_CPU_IMX6Q 0x63 -#define IMX_CHIP_REVISION_1_0 0x10 -#define IMX_CHIP_REVISION_1_1 0x11 -#define IMX_CHIP_REVISION_1_2 0x12 -#define IMX_CHIP_REVISION_1_3 0x13 -#define IMX_CHIP_REVISION_1_4 0x14 -#define IMX_CHIP_REVISION_1_5 0x15 -#define IMX_CHIP_REVISION_2_0 0x20 -#define IMX_CHIP_REVISION_2_1 0x21 -#define IMX_CHIP_REVISION_2_2 0x22 -#define IMX_CHIP_REVISION_2_3 0x23 -#define IMX_CHIP_REVISION_3_0 0x30 -#define IMX_CHIP_REVISION_3_1 0x31 -#define IMX_CHIP_REVISION_3_2 0x32 -#define IMX_CHIP_REVISION_3_3 0x33 -#define IMX_CHIP_REVISION_UNKNOWN 0xff - #define IMX_DDR_TYPE_LPDDR2 1 #ifndef __ASSEMBLY__ diff --git a/include/soc/imx/revision.h b/include/soc/imx/revision.h new file mode 100644 index 000000000000..9ea346924c35 --- /dev/null +++ b/include/soc/imx/revision.h @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SOC_IMX_REVISION_H__ +#define __SOC_IMX_REVISION_H__ + +#define IMX_CHIP_REVISION_1_0 0x10 +#define IMX_CHIP_REVISION_1_1 0x11 +#define IMX_CHIP_REVISION_1_2 0x12 +#define IMX_CHIP_REVISION_1_3 0x13 +#define IMX_CHIP_REVISION_1_4 0x14 +#define IMX_CHIP_REVISION_1_5 0x15 +#define IMX_CHIP_REVISION_2_0 0x20 +#define IMX_CHIP_REVISION_2_1 0x21 +#define IMX_CHIP_REVISION_2_2 0x22 +#define IMX_CHIP_REVISION_2_3 0x23 +#define IMX_CHIP_REVISION_3_0 0x30 +#define IMX_CHIP_REVISION_3_1 0x31 +#define IMX_CHIP_REVISION_3_2 0x32 +#define IMX_CHIP_REVISION_3_3 0x33 +#define IMX_CHIP_REVISION_UNKNOWN 0xff + +int mx27_revision(void); +int mx31_revision(void); +int mx35_revision(void); +int mx51_revision(void); +int mx53_revision(void); + +unsigned int imx_get_soc_revision(void); +void imx_print_silicon_rev(const char *cpu, int srev); + +#endif /* __SOC_IMX_REVISION_H__ */ -- cgit v1.2.3 From f3a9249d096178d29bba69cece29da99a622ce28 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 25 Apr 2015 22:38:19 +0800 Subject: ARM: imx5: let pm code map CCM block on its own We are about to move imx5 clock driver into drivers/clk, so let's get imx5 pm code map CCM block on its own rather than relying on clock driver to do the mapping. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx51-imx53.c | 2 -- arch/arm/mach-imx/common.h | 2 -- arch/arm/mach-imx/pm-imx5.c | 9 ++++----- 3 files changed, 4 insertions(+), 9 deletions(-) (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 0f7e536147cb..f341464fe7e9 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -133,8 +133,6 @@ static struct clk_onecell_data clk_data; static void __init mx5_clocks_common_init(void __iomem *ccm_base) { - imx5_pm_set_ccm_base(ccm_base); - clk[IMX5_CLK_DUMMY] = imx_clk_fixed("dummy", 0); clk[IMX5_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); clk[IMX5_CLK_OSC] = imx_obtain_fixed_clock("osc", 0); diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 3682d094a259..fe510fbd0c8c 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -132,11 +132,9 @@ void imx6q_pm_set_ccm_base(void __iomem *base); #ifdef CONFIG_PM void imx51_pm_init(void); void imx53_pm_init(void); -void imx5_pm_set_ccm_base(void __iomem *base); #else static inline void imx51_pm_init(void) {} static inline void imx53_pm_init(void) {} -static inline void imx5_pm_set_ccm_base(void __iomem *base) {} #endif #ifdef CONFIG_NEON diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index f1f80ab73e69..b04025592d94 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -50,16 +50,19 @@ #define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF struct imx5_pm_data { + phys_addr_t ccm_addr; phys_addr_t cortex_addr; phys_addr_t gpc_addr; }; static const struct imx5_pm_data imx51_pm_data __initconst = { + .ccm_addr = 0x73fd4000, .cortex_addr = 0x83fa0000, .gpc_addr = 0x73fd8000, }; static const struct imx5_pm_data imx53_pm_data __initconst = { + .ccm_addr = 0x53fd4000, .cortex_addr = 0x63fa0000, .gpc_addr = 0x53fd8000, }; @@ -68,11 +71,6 @@ static void __iomem *ccm_base; static void __iomem *cortex_base; static void __iomem *gpc_base; -void __init imx5_pm_set_ccm_base(void __iomem *base) -{ - ccm_base = base; -} - /* * set cpu low power mode before WFI instruction. This function is called * mx5 because it can be used for mx51, and mx53. @@ -208,6 +206,7 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data) arm_pm_idle = imx5_pm_idle; + ccm_base = ioremap(data->ccm_addr, SZ_16K); cortex_base = ioremap(data->cortex_addr, SZ_16K); gpc_base = ioremap(data->gpc_addr, SZ_16K); WARN_ON(!ccm_base || !cortex_base || !gpc_base); -- cgit v1.2.3 From 8fb76a07e2cb08b9f278a6415af4f784bb635a6e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 25 Apr 2015 22:59:19 +0800 Subject: ARM: imx6: set initial power mode in pm function Rather than setting initial low-power mode in every single i.MX6 clock initialization function, we should really do that in pm code. Let's move imx6q_set_lpm(WAIT_CLOCKED) call into imx6_pm_common_init(). While at it, let's rename the function to imx6_set_lpm() since it's actually common for all i.MX6 SoCs. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 3 --- arch/arm/mach-imx/clk-imx6sl.c | 3 --- arch/arm/mach-imx/clk-imx6sx.c | 3 --- arch/arm/mach-imx/common.h | 2 +- arch/arm/mach-imx/cpuidle-imx6q.c | 4 ++-- arch/arm/mach-imx/cpuidle-imx6sl.c | 4 ++-- arch/arm/mach-imx/cpuidle-imx6sx.c | 4 ++-- arch/arm/mach-imx/pm-imx6.c | 14 ++++++++------ 8 files changed, 15 insertions(+), 22 deletions(-) (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 469a150bf98f..54ce0b30b9ad 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -527,8 +527,5 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) /* All existing boards with PCIe use LVDS1 */ if (IS_ENABLED(CONFIG_PCI_IMX6)) clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]); - - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); } CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index e982ebe10814..d990f51ded71 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c @@ -443,8 +443,5 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL], clks[IMX6SL_CLK_PLL2_PFD2]); - - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); } CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init); diff --git a/arch/arm/mach-imx/clk-imx6sx.c b/arch/arm/mach-imx/clk-imx6sx.c index 5a3e5a159e70..2b0a1fd5d7eb 100644 --- a/arch/arm/mach-imx/clk-imx6sx.c +++ b/arch/arm/mach-imx/clk-imx6sx.c @@ -560,8 +560,5 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]); clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]); - - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); } CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init); diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index fe510fbd0c8c..d7f3b7b1d911 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -107,7 +107,7 @@ void imx_gpc_hwirq_unmask(unsigned int hwirq); void imx_anatop_init(void); void imx_anatop_pre_suspend(void); void imx_anatop_post_resume(void); -int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); void imx6q_set_int_mem_clk_lpm(bool enable); void imx6sl_set_wait_clk(bool enter); int imx_mmdc_get_ddr_type(void); diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index 8e21ccc1eda2..353bb8774112 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -27,9 +27,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev, */ if (!spin_trylock(&master_lock)) goto idle; - imx6q_set_lpm(WAIT_UNCLOCKED); + imx6_set_lpm(WAIT_UNCLOCKED); cpu_do_idle(); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); spin_unlock(&master_lock); goto done; } diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c index 5742a9fd1ef2..8d866fb674a8 100644 --- a/arch/arm/mach-imx/cpuidle-imx6sl.c +++ b/arch/arm/mach-imx/cpuidle-imx6sl.c @@ -16,7 +16,7 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - imx6q_set_lpm(WAIT_UNCLOCKED); + imx6_set_lpm(WAIT_UNCLOCKED); /* * Software workaround for ERR005311, see function * description for details. @@ -24,7 +24,7 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev, imx6sl_set_wait_clk(true); cpu_do_idle(); imx6sl_set_wait_clk(false); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); return index; } diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c index 2c9f1a8bf245..3c6672b3796b 100644 --- a/arch/arm/mach-imx/cpuidle-imx6sx.c +++ b/arch/arm/mach-imx/cpuidle-imx6sx.c @@ -25,7 +25,7 @@ static int imx6sx_idle_finish(unsigned long val) static int imx6sx_enter_wait(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - imx6q_set_lpm(WAIT_UNCLOCKED); + imx6_set_lpm(WAIT_UNCLOCKED); switch (index) { case 1: @@ -50,7 +50,7 @@ static int imx6sx_enter_wait(struct cpuidle_device *dev, break; } - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); return index; } diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 6a7c6fc780cc..5858bde5a4e7 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -255,7 +255,7 @@ static void imx6q_enable_wb(bool enable) writel_relaxed(val, ccm_base + CCR); } -int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) { u32 val = readl_relaxed(ccm_base + CLPCR); @@ -340,7 +340,7 @@ static int imx6q_pm_enter(suspend_state_t state) { switch (state) { case PM_SUSPEND_STANDBY: - imx6q_set_lpm(STOP_POWER_ON); + imx6_set_lpm(STOP_POWER_ON); imx6q_set_int_mem_clk_lpm(true); imx_gpc_pre_suspend(false); if (cpu_is_imx6sl()) @@ -350,10 +350,10 @@ static int imx6q_pm_enter(suspend_state_t state) if (cpu_is_imx6sl()) imx6sl_set_wait_clk(false); imx_gpc_post_resume(); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); break; case PM_SUSPEND_MEM: - imx6q_set_lpm(STOP_POWER_OFF); + imx6_set_lpm(STOP_POWER_OFF); imx6q_set_int_mem_clk_lpm(false); imx6q_enable_wb(true); /* @@ -373,7 +373,7 @@ static int imx6q_pm_enter(suspend_state_t state) imx6_enable_rbc(false); imx6q_enable_wb(false); imx6q_set_int_mem_clk_lpm(true); - imx6q_set_lpm(WAIT_CLOCKED); + imx6_set_lpm(WAIT_CLOCKED); break; default: return -EINVAL; @@ -559,6 +559,8 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata WARN_ON(!ccm_base); + imx6_set_lpm(WAIT_CLOCKED); + if (IS_ENABLED(CONFIG_SUSPEND)) { ret = imx6q_suspend_init(socdata); if (ret) @@ -568,7 +570,7 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata /* * This is for SW workaround step #1 of ERR007265, see comments - * in imx6q_set_lpm for details of this errata. + * in imx6_set_lpm for details of this errata. * Force IOMUXC irq pending, so that the interrupt to GPC can be * used to deassert dsm_request signal when the signal gets * asserted unexpectedly. -- cgit v1.2.3 From f0b478b5d42ee9d925b45c22cbdc1ad4c90c3cf1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 25 Apr 2015 23:37:12 +0800 Subject: ARM: imx6: let pm code map CCM block on its own We are about to move imx6 clock driver into drivers/clk, so let's get imx6 pm code map CCM block on its own rather than relying on clock driver to do the mapping. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 2 -- arch/arm/mach-imx/clk-imx6sl.c | 3 --- arch/arm/mach-imx/clk-imx6sx.c | 2 -- arch/arm/mach-imx/common.h | 1 - arch/arm/mach-imx/pm-imx6.c | 16 +++++++++------- 5 files changed, 9 insertions(+), 15 deletions(-) (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 54ce0b30b9ad..5e88038ad51c 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -262,8 +262,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) base = of_iomap(np, 0); WARN_ON(!base); - imx6q_pm_set_ccm_base(base); - /* name reg shift width parent_names num_parents */ clk[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); clk[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index d990f51ded71..3aef26464110 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c @@ -288,9 +288,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) WARN_ON(!base); ccm_base = base; - /* Reuse imx6q pm code */ - imx6q_pm_set_ccm_base(base); - /* name reg shift width parent_names num_parents */ clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); diff --git a/arch/arm/mach-imx/clk-imx6sx.c b/arch/arm/mach-imx/clk-imx6sx.c index 2b0a1fd5d7eb..151460a95130 100644 --- a/arch/arm/mach-imx/clk-imx6sx.c +++ b/arch/arm/mach-imx/clk-imx6sx.c @@ -268,8 +268,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) base = of_iomap(np, 0); WARN_ON(!base); - imx6q_pm_set_ccm_base(base); - /* name reg shift width parent_names num_parents */ clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index d7f3b7b1d911..d1e2873f807e 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -127,7 +127,6 @@ void imx6q_pm_init(void); void imx6dl_pm_init(void); void imx6sl_pm_init(void); void imx6sx_pm_init(void); -void imx6q_pm_set_ccm_base(void __iomem *base); #ifdef CONFIG_PM void imx51_pm_init(void); diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 5858bde5a4e7..27bc80dab2d8 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -89,6 +89,7 @@ struct imx6_pm_base { struct imx6_pm_socdata { u32 ddr_type; + const char *ccm_compat; const char *mmdc_compat; const char *src_compat; const char *iomuxc_compat; @@ -138,6 +139,7 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = { }; static const struct imx6_pm_socdata imx6q_pm_data __initconst = { + .ccm_compat = "fsl,imx6q-ccm", .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6q-iomuxc", @@ -147,6 +149,7 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { + .ccm_compat = "fsl,imx6q-ccm", .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6dl-iomuxc", @@ -156,6 +159,7 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { + .ccm_compat = "fsl,imx6sl-ccm", .mmdc_compat = "fsl,imx6sl-mmdc", .src_compat = "fsl,imx6sl-src", .iomuxc_compat = "fsl,imx6sl-iomuxc", @@ -165,6 +169,7 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { + .ccm_compat = "fsl,imx6sx-ccm", .mmdc_compat = "fsl,imx6sx-mmdc", .src_compat = "fsl,imx6sx-src", .iomuxc_compat = "fsl,imx6sx-iomuxc", @@ -392,11 +397,6 @@ static const struct platform_suspend_ops imx6q_pm_ops = { .valid = imx6q_pm_valid, }; -void __init imx6q_pm_set_ccm_base(void __iomem *base) -{ - ccm_base = base; -} - static int __init imx6_pm_get_base(struct imx6_pm_base *base, const char *compat) { @@ -482,8 +482,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) /* * ccm physical address is not used by asm code currently, - * so get ccm virtual address directly, as we already have - * it from ccm driver. + * so get ccm virtual address directly. */ pm_info->ccm_base.vbase = ccm_base; @@ -554,9 +553,12 @@ put_node: static void __init imx6_pm_common_init(const struct imx6_pm_socdata *socdata) { + struct device_node *np; struct regmap *gpr; int ret; + np = of_find_compatible_node(NULL, NULL, socdata->ccm_compat); + ccm_base = of_iomap(np, 0); WARN_ON(!ccm_base); imx6_set_lpm(WAIT_CLOCKED); -- cgit v1.2.3 From 35e2916f70e3be767c5c8ef6cc80bc5398b8914c Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 29 Apr 2015 13:07:03 +0800 Subject: ARM: imx6: initialize CCM_CLPCR_LPM into RUN mode earlier Commit 4631960d26da ("ARM: imx6: set initial power mode in pm function") moves imx6_set_lpm() from clock init function into imx6_pm_common_init(). This causes a hang when cpuidle support is enabled. The reason for that is ARM core clock is shut down unexpectedly by WAIT mode. It happens with the following call stack: cpuidle_register_governor() cpuidle_switch_governor() cpuidle_uninstall_idle_handler() synchronize_sched() wait_rcu_gp() wait_for_completion() When wait_for_completion() is called as above, all cores are idle/WFI. Hence, the reset value of CCM_CLPCR_LPM - WAIT mode, will trigger a hardware shutdown of the ARM core clock. To fix the regression, we need to ensure that CCM_CLPCR_LPM is initialized into RUN mode earlier than cpuidle governor registration, which is a postcore_initcall. This patch creates function imx6_pm_ccm_init() to map CCM block and initialize CCM_CLPCR_LPM into RUN mode, and have the function called from machine .init_irq hook, which should be early enough. Reported-by: Kevin Hilman Fixes: 8fb76a07e2cb ("ARM: imx6: set initial power mode in pm function") Tested-by: Kevin Hilman Tested-by: Tyler Baker Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 1 + arch/arm/mach-imx/mach-imx6q.c | 1 + arch/arm/mach-imx/mach-imx6sl.c | 1 + arch/arm/mach-imx/mach-imx6sx.c | 1 + arch/arm/mach-imx/pm-imx6.c | 28 ++++++++++++++++++---------- 5 files changed, 22 insertions(+), 10 deletions(-) (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index d1e2873f807e..fbd86f1b7f3b 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -123,6 +123,7 @@ static inline void v7_cpu_resume(void) {} static inline void imx6_suspend(void __iomem *ocram_vbase) {} #endif +void imx6_pm_ccm_init(const char *ccm_compat); void imx6q_pm_init(void); void imx6dl_pm_init(void); void imx6sl_pm_init(void); diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 3ab61549ce0f..9602cc12d2f1 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -393,6 +393,7 @@ static void __init imx6q_init_irq(void) imx_init_l2cache(); imx_src_init(); irqchip_init(); + imx6_pm_ccm_init("fsl,imx6q-ccm"); } static const char * const imx6q_dt_compat[] __initconst = { diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index 12a1b098fc6a..300326373166 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -66,6 +66,7 @@ static void __init imx6sl_init_irq(void) imx_init_l2cache(); imx_src_init(); irqchip_init(); + imx6_pm_ccm_init("fsl,imx6sl-ccm"); } static const char * const imx6sl_dt_compat[] __initconst = { diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index f17b7004c24b..6a0b0614de29 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -86,6 +86,7 @@ static void __init imx6sx_init_irq(void) imx_init_l2cache(); imx_src_init(); irqchip_init(); + imx6_pm_ccm_init("fsl,imx6sx-ccm"); } static void __init imx6sx_init_late(void) diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 27bc80dab2d8..b01650d94f91 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -89,7 +89,6 @@ struct imx6_pm_base { struct imx6_pm_socdata { u32 ddr_type; - const char *ccm_compat; const char *mmdc_compat; const char *src_compat; const char *iomuxc_compat; @@ -139,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = { }; static const struct imx6_pm_socdata imx6q_pm_data __initconst = { - .ccm_compat = "fsl,imx6q-ccm", .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6q-iomuxc", @@ -149,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { - .ccm_compat = "fsl,imx6q-ccm", .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6dl-iomuxc", @@ -159,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { - .ccm_compat = "fsl,imx6sl-ccm", .mmdc_compat = "fsl,imx6sl-mmdc", .src_compat = "fsl,imx6sl-src", .iomuxc_compat = "fsl,imx6sl-iomuxc", @@ -169,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { - .ccm_compat = "fsl,imx6sx-ccm", .mmdc_compat = "fsl,imx6sx-mmdc", .src_compat = "fsl,imx6sx-src", .iomuxc_compat = "fsl,imx6sx-iomuxc", @@ -553,16 +548,11 @@ put_node: static void __init imx6_pm_common_init(const struct imx6_pm_socdata *socdata) { - struct device_node *np; struct regmap *gpr; int ret; - np = of_find_compatible_node(NULL, NULL, socdata->ccm_compat); - ccm_base = of_iomap(np, 0); WARN_ON(!ccm_base); - imx6_set_lpm(WAIT_CLOCKED); - if (IS_ENABLED(CONFIG_SUSPEND)) { ret = imx6q_suspend_init(socdata); if (ret) @@ -583,6 +573,24 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata IMX6Q_GPR1_GINT); } +void __init imx6_pm_ccm_init(const char *ccm_compat) +{ + struct device_node *np; + u32 val; + + np = of_find_compatible_node(NULL, NULL, ccm_compat); + ccm_base = of_iomap(np, 0); + BUG_ON(!ccm_base); + + /* + * Initialize CCM_CLPCR_LPM into RUN mode to avoid ARM core + * clock being shut down unexpectedly by WAIT mode. + */ + val = readl_relaxed(ccm_base + CLPCR); + val &= ~BM_CLPCR_LPM; + writel_relaxed(val, ccm_base + CLPCR); +} + void __init imx6q_pm_init(void) { imx6_pm_common_init(&imx6q_pm_data); -- cgit v1.2.3 From d0185d96c6c61871f090fe51116b6d81b3dd74b9 Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Wed, 29 Apr 2015 16:18:37 -0500 Subject: ARM: imx: Remove the duplicated function declaration Removed the duplicated function declaration of mxc_timer_init which was already declared in drivers/clk/imx/clk.h. Signed-off-by: Shenwei Wang Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index fbd86f1b7f3b..1f800b9a63f5 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -44,7 +44,6 @@ void imx27_soc_init(void); void imx31_soc_init(void); void imx35_soc_init(void); void epit_timer_init(void __iomem *base, int irq); -void mxc_timer_init(unsigned long, int); int mx1_clocks_init(unsigned long fref); int mx21_clocks_init(unsigned long lref, unsigned long fref); int mx27_clocks_init(unsigned long fref); -- cgit v1.2.3 From 1579c7b9fe0105a523440ec13b0c59da53c880e3 Mon Sep 17 00:00:00 2001 From: Martin Fuzzey Date: Tue, 12 May 2015 15:31:03 +0200 Subject: ARM: imx53: Set DDR pins to high impedance when in suspend to RAM. In order to save power the DDR pins should be put into high impedance when in suspend to RAM. This requires manually requesting self refresh (rather than using the automatic mode implemented by the CCM / ESDCTL), followed by reconfiguring the IOMUXC. Of course the code to do this cannot itself run from DDR so the code is copied to and executed from internal memory. In my tests using a custom i.MX53 board with LPDDR2 RAM this reduced the suspend power consumption from 200mW to 60mW. Signed-off-by: Martin Fuzzey Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 1 + arch/arm/mach-imx/common.h | 4 + arch/arm/mach-imx/pm-imx5.c | 190 +++++++++++++++++++++++++++++++++++++- arch/arm/mach-imx/suspend-imx53.S | 139 ++++++++++++++++++++++++++++ 4 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/suspend-imx53.S (limited to 'arch/arm/mach-imx/common.h') diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 40df12af5036..799e65a530be 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o ifeq ($(CONFIG_SUSPEND),y) AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o +obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o endif obj-$(CONFIG_SOC_IMX6) += pm-imx6.o diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 1f800b9a63f5..21e4e8697a58 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -116,9 +116,13 @@ int imx_cpu_kill(unsigned int cpu); #ifdef CONFIG_SUSPEND void v7_cpu_resume(void); +void imx53_suspend(void __iomem *ocram_vbase); +extern const u32 imx53_suspend_sz; void imx6_suspend(void __iomem *ocram_vbase); #else static inline void v7_cpu_resume(void) {} +static inline void imx53_suspend(void __iomem *ocram_vbase) {} +static const u32 imx53_suspend_sz; static inline void imx6_suspend(void __iomem *ocram_vbase) {} #endif diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index b04025592d94..a8d00b9c9236 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -13,7 +13,14 @@ #include #include #include + +#include +#include +#include +#include + #include +#include #include #include @@ -49,10 +56,50 @@ */ #define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF +struct imx5_suspend_io_state { + u32 offset; + u32 clear; + u32 set; + u32 saved_value; +}; + struct imx5_pm_data { phys_addr_t ccm_addr; phys_addr_t cortex_addr; phys_addr_t gpc_addr; + phys_addr_t m4if_addr; + phys_addr_t iomuxc_addr; + void (*suspend_asm)(void __iomem *ocram_vbase); + const u32 *suspend_asm_sz; + const struct imx5_suspend_io_state *suspend_io_config; + int suspend_io_count; +}; + +static const struct imx5_suspend_io_state imx53_suspend_io_config[] = { +#define MX53_DSE_HIGHZ_MASK (0x7 << 19) + {.offset = 0x584, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM0 */ + {.offset = 0x594, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM1 */ + {.offset = 0x560, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM2 */ + {.offset = 0x554, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM3 */ + {.offset = 0x574, .clear = MX53_DSE_HIGHZ_MASK}, /* CAS */ + {.offset = 0x588, .clear = MX53_DSE_HIGHZ_MASK}, /* RAS */ + {.offset = 0x578, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_0 */ + {.offset = 0x570, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_1 */ + + {.offset = 0x580, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT0 */ + {.offset = 0x564, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT1 */ + {.offset = 0x57c, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS0 */ + {.offset = 0x590, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS1 */ + {.offset = 0x568, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS2 */ + {.offset = 0x558, .clear = MX53_DSE_HIGHZ_MASK}, /* SDSQ3 */ + {.offset = 0x6f0, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_ADDS */ + {.offset = 0x718, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_BODS */ + {.offset = 0x71c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B1DS */ + {.offset = 0x728, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B2DS */ + {.offset = 0x72c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B3DS */ + + /* Controls the CKE signal which is required to leave self refresh */ + {.offset = 0x720, .clear = MX53_DSE_HIGHZ_MASK, .set = 1 << 19}, /* CTLDS */ }; static const struct imx5_pm_data imx51_pm_data __initconst = { @@ -65,11 +112,35 @@ static const struct imx5_pm_data imx53_pm_data __initconst = { .ccm_addr = 0x53fd4000, .cortex_addr = 0x63fa0000, .gpc_addr = 0x53fd8000, + .m4if_addr = 0x63fd8000, + .iomuxc_addr = 0x53fa8000, + .suspend_asm = &imx53_suspend, + .suspend_asm_sz = &imx53_suspend_sz, + .suspend_io_config = imx53_suspend_io_config, + .suspend_io_count = ARRAY_SIZE(imx53_suspend_io_config), }; +#define MX5_MAX_SUSPEND_IOSTATE ARRAY_SIZE(imx53_suspend_io_config) + +/* + * This structure is for passing necessary data for low level ocram + * suspend code(arch/arm/mach-imx/suspend-imx53.S), if this struct + * definition is changed, the offset definition in that file + * must be also changed accordingly otherwise, the suspend to ocram + * function will be broken! + */ +struct imx5_cpu_suspend_info { + void __iomem *m4if_base; + void __iomem *iomuxc_base; + u32 io_count; + struct imx5_suspend_io_state io_state[MX5_MAX_SUSPEND_IOSTATE]; +} __aligned(8); + static void __iomem *ccm_base; static void __iomem *cortex_base; static void __iomem *gpc_base; +static void __iomem *suspend_ocram_base; +static void (*imx5_suspend_in_ocram_fn)(void __iomem *ocram_vbase); /* * set cpu low power mode before WFI instruction. This function is called @@ -159,8 +230,15 @@ static int mx5_suspend_enter(suspend_state_t state) /*clear the EMPGC0/1 bits */ __raw_writel(0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR); __raw_writel(0, gpc_base + MXC_SRPG_EMPGC1_SRPGCR); + + if (imx5_suspend_in_ocram_fn) + imx5_suspend_in_ocram_fn(suspend_ocram_base); + else + cpu_do_idle(); + + } else { + cpu_do_idle(); } - cpu_do_idle(); /* return registers to default idle state */ mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE); @@ -192,6 +270,111 @@ static void imx5_pm_idle(void) imx5_cpu_do_idle(); } +static int __init imx_suspend_alloc_ocram( + size_t size, + void __iomem **virt_out, + phys_addr_t *phys_out) +{ + struct device_node *node; + struct platform_device *pdev; + struct gen_pool *ocram_pool; + unsigned long ocram_base; + void __iomem *virt; + phys_addr_t phys; + int ret = 0; + + /* Copied from imx6: TODO factorize */ + node = of_find_compatible_node(NULL, NULL, "mmio-sram"); + if (!node) { + pr_warn("%s: failed to find ocram node!\n", __func__); + return -ENODEV; + } + + pdev = of_find_device_by_node(node); + if (!pdev) { + pr_warn("%s: failed to find ocram device!\n", __func__); + ret = -ENODEV; + goto put_node; + } + + ocram_pool = dev_get_gen_pool(&pdev->dev); + if (!ocram_pool) { + pr_warn("%s: ocram pool unavailable!\n", __func__); + ret = -ENODEV; + goto put_node; + } + + ocram_base = gen_pool_alloc(ocram_pool, size); + if (!ocram_base) { + pr_warn("%s: unable to alloc ocram!\n", __func__); + ret = -ENOMEM; + goto put_node; + } + + phys = gen_pool_virt_to_phys(ocram_pool, ocram_base); + virt = __arm_ioremap_exec(phys, size, false); + if (phys_out) + *phys_out = phys; + if (virt_out) + *virt_out = virt; + +put_node: + of_node_put(node); + + return ret; +} + +static int __init imx5_suspend_init(const struct imx5_pm_data *soc_data) +{ + struct imx5_cpu_suspend_info *suspend_info; + int ret; + /* Need this to avoid compile error due to const typeof in fncpy.h */ + void (*suspend_asm)(void __iomem *) = soc_data->suspend_asm; + + if (!suspend_asm) + return 0; + + if (!soc_data->suspend_asm_sz || !*soc_data->suspend_asm_sz) + return -EINVAL; + + ret = imx_suspend_alloc_ocram( + *soc_data->suspend_asm_sz + sizeof(*suspend_info), + &suspend_ocram_base, NULL); + if (ret) + return ret; + + suspend_info = suspend_ocram_base; + + suspend_info->io_count = soc_data->suspend_io_count; + memcpy(suspend_info->io_state, soc_data->suspend_io_config, + sizeof(*suspend_info->io_state) * soc_data->suspend_io_count); + + suspend_info->m4if_base = ioremap(soc_data->m4if_addr, SZ_16K); + if (!suspend_info->m4if_base) { + ret = -ENOMEM; + goto failed_map_m4if; + } + + suspend_info->iomuxc_base = ioremap(soc_data->iomuxc_addr, SZ_16K); + if (!suspend_info->iomuxc_base) { + ret = -ENOMEM; + goto failed_map_iomuxc; + } + + imx5_suspend_in_ocram_fn = fncpy( + suspend_ocram_base + sizeof(*suspend_info), + suspend_asm, + *soc_data->suspend_asm_sz); + + return 0; + +failed_map_iomuxc: + iounmap(suspend_info->m4if_base); + +failed_map_m4if: + return ret; +} + static int __init imx5_pm_common_init(const struct imx5_pm_data *data) { int ret; @@ -218,6 +401,11 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data) if (ret) pr_warn("%s: cpuidle init failed %d\n", __func__, ret); + ret = imx5_suspend_init(data); + if (ret) + pr_warn("%s: No DDR LPM support with suspend %d!\n", + __func__, ret); + suspend_set_ops(&mx5_suspend_ops); return 0; diff --git a/arch/arm/mach-imx/suspend-imx53.S b/arch/arm/mach-imx/suspend-imx53.S new file mode 100644 index 000000000000..5ed078ad110a --- /dev/null +++ b/arch/arm/mach-imx/suspend-imx53.S @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + */ +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include + +#define M4IF_MCR0_OFFSET (0x008C) +#define M4IF_MCR0_FDVFS (0x1 << 11) +#define M4IF_MCR0_FDVACK (0x1 << 27) + + .align 3 + +/* + * ==================== low level suspend ==================== + * + * On entry + * r0: pm_info structure address; + * + * suspend ocram space layout: + * ======================== high address ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx53_suspend code + * PM_INFO structure(imx53_suspend_info) + * ======================== low address ======================= + */ + +/* Offsets of members of struct imx53_suspend_info */ +#define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0 +#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4 +#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8 +#define SUSPEND_INFO_MX53_IO_STATE_OFFSET 0xc + +ENTRY(imx53_suspend) + stmfd sp!, {r4,r5,r6,r7} + + /* Save pad config */ + ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] + cmp r1, #0 + beq skip_pad_conf_1 + + add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET + ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] + +1: + ldr r5, [r2], #12 /* IOMUXC register offset */ + ldr r6, [r3, r5] /* current value */ + str r6, [r2], #4 /* save area */ + subs r1, r1, #1 + bne 1b + +skip_pad_conf_1: + /* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */ + ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET] + ldr r2,[r1, #M4IF_MCR0_OFFSET] + orr r2, r2, #M4IF_MCR0_FDVFS + str r2,[r1, #M4IF_MCR0_OFFSET] + + /* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */ +wait_sr_ack: + ldr r2,[r1, #M4IF_MCR0_OFFSET] + ands r2, r2, #M4IF_MCR0_FDVACK + beq wait_sr_ack + + /* Set pad config */ + ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] + cmp r1, #0 + beq skip_pad_conf_2 + + add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET + ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] + +2: + ldr r5, [r2], #4 /* IOMUXC register offset */ + ldr r6, [r2], #4 /* clear */ + ldr r7, [r3, r5] + bic r7, r7, r6 + ldr r6, [r2], #8 /* set */ + orr r7, r7, r6 + str r7, [r3, r5] + subs r1, r1, #1 + bne 2b + +skip_pad_conf_2: + /* Zzz, enter stop mode */ + wfi + nop + nop + nop + nop + + /* Restore pad config */ + ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] + cmp r1, #0 + beq skip_pad_conf_3 + + add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET + ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] + +3: + ldr r5, [r2], #12 /* IOMUXC register offset */ + ldr r6, [r2], #4 /* saved value */ + str r6, [r3, r5] + subs r1, r1, #1 + bne 3b + +skip_pad_conf_3: + /* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */ + ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET] + ldr r2,[r1, #M4IF_MCR0_OFFSET] + bic r2, r2, #M4IF_MCR0_FDVFS + str r2,[r1, #M4IF_MCR0_OFFSET] + + /* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */ +wait_ar_ack: + ldr r2,[r1, #M4IF_MCR0_OFFSET] + ands r2, r2, #M4IF_MCR0_FDVACK + bne wait_ar_ack + + /* Restore registers */ + ldmfd sp!, {r4,r5,r6,r7} + mov pc, lr + +ENDPROC(imx53_suspend) + +ENTRY(imx53_suspend_sz) + .word . - imx53_suspend -- cgit v1.2.3