1 1.23 pgoyette /* $NetBSD: amdzentemp.c,v 1.23 2025/04/06 15:44:15 pgoyette 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.23 pgoyette __KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.23 2025/04/06 15:44:15 pgoyette 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 F10_TEMP_CURTMP __BITS(31,21) /* XXX same as amdtemp.c */ 78 1.13 nonaka #define F10_TEMP_CURTMP_MASK 0x7ff 79 1.10 simonb #define F15M60_CURTMP_TJSEL __BITS(17,16) 80 1.10 simonb 81 1.10 simonb /* 82 1.10 simonb * Reported Temperature, Family 15h, M60+ 83 1.10 simonb * 84 1.10 simonb * Same register bit definitions as other Family 15h CPUs, but access is 85 1.10 simonb * indirect via SMN, like Family 17h. 86 1.10 simonb */ 87 1.10 simonb #define AMD_15H_M60H_REPTMP_CTRL 0xd8200ca4 88 1.10 simonb 89 1.10 simonb /* 90 1.10 simonb * Reported Temperature, Family 17h 91 1.10 simonb * 92 1.10 simonb * According to AMD OSRR for 17H, section 4.2.1, bits 31-21 of this register 93 1.10 simonb * provide the current temp. bit 19, when clear, means the temp is reported in 94 1.10 simonb * a range 0.."225C" (probable typo for 255C), and when set changes the range 95 1.10 simonb * to -49..206C. 96 1.10 simonb */ 97 1.10 simonb #define AMD_17H_CUR_TMP 0x59800 98 1.17 msaitoh #define AMD_17H_CUR_TMP_RANGE_SEL __BIT(19) 99 1.13 nonaka #define AMD_17H_CCD_TMP_VALID __BIT(11) 100 1.13 nonaka 101 1.1 christos struct amdzentemp_softc { 102 1.13 nonaka device_t sc_dev; 103 1.1 christos struct sysmon_envsys *sc_sme; 104 1.1 christos device_t sc_smn; 105 1.1 christos envsys_data_t *sc_sensor; 106 1.1 christos size_t sc_sensor_len; 107 1.10 simonb size_t sc_numsensors; 108 1.9 mlelstv int32_t sc_offset; 109 1.17 msaitoh int32_t sc_ccd_offset; 110 1.1 christos }; 111 1.1 christos 112 1.13 nonaka enum { 113 1.13 nonaka NOSENSOR = 0, 114 1.13 nonaka CORE0_SENSOR0, 115 1.13 nonaka CCD_BASE, 116 1.13 nonaka CCD0 = CCD_BASE, 117 1.13 nonaka CCD1, 118 1.13 nonaka CCD2, 119 1.13 nonaka CCD3, 120 1.13 nonaka CCD4, 121 1.13 nonaka CCD5, 122 1.13 nonaka CCD6, 123 1.13 nonaka CCD7, 124 1.18 msaitoh CCD8, 125 1.18 msaitoh CCD9, 126 1.18 msaitoh CCD10, 127 1.18 msaitoh CCD11, 128 1.13 nonaka CCD_MAX, 129 1.13 nonaka NUM_CCDS = CCD_MAX - CCD_BASE 130 1.13 nonaka }; 131 1.13 nonaka 132 1.1 christos 133 1.1 christos static int amdzentemp_match(device_t, cfdata_t, void *); 134 1.1 christos static void amdzentemp_attach(device_t, device_t, void *); 135 1.1 christos static int amdzentemp_detach(device_t, int); 136 1.1 christos 137 1.13 nonaka static void amdzentemp_init(struct amdzentemp_softc *, int, int); 138 1.13 nonaka static void amdzentemp_setup_sensors(struct amdzentemp_softc *); 139 1.10 simonb static void amdzentemp_family15_refresh(struct sysmon_envsys *, envsys_data_t *); 140 1.1 christos static void amdzentemp_family17_refresh(struct sysmon_envsys *, envsys_data_t *); 141 1.13 nonaka static int amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *, int, int); 142 1.13 nonaka static void amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *); 143 1.1 christos 144 1.1 christos CFATTACH_DECL_NEW(amdzentemp, sizeof(struct amdzentemp_softc), 145 1.1 christos amdzentemp_match, amdzentemp_attach, amdzentemp_detach, NULL); 146 1.1 christos 147 1.1 christos static int 148 1.1 christos amdzentemp_match(device_t parent, cfdata_t match, void *aux) 149 1.1 christos { 150 1.5 pgoyette struct pci_attach_args *pa __diagused = aux; 151 1.3 pgoyette 152 1.1 christos KASSERT(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD); 153 1.13 nonaka 154 1.1 christos cfdata_t parent_cfdata = device_cfdata(parent); 155 1.13 nonaka 156 1.1 christos /* Got AMD family 17h system management network */ 157 1.1 christos return parent_cfdata->cf_name && 158 1.1 christos memcmp(parent_cfdata->cf_name, "amdsmn", 6) == 0; 159 1.1 christos } 160 1.1 christos 161 1.1 christos static void 162 1.1 christos amdzentemp_attach(device_t parent, device_t self, void *aux) 163 1.1 christos { 164 1.1 christos struct amdzentemp_softc *sc = device_private(self); 165 1.10 simonb struct cpu_info *ci = curcpu(); 166 1.13 nonaka int family, model; 167 1.1 christos int error; 168 1.1 christos size_t i; 169 1.1 christos 170 1.13 nonaka sc->sc_dev = self; 171 1.13 nonaka 172 1.10 simonb family = CPUID_TO_FAMILY(ci->ci_signature); 173 1.13 nonaka model = CPUID_TO_MODEL(ci->ci_signature); 174 1.1 christos aprint_naive("\n"); 175 1.23 pgoyette aprint_normal(": AMD CPU Temperature Sensors (Family %xh)", family); 176 1.1 christos 177 1.1 christos sc->sc_smn = parent; 178 1.9 mlelstv 179 1.13 nonaka amdzentemp_init(sc, family, model); 180 1.1 christos 181 1.1 christos aprint_normal("\n"); 182 1.1 christos 183 1.1 christos sc->sc_sme = sysmon_envsys_create(); 184 1.1 christos sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors; 185 1.1 christos sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP); 186 1.1 christos 187 1.13 nonaka amdzentemp_setup_sensors(sc); 188 1.1 christos 189 1.1 christos /* 190 1.1 christos * Set properties in sensors. 191 1.1 christos */ 192 1.1 christos for (i = 0; i < sc->sc_numsensors; i++) { 193 1.13 nonaka if (sc->sc_sensor[i].private == NOSENSOR) 194 1.13 nonaka continue; 195 1.1 christos if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) 196 1.1 christos goto bad; 197 1.1 christos } 198 1.1 christos 199 1.1 christos /* 200 1.1 christos * Register the sysmon_envsys device. 201 1.1 christos */ 202 1.1 christos sc->sc_sme->sme_name = device_xname(self); 203 1.1 christos sc->sc_sme->sme_cookie = sc; 204 1.1 christos 205 1.10 simonb switch (family) { 206 1.10 simonb case 0x15: 207 1.10 simonb sc->sc_sme->sme_refresh = amdzentemp_family15_refresh; 208 1.10 simonb break; 209 1.10 simonb case 0x17: 210 1.12 nonaka case 0x19: 211 1.21 msaitoh case 0x1a: 212 1.10 simonb sc->sc_sme->sme_refresh = amdzentemp_family17_refresh; 213 1.10 simonb break; 214 1.10 simonb default: 215 1.10 simonb /* XXX panic */ 216 1.10 simonb break; 217 1.10 simonb } 218 1.1 christos 219 1.1 christos error = sysmon_envsys_register(sc->sc_sme); 220 1.1 christos if (error) { 221 1.1 christos aprint_error_dev(self, "unable to register with sysmon " 222 1.1 christos "(error=%d)\n", error); 223 1.1 christos goto bad; 224 1.1 christos } 225 1.1 christos 226 1.1 christos (void)pmf_device_register(self, NULL, NULL); 227 1.1 christos 228 1.1 christos return; 229 1.1 christos 230 1.1 christos bad: 231 1.1 christos if (sc->sc_sme != NULL) { 232 1.1 christos sysmon_envsys_destroy(sc->sc_sme); 233 1.1 christos sc->sc_sme = NULL; 234 1.1 christos } 235 1.1 christos 236 1.7 pgoyette kmem_free(sc->sc_sensor, sc->sc_sensor_len); 237 1.7 pgoyette sc->sc_sensor = NULL; 238 1.1 christos } 239 1.1 christos 240 1.1 christos static int 241 1.1 christos amdzentemp_detach(device_t self, int flags) 242 1.1 christos { 243 1.1 christos struct amdzentemp_softc *sc = device_private(self); 244 1.1 christos 245 1.1 christos pmf_device_deregister(self); 246 1.1 christos if (sc->sc_sme != NULL) 247 1.1 christos sysmon_envsys_unregister(sc->sc_sme); 248 1.1 christos 249 1.1 christos if (sc->sc_sensor != NULL) 250 1.1 christos kmem_free(sc->sc_sensor, sc->sc_sensor_len); 251 1.1 christos 252 1.1 christos return 0; 253 1.1 christos } 254 1.1 christos 255 1.1 christos 256 1.1 christos static void 257 1.13 nonaka amdzentemp_init(struct amdzentemp_softc *sc, int family, int model) 258 1.1 christos { 259 1.9 mlelstv 260 1.13 nonaka sc->sc_numsensors = 1 + amdzentemp_probe_ccd_sensors(sc, family, model); 261 1.9 mlelstv sc->sc_offset = 0; 262 1.9 mlelstv 263 1.9 mlelstv if (strstr(cpu_brand_string, "AMD Ryzen 5 1600X") 264 1.9 mlelstv || strstr(cpu_brand_string, "AMD Ryzen 7 1700X") 265 1.9 mlelstv || strstr(cpu_brand_string, "AMD Ryzen 7 1800X")) 266 1.9 mlelstv sc->sc_offset = -20000000; 267 1.9 mlelstv else if (strstr(cpu_brand_string, "AMD Ryzen 7 2700X")) 268 1.9 mlelstv sc->sc_offset = -10000000; 269 1.9 mlelstv else if (strstr(cpu_brand_string, "AMD Ryzen Threadripper 19") 270 1.9 mlelstv || strstr(cpu_brand_string, "AMD Ryzen Threadripper 29")) 271 1.9 mlelstv sc->sc_offset = -27000000; 272 1.1 christos } 273 1.1 christos 274 1.1 christos static void 275 1.13 nonaka amdzentemp_setup_sensors(struct amdzentemp_softc *sc) 276 1.1 christos { 277 1.1 christos sc->sc_sensor[0].units = ENVSYS_STEMP; 278 1.1 christos sc->sc_sensor[0].state = ENVSYS_SVALID; 279 1.1 christos sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY; 280 1.13 nonaka sc->sc_sensor[0].private = CORE0_SENSOR0; 281 1.1 christos 282 1.1 christos snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc), 283 1.13 nonaka "cpu%u temperature", device_unit(sc->sc_dev)); 284 1.13 nonaka 285 1.13 nonaka if (sc->sc_numsensors > 1) 286 1.13 nonaka amdzentemp_setup_ccd_sensors(sc); 287 1.1 christos } 288 1.1 christos 289 1.1 christos static void 290 1.10 simonb amdzentemp_family15_refresh(struct sysmon_envsys *sme, 291 1.13 nonaka envsys_data_t *edata) 292 1.10 simonb { 293 1.10 simonb struct amdzentemp_softc *sc = sme->sme_cookie; 294 1.10 simonb uint32_t val, temp; 295 1.10 simonb int error; 296 1.13 nonaka 297 1.10 simonb error = amdsmn_read(sc->sc_smn, AMD_15H_M60H_REPTMP_CTRL, &val); 298 1.10 simonb if (error) { 299 1.10 simonb edata->state = ENVSYS_SINVALID; 300 1.10 simonb return; 301 1.10 simonb } 302 1.10 simonb 303 1.10 simonb /* from amdtemp.c:amdtemp_family10_refresh() */ 304 1.10 simonb temp = __SHIFTOUT(val, F10_TEMP_CURTMP); 305 1.10 simonb 306 1.10 simonb /* From Celsius to micro-Kelvin. */ 307 1.10 simonb edata->value_cur = (temp * 125000) + 273150000; 308 1.10 simonb 309 1.10 simonb /* 310 1.10 simonb * On Family 15h and higher, if CurTmpTjSel is 11b, the range is 311 1.10 simonb * adjusted down by 49.0 degrees Celsius. (This adjustment is not 312 1.10 simonb * documented in BKDGs prior to family 15h model 00h.) 313 1.10 simonb * 314 1.10 simonb * XXX should be in amdtemp.c:amdtemp_family10_refresh() for f15 315 1.10 simonb * as well?? 316 1.10 simonb */ 317 1.10 simonb if (__SHIFTOUT(val, F15M60_CURTMP_TJSEL) == 0x3) 318 1.10 simonb edata->value_cur -= AMD_CURTMP_RANGE_ADJUST; 319 1.10 simonb 320 1.10 simonb edata->state = ENVSYS_SVALID; 321 1.10 simonb } 322 1.10 simonb 323 1.10 simonb static void 324 1.13 nonaka amdzentemp_family17_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 325 1.1 christos { 326 1.1 christos struct amdzentemp_softc *sc = sme->sme_cookie; 327 1.1 christos uint32_t temp; 328 1.13 nonaka bool minus49; 329 1.13 nonaka int i, error; 330 1.13 nonaka 331 1.13 nonaka switch (edata->private) { 332 1.13 nonaka case CORE0_SENSOR0: 333 1.13 nonaka /* Tctl */ 334 1.13 nonaka error = amdsmn_read(sc->sc_smn, AMD_17H_CUR_TMP, &temp); 335 1.13 nonaka if (error) { 336 1.13 nonaka edata->state = ENVSYS_SINVALID; 337 1.13 nonaka return; 338 1.13 nonaka } 339 1.17 msaitoh minus49 = (temp & AMD_17H_CUR_TMP_RANGE_SEL) ? 340 1.17 msaitoh true : false; 341 1.13 nonaka temp = __SHIFTOUT(temp, F10_TEMP_CURTMP); 342 1.13 nonaka break; 343 1.13 nonaka case CCD_BASE ... (CCD_MAX - 1): 344 1.13 nonaka /* Tccd */ 345 1.13 nonaka i = edata->private - CCD_BASE; 346 1.13 nonaka error = amdsmn_read(sc->sc_smn, 347 1.17 msaitoh AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), 348 1.17 msaitoh &temp); 349 1.13 nonaka if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) { 350 1.13 nonaka edata->state = ENVSYS_SINVALID; 351 1.13 nonaka return; 352 1.13 nonaka } 353 1.13 nonaka minus49 = true; 354 1.13 nonaka temp &= F10_TEMP_CURTMP_MASK; 355 1.13 nonaka break; 356 1.13 nonaka 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.13 nonaka /* From C to uK. */ 362 1.13 nonaka edata->value_cur = (temp * 125000) + 273150000; 363 1.8 para /* adjust for possible offset of 49K */ 364 1.13 nonaka 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.13 nonaka static int 370 1.13 nonaka amdzentemp_probe_ccd_sensors17h(struct amdzentemp_softc *sc, int model) 371 1.13 nonaka { 372 1.13 nonaka int maxreg; 373 1.13 nonaka 374 1.13 nonaka switch (model) { 375 1.13 nonaka case 0x00 ... 0x2f: /* Zen1, Zen+ */ 376 1.20 msaitoh sc->sc_ccd_offset = 0x154; 377 1.13 nonaka maxreg = 4; 378 1.13 nonaka break; 379 1.13 nonaka case 0x30 ... 0x3f: /* Zen2 TR (Castle Peak)/EPYC (Rome) */ 380 1.13 nonaka case 0x60 ... 0x7f: /* Zen2 Ryzen (Renoir APU, Matisse) */ 381 1.13 nonaka case 0x90 ... 0x9f: /* Zen2 Ryzen (Van Gogh APU) */ 382 1.20 msaitoh sc->sc_ccd_offset = 0x154; 383 1.20 msaitoh maxreg = 8; 384 1.20 msaitoh break; 385 1.20 msaitoh case 0xa0 ... 0xaf: /* Zen2 Ryzen (Mendocino APU) */ 386 1.20 msaitoh sc->sc_ccd_offset = 0x300; 387 1.13 nonaka maxreg = 8; 388 1.13 nonaka break; 389 1.13 nonaka default: 390 1.13 nonaka aprint_error_dev(sc->sc_dev, 391 1.13 nonaka "Unrecognized Family 17h Model: %02xh\n", model); 392 1.13 nonaka return 0; 393 1.13 nonaka } 394 1.13 nonaka 395 1.13 nonaka return maxreg; 396 1.13 nonaka } 397 1.13 nonaka 398 1.13 nonaka static int 399 1.13 nonaka amdzentemp_probe_ccd_sensors19h(struct amdzentemp_softc *sc, int model) 400 1.13 nonaka { 401 1.13 nonaka int maxreg; 402 1.13 nonaka 403 1.13 nonaka switch (model) { 404 1.13 nonaka case 0x00 ... 0x0f: /* Zen3 EPYC "Milan" */ 405 1.13 nonaka case 0x20 ... 0x2f: /* Zen3 Ryzen "Vermeer" */ 406 1.16 mrg case 0x50 ... 0x5f: /* Zen3 Ryzen "Cezanne" */ 407 1.17 msaitoh sc->sc_ccd_offset = 0x154; 408 1.13 nonaka maxreg = 8; 409 1.13 nonaka break; 410 1.15 msaitoh case 0x60 ... 0x6f: /* Zen4 Ryzen "Raphael" */ 411 1.19 msaitoh case 0x70 ... 0x7f: /* Zen4 Ryzen "Phoenix" */ 412 1.17 msaitoh sc->sc_ccd_offset = 0x308; 413 1.15 msaitoh maxreg = 8; 414 1.15 msaitoh break; 415 1.18 msaitoh case 0x40 ... 0x4f: /* Zen3+ "Rembrandt" */ 416 1.18 msaitoh sc->sc_ccd_offset = 0x300; 417 1.18 msaitoh maxreg = 8; 418 1.18 msaitoh break; 419 1.18 msaitoh case 0x10 ... 0x1f: /* Zen4 "Genoa" */ 420 1.22 msaitoh case 0xa0 ... 0xaf: /* Zen4 "Siena" */ 421 1.18 msaitoh sc->sc_ccd_offset = 0x300; 422 1.18 msaitoh maxreg = 12; 423 1.18 msaitoh break; 424 1.13 nonaka default: 425 1.13 nonaka aprint_error_dev(sc->sc_dev, 426 1.13 nonaka "Unrecognized Family 19h Model: %02xh\n", model); 427 1.13 nonaka return 0; 428 1.13 nonaka } 429 1.13 nonaka 430 1.13 nonaka return maxreg; 431 1.13 nonaka } 432 1.13 nonaka 433 1.13 nonaka static int 434 1.21 msaitoh amdzentemp_probe_ccd_sensors1ah(struct amdzentemp_softc *sc, int model) 435 1.21 msaitoh { 436 1.21 msaitoh int maxreg; 437 1.21 msaitoh 438 1.21 msaitoh switch (model) { 439 1.22 msaitoh case 0x00 ... 0x0f: /* Zen5 "Turin Classic" */ 440 1.22 msaitoh sc->sc_ccd_offset = 0x300; 441 1.22 msaitoh maxreg = 16; 442 1.22 msaitoh break; 443 1.22 msaitoh case 0x10 ... 0x1f: /* Zen5 "Turin Dense" */ 444 1.22 msaitoh sc->sc_ccd_offset = 0x300; 445 1.22 msaitoh maxreg = 12; 446 1.22 msaitoh break; 447 1.22 msaitoh case 0x20 ... 0x2f: /* Zen5 "Strix Point" */ 448 1.22 msaitoh sc->sc_ccd_offset = 0x300; 449 1.22 msaitoh maxreg = 8; 450 1.22 msaitoh break; 451 1.22 msaitoh case 0x40 ... 0x4f: /* Zen5 "Granite Ridge "*/ 452 1.21 msaitoh sc->sc_ccd_offset = 0x300; 453 1.21 msaitoh maxreg = 8; 454 1.21 msaitoh break; 455 1.21 msaitoh default: 456 1.21 msaitoh aprint_error_dev(sc->sc_dev, 457 1.21 msaitoh "Unrecognized Family 19h Model: %02xh\n", model); 458 1.21 msaitoh return 0; 459 1.21 msaitoh } 460 1.21 msaitoh 461 1.21 msaitoh return maxreg; 462 1.21 msaitoh } 463 1.21 msaitoh 464 1.21 msaitoh static int 465 1.13 nonaka amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *sc, int family, int model) 466 1.13 nonaka { 467 1.13 nonaka int nccd; 468 1.13 nonaka 469 1.13 nonaka switch (family) { 470 1.13 nonaka case 0x17: 471 1.13 nonaka nccd = amdzentemp_probe_ccd_sensors17h(sc, model); 472 1.13 nonaka break; 473 1.13 nonaka case 0x19: 474 1.13 nonaka nccd = amdzentemp_probe_ccd_sensors19h(sc, model); 475 1.13 nonaka break; 476 1.21 msaitoh case 0x1a: 477 1.21 msaitoh nccd = amdzentemp_probe_ccd_sensors1ah(sc, model); 478 1.21 msaitoh break; 479 1.13 nonaka default: 480 1.13 nonaka return 0; 481 1.13 nonaka } 482 1.13 nonaka 483 1.13 nonaka return nccd; 484 1.13 nonaka } 485 1.13 nonaka 486 1.13 nonaka static void 487 1.13 nonaka amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *sc) 488 1.13 nonaka { 489 1.13 nonaka envsys_data_t *edata; 490 1.14 nonaka size_t i; 491 1.13 nonaka uint32_t temp; 492 1.14 nonaka int error; 493 1.13 nonaka 494 1.13 nonaka for (i = 0; i < sc->sc_numsensors - 1; i++) { 495 1.13 nonaka error = amdsmn_read(sc->sc_smn, 496 1.17 msaitoh AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), 497 1.17 msaitoh &temp); 498 1.13 nonaka if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) 499 1.13 nonaka continue; 500 1.13 nonaka 501 1.13 nonaka edata = &sc->sc_sensor[1 + i]; 502 1.13 nonaka edata->units = ENVSYS_STEMP; 503 1.13 nonaka edata->state = ENVSYS_SVALID; 504 1.13 nonaka edata->flags = ENVSYS_FHAS_ENTROPY; 505 1.13 nonaka edata->private = CCD_BASE + i; 506 1.13 nonaka snprintf(edata->desc, sizeof(edata->desc), 507 1.14 nonaka "cpu%u ccd%zu temperature", device_unit(sc->sc_dev), i); 508 1.13 nonaka } 509 1.13 nonaka } 510 1.13 nonaka 511 1.6 pgoyette MODULE(MODULE_CLASS_DRIVER, amdzentemp, "sysmon_envsys,amdsmn"); 512 1.1 christos 513 1.1 christos #ifdef _MODULE 514 1.1 christos #include "ioconf.c" 515 1.1 christos #endif 516 1.1 christos 517 1.1 christos static int 518 1.1 christos amdzentemp_modcmd(modcmd_t cmd, void *aux) 519 1.1 christos { 520 1.1 christos int error = 0; 521 1.1 christos 522 1.1 christos switch (cmd) { 523 1.1 christos case MODULE_CMD_INIT: 524 1.1 christos #ifdef _MODULE 525 1.1 christos error = config_init_component(cfdriver_ioconf_amdzentemp, 526 1.1 christos cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); 527 1.1 christos #endif 528 1.1 christos return error; 529 1.1 christos case MODULE_CMD_FINI: 530 1.1 christos #ifdef _MODULE 531 1.1 christos error = config_fini_component(cfdriver_ioconf_amdzentemp, 532 1.1 christos cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); 533 1.1 christos #endif 534 1.1 christos return error; 535 1.1 christos default: 536 1.1 christos return ENOTTY; 537 1.1 christos } 538 1.1 christos } 539