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$"); 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 79263870Sbrueffer#define DEVICEID_AMD_MISC16 0x1533 80178151Srpaulo 81189769Srpaulostatic struct amdtemp_product { 82189769Srpaulo uint16_t amdtemp_vendorid; 83189769Srpaulo uint16_t amdtemp_deviceid; 84189769Srpaulo} amdtemp_products[] = { 85189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 86189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 87189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 88263870Sbrueffer { VENDORID_AMD, DEVICEID_AMD_MISC16 }, 89178151Srpaulo { 0, 0 } 90178151Srpaulo}; 91178151Srpaulo 92178151Srpaulo/* 93197102Sjkim * Reported Temperature Control Register (Family 10h/11h only) 94178151Srpaulo */ 95197102Sjkim#define AMDTEMP_REPTMP_CTRL 0xa4 96178151Srpaulo 97189769Srpaulo/* 98197102Sjkim * Thermaltrip Status Register 99189769Srpaulo */ 100197102Sjkim#define AMDTEMP_THERMTP_STAT 0xe4 101197102Sjkim#define AMDTEMP_TTSR_SELCORE 0x04 /* Family 0Fh only */ 102197102Sjkim#define AMDTEMP_TTSR_SELSENSOR 0x40 /* Family 0Fh only */ 103178151Srpaulo 104197102Sjkim/* 105197102Sjkim * CPU Family/Model Register 106197102Sjkim */ 107197102Sjkim#define AMDTEMP_CPUID 0xfc 108178151Srpaulo 109178151Srpaulo/* 110178151Srpaulo * Device methods. 111178151Srpaulo */ 112189769Srpaulostatic void amdtemp_identify(driver_t *driver, device_t parent); 113189769Srpaulostatic int amdtemp_probe(device_t dev); 114189769Srpaulostatic int amdtemp_attach(device_t dev); 115189769Srpaulostatic void amdtemp_intrhook(void *arg); 116189769Srpaulostatic int amdtemp_detach(device_t dev); 117189769Srpaulostatic int amdtemp_match(device_t dev); 118189769Srpaulostatic int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 119189769Srpaulostatic int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 120189769Srpaulostatic int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 121178151Srpaulo 122189769Srpaulostatic device_method_t amdtemp_methods[] = { 123178151Srpaulo /* Device interface */ 124189769Srpaulo DEVMETHOD(device_identify, amdtemp_identify), 125189769Srpaulo DEVMETHOD(device_probe, amdtemp_probe), 126189769Srpaulo DEVMETHOD(device_attach, amdtemp_attach), 127189769Srpaulo DEVMETHOD(device_detach, amdtemp_detach), 128178151Srpaulo 129178151Srpaulo {0, 0} 130178151Srpaulo}; 131178151Srpaulo 132189769Srpaulostatic driver_t amdtemp_driver = { 133189769Srpaulo "amdtemp", 134189769Srpaulo amdtemp_methods, 135189769Srpaulo sizeof(struct amdtemp_softc), 136178151Srpaulo}; 137178151Srpaulo 138189769Srpaulostatic devclass_t amdtemp_devclass; 139189769SrpauloDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 140178151Srpaulo 141178151Srpaulostatic int 142189769Srpauloamdtemp_match(device_t dev) 143178151Srpaulo{ 144178151Srpaulo int i; 145178151Srpaulo uint16_t vendor, devid; 146197102Sjkim 147197102Sjkim vendor = pci_get_vendor(dev); 148178151Srpaulo devid = pci_get_device(dev); 149178151Srpaulo 150189769Srpaulo for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 151189769Srpaulo if (vendor == amdtemp_products[i].amdtemp_vendorid && 152189769Srpaulo devid == amdtemp_products[i].amdtemp_deviceid) 153178151Srpaulo return (1); 154178151Srpaulo } 155178151Srpaulo 156178151Srpaulo return (0); 157178151Srpaulo} 158178151Srpaulo 159178151Srpaulostatic void 160189769Srpauloamdtemp_identify(driver_t *driver, device_t parent) 161178151Srpaulo{ 162178151Srpaulo device_t child; 163178151Srpaulo 164178151Srpaulo /* Make sure we're not being doubly invoked. */ 165189769Srpaulo if (device_find_child(parent, "amdtemp", -1) != NULL) 166178151Srpaulo return; 167197102Sjkim 168189769Srpaulo if (amdtemp_match(parent)) { 169189769Srpaulo child = device_add_child(parent, "amdtemp", -1); 170178151Srpaulo if (child == NULL) 171189769Srpaulo device_printf(parent, "add amdtemp child failed\n"); 172178151Srpaulo } 173178151Srpaulo} 174178151Srpaulo 175178151Srpaulostatic int 176189769Srpauloamdtemp_probe(device_t dev) 177178151Srpaulo{ 178197205Sjkim uint32_t family, model; 179197102Sjkim 180189769Srpaulo if (resource_disabled("amdtemp", 0)) 181178151Srpaulo return (ENXIO); 182178151Srpaulo 183197205Sjkim family = CPUID_TO_FAMILY(cpu_id); 184197205Sjkim model = CPUID_TO_MODEL(cpu_id); 185197102Sjkim 186197102Sjkim switch (family) { 187197102Sjkim case 0x0f: 188197205Sjkim if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 189197205Sjkim (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 190197102Sjkim return (ENXIO); 191197102Sjkim break; 192197102Sjkim case 0x10: 193197102Sjkim case 0x11: 194263870Sbrueffer case 0x16: 195197102Sjkim break; 196197102Sjkim default: 197178151Srpaulo return (ENXIO); 198178151Srpaulo } 199197102Sjkim device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 200197102Sjkim 201178151Srpaulo return (BUS_PROBE_GENERIC); 202178151Srpaulo} 203178151Srpaulo 204178151Srpaulostatic int 205189769Srpauloamdtemp_attach(device_t dev) 206178151Srpaulo{ 207189769Srpaulo struct amdtemp_softc *sc = device_get_softc(dev); 208178151Srpaulo struct sysctl_ctx_list *sysctlctx; 209178151Srpaulo struct sysctl_oid *sysctlnode; 210197205Sjkim uint32_t regs[4]; 211197102Sjkim uint32_t cpuid, family, model; 212178151Srpaulo 213197205Sjkim /* 214197205Sjkim * Errata #154: Incorect Diode Offset 215197205Sjkim */ 216197205Sjkim if (cpu_id == 0x20f32) { 217197205Sjkim do_cpuid(0x80000001, regs); 218197205Sjkim if ((regs[1] & 0xfff) == 0x2c) 219197205Sjkim sc->sc_flags |= AMDTEMP_FLAG_DO_QUIRK; 220197205Sjkim } 221180312Srpaulo 222197205Sjkim /* 223197205Sjkim * CPUID Register is available from Revision F. 224197205Sjkim */ 225197205Sjkim family = CPUID_TO_FAMILY(cpu_id); 226197205Sjkim model = CPUID_TO_MODEL(cpu_id); 227197205Sjkim if (family != 0x0f || model >= 0x40) { 228197205Sjkim cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 229197205Sjkim family = CPUID_TO_FAMILY(cpuid); 230197205Sjkim model = CPUID_TO_MODEL(cpuid); 231197205Sjkim } 232197205Sjkim 233197102Sjkim switch (family) { 234197102Sjkim case 0x0f: 235197102Sjkim /* 236197205Sjkim * Thermaltrip Status Register 237197102Sjkim * 238197205Sjkim * - DiodeOffsetSignBit 239197205Sjkim * 240197205Sjkim * Revision D & E: bit 24 241197205Sjkim * Other: N/A 242197205Sjkim * 243197205Sjkim * - ThermSenseCoreSel 244197205Sjkim * 245197205Sjkim * Revision F & G: 0 - Core1, 1 - Core0 246197205Sjkim * Other: 0 - Core0, 1 - Core1 247197205Sjkim * 248197205Sjkim * - CurTmp 249197205Sjkim * 250197102Sjkim * Revision G: bits 23-14 251197205Sjkim * Other: bits 23-16 252197102Sjkim * 253197205Sjkim * XXX According to the BKDG, CurTmp, ThermSenseSel and 254197205Sjkim * ThermSenseCoreSel bits were introduced in Revision F 255197205Sjkim * but CurTmp seems working fine as early as Revision C. 256197205Sjkim * However, it is not clear whether ThermSenseSel and/or 257197205Sjkim * ThermSenseCoreSel work in undocumented cases as well. 258197205Sjkim * In fact, the Linux driver suggests it may not work but 259197205Sjkim * we just assume it does until we find otherwise. 260197102Sjkim */ 261197205Sjkim if (model < 0x40) { 262197205Sjkim sc->sc_flags |= AMDTEMP_FLAG_DO_ZERO; 263197205Sjkim if (model >= 0x10) 264197205Sjkim sc->sc_flags |= AMDTEMP_FLAG_DO_SIGN; 265197205Sjkim } else { 266197205Sjkim sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; 267197205Sjkim if (model >= 0x60 && model != 0xc1) 268197205Sjkim sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; 269197205Sjkim } 270197102Sjkim 271197102Sjkim /* 272197102Sjkim * There are two sensors per core. 273197102Sjkim */ 274197102Sjkim sc->sc_ntemps = 2; 275197102Sjkim 276189769Srpaulo sc->sc_gettemp = amdtemp_gettemp0f; 277197102Sjkim break; 278197102Sjkim case 0x10: 279197102Sjkim case 0x11: 280263870Sbrueffer case 0x16: 281197102Sjkim /* 282197102Sjkim * There is only one sensor per package. 283197102Sjkim */ 284197102Sjkim sc->sc_ntemps = 1; 285197102Sjkim 286189769Srpaulo sc->sc_gettemp = amdtemp_gettemp; 287197102Sjkim break; 288189769Srpaulo } 289189769Srpaulo 290197102Sjkim /* Find number of cores per package. */ 291197102Sjkim sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 292197102Sjkim (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 293197102Sjkim if (sc->sc_ncores > MAXCPU) 294197102Sjkim return (ENXIO); 295197102Sjkim 296197102Sjkim if (bootverbose) 297197102Sjkim device_printf(dev, "Found %d cores and %d sensors.\n", 298197102Sjkim sc->sc_ncores, 299197102Sjkim sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 300197102Sjkim 301178151Srpaulo /* 302189769Srpaulo * dev.amdtemp.N tree. 303178151Srpaulo */ 304178151Srpaulo sysctlctx = device_get_sysctl_ctx(dev); 305178151Srpaulo sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 306197102Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 307197102Sjkim "sensor0", CTLFLAG_RD, 0, "Sensor 0"); 308197102Sjkim 309178151Srpaulo SYSCTL_ADD_PROC(sysctlctx, 310178151Srpaulo SYSCTL_CHILDREN(sysctlnode), 311178151Srpaulo OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 312189769Srpaulo dev, SENSOR0_CORE0, amdtemp_sysctl, "IK", 313178151Srpaulo "Sensor 0 / Core 0 temperature"); 314178151Srpaulo 315197102Sjkim if (sc->sc_ntemps > 1) { 316197102Sjkim if (sc->sc_ncores > 1) 317197102Sjkim SYSCTL_ADD_PROC(sysctlctx, 318197102Sjkim SYSCTL_CHILDREN(sysctlnode), 319197102Sjkim OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 320197102Sjkim dev, SENSOR0_CORE1, amdtemp_sysctl, "IK", 321197102Sjkim "Sensor 0 / Core 1 temperature"); 322197102Sjkim 323197102Sjkim sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 324197102Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 325197102Sjkim "sensor1", CTLFLAG_RD, 0, "Sensor 1"); 326197102Sjkim 327197102Sjkim SYSCTL_ADD_PROC(sysctlctx, 328197102Sjkim SYSCTL_CHILDREN(sysctlnode), 329197102Sjkim OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 330197102Sjkim dev, SENSOR1_CORE0, amdtemp_sysctl, "IK", 331197102Sjkim "Sensor 1 / Core 0 temperature"); 332197102Sjkim 333197102Sjkim if (sc->sc_ncores > 1) 334197102Sjkim SYSCTL_ADD_PROC(sysctlctx, 335197102Sjkim SYSCTL_CHILDREN(sysctlnode), 336197102Sjkim OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 337197102Sjkim dev, SENSOR1_CORE1, amdtemp_sysctl, "IK", 338197102Sjkim "Sensor 1 / Core 1 temperature"); 339197102Sjkim } 340197102Sjkim 341197102Sjkim /* 342197102Sjkim * Try to create dev.cpu sysctl entries and setup intrhook function. 343197102Sjkim * This is needed because the cpu driver may be loaded late on boot, 344197102Sjkim * after us. 345197102Sjkim */ 346197102Sjkim amdtemp_intrhook(dev); 347197102Sjkim sc->sc_ich.ich_func = amdtemp_intrhook; 348197102Sjkim sc->sc_ich.ich_arg = dev; 349197102Sjkim if (config_intrhook_establish(&sc->sc_ich) != 0) { 350197102Sjkim device_printf(dev, "config_intrhook_establish failed!\n"); 351197102Sjkim return (ENXIO); 352197102Sjkim } 353197102Sjkim 354178151Srpaulo return (0); 355178151Srpaulo} 356178151Srpaulo 357180312Srpaulovoid 358189769Srpauloamdtemp_intrhook(void *arg) 359180312Srpaulo{ 360189769Srpaulo struct amdtemp_softc *sc; 361180312Srpaulo struct sysctl_ctx_list *sysctlctx; 362197102Sjkim device_t dev = (device_t)arg; 363197102Sjkim device_t acpi, cpu, nexus; 364197102Sjkim amdsensor_t sensor; 365197102Sjkim int i; 366180312Srpaulo 367180312Srpaulo sc = device_get_softc(dev); 368197102Sjkim 369180312Srpaulo /* 370180312Srpaulo * dev.cpu.N.temperature. 371180312Srpaulo */ 372180312Srpaulo nexus = device_find_child(root_bus, "nexus", 0); 373180312Srpaulo acpi = device_find_child(nexus, "acpi", 0); 374180312Srpaulo 375197102Sjkim for (i = 0; i < sc->sc_ncores; i++) { 376197102Sjkim if (sc->sc_sysctl_cpu[i] != NULL) 377197102Sjkim continue; 378180312Srpaulo cpu = device_find_child(acpi, "cpu", 379197102Sjkim device_get_unit(dev) * sc->sc_ncores + i); 380197102Sjkim if (cpu != NULL) { 381180312Srpaulo sysctlctx = device_get_sysctl_ctx(cpu); 382180312Srpaulo 383197102Sjkim sensor = sc->sc_ntemps > 1 ? 384197102Sjkim (i == 0 ? CORE0 : CORE1) : SENSOR0_CORE0; 385180312Srpaulo sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 386180312Srpaulo SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 387180312Srpaulo OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 388197102Sjkim dev, sensor, amdtemp_sysctl, "IK", 389197102Sjkim "Current temparature"); 390180312Srpaulo } 391180312Srpaulo } 392197102Sjkim if (sc->sc_ich.ich_arg != NULL) 393197102Sjkim config_intrhook_disestablish(&sc->sc_ich); 394180312Srpaulo} 395180312Srpaulo 396178151Srpauloint 397189769Srpauloamdtemp_detach(device_t dev) 398178151Srpaulo{ 399197102Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 400178151Srpaulo int i; 401197102Sjkim 402197102Sjkim for (i = 0; i < sc->sc_ncores; i++) 403197102Sjkim if (sc->sc_sysctl_cpu[i] != NULL) 404178151Srpaulo sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 405178151Srpaulo 406189769Srpaulo /* NewBus removes the dev.amdtemp.N tree by itself. */ 407197102Sjkim 408178151Srpaulo return (0); 409178151Srpaulo} 410178151Srpaulo 411178151Srpaulostatic int 412189769Srpauloamdtemp_sysctl(SYSCTL_HANDLER_ARGS) 413178151Srpaulo{ 414197102Sjkim device_t dev = (device_t)arg1; 415189769Srpaulo struct amdtemp_softc *sc = device_get_softc(dev); 416197102Sjkim amdsensor_t sensor = (amdsensor_t)arg2; 417197102Sjkim int32_t auxtemp[2], temp; 418178151Srpaulo int error; 419178151Srpaulo 420197102Sjkim switch (sensor) { 421178151Srpaulo case CORE0: 422189769Srpaulo auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE0); 423189769Srpaulo auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE0); 424178988Srpaulo temp = imax(auxtemp[0], auxtemp[1]); 425178151Srpaulo break; 426178151Srpaulo case CORE1: 427189769Srpaulo auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE1); 428189769Srpaulo auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE1); 429178988Srpaulo temp = imax(auxtemp[0], auxtemp[1]); 430178151Srpaulo break; 431178151Srpaulo default: 432197102Sjkim temp = sc->sc_gettemp(dev, sensor); 433178151Srpaulo break; 434178151Srpaulo } 435178151Srpaulo error = sysctl_handle_int(oidp, &temp, 0, req); 436197102Sjkim 437178151Srpaulo return (error); 438178151Srpaulo} 439178151Srpaulo 440197102Sjkim#define AMDTEMP_ZERO_C_TO_K 2732 441197102Sjkim 442178151Srpaulostatic int32_t 443189769Srpauloamdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 444178151Srpaulo{ 445197102Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 446197205Sjkim uint32_t mask, temp; 447197102Sjkim int32_t diode_offset, offset; 448197102Sjkim uint8_t cfg, sel; 449197102Sjkim 450197102Sjkim /* Set Sensor/Core selector. */ 451197102Sjkim sel = 0; 452178151Srpaulo switch (sensor) { 453197102Sjkim case SENSOR1_CORE0: 454197102Sjkim sel |= AMDTEMP_TTSR_SELSENSOR; 455197103Sjkim /* FALLTHROUGH */ 456178151Srpaulo case SENSOR0_CORE0: 457197102Sjkim case CORE0: 458197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) 459197102Sjkim sel |= AMDTEMP_TTSR_SELCORE; 460178151Srpaulo break; 461197102Sjkim case SENSOR1_CORE1: 462197102Sjkim sel |= AMDTEMP_TTSR_SELSENSOR; 463197103Sjkim /* FALLTHROUGH */ 464178151Srpaulo case SENSOR0_CORE1: 465197102Sjkim case CORE1: 466197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) 467197102Sjkim sel |= AMDTEMP_TTSR_SELCORE; 468178151Srpaulo break; 469178151Srpaulo } 470197102Sjkim cfg = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 471197102Sjkim cfg &= ~(AMDTEMP_TTSR_SELSENSOR | AMDTEMP_TTSR_SELCORE); 472197102Sjkim pci_write_config(dev, AMDTEMP_THERMTP_STAT, cfg | sel, 1); 473197102Sjkim 474197102Sjkim /* CurTmp starts from -49C. */ 475197102Sjkim offset = AMDTEMP_ZERO_C_TO_K - 490; 476197102Sjkim 477197102Sjkim /* Adjust offset if DiodeOffset is set and valid. */ 478197102Sjkim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 479197102Sjkim diode_offset = (temp >> 8) & 0x3f; 480197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_DO_ZERO) != 0) { 481197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_DO_SIGN) != 0 && 482197205Sjkim ((temp >> 24) & 0x1) != 0) 483197205Sjkim diode_offset *= -1; 484197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_DO_QUIRK) != 0 && 485197205Sjkim ((temp >> 25) & 0xf) <= 2) 486197205Sjkim diode_offset += 10; 487197205Sjkim offset += diode_offset * 10; 488197205Sjkim } else if (diode_offset != 0) 489197102Sjkim offset += (diode_offset - 11) * 10; 490197102Sjkim 491197205Sjkim mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; 492197205Sjkim temp = ((temp >> 14) & mask) * 5 / 2 + offset; 493197102Sjkim 494178151Srpaulo return (temp); 495178151Srpaulo} 496189769Srpaulo 497189769Srpaulostatic int32_t 498189769Srpauloamdtemp_gettemp(device_t dev, amdsensor_t sensor) 499189769Srpaulo{ 500189769Srpaulo uint32_t temp; 501197102Sjkim int32_t diode_offset, offset; 502189769Srpaulo 503197102Sjkim /* CurTmp starts from 0C. */ 504197102Sjkim offset = AMDTEMP_ZERO_C_TO_K; 505189769Srpaulo 506197102Sjkim /* Adjust offset if DiodeOffset is set and valid. */ 507197102Sjkim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 508197102Sjkim diode_offset = (temp >> 8) & 0x7f; 509197102Sjkim if (diode_offset > 0 && diode_offset < 0x40) 510197102Sjkim offset += (diode_offset - 11) * 10; 511197102Sjkim 512197102Sjkim temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 513197205Sjkim temp = ((temp >> 21) & 0x7ff) * 5 / 4 + offset; 514197102Sjkim 515189769Srpaulo return (temp); 516189769Srpaulo} 517