DEFINE_SPINLOCK(ddr_freq_lock);
int low_bus_freq_mode;
+int audio_bus_freq_mode;
int high_bus_freq_mode;
int med_bus_freq_mode;
int lp_high_freq;
int lp_med_freq;
+int lp_audio_freq;
unsigned int ddr_low_rate;
unsigned int ddr_med_rate;
unsigned int ddr_normal_rate;
if (low_bus_freq_mode || !low_freq_bus_used())
return;
+ if (audio_bus_freq_mode && lp_audio_freq)
+ return;
+
while (!mutex_trylock(&bus_freq_mutex))
msleep(1);
mutex_unlock(&bus_freq_mutex);
return;
}
- clk_enable(pll3);
-
+ if (audio_bus_freq_mode && lp_audio_freq) {
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
- update_ddr_freq(24000000);
+ clk_enable(pll3);
+ if (lp_audio_freq) {
+ /* Need to ensure that PLL2_PFD_400M is kept ON. */
+ clk_enable(pll2_400);
+ update_ddr_freq(50000000);
+ audio_bus_freq_mode = 1;
+ low_bus_freq_mode = 0;
+ } else {
+ update_ddr_freq(24000000);
+ if (audio_bus_freq_mode)
+ clk_disable(pll2_400);
+ low_bus_freq_mode = 1;
+ audio_bus_freq_mode = 0;
+ }
if (med_bus_freq_mode)
clk_disable(pll2_400);
- low_bus_freq_mode = 1;
high_bus_freq_mode = 0;
med_bus_freq_mode = 0;
update_ddr_freq(ddr_normal_rate);
if (med_bus_freq_mode)
clk_disable(pll2_400);
- low_bus_freq_mode = 0;
high_bus_freq_mode = 1;
med_bus_freq_mode = 0;
} else {
clk_enable(pll2_400);
update_ddr_freq(ddr_med_rate);
- low_bus_freq_mode = 0;
high_bus_freq_mode = 0;
med_bus_freq_mode = 1;
}
+ if (audio_bus_freq_mode)
+ clk_disable(pll2_400);
+ low_bus_freq_mode = 0;
+ audio_bus_freq_mode = 0;
mutex_unlock(&bus_freq_mutex);
clk_disable(pll3);
extern struct cpu_op *(*get_cpu_op)(int *op);
extern int lp_high_freq;
extern int lp_med_freq;
+extern int lp_audio_freq;
void __iomem *apll_base;
static struct clk pll1_sys_main_clk;
#else
.secondary = &mmdc_ch0_axi_clk[0],
#endif
+ .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_ssi2_get_rate(struct clk *clk)
#else
.secondary = &mmdc_ch0_axi_clk[0],
#endif
+ .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_ssi3_get_rate(struct clk *clk)
#else
.secondary = &mmdc_ch0_axi_clk[0],
#endif
+ .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_ldb_di_round_rate(struct clk *clk,
lp_high_freq = 0;
lp_med_freq = 0;
+ lp_audio_freq = 0;
/* Turn OFF all unnecessary PHYs. */
if (cpu_is_mx6q()) {
orr r0, r0, #0xC0000
str r0, [r6, #0x18]
- /* Set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=6 (need to maintain GPT divider). */
+ /* Set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8 (need to maintain GPT divider). */
ldr r0, [r6, #0x14]
ldr r2, =0x3F1C00
bic r0, r0, r2
orr r0, r0, #0x180000
- orr r0, r0, #0x10000
+ orr r0, r0, #0x30000
/* If changing AHB divider remember to change the IPGPER divider too below. */
- orr r0, r0, #0xC00
+ orr r0, r0, #0x1C00
str r0, [r6, #0x14]
wait_div_update_50:
extern int dvfs_core_is_active;
extern int lp_high_freq;
extern int lp_med_freq;
+extern int lp_audio_freq;
+extern int audio_bus_freq_mode;
extern int low_bus_freq_mode;
extern int high_bus_freq_mode;
extern int med_bus_freq_mode;
lp_high_freq++;
else if (clk->flags & AHB_MED_SET_POINT)
lp_med_freq++;
+ else if (clk->flags & AHB_AUDIO_SET_POINT)
+ lp_audio_freq++;
if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
&& (clk_get_usecount(clk) == 0)) {
if (!(clk->flags &
(AHB_HIGH_SET_POINT | AHB_MED_SET_POINT))) {
- if (low_freq_bus_used() && !low_bus_freq_mode)
- set_low_bus_freq();
+ if (low_freq_bus_used()) {
+ if ((clk->flags & AHB_AUDIO_SET_POINT) & !audio_bus_freq_mode)
+ set_low_bus_freq();
+ else if (!low_bus_freq_mode)
+ set_low_bus_freq();
+ }
} else {
if ((clk->flags & AHB_MED_SET_POINT)
&& !med_bus_freq_mode)
lp_high_freq--;
else if (clk->flags & AHB_MED_SET_POINT)
lp_med_freq--;
+ else if (clk->flags & AHB_AUDIO_SET_POINT)
+ lp_audio_freq--;
mutex_lock(&clocks_mutex);
__clk_disable(clk);
/*
- * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc.
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
*
* This program is free software; you can redistribute it and/or
#define CPU_FREQ_TRIG_UPDATE (1 << 3) /* CPUFREQ trig update */
#define AHB_HIGH_SET_POINT (1 << 4) /* Requires max AHB clock */
#define AHB_MED_SET_POINT (1 << 5) /* Requires med AHB clock */
+#define AHB_AUDIO_SET_POINT (1 << 6) /* Requires LOW AHB, but higher DDR clock */
unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref);