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