amdtemp.c revision 197205
1169689Skan/*- 2169689Skan * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> 3169689Skan * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> 4169689Skan * Copyright (c) 2009 Jung-uk Kim <jkim@FreeBSD.org> 5169689Skan * All rights reserved. 6169689Skan * 7169689Skan * Redistribution and use in source and binary forms, with or without 8169689Skan * modification, are permitted provided that the following conditions 9169689Skan * are met: 10169689Skan * 1. Redistributions of source code must retain the above copyright 11169689Skan * notice, this list of conditions and the following disclaimer. 12169689Skan * 2. Redistributions in binary form must reproduce the above copyright 13169689Skan * notice, this list of conditions and the following disclaimer in the 14169689Skan * documentation and/or other materials provided with the distribution. 15169689Skan * 16169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17169689Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18169689Skan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19169689Skan * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20169689Skan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21169689Skan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22169689Skan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24169689Skan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25169689Skan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26169689Skan * POSSIBILITY OF SUCH DAMAGE. 27169689Skan */ 28169689Skan 29169689Skan/* 30169689Skan * Driver for the AMD CPU on-die thermal sensors for Family 0Fh/10h/11h procs. 31169689Skan * Initially based on the k8temp Linux driver. 32169689Skan */ 33169689Skan 34169689Skan#include <sys/cdefs.h> 35169689Skan__FBSDID("$FreeBSD: head/sys/dev/amdtemp/amdtemp.c 197205 2009-09-14 23:08:19Z jkim $"); 36169689Skan 37169689Skan#include <sys/param.h> 38169689Skan#include <sys/bus.h> 39169689Skan#include <sys/conf.h> 40169689Skan#include <sys/kernel.h> 41169689Skan#include <sys/module.h> 42169689Skan#include <sys/sysctl.h> 43169689Skan#include <sys/systm.h> 44169689Skan 45169689Skan#include <machine/cpufunc.h> 46169689Skan#include <machine/md_var.h> 47169689Skan#include <machine/specialreg.h> 48169689Skan 49169689Skan#include <dev/pci/pcivar.h> 50169689Skan 51169689Skantypedef enum { 52169689Skan SENSOR0_CORE0, 53169689Skan SENSOR0_CORE1, 54169689Skan SENSOR1_CORE0, 55169689Skan SENSOR1_CORE1, 56169689Skan CORE0, 57169689Skan CORE1 58169689Skan} amdsensor_t; 59169689Skan 60169689Skanstruct amdtemp_softc { 61169689Skan device_t sc_dev; 62169689Skan int sc_ncores; 63169689Skan int sc_ntemps; 64169689Skan int sc_flags; 65169689Skan#define AMDTEMP_FLAG_DO_QUIRK 0x01 /* DiodeOffset may be incorrect. */ 66169689Skan#define AMDTEMP_FLAG_DO_ZERO 0x02 /* DiodeOffset starts from 0C. */ 67169689Skan#define AMDTEMP_FLAG_DO_SIGN 0x04 /* DiodeOffsetSignBit is present. */ 68169689Skan#define AMDTEMP_FLAG_CS_SWAP 0x08 /* ThermSenseCoreSel is inverted. */ 69169689Skan#define AMDTEMP_FLAG_CT_10BIT 0x10 /* CurTmp is 10-bit wide. */ 70169689Skan int32_t (*sc_gettemp)(device_t, amdsensor_t); 71169689Skan struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; 72169689Skan struct intr_config_hook sc_ich; 73169689Skan}; 74169689Skan 75169689Skan#define VENDORID_AMD 0x1022 76169689Skan#define DEVICEID_AMD_MISC0F 0x1103 77169689Skan#define DEVICEID_AMD_MISC10 0x1203 78169689Skan#define DEVICEID_AMD_MISC11 0x1303 79169689Skan 80169689Skanstatic struct amdtemp_product { 81169689Skan uint16_t amdtemp_vendorid; 82169689Skan uint16_t amdtemp_deviceid; 83169689Skan} amdtemp_products[] = { 84169689Skan { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 85169689Skan { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 86169689Skan { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 87169689Skan { 0, 0 } 88169689Skan}; 89169689Skan 90169689Skan/* 91169689Skan * Reported Temperature Control Register (Family 10h/11h only) 92169689Skan */ 93169689Skan#define AMDTEMP_REPTMP_CTRL 0xa4 94169689Skan 95169689Skan/* 96169689Skan * Thermaltrip Status Register 97169689Skan */ 98169689Skan#define AMDTEMP_THERMTP_STAT 0xe4 99169689Skan#define AMDTEMP_TTSR_SELCORE 0x04 /* Family 0Fh only */ 100169689Skan#define AMDTEMP_TTSR_SELSENSOR 0x40 /* Family 0Fh only */ 101169689Skan 102169689Skan/* 103169689Skan * CPU Family/Model Register 104169689Skan */ 105169689Skan#define AMDTEMP_CPUID 0xfc 106169689Skan 107169689Skan/* 108169689Skan * Device methods. 109169689Skan */ 110169689Skanstatic void amdtemp_identify(driver_t *driver, device_t parent); 111169689Skanstatic int amdtemp_probe(device_t dev); 112169689Skanstatic int amdtemp_attach(device_t dev); 113169689Skanstatic void amdtemp_intrhook(void *arg); 114169689Skanstatic int amdtemp_detach(device_t dev); 115169689Skanstatic int amdtemp_match(device_t dev); 116169689Skanstatic int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 117169689Skanstatic int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 118169689Skanstatic int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 119169689Skan 120169689Skanstatic device_method_t amdtemp_methods[] = { 121169689Skan /* Device interface */ 122169689Skan DEVMETHOD(device_identify, amdtemp_identify), 123169689Skan DEVMETHOD(device_probe, amdtemp_probe), 124169689Skan DEVMETHOD(device_attach, amdtemp_attach), 125169689Skan DEVMETHOD(device_detach, amdtemp_detach), 126169689Skan 127169689Skan {0, 0} 128169689Skan}; 129169689Skan 130169689Skanstatic driver_t amdtemp_driver = { 131169689Skan "amdtemp", 132169689Skan amdtemp_methods, 133169689Skan sizeof(struct amdtemp_softc), 134169689Skan}; 135169689Skan 136169689Skanstatic devclass_t amdtemp_devclass; 137169689SkanDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 138169689Skan 139169689Skanstatic int 140169689Skanamdtemp_match(device_t dev) 141169689Skan{ 142169689Skan int i; 143169689Skan uint16_t vendor, devid; 144169689Skan 145169689Skan vendor = pci_get_vendor(dev); 146169689Skan devid = pci_get_device(dev); 147169689Skan 148169689Skan for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 149169689Skan if (vendor == amdtemp_products[i].amdtemp_vendorid && 150169689Skan devid == amdtemp_products[i].amdtemp_deviceid) 151169689Skan return (1); 152169689Skan } 153169689Skan 154169689Skan return (0); 155169689Skan} 156169689Skan 157169689Skanstatic void 158169689Skanamdtemp_identify(driver_t *driver, device_t parent) 159169689Skan{ 160169689Skan device_t child; 161169689Skan 162169689Skan /* Make sure we're not being doubly invoked. */ 163169689Skan if (device_find_child(parent, "amdtemp", -1) != NULL) 164169689Skan return; 165169689Skan 166169689Skan if (amdtemp_match(parent)) { 167169689Skan child = device_add_child(parent, "amdtemp", -1); 168169689Skan if (child == NULL) 169169689Skan device_printf(parent, "add amdtemp child failed\n"); 170169689Skan } 171169689Skan} 172169689Skan 173169689Skanstatic int 174169689Skanamdtemp_probe(device_t dev) 175169689Skan{ 176169689Skan uint32_t family, model; 177169689Skan 178169689Skan if (resource_disabled("amdtemp", 0)) 179169689Skan return (ENXIO); 180169689Skan 181169689Skan family = CPUID_TO_FAMILY(cpu_id); 182169689Skan model = CPUID_TO_MODEL(cpu_id); 183169689Skan 184169689Skan switch (family) { 185169689Skan case 0x0f: 186169689Skan if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 187169689Skan (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 188169689Skan return (ENXIO); 189169689Skan break; 190169689Skan case 0x10: 191169689Skan case 0x11: 192169689Skan break; 193169689Skan default: 194169689Skan return (ENXIO); 195169689Skan } 196169689Skan device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 197169689Skan 198169689Skan return (BUS_PROBE_GENERIC); 199169689Skan} 200169689Skan 201169689Skanstatic int 202169689Skanamdtemp_attach(device_t dev) 203169689Skan{ 204169689Skan struct amdtemp_softc *sc = device_get_softc(dev); 205169689Skan struct sysctl_ctx_list *sysctlctx; 206169689Skan struct sysctl_oid *sysctlnode; 207169689Skan uint32_t regs[4]; 208169689Skan uint32_t cpuid, family, model; 209169689Skan 210169689Skan /* 211169689Skan * Errata #154: Incorect Diode Offset 212169689Skan */ 213169689Skan if (cpu_id == 0x20f32) { 214169689Skan do_cpuid(0x80000001, regs); 215169689Skan if ((regs[1] & 0xfff) == 0x2c) 216169689Skan sc->sc_flags |= AMDTEMP_FLAG_DO_QUIRK; 217169689Skan } 218169689Skan 219169689Skan /* 220169689Skan * CPUID Register is available from Revision F. 221169689Skan */ 222169689Skan family = CPUID_TO_FAMILY(cpu_id); 223169689Skan model = CPUID_TO_MODEL(cpu_id); 224169689Skan if (family != 0x0f || model >= 0x40) { 225169689Skan cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 226169689Skan family = CPUID_TO_FAMILY(cpuid); 227169689Skan model = CPUID_TO_MODEL(cpuid); 228169689Skan } 229169689Skan 230169689Skan switch (family) { 231169689Skan case 0x0f: 232169689Skan /* 233169689Skan * Thermaltrip Status Register 234169689Skan * 235169689Skan * - DiodeOffsetSignBit 236169689Skan * 237169689Skan * Revision D & E: bit 24 238169689Skan * Other: N/A 239169689Skan * 240169689Skan * - ThermSenseCoreSel 241169689Skan * 242169689Skan * Revision F & G: 0 - Core1, 1 - Core0 243169689Skan * Other: 0 - Core0, 1 - Core1 244169689Skan * 245169689Skan * - CurTmp 246169689Skan * 247169689Skan * Revision G: bits 23-14 248169689Skan * Other: bits 23-16 249169689Skan * 250169689Skan * XXX According to the BKDG, CurTmp, ThermSenseSel and 251169689Skan * ThermSenseCoreSel bits were introduced in Revision F 252169689Skan * but CurTmp seems working fine as early as Revision C. 253169689Skan * However, it is not clear whether ThermSenseSel and/or 254169689Skan * ThermSenseCoreSel work in undocumented cases as well. 255169689Skan * In fact, the Linux driver suggests it may not work but 256169689Skan * we just assume it does until we find otherwise. 257169689Skan */ 258169689Skan if (model < 0x40) { 259169689Skan sc->sc_flags |= AMDTEMP_FLAG_DO_ZERO; 260169689Skan if (model >= 0x10) 261169689Skan sc->sc_flags |= AMDTEMP_FLAG_DO_SIGN; 262169689Skan } else { 263169689Skan sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; 264169689Skan if (model >= 0x60 && model != 0xc1) 265169689Skan sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; 266169689Skan } 267169689Skan 268169689Skan /* 269169689Skan * There are two sensors per core. 270169689Skan */ 271169689Skan sc->sc_ntemps = 2; 272169689Skan 273169689Skan sc->sc_gettemp = amdtemp_gettemp0f; 274169689Skan break; 275169689Skan case 0x10: 276169689Skan case 0x11: 277169689Skan /* 278169689Skan * There is only one sensor per package. 279169689Skan */ 280169689Skan sc->sc_ntemps = 1; 281169689Skan 282169689Skan sc->sc_gettemp = amdtemp_gettemp; 283169689Skan break; 284169689Skan } 285169689Skan 286169689Skan /* Find number of cores per package. */ 287169689Skan sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 288169689Skan (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 289169689Skan if (sc->sc_ncores > MAXCPU) 290169689Skan return (ENXIO); 291169689Skan 292169689Skan if (bootverbose) 293169689Skan device_printf(dev, "Found %d cores and %d sensors.\n", 294169689Skan sc->sc_ncores, 295169689Skan sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 296169689Skan 297169689Skan /* 298169689Skan * dev.amdtemp.N tree. 299169689Skan */ 300169689Skan sysctlctx = device_get_sysctl_ctx(dev); 301169689Skan sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 302169689Skan SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 303169689Skan "sensor0", CTLFLAG_RD, 0, "Sensor 0"); 304169689Skan 305169689Skan SYSCTL_ADD_PROC(sysctlctx, 306169689Skan SYSCTL_CHILDREN(sysctlnode), 307169689Skan OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 308169689Skan dev, SENSOR0_CORE0, amdtemp_sysctl, "IK", 309169689Skan "Sensor 0 / Core 0 temperature"); 310169689Skan 311169689Skan if (sc->sc_ntemps > 1) { 312169689Skan if (sc->sc_ncores > 1) 313169689Skan SYSCTL_ADD_PROC(sysctlctx, 314169689Skan SYSCTL_CHILDREN(sysctlnode), 315169689Skan OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 316169689Skan dev, SENSOR0_CORE1, amdtemp_sysctl, "IK", 317169689Skan "Sensor 0 / Core 1 temperature"); 318169689Skan 319169689Skan sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 320169689Skan SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 321169689Skan "sensor1", CTLFLAG_RD, 0, "Sensor 1"); 322169689Skan 323169689Skan SYSCTL_ADD_PROC(sysctlctx, 324169689Skan SYSCTL_CHILDREN(sysctlnode), 325169689Skan OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 326169689Skan dev, SENSOR1_CORE0, amdtemp_sysctl, "IK", 327169689Skan "Sensor 1 / Core 0 temperature"); 328169689Skan 329169689Skan if (sc->sc_ncores > 1) 330169689Skan SYSCTL_ADD_PROC(sysctlctx, 331169689Skan SYSCTL_CHILDREN(sysctlnode), 332169689Skan OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 333169689Skan dev, SENSOR1_CORE1, amdtemp_sysctl, "IK", 334169689Skan "Sensor 1 / Core 1 temperature"); 335169689Skan } 336169689Skan 337169689Skan /* 338169689Skan * Try to create dev.cpu sysctl entries and setup intrhook function. 339169689Skan * This is needed because the cpu driver may be loaded late on boot, 340169689Skan * after us. 341169689Skan */ 342169689Skan amdtemp_intrhook(dev); 343169689Skan sc->sc_ich.ich_func = amdtemp_intrhook; 344169689Skan sc->sc_ich.ich_arg = dev; 345169689Skan if (config_intrhook_establish(&sc->sc_ich) != 0) { 346169689Skan device_printf(dev, "config_intrhook_establish failed!\n"); 347169689Skan return (ENXIO); 348169689Skan } 349169689Skan 350169689Skan return (0); 351169689Skan} 352169689Skan 353169689Skanvoid 354169689Skanamdtemp_intrhook(void *arg) 355169689Skan{ 356169689Skan struct amdtemp_softc *sc; 357169689Skan struct sysctl_ctx_list *sysctlctx; 358169689Skan device_t dev = (device_t)arg; 359169689Skan device_t acpi, cpu, nexus; 360169689Skan amdsensor_t sensor; 361169689Skan int i; 362169689Skan 363169689Skan sc = device_get_softc(dev); 364169689Skan 365169689Skan /* 366169689Skan * dev.cpu.N.temperature. 367169689Skan */ 368169689Skan nexus = device_find_child(root_bus, "nexus", 0); 369169689Skan acpi = device_find_child(nexus, "acpi", 0); 370169689Skan 371169689Skan for (i = 0; i < sc->sc_ncores; i++) { 372169689Skan if (sc->sc_sysctl_cpu[i] != NULL) 373169689Skan continue; 374169689Skan cpu = device_find_child(acpi, "cpu", 375169689Skan device_get_unit(dev) * sc->sc_ncores + i); 376169689Skan if (cpu != NULL) { 377169689Skan sysctlctx = device_get_sysctl_ctx(cpu); 378169689Skan 379169689Skan sensor = sc->sc_ntemps > 1 ? 380169689Skan (i == 0 ? CORE0 : CORE1) : SENSOR0_CORE0; 381169689Skan sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 382169689Skan SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 383169689Skan OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 384169689Skan dev, sensor, amdtemp_sysctl, "IK", 385169689Skan "Current temparature"); 386169689Skan } 387169689Skan } 388169689Skan if (sc->sc_ich.ich_arg != NULL) 389169689Skan config_intrhook_disestablish(&sc->sc_ich); 390169689Skan} 391169689Skan 392169689Skanint 393169689Skanamdtemp_detach(device_t dev) 394169689Skan{ 395169689Skan struct amdtemp_softc *sc = device_get_softc(dev); 396169689Skan int i; 397169689Skan 398169689Skan for (i = 0; i < sc->sc_ncores; i++) 399169689Skan if (sc->sc_sysctl_cpu[i] != NULL) 400169689Skan sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 401169689Skan 402169689Skan /* NewBus removes the dev.amdtemp.N tree by itself. */ 403169689Skan 404169689Skan return (0); 405169689Skan} 406169689Skan 407169689Skanstatic int 408169689Skanamdtemp_sysctl(SYSCTL_HANDLER_ARGS) 409169689Skan{ 410169689Skan device_t dev = (device_t)arg1; 411169689Skan struct amdtemp_softc *sc = device_get_softc(dev); 412169689Skan amdsensor_t sensor = (amdsensor_t)arg2; 413169689Skan int32_t auxtemp[2], temp; 414169689Skan int error; 415169689Skan 416169689Skan switch (sensor) { 417169689Skan case CORE0: 418169689Skan auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE0); 419169689Skan auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE0); 420169689Skan temp = imax(auxtemp[0], auxtemp[1]); 421169689Skan break; 422169689Skan case CORE1: 423169689Skan auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE1); 424169689Skan auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE1); 425169689Skan temp = imax(auxtemp[0], auxtemp[1]); 426169689Skan break; 427169689Skan default: 428169689Skan temp = sc->sc_gettemp(dev, sensor); 429169689Skan break; 430169689Skan } 431169689Skan error = sysctl_handle_int(oidp, &temp, 0, req); 432169689Skan 433169689Skan return (error); 434169689Skan} 435169689Skan 436169689Skan#define AMDTEMP_ZERO_C_TO_K 2732 437169689Skan 438169689Skanstatic int32_t 439169689Skanamdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 440169689Skan{ 441169689Skan struct amdtemp_softc *sc = device_get_softc(dev); 442169689Skan uint32_t mask, temp; 443169689Skan int32_t diode_offset, offset; 444169689Skan uint8_t cfg, sel; 445169689Skan 446169689Skan /* Set Sensor/Core selector. */ 447169689Skan sel = 0; 448169689Skan switch (sensor) { 449169689Skan case SENSOR1_CORE0: 450169689Skan sel |= AMDTEMP_TTSR_SELSENSOR; 451169689Skan /* FALLTHROUGH */ 452169689Skan case SENSOR0_CORE0: 453169689Skan case CORE0: 454169689Skan if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) 455169689Skan sel |= AMDTEMP_TTSR_SELCORE; 456169689Skan break; 457169689Skan case SENSOR1_CORE1: 458169689Skan sel |= AMDTEMP_TTSR_SELSENSOR; 459169689Skan /* FALLTHROUGH */ 460169689Skan case SENSOR0_CORE1: 461169689Skan case CORE1: 462169689Skan if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) 463169689Skan sel |= AMDTEMP_TTSR_SELCORE; 464169689Skan break; 465169689Skan } 466169689Skan cfg = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 467169689Skan cfg &= ~(AMDTEMP_TTSR_SELSENSOR | AMDTEMP_TTSR_SELCORE); 468169689Skan pci_write_config(dev, AMDTEMP_THERMTP_STAT, cfg | sel, 1); 469169689Skan 470169689Skan /* CurTmp starts from -49C. */ 471169689Skan offset = AMDTEMP_ZERO_C_TO_K - 490; 472169689Skan 473169689Skan /* Adjust offset if DiodeOffset is set and valid. */ 474169689Skan temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 475169689Skan diode_offset = (temp >> 8) & 0x3f; 476169689Skan if ((sc->sc_flags & AMDTEMP_FLAG_DO_ZERO) != 0) { 477169689Skan if ((sc->sc_flags & AMDTEMP_FLAG_DO_SIGN) != 0 && 478169689Skan ((temp >> 24) & 0x1) != 0) 479169689Skan diode_offset *= -1; 480169689Skan if ((sc->sc_flags & AMDTEMP_FLAG_DO_QUIRK) != 0 && 481169689Skan ((temp >> 25) & 0xf) <= 2) 482169689Skan diode_offset += 10; 483169689Skan offset += diode_offset * 10; 484169689Skan } else if (diode_offset != 0) 485169689Skan offset += (diode_offset - 11) * 10; 486169689Skan 487169689Skan mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; 488169689Skan temp = ((temp >> 14) & mask) * 5 / 2 + offset; 489169689Skan 490169689Skan return (temp); 491169689Skan} 492169689Skan 493169689Skanstatic int32_t 494169689Skanamdtemp_gettemp(device_t dev, amdsensor_t sensor) 495169689Skan{ 496169689Skan uint32_t temp; 497169689Skan int32_t diode_offset, offset; 498169689Skan 499169689Skan /* CurTmp starts from 0C. */ 500169689Skan offset = AMDTEMP_ZERO_C_TO_K; 501169689Skan 502169689Skan /* Adjust offset if DiodeOffset is set and valid. */ 503169689Skan temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 504169689Skan diode_offset = (temp >> 8) & 0x7f; 505169689Skan if (diode_offset > 0 && diode_offset < 0x40) 506169689Skan offset += (diode_offset - 11) * 10; 507169689Skan 508169689Skan temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 509169689Skan temp = ((temp >> 21) & 0x7ff) * 5 / 4 + offset; 510169689Skan 511169689Skan return (temp); 512169689Skan} 513169689Skan