diff options
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/imx/busfreq-imx8mq.c | 202 |
1 files changed, 85 insertions, 117 deletions
diff --git a/drivers/soc/imx/busfreq-imx8mq.c b/drivers/soc/imx/busfreq-imx8mq.c index 441d5229f5c3..28fd6cb4fd46 100644 --- a/drivers/soc/imx/busfreq-imx8mq.c +++ b/drivers/soc/imx/busfreq-imx8mq.c @@ -41,6 +41,7 @@ #define LOW_BUS_FREQ_100MTS 0x2 #define LOW_BUS_FREQ_667MTS 0x1 #define WAIT_BUS_FREQ_DONE 0xf +#define DLL_ON_DRATE 667 static struct device *busfreq_dev; static int low_bus_freq_mode; @@ -53,6 +54,12 @@ static int cur_bus_freq_mode; static int busfreq_suspended; static bool cancel_reduce_bus_freq; +static unsigned int fsp_table[4]; +static unsigned long origin_noc_rate; +static int low_bus_mode_fsp_index; +/* no bypass or dll off mode support if lowest fsp > 667mts */ +static bool bypass_support = true; + static struct clk *dram_pll_clk; static struct clk *sys1_pll_800m; static struct clk *sys1_pll_400m; @@ -115,50 +122,14 @@ static void reduce_bus_freq(void) */ if (audio_bus_count) { if (cur_bus_freq_mode == BUS_FREQ_HIGH) { - - if (of_machine_is_compatible("fsl,imx8mq")) { - if (imx8_get_soc_revision() < IMX_CHIP_REVISION_2_1) { - update_bus_freq(LOW_BUS_FREQ_667MTS); - - /* - * the dram_apb and dram_core clk rate is changed - * in ATF side, below two lines of code is just used - * to upate the clock tree info in kernel side. - */ - clk_set_rate(dram_apb_pre_div, 160000000); - clk_get_rate(dram_pll_clk); - } else { - /* prepare the necessary clk before frequency change */ - clk_prepare_enable(sys1_pll_40m); - clk_prepare_enable(dram_alt_root); - clk_prepare_enable(sys1_pll_100m); - - update_bus_freq(LOW_BUS_FREQ_100MTS); - - clk_set_parent(dram_alt_src, sys1_pll_100m); - clk_set_parent(dram_core_clk, dram_alt_root); - clk_set_parent(dram_apb_src, sys1_pll_40m); - clk_set_rate(dram_apb_pre_div, 20000000); - clk_disable_unprepare(sys1_pll_100m); - clk_disable_unprepare(sys1_pll_40m); - clk_disable_unprepare(dram_alt_root); - } - /* reduce the NOC & bus clock */ - rate = clk_get_rate(noc_div); - if (rate == 0) { - WARN_ON(1); - return; - } - clk_set_rate(noc_div, rate / 8); - } else { + if (bypass_support) { /* prepare the necessary clk before frequency change */ clk_prepare_enable(sys1_pll_40m); clk_prepare_enable(dram_alt_root); clk_prepare_enable(sys1_pll_100m); - update_bus_freq(LOW_BUS_FREQ_100MTS); + update_bus_freq(low_bus_mode_fsp_index); - /* correct the clock tree info */ clk_set_parent(dram_alt_src, sys1_pll_100m); clk_set_parent(dram_core_clk, dram_alt_root); clk_set_parent(dram_apb_src, sys1_pll_40m); @@ -166,15 +137,22 @@ static void reduce_bus_freq(void) clk_disable_unprepare(sys1_pll_100m); clk_disable_unprepare(sys1_pll_40m); clk_disable_unprepare(dram_alt_root); - - /* change the NOC rate */ - rate = clk_get_rate(noc_div); - if (rate == 0) { - WARN_ON(1); - return; - } - clk_set_rate(noc_div, rate / 5); + } else { + update_bus_freq(low_bus_mode_fsp_index); + /* + * the dram_apb and dram_core clk rate is changed + * in ATF side, below two lines of code is just used + * to update the clock tree info in kernel side. + */ + clk_set_rate(dram_apb_pre_div, 160000000); + clk_get_rate(dram_pll_clk); } + /* change the NOC rate */ + if (of_machine_is_compatible("fsl,imx8mq")) + clk_set_rate(noc_div, origin_noc_rate / 8); + else + clk_set_rate(noc_div, origin_noc_rate / 5); + rate = clk_get_rate(ahb_div); if (rate == 0) { WARN_ON(1); @@ -189,49 +167,14 @@ static void reduce_bus_freq(void) cur_bus_freq_mode = BUS_FREQ_AUDIO; } else { if (cur_bus_freq_mode == BUS_FREQ_HIGH) { - if (of_machine_is_compatible("fsl,imx8mq")) { - if (imx8_get_soc_revision() < IMX_CHIP_REVISION_2_1) { - update_bus_freq(LOW_BUS_FREQ_667MTS); - - /* - * the dram_apb and dram_core clk rate is changed - * in ATF side, below two lines of code is just used - * to upate the clock tree info in kernel side. - */ - clk_set_rate(dram_apb_pre_div, 160000000); - clk_get_rate(dram_pll_clk); - } else { - /* prepare the necessary clk before frequency change */ - clk_prepare_enable(sys1_pll_40m); - clk_prepare_enable(dram_alt_root); - clk_prepare_enable(sys1_pll_100m); - - update_bus_freq(LOW_BUS_FREQ_100MTS); - - clk_set_parent(dram_alt_src, sys1_pll_100m); - clk_set_parent(dram_core_clk, dram_alt_root); - clk_set_parent(dram_apb_src, sys1_pll_40m); - clk_set_rate(dram_apb_pre_div, 20000000); - clk_disable_unprepare(sys1_pll_100m); - clk_disable_unprepare(sys1_pll_40m); - clk_disable_unprepare(dram_alt_root); - } - /* reduce the NOC & bus clock */ - rate = clk_get_rate(noc_div); - if (rate == 0) { - WARN_ON(1); - return; - } - clk_set_rate(noc_div, rate / 8); - } else { + if (bypass_support) { /* prepare the necessary clk before frequency change */ clk_prepare_enable(sys1_pll_40m); clk_prepare_enable(dram_alt_root); clk_prepare_enable(sys1_pll_100m); - update_bus_freq(LOW_BUS_FREQ_100MTS); + update_bus_freq(low_bus_mode_fsp_index); - /* correct the clock tree info */ clk_set_parent(dram_alt_src, sys1_pll_100m); clk_set_parent(dram_core_clk, dram_alt_root); clk_set_parent(dram_apb_src, sys1_pll_40m); @@ -239,16 +182,23 @@ static void reduce_bus_freq(void) clk_disable_unprepare(sys1_pll_100m); clk_disable_unprepare(sys1_pll_40m); clk_disable_unprepare(dram_alt_root); - - /* change the NOC clock rate */ - rate = clk_get_rate(noc_div); - if (rate == 0) { - WARN_ON(1); - return; - } - clk_set_rate(noc_div, rate / 5); + } else { + update_bus_freq(low_bus_mode_fsp_index); + /* + * the dram_apb and dram_core clk rate is changed + * in ATF side, below two lines of code is just used + * to update the clock tree info in kernel side. + */ + clk_set_rate(dram_apb_pre_div, 160000000); + clk_get_rate(dram_pll_clk); } + /* change the NOC rate */ + if (of_machine_is_compatible("fsl,imx8mq")) + clk_set_rate(noc_div, origin_noc_rate / 8); + else + clk_set_rate(noc_div, origin_noc_rate / 5); + rate = clk_get_rate(ahb_div); if (rate == 0) { WARN_ON(1); @@ -323,30 +273,7 @@ static int set_high_bus_freq(int high_bus_freq) if (high_bus_freq_mode) return 0; - if (of_machine_is_compatible("fsl,imx8mq")) { - if (imx8_get_soc_revision() < IMX_CHIP_REVISION_2_1) { - /* switch the DDR freqeuncy */ - update_bus_freq(HIGH_FREQ_3200MTS); - - clk_set_rate(dram_apb_pre_div, 200000000); - clk_get_rate(dram_pll_clk); - } else { - /* enable the clks needed in frequency */ - clk_prepare_enable(sys1_pll_800m); - clk_prepare_enable(dram_pll_clk); - - /* switch the DDR freqeuncy */ - update_bus_freq(HIGH_FREQ_3200MTS); - - /* correct the clock tree info */ - clk_set_parent(dram_apb_src, sys1_pll_800m); - clk_set_rate(dram_apb_pre_div, 160000000); - clk_set_parent(dram_core_clk, dram_pll_clk); - clk_disable_unprepare(sys1_pll_800m); - clk_disable_unprepare(dram_pll_clk); - } - clk_set_rate(noc_div, 800000000); - } else { + if (bypass_support) { /* enable the clks needed in frequency */ clk_prepare_enable(sys1_pll_800m); clk_prepare_enable(dram_pll_clk); @@ -360,9 +287,15 @@ static int set_high_bus_freq(int high_bus_freq) clk_set_parent(dram_core_clk, dram_pll_clk); clk_disable_unprepare(sys1_pll_800m); clk_disable_unprepare(dram_pll_clk); - clk_set_rate(noc_div, 750000000); + } else { + /* switch the DDR freqeuncy */ + update_bus_freq(HIGH_FREQ_3200MTS); + + clk_set_rate(dram_apb_pre_div, 200000000); + clk_get_rate(dram_pll_clk); } + clk_set_rate(noc_div, origin_noc_rate); clk_set_rate(ahb_div, 133333333); clk_set_parent(main_axi_src, sys2_pll_333m); @@ -651,9 +584,11 @@ static int imx8mm_init_busfreq_clk(struct platform_device *pdev) * @return The function returns 0 on success * */ + static int busfreq_probe(struct platform_device *pdev) { - int err; + int i, err; + struct arm_smccc_res res; busfreq_dev = &pdev->dev; @@ -668,6 +603,39 @@ static int busfreq_probe(struct platform_device *pdev) return err; } + origin_noc_rate = clk_get_rate(noc_div); + if (origin_noc_rate == 0) { + WARN_ON(1); + return -EINVAL; + } + + /* + * Get the supported frequency, normally the lowest frequency point + * is used for low bus & audio bus mode. + */ + for (i = 0; i < 4; i++) { + arm_smccc_smc(FSL_SIP_DDR_DVFS, 0x11, i, 0, 0, 0, 0, 0, &res); + err = res.a0; + if (err < 0) + return -EINVAL; + + fsp_table[i] = res.a0; + } + + /* get the lowest fsp index */ + for (i = 0; i < 4; i++) + if (fsp_table[i] == 0) + break; + + low_bus_mode_fsp_index = i - 1; + + /* + * if lowest fsp data rate higher than 666mts, then no dll off mode or + * bypass mode support. + */ + if (fsp_table[low_bus_mode_fsp_index] >= DLL_ON_DRATE) + bypass_support = false; + /* init the irq used for ddr frequency change */ err = init_busfreq_irq(pdev); if (err) { |