1*29002501Sis /* $NetBSD: amdtemp.c,v 1.23 2018/12/30 15:43:43 is Exp $ */
268519ac9Scegger /* $OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $ */
368519ac9Scegger
468519ac9Scegger /*
568519ac9Scegger * Copyright (c) 2008 The NetBSD Foundation, Inc.
668519ac9Scegger * All rights reserved.
768519ac9Scegger *
868519ac9Scegger * This code is derived from software contributed to The NetBSD Foundation
968519ac9Scegger * by Christoph Egger.
1068519ac9Scegger *
1168519ac9Scegger * Redistribution and use in source and binary forms, with or without
1268519ac9Scegger * modification, are permitted provided that the following conditions
1368519ac9Scegger * are met:
1468519ac9Scegger * 1. Redistributions of source code must retain the above copyright
1568519ac9Scegger * notice, this list of conditions and the following disclaimer.
1668519ac9Scegger * 2. Redistributions in binary form must reproduce the above copyright
1768519ac9Scegger * notice, this list of conditions and the following disclaimer in the
1868519ac9Scegger * documentation and/or other materials provided with the distribution.
1968519ac9Scegger *
2068519ac9Scegger * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2168519ac9Scegger * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2268519ac9Scegger * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2368519ac9Scegger * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2468519ac9Scegger * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2568519ac9Scegger * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2668519ac9Scegger * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2768519ac9Scegger * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2868519ac9Scegger * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2968519ac9Scegger * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3068519ac9Scegger * POSSIBILITY OF SUCH DAMAGE.
3168519ac9Scegger */
3268519ac9Scegger
3368519ac9Scegger /*
3468519ac9Scegger * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
3568519ac9Scegger *
3668519ac9Scegger * Permission to use, copy, modify, and distribute this software for any
3768519ac9Scegger * purpose with or without fee is hereby granted, provided that the above
3868519ac9Scegger * copyright notice and this permission notice appear in all copies.
3968519ac9Scegger *
4068519ac9Scegger * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
4168519ac9Scegger * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
4268519ac9Scegger * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
4368519ac9Scegger * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
4468519ac9Scegger * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
4568519ac9Scegger * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
4668519ac9Scegger * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4768519ac9Scegger */
4868519ac9Scegger
4968519ac9Scegger #include <sys/cdefs.h>
50*29002501Sis __KERNEL_RCSID(0, "$NetBSD: amdtemp.c,v 1.23 2018/12/30 15:43:43 is Exp $ ");
5168519ac9Scegger
5268519ac9Scegger #include <sys/param.h>
53c6e5cf85Sjruoho #include <sys/bus.h>
54c6e5cf85Sjruoho #include <sys/cpu.h>
5568519ac9Scegger #include <sys/systm.h>
5668519ac9Scegger #include <sys/device.h>
5768519ac9Scegger #include <sys/kmem.h>
58c6e5cf85Sjruoho #include <sys/module.h>
5968519ac9Scegger
6068519ac9Scegger #include <machine/specialreg.h>
6168519ac9Scegger
6268519ac9Scegger #include <dev/pci/pcireg.h>
6368519ac9Scegger #include <dev/pci/pcivar.h>
6468519ac9Scegger #include <dev/pci/pcidevs.h>
6568519ac9Scegger
66c6e5cf85Sjruoho #include <dev/sysmon/sysmonvar.h>
67c6e5cf85Sjruoho
6868519ac9Scegger /*
6968519ac9Scegger * AMD K8:
7068519ac9Scegger * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
7118130206Scegger * AMD K8 Errata: #141
7218130206Scegger * http://support.amd.com/us/Processor_TechDocs/33610_PUB_Rev3%2042v3.pdf
7318130206Scegger *
7468519ac9Scegger * Family10h:
7568519ac9Scegger * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116.PDF
76f94b5172Scegger * Family10h Errata: #319
77f94b5172Scegger * http://support.amd.com/de/Processor_TechDocs/41322.pdf
7818130206Scegger *
7918130206Scegger * Family11h:
8018130206Scegger * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/41256.pdf
8168519ac9Scegger */
8268519ac9Scegger
832e5784d8Sjmcneill /* AMD Processors, Function 3 -- Miscellaneous Control
8468519ac9Scegger */
8568519ac9Scegger
8668519ac9Scegger /* Function 3 Registers */
8768519ac9Scegger #define THERMTRIP_STAT_R 0xe4
8868519ac9Scegger #define NORTHBRIDGE_CAP_R 0xe8
8968519ac9Scegger #define CPUID_FAMILY_MODEL_R 0xfc
9068519ac9Scegger
9168519ac9Scegger /*
9268519ac9Scegger * AMD NPT Family 0Fh Processors, Function 3 -- Miscellaneous Control
9368519ac9Scegger */
9468519ac9Scegger
9568519ac9Scegger /* Bits within Thermtrip Status Register */
9668519ac9Scegger #define K8_THERM_SENSE_SEL (1 << 6)
9768519ac9Scegger #define K8_THERM_SENSE_CORE_SEL (1 << 2)
9868519ac9Scegger
9968519ac9Scegger /* Flip core and sensor selection bits */
10068519ac9Scegger #define K8_T_SEL_C0(v) (v |= K8_THERM_SENSE_CORE_SEL)
10168519ac9Scegger #define K8_T_SEL_C1(v) (v &= ~(K8_THERM_SENSE_CORE_SEL))
10268519ac9Scegger #define K8_T_SEL_S0(v) (v &= ~(K8_THERM_SENSE_SEL))
10368519ac9Scegger #define K8_T_SEL_S1(v) (v |= K8_THERM_SENSE_SEL)
10468519ac9Scegger
10568519ac9Scegger /*
1062e5784d8Sjmcneill * AMD Family 10h Processors, Function 3 -- Miscellaneous Control
10768519ac9Scegger */
10868519ac9Scegger
10968519ac9Scegger /* Function 3 Registers */
11068519ac9Scegger #define F10_TEMPERATURE_CTL_R 0xa4
111124c8cd2Smaxv #define F10_TEMP_CURTMP __BITS(31,21)
11268519ac9Scegger
11368519ac9Scegger /*
11468519ac9Scegger * Revision Guide for AMD NPT Family 0Fh Processors,
11568519ac9Scegger * Publication # 33610, Revision 3.30, February 2008
11668519ac9Scegger */
11772f1a5aaScegger #define K8_SOCKET_F 1 /* Server */
11872f1a5aaScegger #define K8_SOCKET_AM2 2 /* Desktop */
11972f1a5aaScegger #define K8_SOCKET_S1 3 /* Laptop */
12072f1a5aaScegger
12168519ac9Scegger static const struct {
12268519ac9Scegger const char rev[5];
12372f1a5aaScegger const struct {
12472f1a5aaScegger const pcireg_t cpuid;
12572f1a5aaScegger const uint8_t socket;
12672f1a5aaScegger } cpu[5];
12768519ac9Scegger } amdtemp_core[] = {
12872f1a5aaScegger { "BH-F", { { 0x00040FB0, K8_SOCKET_AM2 }, /* F2 */
12972f1a5aaScegger { 0x00040F80, K8_SOCKET_S1 }, /* F2 */
13072f1a5aaScegger { 0, 0 }, { 0, 0 }, { 0, 0 } } },
13172f1a5aaScegger { "DH-F", { { 0x00040FF0, K8_SOCKET_AM2 }, /* F2 */
13272f1a5aaScegger { 0x00040FC0, K8_SOCKET_S1 }, /* F2 */
13372f1a5aaScegger { 0x00050FF0, K8_SOCKET_AM2 }, /* F2, F3 */
13472f1a5aaScegger { 0, 0 }, { 0, 0 } } },
13572f1a5aaScegger { "JH-F", { { 0x00040F10, K8_SOCKET_F }, /* F2, F3 */
13672f1a5aaScegger { 0x00040F30, K8_SOCKET_AM2 }, /* F2, F3 */
13772f1a5aaScegger { 0x000C0F10, K8_SOCKET_F }, /* F3 */
13872f1a5aaScegger { 0, 0 }, { 0, 0 } } },
13972f1a5aaScegger { "BH-G", { { 0x00060FB0, K8_SOCKET_AM2 }, /* G1, G2 */
14072f1a5aaScegger { 0x00060F80, K8_SOCKET_S1 }, /* G1, G2 */
14172f1a5aaScegger { 0, 0 }, { 0, 0 }, { 0, 0 } } },
14272f1a5aaScegger { "DH-G", { { 0x00060FF0, K8_SOCKET_AM2 }, /* G1, G2 */
14372f1a5aaScegger { 0x00060FC0, K8_SOCKET_S1 }, /* G2 */
14472f1a5aaScegger { 0x00070FF0, K8_SOCKET_AM2 }, /* G1, G2 */
14572f1a5aaScegger { 0x00070FC0, K8_SOCKET_S1 }, /* G2 */
14672f1a5aaScegger { 0, 0 } } }
14768519ac9Scegger };
14868519ac9Scegger
14968519ac9Scegger struct amdtemp_softc {
15068519ac9Scegger pci_chipset_tag_t sc_pc;
15168519ac9Scegger pcitag_t sc_pcitag;
15268519ac9Scegger
15368519ac9Scegger struct sysmon_envsys *sc_sme;
15468519ac9Scegger envsys_data_t *sc_sensor;
155c6e5cf85Sjruoho size_t sc_sensor_len;
15668519ac9Scegger
15768519ac9Scegger char sc_rev;
15868519ac9Scegger int8_t sc_numsensors;
15968519ac9Scegger uint32_t sc_family;
16072f1a5aaScegger int32_t sc_adjustment;
16168519ac9Scegger };
16268519ac9Scegger
16368519ac9Scegger static int amdtemp_match(device_t, cfdata_t, void *);
16468519ac9Scegger static void amdtemp_attach(device_t, device_t, void *);
165c6e5cf85Sjruoho static int amdtemp_detach(device_t, int);
16668519ac9Scegger
16768519ac9Scegger static void amdtemp_k8_init(struct amdtemp_softc *, pcireg_t);
16868519ac9Scegger static void amdtemp_k8_setup_sensors(struct amdtemp_softc *, int);
16968519ac9Scegger static void amdtemp_k8_refresh(struct sysmon_envsys *, envsys_data_t *);
17068519ac9Scegger
17168519ac9Scegger static void amdtemp_family10_init(struct amdtemp_softc *);
17268519ac9Scegger static void amdtemp_family10_setup_sensors(struct amdtemp_softc *, int);
17368519ac9Scegger static void amdtemp_family10_refresh(struct sysmon_envsys *, envsys_data_t *);
17468519ac9Scegger
17568519ac9Scegger CFATTACH_DECL_NEW(amdtemp, sizeof(struct amdtemp_softc),
176c6e5cf85Sjruoho amdtemp_match, amdtemp_attach, amdtemp_detach, NULL);
17768519ac9Scegger
17868519ac9Scegger static int
amdtemp_match(device_t parent,cfdata_t match,void * aux)17968519ac9Scegger amdtemp_match(device_t parent, cfdata_t match, void *aux)
18068519ac9Scegger {
18168519ac9Scegger struct pci_attach_args *pa = aux;
18268519ac9Scegger pcireg_t cpu_signature;
18368519ac9Scegger uint32_t family;
18468519ac9Scegger
185c42e0053Scegger KASSERT(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD);
18668519ac9Scegger
1873bd1efebSjruoho cpu_signature = pci_conf_read(pa->pa_pc,
1883bd1efebSjruoho pa->pa_tag, CPUID_FAMILY_MODEL_R);
18968519ac9Scegger
190124c8cd2Smaxv /*
191124c8cd2Smaxv * This CPUID northbridge register has been introduced in
192124c8cd2Smaxv * Revision F.
193124c8cd2Smaxv */
19468519ac9Scegger if (cpu_signature == 0x0)
19568519ac9Scegger return 0;
19668519ac9Scegger
197b1a32cacSmsaitoh family = CPUID_TO_FAMILY(cpu_signature);
19868519ac9Scegger
199f94b5172Scegger /* Errata #319: This has been fixed in Revision C2. */
200f94b5172Scegger if (family == 0x10) {
201b1a32cacSmsaitoh if (CPUID_TO_BASEMODEL(cpu_signature) < 4)
202f94b5172Scegger return 0;
203124c8cd2Smaxv if (CPUID_TO_BASEMODEL(cpu_signature) == 4 &&
204124c8cd2Smaxv CPUID_TO_STEPPING(cpu_signature) < 2)
205f94b5172Scegger return 0;
206f94b5172Scegger }
207f94b5172Scegger
208124c8cd2Smaxv /* Not yet supported CPUs. */
209867d63b1Sis if (family > 0x16)
21068519ac9Scegger return 0;
21168519ac9Scegger
212c42e0053Scegger return 1;
21368519ac9Scegger }
21468519ac9Scegger
21568519ac9Scegger static void
amdtemp_attach(device_t parent,device_t self,void * aux)21668519ac9Scegger amdtemp_attach(device_t parent, device_t self, void *aux)
21768519ac9Scegger {
21868519ac9Scegger struct amdtemp_softc *sc = device_private(self);
21968519ac9Scegger struct pci_attach_args *pa = aux;
22068519ac9Scegger pcireg_t cpu_signature;
22168519ac9Scegger int error;
22268519ac9Scegger uint8_t i;
22368519ac9Scegger
22468519ac9Scegger aprint_naive("\n");
225960d9f28Scegger aprint_normal(": AMD CPU Temperature Sensors");
22668519ac9Scegger
2273bd1efebSjruoho cpu_signature = pci_conf_read(pa->pa_pc,
2283bd1efebSjruoho pa->pa_tag, CPUID_FAMILY_MODEL_R);
22968519ac9Scegger
23068519ac9Scegger /* If we hit this, then match routine is wrong. */
23168519ac9Scegger KASSERT(cpu_signature != 0x0);
23268519ac9Scegger
233b1a32cacSmsaitoh sc->sc_family = CPUID_TO_FAMILY(cpu_signature);
2343bd1efebSjruoho
23568519ac9Scegger KASSERT(sc->sc_family >= 0xf);
23668519ac9Scegger
2373bd1efebSjruoho sc->sc_sme = NULL;
2383bd1efebSjruoho sc->sc_sensor = NULL;
2393bd1efebSjruoho
24068519ac9Scegger sc->sc_pc = pa->pa_pc;
24168519ac9Scegger sc->sc_pcitag = pa->pa_tag;
24272f1a5aaScegger sc->sc_adjustment = 0;
24368519ac9Scegger
24468519ac9Scegger switch (sc->sc_family) {
24568519ac9Scegger case 0xf: /* AMD K8 NPT */
24668519ac9Scegger amdtemp_k8_init(sc, cpu_signature);
24768519ac9Scegger break;
24868519ac9Scegger
24968519ac9Scegger case 0x10: /* AMD Barcelona/Phenom */
25068519ac9Scegger case 0x11: /* AMD Griffin */
251f34c8606Snonaka case 0x12: /* AMD Lynx/Sabine (Llano) */
252f34c8606Snonaka case 0x14: /* AMD Brazos (Ontario/Zacate/Desna) */
253*29002501Sis case 0x15: /* AMD Bobcat */
254*29002501Sis case 0x16: /* AMD Puma/Jaguar */
25568519ac9Scegger amdtemp_family10_init(sc);
25668519ac9Scegger break;
25768519ac9Scegger
25868519ac9Scegger default:
259960d9f28Scegger aprint_normal(", family 0x%x not supported\n",
260960d9f28Scegger sc->sc_family);
26168519ac9Scegger return;
26268519ac9Scegger }
26368519ac9Scegger
26468519ac9Scegger aprint_normal("\n");
26568519ac9Scegger
26672f1a5aaScegger if (sc->sc_adjustment != 0)
26772f1a5aaScegger aprint_debug_dev(self, "Workaround enabled\n");
26872f1a5aaScegger
26968519ac9Scegger sc->sc_sme = sysmon_envsys_create();
270c6e5cf85Sjruoho sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors;
2713bd1efebSjruoho sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP);
2723bd1efebSjruoho
27368519ac9Scegger switch (sc->sc_family) {
27468519ac9Scegger case 0xf:
27568519ac9Scegger amdtemp_k8_setup_sensors(sc, device_unit(self));
27668519ac9Scegger break;
27768519ac9Scegger case 0x10:
27868519ac9Scegger case 0x11:
279f34c8606Snonaka case 0x12:
2802e5784d8Sjmcneill case 0x14:
2815828a00eScegger case 0x15:
282867d63b1Sis case 0x16:
28368519ac9Scegger amdtemp_family10_setup_sensors(sc, device_unit(self));
28468519ac9Scegger break;
28568519ac9Scegger }
28668519ac9Scegger
28768519ac9Scegger /*
28868519ac9Scegger * Set properties in sensors.
28968519ac9Scegger */
29068519ac9Scegger for (i = 0; i < sc->sc_numsensors; i++) {
291124c8cd2Smaxv if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i]))
29268519ac9Scegger goto bad;
29368519ac9Scegger }
29468519ac9Scegger
29568519ac9Scegger /*
29668519ac9Scegger * Register the sysmon_envsys device.
29768519ac9Scegger */
29868519ac9Scegger sc->sc_sme->sme_name = device_xname(self);
29968519ac9Scegger sc->sc_sme->sme_cookie = sc;
30068519ac9Scegger
30168519ac9Scegger switch (sc->sc_family) {
30268519ac9Scegger case 0xf:
30368519ac9Scegger sc->sc_sme->sme_refresh = amdtemp_k8_refresh;
30468519ac9Scegger break;
30568519ac9Scegger case 0x10:
30668519ac9Scegger case 0x11:
307f34c8606Snonaka case 0x12:
3082e5784d8Sjmcneill case 0x14:
3095828a00eScegger case 0x15:
310867d63b1Sis case 0x16:
31168519ac9Scegger sc->sc_sme->sme_refresh = amdtemp_family10_refresh;
31268519ac9Scegger break;
31368519ac9Scegger }
31468519ac9Scegger
31568519ac9Scegger error = sysmon_envsys_register(sc->sc_sme);
31668519ac9Scegger if (error) {
31768519ac9Scegger aprint_error_dev(self, "unable to register with sysmon "
31868519ac9Scegger "(error=%d)\n", error);
31968519ac9Scegger goto bad;
32068519ac9Scegger }
32168519ac9Scegger
3223bd1efebSjruoho (void)pmf_device_register(self, NULL, NULL);
32368519ac9Scegger
32468519ac9Scegger return;
32568519ac9Scegger
32668519ac9Scegger bad:
3273bd1efebSjruoho if (sc->sc_sme != NULL) {
32868519ac9Scegger sysmon_envsys_destroy(sc->sc_sme);
329c6e5cf85Sjruoho sc->sc_sme = NULL;
330c6e5cf85Sjruoho }
331c6e5cf85Sjruoho
3323bd1efebSjruoho if (sc->sc_sensor != NULL) {
3333bd1efebSjruoho kmem_free(sc->sc_sensor, sc->sc_sensor_len);
3343bd1efebSjruoho sc->sc_sensor = NULL;
3353bd1efebSjruoho }
3363bd1efebSjruoho }
3373bd1efebSjruoho
338c6e5cf85Sjruoho static int
amdtemp_detach(device_t self,int flags)339c6e5cf85Sjruoho amdtemp_detach(device_t self, int flags)
340c6e5cf85Sjruoho {
341c6e5cf85Sjruoho struct amdtemp_softc *sc = device_private(self);
342c6e5cf85Sjruoho
3435828a00eScegger pmf_device_deregister(self);
344c6e5cf85Sjruoho if (sc->sc_sme != NULL)
345c6e5cf85Sjruoho sysmon_envsys_unregister(sc->sc_sme);
346c6e5cf85Sjruoho
347c6e5cf85Sjruoho if (sc->sc_sensor != NULL)
348c6e5cf85Sjruoho kmem_free(sc->sc_sensor, sc->sc_sensor_len);
349c6e5cf85Sjruoho
350c6e5cf85Sjruoho return 0;
35168519ac9Scegger }
35268519ac9Scegger
35368519ac9Scegger static void
amdtemp_k8_init(struct amdtemp_softc * sc,pcireg_t cpu_signature)35468519ac9Scegger amdtemp_k8_init(struct amdtemp_softc *sc, pcireg_t cpu_signature)
35568519ac9Scegger {
35668519ac9Scegger pcireg_t data;
35768519ac9Scegger uint32_t cmpcap;
35868519ac9Scegger uint8_t i, j;
35968519ac9Scegger
36068519ac9Scegger aprint_normal(" (K8");
36168519ac9Scegger
36268519ac9Scegger for (i = 0; i < __arraycount(amdtemp_core) && sc->sc_rev == '\0'; i++) {
36372f1a5aaScegger for (j = 0; amdtemp_core[i].cpu[j].cpuid != 0; j++) {
36468519ac9Scegger if ((cpu_signature & ~0xf)
36572f1a5aaScegger != amdtemp_core[i].cpu[j].cpuid)
36672f1a5aaScegger continue;
36772f1a5aaScegger
36868519ac9Scegger sc->sc_rev = amdtemp_core[i].rev[3];
36968519ac9Scegger aprint_normal(": core rev %.4s%.1x",
37068519ac9Scegger amdtemp_core[i].rev,
371b1a32cacSmsaitoh CPUID_TO_STEPPING(cpu_signature));
37272f1a5aaScegger
37372f1a5aaScegger switch (amdtemp_core[i].cpu[j].socket) {
37472f1a5aaScegger case K8_SOCKET_AM2:
3759db96566Scegger if (sc->sc_rev == 'G')
37672f1a5aaScegger sc->sc_adjustment = 21000000;
37772f1a5aaScegger aprint_normal(", socket AM2");
37872f1a5aaScegger break;
37972f1a5aaScegger case K8_SOCKET_S1:
38072f1a5aaScegger aprint_normal(", socket S1");
38172f1a5aaScegger break;
38272f1a5aaScegger case K8_SOCKET_F:
38372f1a5aaScegger aprint_normal(", socket F");
38472f1a5aaScegger break;
38568519ac9Scegger }
38668519ac9Scegger }
38768519ac9Scegger }
38868519ac9Scegger
38968519ac9Scegger if (sc->sc_rev == '\0') {
390124c8cd2Smaxv /*
391124c8cd2Smaxv * CPUID Family Model Register was introduced in
392124c8cd2Smaxv * Revision F
393124c8cd2Smaxv */
39468519ac9Scegger sc->sc_rev = 'G'; /* newer than E, assume G */
39568519ac9Scegger aprint_normal(": cpuid 0x%x", cpu_signature);
39668519ac9Scegger }
39768519ac9Scegger
39868519ac9Scegger aprint_normal(")");
39968519ac9Scegger
40068519ac9Scegger data = pci_conf_read(sc->sc_pc, sc->sc_pcitag, NORTHBRIDGE_CAP_R);
40168519ac9Scegger cmpcap = (data >> 12) & 0x3;
40268519ac9Scegger
40368519ac9Scegger sc->sc_numsensors = cmpcap ? 4 : 2;
40468519ac9Scegger }
40568519ac9Scegger
40668519ac9Scegger static void
amdtemp_k8_setup_sensors(struct amdtemp_softc * sc,int dv_unit)40768519ac9Scegger amdtemp_k8_setup_sensors(struct amdtemp_softc *sc, int dv_unit)
40868519ac9Scegger {
40968519ac9Scegger uint8_t i;
41068519ac9Scegger
411124c8cd2Smaxv /*
412124c8cd2Smaxv * There are two sensors per CPU core. So we use the device unit as
413124c8cd2Smaxv * socket counter to correctly enumerate the CPUs on multi-socket
414124c8cd2Smaxv * machines.
41568519ac9Scegger */
41668519ac9Scegger dv_unit *= (sc->sc_numsensors / 2);
41768519ac9Scegger for (i = 0; i < sc->sc_numsensors; i++) {
41868519ac9Scegger sc->sc_sensor[i].units = ENVSYS_STEMP;
41968519ac9Scegger sc->sc_sensor[i].state = ENVSYS_SVALID;
42098b25da6Spgoyette sc->sc_sensor[i].flags = ENVSYS_FHAS_ENTROPY;
42168519ac9Scegger
42268519ac9Scegger snprintf(sc->sc_sensor[i].desc, sizeof(sc->sc_sensor[i].desc),
42368519ac9Scegger "CPU%u Sensor%u", dv_unit + (i / 2), i % 2);
42468519ac9Scegger }
42568519ac9Scegger }
42668519ac9Scegger
42768519ac9Scegger static void
amdtemp_k8_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)42868519ac9Scegger amdtemp_k8_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
42968519ac9Scegger {
43068519ac9Scegger struct amdtemp_softc *sc = sme->sme_cookie;
43168519ac9Scegger pcireg_t status, match, tmp;
43268519ac9Scegger uint32_t value;
43368519ac9Scegger
43468519ac9Scegger status = pci_conf_read(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R);
43568519ac9Scegger
43668519ac9Scegger switch (edata->sensor) { /* sensor number */
43768519ac9Scegger case 0: /* Core 0 Sensor 0 */
43868519ac9Scegger K8_T_SEL_C0(status);
43968519ac9Scegger K8_T_SEL_S0(status);
44068519ac9Scegger break;
44168519ac9Scegger case 1: /* Core 0 Sensor 1 */
44268519ac9Scegger K8_T_SEL_C0(status);
44368519ac9Scegger K8_T_SEL_S1(status);
44468519ac9Scegger break;
44568519ac9Scegger case 2: /* Core 1 Sensor 0 */
44668519ac9Scegger K8_T_SEL_C1(status);
44768519ac9Scegger K8_T_SEL_S0(status);
44868519ac9Scegger break;
44968519ac9Scegger case 3: /* Core 1 Sensor 1 */
45068519ac9Scegger K8_T_SEL_C1(status);
45168519ac9Scegger K8_T_SEL_S1(status);
45268519ac9Scegger break;
45368519ac9Scegger }
45468519ac9Scegger
45568519ac9Scegger match = status & (K8_THERM_SENSE_CORE_SEL | K8_THERM_SENSE_SEL);
45668519ac9Scegger pci_conf_write(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R, status);
45768519ac9Scegger status = pci_conf_read(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R);
45868519ac9Scegger tmp = status & (K8_THERM_SENSE_CORE_SEL | K8_THERM_SENSE_SEL);
45968519ac9Scegger
46068519ac9Scegger value = 0x3ff & (status >> 14);
46168519ac9Scegger if (sc->sc_rev != 'G')
46268519ac9Scegger value &= ~0x3;
46368519ac9Scegger
46468519ac9Scegger edata->state = ENVSYS_SINVALID;
46568519ac9Scegger if ((tmp == match) && ((value & ~0x3) != 0)) {
46668519ac9Scegger edata->state = ENVSYS_SVALID;
467124c8cd2Smaxv edata->value_cur = (value * 250000 - 49000000) + 273150000 +
468124c8cd2Smaxv sc->sc_adjustment;
46968519ac9Scegger }
47068519ac9Scegger }
47168519ac9Scegger
47268519ac9Scegger static void
amdtemp_family10_init(struct amdtemp_softc * sc)47368519ac9Scegger amdtemp_family10_init(struct amdtemp_softc *sc)
47468519ac9Scegger {
4752e5784d8Sjmcneill aprint_normal(" (Family%02xh)", sc->sc_family);
47668519ac9Scegger
47768519ac9Scegger sc->sc_numsensors = 1;
47868519ac9Scegger }
47968519ac9Scegger
48068519ac9Scegger static void
amdtemp_family10_setup_sensors(struct amdtemp_softc * sc,int dv_unit)48168519ac9Scegger amdtemp_family10_setup_sensors(struct amdtemp_softc *sc, int dv_unit)
48268519ac9Scegger {
48368519ac9Scegger /* sanity check for future enhancements */
48468519ac9Scegger KASSERT(sc->sc_numsensors == 1);
48568519ac9Scegger
486124c8cd2Smaxv /*
487124c8cd2Smaxv * There's one sensor per memory controller (= socket), so we use the
488124c8cd2Smaxv * device unit as socket counter to correctly enumerate the CPUs.
48968519ac9Scegger */
49068519ac9Scegger sc->sc_sensor[0].units = ENVSYS_STEMP;
49168519ac9Scegger sc->sc_sensor[0].state = ENVSYS_SVALID;
49298b25da6Spgoyette sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY;
49368519ac9Scegger
49468519ac9Scegger snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc),
4952e5784d8Sjmcneill "cpu%u temperature", dv_unit);
49668519ac9Scegger }
49768519ac9Scegger
49868519ac9Scegger static void
amdtemp_family10_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)49968519ac9Scegger amdtemp_family10_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
50068519ac9Scegger {
50168519ac9Scegger struct amdtemp_softc *sc = sme->sme_cookie;
50268519ac9Scegger pcireg_t status;
50368519ac9Scegger uint32_t value;
50468519ac9Scegger
505124c8cd2Smaxv status = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
506124c8cd2Smaxv F10_TEMPERATURE_CTL_R);
507124c8cd2Smaxv value = __SHIFTOUT(status, F10_TEMP_CURTMP);
50868519ac9Scegger
509124c8cd2Smaxv /* From Celsius to micro-Kelvin. */
510124c8cd2Smaxv edata->value_cur = (value * 125000) + 273150000;
51168519ac9Scegger edata->state = ENVSYS_SVALID;
51268519ac9Scegger }
513c6e5cf85Sjruoho
51476a2f91aSpgoyette MODULE(MODULE_CLASS_DRIVER, amdtemp, "sysmon_envsys");
515c6e5cf85Sjruoho
516c6e5cf85Sjruoho #ifdef _MODULE
517c6e5cf85Sjruoho #include "ioconf.c"
518c6e5cf85Sjruoho #endif
519c6e5cf85Sjruoho
520c6e5cf85Sjruoho static int
amdtemp_modcmd(modcmd_t cmd,void * aux)521c6e5cf85Sjruoho amdtemp_modcmd(modcmd_t cmd, void *aux)
522c6e5cf85Sjruoho {
523c6e5cf85Sjruoho int error = 0;
524c6e5cf85Sjruoho
525c6e5cf85Sjruoho switch (cmd) {
526c6e5cf85Sjruoho case MODULE_CMD_INIT:
527c6e5cf85Sjruoho #ifdef _MODULE
528c6e5cf85Sjruoho error = config_init_component(cfdriver_ioconf_amdtemp,
529c6e5cf85Sjruoho cfattach_ioconf_amdtemp, cfdata_ioconf_amdtemp);
530c6e5cf85Sjruoho #endif
531c6e5cf85Sjruoho return error;
532c6e5cf85Sjruoho case MODULE_CMD_FINI:
533c6e5cf85Sjruoho #ifdef _MODULE
534c6e5cf85Sjruoho error = config_fini_component(cfdriver_ioconf_amdtemp,
535c6e5cf85Sjruoho cfattach_ioconf_amdtemp, cfdata_ioconf_amdtemp);
536c6e5cf85Sjruoho #endif
537c6e5cf85Sjruoho return error;
538c6e5cf85Sjruoho default:
539c6e5cf85Sjruoho return ENOTTY;
540c6e5cf85Sjruoho }
541c6e5cf85Sjruoho }
542