When PLL5P is used as a parent clock for some of the peripherals,
the current code just selects some hardcoded divisors. This happens
to work, but only under assumption that the PLL5P clock speed is
somewhere between 360MHz and 480MHz (the typical DRAM clock speeds).

However with some tweaks for the DRAM parameters, it is possible to
clock DRAM up to 600MHz and more on some devices:

    http://lists.denx.de/pipermail/u-boot/2014-July/183981.html

And this introduces concerns about the hardcoded divisors in the
kernel, which may cause some peripherals to operate at abnormally
high clock speeds if the PLL5 clock speed is too fast (PLL5 is used
for clocking DRAM).

Moreover, it makes sense to avoid pre-dividing PLL5P and make it run
even faster than DRAM. This provides better granularity of the clock
speed selection for MBUS, G2D and everything else that is using PLL5P
as the parent clock. but running PLL5P faster means that the hardcoded
divisors become even more inappropriate.

This patch improves the clock divisors selection for G2D, ACE and
DEBE to insure that they can work correctly with any PLL5P clock
speed.

Signed-off-by: Siarhei Siamashka <siarhei.siamas...@gmail.com>
---
 drivers/char/sunxi_g2d/g2d.c        |  8 ++++++--
 drivers/media/audio/sun4i_dev_ace.c |  7 ++++++-
 drivers/video/sunxi/disp/disp_clk.c | 17 ++++++++---------
 3 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/char/sunxi_g2d/g2d.c b/drivers/char/sunxi_g2d/g2d.c
index 288685a..539c726 100644
--- a/drivers/char/sunxi_g2d/g2d.c
+++ b/drivers/char/sunxi_g2d/g2d.c
@@ -29,9 +29,12 @@
 struct clk *g2d_ahbclk,*g2d_dramclk,*g2d_mclk,*g2d_src;
 extern __g2d_drv_t      g2d_ext_hd;
 
+/* Arbitrarily pick 240MHz (TODO: confirm what is the real limit) */
+#define G2D_CLOCK_SPEED_LIMIT 240000000
+
 int g2d_openclk(void)
 {
-       __u32 ret;
+       __u32 ret, g2d_div;
 
        /* ahb g2d gating */
        g2d_ahbclk = clk_get(NULL,"ahb_de_mix");
@@ -51,7 +54,8 @@ int g2d_openclk(void)
        clk_put(g2d_src);
 
        ret = clk_get_rate(g2d_src);
-       clk_set_rate(g2d_mclk,ret/2);
+       g2d_div = DIV_ROUND_UP(ret, G2D_CLOCK_SPEED_LIMIT);
+       clk_set_rate(g2d_mclk, ret / g2d_div);
 
        return 0;
 }
diff --git a/drivers/media/audio/sun4i_dev_ace.c 
b/drivers/media/audio/sun4i_dev_ace.c
index 59fdfeb..e3599f6 100644
--- a/drivers/media/audio/sun4i_dev_ace.c
+++ b/drivers/media/audio/sun4i_dev_ace.c
@@ -91,10 +91,14 @@ static irqreturn_t ace_interrupt(int irq, void *dev)
     return IRQ_HANDLED;
 }
 
+/* 200MHz is the limit for ACE_CLK_REG (see the A10 User Manual) */
+#define ACE_CLOCK_SPEED_LIMIT 200000000
+
 static long ace_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long 
arg)
 {
        int                             ret_val = 0;
        unsigned long       test_arg;
+       int pll5_div;
        __ace_req_e             mpara;
        unsigned long rate;
        switch (cmd){
@@ -137,7 +141,8 @@ static long ace_dev_ioctl(struct file *filp, unsigned int 
cmd, unsigned long arg
                                printk("try to set parent of ace_moduleclk to 
ace_pll5clk failed!\n");
                        }
                        rate = clk_get_rate(ace_pll5_pclk);
-                       if(clk_set_rate(ace_moduleclk, rate/2)) {
+                       pll5_div = DIV_ROUND_UP(rate, ACE_CLOCK_SPEED_LIMIT);
+                       if(clk_set_rate(ace_moduleclk, rate / pll5_div)) {
                                printk("try to set ace_moduleclk rate 
failed!!!\n");
                                 goto out;
                        }
diff --git a/drivers/video/sunxi/disp/disp_clk.c 
b/drivers/video/sunxi/disp/disp_clk.c
index abd1877..ff46bcc 100644
--- a/drivers/video/sunxi/disp/disp_clk.c
+++ b/drivers/video/sunxi/disp/disp_clk.c
@@ -120,9 +120,12 @@ __disp_clk_tab clk_tab = {
        }
 };
 
+/* 300MHz */
+#define DEBE_CLOCK_SPEED_LIMIT 300000000
+
 __s32 image_clk_init(__u32 sel)
 {
-       __u32 dram_pll;
+       __u32 dram_pll, pll5_div;
 
        if (sel == 0) {
                h_debe0ahbclk = OSAL_CCMU_OpenMclk(AW_MOD_CLK_AHB_DEBE0);
@@ -137,10 +140,8 @@ __s32 image_clk_init(__u32 sel)
                OSAL_CCMU_SetMclkSrc(h_debe0mclk, AW_SYS_CLK_PLL5P);
 
                dram_pll = OSAL_CCMU_GetSrcFreq(AW_SYS_CLK_PLL5P);
-               if (dram_pll < 300000000)
-                       OSAL_CCMU_SetMclkDiv(h_debe0mclk, 1);
-               else
-                       OSAL_CCMU_SetMclkDiv(h_debe0mclk, 2);
+               pll5_div = DIV_ROUND_UP(dram_pll, DEBE_CLOCK_SPEED_LIMIT);
+               OSAL_CCMU_SetMclkDiv(h_debe0mclk, pll5_div);
 
                OSAL_CCMU_MclkOnOff(h_debe0ahbclk, CLK_ON);
                if (sunxi_is_sun4i()) {
@@ -162,10 +163,8 @@ __s32 image_clk_init(__u32 sel)
                OSAL_CCMU_SetMclkSrc(h_debe1mclk, AW_SYS_CLK_PLL5P);
 
                dram_pll = OSAL_CCMU_GetSrcFreq(AW_SYS_CLK_PLL5P);
-               if (dram_pll < 300000000)
-                       OSAL_CCMU_SetMclkDiv(h_debe1mclk, 1);
-               else
-                       OSAL_CCMU_SetMclkDiv(h_debe1mclk, 2);
+               pll5_div = DIV_ROUND_UP(dram_pll, DEBE_CLOCK_SPEED_LIMIT);
+               OSAL_CCMU_SetMclkDiv(h_debe1mclk, pll5_div);
 
                OSAL_CCMU_MclkOnOff(h_debe1ahbclk, CLK_ON);
                if (sunxi_is_sun4i()) {
-- 
1.8.3.2

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to