aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2013-09-20 11:36:00 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:05:43 -0400
commit129237a8ba4f89084464ffbe323f8dfe7de3d9c7 (patch)
treed54ae84774c7dd9c39357f738adf58b5a8e2e7b1
parentfaae41bf9ff800696c7f2e6761157d34065cef3c (diff)
ENGR00281017 [MX6SL]Low power IDLE mode optimizations
Added a new bus freq mode - ultra_low_bus_freq_mode. In this mode the ARM is the only bus master that is active and the system is already in low power idle mode. And when ARM executes WFI in this mode, we do some aggressive power savings techinques like: 1. Drop DDR freq to 1MHz 2. Drop AHB freq to 3MHz 3. Float the DDR IO pads 4. If all PLLs are in bypass (which should be the case), do some analog power saving options like reducing the OSC-bias current, turning off the regular bandgap, disabling the regular 2P5, enabling the weak 2p5 etc. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
-rw-r--r--arch/arm/boot/dts/imx6sl.dtsi5
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/busfreq-imx6.c141
-rw-r--r--arch/arm/mach-imx/busfreq_lpddr2.c9
-rw-r--r--arch/arm/mach-imx/clk-imx6sl.c17
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sl.c91
-rw-r--r--arch/arm/mach-imx/imx6sl_wfi.S584
-rw-r--r--arch/arm/mach-imx/lpddr2_freq_imx6.S2
8 files changed, 800 insertions, 51 deletions
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index c64207a6fa58..f03f2e1a92c6 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -104,10 +104,11 @@
104 <&clks IMX6SL_CLK_PLL1_SYS>, <&clks IMX6SL_CLK_PERIPH2>, 104 <&clks IMX6SL_CLK_PLL1_SYS>, <&clks IMX6SL_CLK_PERIPH2>,
105 <&clks IMX6SL_CLK_AHB>, <&clks IMX6SL_CLK_OCRAM>, 105 <&clks IMX6SL_CLK_AHB>, <&clks IMX6SL_CLK_OCRAM>,
106 <&clks IMX6SL_CLK_PLL1_SW>, <&clks IMX6SL_CLK_PRE_PERIPH2_SEL>, 106 <&clks IMX6SL_CLK_PLL1_SW>, <&clks IMX6SL_CLK_PRE_PERIPH2_SEL>,
107 <&clks IMX6SL_CLK_PERIPH2_CLK2_SEL>, <&clks IMX6SL_CLK_PERIPH2_CLK2>; 107 <&clks IMX6SL_CLK_PERIPH2_CLK2_SEL>, <&clks IMX6SL_CLK_PERIPH2_CLK2>,
108 <&clks IMX6SL_CLK_STEP>;
108 clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", 109 clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph",
109 "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", "pll1_sys", "periph2", "ahb", "ocram", "pll1_sw", 110 "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", "pll1_sys", "periph2", "ahb", "ocram", "pll1_sw",
110 "periph2_pre", "periph2_clk2_sel", "periph2_clk2"; 111 "periph2_pre", "periph2_clk2_sel", "periph2_clk2", "step";
111 fsl,max_ddr_freq = <400000000>; 112 fsl,max_ddr_freq = <400000000>;
112 }; 113 };
113 114
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 50887de73cde..87a323b0f0f8 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -108,7 +108,7 @@ obj-$(CONFIG_PM) += pm-imx6.o headsmp.o suspend-imx6.o
108ifeq ($(CONFIG_ARM_IMX6_CPUFREQ),y) 108ifeq ($(CONFIG_ARM_IMX6_CPUFREQ),y)
109obj-y += busfreq-imx6.o 109obj-y += busfreq-imx6.o
110obj-$(CONFIG_SOC_IMX6Q) += ddr3_freq_imx6.o busfreq_ddr3.o 110obj-$(CONFIG_SOC_IMX6Q) += ddr3_freq_imx6.o busfreq_ddr3.o
111obj-$(CONFIG_SOC_IMX6SL) += lpddr2_freq_imx6.o busfreq_lpddr2.o 111obj-$(CONFIG_SOC_IMX6SL) += lpddr2_freq_imx6.o busfreq_lpddr2.o imx6sl_wfi.o
112endif 112endif
113 113
114 114
diff --git a/arch/arm/mach-imx/busfreq-imx6.c b/arch/arm/mach-imx/busfreq-imx6.c
index 58ecef05e95a..a32b1d25fbc1 100644
--- a/arch/arm/mach-imx/busfreq-imx6.c
+++ b/arch/arm/mach-imx/busfreq-imx6.c
@@ -54,6 +54,7 @@ int high_bus_freq_mode;
54int med_bus_freq_mode; 54int med_bus_freq_mode;
55int audio_bus_freq_mode; 55int audio_bus_freq_mode;
56int low_bus_freq_mode; 56int low_bus_freq_mode;
57int ultra_low_bus_freq_mode;
57unsigned int ddr_med_rate; 58unsigned int ddr_med_rate;
58unsigned int ddr_normal_rate; 59unsigned int ddr_normal_rate;
59 60
@@ -62,7 +63,7 @@ static struct device *busfreq_dev;
62static int busfreq_suspended; 63static int busfreq_suspended;
63static u32 org_arm_rate; 64static u32 org_arm_rate;
64static int bus_freq_scaling_is_active; 65static int bus_freq_scaling_is_active;
65static int high_bus_count, med_bus_count, audio_bus_count; 66static int high_bus_count, med_bus_count, audio_bus_count, low_bus_count;
66static unsigned int ddr_low_rate; 67static unsigned int ddr_low_rate;
67 68
68extern int init_mmdc_lpddr2_settings(struct platform_device *dev); 69extern int init_mmdc_lpddr2_settings(struct platform_device *dev);
@@ -91,6 +92,7 @@ static struct clk *pll1_sw_clk;
91static struct clk *periph2_pre_clk; 92static struct clk *periph2_pre_clk;
92static struct clk *periph2_clk2_sel; 93static struct clk *periph2_clk2_sel;
93static struct clk *periph2_clk2; 94static struct clk *periph2_clk2;
95static struct clk *step_clk;
94 96
95static u32 pll2_org_rate; 97static u32 pll2_org_rate;
96static struct delayed_work low_bus_freq_handler; 98static struct delayed_work low_bus_freq_handler;
@@ -120,7 +122,7 @@ static void enter_lpm_imx6sl(void)
120 clk_set_parent(periph2_pre_clk, pll2_200); 122 clk_set_parent(periph2_pre_clk, pll2_200);
121 clk_set_parent(periph2_clk, periph2_pre_clk); 123 clk_set_parent(periph2_clk, periph2_pre_clk);
122 124
123 if (low_bus_freq_mode) { 125 if (low_bus_freq_mode || ultra_low_bus_freq_mode) {
124 /* 126 /*
125 * Swtich ARM to run off PLL2_PFD2_400MHz 127 * Swtich ARM to run off PLL2_PFD2_400MHz
126 * since DDR is anyway at 100MHz. 128 * since DDR is anyway at 100MHz.
@@ -133,46 +135,73 @@ static void enter_lpm_imx6sl(void)
133 clk_set_rate(cpu_clk, org_arm_rate); 135 clk_set_rate(cpu_clk, org_arm_rate);
134 } 136 }
135 low_bus_freq_mode = 0; 137 low_bus_freq_mode = 0;
138 ultra_low_bus_freq_mode = 0;
136 audio_bus_freq_mode = 1; 139 audio_bus_freq_mode = 1;
137 } else { 140 } else {
138 u32 arm_div, pll1_rate; 141 u32 arm_div, pll1_rate;
139 org_arm_rate = clk_get_rate(cpu_clk); 142 org_arm_rate = clk_get_rate(cpu_clk);
140 /* 143 if (low_bus_freq_mode && low_bus_count == 0) {
141 * Set DDR to 24MHz. 144 /*
142 * Since we are going to bypass PLL2, we need 145 * We are already in DDR @ 24MHz state, but
143 * to move ARM clk off PLL2_PFD2 to PLL1. 146 * no one but ARM needs the DDR. In this case,
144 * Make sure the PLL1 is running at the lowest possible freq. 147 * we can lower the DDR freq to 1MHz when ARM
145 */ 148 * enters WFI in this state. Keep track of this state.
146 clk_set_rate(pll1_sys, clk_round_rate(pll1_sys, org_arm_rate)); 149 */
147 pll1_rate = clk_get_rate(pll1_sys); 150 ultra_low_bus_freq_mode = 1;
148 arm_div = pll1_rate / org_arm_rate + 1; 151 low_bus_freq_mode = 0;
149 /* Ensure ARM CLK is lower before changing the parent. */ 152 audio_bus_freq_mode = 0;
150 clk_set_rate(cpu_clk, org_arm_rate / arm_div); 153 } else {
151 /* Now set the ARM clk parent to PLL1_SYS. */ 154 if (!ultra_low_bus_freq_mode && !low_bus_freq_mode) {
152 clk_set_parent(pll1_sw_clk, pll1_sys); 155 /*
153 156 * Set DDR to 24MHz.
154 /* Now set DDR to 24MHz. */ 157 * Since we are going to bypass PLL2,
155 spin_lock_irqsave(&freq_lock, flags); 158 * we need to move ARM clk off PLL2_PFD2
156 update_lpddr2_freq(LPAPM_CLK); 159 * to PLL1. Make sure the PLL1 is running
157 spin_unlock_irqrestore(&freq_lock, flags); 160 * at the lowest possible freq.
158 161 */
159 /* 162 clk_set_rate(pll1_sys,
160 * Fix the clock tree in kernel. 163 clk_round_rate(pll1_sys, org_arm_rate));
161 * Make sure PLL2 rate is updated as it gets 164 pll1_rate = clk_get_rate(pll1_sys);
162 * bypassed in the DDR freq change code. 165 arm_div = pll1_rate / org_arm_rate + 1;
163 */ 166 /*
164 clk_set_rate(pll2, LPAPM_CLK); 167 * Ensure ARM CLK is lower before
165 clk_set_parent(periph2_clk2_sel, pll2); 168 * changing the parent.
166 clk_set_parent(periph2_clk, periph2_clk2_sel); 169 */
167 170 clk_set_rate(cpu_clk, org_arm_rate / arm_div);
168 low_bus_freq_mode = 1; 171 /* Now set the ARM clk parent to PLL1_SYS. */
169 audio_bus_freq_mode = 0; 172 clk_set_parent(pll1_sw_clk, pll1_sys);
173
174 /* Now set DDR to 24MHz. */
175 spin_lock_irqsave(&freq_lock, flags);
176 update_lpddr2_freq(LPAPM_CLK);
177 spin_unlock_irqrestore(&freq_lock, flags);
178
179 /*
180 * Fix the clock tree in kernel.
181 * Make sure PLL2 rate is updated as it gets
182 * bypassed in the DDR freq change code.
183 */
184 clk_set_rate(pll2, LPAPM_CLK);
185 clk_set_parent(periph2_clk2_sel, pll2);
186 clk_set_parent(periph2_clk, periph2_clk2_sel);
187
188 }
189 if (low_bus_count == 0) {
190 ultra_low_bus_freq_mode = 1;
191 low_bus_freq_mode = 0;
192 } else {
193 ultra_low_bus_freq_mode = 0;
194 low_bus_freq_mode = 1;
195 }
196 audio_bus_freq_mode = 0;
197 }
170 } 198 }
171} 199}
172 200
173static void exit_lpm_imx6sl(void) 201static void exit_lpm_imx6sl(void)
174{ 202{
175 unsigned long flags; 203 unsigned long flags;
204
176 spin_lock_irqsave(&freq_lock, flags); 205 spin_lock_irqsave(&freq_lock, flags);
177 /* Change DDR freq in IRAM. */ 206 /* Change DDR freq in IRAM. */
178 update_lpddr2_freq(ddr_normal_rate); 207 update_lpddr2_freq(ddr_normal_rate);
@@ -197,10 +226,12 @@ static void exit_lpm_imx6sl(void)
197 clk_set_rate(ocram_clk, LPAPM_CLK / 2); 226 clk_set_rate(ocram_clk, LPAPM_CLK / 2);
198 clk_set_parent(periph_clk, periph_pre_clk); 227 clk_set_parent(periph_clk, periph_pre_clk);
199 228
200 if (low_bus_freq_mode) { 229 if (low_bus_freq_mode || ultra_low_bus_freq_mode) {
201 /* Move ARM from PLL1_SW_CLK to PLL2_400. */ 230 /* Move ARM from PLL1_SW_CLK to PLL2_400. */
202 clk_set_parent(pll1_sw_clk, pll2_400); 231 clk_set_parent(step_clk, pll2_400);
232 clk_set_parent(pll1_sw_clk, step_clk);
203 clk_set_rate(cpu_clk, org_arm_rate); 233 clk_set_rate(cpu_clk, org_arm_rate);
234 ultra_low_bus_freq_mode = 0;
204 } 235 }
205} 236}
206 237
@@ -287,7 +318,7 @@ static void reduce_bus_freq_handler(struct work_struct *work)
287 * This mode will be activated only when none of the modules that 318 * This mode will be activated only when none of the modules that
288 * need a higher DDR or AHB frequency are active. 319 * need a higher DDR or AHB frequency are active.
289 */ 320 */
290int set_low_bus_freq(int low_bus_mode) 321int set_low_bus_freq(void)
291{ 322{
292 if (busfreq_suspended) 323 if (busfreq_suspended)
293 return 0; 324 return 0;
@@ -417,6 +448,8 @@ void request_bus_freq(enum bus_freq_mode mode)
417 med_bus_count++; 448 med_bus_count++;
418 else if (mode == BUS_FREQ_AUDIO) 449 else if (mode == BUS_FREQ_AUDIO)
419 audio_bus_count++; 450 audio_bus_count++;
451 else if (mode == BUS_FREQ_LOW)
452 low_bus_count++;
420 453
421 if (busfreq_suspended || !bus_freq_scaling_initialized || 454 if (busfreq_suspended || !bus_freq_scaling_initialized ||
422 !bus_freq_scaling_is_active) { 455 !bus_freq_scaling_is_active) {
@@ -448,7 +481,7 @@ void request_bus_freq(enum bus_freq_mode mode)
448 } 481 }
449 if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) && 482 if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) &&
450 (!med_bus_freq_mode) && (!audio_bus_freq_mode)) { 483 (!med_bus_freq_mode) && (!audio_bus_freq_mode)) {
451 set_low_bus_freq(1); 484 set_low_bus_freq();
452 mutex_unlock(&bus_freq_mutex); 485 mutex_unlock(&bus_freq_mutex);
453 return; 486 return;
454 } 487 }
@@ -485,6 +518,14 @@ void release_bus_freq(enum bus_freq_mode mode)
485 return; 518 return;
486 } 519 }
487 audio_bus_count--; 520 audio_bus_count--;
521 } else if (mode == BUS_FREQ_LOW) {
522 if (low_bus_count == 0) {
523 dev_err(busfreq_dev, "low bus count mismatch!\n");
524 dump_stack();
525 mutex_unlock(&bus_freq_mutex);
526 return;
527 }
528 low_bus_count--;
488 } 529 }
489 530
490 if (busfreq_suspended || !bus_freq_scaling_initialized || 531 if (busfreq_suspended || !bus_freq_scaling_initialized ||
@@ -503,13 +544,24 @@ void release_bus_freq(enum bus_freq_mode mode)
503 544
504 if ((!audio_bus_freq_mode) && (high_bus_count == 0) && 545 if ((!audio_bus_freq_mode) && (high_bus_count == 0) &&
505 (med_bus_count == 0) && (audio_bus_count != 0)) { 546 (med_bus_count == 0) && (audio_bus_count != 0)) {
506 set_low_bus_freq(1); 547 set_low_bus_freq();
507 mutex_unlock(&bus_freq_mutex); 548 mutex_unlock(&bus_freq_mutex);
508 return; 549 return;
509 } 550 }
510 if ((!low_bus_freq_mode) && (high_bus_count == 0) && 551 if ((!low_bus_freq_mode) && (high_bus_count == 0) &&
511 (med_bus_count == 0) && (audio_bus_count == 0)) 552 (med_bus_count == 0) && (audio_bus_count == 0) &&
512 set_low_bus_freq(0); 553 (low_bus_count != 0)) {
554 set_low_bus_freq();
555 mutex_unlock(&bus_freq_mutex);
556 return;
557 }
558 if ((!ultra_low_bus_freq_mode) && (high_bus_count == 0) &&
559 (med_bus_count == 0) && (audio_bus_count == 0) &&
560 (low_bus_count == 0)) {
561 set_low_bus_freq();
562 mutex_unlock(&bus_freq_mutex);
563 return;
564 }
513 565
514 mutex_unlock(&bus_freq_mutex); 566 mutex_unlock(&bus_freq_mutex);
515 return; 567 return;
@@ -521,7 +573,7 @@ static void bus_freq_daemon_handler(struct work_struct *work)
521 mutex_lock(&bus_freq_mutex); 573 mutex_lock(&bus_freq_mutex);
522 if ((!low_bus_freq_mode) && (high_bus_count == 0) && 574 if ((!low_bus_freq_mode) && (high_bus_count == 0) &&
523 (med_bus_count == 0) && (audio_bus_count == 0)) 575 (med_bus_count == 0) && (audio_bus_count == 0))
524 set_low_bus_freq(0); 576 set_low_bus_freq();
525 mutex_unlock(&bus_freq_mutex); 577 mutex_unlock(&bus_freq_mutex);
526} 578}
527 579
@@ -744,6 +796,14 @@ static int busfreq_probe(struct platform_device *pdev)
744 return PTR_ERR(periph2_clk2_sel); 796 return PTR_ERR(periph2_clk2_sel);
745 } 797 }
746 798
799 step_clk = devm_clk_get(&pdev->dev, "step");
800 if (IS_ERR(step_clk)) {
801 dev_err(busfreq_dev,
802 "%s: failed to get step_clk\n",
803 __func__);
804 return PTR_ERR(periph2_clk2_sel);
805 }
806
747 } 807 }
748 808
749 err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr); 809 err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
@@ -763,6 +823,7 @@ static int busfreq_probe(struct platform_device *pdev)
763 med_bus_freq_mode = 0; 823 med_bus_freq_mode = 0;
764 low_bus_freq_mode = 0; 824 low_bus_freq_mode = 0;
765 audio_bus_freq_mode = 0; 825 audio_bus_freq_mode = 0;
826 ultra_low_bus_freq_mode = 0;
766 827
767 bus_freq_scaling_is_active = 1; 828 bus_freq_scaling_is_active = 1;
768 bus_freq_scaling_initialized = 1; 829 bus_freq_scaling_initialized = 1;
diff --git a/arch/arm/mach-imx/busfreq_lpddr2.c b/arch/arm/mach-imx/busfreq_lpddr2.c
index f15b8290669c..900d7bdf469f 100644
--- a/arch/arm/mach-imx/busfreq_lpddr2.c
+++ b/arch/arm/mach-imx/busfreq_lpddr2.c
@@ -50,14 +50,15 @@ static void __iomem *l2_base;
50static struct device *busfreq_dev; 50static struct device *busfreq_dev;
51static void *ddr_freq_change_iram_base; 51static void *ddr_freq_change_iram_base;
52static int curr_ddr_rate; 52static int curr_ddr_rate;
53static unsigned long reg_addrs[4]; 53
54unsigned long reg_addrs[4];
54 55
55void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode, 56void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode,
56 void *iram_addr) = NULL; 57 void *iram_addr) = NULL;
57 58
58extern unsigned int ddr_normal_rate; 59extern unsigned int ddr_normal_rate;
59extern int low_bus_freq_mode; 60extern int low_bus_freq_mode;
60extern int audio_bus_freq_mode; 61extern int ultra_low_bus_freq_mode;
61extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode, 62extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode,
62 void *iram_addr); 63 void *iram_addr);
63 64
@@ -71,7 +72,9 @@ int update_lpddr2_freq(int ddr_rate)
71 if (ddr_rate == curr_ddr_rate) 72 if (ddr_rate == curr_ddr_rate)
72 return 0; 73 return 0;
73 74
74 mx6_change_lpddr2_freq(ddr_rate, low_bus_freq_mode, reg_addrs); 75 mx6_change_lpddr2_freq(ddr_rate,
76 (low_bus_freq_mode | ultra_low_bus_freq_mode),
77 reg_addrs);
75 78
76 curr_ddr_rate = ddr_rate; 79 curr_ddr_rate = ddr_rate;
77 80
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
index 36a5d00c10f2..9ee6a168c705 100644
--- a/arch/arm/mach-imx/clk-imx6sl.c
+++ b/arch/arm/mach-imx/clk-imx6sl.c
@@ -74,6 +74,7 @@ static struct clk_onecell_data clk_data;
74static u32 cur_arm_podf; 74static u32 cur_arm_podf;
75 75
76extern int low_bus_freq_mode; 76extern int low_bus_freq_mode;
77extern int audio_bus_freq_mode;
77 78
78/* 79/*
79 * On MX6SL, need to ensure that the ARM:IPG clock ratio is maintained 80 * On MX6SL, need to ensure that the ARM:IPG clock ratio is maintained
@@ -103,6 +104,15 @@ void imx6sl_set_wait_clk(bool enter)
103 clks[IMX6SL_CLK_OSC]); 104 clks[IMX6SL_CLK_OSC]);
104 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], 105 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW],
105 clks[IMX6SL_CLK_STEP]); 106 clks[IMX6SL_CLK_STEP]);
107 } else if (audio_bus_freq_mode) {
108 /*
109 * In this mode ARM is from PLL2_PFD2 (396MHz),
110 * but IPG is at 12MHz. Need to switch ARM to run
111 * from the bypassed PLL1 clocks so that we can run
112 * ARM at 24MHz.
113 */
114 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW],
115 clks[IMX6SL_CLK_PLL1_SYS]);
106 } 116 }
107 new_parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); 117 new_parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]);
108 wait_podf = (new_parent_rate + max_arm_wait_clk - 1) / 118 wait_podf = (new_parent_rate + max_arm_wait_clk - 1) /
@@ -112,7 +122,12 @@ void imx6sl_set_wait_clk(bool enter)
112 } else { 122 } else {
113 if (low_bus_freq_mode) 123 if (low_bus_freq_mode)
114 /* Move ARM back to PLL1. */ 124 /* Move ARM back to PLL1. */
115 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], clks[IMX6SL_CLK_PLL1_SYS]); 125 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW],
126 clks[IMX6SL_CLK_PLL1_SYS]);
127 else if (audio_bus_freq_mode)
128 /* Move ARM back to PLL2_PFD2 via STEP_CLK. */
129 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW],
130 clks[IMX6SL_CLK_STEP]);
116 parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); 131 parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]);
117 clk_set_rate(clks[IMX6SL_CLK_ARM], parent_rate / cur_arm_podf); 132 clk_set_rate(clks[IMX6SL_CLK_ARM], parent_rate / cur_arm_podf);
118 } 133 }
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
index 7d8ed7c90043..841b65749c5b 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sl.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -7,21 +7,48 @@
7 */ 7 */
8 8
9#include <linux/cpuidle.h> 9#include <linux/cpuidle.h>
10#include <linux/genalloc.h>
10#include <linux/module.h> 11#include <linux/module.h>
11#include <linux/of.h> 12#include <linux/of.h>
13#include <linux/of_address.h>
14#include <linux/of_device.h>
12#include <asm/cpuidle.h> 15#include <asm/cpuidle.h>
16#include <asm/fncpy.h>
17#include <asm/mach/map.h>
13#include <asm/proc-fns.h> 18#include <asm/proc-fns.h>
14 19
15#include "common.h" 20#include "common.h"
16#include "cpuidle.h" 21#include "cpuidle.h"
17 22
23extern u32 low_bus_freq_mode;
24extern u32 ultra_low_bus_freq_mode;
25extern unsigned long reg_addrs[];
26extern void imx6sl_low_power_wfi(void);
27
28static void __iomem *iomux_base;
29static void *wfi_iram_base;
30
31void (*imx6sl_wfi_in_iram_fn)(void *wfi_iram_base,
32 void *iomux_addr, void *regs_addr) = NULL;
33
34#define WFI_IN_IRAM_SIZE 0x1000
35
18static int imx6sl_enter_wait(struct cpuidle_device *dev, 36static int imx6sl_enter_wait(struct cpuidle_device *dev,
19 struct cpuidle_driver *drv, int index) 37 struct cpuidle_driver *drv, int index)
20{ 38{
21 imx6_set_lpm(WAIT_UNCLOCKED); 39 imx6_set_lpm(WAIT_UNCLOCKED);
22 imx6sl_set_wait_clk(true); 40 if (ultra_low_bus_freq_mode)
23 cpu_do_idle(); 41 /*
24 imx6sl_set_wait_clk(false); 42 * Run WFI code from IRAM.
43 * Drop the DDR freq to 1MHz and AHB to 3MHz
44 * Also float DDR IO pads.
45 */
46 imx6sl_wfi_in_iram_fn(wfi_iram_base, iomux_base, reg_addrs);
47 else {
48 imx6sl_set_wait_clk(true);
49 cpu_do_idle();
50 imx6sl_set_wait_clk(false);
51 }
25 imx6_set_lpm(WAIT_CLOCKED); 52 imx6_set_lpm(WAIT_CLOCKED);
26 53
27 return index; 54 return index;
@@ -50,5 +77,63 @@ static struct cpuidle_driver imx6sl_cpuidle_driver = {
50 77
51int __init imx6sl_cpuidle_init(void) 78int __init imx6sl_cpuidle_init(void)
52{ 79{
80 struct platform_device *ocram_dev;
81 unsigned int iram_paddr;
82 struct device_node *node;
83 struct gen_pool *iram_pool;
84
85 node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-iomuxc");
86 if (!node) {
87 pr_err("failed to find imx6sl-iomuxc device tree data!\n");
88 return -EINVAL;
89 }
90 iomux_base = of_iomap(node, 0);
91 WARN(!iomux_base, "unable to map iomux registers\n");
92
93 node = NULL;
94 node = of_find_compatible_node(NULL, NULL, "mmio-sram");
95 if (!node) {
96 pr_err("%s: failed to find ocram node\n",
97 __func__);
98 return -EINVAL;
99 }
100
101 ocram_dev = of_find_device_by_node(node);
102 if (!ocram_dev) {
103 pr_err("failed to find ocram device!\n");
104 return -EINVAL;
105 }
106
107 iram_pool = dev_get_gen_pool(&ocram_dev->dev);
108 if (!iram_pool) {
109 pr_err("iram pool unavailable!\n");
110 return -EINVAL;
111 }
112 /*
113 * Allocate IRAM memory when ARM executes WFI in
114 * ultra_low_power_mode.
115 */
116 wfi_iram_base = (void *)gen_pool_alloc(iram_pool,
117 WFI_IN_IRAM_SIZE);
118 if (!wfi_iram_base) {
119 pr_err("Cannot alloc iram for wfi code!\n");
120 return -ENOMEM;
121 }
122
123 iram_paddr = gen_pool_virt_to_phys(iram_pool,
124 (unsigned long)wfi_iram_base);
125 /*
126 * Need to remap the area here since we want
127 * the memory region to be executable.
128 */
129 wfi_iram_base = __arm_ioremap(iram_paddr,
130 WFI_IN_IRAM_SIZE,
131 MT_MEMORY_NONCACHED);
132 if (!wfi_iram_base)
133 pr_err("wfi_ram_base NOT remapped\n");
134
135 imx6sl_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base,
136 &imx6sl_low_power_wfi, WFI_IN_IRAM_SIZE);
137
53 return cpuidle_register(&imx6sl_cpuidle_driver, NULL); 138 return cpuidle_register(&imx6sl_cpuidle_driver, NULL);
54} 139}
diff --git a/arch/arm/mach-imx/imx6sl_wfi.S b/arch/arm/mach-imx/imx6sl_wfi.S
new file mode 100644
index 000000000000..2fe8bae1d968
--- /dev/null
+++ b/arch/arm/mach-imx/imx6sl_wfi.S
@@ -0,0 +1,584 @@
1/*
2 * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include <linux/linkage.h>
20#define IRAM_WAIT_SIZE (1 << 11)
21
22 .macro sl_ddr_io_save
23
24 ldr r4, [r1, #0x30c] /* DRAM_DQM0 */
25 ldr r5, [r1, #0x310] /* DRAM_DQM1 */
26 ldr r6, [r1, #0x314] /* DRAM_DQM2 */
27 ldr r7, [r1, #0x318] /* DRAM_DQM3 */
28 stmfd r9!, {r4-r7}
29
30 ldr r4, [r1, #0x5c4] /* GPR_B0DS */
31 ldr r5, [r1, #0x5cc] /* GPR_B1DS */
32 ldr r6, [r1, #0x5d4] /* GPR_B2DS */
33 ldr r7, [r1, #0x5d8] /* GPR_B3DS */
34 stmfd r9!, {r4-r7}
35
36 ldr r4, [r1, #0x300] /* DRAM_CAS */
37 ldr r5, [r1, #0x31c] /* DRAM_RAS */
38 ldr r6, [r1, #0x338] /* DRAM_SDCLK_0 */
39 ldr r7, [r1, #0x5ac] /* GPR_ADDS*/
40 stmfd r9!, {r4-r7}
41
42 ldr r4, [r1, #0x5b0] /* DDRMODE_CTL */
43 ldr r5, [r1, #0x5c0] /* DDRMODE */
44 ldr r6, [r1, #0x33c] /* DRAM_SODT0*/
45 ldr r7, [r1, #0x340] /* DRAM_SODT1*/
46 stmfd r9!, {r4-r7}
47
48 ldr r4, [r1, #0x330] /* DRAM_SDCKE0 */
49 ldr r5, [r1, #0x334] /* DRAM_SDCKE1 */
50 ldr r6, [r1, #0x320] /* DRAM_RESET */
51 stmfd r9!, {r4-r6}
52
53 .endm
54
55 .macro sl_ddr_io_restore
56
57 /*
58 * r9 points to IRAM stack.
59 * r1 points to IOMUX base address.
60 * r8 points to MMDC base address.
61 */
62 ldmea r9!, {r4-r7}
63 str r4, [r1, #0x30c] /* DRAM_DQM0 */
64 str r5, [r1, #0x310] /* DRAM_DQM1 */
65 str r6, [r1, #0x314] /* DRAM_DQM2 */
66 str r7, [r1, #0x318] /* DRAM_DQM3 */
67
68 ldmea r9!, {r4-r7}
69 str r4, [r1, #0x5c4] /* GPR_B0DS */
70 str r5, [r1, #0x5cc] /* GPR_B1DS */
71 str r6, [r1, #0x5d4] /* GPR_B2DS */
72 str r7, [r1, #0x5d8] /* GPR_B3DS */
73
74 ldmea r9!, {r4-r7}
75 str r4, [r1, #0x300] /* DRAM_CAS */
76 str r5, [r1, #0x31c] /* DRAM_RAS */
77 str r6, [r1, #0x338] /* DRAM_SDCLK_0 */
78 str r7, [r1, #0x5ac] /* GPR_ADDS*/
79
80 ldmea r9!, {r4-r7}
81 str r4, [r1, #0x5b0] /* DDRMODE_CTL */
82 str r5, [r1, #0x5c0] /* DDRMODE */
83 str r6, [r1, #0x33c] /* DRAM_SODT0*/
84 str r7, [r1, #0x340] /* DRAM_SODT1*/
85
86 ldmea r9!, {r4-r6}
87 str r4, [r1, #0x330] /* DRAM_SDCKE0 */
88 str r5, [r1, #0x334] /* DRAM_SDCKE1 */
89 str r6, [r1, #0x320] /* DRAM_RESET */
90
91 /*
92 * Need to reset the FIFO to avoid MMDC lockup
93 * caused because of floating/changing the
94 * configuration of many DDR IO pads.
95 */
96 ldr r7, =0x83c
97 ldr r6, [r8, r7]
98 orr r6, r6, #0x80000000
99 str r6, [r8, r7]
100fifo_reset1_wait:
101 ldr r6, [r8, r7]
102 and r6, r6, #0x80000000
103 cmp r6, #0
104 bne fifo_reset1_wait
105
106 /* reset FIFO a second time */
107 ldr r6, [r8, r7]
108 orr r6, r6, #0x80000000
109 str r6, [r8, r7]
110fifo_reset2_wait:
111 ldr r6, [r8, r7]
112 and r6, r6, #0x80000000
113 cmp r6, #0
114 bne fifo_reset2_wait
115
116 .endm
117
118 .macro sl_ddr_io_set_lpm
119
120 mov r4, #0
121 str r4, [r1, #0x30c] /* DRAM_DQM0 */
122 str r4, [r1, #0x310] /* DRAM_DQM1 */
123 str r4, [r1, #0x314] /* DRAM_DQM2 */
124 str r4, [r1, #0x318] /* DRAM_DQM3 */
125
126 str r4, [r1, #0x5c4] /* GPR_B0DS */
127 str r4, [r1, #0x5cc] /* GPR_B1DS */
128 str r4, [r1, #0x5d4] /* GPR_B2DS */
129 str r4, [r1, #0x5d8] /* GPR_B3DS */
130
131 str r4, [r1, #0x300] /* DRAM_CAS */
132 str r4, [r1, #0x31c] /* DRAM_RAS */
133 str r4, [r1, #0x338] /* DRAM_SDCLK_0 */
134 str r4, [r1, #0x5ac] /* GPR_ADDS*/
135
136 str r4, [r1, #0x5b0] /* DDRMODE_CTL */
137 str r4, [r1, #0x5c0] /* DDRMODE */
138 str r4, [r1, #0x33c] /* DRAM_SODT0*/
139 str r4, [r1, #0x340] /* DRAM_SODT1*/
140
141 mov r4, #0x80000
142 str r4, [r1, #0x320] /* DRAM_RESET */
143 mov r4, #0x1000
144 str r4, [r1, #0x330] /* DRAM_SDCKE0 */
145 str r4, [r1, #0x334] /* DRAM_SDCKE1 */
146
147 .endm
148
149/*
150 * imx6sl_low_power_wfi
151 *
152 * Idle the processor (eg, wait for interrupt).
153 * Make sure DDR is in self-refresh.
154 * IRQs are already disabled.
155 * r0: WFI IRAMcode base address.
156 * r1: IOMUX base address
157 * r2: Base address of CCM, ANATOP and MMDC
158 */
159 .align 3
160ENTRY(imx6sl_low_power_wfi)
161
162 push {r4-r10}
163
164mx6sl_lpm_wfi:
165 mov r4,r2
166 /* Get the IRAM data storage address. */
167 mov r10, r0
168 mov r9, r0 /* get suspend_iram_base */
169 add r9, r9, #IRAM_WAIT_SIZE
170
171 /* Anatop Base address in r3. */
172 ldr r3, [r4]
173 /* CCM Base Address in r2 */
174 ldr r2, [r4, #0x4]
175 /* MMDC Base Address in r8 */
176 ldr r8, [r4, #0x8]
177 /* L2 Base Address in r7 */
178 ldr r7, [r4, #0xC]
179
180 ldr r6, [r8]
181 ldr r6, [r3]
182 ldr r6, [r2]
183 ldr r6, [r1]
184
185 /* Store the original ARM PODF. */
186 ldr r0, [r2, #0x10]
187
188 /* Drain all the L1 buffers. */
189 dsb
190
191#ifdef CONFIG_CACHE_L2X0
192 /*
193 * Need to make sure the buffers in L2 are drained.
194 * Performing a sync operation does this.
195 */
196 mov r6, #0x0
197 str r6, [r7, #0x730]
198#endif
199
200 /*
201 * The second dsb might be needed to keep cache sync (device write)
202 * ordering with the memory accesses before it.
203 */
204 dsb
205 isb
206
207 /* Save the DDR IO state. */
208 sl_ddr_io_save
209
210 /* Disable Automatic power savings. */
211 ldr r6, [r8, #0x404]
212 orr r6, r6, #0x01
213 str r6, [r8, #0x404]
214
215 /* Make the DDR explicitly enter self-refresh. */
216 ldr r6, [r8, #0x404]
217 orr r6, r6, #0x200000
218 str r6, [r8, #0x404]
219
220poll_dvfs_set_1:
221 ldr r6, [r8, #0x404]
222 and r6, r6, #0x2000000
223 cmp r6, #0x2000000
224 bne poll_dvfs_set_1
225
226 /* set SBS step-by-step mode */
227 ldr r6, [r8, #0x410]
228 orr r6, r6, #0x100
229 str r6, [r8, #0x410]
230
231 /*
232 * Now set DDR rate to 1MHz.
233 * DDR is from bypassed PLL2 on periph2_clk2 path.
234 * Set the periph2_clk2_podf to divide by 8.
235 */
236 ldr r6, [r2, #0x14]
237 orr r6, r6, #0x07
238 str r6, [r2, #0x14]
239
240 /* Now set MMDC PODF to divide by 3. */
241 ldr r6, [r2, #0x14]
242 bic r6, r6, #0x38
243 orr r6, r6, #0x10
244 str r6, [r2, #0x14]
245
246 /* Loop till podf is accepted. */
247mmdc_podf:
248 ldr r6, [r2, #0x48]
249 cmp r6, #0x0
250 bne mmdc_podf
251
252 /* Set the DDR IO in LPM state. */
253 sl_ddr_io_set_lpm
254
255 /*
256 * Check if none of the PLLs are
257 * locked, except PLL1 which will get
258 * bypassed below.
259 * We should not be here if PLL2 is not
260 * bypassed.
261 */
262 ldr r7, =1
263 /* USB1 PLL3 */
264 ldr r6, [r3, #0x10]
265 and r6, r6, #0x80000000
266 cmp r6, #0x80000000
267 beq no_analog_saving
268
269 /* USB2 PLL7 */
270 ldr r6, [r3, #0x20]
271 and r6, r6, #0x80000000
272 cmp r6, #0x80000000
273 beq no_analog_saving
274
275 /* Audio PLL4 */
276 ldr r6, [r3, #0x70]
277 and r6, r6, #0x80000000
278 cmp r6, #0x80000000
279 beq no_analog_saving
280
281 /* Video PLL5 */
282 ldr r6, [r3, #0xA0]
283 and r6, r6, #0x80000000
284 cmp r6, #0x80000000
285 beq no_analog_saving
286
287 /* ENET PLL8 */
288 ldr r6, [r3, #0xE0]
289 and r6, r6, #0x80000000
290 cmp r6, #0x80000000
291 beq no_analog_saving
292
293 b cont
294
295no_analog_saving:
296 ldr r7, =0
297
298cont:
299 /* Set the AHB to 3MHz. AXI to 3MHz. */
300 ldr r9, [r2, #0x14]
301 mov r6, r9
302 orr r6, r6, #0x1c00
303 orr r6, r6, #0x70000
304 str r6, [r2, #0x14]
305
306 /* Loop till podf is accepted. */
307ahb_podf:
308 ldr r6, [r2, #0x48]
309 cmp r6, #0x0
310 bne podf_loop
311
312 /*
313 * Now set ARM to 24MHz.
314 * Move ARM to be sourced from STEP_CLK
315 * after setting STEP_CLK to 24MHz.
316 */
317 ldr r6, [r2, #0xc]
318 bic r6, r6, #0x100
319 str r6, [r2, #0x0c]
320 /* Now PLL1_SW_CLK to step_clk. */
321 ldr r6, [r2, #0x0c]
322 orr r6, r6, #0x4
323 str r6, [r2, #0x0c]
324
325 /* Bypass PLL1 and power it down. */
326 ldr r6, =(1 << 16)
327 orr r6, r6, #0x1000
328 str r6, [r3, #0x04]
329
330 /*
331 * Set the ARM PODF to divide by 8.
332 * IPG is at 1.5MHz here, we need ARM to
333 * run at the 12:5 ratio (WAIT mode issue).
334 */
335 ldr r6, =0x7
336 str r6, [r2, #0x10]
337
338 /* Loop till podf is accepted. */
339podf_loop:
340 ldr r6, [r2, #0x48]
341 cmp r6, #0x0
342 bne podf_loop
343
344 /*
345 * Check if we can save some
346 * power in the Analog section.
347 */
348 cmp r7, #0x1
349 bne do_wfi
350
351 /* Disable 1p1 brown out. */
352 ldr r6, [r3, #0x110]
353 bic r6, r6, #0x2
354 str r6, [r3, #0x110]
355
356 /* Enable the weak 2P5 */
357 ldr r6, [r3, #0x130]
358 orr r6, r6, #0x40000
359 str r6, [r3, #0x130]
360
361 /* Disable main 2p5. */
362 ldr r6, [r3, #0x130]
363 bic r6, r6, #0x1
364 str r6, [r3, #0x130]
365
366 /*
367 * Set the OSC bias current to -37.5%
368 * to drop the power on VDDHIGH.
369 */
370 ldr r6, [r3, #0x150]
371 orr r6, r6, #0xC000
372 str r6, [r3, #0x150]
373
374 /* Enable low power bandgap */
375 ldr r6, [r3, #0x260]
376 orr r6, r6, #0x20
377 str r6, [r3, #0x260]
378
379 /*
380 * Turn off the bias current
381 * from the regular bandgap.
382 */
383 ldr r6, [r3, #0x260]
384 orr r6, r6, #0x80
385 str r6, [r3, #0x260]
386
387 /*
388 * Clear the REFTOP_SELFBIASOFF,
389 * self-bias circuit of the band gap.
390 * Per RM, should be cleared when
391 * band gap is powered down.
392 */
393 ldr r6, [r3, #0x150]
394 bic r6, r6, #0x8
395 str r6, [r3, #0x150]
396
397 /* Power down the regular bandgap. */
398 ldr r6, [r3, #0x150]
399 orr r6, r6, #0x1
400 str r6, [r3, #0x150]
401
402do_wfi:
403 /* Now do WFI. */
404 wfi
405
406 /* Set original ARM PODF back. */
407 str r0, [r2, #0x10]
408
409 /* Loop till podf is accepted. */
410podf_loop1:
411 ldr r6, [r2, #0x48]
412 cmp r6, #0x0
413 bne podf_loop1
414
415 /*
416 * Check if powered down
417 * analog components.
418 */
419 cmp r7, #0x1
420 bne skip_analog_restore
421
422 /* Power up the regular bandgap. */
423 ldr r6, [r3, #0x150]
424 bic r6, r6, #0x1
425 str r6, [r3, #0x150]
426
427 /*
428 * Turn on the bias current
429 * from the regular bandgap.
430 */
431 ldr r6, [r3, #0x260]
432 bic r6, r6, #0x80
433 str r6, [r3, #0x260]
434
435 /* Disable the low power bandgap */
436 ldr r6, [r3, #0x260]
437 bic r6, r6, #0x20
438 str r6, [r3, #0x260]
439
440 /*
441 * Set the OSC bias current to max
442 * value for normal operation.
443 */
444 ldr r6, [r3, #0x150]
445 bic r6, r6, #0xC000
446 str r6, [r3, #0x150]
447
448 /* Enable main 2p5. */
449 ldr r6, [r3, #0x130]
450 orr r6, r6, #0x1
451 str r6, [r3, #0x130]
452
453 /* Ensure the 2P5 is up. */
454loop_2p5:
455 ldr r6, [r3, #0x130]
456 and r6, r6, #0x20000
457 cmp r6, #0x20000
458 bne loop_2p5
459
460 /* Disable the weak 2P5 */
461 ldr r6, [r3, #0x130]
462 bic r6, r6, #0x40000
463 str r6, [r3, #0x130]
464
465 /* Enable 1p1 brown out. */
466 ldr r6, [r3, #0x110]
467 orr r6, r6, #0x2
468 str r6, [r3, #0x110]
469
470skip_analog_restore:
471
472 /* Power up PLL1 and un-bypass it. */
473 ldr r6, =(1 << 12)
474 str r6, [r3, #0x08]
475
476 /* Wait for PLL1 to relock. */
477wait_for_pll_lock:
478 ldr r6, [r3, #0x0]
479 and r6, r6, #0x80000000
480 cmp r6, #0x80000000
481 bne wait_for_pll_lock
482
483 ldr r6, =(1 << 16)
484 str r6, [r3, #0x08]
485
486 /* Set PLL1_sw_clk back to PLL1. */
487 ldr r6, [r2, #0x0c]
488 bic r6, r6, #0x4
489 str r6, [r2, #0xc]
490
491 /* Restore AHB/AXI back. */
492 str r9, [r2, #0x14]
493
494 /* Loop till podf is accepted. */
495ahb_podf1:
496 ldr r6, [r2, #0x48]
497 cmp r6, #0x0
498 bne podf_loop1
499
500wfi_restore:
501 /* get suspend_iram_base */
502 mov r9, r10
503 add r9, r9, #IRAM_WAIT_SIZE
504
505 /* Restore the DDR IO before exiting self-refresh. */
506 sl_ddr_io_restore
507
508 /*
509 * Set MMDC back to 24MHz.
510 * Set periph2_clk2_podf to divide by 1
511 * Now set MMDC PODF to divide by 1.
512 */
513 ldr r6, [r2, #0x14]
514 bic r6, r6, #0x3f
515 str r6, [r2, #0x14]
516
517mmdc_podf1:
518 ldr r6, [r2, #0x48]
519 cmp r6, #0x0
520 bne mmdc_podf1
521
522 /* clear DVFS - exit from self refresh mode */
523 ldr r6, [r8, #0x404]
524 bic r6, r6, #0x200000
525 str r6, [r8, #0x404]
526
527poll_dvfs_clear_1:
528 ldr r6, [r8, #0x404]
529 and r6, r6, #0x2000000
530 cmp r6, #0x2000000
531 beq poll_dvfs_clear_1
532
533 /*
534 * Add these nops so that the
535 * prefetcher will not try to get
536 * any instructions from DDR.
537 * The prefetch depth is about 23
538 * on A9, so adding 25 nops.
539 */
540 nop
541 nop
542 nop
543 nop
544 nop
545
546 nop
547 nop
548 nop
549 nop
550 nop
551
552 nop
553 nop
554 nop
555 nop
556 nop
557
558 nop
559 nop
560 nop
561 nop
562 nop
563
564 nop
565 nop
566 nop
567 nop
568 nop
569
570 /* Enable Automatic power savings. */
571 ldr r6, [r8, #0x404]
572 bic r6, r6, #0x01
573 str r6, [r8, #0x404]
574
575 /* clear SBS - unblock DDR accesses */
576 ldr r6, [r8, #0x410]
577 bic r6, r6, #0x100
578 str r6, [r8, #0x410]
579
580
581 pop {r4-r10}
582
583 /* Restore registers */
584 mov pc, lr
diff --git a/arch/arm/mach-imx/lpddr2_freq_imx6.S b/arch/arm/mach-imx/lpddr2_freq_imx6.S
index 975582ec2468..a126f110b0d3 100644
--- a/arch/arm/mach-imx/lpddr2_freq_imx6.S
+++ b/arch/arm/mach-imx/lpddr2_freq_imx6.S
@@ -341,7 +341,7 @@ force_measure1:
341 * r1: low_bus_freq_mode flag 341 * r1: low_bus_freq_mode flag
342 * r2: Pointer to array containing addresses of registers. 342 * r2: Pointer to array containing addresses of registers.
343 */ 343 */
344 .align 8 344 .align 3
345ENTRY(mx6_lpddr2_freq_change) 345ENTRY(mx6_lpddr2_freq_change)
346 346
347 push {r4-r10} 347 push {r4-r10}