1 // SPDX-License-Identifier: GPL-2.0-only
3 * Windfarm PowerMac thermal control. Generic PID helpers
5 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
6 * <benh@kernel.crashing.org>
9 #include <linux/types.h>
10 #include <linux/errno.h>
11 #include <linux/kernel.h>
12 #include <linux/string.h>
13 #include <linux/module.h>
15 #include "windfarm_pid.h"
20 #define DBG(args...) printk(args)
22 #define DBG(args...) do { } while(0)
25 void wf_pid_init(struct wf_pid_state
*st
, struct wf_pid_param
*param
)
27 memset(st
, 0, sizeof(struct wf_pid_state
));
31 EXPORT_SYMBOL_GPL(wf_pid_init
);
33 s32
wf_pid_run(struct wf_pid_state
*st
, s32 new_sample
)
35 s64 error
, integ
, deriv
;
37 int i
, hlen
= st
->param
.history_len
;
39 /* Calculate error term */
40 error
= new_sample
- st
->param
.itarget
;
42 /* Get samples into our history buffer */
44 for (i
= 0; i
< hlen
; i
++) {
45 st
->samples
[i
] = new_sample
;
46 st
->errors
[i
] = error
;
51 st
->index
= (st
->index
+ 1) % hlen
;
52 st
->samples
[st
->index
] = new_sample
;
53 st
->errors
[st
->index
] = error
;
56 /* Calculate integral term */
57 for (i
= 0, integ
= 0; i
< hlen
; i
++)
58 integ
+= st
->errors
[(st
->index
+ hlen
- i
) % hlen
];
59 integ
*= st
->param
.interval
;
61 /* Calculate derivative term */
62 deriv
= st
->errors
[st
->index
] -
63 st
->errors
[(st
->index
+ hlen
- 1) % hlen
];
64 deriv
/= st
->param
.interval
;
66 /* Calculate target */
67 target
= (s32
)((integ
* (s64
)st
->param
.gr
+ deriv
* (s64
)st
->param
.gd
+
68 error
* (s64
)st
->param
.gp
) >> 36);
69 if (st
->param
.additive
)
71 target
= max(target
, st
->param
.min
);
72 target
= min(target
, st
->param
.max
);
77 EXPORT_SYMBOL_GPL(wf_pid_run
);
79 void wf_cpu_pid_init(struct wf_cpu_pid_state
*st
,
80 struct wf_cpu_pid_param
*param
)
82 memset(st
, 0, sizeof(struct wf_cpu_pid_state
));
86 EXPORT_SYMBOL_GPL(wf_cpu_pid_init
);
88 s32
wf_cpu_pid_run(struct wf_cpu_pid_state
*st
, s32 new_power
, s32 new_temp
)
90 s64 integ
, deriv
, prop
;
91 s32 error
, target
, sval
, adj
;
92 int i
, hlen
= st
->param
.history_len
;
94 /* Calculate error term */
95 error
= st
->param
.pmaxadj
- new_power
;
97 /* Get samples into our history buffer */
99 for (i
= 0; i
< hlen
; i
++) {
100 st
->powers
[i
] = new_power
;
101 st
->errors
[i
] = error
;
103 st
->temps
[0] = st
->temps
[1] = new_temp
;
105 st
->index
= st
->tindex
= 0;
107 st
->index
= (st
->index
+ 1) % hlen
;
108 st
->powers
[st
->index
] = new_power
;
109 st
->errors
[st
->index
] = error
;
110 st
->tindex
= (st
->tindex
+ 1) % 2;
111 st
->temps
[st
->tindex
] = new_temp
;
114 /* Calculate integral term */
115 for (i
= 0, integ
= 0; i
< hlen
; i
++)
116 integ
+= st
->errors
[(st
->index
+ hlen
- i
) % hlen
];
117 integ
*= st
->param
.interval
;
118 integ
*= st
->param
.gr
;
119 sval
= st
->param
.tmax
- (s32
)(integ
>> 20);
120 adj
= min(st
->param
.ttarget
, sval
);
122 DBG("integ: %lx, sval: %lx, adj: %lx\n", integ
, sval
, adj
);
124 /* Calculate derivative term */
125 deriv
= st
->temps
[st
->tindex
] -
126 st
->temps
[(st
->tindex
+ 2 - 1) % 2];
127 deriv
/= st
->param
.interval
;
128 deriv
*= st
->param
.gd
;
130 /* Calculate proportional term */
131 prop
= st
->last_delta
= (new_temp
- adj
);
132 prop
*= st
->param
.gp
;
134 DBG("deriv: %lx, prop: %lx\n", deriv
, prop
);
136 /* Calculate target */
137 target
= st
->target
+ (s32
)((deriv
+ prop
) >> 36);
138 target
= max(target
, st
->param
.min
);
139 target
= min(target
, st
->param
.max
);
144 EXPORT_SYMBOL_GPL(wf_cpu_pid_run
);
146 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
147 MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control");
148 MODULE_LICENSE("GPL");