{
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;
}
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,
// .set_rate = arm_clk_set_rate,
.clksel_reg = CLKSEL2_REG,
.clksel_mask = 0xF,
+ .clksel_maxdiv = 16,
};
static struct clk arm_hclk = {
.recalc = clksel_recalc,
.clksel_reg = CLKSEL0_REG,
.clksel_mask = 0x3,
+ .clksel_maxdiv = 4,
};
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 = {
.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,
.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)
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);
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,
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,
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,
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);
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),
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),
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);