mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.7 KiB
148 lines
3.7 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* Windfarm PowerMac thermal control. Generic PID helpers |
|
* |
|
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. |
|
* <[email protected]> |
|
*/ |
|
|
|
#include <linux/types.h> |
|
#include <linux/errno.h> |
|
#include <linux/kernel.h> |
|
#include <linux/string.h> |
|
#include <linux/module.h> |
|
|
|
#include "windfarm_pid.h" |
|
|
|
#undef DEBUG |
|
|
|
#ifdef DEBUG |
|
#define DBG(args...) printk(args) |
|
#else |
|
#define DBG(args...) do { } while(0) |
|
#endif |
|
|
|
void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param) |
|
{ |
|
memset(st, 0, sizeof(struct wf_pid_state)); |
|
st->param = *param; |
|
st->first = 1; |
|
} |
|
EXPORT_SYMBOL_GPL(wf_pid_init); |
|
|
|
s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample) |
|
{ |
|
s64 error, integ, deriv; |
|
s32 target; |
|
int i, hlen = st->param.history_len; |
|
|
|
/* Calculate error term */ |
|
error = new_sample - st->param.itarget; |
|
|
|
/* Get samples into our history buffer */ |
|
if (st->first) { |
|
for (i = 0; i < hlen; i++) { |
|
st->samples[i] = new_sample; |
|
st->errors[i] = error; |
|
} |
|
st->first = 0; |
|
st->index = 0; |
|
} else { |
|
st->index = (st->index + 1) % hlen; |
|
st->samples[st->index] = new_sample; |
|
st->errors[st->index] = error; |
|
} |
|
|
|
/* Calculate integral term */ |
|
for (i = 0, integ = 0; i < hlen; i++) |
|
integ += st->errors[(st->index + hlen - i) % hlen]; |
|
integ *= st->param.interval; |
|
|
|
/* Calculate derivative term */ |
|
deriv = st->errors[st->index] - |
|
st->errors[(st->index + hlen - 1) % hlen]; |
|
deriv /= st->param.interval; |
|
|
|
/* Calculate target */ |
|
target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd + |
|
error * (s64)st->param.gp) >> 36); |
|
if (st->param.additive) |
|
target += st->target; |
|
target = max(target, st->param.min); |
|
target = min(target, st->param.max); |
|
st->target = target; |
|
|
|
return st->target; |
|
} |
|
EXPORT_SYMBOL_GPL(wf_pid_run); |
|
|
|
void wf_cpu_pid_init(struct wf_cpu_pid_state *st, |
|
struct wf_cpu_pid_param *param) |
|
{ |
|
memset(st, 0, sizeof(struct wf_cpu_pid_state)); |
|
st->param = *param; |
|
st->first = 1; |
|
} |
|
EXPORT_SYMBOL_GPL(wf_cpu_pid_init); |
|
|
|
s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp) |
|
{ |
|
s64 integ, deriv, prop; |
|
s32 error, target, sval, adj; |
|
int i, hlen = st->param.history_len; |
|
|
|
/* Calculate error term */ |
|
error = st->param.pmaxadj - new_power; |
|
|
|
/* Get samples into our history buffer */ |
|
if (st->first) { |
|
for (i = 0; i < hlen; i++) { |
|
st->powers[i] = new_power; |
|
st->errors[i] = error; |
|
} |
|
st->temps[0] = st->temps[1] = new_temp; |
|
st->first = 0; |
|
st->index = st->tindex = 0; |
|
} else { |
|
st->index = (st->index + 1) % hlen; |
|
st->powers[st->index] = new_power; |
|
st->errors[st->index] = error; |
|
st->tindex = (st->tindex + 1) % 2; |
|
st->temps[st->tindex] = new_temp; |
|
} |
|
|
|
/* Calculate integral term */ |
|
for (i = 0, integ = 0; i < hlen; i++) |
|
integ += st->errors[(st->index + hlen - i) % hlen]; |
|
integ *= st->param.interval; |
|
integ *= st->param.gr; |
|
sval = st->param.tmax - (s32)(integ >> 20); |
|
adj = min(st->param.ttarget, sval); |
|
|
|
DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj); |
|
|
|
/* Calculate derivative term */ |
|
deriv = st->temps[st->tindex] - |
|
st->temps[(st->tindex + 2 - 1) % 2]; |
|
deriv /= st->param.interval; |
|
deriv *= st->param.gd; |
|
|
|
/* Calculate proportional term */ |
|
prop = st->last_delta = (new_temp - adj); |
|
prop *= st->param.gp; |
|
|
|
DBG("deriv: %lx, prop: %lx\n", deriv, prop); |
|
|
|
/* Calculate target */ |
|
target = st->target + (s32)((deriv + prop) >> 36); |
|
target = max(target, st->param.min); |
|
target = min(target, st->param.max); |
|
st->target = target; |
|
|
|
return st->target; |
|
} |
|
EXPORT_SYMBOL_GPL(wf_cpu_pid_run); |
|
|
|
MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>"); |
|
MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control"); |
|
MODULE_LICENSE("GPL");
|
|
|