From d9661b096f2bb798ba42ca9f0d79d510eb8080f8 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Thu, 7 Apr 2016 17:20:03 +0800 Subject: [PATCH] MLK-12868-03 ARM: imx: add busfreq support on imx6ull Add busfreq support on i.MX6ULL. per to the design team, there is a 24MHz low power run mode on i.MX6ULL. the define for this mode is as below: ---------------------------- |cpu DRAM AXI AHB | 24MHz 24MHz 24MHz 24MHz The mode can be implemented as 'low_bus_mode' in busfreq, compared to i.MX6UL, the additional code we need to add is clk change for cpu core. so in low_bus_mode, the cpu will run at 24MHz. Signed-off-by: Bai Ping --- arch/arm/mach-imx/busfreq-imx.c | 75 +++++++++++++++++++++++++------- arch/arm/mach-imx/busfreq_ddr3.c | 6 +-- 2 files changed, 63 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-imx/busfreq-imx.c b/arch/arm/mach-imx/busfreq-imx.c index 49e3429ba53e..0a99bdba59bd 100644 --- a/arch/arm/mach-imx/busfreq-imx.c +++ b/arch/arm/mach-imx/busfreq-imx.c @@ -155,6 +155,34 @@ int unregister_busfreq_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(unregister_busfreq_notifier); +static struct clk *origin_step_parent; + +/* + * on i.MX6ULL, when entering low bus mode, the ARM core + * can run at 24MHz to support the low power run mode per + * to design team. + */ +static void imx6ull_lower_cpu_rate(bool enter) +{ + if (enter) + org_arm_rate = clk_get_rate(arm_clk); + + clk_set_parent(pll1_bypass_clk, pll1_bypass_src_clk); + clk_set_parent(pll1_sw_clk, pll1_sys_clk); + + if (enter) { + origin_step_parent = clk_get_parent(step_clk); + clk_set_parent(step_clk, osc_clk); + clk_set_parent(pll1_sw_clk, step_clk); + clk_set_rate(arm_clk, LPAPM_CLK); + } else { + clk_set_parent(step_clk, origin_step_parent); + clk_set_parent(pll1_sw_clk, step_clk); + clk_set_rate(arm_clk, org_arm_rate); + clk_set_parent(pll1_bypass_clk, pll1_clk); + } +} + /* * enter_lpm_imx6_up and exit_lpm_imx6_up is used by * i.MX6SX/i.MX6UL for entering and exiting lpm mode. @@ -197,6 +225,10 @@ static void enter_lpm_imx6_up(void) else if (ddr_type == IMX_DDR_TYPE_LPDDR2) clk_set_rate(mmdc_clk, HIGH_AUDIO_CLK); } + + if (cpu_is_imx6ull() && low_bus_freq_mode) + imx6ull_lower_cpu_rate(false); + audio_bus_freq_mode = 1; low_bus_freq_mode = 0; cur_bus_freq_mode = BUS_FREQ_AUDIO; @@ -210,6 +242,10 @@ static void enter_lpm_imx6_up(void) if (audio_bus_freq_mode) clk_disable_unprepare(pll2_400_clk); + + if (cpu_is_imx6ull()) + imx6ull_lower_cpu_rate(true); + low_bus_freq_mode = 1; audio_bus_freq_mode = 0; cur_bus_freq_mode = BUS_FREQ_LOW; @@ -255,20 +291,23 @@ static void enter_lpm_imx6_smp(void) static void exit_lpm_imx6_up(void) { + if (cpu_is_imx6ull() && low_bus_freq_mode) + imx6ull_lower_cpu_rate(false); + clk_prepare_enable(pll2_400_clk); /* * lower ahb/ocram's freq first to avoid too high * freq during parent switch from OSC to pll3. */ - if (cpu_is_imx6ul()) + if (cpu_is_imx6ul() || cpu_is_imx6ull()) clk_set_rate(ahb_clk, LPAPM_CLK / 4); else clk_set_rate(ahb_clk, LPAPM_CLK / 3); clk_set_rate(ocram_clk, LPAPM_CLK / 2); /* set periph clk to from pll2_bus on i.MX6UL */ - if (cpu_is_imx6ul()) + if (cpu_is_imx6ul() || cpu_is_imx6ull()) clk_set_parent(periph_pre_clk, pll2_bus_clk); /* set periph clk to from pll2_400 */ else @@ -563,7 +602,7 @@ static void reduce_bus_freq(void) if (cpu_is_imx7d()) enter_lpm_imx7d(); - else if (cpu_is_imx6sx() || cpu_is_imx6ul()) + else if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull()) enter_lpm_imx6_up(); else if (cpu_is_imx6q() || cpu_is_imx6dl()) enter_lpm_imx6_smp(); @@ -656,7 +695,7 @@ static int set_high_bus_freq(int high_bus_freq) if (cpu_is_imx7d()) exit_lpm_imx7d(); - else if (cpu_is_imx6sx() || cpu_is_imx6ul()) + else if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull()) exit_lpm_imx6_up(); else if (cpu_is_imx6q() || cpu_is_imx6dl()) exit_lpm_imx6_smp(); @@ -1015,7 +1054,7 @@ static int busfreq_probe(struct platform_device *pdev) } } - if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6sl()) { + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6sl() || cpu_is_imx6ull()) { ahb_clk = devm_clk_get(&pdev->dev, "ahb"); ocram_clk = devm_clk_get(&pdev->dev, "ocram"); periph2_clk = devm_clk_get(&pdev->dev, "periph2"); @@ -1033,7 +1072,7 @@ static int busfreq_probe(struct platform_device *pdev) } } - if (cpu_is_imx6sx() || cpu_is_imx6ul()) { + if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull()) { mmdc_clk = devm_clk_get(&pdev->dev, "mmdc"); if (IS_ERR(mmdc_clk)) { dev_err(busfreq_dev, @@ -1051,6 +1090,18 @@ static int busfreq_probe(struct platform_device *pdev) } if (cpu_is_imx6sl()) { + pll2_bypass_src_clk = devm_clk_get(&pdev->dev, "pll2_bypass_src"); + pll2_bypass_clk = devm_clk_get(&pdev->dev, "pll2_bypass"); + pll2_clk = devm_clk_get(&pdev->dev, "pll2"); + if (IS_ERR(pll2_bypass_src_clk) || IS_ERR(pll2_bypass_clk) + || IS_ERR(pll2_clk)) { + dev_err(busfreq_dev, + "%s failed to get busfreq clk for imx6sl.\n", __func__); + return -EINVAL; + } + } + + if (cpu_is_imx6ull() || cpu_is_imx6sl()) { arm_clk = devm_clk_get(&pdev->dev, "arm"); step_clk = devm_clk_get(&pdev->dev, "step"); pll1_clk = devm_clk_get(&pdev->dev, "pll1"); @@ -1058,16 +1109,10 @@ static int busfreq_probe(struct platform_device *pdev) pll1_bypass_clk = devm_clk_get(&pdev->dev, "pll1_bypass"); pll1_sys_clk = devm_clk_get(&pdev->dev, "pll1_sys"); pll1_sw_clk = devm_clk_get(&pdev->dev, "pll1_sw"); - pll2_bypass_src_clk = devm_clk_get(&pdev->dev, "pll2_bypass_src"); - pll2_bypass_clk = devm_clk_get(&pdev->dev, "pll2_bypass"); - pll2_clk = devm_clk_get(&pdev->dev, "pll2"); if (IS_ERR(arm_clk) || IS_ERR(step_clk) || IS_ERR(pll1_clk) || IS_ERR(pll1_bypass_src_clk) || IS_ERR(pll1_bypass_clk) - || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) - || IS_ERR(pll2_bypass_src_clk) || IS_ERR(pll2_bypass_clk) - || IS_ERR(pll2_clk)) { - dev_err(busfreq_dev, - "%s failed to get busfreq clk for imx6sl.\n", __func__); + || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk)) { + dev_err(busfreq_dev, "%s failed to get busfreq clk for imx6ull/sl.\n", __func__); return -EINVAL; } } @@ -1160,7 +1205,7 @@ static int busfreq_probe(struct platform_device *pdev) pr_info("ddr3 normal rate changed to 400MHz for TO1.1.\n"); } err = init_ddrc_ddr_settings(pdev); - } else if (cpu_is_imx6sx() || cpu_is_imx6ul()) { + } else if (cpu_is_imx6sx() || cpu_is_imx6ul() || cpu_is_imx6ull()) { ddr_type = imx_mmdc_get_ddr_type(); if (ddr_type == IMX_DDR_TYPE_DDR3) err = init_mmdc_ddr3_settings_imx6_up(pdev); diff --git a/arch/arm/mach-imx/busfreq_ddr3.c b/arch/arm/mach-imx/busfreq_ddr3.c index d98bb26f699d..3a016f15d5bb 100644 --- a/arch/arm/mach-imx/busfreq_ddr3.c +++ b/arch/arm/mach-imx/busfreq_ddr3.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -540,7 +540,7 @@ int init_mmdc_ddr3_settings_imx6_up(struct platform_device *busfreq_pdev) + normal_mmdc_settings[i][0]); } - if (cpu_is_imx6ul()) + if (cpu_is_imx6ul() || cpu_is_imx6ull()) iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6ul); else iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6sx); @@ -567,7 +567,7 @@ int init_mmdc_ddr3_settings_imx6_up(struct platform_device *busfreq_pdev) } for (i = 0; i < iomux_settings_size; i++) { - if (cpu_is_imx6ul()) { + if (cpu_is_imx6ul() || cpu_is_imx6ull()) { iomux_offsets_mx6ul[i][1] = readl_relaxed(iomux_base + iomux_offsets_mx6ul[i][0]); -- 2.17.1