aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2013-11-13 15:03:35 -0500
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:47:14 -0400
commitfdb2a0eefc98f7b9d24d9b965b4a6b7e5830d5c1 (patch)
tree9cbb19106a20d6b3ea608710692a360593a6bc69
parent8dfdc91887fc4ff52181875ef44a425cf2e8959e (diff)
ENGR00288123 [iMX6SL] Add low power audio support
Add support for low power audio playback: 1. SSI2 is sourced from PLL4 2. Extern_audio_clk is sourced from pll4 3. PLL4 is in bypass mode during audio playback (based on freq requested by extern_audio_clk and ssi2 clk) 4. DDR is at 100MHz, AHB is at 24MHz. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
-rw-r--r--arch/arm/mach-imx/busfreq-imx6.c15
-rw-r--r--arch/arm/mach-imx/clk-imx6sl.c31
-rw-r--r--arch/arm/mach-imx/clk-pllv3.c86
3 files changed, 109 insertions, 23 deletions
diff --git a/arch/arm/mach-imx/busfreq-imx6.c b/arch/arm/mach-imx/busfreq-imx6.c
index 142a0cc0228a..eddc5a0245a6 100644
--- a/arch/arm/mach-imx/busfreq-imx6.c
+++ b/arch/arm/mach-imx/busfreq-imx6.c
@@ -130,7 +130,8 @@ static void enter_lpm_imx6sl(void)
130 * Swtich ARM to run off PLL2_PFD2_400MHz 130 * Swtich ARM to run off PLL2_PFD2_400MHz
131 * since DDR is anyway at 100MHz. 131 * since DDR is anyway at 100MHz.
132 */ 132 */
133 clk_set_parent(pll1_sw_clk, pll2_400); 133 clk_set_parent(step_clk, pll2_400);
134 clk_set_parent(pll1_sw_clk, step_clk);
134 /* 135 /*
135 * Ensure that the clock will be 136 * Ensure that the clock will be
136 * at original speed. 137 * at original speed.
@@ -174,6 +175,15 @@ static void enter_lpm_imx6sl(void)
174 /* Now set the ARM clk parent to PLL1_SYS. */ 175 /* Now set the ARM clk parent to PLL1_SYS. */
175 clk_set_parent(pll1_sw_clk, pll1_sys); 176 clk_set_parent(pll1_sw_clk, pll1_sys);
176 177
178 /*
179 * Set STEP_CLK back to OSC to save power and
180 * also to maintain the parent.The WFI iram code
181 * will switch step_clk to osc, but the clock API
182 * is not aware of the change and when a new request
183 * to change the step_clk parent to pll2_pfd2_400M
184 * is requested sometime later, the change is ignored.
185 */
186 clk_set_parent(step_clk, osc_clk);
177 /* Now set DDR to 24MHz. */ 187 /* Now set DDR to 24MHz. */
178 spin_lock_irqsave(&freq_lock, flags); 188 spin_lock_irqsave(&freq_lock, flags);
179 update_lpddr2_freq(LPAPM_CLK); 189 update_lpddr2_freq(LPAPM_CLK);
@@ -336,7 +346,7 @@ int set_low_bus_freq(void)
336 * low bus freq mode to audio bus freq mode. 346 * low bus freq mode to audio bus freq mode.
337 * If so, the change needs to be done immediately. 347 * If so, the change needs to be done immediately.
338 */ 348 */
339 if (audio_bus_count && low_bus_freq_mode) 349 if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode))
340 reduce_bus_freq(); 350 reduce_bus_freq();
341 else 351 else
342 /* 352 /*
@@ -465,7 +475,6 @@ void request_bus_freq(enum bus_freq_mode mode)
465 mutex_unlock(&bus_freq_mutex); 475 mutex_unlock(&bus_freq_mutex);
466 return; 476 return;
467 } 477 }
468
469 cancel_delayed_work_sync(&low_bus_freq_handler); 478 cancel_delayed_work_sync(&low_bus_freq_handler);
470 479
471 if (cpu_is_imx6dl()) { 480 if (cpu_is_imx6dl()) {
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
index 7ff93fa2e84f..8210649fe4b3 100644
--- a/arch/arm/mach-imx/clk-imx6sl.c
+++ b/arch/arm/mach-imx/clk-imx6sl.c
@@ -21,6 +21,7 @@
21#define PFD2_CLK_GATE (1 << 23) 21#define PFD2_CLK_GATE (1 << 23)
22#define PFD3_CLK_GATE (1 << 31) 22#define PFD3_CLK_GATE (1 << 31)
23#define CCDR_CH0_HS_BYP 17 23#define CCDR_CH0_HS_BYP 17
24#define OSC_RATE 24000000
24 25
25#define CCM_CCGR_OFFSET(index) (index * 2) 26#define CCM_CCGR_OFFSET(index) (index * 2)
26 27
@@ -88,6 +89,7 @@ static struct clk_div_table video_div_table[] = {
88static struct clk *clks[IMX6SL_CLK_CLK_END]; 89static struct clk *clks[IMX6SL_CLK_CLK_END];
89static struct clk_onecell_data clk_data; 90static struct clk_onecell_data clk_data;
90static u32 cur_arm_podf; 91static u32 cur_arm_podf;
92static u32 pll1_org_rate;
91 93
92extern int low_bus_freq_mode; 94extern int low_bus_freq_mode;
93extern int audio_bus_freq_mode; 95extern int audio_bus_freq_mode;
@@ -104,7 +106,8 @@ void imx6sl_set_wait_clk(bool enter)
104 u32 parent_rate; 106 u32 parent_rate;
105 107
106 if (enter) { 108 if (enter) {
107 u32 wait_podf, new_parent_rate; 109 u32 wait_podf;
110 u32 new_parent_rate = OSC_RATE;
108 u32 ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]); 111 u32 ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]);
109 u32 max_arm_wait_clk = (12 * ipg_rate) / 5; 112 u32 max_arm_wait_clk = (12 * ipg_rate) / 5;
110 parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); 113 parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]);
@@ -127,10 +130,12 @@ void imx6sl_set_wait_clk(bool enter)
127 * from the bypassed PLL1 clocks so that we can run 130 * from the bypassed PLL1 clocks so that we can run
128 * ARM at 24MHz. 131 * ARM at 24MHz.
129 */ 132 */
130 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], 133 pll1_org_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SYS]);
131 clks[IMX6SL_CLK_PLL1_SYS]); 134 /* Ensure PLL1 is at 24MHz. */
132 } 135 clk_set_rate(clks[IMX6SL_CLK_PLL1_SYS], OSC_RATE);
133 new_parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); 136 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], clks[IMX6SL_CLK_PLL1_SYS]);
137 } else
138 new_parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]);
134 wait_podf = (new_parent_rate + max_arm_wait_clk - 1) / 139 wait_podf = (new_parent_rate + max_arm_wait_clk - 1) /
135 max_arm_wait_clk; 140 max_arm_wait_clk;
136 141
@@ -140,10 +145,11 @@ void imx6sl_set_wait_clk(bool enter)
140 /* Move ARM back to PLL1. */ 145 /* Move ARM back to PLL1. */
141 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], 146 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW],
142 clks[IMX6SL_CLK_PLL1_SYS]); 147 clks[IMX6SL_CLK_PLL1_SYS]);
143 else if (audio_bus_freq_mode) 148 else if (audio_bus_freq_mode) {
144 /* Move ARM back to PLL2_PFD2 via STEP_CLK. */ 149 /* Move ARM back to PLL2_PFD2 via STEP_CLK. */
145 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], 150 clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], clks[IMX6SL_CLK_STEP]);
146 clks[IMX6SL_CLK_STEP]); 151 clk_set_rate(clks[IMX6SL_CLK_PLL1_SYS], pll1_org_rate);
152 }
147 parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); 153 parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]);
148 clk_set_rate(clks[IMX6SL_CLK_ARM], parent_rate / cur_arm_podf); 154 clk_set_rate(clks[IMX6SL_CLK_ARM], parent_rate / cur_arm_podf);
149 } 155 }
@@ -274,7 +280,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
274 clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux_flags("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels), CLK_SET_RATE_PARENT); 280 clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux_flags("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels), CLK_SET_RATE_PARENT);
275 clks[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); 281 clks[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
276 clks[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); 282 clks[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
277 clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); 283 clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux_flags("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels), CLK_SET_RATE_PARENT);
278 clks[IMX6SL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); 284 clks[IMX6SL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
279 clks[IMX6SL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); 285 clks[IMX6SL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
280 286
@@ -452,9 +458,16 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
452 /* Audio clocks */ 458 /* Audio clocks */
453 clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]); 459 clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
454 460
461 /* set extern_audio to be sourced from PLL4/audio PLL */
462 clk_set_parent(clks[IMX6SL_CLK_EXTERN_AUDIO_SEL], clks[IMX6SL_CLK_PLL4_AUDIO_DIV]);
455 /* set extern_audio to 24MHz */ 463 /* set extern_audio to 24MHz */
464 clk_set_rate(clks[IMX6SL_CLK_PLL4_AUDIO], 24000000);
456 clk_set_rate(clks[IMX6SL_CLK_EXTERN_AUDIO], 24000000); 465 clk_set_rate(clks[IMX6SL_CLK_EXTERN_AUDIO], 24000000);
457 466
467 /* set SSI2 parent to PLL4 */
468 clk_set_parent(clks[IMX6SL_CLK_SSI2_SEL], clks[IMX6SL_CLK_PLL4_AUDIO_DIV]);
469 clk_set_rate(clks[IMX6SL_CLK_SSI2], 24000000);
470
458 /* set perclk to source from OSC 24MHz */ 471 /* set perclk to source from OSC 24MHz */
459 clk_set_parent(clks[IMX6SL_CLK_PERCLK_SEL], clks[IMX6SL_CLK_OSC]); 472 clk_set_parent(clks[IMX6SL_CLK_PERCLK_SEL], clks[IMX6SL_CLK_OSC]);
460 473
diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
index ab0e48f57829..f187052d639d 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/arch/arm/mach-imx/clk-pllv3.c
@@ -45,6 +45,7 @@ struct clk_pllv3 {
45 bool powerup_set; 45 bool powerup_set;
46 bool always_on; 46 bool always_on;
47 u32 div_mask; 47 u32 div_mask;
48 u32 rate_req;
48}; 49};
49 50
50#define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw) 51#define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw)
@@ -105,7 +106,8 @@ static int clk_pllv3_enable(struct clk_hw *hw)
105 struct clk_pllv3 *pll = to_clk_pllv3(hw); 106 struct clk_pllv3 *pll = to_clk_pllv3(hw);
106 u32 val; 107 u32 val;
107 108
108 clk_pllv3_power_up_down(hw, true); 109 if (pll->rate_req != BYPASS_RATE)
110 clk_pllv3_power_up_down(hw, true);
109 111
110 val = readl_relaxed(pll->base); 112 val = readl_relaxed(pll->base);
111 val |= BM_PLL_ENABLE; 113 val |= BM_PLL_ENABLE;
@@ -124,7 +126,8 @@ static void clk_pllv3_disable(struct clk_hw *hw)
124 val &= ~BM_PLL_ENABLE; 126 val &= ~BM_PLL_ENABLE;
125 writel_relaxed(val, pll->base); 127 writel_relaxed(val, pll->base);
126 128
127 clk_pllv3_power_up_down(hw, false); 129 if (pll->rate_req != BYPASS_RATE)
130 clk_pllv3_power_up_down(hw, false);
128} 131}
129 132
130static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw, 133static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw,
@@ -135,7 +138,7 @@ static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw,
135 u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK; 138 u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK;
136 u32 rate; 139 u32 rate;
137 140
138 if (bypass) 141 if (pll->rate_req == BYPASS_RATE && bypass)
139 rate = BYPASS_RATE; 142 rate = BYPASS_RATE;
140 else 143 else
141 rate = (div == 1) ? parent_rate * 22 : parent_rate * 20; 144 rate = (div == 1) ? parent_rate * 22 : parent_rate * 20;
@@ -147,11 +150,9 @@ static long clk_pllv3_round_rate(struct clk_hw *hw, unsigned long rate,
147 unsigned long *prate) 150 unsigned long *prate)
148{ 151{
149 unsigned long parent_rate = *prate; 152 unsigned long parent_rate = *prate;
150 struct clk_pllv3 *pll = to_clk_pllv3(hw);
151 u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK;
152 153
153 /* If the PLL is bypassed, its rate is 24MHz. */ 154 /* If the PLL is bypassed, its rate is 24MHz. */
154 if (bypass) 155 if (rate == BYPASS_RATE)
155 return BYPASS_RATE; 156 return BYPASS_RATE;
156 157
157 return (rate >= parent_rate * 22) ? parent_rate * 22 : 158 return (rate >= parent_rate * 22) ? parent_rate * 22 :
@@ -163,12 +164,22 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate,
163{ 164{
164 struct clk_pllv3 *pll = to_clk_pllv3(hw); 165 struct clk_pllv3 *pll = to_clk_pllv3(hw);
165 u32 val, div; 166 u32 val, div;
166 u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK; 167
168 pll->rate_req = rate;
169 val = readl_relaxed(pll->base);
167 170
168 /* If the PLL is bypassed, its rate is 24MHz. */ 171 /* If the PLL is bypassed, its rate is 24MHz. */
169 if (bypass) 172 if (rate == BYPASS_RATE) {
170 return 0; 173 /* Set the bypass bit. */
174 val |= BM_PLL_BYPASS;
175 if (pll->powerup_set)
176 val |= BM_PLL_POWER;
177 else
178 val &= ~BM_PLL_POWER;
179 writel_relaxed(val, pll->base);
171 180
181 return 0;
182 }
172 if (rate == parent_rate * 22) 183 if (rate == parent_rate * 22)
173 div = 1; 184 div = 1;
174 else if (rate == parent_rate * 20) 185 else if (rate == parent_rate * 20)
@@ -197,6 +208,10 @@ static unsigned long clk_pllv3_sys_recalc_rate(struct clk_hw *hw,
197{ 208{
198 struct clk_pllv3 *pll = to_clk_pllv3(hw); 209 struct clk_pllv3 *pll = to_clk_pllv3(hw);
199 u32 div = readl_relaxed(pll->base) & pll->div_mask; 210 u32 div = readl_relaxed(pll->base) & pll->div_mask;
211 u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK;
212
213 if (pll->rate_req == BYPASS_RATE && bypass)
214 return BYPASS_RATE;
200 215
201 return parent_rate * div / 2; 216 return parent_rate * div / 2;
202} 217}
@@ -209,6 +224,9 @@ static long clk_pllv3_sys_round_rate(struct clk_hw *hw, unsigned long rate,
209 unsigned long max_rate = parent_rate * 108 / 2; 224 unsigned long max_rate = parent_rate * 108 / 2;
210 u32 div; 225 u32 div;
211 226
227 if (rate == BYPASS_RATE)
228 return BYPASS_RATE;
229
212 if (rate > max_rate) 230 if (rate > max_rate)
213 rate = max_rate; 231 rate = max_rate;
214 else if (rate < min_rate) 232 else if (rate < min_rate)
@@ -226,9 +244,26 @@ static int clk_pllv3_sys_set_rate(struct clk_hw *hw, unsigned long rate,
226 unsigned long max_rate = parent_rate * 108 / 2; 244 unsigned long max_rate = parent_rate * 108 / 2;
227 u32 val, div; 245 u32 val, div;
228 246
229 if (rate < min_rate || rate > max_rate) 247 if (rate != BYPASS_RATE && (rate < min_rate || rate > max_rate))
230 return -EINVAL; 248 return -EINVAL;
231 249
250 pll->rate_req = rate;
251 val = readl_relaxed(pll->base);
252
253 if (rate == BYPASS_RATE) {
254 /*
255 * Set the PLL in bypass mode if rate requested is
256 * BYPASS_RATE.
257 */
258 val |= BM_PLL_BYPASS;
259 /* Power down the PLL. */
260 if (pll->powerup_set)
261 val &= ~BM_PLL_POWER;
262 else
263 val |= BM_PLL_POWER;
264 writel_relaxed(val, pll->base);
265 return 0;
266 }
232 div = rate * 2 / parent_rate; 267 div = rate * 2 / parent_rate;
233 val = readl_relaxed(pll->base); 268 val = readl_relaxed(pll->base);
234 val &= ~pll->div_mask; 269 val &= ~pll->div_mask;
@@ -253,6 +288,10 @@ static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw,
253 u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET); 288 u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET);
254 u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET); 289 u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET);
255 u32 div = readl_relaxed(pll->base) & pll->div_mask; 290 u32 div = readl_relaxed(pll->base) & pll->div_mask;
291 u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK;
292
293 if (pll->rate_req == BYPASS_RATE && bypass)
294 return BYPASS_RATE;
256 295
257 return (parent_rate * div) + ((parent_rate / mfd) * mfn); 296 return (parent_rate * div) + ((parent_rate / mfd) * mfn);
258} 297}
@@ -267,6 +306,9 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate,
267 u32 mfn, mfd = 1000000; 306 u32 mfn, mfd = 1000000;
268 s64 temp64; 307 s64 temp64;
269 308
309 if (rate == BYPASS_RATE)
310 return BYPASS_RATE;
311
270 if (rate > max_rate) 312 if (rate > max_rate)
271 rate = max_rate; 313 rate = max_rate;
272 else if (rate < min_rate) 314 else if (rate < min_rate)
@@ -291,9 +333,31 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
291 u32 mfn, mfd = 1000000; 333 u32 mfn, mfd = 1000000;
292 s64 temp64; 334 s64 temp64;
293 335
294 if (rate < min_rate || rate > max_rate) 336 if (rate != BYPASS_RATE && (rate < min_rate || rate > max_rate))
295 return -EINVAL; 337 return -EINVAL;
296 338
339 pll->rate_req = rate;
340 val = readl_relaxed(pll->base);
341
342 if (rate == BYPASS_RATE) {
343 /*
344 * Set the PLL in bypass mode if rate requested is
345 * BYPASS_RATE.
346 */
347 /* Bypass the PLL */
348 val |= BM_PLL_BYPASS;
349 /* Power down the PLL. */
350 if (pll->powerup_set)
351 val &= ~BM_PLL_POWER;
352 else
353 val |= BM_PLL_POWER;
354 writel_relaxed(val, pll->base);
355 return 0;
356 }
357 /* Else clear the bypass bit. */
358 val &= ~BM_PLL_BYPASS;
359 writel_relaxed(val, pll->base);
360
297 div = rate / parent_rate; 361 div = rate / parent_rate;
298 temp64 = (u64) (rate - div * parent_rate); 362 temp64 = (u64) (rate - div * parent_rate);
299 temp64 *= mfd; 363 temp64 *= mfd;