xref: /OK3568_Linux_fs/kernel/Documentation/driver-api/thermal/power_allocator.rst (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun=================================
2*4882a593SmuzhiyunPower allocator governor tunables
3*4882a593Smuzhiyun=================================
4*4882a593Smuzhiyun
5*4882a593SmuzhiyunTrip points
6*4882a593Smuzhiyun-----------
7*4882a593Smuzhiyun
8*4882a593SmuzhiyunThe governor works optimally with the following two passive trip points:
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun1.  "switch on" trip point: temperature above which the governor
11*4882a593Smuzhiyun    control loop starts operating.  This is the first passive trip
12*4882a593Smuzhiyun    point of the thermal zone.
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun2.  "desired temperature" trip point: it should be higher than the
15*4882a593Smuzhiyun    "switch on" trip point.  This the target temperature the governor
16*4882a593Smuzhiyun    is controlling for.  This is the last passive trip point of the
17*4882a593Smuzhiyun    thermal zone.
18*4882a593Smuzhiyun
19*4882a593SmuzhiyunPID Controller
20*4882a593Smuzhiyun--------------
21*4882a593Smuzhiyun
22*4882a593SmuzhiyunThe power allocator governor implements a
23*4882a593SmuzhiyunProportional-Integral-Derivative controller (PID controller) with
24*4882a593Smuzhiyuntemperature as the control input and power as the controlled output:
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun    P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power
27*4882a593Smuzhiyun
28*4882a593Smuzhiyunwhere
29*4882a593Smuzhiyun   -  e = desired_temperature - current_temperature
30*4882a593Smuzhiyun   -  err_integral is the sum of previous errors
31*4882a593Smuzhiyun   -  diff_err = e - previous_error
32*4882a593Smuzhiyun
33*4882a593SmuzhiyunIt is similar to the one depicted below::
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun				      k_d
36*4882a593Smuzhiyun				       |
37*4882a593Smuzhiyun  current_temp                         |
38*4882a593Smuzhiyun       |                               v
39*4882a593Smuzhiyun       |              +----------+   +---+
40*4882a593Smuzhiyun       |       +----->| diff_err |-->| X |------+
41*4882a593Smuzhiyun       |       |      +----------+   +---+      |
42*4882a593Smuzhiyun       |       |                                |      tdp        actor
43*4882a593Smuzhiyun       |       |                      k_i       |       |  get_requested_power()
44*4882a593Smuzhiyun       |       |                       |        |       |        |     |
45*4882a593Smuzhiyun       |       |                       |        |       |        |     | ...
46*4882a593Smuzhiyun       v       |                       v        v       v        v     v
47*4882a593Smuzhiyun     +---+     |      +-------+      +---+    +---+   +---+   +----------+
48*4882a593Smuzhiyun     | S |-----+----->| sum e |----->| X |--->| S |-->| S |-->|power     |
49*4882a593Smuzhiyun     +---+     |      +-------+      +---+    +---+   +---+   |allocation|
50*4882a593Smuzhiyun       ^       |                                ^             +----------+
51*4882a593Smuzhiyun       |       |                                |                |     |
52*4882a593Smuzhiyun       |       |        +---+                   |                |     |
53*4882a593Smuzhiyun       |       +------->| X |-------------------+                v     v
54*4882a593Smuzhiyun       |                +---+                               granted performance
55*4882a593Smuzhiyun  desired_temperature     ^
56*4882a593Smuzhiyun			  |
57*4882a593Smuzhiyun			  |
58*4882a593Smuzhiyun		      k_po/k_pu
59*4882a593Smuzhiyun
60*4882a593SmuzhiyunSustainable power
61*4882a593Smuzhiyun-----------------
62*4882a593Smuzhiyun
63*4882a593SmuzhiyunAn estimate of the sustainable dissipatable power (in mW) should be
64*4882a593Smuzhiyunprovided while registering the thermal zone.  This estimates the
65*4882a593Smuzhiyunsustained power that can be dissipated at the desired control
66*4882a593Smuzhiyuntemperature.  This is the maximum sustained power for allocation at
67*4882a593Smuzhiyunthe desired maximum temperature.  The actual sustained power can vary
68*4882a593Smuzhiyunfor a number of reasons.  The closed loop controller will take care of
69*4882a593Smuzhiyunvariations such as environmental conditions, and some factors related
70*4882a593Smuzhiyunto the speed-grade of the silicon.  `sustainable_power` is therefore
71*4882a593Smuzhiyunsimply an estimate, and may be tuned to affect the aggressiveness of
72*4882a593Smuzhiyunthe thermal ramp. For reference, the sustainable power of a 4" phone
73*4882a593Smuzhiyunis typically 2000mW, while on a 10" tablet is around 4500mW (may vary
74*4882a593Smuzhiyundepending on screen size).
75*4882a593Smuzhiyun
76*4882a593SmuzhiyunIf you are using device tree, do add it as a property of the
77*4882a593Smuzhiyunthermal-zone.  For example::
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun	thermal-zones {
80*4882a593Smuzhiyun		soc_thermal {
81*4882a593Smuzhiyun			polling-delay = <1000>;
82*4882a593Smuzhiyun			polling-delay-passive = <100>;
83*4882a593Smuzhiyun			sustainable-power = <2500>;
84*4882a593Smuzhiyun			...
85*4882a593Smuzhiyun
86*4882a593SmuzhiyunInstead, if the thermal zone is registered from the platform code, pass a
87*4882a593Smuzhiyun`thermal_zone_params` that has a `sustainable_power`.  If no
88*4882a593Smuzhiyun`thermal_zone_params` were being passed, then something like below
89*4882a593Smuzhiyunwill suffice::
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun	static const struct thermal_zone_params tz_params = {
92*4882a593Smuzhiyun		.sustainable_power = 3500,
93*4882a593Smuzhiyun	};
94*4882a593Smuzhiyun
95*4882a593Smuzhiyunand then pass `tz_params` as the 5th parameter to
96*4882a593Smuzhiyun`thermal_zone_device_register()`
97*4882a593Smuzhiyun
98*4882a593Smuzhiyunk_po and k_pu
99*4882a593Smuzhiyun-------------
100*4882a593Smuzhiyun
101*4882a593SmuzhiyunThe implementation of the PID controller in the power allocator
102*4882a593Smuzhiyunthermal governor allows the configuration of two proportional term
103*4882a593Smuzhiyunconstants: `k_po` and `k_pu`.  `k_po` is the proportional term
104*4882a593Smuzhiyunconstant during temperature overshoot periods (current temperature is
105*4882a593Smuzhiyunabove "desired temperature" trip point).  Conversely, `k_pu` is the
106*4882a593Smuzhiyunproportional term constant during temperature undershoot periods
107*4882a593Smuzhiyun(current temperature below "desired temperature" trip point).
108*4882a593Smuzhiyun
109*4882a593SmuzhiyunThese controls are intended as the primary mechanism for configuring
110*4882a593Smuzhiyunthe permitted thermal "ramp" of the system.  For instance, a lower
111*4882a593Smuzhiyun`k_pu` value will provide a slower ramp, at the cost of capping
112*4882a593Smuzhiyunavailable capacity at a low temperature.  On the other hand, a high
113*4882a593Smuzhiyunvalue of `k_pu` will result in the governor granting very high power
114*4882a593Smuzhiyunwhile temperature is low, and may lead to temperature overshooting.
115*4882a593Smuzhiyun
116*4882a593SmuzhiyunThe default value for `k_pu` is::
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun    2 * sustainable_power / (desired_temperature - switch_on_temp)
119*4882a593Smuzhiyun
120*4882a593SmuzhiyunThis means that at `switch_on_temp` the output of the controller's
121*4882a593Smuzhiyunproportional term will be 2 * `sustainable_power`.  The default value
122*4882a593Smuzhiyunfor `k_po` is::
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun    sustainable_power / (desired_temperature - switch_on_temp)
125*4882a593Smuzhiyun
126*4882a593SmuzhiyunFocusing on the proportional and feed forward values of the PID
127*4882a593Smuzhiyuncontroller equation we have::
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun    P_max = k_p * e + sustainable_power
130*4882a593Smuzhiyun
131*4882a593SmuzhiyunThe proportional term is proportional to the difference between the
132*4882a593Smuzhiyundesired temperature and the current one.  When the current temperature
133*4882a593Smuzhiyunis the desired one, then the proportional component is zero and
134*4882a593Smuzhiyun`P_max` = `sustainable_power`.  That is, the system should operate in
135*4882a593Smuzhiyunthermal equilibrium under constant load.  `sustainable_power` is only
136*4882a593Smuzhiyunan estimate, which is the reason for closed-loop control such as this.
137*4882a593Smuzhiyun
138*4882a593SmuzhiyunExpanding `k_pu` we get::
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun    P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on) +
141*4882a593Smuzhiyun	sustainable_power
142*4882a593Smuzhiyun
143*4882a593Smuzhiyunwhere:
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun    - T_set is the desired temperature
146*4882a593Smuzhiyun    - T is the current temperature
147*4882a593Smuzhiyun    - T_on is the switch on temperature
148*4882a593Smuzhiyun
149*4882a593SmuzhiyunWhen the current temperature is the switch_on temperature, the above
150*4882a593Smuzhiyunformula becomes::
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun    P_max = 2 * sustainable_power * (T_set - T_on) / (T_set - T_on) +
153*4882a593Smuzhiyun	sustainable_power = 2 * sustainable_power + sustainable_power =
154*4882a593Smuzhiyun	3 * sustainable_power
155*4882a593Smuzhiyun
156*4882a593SmuzhiyunTherefore, the proportional term alone linearly decreases power from
157*4882a593Smuzhiyun3 * `sustainable_power` to `sustainable_power` as the temperature
158*4882a593Smuzhiyunrises from the switch on temperature to the desired temperature.
159*4882a593Smuzhiyun
160*4882a593Smuzhiyunk_i and integral_cutoff
161*4882a593Smuzhiyun-----------------------
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun`k_i` configures the PID loop's integral term constant.  This term
164*4882a593Smuzhiyunallows the PID controller to compensate for long term drift and for
165*4882a593Smuzhiyunthe quantized nature of the output control: cooling devices can't set
166*4882a593Smuzhiyunthe exact power that the governor requests.  When the temperature
167*4882a593Smuzhiyunerror is below `integral_cutoff`, errors are accumulated in the
168*4882a593Smuzhiyunintegral term.  This term is then multiplied by `k_i` and the result
169*4882a593Smuzhiyunadded to the output of the controller.  Typically `k_i` is set low (1
170*4882a593Smuzhiyunor 2) and `integral_cutoff` is 0.
171*4882a593Smuzhiyun
172*4882a593Smuzhiyunk_d
173*4882a593Smuzhiyun---
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun`k_d` configures the PID loop's derivative term constant.  It's
176*4882a593Smuzhiyunrecommended to leave it as the default: 0.
177*4882a593Smuzhiyun
178*4882a593SmuzhiyunCooling device power API
179*4882a593Smuzhiyun========================
180*4882a593Smuzhiyun
181*4882a593SmuzhiyunCooling devices controlled by this governor must supply the additional
182*4882a593Smuzhiyun"power" API in their `cooling_device_ops`.  It consists on three ops:
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun1. ::
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun    int get_requested_power(struct thermal_cooling_device *cdev,
187*4882a593Smuzhiyun			    struct thermal_zone_device *tz, u32 *power);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun@cdev:
191*4882a593Smuzhiyun	The `struct thermal_cooling_device` pointer
192*4882a593Smuzhiyun@tz:
193*4882a593Smuzhiyun	thermal zone in which we are currently operating
194*4882a593Smuzhiyun@power:
195*4882a593Smuzhiyun	pointer in which to store the calculated power
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun`get_requested_power()` calculates the power requested by the device
198*4882a593Smuzhiyunin milliwatts and stores it in @power .  It should return 0 on
199*4882a593Smuzhiyunsuccess, -E* on failure.  This is currently used by the power
200*4882a593Smuzhiyunallocator governor to calculate how much power to give to each cooling
201*4882a593Smuzhiyundevice.
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun2. ::
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun	int state2power(struct thermal_cooling_device *cdev, struct
206*4882a593Smuzhiyun			thermal_zone_device *tz, unsigned long state,
207*4882a593Smuzhiyun			u32 *power);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun@cdev:
210*4882a593Smuzhiyun	The `struct thermal_cooling_device` pointer
211*4882a593Smuzhiyun@tz:
212*4882a593Smuzhiyun	thermal zone in which we are currently operating
213*4882a593Smuzhiyun@state:
214*4882a593Smuzhiyun	A cooling device state
215*4882a593Smuzhiyun@power:
216*4882a593Smuzhiyun	pointer in which to store the equivalent power
217*4882a593Smuzhiyun
218*4882a593SmuzhiyunConvert cooling device state @state into power consumption in
219*4882a593Smuzhiyunmilliwatts and store it in @power.  It should return 0 on success, -E*
220*4882a593Smuzhiyunon failure.  This is currently used by thermal core to calculate the
221*4882a593Smuzhiyunmaximum power that an actor can consume.
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun3. ::
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun	int power2state(struct thermal_cooling_device *cdev, u32 power,
226*4882a593Smuzhiyun			unsigned long *state);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun@cdev:
229*4882a593Smuzhiyun	The `struct thermal_cooling_device` pointer
230*4882a593Smuzhiyun@power:
231*4882a593Smuzhiyun	power in milliwatts
232*4882a593Smuzhiyun@state:
233*4882a593Smuzhiyun	pointer in which to store the resulting state
234*4882a593Smuzhiyun
235*4882a593SmuzhiyunCalculate a cooling device state that would make the device consume at
236*4882a593Smuzhiyunmost @power mW and store it in @state.  It should return 0 on success,
237*4882a593Smuzhiyun-E* on failure.  This is currently used by the thermal core to convert
238*4882a593Smuzhiyuna given power set by the power allocator governor to a state that the
239*4882a593Smuzhiyuncooling device can set.  It is a function because this conversion may
240*4882a593Smuzhiyundepend on external factors that may change so this function should the
241*4882a593Smuzhiyunbest conversion given "current circumstances".
242*4882a593Smuzhiyun
243*4882a593SmuzhiyunCooling device weights
244*4882a593Smuzhiyun----------------------
245*4882a593Smuzhiyun
246*4882a593SmuzhiyunWeights are a mechanism to bias the allocation among cooling
247*4882a593Smuzhiyundevices.  They express the relative power efficiency of different
248*4882a593Smuzhiyuncooling devices.  Higher weight can be used to express higher power
249*4882a593Smuzhiyunefficiency.  Weighting is relative such that if each cooling device
250*4882a593Smuzhiyunhas a weight of one they are considered equal.  This is particularly
251*4882a593Smuzhiyunuseful in heterogeneous systems where two cooling devices may perform
252*4882a593Smuzhiyunthe same kind of compute, but with different efficiency.  For example,
253*4882a593Smuzhiyuna system with two different types of processors.
254*4882a593Smuzhiyun
255*4882a593SmuzhiyunIf the thermal zone is registered using
256*4882a593Smuzhiyun`thermal_zone_device_register()` (i.e., platform code), then weights
257*4882a593Smuzhiyunare passed as part of the thermal zone's `thermal_bind_parameters`.
258*4882a593SmuzhiyunIf the platform is registered using device tree, then they are passed
259*4882a593Smuzhiyunas the `contribution` property of each map in the `cooling-maps` node.
260*4882a593Smuzhiyun
261*4882a593SmuzhiyunLimitations of the power allocator governor
262*4882a593Smuzhiyun===========================================
263*4882a593Smuzhiyun
264*4882a593SmuzhiyunThe power allocator governor's PID controller works best if there is a
265*4882a593Smuzhiyunperiodic tick.  If you have a driver that calls
266*4882a593Smuzhiyun`thermal_zone_device_update()` (or anything that ends up calling the
267*4882a593Smuzhiyungovernor's `throttle()` function) repetitively, the governor response
268*4882a593Smuzhiyunwon't be very good.  Note that this is not particular to this
269*4882a593Smuzhiyungovernor, step-wise will also misbehave if you call its throttle()
270*4882a593Smuzhiyunfaster than the normal thermal framework tick (due to interrupts for
271*4882a593Smuzhiyunexample) as it will overreact.
272