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