1*18f9d255Smsaitoh /* $NetBSD: amdzentemp.c,v 1.22 2024/10/17 14:16:48 msaitoh Exp $ */ 23a74451dSchristos /* $OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $ */ 33a74451dSchristos 43a74451dSchristos /* 5f90792d2Ssimonb * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc. 6f90792d2Ssimonb * All rights reserved. 7f90792d2Ssimonb * 8f90792d2Ssimonb * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org> 93a74451dSchristos * All rights reserved. 103a74451dSchristos * 113a74451dSchristos * This code is derived from software contributed to The NetBSD Foundation 123a74451dSchristos * by Christoph Egger. 133a74451dSchristos * 143a74451dSchristos * NetBSD port by Ian Clark <mrrooster@gmail.com> 153a74451dSchristos * 163a74451dSchristos * Redistribution and use in source and binary forms, with or without 173a74451dSchristos * modification, are permitted provided that the following conditions 183a74451dSchristos * are met: 193a74451dSchristos * 1. Redistributions of source code must retain the above copyright 203a74451dSchristos * notice, this list of conditions and the following disclaimer. 213a74451dSchristos * 2. Redistributions in binary form must reproduce the above copyright 223a74451dSchristos * notice, this list of conditions and the following disclaimer in the 233a74451dSchristos * documentation and/or other materials provided with the distribution. 243a74451dSchristos * 253a74451dSchristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 263a74451dSchristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 273a74451dSchristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 283a74451dSchristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 293a74451dSchristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 303a74451dSchristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 313a74451dSchristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 323a74451dSchristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 333a74451dSchristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 343a74451dSchristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 353a74451dSchristos * POSSIBILITY OF SUCH DAMAGE. 363a74451dSchristos */ 373a74451dSchristos 383a74451dSchristos /* 393a74451dSchristos * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> 403a74451dSchristos * 413a74451dSchristos * Permission to use, copy, modify, and distribute this software for any 423a74451dSchristos * purpose with or without fee is hereby granted, provided that the above 433a74451dSchristos * copyright notice and this permission notice appear in all copies. 443a74451dSchristos * 453a74451dSchristos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 463a74451dSchristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 473a74451dSchristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 483a74451dSchristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 493a74451dSchristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 503a74451dSchristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 513a74451dSchristos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 523a74451dSchristos */ 533a74451dSchristos 543a74451dSchristos 553a74451dSchristos #include <sys/cdefs.h> 56*18f9d255Smsaitoh __KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.22 2024/10/17 14:16:48 msaitoh Exp $ "); 573a74451dSchristos 583a74451dSchristos #include <sys/param.h> 593a74451dSchristos #include <sys/bus.h> 603a74451dSchristos #include <sys/cpu.h> 613a74451dSchristos #include <sys/systm.h> 623a74451dSchristos #include <sys/device.h> 633a74451dSchristos #include <sys/kmem.h> 643a74451dSchristos #include <sys/module.h> 653a74451dSchristos 663a74451dSchristos #include <machine/specialreg.h> 673a74451dSchristos 683a74451dSchristos #include <dev/pci/pcireg.h> 693a74451dSchristos #include <dev/pci/pcivar.h> 703a74451dSchristos #include <dev/pci/pcidevs.h> 713a74451dSchristos 723a74451dSchristos #include <dev/sysmon/sysmonvar.h> 733a74451dSchristos 743a74451dSchristos #include "amdsmn.h" 753a74451dSchristos 76f90792d2Ssimonb #define AMD_CURTMP_RANGE_ADJUST 49000000 /* in microKelvins (ie, 49C) */ 77f90792d2Ssimonb #define F10_TEMP_CURTMP __BITS(31,21) /* XXX same as amdtemp.c */ 78b067962fSnonaka #define F10_TEMP_CURTMP_MASK 0x7ff 79f90792d2Ssimonb #define F15M60_CURTMP_TJSEL __BITS(17,16) 80f90792d2Ssimonb 81f90792d2Ssimonb /* 82f90792d2Ssimonb * Reported Temperature, Family 15h, M60+ 83f90792d2Ssimonb * 84f90792d2Ssimonb * Same register bit definitions as other Family 15h CPUs, but access is 85f90792d2Ssimonb * indirect via SMN, like Family 17h. 86f90792d2Ssimonb */ 87f90792d2Ssimonb #define AMD_15H_M60H_REPTMP_CTRL 0xd8200ca4 88f90792d2Ssimonb 89f90792d2Ssimonb /* 90f90792d2Ssimonb * Reported Temperature, Family 17h 91f90792d2Ssimonb * 92f90792d2Ssimonb * According to AMD OSRR for 17H, section 4.2.1, bits 31-21 of this register 93f90792d2Ssimonb * provide the current temp. bit 19, when clear, means the temp is reported in 94f90792d2Ssimonb * a range 0.."225C" (probable typo for 255C), and when set changes the range 95f90792d2Ssimonb * to -49..206C. 96f90792d2Ssimonb */ 973a74451dSchristos #define AMD_17H_CUR_TMP 0x59800 98c9f90033Smsaitoh #define AMD_17H_CUR_TMP_RANGE_SEL __BIT(19) 99b067962fSnonaka #define AMD_17H_CCD_TMP_VALID __BIT(11) 100b067962fSnonaka 1013a74451dSchristos struct amdzentemp_softc { 102b067962fSnonaka device_t sc_dev; 1033a74451dSchristos struct sysmon_envsys *sc_sme; 1043a74451dSchristos device_t sc_smn; 1053a74451dSchristos envsys_data_t *sc_sensor; 1063a74451dSchristos size_t sc_sensor_len; 1073a74451dSchristos size_t sc_numsensors; 10886bc92a4Smlelstv int32_t sc_offset; 109c9f90033Smsaitoh int32_t sc_ccd_offset; 1103a74451dSchristos }; 1113a74451dSchristos 112b067962fSnonaka enum { 113b067962fSnonaka NOSENSOR = 0, 114b067962fSnonaka CORE0_SENSOR0, 115b067962fSnonaka CCD_BASE, 116b067962fSnonaka CCD0 = CCD_BASE, 117b067962fSnonaka CCD1, 118b067962fSnonaka CCD2, 119b067962fSnonaka CCD3, 120b067962fSnonaka CCD4, 121b067962fSnonaka CCD5, 122b067962fSnonaka CCD6, 123b067962fSnonaka CCD7, 12497018bdaSmsaitoh CCD8, 12597018bdaSmsaitoh CCD9, 12697018bdaSmsaitoh CCD10, 12797018bdaSmsaitoh CCD11, 128b067962fSnonaka CCD_MAX, 129b067962fSnonaka NUM_CCDS = CCD_MAX - CCD_BASE 130b067962fSnonaka }; 131b067962fSnonaka 1323a74451dSchristos 1333a74451dSchristos static int amdzentemp_match(device_t, cfdata_t, void *); 1343a74451dSchristos static void amdzentemp_attach(device_t, device_t, void *); 1353a74451dSchristos static int amdzentemp_detach(device_t, int); 1363a74451dSchristos 137b067962fSnonaka static void amdzentemp_init(struct amdzentemp_softc *, int, int); 138b067962fSnonaka static void amdzentemp_setup_sensors(struct amdzentemp_softc *); 139f90792d2Ssimonb static void amdzentemp_family15_refresh(struct sysmon_envsys *, envsys_data_t *); 1403a74451dSchristos static void amdzentemp_family17_refresh(struct sysmon_envsys *, envsys_data_t *); 141b067962fSnonaka static int amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *, int, int); 142b067962fSnonaka static void amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *); 1433a74451dSchristos 1443a74451dSchristos CFATTACH_DECL_NEW(amdzentemp, sizeof(struct amdzentemp_softc), 1453a74451dSchristos amdzentemp_match, amdzentemp_attach, amdzentemp_detach, NULL); 1463a74451dSchristos 1473a74451dSchristos static int 1483a74451dSchristos amdzentemp_match(device_t parent, cfdata_t match, void *aux) 1493a74451dSchristos { 150c0bd5644Spgoyette struct pci_attach_args *pa __diagused = aux; 151a74d9d21Spgoyette 1523a74451dSchristos KASSERT(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD); 1533a74451dSchristos 1543a74451dSchristos cfdata_t parent_cfdata = device_cfdata(parent); 1553a74451dSchristos 1563a74451dSchristos /* Got AMD family 17h system management network */ 1573a74451dSchristos return parent_cfdata->cf_name && 1583a74451dSchristos memcmp(parent_cfdata->cf_name, "amdsmn", 6) == 0; 1593a74451dSchristos } 1603a74451dSchristos 1613a74451dSchristos static void 1623a74451dSchristos amdzentemp_attach(device_t parent, device_t self, void *aux) 1633a74451dSchristos { 1643a74451dSchristos struct amdzentemp_softc *sc = device_private(self); 165f90792d2Ssimonb struct cpu_info *ci = curcpu(); 166b067962fSnonaka int family, model; 1673a74451dSchristos int error; 1683a74451dSchristos size_t i; 1693a74451dSchristos 170b067962fSnonaka sc->sc_dev = self; 171b067962fSnonaka 172f90792d2Ssimonb family = CPUID_TO_FAMILY(ci->ci_signature); 173b067962fSnonaka model = CPUID_TO_MODEL(ci->ci_signature); 1743a74451dSchristos aprint_naive("\n"); 175b067962fSnonaka aprint_normal(": AMD CPU Temperature Sensors (Family%xh)", family); 1763a74451dSchristos 1773a74451dSchristos sc->sc_smn = parent; 1783a74451dSchristos 179b067962fSnonaka amdzentemp_init(sc, family, model); 1803a74451dSchristos 1813a74451dSchristos aprint_normal("\n"); 1823a74451dSchristos 1833a74451dSchristos sc->sc_sme = sysmon_envsys_create(); 1843a74451dSchristos sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors; 1853a74451dSchristos sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP); 1863a74451dSchristos 187b067962fSnonaka amdzentemp_setup_sensors(sc); 1883a74451dSchristos 1893a74451dSchristos /* 1903a74451dSchristos * Set properties in sensors. 1913a74451dSchristos */ 1923a74451dSchristos for (i = 0; i < sc->sc_numsensors; i++) { 193b067962fSnonaka if (sc->sc_sensor[i].private == NOSENSOR) 194b067962fSnonaka continue; 1953a74451dSchristos if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) 1963a74451dSchristos goto bad; 1973a74451dSchristos } 1983a74451dSchristos 1993a74451dSchristos /* 2003a74451dSchristos * Register the sysmon_envsys device. 2013a74451dSchristos */ 2023a74451dSchristos sc->sc_sme->sme_name = device_xname(self); 2033a74451dSchristos sc->sc_sme->sme_cookie = sc; 2043a74451dSchristos 205f90792d2Ssimonb switch (family) { 206f90792d2Ssimonb case 0x15: 207f90792d2Ssimonb sc->sc_sme->sme_refresh = amdzentemp_family15_refresh; 208f90792d2Ssimonb break; 209f90792d2Ssimonb case 0x17: 210b8ea29baSnonaka case 0x19: 2117d75762aSmsaitoh case 0x1a: 2123a74451dSchristos sc->sc_sme->sme_refresh = amdzentemp_family17_refresh; 213f90792d2Ssimonb break; 214f90792d2Ssimonb default: 215f90792d2Ssimonb /* XXX panic */ 216f90792d2Ssimonb break; 217f90792d2Ssimonb } 2183a74451dSchristos 2193a74451dSchristos error = sysmon_envsys_register(sc->sc_sme); 2203a74451dSchristos if (error) { 2213a74451dSchristos aprint_error_dev(self, "unable to register with sysmon " 2223a74451dSchristos "(error=%d)\n", error); 2233a74451dSchristos goto bad; 2243a74451dSchristos } 2253a74451dSchristos 2263a74451dSchristos (void)pmf_device_register(self, NULL, NULL); 2273a74451dSchristos 2283a74451dSchristos return; 2293a74451dSchristos 2303a74451dSchristos bad: 2313a74451dSchristos if (sc->sc_sme != NULL) { 2323a74451dSchristos sysmon_envsys_destroy(sc->sc_sme); 2333a74451dSchristos sc->sc_sme = NULL; 2343a74451dSchristos } 2353a74451dSchristos 2363a74451dSchristos kmem_free(sc->sc_sensor, sc->sc_sensor_len); 2373a74451dSchristos sc->sc_sensor = NULL; 2383a74451dSchristos } 2393a74451dSchristos 2403a74451dSchristos static int 2413a74451dSchristos amdzentemp_detach(device_t self, int flags) 2423a74451dSchristos { 2433a74451dSchristos struct amdzentemp_softc *sc = device_private(self); 2443a74451dSchristos 2453a74451dSchristos pmf_device_deregister(self); 2463a74451dSchristos if (sc->sc_sme != NULL) 2473a74451dSchristos sysmon_envsys_unregister(sc->sc_sme); 2483a74451dSchristos 2493a74451dSchristos if (sc->sc_sensor != NULL) 2503a74451dSchristos kmem_free(sc->sc_sensor, sc->sc_sensor_len); 2513a74451dSchristos 2523a74451dSchristos return 0; 2533a74451dSchristos } 2543a74451dSchristos 2553a74451dSchristos 2563a74451dSchristos static void 257b067962fSnonaka amdzentemp_init(struct amdzentemp_softc *sc, int family, int model) 2583a74451dSchristos { 25986bc92a4Smlelstv 260b067962fSnonaka sc->sc_numsensors = 1 + amdzentemp_probe_ccd_sensors(sc, family, model); 26186bc92a4Smlelstv sc->sc_offset = 0; 26286bc92a4Smlelstv 26386bc92a4Smlelstv if (strstr(cpu_brand_string, "AMD Ryzen 5 1600X") 26486bc92a4Smlelstv || strstr(cpu_brand_string, "AMD Ryzen 7 1700X") 26586bc92a4Smlelstv || strstr(cpu_brand_string, "AMD Ryzen 7 1800X")) 26686bc92a4Smlelstv sc->sc_offset = -20000000; 26786bc92a4Smlelstv else if (strstr(cpu_brand_string, "AMD Ryzen 7 2700X")) 26886bc92a4Smlelstv sc->sc_offset = -10000000; 26986bc92a4Smlelstv else if (strstr(cpu_brand_string, "AMD Ryzen Threadripper 19") 27086bc92a4Smlelstv || strstr(cpu_brand_string, "AMD Ryzen Threadripper 29")) 27186bc92a4Smlelstv sc->sc_offset = -27000000; 2723a74451dSchristos } 2733a74451dSchristos 2743a74451dSchristos static void 275b067962fSnonaka amdzentemp_setup_sensors(struct amdzentemp_softc *sc) 2763a74451dSchristos { 2773a74451dSchristos sc->sc_sensor[0].units = ENVSYS_STEMP; 2783a74451dSchristos sc->sc_sensor[0].state = ENVSYS_SVALID; 2793a74451dSchristos sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY; 280b067962fSnonaka sc->sc_sensor[0].private = CORE0_SENSOR0; 2813a74451dSchristos 2823a74451dSchristos snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc), 283b067962fSnonaka "cpu%u temperature", device_unit(sc->sc_dev)); 284b067962fSnonaka 285b067962fSnonaka if (sc->sc_numsensors > 1) 286b067962fSnonaka amdzentemp_setup_ccd_sensors(sc); 2873a74451dSchristos } 2883a74451dSchristos 2893a74451dSchristos static void 290f90792d2Ssimonb amdzentemp_family15_refresh(struct sysmon_envsys *sme, 291f90792d2Ssimonb envsys_data_t *edata) 292f90792d2Ssimonb { 293f90792d2Ssimonb struct amdzentemp_softc *sc = sme->sme_cookie; 294f90792d2Ssimonb uint32_t val, temp; 295f90792d2Ssimonb int error; 296f90792d2Ssimonb 297f90792d2Ssimonb error = amdsmn_read(sc->sc_smn, AMD_15H_M60H_REPTMP_CTRL, &val); 298f90792d2Ssimonb if (error) { 299f90792d2Ssimonb edata->state = ENVSYS_SINVALID; 300f90792d2Ssimonb return; 301f90792d2Ssimonb } 302f90792d2Ssimonb 303f90792d2Ssimonb /* from amdtemp.c:amdtemp_family10_refresh() */ 304f90792d2Ssimonb temp = __SHIFTOUT(val, F10_TEMP_CURTMP); 305f90792d2Ssimonb 306f90792d2Ssimonb /* From Celsius to micro-Kelvin. */ 307f90792d2Ssimonb edata->value_cur = (temp * 125000) + 273150000; 308f90792d2Ssimonb 309f90792d2Ssimonb /* 310f90792d2Ssimonb * On Family 15h and higher, if CurTmpTjSel is 11b, the range is 311f90792d2Ssimonb * adjusted down by 49.0 degrees Celsius. (This adjustment is not 312f90792d2Ssimonb * documented in BKDGs prior to family 15h model 00h.) 313f90792d2Ssimonb * 314f90792d2Ssimonb * XXX should be in amdtemp.c:amdtemp_family10_refresh() for f15 315f90792d2Ssimonb * as well?? 316f90792d2Ssimonb */ 317f90792d2Ssimonb if (__SHIFTOUT(val, F15M60_CURTMP_TJSEL) == 0x3) 318f90792d2Ssimonb edata->value_cur -= AMD_CURTMP_RANGE_ADJUST; 319f90792d2Ssimonb 320f90792d2Ssimonb edata->state = ENVSYS_SVALID; 321f90792d2Ssimonb } 322f90792d2Ssimonb 323f90792d2Ssimonb static void 3243a74451dSchristos amdzentemp_family17_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 3253a74451dSchristos { 3263a74451dSchristos struct amdzentemp_softc *sc = sme->sme_cookie; 3273a74451dSchristos uint32_t temp; 328b067962fSnonaka bool minus49; 329b067962fSnonaka int i, error; 3303a74451dSchristos 331b067962fSnonaka switch (edata->private) { 332b067962fSnonaka case CORE0_SENSOR0: 333b067962fSnonaka /* Tctl */ 3343a74451dSchristos error = amdsmn_read(sc->sc_smn, AMD_17H_CUR_TMP, &temp); 3353a74451dSchristos if (error) { 3363a74451dSchristos edata->state = ENVSYS_SINVALID; 3373a74451dSchristos return; 3383a74451dSchristos } 339c9f90033Smsaitoh minus49 = (temp & AMD_17H_CUR_TMP_RANGE_SEL) ? 340c9f90033Smsaitoh true : false; 341b067962fSnonaka temp = __SHIFTOUT(temp, F10_TEMP_CURTMP); 342b067962fSnonaka break; 343b067962fSnonaka case CCD_BASE ... (CCD_MAX - 1): 344b067962fSnonaka /* Tccd */ 345b067962fSnonaka i = edata->private - CCD_BASE; 346b067962fSnonaka error = amdsmn_read(sc->sc_smn, 347c9f90033Smsaitoh AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), 348c9f90033Smsaitoh &temp); 349b067962fSnonaka if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) { 350b067962fSnonaka edata->state = ENVSYS_SINVALID; 351b067962fSnonaka return; 352b067962fSnonaka } 353b067962fSnonaka minus49 = true; 354b067962fSnonaka temp &= F10_TEMP_CURTMP_MASK; 355b067962fSnonaka break; 356b067962fSnonaka default: 357b067962fSnonaka edata->state = ENVSYS_SINVALID; 358b067962fSnonaka return; 359b067962fSnonaka } 3603a74451dSchristos edata->state = ENVSYS_SVALID; 3613a74451dSchristos /* From C to uK. */ 362b067962fSnonaka edata->value_cur = (temp * 125000) + 273150000; 3631f4e4510Spara /* adjust for possible offset of 49K */ 364b067962fSnonaka if (minus49) 365f90792d2Ssimonb edata->value_cur -= AMD_CURTMP_RANGE_ADJUST; 36686bc92a4Smlelstv edata->value_cur += sc->sc_offset; 3673a74451dSchristos } 3683a74451dSchristos 369b067962fSnonaka static int 370b067962fSnonaka amdzentemp_probe_ccd_sensors17h(struct amdzentemp_softc *sc, int model) 371b067962fSnonaka { 372b067962fSnonaka int maxreg; 373b067962fSnonaka 374b067962fSnonaka switch (model) { 375b067962fSnonaka case 0x00 ... 0x2f: /* Zen1, Zen+ */ 376b39e984dSmsaitoh sc->sc_ccd_offset = 0x154; 377b067962fSnonaka maxreg = 4; 378b067962fSnonaka break; 379b067962fSnonaka case 0x30 ... 0x3f: /* Zen2 TR (Castle Peak)/EPYC (Rome) */ 380b067962fSnonaka case 0x60 ... 0x7f: /* Zen2 Ryzen (Renoir APU, Matisse) */ 381b067962fSnonaka case 0x90 ... 0x9f: /* Zen2 Ryzen (Van Gogh APU) */ 382b39e984dSmsaitoh sc->sc_ccd_offset = 0x154; 383b39e984dSmsaitoh maxreg = 8; 384b39e984dSmsaitoh break; 385b39e984dSmsaitoh case 0xa0 ... 0xaf: /* Zen2 Ryzen (Mendocino APU) */ 386b39e984dSmsaitoh sc->sc_ccd_offset = 0x300; 387b067962fSnonaka maxreg = 8; 388b067962fSnonaka break; 389b067962fSnonaka default: 390b067962fSnonaka aprint_error_dev(sc->sc_dev, 391b067962fSnonaka "Unrecognized Family 17h Model: %02xh\n", model); 392b067962fSnonaka return 0; 393b067962fSnonaka } 394b067962fSnonaka 395b067962fSnonaka return maxreg; 396b067962fSnonaka } 397b067962fSnonaka 398b067962fSnonaka static int 399b067962fSnonaka amdzentemp_probe_ccd_sensors19h(struct amdzentemp_softc *sc, int model) 400b067962fSnonaka { 401b067962fSnonaka int maxreg; 402b067962fSnonaka 403b067962fSnonaka switch (model) { 404b067962fSnonaka case 0x00 ... 0x0f: /* Zen3 EPYC "Milan" */ 405b067962fSnonaka case 0x20 ... 0x2f: /* Zen3 Ryzen "Vermeer" */ 406d137d649Smrg case 0x50 ... 0x5f: /* Zen3 Ryzen "Cezanne" */ 407c9f90033Smsaitoh sc->sc_ccd_offset = 0x154; 408b067962fSnonaka maxreg = 8; 409b067962fSnonaka break; 41008e27227Smsaitoh case 0x60 ... 0x6f: /* Zen4 Ryzen "Raphael" */ 411f2d8fd50Smsaitoh case 0x70 ... 0x7f: /* Zen4 Ryzen "Phoenix" */ 412c9f90033Smsaitoh sc->sc_ccd_offset = 0x308; 41308e27227Smsaitoh maxreg = 8; 41408e27227Smsaitoh break; 41597018bdaSmsaitoh case 0x40 ... 0x4f: /* Zen3+ "Rembrandt" */ 41697018bdaSmsaitoh sc->sc_ccd_offset = 0x300; 41797018bdaSmsaitoh maxreg = 8; 41897018bdaSmsaitoh break; 41997018bdaSmsaitoh case 0x10 ... 0x1f: /* Zen4 "Genoa" */ 420*18f9d255Smsaitoh case 0xa0 ... 0xaf: /* Zen4 "Siena" */ 42197018bdaSmsaitoh sc->sc_ccd_offset = 0x300; 42297018bdaSmsaitoh maxreg = 12; 42397018bdaSmsaitoh break; 424b067962fSnonaka default: 425b067962fSnonaka aprint_error_dev(sc->sc_dev, 426b067962fSnonaka "Unrecognized Family 19h Model: %02xh\n", model); 427b067962fSnonaka return 0; 428b067962fSnonaka } 429b067962fSnonaka 430b067962fSnonaka return maxreg; 431b067962fSnonaka } 432b067962fSnonaka 433b067962fSnonaka static int 4347d75762aSmsaitoh amdzentemp_probe_ccd_sensors1ah(struct amdzentemp_softc *sc, int model) 4357d75762aSmsaitoh { 4367d75762aSmsaitoh int maxreg; 4377d75762aSmsaitoh 4387d75762aSmsaitoh switch (model) { 439*18f9d255Smsaitoh case 0x00 ... 0x0f: /* Zen5 "Turin Classic" */ 440*18f9d255Smsaitoh sc->sc_ccd_offset = 0x300; 441*18f9d255Smsaitoh maxreg = 16; 442*18f9d255Smsaitoh break; 443*18f9d255Smsaitoh case 0x10 ... 0x1f: /* Zen5 "Turin Dense" */ 444*18f9d255Smsaitoh sc->sc_ccd_offset = 0x300; 445*18f9d255Smsaitoh maxreg = 12; 446*18f9d255Smsaitoh break; 447*18f9d255Smsaitoh case 0x20 ... 0x2f: /* Zen5 "Strix Point" */ 448*18f9d255Smsaitoh sc->sc_ccd_offset = 0x300; 449*18f9d255Smsaitoh maxreg = 8; 450*18f9d255Smsaitoh break; 451*18f9d255Smsaitoh case 0x40 ... 0x4f: /* Zen5 "Granite Ridge "*/ 4527d75762aSmsaitoh sc->sc_ccd_offset = 0x300; 4537d75762aSmsaitoh maxreg = 8; 4547d75762aSmsaitoh break; 4557d75762aSmsaitoh default: 4567d75762aSmsaitoh aprint_error_dev(sc->sc_dev, 4577d75762aSmsaitoh "Unrecognized Family 19h Model: %02xh\n", model); 4587d75762aSmsaitoh return 0; 4597d75762aSmsaitoh } 4607d75762aSmsaitoh 4617d75762aSmsaitoh return maxreg; 4627d75762aSmsaitoh } 4637d75762aSmsaitoh 4647d75762aSmsaitoh static int 465b067962fSnonaka amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *sc, int family, int model) 466b067962fSnonaka { 467b067962fSnonaka int nccd; 468b067962fSnonaka 469b067962fSnonaka switch (family) { 470b067962fSnonaka case 0x17: 471b067962fSnonaka nccd = amdzentemp_probe_ccd_sensors17h(sc, model); 472b067962fSnonaka break; 473b067962fSnonaka case 0x19: 474b067962fSnonaka nccd = amdzentemp_probe_ccd_sensors19h(sc, model); 475b067962fSnonaka break; 4767d75762aSmsaitoh case 0x1a: 4777d75762aSmsaitoh nccd = amdzentemp_probe_ccd_sensors1ah(sc, model); 4787d75762aSmsaitoh break; 479b067962fSnonaka default: 480b067962fSnonaka return 0; 481b067962fSnonaka } 482b067962fSnonaka 483b067962fSnonaka return nccd; 484b067962fSnonaka } 485b067962fSnonaka 486b067962fSnonaka static void 487b067962fSnonaka amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *sc) 488b067962fSnonaka { 489b067962fSnonaka envsys_data_t *edata; 490c9464754Snonaka size_t i; 491b067962fSnonaka uint32_t temp; 492c9464754Snonaka int error; 493b067962fSnonaka 494b067962fSnonaka for (i = 0; i < sc->sc_numsensors - 1; i++) { 495b067962fSnonaka error = amdsmn_read(sc->sc_smn, 496c9f90033Smsaitoh AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), 497c9f90033Smsaitoh &temp); 498b067962fSnonaka if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) 499b067962fSnonaka continue; 500b067962fSnonaka 501b067962fSnonaka edata = &sc->sc_sensor[1 + i]; 502b067962fSnonaka edata->units = ENVSYS_STEMP; 503b067962fSnonaka edata->state = ENVSYS_SVALID; 504b067962fSnonaka edata->flags = ENVSYS_FHAS_ENTROPY; 505b067962fSnonaka edata->private = CCD_BASE + i; 506b067962fSnonaka snprintf(edata->desc, sizeof(edata->desc), 507c9464754Snonaka "cpu%u ccd%zu temperature", device_unit(sc->sc_dev), i); 508b067962fSnonaka } 509b067962fSnonaka } 510b067962fSnonaka 511a63689b9Spgoyette MODULE(MODULE_CLASS_DRIVER, amdzentemp, "sysmon_envsys,amdsmn"); 5123a74451dSchristos 5133a74451dSchristos #ifdef _MODULE 5143a74451dSchristos #include "ioconf.c" 5153a74451dSchristos #endif 5163a74451dSchristos 5173a74451dSchristos static int 5183a74451dSchristos amdzentemp_modcmd(modcmd_t cmd, void *aux) 5193a74451dSchristos { 5203a74451dSchristos int error = 0; 5213a74451dSchristos 5223a74451dSchristos switch (cmd) { 5233a74451dSchristos case MODULE_CMD_INIT: 5243a74451dSchristos #ifdef _MODULE 5253a74451dSchristos error = config_init_component(cfdriver_ioconf_amdzentemp, 5263a74451dSchristos cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); 5273a74451dSchristos #endif 5283a74451dSchristos return error; 5293a74451dSchristos case MODULE_CMD_FINI: 5303a74451dSchristos #ifdef _MODULE 5313a74451dSchristos error = config_fini_component(cfdriver_ioconf_amdzentemp, 5323a74451dSchristos cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); 5333a74451dSchristos #endif 5343a74451dSchristos return error; 5353a74451dSchristos default: 5363a74451dSchristos return ENOTTY; 5373a74451dSchristos } 5383a74451dSchristos } 539