]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/intel/pchtherm.c
Import device-tree files from Linux 5.13
[FreeBSD/FreeBSD.git] / sys / dev / intel / pchtherm.c
1 /*
2  * Copyright (c) 2020 Takanori Watanabe
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/errno.h>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/sysctl.h>
37 #include <sys/syslog.h>
38 #include <sys/bus.h>
39
40 #include <machine/bus.h>
41 #include <sys/rman.h>
42 #include <machine/resource.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
45
46 #define PCHTHERM_REG_TEMP 0
47 #define PCHTHERM_REG_TSC 4
48 #define PCHTHERM_REG_TSS 6
49 #define PCHTHERM_REG_TSEL 8
50 #define PCHTHERM_REG_TSREL 0xa
51 #define PCHTHERM_REG_TSMIC 0xc
52 #define PCHTHERM_REG_CTT 0x10
53 #define PCHTHERM_REG_TAHV 0x14
54 #define PCHTHERM_REG_TALV 0x18
55 #define PCHTHERM_REG_TSPM 0x1c
56 #define PCHTHERM_REG_TL 0x40
57 #define PCHTHERM_REG_TL2 0x50
58 #define PCHTHERM_REG_PHL 0x60
59 #define PCHTHERM_REG_PHLC 0x62
60 #define PCHTHERM_REG_TAS 0x80
61 #define PCHTHERM_REG_TSPIEN 0x82
62 #define PCHTHERM_REG_TSGPEN 0x84
63 #define PCHTHERM_REG_TCFD 0xf0
64 #define PCHTHERM_GEN_LOCKDOWN 0x80
65 #define PCHTHERM_GEN_ENABLE 1
66 #define PCHTHERM_TEMP_FACTOR 5
67 #define PCHTHERM_TEMP_ZERO 2231
68 #define PCHTHERM_TEMP_MASK 0x1ff
69 #define PCHTHERM_TL_T0 0
70 #define PCHTHERM_TL_T1 10
71 #define PCHTHERM_TL_T2 20
72 #define PCHTHERM_TEMP_TO_IK(val) (((val) & PCHTHERM_TEMP_MASK) * \
73                                   PCHTHERM_TEMP_FACTOR +       \
74                                   PCHTHERM_TEMP_ZERO)
75
76 struct pchtherm_softc
77 {
78         int tbarrid;
79         struct resource *tbar;
80         int enable;
81         int ctten;
82         int pmtemp;
83         unsigned int pmtime;
84 };
85
86 static const struct pci_device_table pchtherm_devices[] =
87 {
88         { PCI_DEV(0x8086, 0x9c24),
89           PCI_DESCR("Haswell Thermal Subsystem")},
90         { PCI_DEV(0x8086, 0x8c24),
91           PCI_DESCR("Haswell Thermal Subsystem")},
92         { PCI_DEV(0x8086, 0x9ca4),
93           PCI_DESCR("Wildcat Point Thermal Subsystem")},
94         { PCI_DEV(0x8086, 0x9d31),
95           PCI_DESCR("Skylake PCH Thermal Subsystem")},
96         { PCI_DEV(0x8086, 0xa131),
97           PCI_DESCR("Skylake PCH 100 Thermal Subsystem")},
98         { PCI_DEV(0x8086, 0x9df9),
99           PCI_DESCR("CannonLake-LP Thermal Subsystem")},
100         { PCI_DEV(0x8086, 0xa379),
101           PCI_DESCR("CannonLake-H Thermal Subsystem")},
102         { PCI_DEV(0x8086, 0x02f9),
103           PCI_DESCR("CometLake-LP Thermal Subsystem")},
104         { PCI_DEV(0x8086, 0x06f9),
105           PCI_DESCR("CometLake-H Thermal Subsystem")},
106         { PCI_DEV(0x8086, 0xa1b1),
107           PCI_DESCR("Lewisburg Thermal Subsystem")},
108 };
109
110 static int pchtherm_probe(device_t dev)
111 {
112         const struct pci_device_table *tbl;
113
114         tbl = PCI_MATCH(dev, pchtherm_devices);
115         if (tbl == NULL)
116                 return (ENXIO);
117         device_set_desc(dev, tbl->descr);
118
119         return (BUS_PROBE_DEFAULT);
120
121 }
122 static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS)
123 {
124         struct pchtherm_softc *sc = oidp->oid_arg1;
125         int regshift = oidp->oid_arg2;
126         int temp;
127         
128         temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
129         temp >>= regshift;
130         temp = PCHTHERM_TEMP_TO_IK(temp);
131         
132         return sysctl_handle_int(oidp, &temp, 0, req);
133 }       
134 static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS)
135 {
136         struct pchtherm_softc *sc = oidp->oid_arg1;
137         int regoff = oidp->oid_arg2;
138         int temp;
139
140         temp = bus_read_2(sc->tbar, regoff);
141         temp = PCHTHERM_TEMP_TO_IK(temp);
142         
143         return sysctl_handle_int(oidp, &temp, 0, req);
144 }
145
146 #define FLAG_PRINT(dev, str, val) device_printf                         \
147         (dev, str " %s %sable\n",                                       \
148          ((val) & 0x80)? "Locked" : "",                                 \
149          ((val) & 0x1)? "En" : "Dis")
150
151 static int pchtherm_attach(device_t dev)
152 {
153         struct pchtherm_softc *sc =  device_get_softc(dev);
154         unsigned int val;
155         int flag;
156         int temp;
157
158         sc->tbarrid = PCIR_BAR(0);
159         sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
160                                           &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE);
161         if (sc->tbar == NULL) {
162                 return (ENOMEM);
163         }
164         sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
165         if (!(sc->enable & PCHTHERM_GEN_ENABLE )) {
166                 if (sc->enable & PCHTHERM_GEN_LOCKDOWN) {
167                         device_printf(dev, "Sensor not available\n");
168                         return 0;
169                 } else {
170                         device_printf(dev, "Enabling Sensor\n");
171                         bus_write_1(sc->tbar, PCHTHERM_REG_TSEL,
172                                     PCHTHERM_GEN_ENABLE);
173                         sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
174                         if (!(sc->enable & PCHTHERM_GEN_ENABLE)) {
175                                 device_printf(dev, "Sensor enable failed\n");
176                                 return 0;
177                         }
178                 }
179         }
180         
181         sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC);
182         if (bootverbose) {
183                 FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten);
184         }
185         val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL);
186         if (bootverbose) {
187                 FLAG_PRINT(dev, "SMBus report", val);
188         }
189         val = bus_read_1(sc->tbar, PCHTHERM_REG_TSMIC);
190         if (bootverbose) {
191                 FLAG_PRINT(dev, "SMI on alert", val);
192         }
193         val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM);
194         flag = val >> 13;
195         if (bootverbose) {
196                 device_printf(dev, "TSPM: %b\n",
197                               flag, "\20\3Lock\2DTSS0EN\1DSSOC0");
198                 device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n",
199                               1<<((val>>9)&7));
200         }
201
202         temp = val & PCHTHERM_TEMP_MASK;
203         sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp);
204         sc->pmtime = 1<<((val>>9)&7);
205         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
206                         SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
207                         OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD,
208                         sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl,
209                         "IK", "Thermal sensor idle temperature");
210         SYSCTL_ADD_U32(device_get_sysctl_ctx(dev),
211                        SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
212                        OID_AUTO, "pmtime", CTLFLAG_RD,
213                        &sc->pmtime, 0,"Thermal sensor idle duration");
214
215         val = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
216         flag = val>>29;
217
218         if (bootverbose) {
219                 device_printf(dev, "Throttling %b\n",
220                               flag, "\20\3Lock\2TT13EN\1TTEN");
221         }
222         
223         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
224                         SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
225                         OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD,
226                         sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl,
227                         "IK", "T0 temperature");
228
229         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
230                         SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
231                         OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD,
232                         sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl,
233                         "IK", "T1 temperature");
234
235         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
236                         SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
237                         OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD,
238                         sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl,
239                         "IK", "T2 temperature");
240
241         val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2);
242         if (bootverbose) {
243                 flag = val >>14;
244                 device_printf(dev, "TL2 flag %b\n",
245                               flag, "\20\1PMCTEN\2Lock");
246         }
247
248         /* If PHL is disable and lockdown, don't export it.*/
249         val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC);
250         val <<= 16;
251         val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL);
252         if ((val & 0x10000) != 0x10000) {
253                 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
254                                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
255                                 OID_AUTO, "pch_hot_level",
256                                 CTLTYPE_INT |CTLFLAG_RD,
257                                 sc, PCHTHERM_REG_PHL,
258                                 pchtherm_temp_sysctl, "IK",
259                                 "PCH Hot level Temperature");
260         }
261
262         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
263                         SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
264                         OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD,
265                         sc, PCHTHERM_REG_TEMP,
266                         pchtherm_temp_sysctl, "IK", "Current temperature");
267         /*
268          * If sensor enable bit is locked down, there is no way to change
269          * alart values effectively. 
270          */
271         if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
272             bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) {
273                 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
274                                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
275                                 OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD,
276                                 sc, PCHTHERM_REG_TAHV,
277                                 pchtherm_temp_sysctl, "IK",
278                                 "Alart High temperature");
279         }
280            
281         if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
282             bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) {
283                 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
284                                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
285                                 OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD,
286                                 sc, PCHTHERM_REG_TALV,
287                                 pchtherm_temp_sysctl, "IK",
288                                 "Alart Low temperature");
289         }
290         if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) ||
291             sc->ctten& PCHTHERM_GEN_ENABLE) {
292                 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
293                                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
294                                 OID_AUTO, "ctt",
295                                 CTLTYPE_INT |CTLFLAG_RD,
296                                 sc, PCHTHERM_REG_CTT,
297                                 pchtherm_temp_sysctl, "IK",
298                                 "Catastrophic Trip Point");
299         }
300                 
301         return 0;
302 }
303 static int pchtherm_detach(device_t dev)
304 {
305         struct pchtherm_softc *sc =  device_get_softc(dev);
306         bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar);
307
308         return 0;
309 }
310 static device_method_t pchtherm_methods[] =
311 {
312         DEVMETHOD(device_probe, pchtherm_probe),
313         DEVMETHOD(device_attach, pchtherm_attach),
314         DEVMETHOD(device_detach, pchtherm_detach),
315
316         DEVMETHOD_END
317 };
318 static driver_t pchtherm_driver = {
319         "pchtherm",
320         pchtherm_methods,
321         sizeof(struct pchtherm_softc)
322 };
323
324 static devclass_t pchtherm_devclass;
325 DRIVER_MODULE(pchtherm, pci, pchtherm_driver, pchtherm_devclass, 0, 0);
326 PCI_PNP_INFO(pchtherm_devices);