amdtemp.c revision 197205
1178151Srpaulo/*-
2189769Srpaulo * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org>
3189769Srpaulo * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org>
4197102Sjkim * Copyright (c) 2009 Jung-uk Kim <jkim@FreeBSD.org>
5178151Srpaulo * All rights reserved.
6178151Srpaulo *
7178151Srpaulo * Redistribution and use in source and binary forms, with or without
8178151Srpaulo * modification, are permitted provided that the following conditions
9178151Srpaulo * are met:
10178151Srpaulo * 1. Redistributions of source code must retain the above copyright
11178151Srpaulo *    notice, this list of conditions and the following disclaimer.
12178151Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
13178151Srpaulo *    notice, this list of conditions and the following disclaimer in the
14178151Srpaulo *    documentation and/or other materials provided with the distribution.
15178151Srpaulo *
16178151Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17178151Srpaulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18178151Srpaulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19178151Srpaulo * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20178151Srpaulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21178151Srpaulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22178151Srpaulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23178151Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24178151Srpaulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25178151Srpaulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26178151Srpaulo * POSSIBILITY OF SUCH DAMAGE.
27178151Srpaulo */
28178151Srpaulo
29178151Srpaulo/*
30197102Sjkim * Driver for the AMD CPU on-die thermal sensors for Family 0Fh/10h/11h procs.
31197102Sjkim * Initially based on the k8temp Linux driver.
32178151Srpaulo */
33178151Srpaulo
34178151Srpaulo#include <sys/cdefs.h>
35178151Srpaulo__FBSDID("$FreeBSD: head/sys/dev/amdtemp/amdtemp.c 197205 2009-09-14 23:08:19Z jkim $");
36178151Srpaulo
37178151Srpaulo#include <sys/param.h>
38178151Srpaulo#include <sys/bus.h>
39178151Srpaulo#include <sys/conf.h>
40178151Srpaulo#include <sys/kernel.h>
41197102Sjkim#include <sys/module.h>
42178151Srpaulo#include <sys/sysctl.h>
43197102Sjkim#include <sys/systm.h>
44178151Srpaulo
45197205Sjkim#include <machine/cpufunc.h>
46197102Sjkim#include <machine/md_var.h>
47178151Srpaulo#include <machine/specialreg.h>
48178151Srpaulo
49178151Srpaulo#include <dev/pci/pcivar.h>
50178151Srpaulo
51189769Srpaulotypedef enum {
52189769Srpaulo	SENSOR0_CORE0,
53189769Srpaulo	SENSOR0_CORE1,
54189769Srpaulo	SENSOR1_CORE0,
55189769Srpaulo	SENSOR1_CORE1,
56189769Srpaulo	CORE0,
57189769Srpaulo	CORE1
58189769Srpaulo} amdsensor_t;
59189769Srpaulo
60189769Srpaulostruct amdtemp_softc {
61178151Srpaulo	device_t	sc_dev;
62197102Sjkim	int		sc_ncores;
63178151Srpaulo	int		sc_ntemps;
64197205Sjkim	int		sc_flags;
65197205Sjkim#define	AMDTEMP_FLAG_DO_QUIRK	0x01	/* DiodeOffset may be incorrect. */
66197205Sjkim#define	AMDTEMP_FLAG_DO_ZERO	0x02	/* DiodeOffset starts from 0C. */
67197205Sjkim#define	AMDTEMP_FLAG_DO_SIGN	0x04	/* DiodeOffsetSignBit is present. */
68197205Sjkim#define	AMDTEMP_FLAG_CS_SWAP	0x08	/* ThermSenseCoreSel is inverted. */
69197205Sjkim#define	AMDTEMP_FLAG_CT_10BIT	0x10	/* CurTmp is 10-bit wide. */
70197102Sjkim	int32_t		(*sc_gettemp)(device_t, amdsensor_t);
71197102Sjkim	struct sysctl_oid *sc_sysctl_cpu[MAXCPU];
72180312Srpaulo	struct intr_config_hook sc_ich;
73178151Srpaulo};
74178151Srpaulo
75197102Sjkim#define	VENDORID_AMD		0x1022
76197102Sjkim#define	DEVICEID_AMD_MISC0F	0x1103
77197102Sjkim#define	DEVICEID_AMD_MISC10	0x1203
78197102Sjkim#define	DEVICEID_AMD_MISC11	0x1303
79178151Srpaulo
80189769Srpaulostatic struct amdtemp_product {
81189769Srpaulo	uint16_t	amdtemp_vendorid;
82189769Srpaulo	uint16_t	amdtemp_deviceid;
83189769Srpaulo} amdtemp_products[] = {
84189769Srpaulo	{ VENDORID_AMD,	DEVICEID_AMD_MISC0F },
85189769Srpaulo	{ VENDORID_AMD,	DEVICEID_AMD_MISC10 },
86189769Srpaulo	{ VENDORID_AMD,	DEVICEID_AMD_MISC11 },
87178151Srpaulo	{ 0, 0 }
88178151Srpaulo};
89178151Srpaulo
90178151Srpaulo/*
91197102Sjkim * Reported Temperature Control Register (Family 10h/11h only)
92178151Srpaulo */
93197102Sjkim#define	AMDTEMP_REPTMP_CTRL	0xa4
94178151Srpaulo
95189769Srpaulo/*
96197102Sjkim * Thermaltrip Status Register
97189769Srpaulo */
98197102Sjkim#define	AMDTEMP_THERMTP_STAT	0xe4
99197102Sjkim#define	AMDTEMP_TTSR_SELCORE	0x04	/* Family 0Fh only */
100197102Sjkim#define	AMDTEMP_TTSR_SELSENSOR	0x40	/* Family 0Fh only */
101178151Srpaulo
102197102Sjkim/*
103197102Sjkim * CPU Family/Model Register
104197102Sjkim */
105197102Sjkim#define	AMDTEMP_CPUID		0xfc
106178151Srpaulo
107178151Srpaulo/*
108178151Srpaulo * Device methods.
109178151Srpaulo */
110189769Srpaulostatic void 	amdtemp_identify(driver_t *driver, device_t parent);
111189769Srpaulostatic int	amdtemp_probe(device_t dev);
112189769Srpaulostatic int	amdtemp_attach(device_t dev);
113189769Srpaulostatic void	amdtemp_intrhook(void *arg);
114189769Srpaulostatic int	amdtemp_detach(device_t dev);
115189769Srpaulostatic int 	amdtemp_match(device_t dev);
116189769Srpaulostatic int32_t	amdtemp_gettemp0f(device_t dev, amdsensor_t sensor);
117189769Srpaulostatic int32_t	amdtemp_gettemp(device_t dev, amdsensor_t sensor);
118189769Srpaulostatic int	amdtemp_sysctl(SYSCTL_HANDLER_ARGS);
119178151Srpaulo
120189769Srpaulostatic device_method_t amdtemp_methods[] = {
121178151Srpaulo	/* Device interface */
122189769Srpaulo	DEVMETHOD(device_identify,	amdtemp_identify),
123189769Srpaulo	DEVMETHOD(device_probe,		amdtemp_probe),
124189769Srpaulo	DEVMETHOD(device_attach,	amdtemp_attach),
125189769Srpaulo	DEVMETHOD(device_detach,	amdtemp_detach),
126178151Srpaulo
127178151Srpaulo	{0, 0}
128178151Srpaulo};
129178151Srpaulo
130189769Srpaulostatic driver_t amdtemp_driver = {
131189769Srpaulo	"amdtemp",
132189769Srpaulo	amdtemp_methods,
133189769Srpaulo	sizeof(struct amdtemp_softc),
134178151Srpaulo};
135178151Srpaulo
136189769Srpaulostatic devclass_t amdtemp_devclass;
137189769SrpauloDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL);
138178151Srpaulo
139178151Srpaulostatic int
140189769Srpauloamdtemp_match(device_t dev)
141178151Srpaulo{
142178151Srpaulo	int i;
143178151Srpaulo	uint16_t vendor, devid;
144197102Sjkim
145197102Sjkim	vendor = pci_get_vendor(dev);
146178151Srpaulo	devid = pci_get_device(dev);
147178151Srpaulo
148189769Srpaulo	for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) {
149189769Srpaulo		if (vendor == amdtemp_products[i].amdtemp_vendorid &&
150189769Srpaulo		    devid == amdtemp_products[i].amdtemp_deviceid)
151178151Srpaulo			return (1);
152178151Srpaulo	}
153178151Srpaulo
154178151Srpaulo	return (0);
155178151Srpaulo}
156178151Srpaulo
157178151Srpaulostatic void
158189769Srpauloamdtemp_identify(driver_t *driver, device_t parent)
159178151Srpaulo{
160178151Srpaulo	device_t child;
161178151Srpaulo
162178151Srpaulo	/* Make sure we're not being doubly invoked. */
163189769Srpaulo	if (device_find_child(parent, "amdtemp", -1) != NULL)
164178151Srpaulo		return;
165197102Sjkim
166189769Srpaulo	if (amdtemp_match(parent)) {
167189769Srpaulo		child = device_add_child(parent, "amdtemp", -1);
168178151Srpaulo		if (child == NULL)
169189769Srpaulo			device_printf(parent, "add amdtemp child failed\n");
170178151Srpaulo	}
171178151Srpaulo}
172178151Srpaulo
173178151Srpaulostatic int
174189769Srpauloamdtemp_probe(device_t dev)
175178151Srpaulo{
176197205Sjkim	uint32_t family, model;
177197102Sjkim
178189769Srpaulo	if (resource_disabled("amdtemp", 0))
179178151Srpaulo		return (ENXIO);
180178151Srpaulo
181197205Sjkim	family = CPUID_TO_FAMILY(cpu_id);
182197205Sjkim	model = CPUID_TO_MODEL(cpu_id);
183197102Sjkim
184197102Sjkim	switch (family) {
185197102Sjkim	case 0x0f:
186197205Sjkim		if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) ||
187197205Sjkim		    (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1))
188197102Sjkim			return (ENXIO);
189197102Sjkim		break;
190197102Sjkim	case 0x10:
191197102Sjkim	case 0x11:
192197102Sjkim		break;
193197102Sjkim	default:
194178151Srpaulo		return (ENXIO);
195178151Srpaulo	}
196197102Sjkim	device_set_desc(dev, "AMD CPU On-Die Thermal Sensors");
197197102Sjkim
198178151Srpaulo	return (BUS_PROBE_GENERIC);
199178151Srpaulo}
200178151Srpaulo
201178151Srpaulostatic int
202189769Srpauloamdtemp_attach(device_t dev)
203178151Srpaulo{
204189769Srpaulo	struct amdtemp_softc *sc = device_get_softc(dev);
205178151Srpaulo	struct sysctl_ctx_list *sysctlctx;
206178151Srpaulo	struct sysctl_oid *sysctlnode;
207197205Sjkim	uint32_t regs[4];
208197102Sjkim	uint32_t cpuid, family, model;
209178151Srpaulo
210197205Sjkim	/*
211197205Sjkim	 * Errata #154: Incorect Diode Offset
212197205Sjkim	 */
213197205Sjkim	if (cpu_id == 0x20f32) {
214197205Sjkim		do_cpuid(0x80000001, regs);
215197205Sjkim		if ((regs[1] & 0xfff) == 0x2c)
216197205Sjkim			sc->sc_flags |= AMDTEMP_FLAG_DO_QUIRK;
217197205Sjkim	}
218180312Srpaulo
219197205Sjkim	/*
220197205Sjkim	 * CPUID Register is available from Revision F.
221197205Sjkim	 */
222197205Sjkim	family = CPUID_TO_FAMILY(cpu_id);
223197205Sjkim	model = CPUID_TO_MODEL(cpu_id);
224197205Sjkim	if (family != 0x0f || model >= 0x40) {
225197205Sjkim		cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4);
226197205Sjkim		family = CPUID_TO_FAMILY(cpuid);
227197205Sjkim		model = CPUID_TO_MODEL(cpuid);
228197205Sjkim	}
229197205Sjkim
230197102Sjkim	switch (family) {
231197102Sjkim	case 0x0f:
232197102Sjkim		/*
233197205Sjkim		 * Thermaltrip Status Register
234197102Sjkim		 *
235197205Sjkim		 * - DiodeOffsetSignBit
236197205Sjkim		 *
237197205Sjkim		 * Revision D & E:	bit 24
238197205Sjkim		 * Other:		N/A
239197205Sjkim		 *
240197205Sjkim		 * - ThermSenseCoreSel
241197205Sjkim		 *
242197205Sjkim		 * Revision F & G:	0 - Core1, 1 - Core0
243197205Sjkim		 * Other:		0 - Core0, 1 - Core1
244197205Sjkim		 *
245197205Sjkim		 * - CurTmp
246197205Sjkim		 *
247197102Sjkim		 * Revision G:		bits 23-14
248197205Sjkim		 * Other:		bits 23-16
249197102Sjkim		 *
250197205Sjkim		 * XXX According to the BKDG, CurTmp, ThermSenseSel and
251197205Sjkim		 * ThermSenseCoreSel bits were introduced in Revision F
252197205Sjkim		 * but CurTmp seems working fine as early as Revision C.
253197205Sjkim		 * However, it is not clear whether ThermSenseSel and/or
254197205Sjkim		 * ThermSenseCoreSel work in undocumented cases as well.
255197205Sjkim		 * In fact, the Linux driver suggests it may not work but
256197205Sjkim		 * we just assume it does until we find otherwise.
257197102Sjkim		 */
258197205Sjkim		if (model < 0x40) {
259197205Sjkim			sc->sc_flags |= AMDTEMP_FLAG_DO_ZERO;
260197205Sjkim			if (model >= 0x10)
261197205Sjkim				sc->sc_flags |= AMDTEMP_FLAG_DO_SIGN;
262197205Sjkim		} else {
263197205Sjkim			sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP;
264197205Sjkim			if (model >= 0x60 && model != 0xc1)
265197205Sjkim				sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT;
266197205Sjkim		}
267197102Sjkim
268197102Sjkim		/*
269197102Sjkim		 * There are two sensors per core.
270197102Sjkim		 */
271197102Sjkim		sc->sc_ntemps = 2;
272197102Sjkim
273189769Srpaulo		sc->sc_gettemp = amdtemp_gettemp0f;
274197102Sjkim		break;
275197102Sjkim	case 0x10:
276197102Sjkim	case 0x11:
277197102Sjkim		/*
278197102Sjkim		 * There is only one sensor per package.
279197102Sjkim		 */
280197102Sjkim		sc->sc_ntemps = 1;
281197102Sjkim
282189769Srpaulo		sc->sc_gettemp = amdtemp_gettemp;
283197102Sjkim		break;
284189769Srpaulo	}
285189769Srpaulo
286197102Sjkim	/* Find number of cores per package. */
287197102Sjkim	sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ?
288197102Sjkim	    (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
289197102Sjkim	if (sc->sc_ncores > MAXCPU)
290197102Sjkim		return (ENXIO);
291197102Sjkim
292197102Sjkim	if (bootverbose)
293197102Sjkim		device_printf(dev, "Found %d cores and %d sensors.\n",
294197102Sjkim		    sc->sc_ncores,
295197102Sjkim		    sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1);
296197102Sjkim
297178151Srpaulo	/*
298189769Srpaulo	 * dev.amdtemp.N tree.
299178151Srpaulo	 */
300178151Srpaulo	sysctlctx = device_get_sysctl_ctx(dev);
301178151Srpaulo	sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
302197102Sjkim	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
303197102Sjkim	    "sensor0", CTLFLAG_RD, 0, "Sensor 0");
304197102Sjkim
305178151Srpaulo	SYSCTL_ADD_PROC(sysctlctx,
306178151Srpaulo	    SYSCTL_CHILDREN(sysctlnode),
307178151Srpaulo	    OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD,
308189769Srpaulo	    dev, SENSOR0_CORE0, amdtemp_sysctl, "IK",
309178151Srpaulo	    "Sensor 0 / Core 0 temperature");
310178151Srpaulo
311197102Sjkim	if (sc->sc_ntemps > 1) {
312197102Sjkim		if (sc->sc_ncores > 1)
313197102Sjkim			SYSCTL_ADD_PROC(sysctlctx,
314197102Sjkim			    SYSCTL_CHILDREN(sysctlnode),
315197102Sjkim			    OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD,
316197102Sjkim			    dev, SENSOR0_CORE1, amdtemp_sysctl, "IK",
317197102Sjkim			    "Sensor 0 / Core 1 temperature");
318197102Sjkim
319197102Sjkim		sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
320197102Sjkim		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
321197102Sjkim		    "sensor1", CTLFLAG_RD, 0, "Sensor 1");
322197102Sjkim
323197102Sjkim		SYSCTL_ADD_PROC(sysctlctx,
324197102Sjkim		    SYSCTL_CHILDREN(sysctlnode),
325197102Sjkim		    OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD,
326197102Sjkim		    dev, SENSOR1_CORE0, amdtemp_sysctl, "IK",
327197102Sjkim		    "Sensor 1 / Core 0 temperature");
328197102Sjkim
329197102Sjkim		if (sc->sc_ncores > 1)
330197102Sjkim			SYSCTL_ADD_PROC(sysctlctx,
331197102Sjkim			    SYSCTL_CHILDREN(sysctlnode),
332197102Sjkim			    OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD,
333197102Sjkim			    dev, SENSOR1_CORE1, amdtemp_sysctl, "IK",
334197102Sjkim			    "Sensor 1 / Core 1 temperature");
335197102Sjkim	}
336197102Sjkim
337197102Sjkim	/*
338197102Sjkim	 * Try to create dev.cpu sysctl entries and setup intrhook function.
339197102Sjkim	 * This is needed because the cpu driver may be loaded late on boot,
340197102Sjkim	 * after us.
341197102Sjkim	 */
342197102Sjkim	amdtemp_intrhook(dev);
343197102Sjkim	sc->sc_ich.ich_func = amdtemp_intrhook;
344197102Sjkim	sc->sc_ich.ich_arg = dev;
345197102Sjkim	if (config_intrhook_establish(&sc->sc_ich) != 0) {
346197102Sjkim		device_printf(dev, "config_intrhook_establish failed!\n");
347197102Sjkim		return (ENXIO);
348197102Sjkim	}
349197102Sjkim
350178151Srpaulo	return (0);
351178151Srpaulo}
352178151Srpaulo
353180312Srpaulovoid
354189769Srpauloamdtemp_intrhook(void *arg)
355180312Srpaulo{
356189769Srpaulo	struct amdtemp_softc *sc;
357180312Srpaulo	struct sysctl_ctx_list *sysctlctx;
358197102Sjkim	device_t dev = (device_t)arg;
359197102Sjkim	device_t acpi, cpu, nexus;
360197102Sjkim	amdsensor_t sensor;
361197102Sjkim	int i;
362180312Srpaulo
363180312Srpaulo	sc = device_get_softc(dev);
364197102Sjkim
365180312Srpaulo	/*
366180312Srpaulo	 * dev.cpu.N.temperature.
367180312Srpaulo	 */
368180312Srpaulo	nexus = device_find_child(root_bus, "nexus", 0);
369180312Srpaulo	acpi = device_find_child(nexus, "acpi", 0);
370180312Srpaulo
371197102Sjkim	for (i = 0; i < sc->sc_ncores; i++) {
372197102Sjkim		if (sc->sc_sysctl_cpu[i] != NULL)
373197102Sjkim			continue;
374180312Srpaulo		cpu = device_find_child(acpi, "cpu",
375197102Sjkim		    device_get_unit(dev) * sc->sc_ncores + i);
376197102Sjkim		if (cpu != NULL) {
377180312Srpaulo			sysctlctx = device_get_sysctl_ctx(cpu);
378180312Srpaulo
379197102Sjkim			sensor = sc->sc_ntemps > 1 ?
380197102Sjkim			    (i == 0 ? CORE0 : CORE1) : SENSOR0_CORE0;
381180312Srpaulo			sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx,
382180312Srpaulo			    SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
383180312Srpaulo			    OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
384197102Sjkim			    dev, sensor, amdtemp_sysctl, "IK",
385197102Sjkim			    "Current temparature");
386180312Srpaulo		}
387180312Srpaulo	}
388197102Sjkim	if (sc->sc_ich.ich_arg != NULL)
389197102Sjkim		config_intrhook_disestablish(&sc->sc_ich);
390180312Srpaulo}
391180312Srpaulo
392178151Srpauloint
393189769Srpauloamdtemp_detach(device_t dev)
394178151Srpaulo{
395197102Sjkim	struct amdtemp_softc *sc = device_get_softc(dev);
396178151Srpaulo	int i;
397197102Sjkim
398197102Sjkim	for (i = 0; i < sc->sc_ncores; i++)
399197102Sjkim		if (sc->sc_sysctl_cpu[i] != NULL)
400178151Srpaulo			sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0);
401178151Srpaulo
402189769Srpaulo	/* NewBus removes the dev.amdtemp.N tree by itself. */
403197102Sjkim
404178151Srpaulo	return (0);
405178151Srpaulo}
406178151Srpaulo
407178151Srpaulostatic int
408189769Srpauloamdtemp_sysctl(SYSCTL_HANDLER_ARGS)
409178151Srpaulo{
410197102Sjkim	device_t dev = (device_t)arg1;
411189769Srpaulo	struct amdtemp_softc *sc = device_get_softc(dev);
412197102Sjkim	amdsensor_t sensor = (amdsensor_t)arg2;
413197102Sjkim	int32_t auxtemp[2], temp;
414178151Srpaulo	int error;
415178151Srpaulo
416197102Sjkim	switch (sensor) {
417178151Srpaulo	case CORE0:
418189769Srpaulo		auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE0);
419189769Srpaulo		auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE0);
420178988Srpaulo		temp = imax(auxtemp[0], auxtemp[1]);
421178151Srpaulo		break;
422178151Srpaulo	case CORE1:
423189769Srpaulo		auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE1);
424189769Srpaulo		auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE1);
425178988Srpaulo		temp = imax(auxtemp[0], auxtemp[1]);
426178151Srpaulo		break;
427178151Srpaulo	default:
428197102Sjkim		temp = sc->sc_gettemp(dev, sensor);
429178151Srpaulo		break;
430178151Srpaulo	}
431178151Srpaulo	error = sysctl_handle_int(oidp, &temp, 0, req);
432197102Sjkim
433178151Srpaulo	return (error);
434178151Srpaulo}
435178151Srpaulo
436197102Sjkim#define	AMDTEMP_ZERO_C_TO_K	2732
437197102Sjkim
438178151Srpaulostatic int32_t
439189769Srpauloamdtemp_gettemp0f(device_t dev, amdsensor_t sensor)
440178151Srpaulo{
441197102Sjkim	struct amdtemp_softc *sc = device_get_softc(dev);
442197205Sjkim	uint32_t mask, temp;
443197102Sjkim	int32_t diode_offset, offset;
444197102Sjkim	uint8_t cfg, sel;
445197102Sjkim
446197102Sjkim	/* Set Sensor/Core selector. */
447197102Sjkim	sel = 0;
448178151Srpaulo	switch (sensor) {
449197102Sjkim	case SENSOR1_CORE0:
450197102Sjkim		sel |= AMDTEMP_TTSR_SELSENSOR;
451197103Sjkim		/* FALLTHROUGH */
452178151Srpaulo	case SENSOR0_CORE0:
453197102Sjkim	case CORE0:
454197205Sjkim		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0)
455197102Sjkim			sel |= AMDTEMP_TTSR_SELCORE;
456178151Srpaulo		break;
457197102Sjkim	case SENSOR1_CORE1:
458197102Sjkim		sel |= AMDTEMP_TTSR_SELSENSOR;
459197103Sjkim		/* FALLTHROUGH */
460178151Srpaulo	case SENSOR0_CORE1:
461197102Sjkim	case CORE1:
462197205Sjkim		if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0)
463197102Sjkim			sel |= AMDTEMP_TTSR_SELCORE;
464178151Srpaulo		break;
465178151Srpaulo	}
466197102Sjkim	cfg = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1);
467197102Sjkim	cfg &= ~(AMDTEMP_TTSR_SELSENSOR | AMDTEMP_TTSR_SELCORE);
468197102Sjkim	pci_write_config(dev, AMDTEMP_THERMTP_STAT, cfg | sel, 1);
469197102Sjkim
470197102Sjkim	/* CurTmp starts from -49C. */
471197102Sjkim	offset = AMDTEMP_ZERO_C_TO_K - 490;
472197102Sjkim
473197102Sjkim	/* Adjust offset if DiodeOffset is set and valid. */
474197102Sjkim	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4);
475197102Sjkim	diode_offset = (temp >> 8) & 0x3f;
476197205Sjkim	if ((sc->sc_flags & AMDTEMP_FLAG_DO_ZERO) != 0) {
477197205Sjkim		if ((sc->sc_flags & AMDTEMP_FLAG_DO_SIGN) != 0 &&
478197205Sjkim		    ((temp >> 24) & 0x1) != 0)
479197205Sjkim			diode_offset *= -1;
480197205Sjkim		if ((sc->sc_flags & AMDTEMP_FLAG_DO_QUIRK) != 0 &&
481197205Sjkim		    ((temp >> 25) & 0xf) <= 2)
482197205Sjkim			diode_offset += 10;
483197205Sjkim		offset += diode_offset * 10;
484197205Sjkim	} else if (diode_offset != 0)
485197102Sjkim		offset += (diode_offset - 11) * 10;
486197102Sjkim
487197205Sjkim	mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc;
488197205Sjkim	temp = ((temp >> 14) & mask) * 5 / 2 + offset;
489197102Sjkim
490178151Srpaulo	return (temp);
491178151Srpaulo}
492189769Srpaulo
493189769Srpaulostatic int32_t
494189769Srpauloamdtemp_gettemp(device_t dev, amdsensor_t sensor)
495189769Srpaulo{
496189769Srpaulo	uint32_t temp;
497197102Sjkim	int32_t diode_offset, offset;
498189769Srpaulo
499197102Sjkim	/* CurTmp starts from 0C. */
500197102Sjkim	offset = AMDTEMP_ZERO_C_TO_K;
501189769Srpaulo
502197102Sjkim	/* Adjust offset if DiodeOffset is set and valid. */
503197102Sjkim	temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4);
504197102Sjkim	diode_offset = (temp >> 8) & 0x7f;
505197102Sjkim	if (diode_offset > 0 && diode_offset < 0x40)
506197102Sjkim		offset += (diode_offset - 11) * 10;
507197102Sjkim
508197102Sjkim	temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4);
509197205Sjkim	temp = ((temp >> 21) & 0x7ff) * 5 / 4 + offset;
510197102Sjkim
511189769Srpaulo	return (temp);
512189769Srpaulo}
513