^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Windfarm PowerMac thermal control. iMac G5 iSight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * PowerMac12,1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * ============
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * The algorithm used is the PID control algorithm, used the same way
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * the published Darwin code does, using the same values that are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * present in the Darwin 8.10 snapshot property lists (note however
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * that none of the code has been re-used, it's a complete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * re-implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * 17" while Model 3 is iMac G5 20". They do have both the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * controls with a tiny difference. The control-ids of hard-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * and cpu-fan is swapped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Target Correction :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * controls have a target correction calculated as :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * new_value = max(new_value, max(new_min, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * OD Fan control correction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * # model_id: 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * offset : -19563152
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * slope : 1956315
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * # model_id: 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * offset : -15650652
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * slope : 1565065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * HD Fan control correction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * # model_id: 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * offset : -15650652
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * slope : 1565065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * # model_id: 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * offset : -19563152
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * slope : 1956315
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * CPU Fan control correction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * # model_id: 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * offset : -25431900
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * slope : 2543190
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * # model_id: 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * offset : -15650652
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * slope : 1565065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * Target rubber-banding :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Some controls have a target correction which depends on another
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * control value. The correction is computed in the following way :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * new_min = ref_value * slope + offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * ref_value is the value of the reference control. If new_min is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * greater than 0, then we correct the target value using :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * new_target = max (new_target, new_min >> 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * # model_id : 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * control : cpu-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * ref : optical-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * offset : -15650652
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * slope : 1565065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * # model_id : 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * control : optical-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * ref : hard-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * offset : -32768000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * slope : 65536
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * In order to have the moste efficient correction with those
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * dependencies, we must trigger HD loop before OD loop before CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * The various control loops found in Darwin config file are:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * HD Fan control loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * # model_id: 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * control : hard-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * sensor : hard-drive-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * G_p = 0x002D70A3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Input target = 0x370000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * # model_id: 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * control : hard-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * sensor : hard-drive-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * G_p = 0x002170A3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * Input target = 0x370000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * OD Fan control loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * # model_id: 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * control : optical-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * sensor : optical-drive-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * G_p = 0x001FAE14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * Input target = 0x320000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * # model_id: 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * control : optical-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * sensor : optical-drive-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * G_p = 0x001FAE14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * Input target = 0x320000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * GPU Fan control loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * # model_id: 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * control : hard-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * sensor : gpu-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * G_p = 0x002A6666
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * Input target = 0x5A0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * # model_id: 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * control : cpu-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * sensor : gpu-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * G_p = 0x0010CCCC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * Input target = 0x500000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * KODIAK (aka northbridge) Fan control loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * # model_id: 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * control : optical-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * sensor : north-bridge-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * G_p = 0x003BD70A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * Input target = 0x550000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * # model_id: 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * control : hard-drive-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * sensor : north-bridge-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * PID params : G_d = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * G_p = 0x0030F5C2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * G_r = 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * History = 2 entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * Input target = 0x550000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * Interval = 5s
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * CPU Fan control loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * control : cpu-fan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * sensors : cpu-temp, cpu-power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * PID params : from SDB partition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * CPU Slew control loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * control : cpufreq-clamp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * sensor : cpu-temp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) #include <linux/kmod.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) #include <asm/machdep.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) #include <asm/smu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) #include "windfarm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #include "windfarm_pid.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) #define VERSION "0.3"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static int pm121_mach_model; /* machine model id */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* Controls & sensors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static struct wf_sensor *sensor_cpu_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static struct wf_sensor *sensor_cpu_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static struct wf_sensor *sensor_cpu_voltage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static struct wf_sensor *sensor_cpu_current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) static struct wf_sensor *sensor_gpu_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static struct wf_sensor *sensor_north_bridge_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static struct wf_sensor *sensor_hard_drive_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static struct wf_sensor *sensor_optical_drive_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) FAN_CPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) FAN_HD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) FAN_OD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) CPUFREQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) N_CONTROLS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static struct wf_control *controls[N_CONTROLS] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* Set to kick the control loop into life */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static int pm121_all_controls_ok, pm121_all_sensors_ok;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static bool pm121_started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) FAILURE_FAN = 1 << 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) FAILURE_SENSOR = 1 << 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) FAILURE_OVERTEMP = 1 << 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* All sys loops. Note the HD before the OD loop in order to have it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) run before. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) LOOP_GPU, /* control = hd or cpu, but luckily,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) it doesn't matter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) LOOP_HD, /* control = hd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) LOOP_KODIAK, /* control = hd or od */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) LOOP_OD, /* control = od */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) N_LOOPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static const char *loop_names[N_LOOPS] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) "GPU",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) "HD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) "KODIAK",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) "OD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) #define PM121_NUM_CONFIGS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static unsigned int pm121_failure_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static int pm121_readjust, pm121_skipping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static bool pm121_overtemp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static s32 average_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct pm121_correction {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) int slope;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /* FAN_OD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* MODEL 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) { .offset = -19563152,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .slope = 1956315
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /* MODEL 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) { .offset = -15650652,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) .slope = 1565065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* FAN_HD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* MODEL 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) { .offset = -15650652,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) .slope = 1565065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) /* MODEL 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) { .offset = -19563152,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .slope = 1956315
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /* FAN_CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* MODEL 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) { .offset = -25431900,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) .slope = 2543190
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* MODEL 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) { .offset = -15650652,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .slope = 1565065
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* CPUFREQ has no correction (and is not implemented at all) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct pm121_connection {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) unsigned int control_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) unsigned int ref_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) struct pm121_correction correction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static struct pm121_connection pm121_connections[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* MODEL 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) { .control_id = FAN_CPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .ref_id = FAN_OD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) { .offset = -32768000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .slope = 65536
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /* MODEL 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) { .control_id = FAN_OD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .ref_id = FAN_HD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) { .offset = -32768000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .slope = 65536
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /* pointer to the current model connection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static struct pm121_connection *pm121_connection;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * ****** System Fans Control Loop ******
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* Since each loop handles only one control and we want to avoid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * writing virtual control, we store the control correction with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * loop params. Some data are not set, there are common to all loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * and thus, hardcoded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct pm121_sys_param {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) /* purely informative since we use mach_model-2 as index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) int model_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct wf_sensor **sensor; /* use sensor_id instead ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) s32 gp, itarget;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) unsigned int control_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) static struct pm121_sys_param
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) /* GPU Fan control loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) { .model_id = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) .sensor = &sensor_gpu_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) .gp = 0x002A6666,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) .itarget = 0x5A0000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) .control_id = FAN_HD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) { .model_id = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) .sensor = &sensor_gpu_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) .gp = 0x0010CCCC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) .itarget = 0x500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) .control_id = FAN_CPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* HD Fan control loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) { .model_id = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) .sensor = &sensor_hard_drive_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) .gp = 0x002D70A3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) .itarget = 0x370000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) .control_id = FAN_HD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) { .model_id = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) .sensor = &sensor_hard_drive_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) .gp = 0x002170A3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) .itarget = 0x370000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) .control_id = FAN_HD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* KODIAK Fan control loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) { .model_id = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) .sensor = &sensor_north_bridge_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) .gp = 0x003BD70A,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) .itarget = 0x550000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) .control_id = FAN_OD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) { .model_id = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) .sensor = &sensor_north_bridge_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) .gp = 0x0030F5C2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) .itarget = 0x550000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) .control_id = FAN_HD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /* OD Fan control loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) { .model_id = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) .sensor = &sensor_optical_drive_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) .gp = 0x001FAE14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) .itarget = 0x320000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) .control_id = FAN_OD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) { .model_id = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) .sensor = &sensor_optical_drive_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) .gp = 0x001FAE14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) .itarget = 0x320000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) .control_id = FAN_OD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) /* the hardcoded values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) #define PM121_SYS_GD 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) #define PM121_SYS_GR 0x00019999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) #define PM121_SYS_HISTORY_SIZE 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) #define PM121_SYS_INTERVAL 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) /* State data used by the system fans control loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) struct pm121_sys_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) int ticks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) s32 setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) struct wf_pid_state pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * ****** CPU Fans Control Loop ******
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) #define PM121_CPU_INTERVAL 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /* State data used by the cpu fans control loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) struct pm121_cpu_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) int ticks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) s32 setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct wf_cpu_pid_state pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) static struct pm121_cpu_state *pm121_cpu_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) * ***** Implementation *****
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /* correction the value using the output-low-bound correction algo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) static s32 pm121_correct(s32 new_setpoint,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) unsigned int control_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) s32 min)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) s32 new_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct pm121_correction *correction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) correction = &corrections[control_id][pm121_mach_model - 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) new_min = (average_power * correction->slope) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) new_min += correction->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) new_min = (new_min >> 16) + min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return max3(new_setpoint, new_min, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static s32 pm121_connect(unsigned int control_id, s32 setpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) s32 new_min, value, new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (pm121_connection->control_id == control_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) controls[control_id]->ops->get_value(controls[control_id],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) new_min = value * pm121_connection->correction.slope;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) new_min += pm121_connection->correction.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (new_min > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) new_setpoint = max(setpoint, (new_min >> 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (new_setpoint != setpoint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) pr_debug("pm121: %s depending on %s, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) "corrected from %d to %d RPM\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) controls[control_id]->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) controls[pm121_connection->ref_id]->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) (int) setpoint, (int) new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) new_setpoint = setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) /* no connection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) new_setpoint = setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /* FAN LOOPS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static void pm121_create_sys_fans(int loop_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) struct pm121_sys_param *param = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct wf_pid_param pid_param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) struct wf_control *control = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) /* First, locate the params for this model */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) for (i = 0; i < PM121_NUM_CONFIGS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) param = &(pm121_sys_all_params[loop_id][i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* No params found, put fans to max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (param == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) printk(KERN_WARNING "pm121: %s fan config not found "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) " for this machine model\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) loop_names[loop_id]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) control = controls[param->control_id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) /* Alloc & initialize state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (pm121_sys_state[loop_id] == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) printk(KERN_WARNING "pm121: Memory allocation error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) pm121_sys_state[loop_id]->ticks = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /* Fill PID params */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) pid_param.gd = PM121_SYS_GD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) pid_param.gp = param->gp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) pid_param.gr = PM121_SYS_GR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) pid_param.interval = PM121_SYS_INTERVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) pid_param.history_len = PM121_SYS_HISTORY_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) pid_param.itarget = param->itarget;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if(control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) pid_param.min = control->ops->get_min(control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) pid_param.max = control->ops->get_max(control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * This is probably not the right!?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * Perhaps goto fail if control == NULL above?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) pid_param.min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) pid_param.max = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) pr_debug("pm121: %s Fan control loop initialized.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) " itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) loop_names[loop_id], FIX32TOPRINT(pid_param.itarget),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) pid_param.min, pid_param.max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) /* note that this is not optimal since another loop may still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) control the same control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) printk(KERN_WARNING "pm121: failed to set up %s loop "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) "setting \"%s\" to max speed.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) loop_names[loop_id], control ? control->name : "uninitialized value");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (control)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) wf_control_set_max(control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static void pm121_sys_fans_tick(int loop_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) struct pm121_sys_param *param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct pm121_sys_state *st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) struct wf_sensor *sensor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) struct wf_control *control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) s32 temp, new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) st = pm121_sys_state[loop_id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) sensor = *(param->sensor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) control = controls[param->control_id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (--st->ticks != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (pm121_readjust)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) goto readjust;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) st->ticks = PM121_SYS_INTERVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) rc = sensor->ops->get_value(sensor, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) printk(KERN_WARNING "windfarm: %s sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) sensor->name, rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) pm121_failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) loop_names[loop_id], sensor->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) FIX32TOPRINT(temp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) new_setpoint = wf_pid_run(&st->pid, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* correction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) new_setpoint = pm121_correct(new_setpoint,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) param->control_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) st->pid.param.min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) /* linked corretion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) new_setpoint = pm121_connect(param->control_id, new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (new_setpoint == st->setpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) st->setpoint = new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) pr_debug("pm121: %s corrected setpoint: %d RPM\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) control->name, (int)new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) readjust:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) if (control && pm121_failure_state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) rc = control->ops->set_value(control, st->setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) printk(KERN_WARNING "windfarm: %s fan error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) control->name, rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) pm121_failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) /* CPU LOOP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) static void pm121_create_cpu_fans(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) struct wf_cpu_pid_param pid_param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) const struct smu_sdbp_header *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) struct smu_sdbp_cpupiddata *piddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) struct smu_sdbp_fvt *fvt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) struct wf_control *fan_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) s32 tmax, tdelta, maxpow, powadj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) fan_cpu = controls[FAN_CPU];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) /* First, locate the PID params in SMU SBD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (hdr == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) printk(KERN_WARNING "pm121: CPU PID fan config not found.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /* Get the FVT params for operating point 0 (the only supported one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * for now) in order to get tmax
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (hdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) fvt = (struct smu_sdbp_fvt *)&hdr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) tmax = ((s32)fvt->maxtemp) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) tmax = 0x5e0000; /* 94 degree default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) /* Alloc & initialize state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (pm121_cpu_state == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) pm121_cpu_state->ticks = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) /* Fill PID params */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) pid_param.interval = PM121_CPU_INTERVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) pid_param.history_len = piddata->history_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) printk(KERN_WARNING "pm121: History size overflow on "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) "CPU control loop (%d)\n", piddata->history_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) pid_param.gd = piddata->gd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) pid_param.gp = piddata->gp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) pid_param.gr = piddata->gr / pid_param.history_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) tdelta = ((s32)piddata->target_temp_delta) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) maxpow = ((s32)piddata->max_power) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) powadj = ((s32)piddata->power_adj) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) pid_param.tmax = tmax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) pid_param.ttarget = tmax - tdelta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) pid_param.pmaxadj = maxpow - powadj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) pid_param.min = fan_cpu->ops->get_min(fan_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) pid_param.max = fan_cpu->ops->get_max(fan_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) pr_debug("pm121: CPU Fan control initialized.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) pr_debug(" ttarget=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) pid_param.min, pid_param.max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (controls[CPUFREQ])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) wf_control_set_max(controls[CPUFREQ]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (fan_cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) wf_control_set_max(fan_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) static void pm121_cpu_fans_tick(struct pm121_cpu_state *st)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) s32 new_setpoint, temp, power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) struct wf_control *fan_cpu = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) if (--st->ticks != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (pm121_readjust)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) goto readjust;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) st->ticks = PM121_CPU_INTERVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) fan_cpu = controls[FAN_CPU];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) printk(KERN_WARNING "pm121: CPU temp sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) pm121_failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) printk(KERN_WARNING "pm121: CPU power sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) pm121_failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) FIX32TOPRINT(temp), FIX32TOPRINT(power));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) if (temp > st->pid.param.tmax)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) pm121_failure_state |= FAILURE_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) /* correction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) new_setpoint = pm121_correct(new_setpoint,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) FAN_CPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) st->pid.param.min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) /* connected correction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) new_setpoint = pm121_connect(FAN_CPU, new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (st->setpoint == new_setpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) st->setpoint = new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) readjust:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) if (fan_cpu && pm121_failure_state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) printk(KERN_WARNING "pm121: %s fan error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) fan_cpu->name, rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) pm121_failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) * ****** Common ******
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) static void pm121_tick(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) unsigned int last_failure = pm121_failure_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) unsigned int new_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) s32 total_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (!pm121_started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) pr_debug("pm121: creating control loops !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) for (i = 0; i < N_LOOPS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) pm121_create_sys_fans(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) pm121_create_cpu_fans();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) pm121_started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) /* skipping ticks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (pm121_skipping && --pm121_skipping)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) /* compute average power */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) total_power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) total_power += pm121_cpu_state->pid.powers[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) average_power = total_power / pm121_cpu_state->pid.param.history_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) pm121_failure_state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) for (i = 0 ; i < N_LOOPS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) if (pm121_sys_state[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) pm121_sys_fans_tick(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) if (pm121_cpu_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) pm121_cpu_fans_tick(pm121_cpu_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) pm121_readjust = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) new_failure = pm121_failure_state & ~last_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) /* If entering failure mode, clamp cpufreq and ramp all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) * fans to full speed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (pm121_failure_state && !last_failure) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) for (i = 0; i < N_CONTROLS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (controls[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) wf_control_set_max(controls[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) /* If leaving failure mode, unclamp cpufreq and readjust
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) * all fans on next iteration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (!pm121_failure_state && last_failure) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) if (controls[CPUFREQ])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) wf_control_set_min(controls[CPUFREQ]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) pm121_readjust = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) /* Overtemp condition detected, notify and start skipping a couple
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) * ticks to let the temperature go down
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (new_failure & FAILURE_OVERTEMP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) wf_set_overtemp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) pm121_skipping = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) pm121_overtemp = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) /* We only clear the overtemp condition if overtemp is cleared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * _and_ no other failure is present. Since a sensor error will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) * clear the overtemp condition (can't measure temperature) at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * the control loop levels, but we don't want to keep it clear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * here in this case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (!pm121_failure_state && pm121_overtemp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) wf_clear_overtemp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) pm121_overtemp = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) static struct wf_control* pm121_register_control(struct wf_control *ct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) const char *match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) if (controls[id] == NULL && !strcmp(ct->name, match)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (wf_get_control(ct) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) controls[id] = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) return controls[id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) static void pm121_new_control(struct wf_control *ct)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) int all = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) if (pm121_all_controls_ok)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (all)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) pm121_all_controls_ok = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) const char *match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) struct wf_sensor **var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (*var == NULL && !strcmp(sensor->name, match)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) if (wf_get_sensor(sensor) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) *var = sensor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return *var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) static void pm121_new_sensor(struct wf_sensor *sr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) int all = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) if (pm121_all_sensors_ok)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) all = pm121_register_sensor(sr, "cpu-temp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) &sensor_cpu_temp) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) all = pm121_register_sensor(sr, "cpu-current",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) &sensor_cpu_current) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) all = pm121_register_sensor(sr, "cpu-voltage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) &sensor_cpu_voltage) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) all = pm121_register_sensor(sr, "cpu-power",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) &sensor_cpu_power) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) all = pm121_register_sensor(sr, "hard-drive-temp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) &sensor_hard_drive_temp) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) all = pm121_register_sensor(sr, "optical-drive-temp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) &sensor_optical_drive_temp) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) all = pm121_register_sensor(sr, "incoming-air-temp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) &sensor_incoming_air_temp) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) all = pm121_register_sensor(sr, "north-bridge-temp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) &sensor_north_bridge_temp) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) all = pm121_register_sensor(sr, "gpu-temp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) &sensor_gpu_temp) && all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) if (all)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) pm121_all_sensors_ok = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) static int pm121_notify(struct notifier_block *self,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) unsigned long event, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) case WF_EVENT_NEW_CONTROL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) pr_debug("pm121: new control %s detected\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) ((struct wf_control *)data)->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) pm121_new_control(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) case WF_EVENT_NEW_SENSOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) pr_debug("pm121: new sensor %s detected\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) ((struct wf_sensor *)data)->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) pm121_new_sensor(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) case WF_EVENT_TICK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (pm121_all_controls_ok && pm121_all_sensors_ok)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) pm121_tick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) static struct notifier_block pm121_events = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) .notifier_call = pm121_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) static int pm121_init_pm(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) const struct smu_sdbp_header *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) if (hdr != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) struct smu_sdbp_sensortree *st =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) (struct smu_sdbp_sensortree *)&hdr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) pm121_mach_model = st->model_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) pm121_connection = &pm121_connections[pm121_mach_model - 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) pm121_mach_model);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) static int pm121_probe(struct platform_device *ddev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) wf_register_client(&pm121_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) static int pm121_remove(struct platform_device *ddev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) wf_unregister_client(&pm121_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) static struct platform_driver pm121_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) .probe = pm121_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) .remove = pm121_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) .name = "windfarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) .bus = &platform_bus_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) static int __init pm121_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) int rc = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) if (of_machine_is_compatible("PowerMac12,1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) rc = pm121_init_pm();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (rc == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) request_module("windfarm_smu_controls");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) request_module("windfarm_smu_sensors");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) request_module("windfarm_smu_sat");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) request_module("windfarm_lm75_sensor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) request_module("windfarm_max6690_sensor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) request_module("windfarm_cpufreq_clamp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) platform_driver_register(&pm121_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) static void __exit pm121_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) platform_driver_unregister(&pm121_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) module_init(pm121_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) module_exit(pm121_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)