1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
From 4c8fb634216bf73fac117436e1b936557dc97793 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Sat, 13 Mar 2021 23:54:25 -0600
Subject: [PATCH] arm64: dts: allwinner: a64/h5: Add CPU idle states
Powering off idle CPUs saves about 30 mW compared to using WFI only.
Additional power savings are possible by idling the L2 and downclocking
the cluster when all CPUs are idle.
Entry and exit latency were measured using a logic analyzer, with GPIO
pins toggled in Linux after the calls to trace_cpu_idle() in
cpuidle_enter_state(), and in the power management firmware after CPU
power-off completes and immediately after detecting an interrupt.
800 us and 1500 us are worst-case values, largely driven by the fact
that the power management firmware is single threaded. It can only
handle commands to power off CPUs one at a time, and it cannot process
any commands while powering on a CPU in response to an interrupt.
The cluster suspend process reliably takes 36 us; I rounded this up to
50 us. If all CPUs enter the cluster idle state at the same time, exit
latency is actually reduced, because there is no contention in that
case. However, if only some CPUs enter the cluster idle state, behavior
is the same as for CPU idle.
Polling delay for the power management firmware to detect a pending
interrupt is insignificant; it is less than 20 us.
min-residency was chosen as the point where enabling the idle state
consumed no more average power than disabling the idle state at a
variety of interrupt rates.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 26 +++++++++++++++++++
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 26 +++++++++++++++++++
2 files changed, 52 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index cac47cc50..83b198d12 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -61,6 +61,7 @@ cpu0: cpu@0 {
clocks = <&ccu CLK_CPUX>;
clock-names = "cpu";
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
};
cpu1: cpu@1 {
@@ -72,6 +73,7 @@ cpu1: cpu@1 {
clocks = <&ccu CLK_CPUX>;
clock-names = "cpu";
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
};
cpu2: cpu@2 {
@@ -83,6 +85,7 @@ cpu2: cpu@2 {
clocks = <&ccu CLK_CPUX>;
clock-names = "cpu";
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
};
cpu3: cpu@3 {
@@ -94,6 +97,29 @@ cpu3: cpu@3 {
clocks = <&ccu CLK_CPUX>;
clock-names = "cpu";
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
+ };
+
+ idle-states {
+ entry-method = "psci";
+
+ cpu_sleep: cpu-sleep {
+ compatible = "arm,idle-state";
+ local-timer-stop;
+ entry-latency-us = <800>;
+ exit-latency-us = <1500>;
+ min-residency-us = <25000>;
+ arm,psci-suspend-param = <0x00010003>;
+ };
+
+ cluster_sleep: cluster-sleep {
+ compatible = "arm,idle-state";
+ local-timer-stop;
+ entry-latency-us = <850>;
+ exit-latency-us = <1500>;
+ min-residency-us = <50000>;
+ arm,psci-suspend-param = <0x01010013>;
+ };
};
L2: l2-cache {
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
index 62952660b..975a76a9f 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
@@ -24,6 +24,7 @@ cpu0: cpu@0 {
clocks = <&ccu CLK_CPUX>;
clock-latency-ns = <244144>; /* 8 32k periods */
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
};
cpu1: cpu@1 {
@@ -34,6 +35,7 @@ cpu1: cpu@1 {
clocks = <&ccu CLK_CPUX>;
clock-latency-ns = <244144>; /* 8 32k periods */
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
};
cpu2: cpu@2 {
@@ -44,6 +46,7 @@ cpu2: cpu@2 {
clocks = <&ccu CLK_CPUX>;
clock-latency-ns = <244144>; /* 8 32k periods */
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
};
cpu3: cpu@3 {
@@ -54,6 +57,29 @@ cpu3: cpu@3 {
clocks = <&ccu CLK_CPUX>;
clock-latency-ns = <244144>; /* 8 32k periods */
#cooling-cells = <2>;
+ cpu-idle-states = <&cpu_sleep>, <&cluster_sleep>;
+ };
+
+ idle-states {
+ entry-method = "psci";
+
+ cpu_sleep: cpu-sleep {
+ compatible = "arm,idle-state";
+ local-timer-stop;
+ entry-latency-us = <800>;
+ exit-latency-us = <1500>;
+ min-residency-us = <25000>;
+ arm,psci-suspend-param = <0x00010003>;
+ };
+
+ cluster_sleep: cluster-sleep {
+ compatible = "arm,idle-state";
+ local-timer-stop;
+ entry-latency-us = <850>;
+ exit-latency-us = <1500>;
+ min-residency-us = <50000>;
+ arm,psci-suspend-param = <0x01010013>;
+ };
};
};
--
2.39.0
|