summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx6/clock.c
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2012-05-16 12:43:27 -0500
committerRanjani Vaidyanathan <ra5478@freescale.com>2012-05-18 12:53:30 -0500
commit4fd3caa4fd1545208ce616d7707096a5ce9d5932 (patch)
tree0904cc8092104c6bfed484a348adf5afa5a89c80 /arch/arm/mach-mx6/clock.c
parent5dbb4f855f7b890f6f861c441f6f81246e3a4dfa (diff)
ENGR00209617 MX6x - Add WAIT mode workaround
To avoid the ARM from accepting an interrupt in the dangerous window, reduce the ARM core freq just before the sytem is about to enter WAIT state. Reduce the ARM freq so as to maintain 12:5 ARM_CLK to IPG ratio. Use the ARM_PODF to drop the frequency. In a multicore case the frequency is dropped only when all the 4 cores are going to be in WFI. In case of single core environment, its easy to drop the ARM core freq just before WFI since there is no need to identify the state of the other cores. Some other points to note: 1. If "mem_clk_on" is added to the command line, the memory clocks will not be gated in WAIT mode. This will increase the system IDLE power. This mode is valid only on MX6sl, MX6DQ TO1.2 and MX6DL TO1.1. 2. In case the IPG clk is too low (for ex 50MHz) and ARM is at 1GHz, we cannot match the 12:5 ratio using ARM_PODF only. In this case, donot clock gate the memories in WAIT mode (available on MX6SL, MXDQ TO1.2 and MXDL TO1.1). For MXDQ TO1.1 and MX6DL TO1.0, disable system wide WAIT entry in this case. In STOP mode, always ensure that the memory clocks are gated, else power impact will be significant. WAIT mode is enabled by default with this commit. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
Diffstat (limited to 'arch/arm/mach-mx6/clock.c')
-rw-r--r--arch/arm/mach-mx6/clock.c50
1 files changed, 48 insertions, 2 deletions
diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c
index 20fa5505c0d9..465bd2313329 100644
--- a/arch/arm/mach-mx6/clock.c
+++ b/arch/arm/mach-mx6/clock.c
@@ -47,7 +47,11 @@ extern struct regulator *cpu_regulator;
extern struct cpu_op *(*get_cpu_op)(int *op);
extern int lp_high_freq;
extern int lp_med_freq;
+extern int wait_mode_arm_podf;
extern int lp_audio_freq;
+extern int cur_arm_podf;
+extern bool arm_mem_clked_in_wait;
+extern bool enable_wait_mode;
void __iomem *apll_base;
static struct clk ipu1_clk;
@@ -69,6 +73,7 @@ static struct clk apbh_dma_clk;
static struct clk openvg_axi_clk;
static struct clk enfc_clk;
static struct clk usdhc3_clk;
+static struct clk ipg_clk;
static struct cpu_op *cpu_op_tbl;
static int cpu_op_nr;
@@ -516,8 +521,21 @@ static int _clk_pll1_main_set_rate(struct clk *clk, unsigned long rate)
static void _clk_pll1_disable(struct clk *clk)
{
+ void __iomem *pllbase;
+ u32 reg;
+
pll1_enabled = false;
- _clk_pll_disable(clk);
+
+ /* Set PLL1 in bypass mode only. */
+ /* We need to be able to set the ARM-PODF bit
+ * when the system enters WAIT mode. And setting
+ * this bit requires PLL1_main to be enabled.
+ */
+ pllbase = _get_pll_base(clk);
+
+ reg = __raw_readl(pllbase);
+ reg |= ANADIG_PLL_BYPASS;
+ __raw_writel(reg, pllbase);
}
static int _clk_pll1_enable(struct clk *clk)
@@ -1185,6 +1203,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
u32 div;
unsigned long parent_rate;
unsigned long flags;
+ unsigned long ipg_clk_rate, max_arm_wait_clk;
for (i = 0; i < cpu_op_nr; i++) {
if (rate == cpu_op_tbl[i].cpu_rate)
@@ -1229,6 +1248,32 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
}
parent_rate = clk_get_rate(clk->parent);
div = parent_rate / rate;
+ /* Calculate the ARM_PODF to be applied when the system
+ * enters WAIT state. The max ARM clk is decided by the
+ * ipg_clk and has to follow the ratio of ARM_CLK:IPG_CLK of 12:5.
+ * For ex, when IPG is at 66MHz, ARM_CLK cannot be greater
+ * than 158MHz.
+ * Pre-calculate the optimal divider now.
+ */
+ ipg_clk_rate = clk_get_rate(&ipg_clk);
+ max_arm_wait_clk = (12 * ipg_clk_rate) / 5;
+ wait_mode_arm_podf = parent_rate / max_arm_wait_clk;
+ if (wait_mode_arm_podf > 7) {
+ /* IPG_CLK is too low and we cannot get a ARM_CLK
+ * that will satisfy the 12:5 ratio.
+ * Use the mem_ipg_stop_mask bit to ensure clocks to ARM
+ * memories are not gated during WAIT mode.
+ * This bit is NOT available on MX6DQ TO1.1/TO1.0 and
+ * MX6DL TO1.0.
+ * Else disable entry to WAIT mode.
+ */
+ if ((mx6q_revision() > IMX_CHIP_REVISION_1_1) ||
+ (mx6dl_revision() > IMX_CHIP_REVISION_1_0))
+ arm_mem_clked_in_wait = true;
+ else
+ enable_wait_mode = false;
+ }
+
if (div == 0)
div = 1;
@@ -1239,11 +1284,12 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
spin_unlock_irqrestore(&clk_lock, flags);
return -1;
}
-
/* Need PLL1-MAIN to be ON to write to ARM-PODF bit. */
if (!pll1_enabled)
pll1_sys_main_clk.enable(&pll1_sys_main_clk);
+ cur_arm_podf = div;
+
__raw_writel(div - 1, MXC_CCM_CACRR);
while (__raw_readl(MXC_CCM_CDHIPR))