aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnson Huang <b20788@freescale.com>2015-08-04 13:48:37 -0400
committerShawn Guo <shawnguo@kernel.org>2015-09-16 20:54:35 -0400
commitee4a5f838c8437484c9387e9ef9256332f07f3dd (patch)
tree29ae88eb6027eddaeaa6f036a0dc98f66281ac6f
parent6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff)
ARM: imx: add suspend/resume support for i.mx6ul
This patch adds suspend function for i.MX6UL, it supports "standby" and "mem" mode, for "standby" mode, SoC will enter STOP mode only, while for "mem" mode, SoC will enter STOP mode and DDR IO will be set to low power mode. As i.MX6UL contains a "Cortex-A7" ARM core which has no PL310, so we need to avoid any PL310 operations during suspend/resume, also, we need to flush Cortex-A7's inernal L2 cache before suspend. Signed-off-by: Anson Huang <b20788@freescale.com>
-rw-r--r--arch/arm/mach-imx/common.h1
-rw-r--r--arch/arm/mach-imx/mach-imx6ul.c2
-rw-r--r--arch/arm/mach-imx/pm-imx6.c46
-rw-r--r--arch/arm/mach-imx/suspend-imx6.S3
4 files changed, 46 insertions, 6 deletions
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 21e4e8697a58..e2d53839fceb 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -131,6 +131,7 @@ void imx6q_pm_init(void);
131void imx6dl_pm_init(void); 131void imx6dl_pm_init(void);
132void imx6sl_pm_init(void); 132void imx6sl_pm_init(void);
133void imx6sx_pm_init(void); 133void imx6sx_pm_init(void);
134void imx6ul_pm_init(void);
134 135
135#ifdef CONFIG_PM 136#ifdef CONFIG_PM
136void imx51_pm_init(void); 137void imx51_pm_init(void);
diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c
index 1b97fe133cef..be832b98b7e5 100644
--- a/arch/arm/mach-imx/mach-imx6ul.c
+++ b/arch/arm/mach-imx/mach-imx6ul.c
@@ -67,6 +67,7 @@ static void __init imx6ul_init_machine(void)
67 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 67 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
68 imx6ul_enet_init(); 68 imx6ul_enet_init();
69 imx_anatop_init(); 69 imx_anatop_init();
70 imx6ul_pm_init();
70} 71}
71 72
72static void __init imx6ul_init_irq(void) 73static void __init imx6ul_init_irq(void)
@@ -74,6 +75,7 @@ static void __init imx6ul_init_irq(void)
74 imx_init_revision_from_anatop(); 75 imx_init_revision_from_anatop();
75 imx_src_init(); 76 imx_src_init();
76 irqchip_init(); 77 irqchip_init();
78 imx6_pm_ccm_init("fsl,imx6ul-ccm");
77} 79}
78 80
79static const char *imx6ul_dt_compat[] __initconst = { 81static const char *imx6ul_dt_compat[] __initconst = {
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 8ff8fc0b261c..4470376af5f8 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -93,6 +93,7 @@ struct imx6_pm_socdata {
93 const char *src_compat; 93 const char *src_compat;
94 const char *iomuxc_compat; 94 const char *iomuxc_compat;
95 const char *gpc_compat; 95 const char *gpc_compat;
96 const char *pl310_compat;
96 const u32 mmdc_io_num; 97 const u32 mmdc_io_num;
97 const u32 *mmdc_io_offset; 98 const u32 *mmdc_io_offset;
98}; 99};
@@ -137,11 +138,19 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = {
137 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */ 138 0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */
138}; 139};
139 140
141static const u32 imx6ul_mmdc_io_offset[] __initconst = {
142 0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */
143 0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */
144 0x280, 0x284, 0x260, 0x264, /* SDQS0~1, SODT0, SODT1 */
145 0x494, 0x4b0, /* MODE_CTL, MODE, */
146};
147
140static const struct imx6_pm_socdata imx6q_pm_data __initconst = { 148static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
141 .mmdc_compat = "fsl,imx6q-mmdc", 149 .mmdc_compat = "fsl,imx6q-mmdc",
142 .src_compat = "fsl,imx6q-src", 150 .src_compat = "fsl,imx6q-src",
143 .iomuxc_compat = "fsl,imx6q-iomuxc", 151 .iomuxc_compat = "fsl,imx6q-iomuxc",
144 .gpc_compat = "fsl,imx6q-gpc", 152 .gpc_compat = "fsl,imx6q-gpc",
153 .pl310_compat = "arm,pl310-cache",
145 .mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset), 154 .mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset),
146 .mmdc_io_offset = imx6q_mmdc_io_offset, 155 .mmdc_io_offset = imx6q_mmdc_io_offset,
147}; 156};
@@ -151,6 +160,7 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
151 .src_compat = "fsl,imx6q-src", 160 .src_compat = "fsl,imx6q-src",
152 .iomuxc_compat = "fsl,imx6dl-iomuxc", 161 .iomuxc_compat = "fsl,imx6dl-iomuxc",
153 .gpc_compat = "fsl,imx6q-gpc", 162 .gpc_compat = "fsl,imx6q-gpc",
163 .pl310_compat = "arm,pl310-cache",
154 .mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset), 164 .mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset),
155 .mmdc_io_offset = imx6dl_mmdc_io_offset, 165 .mmdc_io_offset = imx6dl_mmdc_io_offset,
156}; 166};
@@ -160,6 +170,7 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
160 .src_compat = "fsl,imx6sl-src", 170 .src_compat = "fsl,imx6sl-src",
161 .iomuxc_compat = "fsl,imx6sl-iomuxc", 171 .iomuxc_compat = "fsl,imx6sl-iomuxc",
162 .gpc_compat = "fsl,imx6sl-gpc", 172 .gpc_compat = "fsl,imx6sl-gpc",
173 .pl310_compat = "arm,pl310-cache",
163 .mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset), 174 .mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset),
164 .mmdc_io_offset = imx6sl_mmdc_io_offset, 175 .mmdc_io_offset = imx6sl_mmdc_io_offset,
165}; 176};
@@ -169,10 +180,21 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
169 .src_compat = "fsl,imx6sx-src", 180 .src_compat = "fsl,imx6sx-src",
170 .iomuxc_compat = "fsl,imx6sx-iomuxc", 181 .iomuxc_compat = "fsl,imx6sx-iomuxc",
171 .gpc_compat = "fsl,imx6sx-gpc", 182 .gpc_compat = "fsl,imx6sx-gpc",
183 .pl310_compat = "arm,pl310-cache",
172 .mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset), 184 .mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset),
173 .mmdc_io_offset = imx6sx_mmdc_io_offset, 185 .mmdc_io_offset = imx6sx_mmdc_io_offset,
174}; 186};
175 187
188static const struct imx6_pm_socdata imx6ul_pm_data __initconst = {
189 .mmdc_compat = "fsl,imx6ul-mmdc",
190 .src_compat = "fsl,imx6ul-src",
191 .iomuxc_compat = "fsl,imx6ul-iomuxc",
192 .gpc_compat = "fsl,imx6ul-gpc",
193 .pl310_compat = NULL,
194 .mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset),
195 .mmdc_io_offset = imx6ul_mmdc_io_offset,
196};
197
176/* 198/*
177 * This structure is for passing necessary data for low level ocram 199 * This structure is for passing necessary data for low level ocram
178 * suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct 200 * suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct
@@ -290,7 +312,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
290 val |= BM_CLPCR_SBYOS; 312 val |= BM_CLPCR_SBYOS;
291 if (cpu_is_imx6sl()) 313 if (cpu_is_imx6sl())
292 val |= BM_CLPCR_BYPASS_PMIC_READY; 314 val |= BM_CLPCR_BYPASS_PMIC_READY;
293 if (cpu_is_imx6sl() || cpu_is_imx6sx()) 315 if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul())
294 val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; 316 val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
295 else 317 else
296 val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; 318 val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
@@ -330,6 +352,10 @@ static int imx6q_suspend_finish(unsigned long val)
330 * as we need to float DDR IO. 352 * as we need to float DDR IO.
331 */ 353 */
332 local_flush_tlb_all(); 354 local_flush_tlb_all();
355 /* check if need to flush internal L2 cache */
356 if (!((struct imx6_cpu_pm_info *)
357 suspend_ocram_base)->l2_base.vbase)
358 flush_cache_all();
333 imx6_suspend_in_ocram_fn(suspend_ocram_base); 359 imx6_suspend_in_ocram_fn(suspend_ocram_base);
334 } 360 }
335 361
@@ -470,6 +496,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
470 suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, 496 suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
471 MX6Q_SUSPEND_OCRAM_SIZE, false); 497 MX6Q_SUSPEND_OCRAM_SIZE, false);
472 498
499 memset(suspend_ocram_base, 0, sizeof(*pm_info));
473 pm_info = suspend_ocram_base; 500 pm_info = suspend_ocram_base;
474 pm_info->pbase = ocram_pbase; 501 pm_info->pbase = ocram_pbase;
475 pm_info->resume_addr = virt_to_phys(v7_cpu_resume); 502 pm_info->resume_addr = virt_to_phys(v7_cpu_resume);
@@ -505,11 +532,13 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
505 goto gpc_map_failed; 532 goto gpc_map_failed;
506 } 533 }
507 534
508 ret = imx6_pm_get_base(&pm_info->l2_base, "arm,pl310-cache"); 535 if (socdata->pl310_compat) {
509 if (ret) { 536 ret = imx6_pm_get_base(&pm_info->l2_base, socdata->pl310_compat);
510 pr_warn("%s: failed to get pl310-cache base %d!\n", 537 if (ret) {
511 __func__, ret); 538 pr_warn("%s: failed to get pl310-cache base %d!\n",
512 goto pl310_cache_map_failed; 539 __func__, ret);
540 goto pl310_cache_map_failed;
541 }
513 } 542 }
514 543
515 pm_info->ddr_type = imx_mmdc_get_ddr_type(); 544 pm_info->ddr_type = imx_mmdc_get_ddr_type();
@@ -610,3 +639,8 @@ void __init imx6sx_pm_init(void)
610{ 639{
611 imx6_pm_common_init(&imx6sx_pm_data); 640 imx6_pm_common_init(&imx6sx_pm_data);
612} 641}
642
643void __init imx6ul_pm_init(void)
644{
645 imx6_pm_common_init(&imx6ul_pm_data);
646}
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index b99987b023fa..76ee2ceec8d5 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -79,12 +79,15 @@
79 /* sync L2 cache to drain L2's buffers to DRAM. */ 79 /* sync L2 cache to drain L2's buffers to DRAM. */
80#ifdef CONFIG_CACHE_L2X0 80#ifdef CONFIG_CACHE_L2X0
81 ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] 81 ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
82 teq r11, #0
83 beq 6f
82 mov r6, #0x0 84 mov r6, #0x0
83 str r6, [r11, #L2X0_CACHE_SYNC] 85 str r6, [r11, #L2X0_CACHE_SYNC]
841: 861:
85 ldr r6, [r11, #L2X0_CACHE_SYNC] 87 ldr r6, [r11, #L2X0_CACHE_SYNC]
86 ands r6, r6, #0x1 88 ands r6, r6, #0x1
87 bne 1b 89 bne 1b
906:
88#endif 91#endif
89 92
90 .endm 93 .endm