Home | History | Annotate | Line # | Download | only in pci
amdzentemp.c revision 1.21
      1  1.21   msaitoh /*      $NetBSD: amdzentemp.c,v 1.21 2024/10/04 03:04:40 msaitoh 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.21   msaitoh __KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.21 2024/10/04 03:04:40 msaitoh 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.13    nonaka 	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.18   msaitoh 		sc->sc_ccd_offset = 0x300;
    421  1.18   msaitoh 		maxreg = 12;
    422  1.18   msaitoh 		break;
    423  1.13    nonaka 	default:
    424  1.13    nonaka 		aprint_error_dev(sc->sc_dev,
    425  1.13    nonaka 		    "Unrecognized Family 19h Model: %02xh\n", model);
    426  1.13    nonaka 		return 0;
    427  1.13    nonaka 	}
    428  1.13    nonaka 
    429  1.13    nonaka 	return maxreg;
    430  1.13    nonaka }
    431  1.13    nonaka 
    432  1.13    nonaka static int
    433  1.21   msaitoh amdzentemp_probe_ccd_sensors1ah(struct amdzentemp_softc *sc, int model)
    434  1.21   msaitoh {
    435  1.21   msaitoh 	int maxreg;
    436  1.21   msaitoh 
    437  1.21   msaitoh 	switch (model) {
    438  1.21   msaitoh 	case 0x40 ... 0x4f: /* Zen5 */
    439  1.21   msaitoh 		sc->sc_ccd_offset = 0x300;
    440  1.21   msaitoh 		maxreg = 8;
    441  1.21   msaitoh 		break;
    442  1.21   msaitoh 	default:
    443  1.21   msaitoh 		aprint_error_dev(sc->sc_dev,
    444  1.21   msaitoh 		    "Unrecognized Family 19h Model: %02xh\n", model);
    445  1.21   msaitoh 		return 0;
    446  1.21   msaitoh 	}
    447  1.21   msaitoh 
    448  1.21   msaitoh 	return maxreg;
    449  1.21   msaitoh }
    450  1.21   msaitoh 
    451  1.21   msaitoh static int
    452  1.13    nonaka amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *sc, int family, int model)
    453  1.13    nonaka {
    454  1.13    nonaka 	int nccd;
    455  1.13    nonaka 
    456  1.13    nonaka 	switch (family) {
    457  1.13    nonaka 	case 0x17:
    458  1.13    nonaka 		nccd = amdzentemp_probe_ccd_sensors17h(sc, model);
    459  1.13    nonaka 		break;
    460  1.13    nonaka 	case 0x19:
    461  1.13    nonaka 		nccd = amdzentemp_probe_ccd_sensors19h(sc, model);
    462  1.13    nonaka 		break;
    463  1.21   msaitoh 	case 0x1a:
    464  1.21   msaitoh 		nccd = amdzentemp_probe_ccd_sensors1ah(sc, model);
    465  1.21   msaitoh 		break;
    466  1.13    nonaka 	default:
    467  1.13    nonaka 		return 0;
    468  1.13    nonaka 	}
    469  1.13    nonaka 
    470  1.13    nonaka 	return nccd;
    471  1.13    nonaka }
    472  1.13    nonaka 
    473  1.13    nonaka static void
    474  1.13    nonaka amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *sc)
    475  1.13    nonaka {
    476  1.13    nonaka 	envsys_data_t *edata;
    477  1.14    nonaka 	size_t i;
    478  1.13    nonaka 	uint32_t temp;
    479  1.14    nonaka 	int error;
    480  1.13    nonaka 
    481  1.13    nonaka 	for (i = 0; i < sc->sc_numsensors - 1; i++) {
    482  1.13    nonaka 		error = amdsmn_read(sc->sc_smn,
    483  1.17   msaitoh 		    AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)),
    484  1.17   msaitoh 		    &temp);
    485  1.13    nonaka 		if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID))
    486  1.13    nonaka 			continue;
    487  1.13    nonaka 
    488  1.13    nonaka 		edata = &sc->sc_sensor[1 + i];
    489  1.13    nonaka 		edata->units = ENVSYS_STEMP;
    490  1.13    nonaka 		edata->state = ENVSYS_SVALID;
    491  1.13    nonaka 		edata->flags = ENVSYS_FHAS_ENTROPY;
    492  1.13    nonaka 		edata->private = CCD_BASE + i;
    493  1.13    nonaka 		snprintf(edata->desc, sizeof(edata->desc),
    494  1.14    nonaka 		    "cpu%u ccd%zu temperature", device_unit(sc->sc_dev), i);
    495  1.13    nonaka 	}
    496  1.13    nonaka }
    497  1.13    nonaka 
    498   1.6  pgoyette MODULE(MODULE_CLASS_DRIVER, amdzentemp, "sysmon_envsys,amdsmn");
    499   1.1  christos 
    500   1.1  christos #ifdef _MODULE
    501   1.1  christos #include "ioconf.c"
    502   1.1  christos #endif
    503   1.1  christos 
    504   1.1  christos static int
    505   1.1  christos amdzentemp_modcmd(modcmd_t cmd, void *aux)
    506   1.1  christos {
    507   1.1  christos 	int error = 0;
    508   1.1  christos 
    509   1.1  christos 	switch (cmd) {
    510   1.1  christos 	case MODULE_CMD_INIT:
    511   1.1  christos #ifdef _MODULE
    512   1.1  christos 		error = config_init_component(cfdriver_ioconf_amdzentemp,
    513   1.1  christos 		    cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp);
    514   1.1  christos #endif
    515   1.1  christos 		return error;
    516   1.1  christos 	case MODULE_CMD_FINI:
    517   1.1  christos #ifdef _MODULE
    518   1.1  christos 		error = config_fini_component(cfdriver_ioconf_amdzentemp,
    519   1.1  christos 		    cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp);
    520   1.1  christos #endif
    521   1.1  christos 		return error;
    522   1.1  christos 	default:
    523   1.1  christos 		return ENOTTY;
    524   1.1  christos 	}
    525   1.1  christos }
    526