From 5ab5cd243feb923a68698791b3e9da838008aa91 Mon Sep 17 00:00:00 2001 From: Ranjani Vaidyanathan Date: Mon, 14 May 2012 16:12:59 -0500 Subject: [PATCH] ENGR00209846 MX6SL-Enable DVFS_CORE on all MX6 platforms Add support DVFS-CORE to MX6Sololite. Set PLL1 in bypass mode when ARM freq drops below 400MHz. ARM will be sourced from PLL2_PFD2_400M in this case. Signed-off-by: Ranjani Vaidyanathan --- arch/arm/mach-mx6/board-mx6sl_arm2.c | 25 +++++++ arch/arm/mach-mx6/clock_mx6sl.c | 97 ++++++++++++++++++++++++---- arch/arm/plat-mxc/dvfs_core.c | 8 +-- 3 files changed, 113 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-mx6/board-mx6sl_arm2.c b/arch/arm/mach-mx6/board-mx6sl_arm2.c index 0cea2c8ec2ff..4e0b7f5119dd 100755 --- a/arch/arm/mach-mx6/board-mx6sl_arm2.c +++ b/arch/arm/mach-mx6/board-mx6sl_arm2.c @@ -356,6 +356,29 @@ static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { }, }; +static struct mxc_dvfs_platform_data mx6sl_arm2_dvfscore_data = { + .reg_id = "cpu_vddgp", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 80, +}; + void __init early_console_setup(unsigned long base, struct clk *clk); static inline void mx6_arm2_init_uart(void) @@ -733,6 +756,8 @@ static void __init mx6_arm2_init(void) imx6dl_add_imx_pxp_client(); mxc_register_device(&max17135_sensor_device, NULL); imx6dl_add_imx_epdc(&epdc_data); + + imx6q_add_dvfs_core(&mx6sl_arm2_dvfscore_data); } extern void __iomem *twd_base; diff --git a/arch/arm/mach-mx6/clock_mx6sl.c b/arch/arm/mach-mx6/clock_mx6sl.c index 70ea1200cfda..1d485c39ed38 100755 --- a/arch/arm/mach-mx6/clock_mx6sl.c +++ b/arch/arm/mach-mx6/clock_mx6sl.c @@ -69,7 +69,10 @@ static struct clk ipg_clk; static struct cpu_op *cpu_op_tbl; static int cpu_op_nr; +static bool pll1_enabled; +static bool arm_needs_pll2_400; +DEFINE_SPINLOCK(mx6sl_clk_lock); #define SPIN_DELAY 1200000 /* in nanoseconds */ #define AUDIO_VIDEO_MIN_CLK_FREQ 650000000 @@ -482,13 +485,39 @@ static int _clk_pll1_main_set_rate(struct clk *clk, unsigned long rate) return 0; } +static int _clk_pll1_main_enable(struct clk *clk) +{ + pll1_enabled = true; + _clk_pll_enable(clk); + return 0; +} + +static void _clk_pll1_main_disable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + pll1_enabled = false; + pllbase = _get_pll_base(clk); + + /* Set the PLL is bypass mode only. + * We need to be able to set the ARM_PODF bit + * in WAIT mode. Setting the ARM_PODF bit + * requires PLL1 to be enabled. + */ + reg = __raw_readl(pllbase); + reg |= ANADIG_PLL_BYPASS; + + __raw_writel(reg, pllbase); +} + static struct clk pll1_sys_main_clk = { __INIT_CLK_DEBUG(pll1_sys_main_clk) .parent = &osc_clk, .get_rate = _clk_pll1_main_get_rate, .set_rate = _clk_pll1_main_set_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, + .enable = _clk_pll1_main_enable, + .disable = _clk_pll1_main_disable, }; static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) @@ -521,6 +550,7 @@ static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; } __raw_writel(reg, MXC_CCM_CCSR); + return 0; } @@ -580,13 +610,19 @@ static struct clk pll2_528_bus_main_clk = { .disable = _clk_pll_disable, }; +static void _clk_pll2_pfd2_400M_disable(struct clk *clk) +{ + if (!arm_needs_pll2_400) + _clk_pfd_disable(clk); +} + static struct clk pll2_pfd2_400M = { __INIT_CLK_DEBUG(pll2_pfd2_400M) .parent = &pll2_528_bus_main_clk, .enable_reg = (void *)PFD_528_BASE_ADDR, .enable_shift = ANADIG_PFD2_FRAC_OFFSET, .enable = _clk_pfd_enable, - .disable = _clk_pfd_disable, + .disable = _clk_pll2_pfd2_400M_disable, .get_rate = pfd_get_rate, .set_rate = pfd_set_rate, .get_rate = pfd_get_rate, @@ -1070,6 +1106,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate) u32 div; u32 parent_rate; unsigned long ipg_clk_rate, max_arm_wait_clk; + unsigned long flags; for (i = 0; i < cpu_op_nr; i++) { if (rate == cpu_op_tbl[i].cpu_rate) @@ -1078,16 +1115,40 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate) if (i >= cpu_op_nr) return -EINVAL; - if (cpu_op_tbl[i].pll_rate != clk_get_rate(&pll1_sys_main_clk)) { - /* Change the PLL1 rate. */ - if (pll2_pfd2_400M.usecount != 0) + spin_lock_irqsave(&mx6sl_clk_lock, flags); + + if (rate <= clk_get_rate(&pll2_pfd2_400M)) { + /* Source pll1_sw_clk from step_clk which is sourced from + * PLL2_PFD2_400M. + */ + if (pll1_sw_clk.parent != &pll2_pfd2_400M) { + pll2_pfd2_400M.enable(&pll2_pfd2_400M); + arm_needs_pll2_400 = true; pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd2_400M); - else - pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk); - pll1_sys_main_clk.set_rate(&pll1_sys_main_clk, cpu_op_tbl[i].pll_rate); - pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk); + pll1_sw_clk.parent = &pll2_pfd2_400M; + } + } else { + if (pll1_sw_clk.parent != &pll1_sys_main_clk) { + /* pll1_sw_clk was being sourced from pll2_400M. */ + /* Enable PLL1 and set pll1_sw_clk parent as PLL1 */ + if (!pll1_enabled) + pll1_sys_main_clk.enable(&pll1_sys_main_clk); + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk); + pll1_sw_clk.parent = &pll1_sys_main_clk; + arm_needs_pll2_400 = false; + if (pll2_pfd2_400M.usecount == 0) + pll2_pfd2_400M.disable(&pll2_pfd2_400M); + } + if (cpu_op_tbl[i].pll_rate != clk_get_rate(&pll1_sys_main_clk)) { + /* Change the PLL1 rate. */ + if (pll2_pfd2_400M.usecount != 0) + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd2_400M); + else + pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk); + pll1_sys_main_clk.set_rate(&pll1_sys_main_clk, cpu_op_tbl[i].pll_rate); + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk); + } } - parent_rate = clk_get_rate(clk->parent); div = parent_rate / rate; /* Calculate the ARM_PODF to be applied when the system @@ -1117,8 +1178,13 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate) if ((parent_rate / div) > rate) div++; - if (div > 8) + if (div > 8) { + spin_unlock_irqrestore(&mx6sl_clk_lock, flags); return -1; + } + + if (!pll1_enabled) + pll1_sys_main_clk.enable(&pll1_sys_main_clk); cur_arm_podf = div; @@ -1127,6 +1193,11 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate) while (__raw_readl(MXC_CCM_CDHIPR)) ; + if (pll1_sys_main_clk.usecount == 1 && arm_needs_pll2_400) + pll1_sys_main_clk.disable(&pll1_sys_main_clk); + + spin_unlock_irqrestore(&mx6sl_clk_lock, flags); + return 0; } @@ -3626,7 +3697,7 @@ static void clk_tree_init(void) * in this case, periph clk will set to 400MHz in uboot, * so in clock init, we need to check whether the ddr clock * is set to 400MHz, if yes, then we should set periph clk - * parent to pll2_pfd_400M. + * parent to pll2_pfd2_400M. */ if ((reg & MMDC_MDMISC_DDR_TYPE_MASK) == (0x1 << MMDC_MDMISC_DDR_TYPE_OFFSET)) { diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c index d52f7b6eb039..a31ee9a71940 100755 --- a/arch/arm/plat-mxc/dvfs_core.c +++ b/arch/arm/plat-mxc/dvfs_core.c @@ -427,7 +427,7 @@ static int set_cpu_freq(int op) { int ret = 0; - if (cpu_is_mx6q() || cpu_is_mx6dl()) + if (cpu_is_mx6()) ret = mx6_set_cpu_freq(op); else ret = mx5_set_cpu_freq(op); @@ -476,7 +476,7 @@ static int start_dvfs(void) /* GPCIRQ=1, select ARM IRQ */ reg |= MXC_GPCCNTR_GPCIRQ_ARM; /* ADU=1, select ARM domain */ - if (!(cpu_is_mx6q() || cpu_is_mx6dl())) + if (!cpu_is_mx6()) reg |= MXC_GPCCNTR_ADU; __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); @@ -509,7 +509,7 @@ static int start_dvfs(void) __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /* Enable DVFS */ - if (cpu_is_mx6q() || cpu_is_mx6dl()) { + if (cpu_is_mx6()) { unsigned long cpu_wfi = 0; int num_cpus = num_possible_cpus(); reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_EMAC); @@ -947,7 +947,7 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) printk(KERN_ERR "%s: failed to get cpu clock\n", __func__); return PTR_ERR(cpu_clk); } - if (!(cpu_is_mx6q() || cpu_is_mx6dl())) { + if (!cpu_is_mx6()) { dvfs_clk = clk_get(NULL, dvfs_data->clk2_id); if (IS_ERR(dvfs_clk)) { printk(KERN_ERR "%s: failed to get dvfs clock\n", __func__); -- 2.39.5