more clock
author黄涛 <huangtao@rock-chips.com>
Mon, 26 Apr 2010 13:13:44 +0000 (13:13 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:34:47 +0000 (13:34 +0800)
arch/arm/mach-rk2818/clock.c

index 28085a389071dba71713d9e1a98381724de08730..5a44bdd11403705607d772cd3b0e4e410c0918b6 100644 (file)
@@ -162,7 +162,15 @@ static unsigned long clksel_recalc(struct clk *clk)
 {
        u32 div = ((readl(clk->clksel_reg) & clk->clksel_mask) >> clk->clksel_shift) + 1;
        unsigned long rate = clk->parent->rate / div;
-       pr_debug("clock: %s new clock rate is %ld (div %d) reg %p mask %x shift %d\n", clk->name, rate, div, clk->clksel_reg, clk->clksel_mask, clk->clksel_shift);
+       pr_debug("clock: %s new clock rate is %ld (div %d)\n", clk->name, rate, div);
+       return rate;
+}
+
+static unsigned long clksel_recalc_shift(struct clk *clk)
+{
+       u32 shift = (readl(clk->clksel_reg) & clk->clksel_mask) >> clk->clksel_shift;
+       unsigned long rate = clk->parent->rate >> shift;
+       pr_debug("clock: %s new clock rate is %ld (shift %d)\n", clk->name, rate, shift);
        return rate;
 }
 
@@ -187,6 +195,27 @@ static int clksel_set_rate(struct clk *clk, unsigned long rate)
        return -ENOENT;
 }
 
