Personal tools

Reducing CPU frequency in iMX8M processors

From SomLabs Wiki

Jump to: navigation, search

Reducing CPU frequency in iMX8M processors


In iMX8M processors a number of core operating frequencies can be defined in order to minimize the power consumption. This tutorial presents how to add additional frequencies to the default list and force the kernel driver to use the required one. It was prepared for the Yocto Scarthgap version with meta-somlabs layer.

The default available frequencies defined in dts files are:

  • 1200000000
  • 1600000000
  • 1800000000

Linux uses those values according to the computing power requirements and the currently used governor. The CPU frequency governors policies are described in the kernel docummentation:

https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt

By default the ondemand governor is used, which automatically chooses the required CPU frequency. It may be verified by reading the sysfs driver file.

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

Adding supported frequencies

In order to add more supported core frequencies the PLL driver needs to be modified, as well as the dts entries for the device. The following patch adds more available frequencies to the system configuration for iMX8Mmini and iMX8MPlus processors:

diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
index abd144c2ea7d..b1a285c41afe 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
@@ -156,6 +156,38 @@ a53_opp_table: opp-table {
                compatible = "operating-points-v2";
                opp-shared;

+               opp-100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0xe>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
+               opp-200000000 {
+                       opp-hz = /bits/ 64 <200000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0xe>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
+               opp-400000000 {
+                       opp-hz = /bits/ 64 <400000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0xe>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0xe>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
                opp-1200000000 {
                        opp-hz = /bits/ 64 <1200000000>;
                        opp-microvolt = <850000>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
index 9335f1713ce6..2b0f57418e66 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
@@ -166,6 +166,38 @@ a53_opp_table: opp-table {
                compatible = "operating-points-v2";
                opp-shared;

+               opp-100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0x8a0>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
+               opp-200000000 {
+                       opp-hz = /bits/ 64 <200000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0x8a0>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
+               opp-400000000 {
+                       opp-hz = /bits/ 64 <400000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0x8a0>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <850000>;
+                       opp-supported-hw = <0x8a0>, <0x7>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+
                opp-1200000000 {
                        opp-hz = /bits/ 64 <1200000000>;
                        opp-microvolt = <850000>;
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index 6c17786ecb9f..7701e6e2f4cc 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -56,7 +56,10 @@ static const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = {
        PLL_1416X_RATE(700000000U,  350, 3, 2),
        PLL_1416X_RATE(640000000U,  320, 3, 2),
        PLL_1416X_RATE(600000000U,  300, 3, 2),
+       PLL_1416X_RATE(400000000U,  200, 3, 2),
        PLL_1416X_RATE(320000000U,  160, 3, 2),
+       PLL_1416X_RATE(200000000U,  200, 3, 3),
+       PLL_1416X_RATE(100000000U,  200, 3, 4),
 };

 static const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {

Note that 800MHz frequency is already defined in the PLL driver. This driver sets the PLL parameters according to the defined macro:

PLL_1416X_RATE(Fout, M, P, S)

The Fout is calculated as follows:

Fout = 32MHz * M / (P * 2^S)

This patch can be added to meta-somlabs layer in order to build it together with the default system image. The created patch file should be placed in meta-somlabs/recipes-kernel/linux/linux-imx directory and the following line should be added to the the kernel recipe meta-somlabs/recipes-kernel/linux//linux-imx_6.6.bbappend:

SRC_URI += "file://frequency.patch"

The frequency.patch file should be changed according to the added patch file in linux-imx directory.

Verifying core frequency

Setting the core frequency can be easily tested using userspace governor which allows for manual configuration. The frequency is set in kHz. For example the following lines set the CPU frequency to 100MHz:

echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo 100000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

The execution time can be then measured using simple script:

echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo 100000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time bash -c "for i in {1..1000000}; do :; done"

real    2m39.501s
user    2m32.015s
sys     0m3.861s
echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo 1600000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time bash -c "for i in {1..1000000}; do :; done"

real    0m11.525s
user    0m11.154s
sys     0m0.330s