Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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)