+static int clksel_set_rate_shift(struct clk *clk, unsigned long rate)
+{
+       u32 shift;
+
+       for (shift = 0; (1 << shift) <= clk->clksel_maxdiv; shift++) {
+               u32 new_rate = clk->parent->rate >> shift;
+               if (new_rate <= rate) {
+                       u32 *reg = clk->clksel_reg;
+                       u32 v = readl(reg);
+                       v &= ~clk->clksel_mask;
+                       v |= shift << clk->clksel_shift;
+                       writel(v, reg);
+                       clk->rate = new_rate;
+                       pr_debug("clock: clksel_set_rate for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift);
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
 static struct clk xin24m = {
        .name           = "xin24m",
        .rate           = 24000000,
@@ -236,6 +265,7 @@ static struct clk arm_clk = {
 //     .set_rate       = arm_clk_set_rate,
        .clksel_reg     = CLKSEL2_REG,
        .clksel_mask    = 0xF,
+       .clksel_maxdiv  = 16,
 };
 
 static struct clk arm_hclk = {
@@ -244,6 +274,7 @@ static struct clk arm_hclk = {
        .recalc         = clksel_recalc,
        .clksel_reg     = CLKSEL0_REG,
        .clksel_mask    = 0x3,
+       .clksel_maxdiv  = 4,
 };
 
 static struct clk clk48m = {
@@ -256,40 +287,28 @@ static struct clk clk48m = {
        .clksel_shift   = 4,
 };
 
-static unsigned long arm_pclk_recalc(struct clk *clk)
-{
-       u32 shift = (readl(&scu_register_base->scu_clksel0_config) >> 2) & 0x3;
-       unsigned long rate = clk->parent->rate >> shift;
-       pr_debug("clock: %s new clock rate is %ld (shift %d)\n", clk->name, rate, shift);
-       return rate;
-}
-
 static struct clk arm_pclk = {
        .name           = "arm_pclk",
        .parent         = &arm_hclk,
-       .recalc         = arm_pclk_recalc,
+       .recalc         = clksel_recalc_shift,
+       .set_rate       = clksel_set_rate_shift,
+       .clksel_reg     = CLKSEL0_REG,
+       .clksel_mask    = 0x3 << 2,
+       .clksel_shift   = 2,
+       .clksel_maxdiv  = 4,
 };
 
 static void demod_clk_init(struct clk *clk)
 {
-       struct clk *real_parent = clk->parent;
+       struct clk *parent = clk->parent;
        u32 r = readl(CLKSEL1_REG);
        if (r & (1 << 26)) {
-               real_parent = &xin24m;
+               parent = &xin24m;
        } else {
                r >>= 24;
-               if (r == 0) {
-                       real_parent = &codec_pll_clk;
-               } else if (r == 1) {
-                       real_parent = &arm_pll_clk;
-               } else if (r == 2) {
-                       real_parent = &dsp_pll_clk;
-               }
-       }
-       if (real_parent != clk->parent) {
-               pr_debug("clock: inited %s parent to %s (was %s)\n", clk->name, real_parent->name, ((clk->parent) ? clk->parent->name : "NULL"));
-               clk_reparent(clk, real_parent);
+               parent = (r == 0) ? &codec_pll_clk : (r == 1) ? &arm_pll_clk : (r == 2) ? &dsp_pll_clk : parent;
        }
+       clk_reparent(clk, parent);
 }
 
 static struct clk demod_clk = {
@@ -298,7 +317,6 @@ static struct clk demod_clk = {
        .recalc         = clksel_recalc,
        .set_rate       = clksel_set_rate,
        .init           = demod_clk_init,
-//     .set_parent     = demod_clk_set_parent,
        .clksel_reg     = CLKSEL1_REG,
        .clksel_mask    = 0xFF << 16,
        .clksel_shift   = 16,
@@ -327,14 +345,39 @@ static struct clk lcdc_divider_clk = {
        .clksel_maxdiv  = 128,
 };
 
+static void otgphy_clk_init(struct clk *clk)
+{
+       u32 r = (readl(CLKSEL0_REG) >> 18) & 3;
+       struct clk *parent = (r == 0) ? &xin24m : (r == 1) ? &clk12m : (r == 2) ? &clk48m : clk->parent;
+       clk_reparent(clk, parent);
+}
+
 static void lcdc_clk_init(struct clk *clk)
 {
-       u32 r = readl(&scu_register_base->scu_clksel0_config) & (1 << 7);
-       struct clk *real_parent = r ? &extclk : &lcdc_divider_clk;
-       if (real_parent != clk->parent) {
-               pr_debug("clock: inited %s parent to %s (was %s)\n", clk->name, real_parent->name, ((clk->parent) ? clk->parent->name : "NULL"));
-               clk_reparent(clk, real_parent);
-       }
+       u32 r = readl(CLKSEL0_REG) & (1 << 7);
+       struct clk *parent = r ? &extclk : &lcdc_divider_clk;
+       clk_reparent(clk, parent);
+}
+
+static void vip_clk_init(struct clk *clk)
+{
+       u32 r = (readl(CLKSEL0_REG) >> 23) & 3;
+       struct clk *parent = (r == 0) ? &xin24m : (r == 1) ? &extclk : (r == 2) ? &clk48m : clk->parent;
+       clk_reparent(clk, parent);
+}
+
+static void ddr_clk_init(struct clk *clk)
+{
+       u32 r = (readl(CLKSEL0_REG) >> 28) & 3;
+       struct clk *parent = (r == 0) ? &codec_pll_clk : (r == 1) ? &arm_pll_clk : (r == 2) ? &dsp_pll_clk : clk->parent;
+       clk_reparent(clk, parent);
+}
+
+static void i2s_clk_init(struct clk *clk)
+{
+       u32 r = readl(CLKSEL1_REG) & (1 << 2);
+       struct clk *parent = r ? &clk12m : &codec_clk;
+       clk_reparent(clk, parent);
 }
 
 static int gate_mode(struct clk *clk, int on)
@@ -372,30 +415,27 @@ static int gate_mode(struct clk *clk, int on)
 static void uart_clk_init(struct clk *clk)
 {
        u32 r = readl(&scu_register_base->scu_clksel1_config) >> 31;
-       struct clk *real_parent = r ? &clk48m : &xin24m;
-       if (real_parent != clk->parent) {
-               pr_debug("clock: inited %s parent to %s (was %s)\n", clk->name, real_parent->name, ((clk->parent) ? clk->parent->name : "NULL"));
-               clk_reparent(clk, real_parent);
-       }
+       struct clk *parent = r ? &clk48m : &xin24m;
+       clk_reparent(clk, parent);
 }
 
 #define UART_CLK(n) \
 static struct clk uart##n##_clk = { \
        .name           = "uart"#n, \
        .parent         = &xin24m, \
-       .gate_idx       = SCU_IPID_UART##n, \
        .mode           = gate_mode, \
        .recalc         = followparent_recalc, \
        .init           = uart_clk_init, \
+       .gate_idx       = SCU_IPID_UART##n, \
 }
 
 #define GATE_CLK(NAME,PARENT,ID) \
 static struct clk NAME##_clk = { \
        .name           = #NAME, \
        .parent         = &PARENT, \
-       .gate_idx       = SCU_IPID_##ID, \
        .mode           = gate_mode, \
        .recalc         = followparent_recalc, \
+       .gate_idx       = SCU_IPID_##ID, \
 }
 
 GATE_CLK(arm_core, arm_clk, ARM);
@@ -405,28 +445,48 @@ GATE_CLK(sramarm, arm_hclk, SRAMARM);
 GATE_CLK(sramdsp, arm_hclk, SRAMDSP);
 GATE_CLK(hif, arm_hclk, HIF);
 GATE_CLK(otgbus, arm_hclk, OTGBUS);
-//GATE_CLK(otgphy, arm_hclk, OTGPHY); //FIXME
+static struct clk otgphy_clk = {
+       .name           = "otgphy",
+       .parent         = &xin24m,
+       .mode           = gate_mode,
+       .recalc         = followparent_recalc,
+       .init           = otgphy_clk_init,
+       .gate_idx       = SCU_IPID_OTGPHY,
+};
 GATE_CLK(nandc, arm_hclk, NANDC);
 GATE_CLK(intc, arm_hclk, INTC);
 GATE_CLK(deblocking_rv, arm_hclk, DEBLK);
 static struct clk lcdc_clk = {
        .name           = "lcdc",
        .parent         = &lcdc_divider_clk,
-       .gate_idx       = SCU_IPID_LCDC,
        .mode           = gate_mode,
        .recalc         = followparent_recalc,
        .init           = lcdc_clk_init,
-//     .set_parent     = lcdc_clk_set_parent,
+       .gate_idx       = SCU_IPID_LCDC,
+};
+static struct clk vip_clk = {
+       .name           = "vip",
+       .parent         = &xin24m,
+       .mode           = gate_mode,
+       .recalc         = followparent_recalc,
+       .init           = vip_clk_init,
+       .gate_idx       = SCU_IPID_VIP,
+};
+static struct clk i2s_clk = {
+       .name           = "i2s",
+       .parent         = &clk12m,
+       .mode           = gate_mode,
+       .recalc         = followparent_recalc,
+       .init           = i2s_clk_init,
+       .gate_idx       = SCU_IPID_I2S,
 };
-GATE_CLK(vip, arm_hclk, VIP); //FIXME
-GATE_CLK(i2s, arm_pclk, I2S); //FIXME
 static struct clk sdmmc0_clk = {
        .name           = "sdmmc0",
        .parent         = &arm_hclk,
-       .gate_idx       = SCU_IPID_SDMMC0,
        .mode           = gate_mode,
        .recalc         = clksel_recalc,
        .set_rate       = clksel_set_rate,
+       .gate_idx       = SCU_IPID_SDMMC0,
        .clksel_reg     = CLKSEL0_REG,
        .clksel_mask    = 7 << 4,
        .clksel_shift   = 4,
@@ -449,10 +509,10 @@ GATE_CLK(rtc, arm_pclk, RTC);
 static struct clk lsadc_clk = {
        .name           = "lsadc",
        .parent         = &arm_pclk,
-       .gate_idx       = SCU_IPID_LSADC,
        .mode           = gate_mode,
        .recalc         = clksel_recalc,
        .set_rate       = clksel_set_rate,
+       .gate_idx       = SCU_IPID_LSADC,
        .clksel_reg     = CLKSEL1_REG,
        .clksel_mask    = 0xFF << 8,
        .clksel_shift   = 8,
@@ -463,10 +523,10 @@ UART_CLK(3);
 static struct clk sdmmc1_clk = {
        .name           = "sdmmc1",
        .parent         = &arm_hclk,
-       .gate_idx       = SCU_IPID_SDMMC1,
        .mode           = gate_mode,
        .recalc         = clksel_recalc,
        .set_rate       = clksel_set_rate,
+       .gate_idx       = SCU_IPID_SDMMC1,
        .clksel_reg     = CLKSEL2_REG,
        .clksel_mask    = 7 << 8,
        .clksel_shift   = 8,
@@ -481,27 +541,39 @@ static unsigned long hsadc_clk_recalc(struct clk *clk)
 static struct clk hsadc_clk = {
        .name           = "hsadc",
        .parent         = &demod_clk,
-       .gate_idx       = SCU_IPID_HSADC,
        .mode           = gate_mode,
        .recalc         = hsadc_clk_recalc,
+       .gate_idx       = SCU_IPID_HSADC,
 };
-//GATE_CLK(mobile_sdram_common, arm_hclk, MOBILE_SDARM_COMMON);
-//GATE_CLK(sdram_controller, arm_hclk, SDRAM_CONTROLLER);
-//GATE_CLK(mobile_sdram_controller, arm_hclk, MOBILE_SDRAM_CONTROLLER);
-//GATE_CLK(lcdc_share_memory, arm_hclk, LCDC_SHARE_MEMORY); //FIXME
-//GATE_CLK(lcdc_hclk, arm_hclk, LCDC_HCLK); //FIXME
-//GATE_CLK(deblocking_h264, arm_hclk, DEBLK_H264);
-//GATE_CLK(gpu, arm_hclk, GPU);
-//GATE_CLK(ddr_hclk, arm_hclk, DDR_HCLK); //FIXME
-//GATE_CLK(ddr, arm_hclk, DDR); //FIXME
-//GATE_CLK(customized_sdram_controller, ); //FIXME
-//GATE_CLK(mcdma, arm_hclk, MCDMA); //FIXME
-//GATE_CLK(sdram, arm_hclk, SDRAM); //FIXME
-//GATE_CLK(ddr_axi, arm_hclk, DDR_AXI); //FIXME
-//GATE_CLK(dsp_timer, ); //FIXME
-//GATE_CLK(dsp_slave, ); //FIXME
-//GATE_CLK(dsp_master, ); //FIXME
-//GATE_CLK(usb_host, ); //FIXME
+GATE_CLK(mobile_sdram_common, arm_hclk, MOBILE_SDARM_COMMON);
+GATE_CLK(sdram_controller, arm_hclk, SDRAM_CONTROLLER);
+GATE_CLK(mobile_sdram_controller, arm_hclk, MOBILE_SDRAM_CONTROLLER);
+GATE_CLK(lcdc_share_memory, arm_hclk, LCDC_SHARE_MEMORY);
+GATE_CLK(lcdc_hclk, arm_hclk, LCDC_HCLK);
+GATE_CLK(deblocking_h264, arm_hclk, DEBLK_H264);
+GATE_CLK(gpu, arm_hclk, GPU);
+GATE_CLK(ddr_hclk, arm_hclk, DDR_HCLK);
+static struct clk ddr_clk = {
+       .name           = "ddr",
+       .parent         = &codec_pll_clk,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_shift,
+       .set_rate       = clksel_set_rate_shift,
+       .init           = ddr_clk_init,
+       .gate_idx       = SCU_IPID_DDR,
+       .clksel_reg     = CLKSEL0_REG,
+       .clksel_mask    = 0x3 << 30,
+       .clksel_shift   = 30,
+       .clksel_maxdiv  = 8,
+};
+GATE_CLK(customized_sdram_controller, arm_hclk, CUSTOMIZED_SDRAM_CONTROLLER);
+GATE_CLK(mcdma, arm_hclk, MCDMA);
+GATE_CLK(sdram, arm_hclk, SDRAM);
+GATE_CLK(ddr_axi, arm_hclk, DDR_AXI);
+GATE_CLK(dsp_timer, arm_hclk, DSP_TIMER);
+GATE_CLK(dsp_slave, arm_hclk, DSP_SLAVE);
+GATE_CLK(dsp_master, arm_hclk, DSP_MASTER);
+GATE_CLK(usb_host, clk48m, USB_HOST);
 
 GATE_CLK(armibus, arm_hclk, ARMIBUS);
 GATE_CLK(armdbus, arm_hclk, ARMDBUS);
@@ -551,13 +623,13 @@ static struct clk_lookup clks[] = {
        CLK1(sramdsp),
        CLK1(hif),
        CLK1(otgbus),
-       //CLK1(otgphy), //FIXME
+       CLK1(otgphy),
        CLK1(nandc),
        CLK1(intc),
        CLK1(deblocking_rv),
        CLK1(lcdc),
-       CLK1(vip), //FIXME
-       CLK1(i2s), //FIXME
+       CLK1(vip),
+       CLK1(i2s),
        CLK1(sdmmc0),
        CLK1(ebrom),
        CLK1(gpio0),
@@ -578,23 +650,23 @@ static struct clk_lookup clks[] = {
        CLK1(sdmmc1),
 
        CLK1(hsadc),
-       //CLK1(mobile_sdram_common),
-       //CLK1(sdram_controller),
-       //CLK1(mobile_sdram_controller),
-       //CLK1(lcdc_share_memory), //FIXME
-       //CLK1(lcdc_hclk), //FIXME
-       //CLK1(deblocking_h264),
-       //CLK1(gpu),
-       //CLK1(ddr_hclk), //FIXME
-       //CLK1(ddr), //FIXME
-       //CLK1(customized_sdram_controller), //FIXME
-       //CLK1(mcdma), //FIXME
-       //CLK1(sdram), //FIXME
-       //CLK1(ddr_axi), //FIXME
-       //CLK1(dsp_timer), //FIXME
-       //CLK1(dsp_slave), //FIXME
-       //CLK1(dsp_master), //FIXME
-       //CLK1(usb_host), //FIXME
+       CLK1(mobile_sdram_common),
+       CLK1(sdram_controller),
+       CLK1(mobile_sdram_controller),
+       CLK1(lcdc_share_memory),
+       CLK1(lcdc_hclk),
+       CLK1(deblocking_h264),
+       CLK1(gpu),
+       CLK1(ddr_hclk),
+       CLK1(ddr),
+       CLK1(customized_sdram_controller),
+       CLK1(mcdma),
+       CLK1(sdram),
+       CLK1(ddr_axi),
+       CLK1(dsp_timer),
+       CLK1(dsp_slave),
+       CLK1(dsp_master),
+       CLK1(usb_host),
 
        CLK1(armibus),
        CLK1(armdbus),
@@ -808,6 +880,10 @@ EXPORT_SYMBOL(clk_get_parent);
 
 static void clk_reparent(struct clk *child, struct clk *parent)
 {
+       if (child->parent == parent)
+               return;
+       pr_debug("clock: %s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL"));
+
        list_del_init(&child->sibling);
        if (parent)
                list_add(&child->sibling, &parent->children);