summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-mx51/clock.c12
-rw-r--r--arch/arm/mach-mx51/devices.c1
-rw-r--r--arch/arm/plat-mxc/dvfs_per.c55
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc_dvfs.h4
4 files changed, 65 insertions, 7 deletions
diff --git a/arch/arm/mach-mx51/clock.c b/arch/arm/mach-mx51/clock.c
index 3600b649cdba..5b053fc268e6 100644
--- a/arch/arm/mach-mx51/clock.c
+++ b/arch/arm/mach-mx51/clock.c
@@ -358,6 +358,18 @@ static int _clk_pll_set_rate(struct clk *clk, unsigned long rate)
__raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN);
}
+ /* If auto restart is disabled, restart the PLL and
+ * wait for it to lock.
+ */
+ reg = __raw_readl(pllbase + MXC_PLL_DP_CONFIG);
+ if (!reg & MXC_PLL_DP_CONFIG_AREN) {
+ reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
+ reg |= MXC_PLL_DP_CTL_RST;
+ __raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
+ }
+ while (!(__raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_LRF))
+ ;
+
clk->rate = rate;
return 0;
}
diff --git a/arch/arm/mach-mx51/devices.c b/arch/arm/mach-mx51/devices.c
index 1219a2a23871..70c865843733 100644
--- a/arch/arm/mach-mx51/devices.c
+++ b/arch/arm/mach-mx51/devices.c
@@ -310,6 +310,7 @@ static void mxc_init_ipu(void)
if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0)
mxc_ipu_data.rev = 2;
+ mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk");
mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");
/* Temporarily setup MIPI module to legacy mode */
clk = clk_get(NULL, "mipi_hsp_clk");
diff --git a/arch/arm/plat-mxc/dvfs_per.c b/arch/arm/plat-mxc/dvfs_per.c
index 1c00e2f29d3e..3460f4f6d6ce 100644
--- a/arch/arm/plat-mxc/dvfs_per.c
+++ b/arch/arm/plat-mxc/dvfs_per.c
@@ -45,6 +45,7 @@
#include <mach/hardware.h>
#include <mach/mxc_dvfs.h>
#include <mach/sdram_autogating.h>
+#include <mach/clock.h>
#if defined(CONFIG_ARCH_MX37)
#include <mach/mxc_dptc.h>
#endif
@@ -82,7 +83,7 @@ int start_dvfs_per(void);
void stop_dvfs_per(void);
int dvfs_per_active(void);
int dvfs_per_divider_active(void);
-int dvfs_per_pixel_clk_limit(int pix_clk);
+int dvfs_per_pixel_clk_limit();
extern int low_bus_freq_mode;
extern int bus_freq_scaling_is_active;
@@ -500,12 +501,15 @@ static int start(void)
return 0;
if (bus_freq_scaling_is_active) {
+ dvfs_per_is_paused = 1;
printk(KERN_INFO "Cannot start DVFS-PER since bus_freq_scaling is active\n");
return 0;
}
- if (!ipu_freq_scaled) {
- printk(KERN_INFO "Cannot start DVFS-PER since pixel clock is above 60MHz\n");
+ if (!dvfs_per_pixel_clk_limit()) {
+ dvfs_per_is_paused = 1;
+ printk(KERN_INFO "Cannot start DVFS-PER since pixel clock is\
+ above 60MHz or divider is not even\n");
return 0;
}
@@ -613,12 +617,52 @@ int dvfs_per_divider_active()
return dvfs_per_low_freq;
}
-int dvfs_per_pixel_clk_limit(int pix_clk)
+int dvfs_per_pixel_clk_limit()
{
- if (pix_clk < DVFS_MAX_PIX_CLK && (!ipu_freq_scaled))
+ struct clk *disp0_pixel_clk;
+ struct clk *disp1_pixel_clk;
+ int disp0_rate = 0;
+ int disp1_rate = 0;
+ int div1 = 0;
+ int div2 = 0;
+ int even_div1 = 1;
+ int even_div2 = 1;
+
+ disp0_pixel_clk = clk_get(NULL, "pixel_clk.0");
+ disp1_pixel_clk = clk_get(NULL, "pixel_clk.1");
+
+ if (disp0_pixel_clk != NULL)
+ disp0_rate = clk_get_rate(disp0_pixel_clk);
+
+ if (disp1_pixel_clk != NULL)
+ disp1_rate = clk_get_rate(disp1_pixel_clk);
+
+ /* DVFS-PER will not work if pixel clock divider is odd */
+ if (disp0_rate != 0)
+ div1 = (clk_get_rate(
+ clk_get_parent(disp0_pixel_clk)) * 10) / disp0_rate;
+
+ if ((div1 % 2) || ((div1 / 10) % 2))
+ even_div1 = 0;
+
+ if ((div2 % 2) || ((div2 / 10) % 2))
+ even_div2 = 0;
+
+ if (disp1_rate != 0)
+ div2 = (clk_get_rate(
+ clk_get_parent(disp1_pixel_clk)) * 10) / disp1_rate;
+
+ if (((disp0_rate < DVFS_MAX_PIX_CLK && even_div1) ||
+ !clk_get_usecount(disp0_pixel_clk)) &&
+ ((disp1_rate < DVFS_MAX_PIX_CLK && even_div2) ||
+ !clk_get_usecount(disp1_pixel_clk)))
ipu_freq_scaled = 1;
else
ipu_freq_scaled = 0;
+
+ clk_put(disp0_pixel_clk);
+ clk_put(disp1_pixel_clk);
+
return ipu_freq_scaled;
}
@@ -747,6 +791,7 @@ static int __devinit mxc_dvfsper_probe(struct platform_device *pdev)
cpu_clk = clk_get(NULL, "cpu_clk");
ahb_clk = clk_get(NULL, "ahb_clk");
axi_b_clk = clk_get(NULL, "axi_b_clk");
+
if (cpu_is_mx51())
ddr_hf_clk = clk_get(NULL, "ddr_hf_clk");
diff --git a/arch/arm/plat-mxc/include/mach/mxc_dvfs.h b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h
index 86b55cfff717..bc8904cf633f 100644
--- a/arch/arm/plat-mxc/include/mach/mxc_dvfs.h
+++ b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h
@@ -224,7 +224,7 @@ extern int start_dvfs_per(void);
extern void stop_dvfs_per(void);
extern int dvfs_per_active(void);
extern int dvfs_per_divider_active(void);
-extern int dvfs_per_pixel_clk_limit(int pix_clk);
+extern int dvfs_per_pixel_clk_limit();
#else
static inline int start_dvfs_per(void)
{
@@ -245,7 +245,7 @@ static inline int dvfs_per_divider_active(void)
return 0;
}
-static inline int dvfs_per_pixel_clk_limit(int pix_clk)
+static inline int dvfs_per_pixel_clk_limit(void)
{
return 0;
}