summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx6/clock_mx6sl.c
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2012-05-16 12:43:27 -0500
committerJason Liu <r64343@freescale.com>2012-07-20 13:37:46 +0800
commit40f361bcc5f8c61dac1ea15acfdd34e32d32f84e (patch)
tree6f93f147e5d89e8989b66ae9ee323f8950cb2de7 /arch/arm/mach-mx6/clock_mx6sl.c
parent49f744921cfa19f2250d5f55cda6157aad6b8234 (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_mx6sl.c')
-rwxr-xr-xarch/arm/mach-mx6/clock_mx6sl.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/arch/arm/mach-mx6/clock_mx6sl.c b/arch/arm/mach-mx6/clock_mx6sl.c
index 20cfd922584d..70ea1200cfda 100755
--- a/arch/arm/mach-mx6/clock_mx6sl.c
+++ b/arch/arm/mach-mx6/clock_mx6sl.c
@@ -50,7 +50,10 @@ 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 mx6q_revision(void);
+extern bool arm_mem_clked_in_wait;
+extern int cur_arm_podf;
static void __iomem *apll_base;
static struct clk pll1_sys_main_clk;
@@ -62,6 +65,7 @@ static struct clk pll5_video_main_clk;
static struct clk pll6_enet_main_clk; /* Essentially same as PLL8 on MX6Q/DL */
static struct clk pll7_usb_host_main_clk;
static struct clk usdhc3_clk;
+static struct clk ipg_clk;
static struct cpu_op *cpu_op_tbl;
static int cpu_op_nr;
@@ -70,6 +74,7 @@ static int cpu_op_nr;
#define AUDIO_VIDEO_MIN_CLK_FREQ 650000000
#define AUDIO_VIDEO_MAX_CLK_FREQ 1300000000
+#define MAX_ARM_CLK_IN_WAIT 158000000
/* We need to check the exp status again after timer expiration,
* as there might be interrupt coming between the first time exp
@@ -1064,7 +1069,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
int i;
u32 div;
u32 parent_rate;
-
+ 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)
@@ -1085,6 +1090,26 @@ 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.
+ * Else disable entry to WAIT mode.
+ */
+ arm_mem_clked_in_wait = true;
+ else
+ arm_mem_clked_in_wait = false;
if (div == 0)
div = 1;
@@ -1095,8 +1120,13 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
if (div > 8)
return -1;
+ cur_arm_podf = div;
+
__raw_writel(div - 1, MXC_CCM_CACRR);
+ while (__raw_readl(MXC_CCM_CDHIPR))
+ ;
+
return 0;
}