From e393c45cc7f2b03d26b879f5caecc12a3f949034 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 26 Apr 2010 13:13:44 +0000 Subject: [PATCH] more clock --- arch/arm/mach-rk2818/clock.c | 242 +++++++++++++++++++++++------------ 1 file changed, 159 insertions(+), 83 deletions(-) diff --git a/arch/arm/mach-rk2818/clock.c b/arch/arm/mach-rk2818/clock.c index 28085a389071..5a44bdd11403 100644 --- a/arch/arm/mach-rk2818/clock.c +++ b/arch/arm/mach-rk2818/clock.c @@ -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); -- 2.34.1