amdzentemp.c revision 1.11.6.1 1 1.11.6.1 thorpej /* $NetBSD: amdzentemp.c,v 1.11.6.1 2021/06/17 04:46:26 thorpej Exp $ */
2 1.1 christos /* $OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $ */
3 1.1 christos
4 1.1 christos /*
5 1.10 simonb * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc.
6 1.10 simonb * All rights reserved.
7 1.10 simonb *
8 1.10 simonb * Copyright (c) 2019 Conrad Meyer <cem (at) FreeBSD.org>
9 1.1 christos * All rights reserved.
10 1.1 christos *
11 1.1 christos * This code is derived from software contributed to The NetBSD Foundation
12 1.1 christos * by Christoph Egger.
13 1.1 christos *
14 1.1 christos * NetBSD port by Ian Clark <mrrooster (at) gmail.com>
15 1.1 christos *
16 1.1 christos * Redistribution and use in source and binary forms, with or without
17 1.1 christos * modification, are permitted provided that the following conditions
18 1.1 christos * are met:
19 1.1 christos * 1. Redistributions of source code must retain the above copyright
20 1.1 christos * notice, this list of conditions and the following disclaimer.
21 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
22 1.1 christos * notice, this list of conditions and the following disclaimer in the
23 1.1 christos * documentation and/or other materials provided with the distribution.
24 1.1 christos *
25 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 1.1 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.1 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.1 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 1.1 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.1 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.1 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.1 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.1 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.1 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.1 christos * POSSIBILITY OF SUCH DAMAGE.
36 1.1 christos */
37 1.1 christos
38 1.1 christos /*
39 1.1 christos * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd (at) bugmail.mojo.ru>
40 1.1 christos *
41 1.1 christos * Permission to use, copy, modify, and distribute this software for any
42 1.1 christos * purpose with or without fee is hereby granted, provided that the above
43 1.1 christos * copyright notice and this permission notice appear in all copies.
44 1.1 christos *
45 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
46 1.1 christos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
47 1.1 christos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
48 1.1 christos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
49 1.1 christos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
50 1.1 christos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
51 1.1 christos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52 1.1 christos */
53 1.1 christos
54 1.1 christos
55 1.1 christos #include <sys/cdefs.h>
56 1.11.6.1 thorpej __KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.11.6.1 2021/06/17 04:46:26 thorpej Exp $ ");
57 1.1 christos
58 1.1 christos #include <sys/param.h>
59 1.1 christos #include <sys/bus.h>
60 1.1 christos #include <sys/cpu.h>
61 1.1 christos #include <sys/systm.h>
62 1.1 christos #include <sys/device.h>
63 1.1 christos #include <sys/kmem.h>
64 1.1 christos #include <sys/module.h>
65 1.1 christos
66 1.1 christos #include <machine/specialreg.h>
67 1.1 christos
68 1.1 christos #include <dev/pci/pcireg.h>
69 1.1 christos #include <dev/pci/pcivar.h>
70 1.1 christos #include <dev/pci/pcidevs.h>
71 1.1 christos
72 1.1 christos #include <dev/sysmon/sysmonvar.h>
73 1.1 christos
74 1.1 christos #include "amdsmn.h"
75 1.1 christos
76 1.10 simonb #define AMD_CURTMP_RANGE_ADJUST 49000000 /* in microKelvins (ie, 49C) */
77 1.10 simonb #define AMD_CURTMP_RANGE_CHECK __BIT(19)
78 1.10 simonb #define F10_TEMP_CURTMP __BITS(31,21) /* XXX same as amdtemp.c */
79 1.11.6.1 thorpej #define F10_TEMP_CURTMP_MASK 0x7ff
80 1.10 simonb #define F15M60_CURTMP_TJSEL __BITS(17,16)
81 1.10 simonb
82 1.10 simonb /*
83 1.10 simonb * Reported Temperature, Family 15h, M60+
84 1.10 simonb *
85 1.10 simonb * Same register bit definitions as other Family 15h CPUs, but access is
86 1.10 simonb * indirect via SMN, like Family 17h.
87 1.10 simonb */
88 1.10 simonb #define AMD_15H_M60H_REPTMP_CTRL 0xd8200ca4
89 1.10 simonb
90 1.10 simonb /*
91 1.10 simonb * Reported Temperature, Family 17h
92 1.10 simonb *
93 1.10 simonb * According to AMD OSRR for 17H, section 4.2.1, bits 31-21 of this register
94 1.10 simonb * provide the current temp. bit 19, when clear, means the temp is reported in
95 1.10 simonb * a range 0.."225C" (probable typo for 255C), and when set changes the range
96 1.10 simonb * to -49..206C.
97 1.10 simonb */
98 1.10 simonb #define AMD_17H_CUR_TMP 0x59800
99 1.1 christos
100 1.11.6.1 thorpej /*
101 1.11.6.1 thorpej * The following register set was discovered experimentally by Ondrej erman
102 1.11.6.1 thorpej * and collaborators, but is not (yet) documented in a PPR/OSRR (other than
103 1.11.6.1 thorpej * the M70H PPR SMN memory map showing [0x59800, +0x314] as allocated to
104 1.11.6.1 thorpej * SMU::THM). It seems plausible and the Linux sensor folks have adopted it.
105 1.11.6.1 thorpej */
106 1.11.6.1 thorpej #define AMD_17H_CCD_TMP_BASE 0x59954
107 1.11.6.1 thorpej #define AMD_17H_CCD_TMP_VALID __BIT(11)
108 1.11.6.1 thorpej
109 1.1 christos struct amdzentemp_softc {
110 1.11.6.1 thorpej device_t sc_dev;
111 1.1 christos struct sysmon_envsys *sc_sme;
112 1.1 christos device_t sc_smn;
113 1.1 christos envsys_data_t *sc_sensor;
114 1.1 christos size_t sc_sensor_len;
115 1.10 simonb size_t sc_numsensors;
116 1.9 mlelstv int32_t sc_offset;
117 1.1 christos };
118 1.1 christos
119 1.11.6.1 thorpej enum {
120 1.11.6.1 thorpej NOSENSOR = 0,
121 1.11.6.1 thorpej CORE0_SENSOR0,
122 1.11.6.1 thorpej CCD_BASE,
123 1.11.6.1 thorpej CCD0 = CCD_BASE,
124 1.11.6.1 thorpej CCD1,
125 1.11.6.1 thorpej CCD2,
126 1.11.6.1 thorpej CCD3,
127 1.11.6.1 thorpej CCD4,
128 1.11.6.1 thorpej CCD5,
129 1.11.6.1 thorpej CCD6,
130 1.11.6.1 thorpej CCD7,
131 1.11.6.1 thorpej CCD_MAX,
132 1.11.6.1 thorpej NUM_CCDS = CCD_MAX - CCD_BASE
133 1.11.6.1 thorpej };
134 1.11.6.1 thorpej
135 1.1 christos
136 1.1 christos static int amdzentemp_match(device_t, cfdata_t, void *);
137 1.1 christos static void amdzentemp_attach(device_t, device_t, void *);
138 1.1 christos static int amdzentemp_detach(device_t, int);
139 1.1 christos
140 1.11.6.1 thorpej static void amdzentemp_init(struct amdzentemp_softc *, int, int);
141 1.11.6.1 thorpej static void amdzentemp_setup_sensors(struct amdzentemp_softc *);
142 1.10 simonb static void amdzentemp_family15_refresh(struct sysmon_envsys *, envsys_data_t *);
143 1.1 christos static void amdzentemp_family17_refresh(struct sysmon_envsys *, envsys_data_t *);
144 1.11.6.1 thorpej static int amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *, int, int);
145 1.11.6.1 thorpej static void amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *);
146 1.1 christos
147 1.1 christos CFATTACH_DECL_NEW(amdzentemp, sizeof(struct amdzentemp_softc),
148 1.1 christos amdzentemp_match, amdzentemp_attach, amdzentemp_detach, NULL);
149 1.1 christos
150 1.1 christos static int
151 1.1 christos amdzentemp_match(device_t parent, cfdata_t match, void *aux)
152 1.1 christos {
153 1.5 pgoyette struct pci_attach_args *pa __diagused = aux;
154 1.3 pgoyette
155 1.1 christos KASSERT(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD);
156 1.11.6.1 thorpej
157 1.1 christos cfdata_t parent_cfdata = device_cfdata(parent);
158 1.11.6.1 thorpej
159 1.1 christos /* Got AMD family 17h system management network */
160 1.1 christos return parent_cfdata->cf_name &&
161 1.1 christos memcmp(parent_cfdata->cf_name, "amdsmn", 6) == 0;
162 1.1 christos }
163 1.1 christos
164 1.1 christos static void
165 1.1 christos amdzentemp_attach(device_t parent, device_t self, void *aux)
166 1.1 christos {
167 1.1 christos struct amdzentemp_softc *sc = device_private(self);
168 1.10 simonb struct cpu_info *ci = curcpu();
169 1.11.6.1 thorpej int family, model;
170 1.1 christos int error;
171 1.1 christos size_t i;
172 1.1 christos
173 1.11.6.1 thorpej sc->sc_dev = self;
174 1.11.6.1 thorpej
175 1.10 simonb family = CPUID_TO_FAMILY(ci->ci_signature);
176 1.11.6.1 thorpej model = CPUID_TO_MODEL(ci->ci_signature);
177 1.1 christos aprint_naive("\n");
178 1.11.6.1 thorpej aprint_normal(": AMD CPU Temperature Sensors (Family%xh)", family);
179 1.1 christos
180 1.1 christos sc->sc_smn = parent;
181 1.9 mlelstv
182 1.11.6.1 thorpej amdzentemp_init(sc, family, model);
183 1.1 christos
184 1.1 christos aprint_normal("\n");
185 1.1 christos
186 1.1 christos sc->sc_sme = sysmon_envsys_create();
187 1.1 christos sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors;
188 1.1 christos sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP);
189 1.1 christos
190 1.11.6.1 thorpej amdzentemp_setup_sensors(sc);
191 1.1 christos
192 1.1 christos /*
193 1.1 christos * Set properties in sensors.
194 1.1 christos */
195 1.1 christos for (i = 0; i < sc->sc_numsensors; i++) {
196 1.11.6.1 thorpej if (sc->sc_sensor[i].private == NOSENSOR)
197 1.11.6.1 thorpej continue;
198 1.1 christos if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i]))
199 1.1 christos goto bad;
200 1.1 christos }
201 1.1 christos
202 1.1 christos /*
203 1.1 christos * Register the sysmon_envsys device.
204 1.1 christos */
205 1.1 christos sc->sc_sme->sme_name = device_xname(self);
206 1.1 christos sc->sc_sme->sme_cookie = sc;
207 1.1 christos
208 1.10 simonb switch (family) {
209 1.10 simonb case 0x15:
210 1.10 simonb sc->sc_sme->sme_refresh = amdzentemp_family15_refresh;
211 1.10 simonb break;
212 1.10 simonb case 0x17:
213 1.11.6.1 thorpej case 0x19:
214 1.10 simonb sc->sc_sme->sme_refresh = amdzentemp_family17_refresh;
215 1.10 simonb break;
216 1.10 simonb default:
217 1.10 simonb /* XXX panic */
218 1.10 simonb break;
219 1.10 simonb }
220 1.1 christos
221 1.1 christos error = sysmon_envsys_register(sc->sc_sme);
222 1.1 christos if (error) {
223 1.1 christos aprint_error_dev(self, "unable to register with sysmon "
224 1.1 christos "(error=%d)\n", error);
225 1.1 christos goto bad;
226 1.1 christos }
227 1.1 christos
228 1.1 christos (void)pmf_device_register(self, NULL, NULL);
229 1.1 christos
230 1.1 christos return;
231 1.1 christos
232 1.1 christos bad:
233 1.1 christos if (sc->sc_sme != NULL) {
234 1.1 christos sysmon_envsys_destroy(sc->sc_sme);
235 1.1 christos sc->sc_sme = NULL;
236 1.1 christos }
237 1.1 christos
238 1.7 pgoyette kmem_free(sc->sc_sensor, sc->sc_sensor_len);
239 1.7 pgoyette sc->sc_sensor = NULL;
240 1.1 christos }
241 1.1 christos
242 1.1 christos static int
243 1.1 christos amdzentemp_detach(device_t self, int flags)
244 1.1 christos {
245 1.1 christos struct amdzentemp_softc *sc = device_private(self);
246 1.1 christos
247 1.1 christos pmf_device_deregister(self);
248 1.1 christos if (sc->sc_sme != NULL)
249 1.1 christos sysmon_envsys_unregister(sc->sc_sme);
250 1.1 christos
251 1.1 christos if (sc->sc_sensor != NULL)
252 1.1 christos kmem_free(sc->sc_sensor, sc->sc_sensor_len);
253 1.1 christos
254 1.1 christos return 0;
255 1.1 christos }
256 1.1 christos
257 1.1 christos
258 1.1 christos static void
259 1.11.6.1 thorpej amdzentemp_init(struct amdzentemp_softc *sc, int family, int model)
260 1.1 christos {
261 1.9 mlelstv
262 1.11.6.1 thorpej sc->sc_numsensors = 1 + amdzentemp_probe_ccd_sensors(sc, family, model);
263 1.9 mlelstv sc->sc_offset = 0;
264 1.9 mlelstv
265 1.9 mlelstv if (strstr(cpu_brand_string, "AMD Ryzen 5 1600X")
266 1.9 mlelstv || strstr(cpu_brand_string, "AMD Ryzen 7 1700X")
267 1.9 mlelstv || strstr(cpu_brand_string, "AMD Ryzen 7 1800X"))
268 1.9 mlelstv sc->sc_offset = -20000000;
269 1.9 mlelstv else if (strstr(cpu_brand_string, "AMD Ryzen 7 2700X"))
270 1.9 mlelstv sc->sc_offset = -10000000;
271 1.9 mlelstv else if (strstr(cpu_brand_string, "AMD Ryzen Threadripper 19")
272 1.9 mlelstv || strstr(cpu_brand_string, "AMD Ryzen Threadripper 29"))
273 1.9 mlelstv sc->sc_offset = -27000000;
274 1.1 christos }
275 1.1 christos
276 1.1 christos static void
277 1.11.6.1 thorpej amdzentemp_setup_sensors(struct amdzentemp_softc *sc)
278 1.1 christos {
279 1.1 christos sc->sc_sensor[0].units = ENVSYS_STEMP;
280 1.1 christos sc->sc_sensor[0].state = ENVSYS_SVALID;
281 1.1 christos sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY;
282 1.11.6.1 thorpej sc->sc_sensor[0].private = CORE0_SENSOR0;
283 1.1 christos
284 1.1 christos snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc),
285 1.11.6.1 thorpej "cpu%u temperature", device_unit(sc->sc_dev));
286 1.11.6.1 thorpej
287 1.11.6.1 thorpej if (sc->sc_numsensors > 1)
288 1.11.6.1 thorpej amdzentemp_setup_ccd_sensors(sc);
289 1.1 christos }
290 1.1 christos
291 1.1 christos static void
292 1.10 simonb amdzentemp_family15_refresh(struct sysmon_envsys *sme,
293 1.11.6.1 thorpej envsys_data_t *edata)
294 1.10 simonb {
295 1.10 simonb struct amdzentemp_softc *sc = sme->sme_cookie;
296 1.10 simonb uint32_t val, temp;
297 1.10 simonb int error;
298 1.11.6.1 thorpej
299 1.10 simonb error = amdsmn_read(sc->sc_smn, AMD_15H_M60H_REPTMP_CTRL, &val);
300 1.10 simonb if (error) {
301 1.10 simonb edata->state = ENVSYS_SINVALID;
302 1.10 simonb return;
303 1.10 simonb }
304 1.10 simonb
305 1.10 simonb /* from amdtemp.c:amdtemp_family10_refresh() */
306 1.10 simonb temp = __SHIFTOUT(val, F10_TEMP_CURTMP);
307 1.10 simonb
308 1.10 simonb /* From Celsius to micro-Kelvin. */
309 1.10 simonb edata->value_cur = (temp * 125000) + 273150000;
310 1.10 simonb
311 1.10 simonb /*
312 1.10 simonb * On Family 15h and higher, if CurTmpTjSel is 11b, the range is
313 1.10 simonb * adjusted down by 49.0 degrees Celsius. (This adjustment is not
314 1.10 simonb * documented in BKDGs prior to family 15h model 00h.)
315 1.10 simonb *
316 1.10 simonb * XXX should be in amdtemp.c:amdtemp_family10_refresh() for f15
317 1.10 simonb * as well??
318 1.10 simonb */
319 1.10 simonb if (__SHIFTOUT(val, F15M60_CURTMP_TJSEL) == 0x3)
320 1.10 simonb edata->value_cur -= AMD_CURTMP_RANGE_ADJUST;
321 1.10 simonb
322 1.10 simonb edata->state = ENVSYS_SVALID;
323 1.10 simonb }
324 1.10 simonb
325 1.10 simonb static void
326 1.11.6.1 thorpej amdzentemp_family17_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
327 1.1 christos {
328 1.1 christos struct amdzentemp_softc *sc = sme->sme_cookie;
329 1.1 christos uint32_t temp;
330 1.11.6.1 thorpej bool minus49;
331 1.11.6.1 thorpej int i, error;
332 1.11.6.1 thorpej
333 1.11.6.1 thorpej switch (edata->private) {
334 1.11.6.1 thorpej case CORE0_SENSOR0:
335 1.11.6.1 thorpej /* Tctl */
336 1.11.6.1 thorpej error = amdsmn_read(sc->sc_smn, AMD_17H_CUR_TMP, &temp);
337 1.11.6.1 thorpej if (error) {
338 1.11.6.1 thorpej edata->state = ENVSYS_SINVALID;
339 1.11.6.1 thorpej return;
340 1.11.6.1 thorpej }
341 1.11.6.1 thorpej minus49 = (temp & AMD_CURTMP_RANGE_CHECK) ? true : false;
342 1.11.6.1 thorpej temp = __SHIFTOUT(temp, F10_TEMP_CURTMP);
343 1.11.6.1 thorpej break;
344 1.11.6.1 thorpej case CCD_BASE ... (CCD_MAX - 1):
345 1.11.6.1 thorpej /* Tccd */
346 1.11.6.1 thorpej i = edata->private - CCD_BASE;
347 1.11.6.1 thorpej error = amdsmn_read(sc->sc_smn,
348 1.11.6.1 thorpej AMD_17H_CCD_TMP_BASE + (i * sizeof(temp)), &temp);
349 1.11.6.1 thorpej if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) {
350 1.11.6.1 thorpej edata->state = ENVSYS_SINVALID;
351 1.11.6.1 thorpej return;
352 1.11.6.1 thorpej }
353 1.11.6.1 thorpej minus49 = true;
354 1.11.6.1 thorpej temp &= F10_TEMP_CURTMP_MASK;
355 1.11.6.1 thorpej break;
356 1.11.6.1 thorpej default:
357 1.1 christos edata->state = ENVSYS_SINVALID;
358 1.1 christos return;
359 1.1 christos }
360 1.1 christos edata->state = ENVSYS_SVALID;
361 1.11.6.1 thorpej /* From C to uK. */
362 1.11.6.1 thorpej edata->value_cur = (temp * 125000) + 273150000;
363 1.8 para /* adjust for possible offset of 49K */
364 1.11.6.1 thorpej if (minus49)
365 1.10 simonb edata->value_cur -= AMD_CURTMP_RANGE_ADJUST;
366 1.9 mlelstv edata->value_cur += sc->sc_offset;
367 1.1 christos }
368 1.1 christos
369 1.11.6.1 thorpej static int
370 1.11.6.1 thorpej amdzentemp_probe_ccd_sensors17h(struct amdzentemp_softc *sc, int model)
371 1.11.6.1 thorpej {
372 1.11.6.1 thorpej int maxreg;
373 1.11.6.1 thorpej
374 1.11.6.1 thorpej switch (model) {
375 1.11.6.1 thorpej case 0x00 ... 0x2f: /* Zen1, Zen+ */
376 1.11.6.1 thorpej maxreg = 4;
377 1.11.6.1 thorpej break;
378 1.11.6.1 thorpej case 0x30 ... 0x3f: /* Zen2 TR (Castle Peak)/EPYC (Rome) */
379 1.11.6.1 thorpej case 0x60 ... 0x7f: /* Zen2 Ryzen (Renoir APU, Matisse) */
380 1.11.6.1 thorpej case 0x90 ... 0x9f: /* Zen2 Ryzen (Van Gogh APU) */
381 1.11.6.1 thorpej maxreg = 8;
382 1.11.6.1 thorpej break;
383 1.11.6.1 thorpej default:
384 1.11.6.1 thorpej aprint_error_dev(sc->sc_dev,
385 1.11.6.1 thorpej "Unrecognized Family 17h Model: %02xh\n", model);
386 1.11.6.1 thorpej return 0;
387 1.11.6.1 thorpej }
388 1.11.6.1 thorpej
389 1.11.6.1 thorpej return maxreg;
390 1.11.6.1 thorpej }
391 1.11.6.1 thorpej
392 1.11.6.1 thorpej static int
393 1.11.6.1 thorpej amdzentemp_probe_ccd_sensors19h(struct amdzentemp_softc *sc, int model)
394 1.11.6.1 thorpej {
395 1.11.6.1 thorpej int maxreg;
396 1.11.6.1 thorpej
397 1.11.6.1 thorpej switch (model) {
398 1.11.6.1 thorpej case 0x00 ... 0x0f: /* Zen3 EPYC "Milan" */
399 1.11.6.1 thorpej case 0x20 ... 0x2f: /* Zen3 Ryzen "Vermeer" */
400 1.11.6.1 thorpej maxreg = 8;
401 1.11.6.1 thorpej break;
402 1.11.6.1 thorpej default:
403 1.11.6.1 thorpej aprint_error_dev(sc->sc_dev,
404 1.11.6.1 thorpej "Unrecognized Family 19h Model: %02xh\n", model);
405 1.11.6.1 thorpej return 0;
406 1.11.6.1 thorpej }
407 1.11.6.1 thorpej
408 1.11.6.1 thorpej return maxreg;
409 1.11.6.1 thorpej }
410 1.11.6.1 thorpej
411 1.11.6.1 thorpej static int
412 1.11.6.1 thorpej amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *sc, int family, int model)
413 1.11.6.1 thorpej {
414 1.11.6.1 thorpej int nccd;
415 1.11.6.1 thorpej
416 1.11.6.1 thorpej switch (family) {
417 1.11.6.1 thorpej case 0x17:
418 1.11.6.1 thorpej nccd = amdzentemp_probe_ccd_sensors17h(sc, model);
419 1.11.6.1 thorpej break;
420 1.11.6.1 thorpej case 0x19:
421 1.11.6.1 thorpej nccd = amdzentemp_probe_ccd_sensors19h(sc, model);
422 1.11.6.1 thorpej break;
423 1.11.6.1 thorpej default:
424 1.11.6.1 thorpej return 0;
425 1.11.6.1 thorpej }
426 1.11.6.1 thorpej
427 1.11.6.1 thorpej return nccd;
428 1.11.6.1 thorpej }
429 1.11.6.1 thorpej
430 1.11.6.1 thorpej static void
431 1.11.6.1 thorpej amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *sc)
432 1.11.6.1 thorpej {
433 1.11.6.1 thorpej envsys_data_t *edata;
434 1.11.6.1 thorpej size_t i;
435 1.11.6.1 thorpej uint32_t temp;
436 1.11.6.1 thorpej int error;
437 1.11.6.1 thorpej
438 1.11.6.1 thorpej for (i = 0; i < sc->sc_numsensors - 1; i++) {
439 1.11.6.1 thorpej error = amdsmn_read(sc->sc_smn,
440 1.11.6.1 thorpej AMD_17H_CCD_TMP_BASE + (i * sizeof(temp)), &temp);
441 1.11.6.1 thorpej if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID))
442 1.11.6.1 thorpej continue;
443 1.11.6.1 thorpej
444 1.11.6.1 thorpej edata = &sc->sc_sensor[1 + i];
445 1.11.6.1 thorpej edata->units = ENVSYS_STEMP;
446 1.11.6.1 thorpej edata->state = ENVSYS_SVALID;
447 1.11.6.1 thorpej edata->flags = ENVSYS_FHAS_ENTROPY;
448 1.11.6.1 thorpej edata->private = CCD_BASE + i;
449 1.11.6.1 thorpej snprintf(edata->desc, sizeof(edata->desc),
450 1.11.6.1 thorpej "cpu%u ccd%zu temperature", device_unit(sc->sc_dev), i);
451 1.11.6.1 thorpej }
452 1.11.6.1 thorpej }
453 1.11.6.1 thorpej
454 1.6 pgoyette MODULE(MODULE_CLASS_DRIVER, amdzentemp, "sysmon_envsys,amdsmn");
455 1.1 christos
456 1.1 christos #ifdef _MODULE
457 1.1 christos #include "ioconf.c"
458 1.1 christos #endif
459 1.1 christos
460 1.1 christos static int
461 1.1 christos amdzentemp_modcmd(modcmd_t cmd, void *aux)
462 1.1 christos {
463 1.1 christos int error = 0;
464 1.1 christos
465 1.1 christos switch (cmd) {
466 1.1 christos case MODULE_CMD_INIT:
467 1.1 christos #ifdef _MODULE
468 1.1 christos error = config_init_component(cfdriver_ioconf_amdzentemp,
469 1.1 christos cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp);
470 1.1 christos #endif
471 1.1 christos return error;
472 1.1 christos case MODULE_CMD_FINI:
473 1.1 christos #ifdef _MODULE
474 1.1 christos error = config_fini_component(cfdriver_ioconf_amdzentemp,
475 1.1 christos cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp);
476 1.1 christos #endif
477 1.1 christos return error;
478 1.1 christos default:
479 1.1 christos return ENOTTY;
480 1.1 christos }
481 1.1 christos }
482