MLK-16804-08 driver: soc: Reduce NOC/AHB/MAIN_AXI to save SOC power for audio playback
authorAnson Huang <Anson.Huang@nxp.com>
Wed, 8 Nov 2017 10:17:22 +0000 (18:17 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:46:54 +0000 (15:46 -0500)
reduce the NOC, main AXI and AHB bus clock frequency to save power when DDR enter low
frequency mode. VDDSOC is ~195mA during video play, and ~180mA in idle.

Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Signed-off-by: Bai Ping <ping.bai@nxp.com>
arch/arm64/boot/dts/freescale/fsl-imx8mq.dtsi
drivers/clk/imx/clk-imx8mq.c
drivers/soc/imx/busfreq-imx8mq.c

index 2245766..117d663 100644 (file)
                         <&clk IMX8MQ_CLK_DRAM_APB_SRC>, <&clk IMX8MQ_CLK_DRAM_APB_PRE_DIV>,
                         <&clk IMX8MQ_CLK_DRAM_CORE>, <&clk IMX8MQ_CLK_DRAM_ALT_ROOT>,
                         <&clk IMX8MQ_SYS1_PLL_40M>, <&clk IMX8MQ_SYS1_PLL_400M>,
-                        <&clk IMX8MQ_SYS1_PLL_100M>, <&clk IMX8MQ_SYS1_PLL_800M>;
+                        <&clk IMX8MQ_SYS1_PLL_100M>, <&clk IMX8MQ_SYS1_PLL_800M>,
+                        <&clk IMX8MQ_CLK_NOC_DIV>, <&clk IMX8MQ_CLK_MAIN_AXI_SRC>,
+                        <&clk IMX8MQ_CLK_AHB_DIV>, <&clk IMX8MQ_CLK_25M>,
+                        <&clk IMX8MQ_SYS2_PLL_333M>, <&clk IMX8MQ_SYS1_PLL_133M>;
                clock-names = "dram_pll", "dram_alt_src", "dram_apb_src", "dram_apb_pre_div",
                              "dram_core", "dram_alt_root", "sys1_pll_40m", "sys1_pll_400m",
-                             "sys1_pll_100m", "sys1_pll_800m";
+                             "sys1_pll_100m", "sys1_pll_800m", "noc_div", "main_axi_src",
+                             "ahb_div", "osc_25m", "sys2_pll_333m", "sys1_pll_133m";
                interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-name = "irq_busfreq_0", "irq_busfreq_1", "irq_busfreq_2", "irq_busfreq_3";
index a10b76d..7f8c32a 100644 (file)
@@ -500,7 +500,7 @@ static void __init imx8mq_clocks_init(struct device_node *ccm_node)
        clks[IMX8MQ_CLK_AUDIO_AHB_CG] = imx_clk_gate3("audio_ahb_cg", "audio_ahb_src", base + 0x9100, 28);
        clks[IMX8MQ_CLK_AHB_PRE_DIV] = imx_clk_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
        clks[IMX8MQ_CLK_AUDIO_AHB_PRE_DIV] = imx_clk_divider2("audio_ahb_pre_div", "audio_ahb_cg", base + 0x9100, 16, 3);
-       clks[IMX8MQ_CLK_AHB_DIV] = imx_clk_divider2("ahb_div", "ahb_pre_div", base + 0x9000, 0, 6);
+       clks[IMX8MQ_CLK_AHB_DIV] = imx_clk_divider_flags("ahb_div", "ahb_pre_div", base + 0x9000, 0, 6, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
        clks[IMX8MQ_CLK_AUDIO_AHB_DIV] = imx_clk_divider2("audio_ahb_div", "audio_ahb_pre_div", base + 0x9100, 0, 6);
 
        /* IPG */
index 4054c37..3f11600 100644 (file)
@@ -60,6 +60,11 @@ static struct clk *dram_alt_root;
 static struct clk *dram_core_clk;
 static struct clk *dram_apb_src;
 static struct clk *dram_apb_pre_div;
+static struct clk *noc_div;
+static struct clk *main_axi_src;
+static struct clk *ahb_div;
+static struct clk *osc_25m;
+static struct clk *sys2_pll_333m;
 
 static struct delayed_work low_bus_freq_handler;
 static struct delayed_work bus_freq_daemon;
@@ -118,6 +123,10 @@ static void reduce_bus_freq(void)
                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);
+               /* reduce the NOC & bus clock */
+               clk_set_rate(noc_div, clk_get_rate(noc_div) / 8);
+               clk_set_rate(ahb_div, clk_get_rate(ahb_div) / 6);
+               clk_set_parent(main_axi_src, osc_25m);
 
                low_bus_freq_mode = 0;
                audio_bus_freq_mode = 1;
@@ -134,6 +143,10 @@ static void reduce_bus_freq(void)
                clk_set_parent(dram_apb_src, sys1_pll_40m);
                clk_set_rate(dram_apb_pre_div, 20000000);
                clk_prepare_enable(sys1_pll_400m);
+               /* reduce the NOC & bus clock */
+               clk_set_rate(noc_div, clk_get_rate(noc_div) / 8);
+               clk_set_rate(ahb_div, clk_get_rate(ahb_div) / 6);
+               clk_set_parent(main_axi_src, osc_25m);
 
                low_bus_freq_mode = 1;
                audio_bus_freq_mode = 0;
@@ -178,7 +191,7 @@ static int set_low_bus_freq(void)
                reduce_bus_freq();
        else
                schedule_delayed_work(&low_bus_freq_handler,
-                                       usecs_to_jiffies(3000000));
+                                       usecs_to_jiffies(1000000));
 
        return 0;
 }
@@ -216,6 +229,9 @@ 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, 800000000);
+       clk_set_rate(ahb_div, 133333333);
+       clk_set_parent(main_axi_src, sys2_pll_333m);
 
        high_bus_freq_mode = 1;
        audio_bus_freq_mode = 0;
@@ -446,10 +462,17 @@ static int init_busfreq_clk(struct platform_device *pdev)
        dram_core_clk = devm_clk_get(&pdev->dev, "dram_core");
        dram_apb_src = devm_clk_get(&pdev->dev, "dram_apb_src");
        dram_apb_pre_div = devm_clk_get(&pdev->dev, "dram_apb_pre_div");
+       noc_div = devm_clk_get(&pdev->dev, "noc_div");
+       ahb_div = devm_clk_get(&pdev->dev, "ahb_div");
+       main_axi_src = devm_clk_get(&pdev->dev, "main_axi_src");
+       osc_25m = devm_clk_get(&pdev->dev, "osc_25m");
+       sys2_pll_333m = devm_clk_get(&pdev->dev, "sys2_pll_333m");
 
        if (IS_ERR(dram_pll_clk) || IS_ERR(sys1_pll_400m) || IS_ERR(sys1_pll_100m) ||
            IS_ERR(sys1_pll_40m) || IS_ERR(dram_alt_src) || IS_ERR(dram_alt_root) ||
-           IS_ERR(dram_core_clk) || IS_ERR(dram_apb_src) || IS_ERR(dram_apb_pre_div)) {
+           IS_ERR(dram_core_clk) || IS_ERR(dram_apb_src) || IS_ERR(dram_apb_pre_div)
+           || IS_ERR(noc_div) || IS_ERR(main_axi_src) || IS_ERR(ahb_div)
+           || IS_ERR(osc_25m) || IS_ERR(sys2_pll_333m)) {
                dev_err(&pdev->dev, "failed to get busfreq clk\n");
                return -EINVAL;
        }