1 /*- 2 * Copyright (c) 2009 Andriy Gapon <avg@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * This is a driver for watchdog timer present in AMD SB600/SB7xx/SB8xx 29 * southbridges. 30 * Please see the following specifications for the descriptions of the 31 * registers and flags: 32 * - AMD SB600 Register Reference Guide, Public Version, Rev. 3.03 (SB600 RRG) 33 * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/46155_sb600_rrg_pub_3.03.pdf 34 * - AMD SB700/710/750 Register Reference Guide (RRG) 35 * http://developer.amd.com/assets/43009_sb7xx_rrg_pub_1.00.pdf 36 * - AMD SB700/710/750 Register Programming Requirements (RPR) 37 * http://developer.amd.com/assets/42413_sb7xx_rpr_pub_1.00.pdf 38 * - AMD SB800-Series Southbridges Register Reference Guide (RRG) 39 * http://support.amd.com/us/Embedded_TechDocs/45482.pdf 40 * Please see the following for Watchdog Resource Table specification: 41 * - Watchdog Timer Hardware Requirements for Windows Server 2003 (WDRT) 42 * http://www.microsoft.com/whdc/system/sysinternals/watchdog.mspx 43 * AMD SB600/SB7xx/SB8xx watchdog hardware seems to conform to the above 44 * specifications, but the table hasn't been spotted in the wild yet. 45 * 46 * $FreeBSD: src/sys/dev/amdsbwd/amdsbwd.c,v 1.3 2011/06/07 06:18:02 avg Exp $ 47 */ 48 49 #include <sys/param.h> 50 #include <sys/kernel.h> 51 #include <sys/module.h> 52 #include <sys/systm.h> 53 #include <sys/sysctl.h> 54 #include <sys/bus.h> 55 #include <sys/rman.h> 56 #include <sys/resource.h> 57 #include <sys/wdog.h> 58 59 #include <bus/isa/isavar.h> 60 #include <bus/pci/pcivar.h> 61 62 #include "amd_chipset.h" 63 64 /* 65 * Registers in the Watchdog IO space. 66 * See SB7xx RRG 2.3.4, WDRT. 67 */ 68 #define AMDSB_WD_CTRL 0x00 69 #define AMDSB_WD_RUN 0x01 70 #define AMDSB_WD_FIRED 0x02 71 #define AMDSB_WD_SHUTDOWN 0x04 72 #define AMDSB_WD_DISABLE 0x08 73 #define AMDSB_WD_RESERVED 0x70 74 #define AMDSB_WD_RELOAD 0x80 75 #define AMDSB_WD_COUNT 0x04 76 #define AMDSB_WD_COUNT_MASK 0xffff 77 #define AMDSB_WDIO_REG_WIDTH 4 78 79 #define amdsbwd_verbose_printf(dev, ...) \ 80 do { \ 81 if (bootverbose) \ 82 device_printf(dev, __VA_ARGS__);\ 83 } while (0) 84 85 struct amdsbwd_softc { 86 device_t dev; 87 struct watchdog wdog; 88 struct resource *res_ctrl; 89 struct resource *res_count; 90 int rid_ctrl; 91 int rid_count; 92 int ms_per_tick; 93 int max_ticks; 94 int active; 95 unsigned int timeout; 96 }; 97 98 static void amdsbwd_identify(driver_t *driver, device_t parent); 99 static int amdsbwd_probe(device_t dev); 100 static int amdsbwd_attach(device_t dev); 101 static int amdsbwd_detach(device_t dev); 102 static int amdsbwd_suspend(device_t dev); 103 static int amdsbwd_resume(device_t dev); 104 105 static device_method_t amdsbwd_methods[] = { 106 DEVMETHOD(device_identify, amdsbwd_identify), 107 DEVMETHOD(device_probe, amdsbwd_probe), 108 DEVMETHOD(device_attach, amdsbwd_attach), 109 DEVMETHOD(device_detach, amdsbwd_detach), 110 DEVMETHOD(device_suspend, amdsbwd_suspend), 111 DEVMETHOD(device_resume, amdsbwd_resume), 112 #if 0 113 DEVMETHOD(device_shutdown, amdsbwd_detach), 114 #endif 115 DEVMETHOD_END 116 }; 117 118 static devclass_t amdsbwd_devclass; 119 static driver_t amdsbwd_driver = { 120 "amdsbwd", 121 amdsbwd_methods, 122 sizeof(struct amdsbwd_softc) 123 }; 124 125 DRIVER_MODULE(amdsbwd, isa, amdsbwd_driver, amdsbwd_devclass, NULL, NULL); 126 MODULE_VERSION(amdsbwd, 1); 127 128 129 static uint8_t 130 pmio_read(struct resource *res, uint8_t reg) 131 { 132 bus_write_1(res, 0, reg); /* Index */ 133 return (bus_read_1(res, 1)); /* Data */ 134 } 135 136 static void 137 pmio_write(struct resource *res, uint8_t reg, uint8_t val) 138 { 139 bus_write_1(res, 0, reg); /* Index */ 140 bus_write_1(res, 1, val); /* Data */ 141 } 142 143 static uint32_t 144 wdctrl_read(struct amdsbwd_softc *sc) 145 { 146 return (bus_read_4(sc->res_ctrl, 0)); 147 } 148 149 static void 150 wdctrl_write(struct amdsbwd_softc *sc, uint32_t val) 151 { 152 bus_write_4(sc->res_ctrl, 0, val); 153 } 154 155 static __unused uint32_t 156 wdcount_read(struct amdsbwd_softc *sc) 157 { 158 return (bus_read_4(sc->res_count, 0)); 159 } 160 161 static void 162 wdcount_write(struct amdsbwd_softc *sc, uint32_t val) 163 { 164 bus_write_4(sc->res_count, 0, val); 165 } 166 167 static void 168 amdsbwd_tmr_enable(struct amdsbwd_softc *sc) 169 { 170 uint32_t val; 171 172 val = wdctrl_read(sc); 173 val |= AMDSB_WD_RUN; 174 wdctrl_write(sc, val); 175 sc->active = 1; 176 amdsbwd_verbose_printf(sc->dev, "timer enabled\n"); 177 } 178 179 static void 180 amdsbwd_tmr_disable(struct amdsbwd_softc *sc) 181 { 182 uint32_t val; 183 184 val = wdctrl_read(sc); 185 val &= ~AMDSB_WD_RUN; 186 wdctrl_write(sc, val); 187 sc->active = 0; 188 amdsbwd_verbose_printf(sc->dev, "timer disabled\n"); 189 } 190 191 static void 192 amdsbwd_tmr_reload(struct amdsbwd_softc *sc) 193 { 194 uint32_t val; 195 196 val = wdctrl_read(sc); 197 val |= AMDSB_WD_RELOAD; 198 wdctrl_write(sc, val); 199 } 200 201 static void 202 amdsbwd_tmr_set(struct amdsbwd_softc *sc, uint16_t timeout) 203 { 204 205 timeout &= AMDSB_WD_COUNT_MASK; 206 wdcount_write(sc, timeout); 207 sc->timeout = timeout; 208 amdsbwd_verbose_printf(sc->dev, "timeout set to %u ticks\n", timeout); 209 } 210 211 static int 212 amdsb_watchdog(void *arg, int period) 213 { 214 unsigned int timeout; 215 struct amdsbwd_softc *sc = arg; 216 217 timeout = (period * 1000) / sc->ms_per_tick; 218 if (timeout > sc->max_ticks) 219 timeout = sc->max_ticks; 220 if (timeout != sc->timeout) { 221 amdsbwd_tmr_set(sc, timeout); 222 if (!sc->active) 223 amdsbwd_tmr_enable(sc); 224 } 225 amdsbwd_tmr_reload(sc); 226 227 return period; 228 } 229 230 static void 231 amdsbwd_identify(driver_t *driver, device_t parent) 232 { 233 device_t child; 234 device_t smb_dev; 235 236 if (resource_disabled("amdsbwd", 0)) 237 return; 238 if (device_find_child(parent, "amdsbwd", -1) != NULL) 239 return; 240 241 /* 242 * Try to identify SB600/SB7xx by PCI Device ID of SMBus device 243 * that should be present at bus 0, device 20, function 0. 244 */ 245 smb_dev = pci_find_bsf(0, 20, 0); 246 if (smb_dev == NULL) 247 return; 248 if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID && 249 pci_get_devid(smb_dev) != AMDFCH_SMBUS_DEVID && 250 pci_get_devid(smb_dev) != AMDCZ_SMBUS_DEVID) { 251 return; 252 } 253 254 child = BUS_ADD_CHILD(parent, parent, ISA_ORDER_SPECULATIVE, 255 "amdsbwd", -1); 256 if (child == NULL) 257 device_printf(parent, "add amdsbwd child failed\n"); 258 } 259 260 261 static void 262 amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr) 263 { 264 uint8_t val; 265 int i; 266 267 /* Report cause of previous reset for user's convenience. */ 268 val = pmio_read(pmres, AMDSB_PM_RESET_STATUS0); 269 if (val != 0) 270 amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val); 271 val = pmio_read(pmres, AMDSB_PM_RESET_STATUS1); 272 if (val != 0) 273 amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val); 274 if ((val & AMDSB_WD_RST_STS) != 0) 275 device_printf(dev, "Previous Reset was caused by Watchdog\n"); 276 277 /* Find base address of memory mapped WDT registers. */ 278 for (*addr = 0, i = 0; i < 4; i++) { 279 *addr <<= 8; 280 *addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i); 281 } 282 *addr &= ~0x07U; 283 284 /* Set watchdog timer tick to 1s. */ 285 val = pmio_read(pmres, AMDSB_PM_WDT_CTRL); 286 val &= ~AMDSB_WDT_RES_MASK; 287 val |= AMDSB_WDT_RES_1S; 288 pmio_write(pmres, AMDSB_PM_WDT_CTRL, val); 289 290 /* Enable watchdog device (in stopped state). */ 291 val = pmio_read(pmres, AMDSB_PM_WDT_CTRL); 292 val &= ~AMDSB_WDT_DISABLE; 293 pmio_write(pmres, AMDSB_PM_WDT_CTRL, val); 294 295 /* 296 * XXX TODO: Ensure that watchdog decode is enabled 297 * (register 0x41, bit 3). 298 */ 299 device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer"); 300 } 301 302 static void 303 amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr) 304 { 305 uint32_t val; 306 int i; 307 308 /* Report cause of previous reset for user's convenience. */ 309 310 val = pmio_read(pmres, AMDSB8_PM_RESET_CTRL); 311 if ((val & AMDSB8_RST_STS_DIS) != 0) { 312 val &= ~AMDSB8_RST_STS_DIS; 313 pmio_write(pmres, AMDSB8_PM_RESET_CTRL, val); 314 } 315 val = 0; 316 for (i = 3; i >= 0; i--) { 317 val <<= 8; 318 val |= pmio_read(pmres, AMDSB8_PM_RESET_STATUS + i); 319 } 320 if (val != 0) 321 amdsbwd_verbose_printf(dev, "ResetStatus = 0x%08x\n", val); 322 if ((val & AMDSB8_WD_RST_STS) != 0) 323 device_printf(dev, "Previous Reset was caused by Watchdog\n"); 324 325 /* Find base address of memory mapped WDT registers. */ 326 for (*addr = 0, i = 0; i < 4; i++) { 327 *addr <<= 8; 328 *addr |= pmio_read(pmres, AMDSB8_PM_WDT_EN + 3 - i); 329 } 330 *addr &= ~0x07u; 331 332 /* Set watchdog timer tick to 1s. */ 333 val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL); 334 val &= ~AMDSB8_WDT_RES_MASK; 335 val |= AMDSB8_WDT_1HZ; 336 pmio_write(pmres, AMDSB8_PM_WDT_CTRL, val); 337 #ifdef AMDSBWD_DEBUG 338 val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL); 339 amdsbwd_verbose_printf(dev, "AMDSB8_PM_WDT_CTRL value = %#04x\n", val); 340 #endif 341 342 /* 343 * Enable watchdog device (in stopped state) 344 * and decoding of its address. 345 */ 346 val = pmio_read(pmres, AMDSB8_PM_WDT_EN); 347 val &= ~AMDSB8_WDT_DISABLE; 348 val |= AMDSB8_WDT_DEC_EN; 349 pmio_write(pmres, AMDSB8_PM_WDT_EN, val); 350 #ifdef AMDSBWD_DEBUG 351 val = pmio_read(pmres, AMDSB8_PM_WDT_EN); 352 device_printf(dev, "AMDSB8_PM_WDT_EN value = %#02x\n", val); 353 #endif 354 device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer"); 355 } 356 357 static void 358 amdsbwd_probe_fch41(device_t dev, struct resource *pmres, uint32_t *addr) 359 { 360 uint8_t val; 361 362 val = pmio_read(pmres, AMDFCH41_PM_ISA_CTRL); 363 if ((val & AMDFCH41_MMIO_EN) != 0) { 364 /* Fixed offset for the watchdog within ACPI MMIO range. */ 365 amdsbwd_verbose_printf(dev, "ACPI MMIO range is enabled\n"); 366 *addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_WDT_OFF; 367 } else { 368 /* 369 * Enable decoding of watchdog MMIO address. 370 */ 371 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0); 372 val |= AMDFCH41_WDT_EN; 373 pmio_write(pmres, AMDFCH41_PM_DECODE_EN0, val); 374 #ifdef AMDSBWD_DEBUG 375 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0); 376 device_printf(dev, "AMDFCH41_PM_DECODE_EN0 value = %#04x\n", 377 val); 378 #endif 379 380 /* Special fixed MMIO range for the watchdog. */ 381 *addr = AMDFCH41_WDT_FIXED_ADDR; 382 } 383 384 /* 385 * Set watchdog timer tick to 1s and 386 * enable the watchdog device (in stopped state). 387 */ 388 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3); 389 val &= ~AMDFCH41_WDT_RES_MASK; 390 val |= AMDFCH41_WDT_RES_1S; 391 val &= ~AMDFCH41_WDT_EN_MASK; 392 val |= AMDFCH41_WDT_ENABLE; 393 pmio_write(pmres, AMDFCH41_PM_DECODE_EN3, val); 394 #ifdef AMDSBWD_DEBUG 395 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3); 396 amdsbwd_verbose_printf(dev, "AMDFCH41_PM_DECODE_EN3 value = %#04x\n", 397 val); 398 #endif 399 device_set_desc(dev, "AMD FCH Rev 41h+ Watchdog Timer"); 400 } 401 402 static int 403 amdsbwd_probe(device_t dev) 404 { 405 struct resource *res; 406 device_t smb_dev; 407 uint32_t addr; 408 int rid; 409 int rc; 410 uint32_t devid; 411 uint8_t revid; 412 413 /* Do not claim some ISA PnP device by accident. */ 414 if (isa_get_logicalid(dev) != 0) 415 return (ENXIO); 416 417 rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX, 418 AMDSB_PMIO_WIDTH, -1); 419 if (rc != 0) { 420 device_printf(dev, "bus_set_resource for IO failed\n"); 421 return (ENXIO); 422 } 423 rid = 0; 424 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul, 425 AMDSB_PMIO_WIDTH, RF_ACTIVE | RF_SHAREABLE); 426 if (res == NULL) { 427 device_printf(dev, "bus_alloc_resource for IO failed\n"); 428 return (ENXIO); 429 } 430 431 smb_dev = pci_find_bsf(0, 20, 0); 432 KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n")); 433 devid = pci_get_devid(smb_dev); 434 revid = pci_get_revid(smb_dev); 435 if (devid == AMDSB_SMBUS_DEVID && revid < AMDSB8_SMBUS_REVID) { 436 amdsbwd_probe_sb7xx(dev, res, &addr); 437 } else if (devid == AMDSB_SMBUS_DEVID || 438 (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) || 439 (devid == AMDCZ_SMBUS_DEVID && revid < AMDCZ49_SMBUS_REVID)) { 440 amdsbwd_probe_sb8xx(dev, res, &addr); 441 } else { 442 amdsbwd_probe_fch41(dev, res, &addr); 443 } 444 445 bus_release_resource(dev, SYS_RES_IOPORT, rid, res); 446 bus_delete_resource(dev, SYS_RES_IOPORT, rid); 447 448 amdsbwd_verbose_printf(dev, "memory base address = %#010x\n", addr); 449 rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + AMDSB_WD_CTRL, 450 AMDSB_WDIO_REG_WIDTH, -1); 451 if (rc != 0) { 452 device_printf(dev, "bus_set_resource for control failed\n"); 453 return (ENXIO); 454 } 455 rc = bus_set_resource(dev, SYS_RES_MEMORY, 1, addr + AMDSB_WD_COUNT, 456 AMDSB_WDIO_REG_WIDTH, -1); 457 if (rc != 0) { 458 device_printf(dev, "bus_set_resource for count failed\n"); 459 return (ENXIO); 460 } 461 462 return (0); 463 } 464 465 static int 466 amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc) 467 { 468 sc->max_ticks = UINT16_MAX; 469 sc->rid_ctrl = 0; 470 sc->rid_count = 1; 471 472 sc->ms_per_tick = 1000; 473 474 sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 475 &sc->rid_ctrl, RF_ACTIVE); 476 if (sc->res_ctrl == NULL) { 477 device_printf(dev, "bus_alloc_resource for ctrl failed\n"); 478 return (ENXIO); 479 } 480 sc->res_count = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 481 &sc->rid_count, RF_ACTIVE); 482 if (sc->res_count == NULL) { 483 device_printf(dev, "bus_alloc_resource for count failed\n"); 484 return (ENXIO); 485 } 486 return (0); 487 } 488 489 static int 490 amdsbwd_attach(device_t dev) 491 { 492 struct amdsbwd_softc *sc; 493 int rc; 494 495 sc = device_get_softc(dev); 496 sc->dev = dev; 497 498 rc = amdsbwd_attach_sb(dev, sc); 499 if (rc != 0) 500 goto fail; 501 502 #ifdef AMDSBWD_DEBUG 503 device_printf(dev, "wd ctrl = %#04x\n", wdctrl_read(sc)); 504 device_printf(dev, "wd count = %#04x\n", wdcount_read(sc)); 505 #endif 506 507 /* Setup initial state of Watchdog Control. */ 508 wdctrl_write(sc, AMDSB_WD_FIRED); 509 510 if (wdctrl_read(sc) & AMDSB_WD_DISABLE) { 511 device_printf(dev, "watchdog hardware is disabled\n"); 512 goto fail; 513 } 514 515 sc->wdog.name = "AMD southbridge"; 516 sc->wdog.wdog_fn = amdsb_watchdog; 517 sc->wdog.arg = sc; 518 sc->wdog.period_max = (UINT16_MAX*1000) / 10; 519 wdog_register(&sc->wdog); 520 521 return (0); 522 523 fail: 524 amdsbwd_detach(dev); 525 return (ENXIO); 526 } 527 528 static int 529 amdsbwd_detach(device_t dev) 530 { 531 struct amdsbwd_softc *sc; 532 533 sc = device_get_softc(dev); 534 if (sc->wdog.name) 535 wdog_unregister(&sc->wdog); 536 537 if (sc->active) 538 amdsbwd_tmr_disable(sc); 539 540 if (sc->res_ctrl != NULL) 541 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl, 542 sc->res_ctrl); 543 544 if (sc->res_count != NULL) 545 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_count, 546 sc->res_count); 547 548 return (0); 549 } 550 551 static int 552 amdsbwd_suspend(device_t dev) 553 { 554 struct amdsbwd_softc *sc; 555 uint32_t val; 556 557 sc = device_get_softc(dev); 558 val = wdctrl_read(sc); 559 val &= ~AMDSB_WD_RUN; 560 wdctrl_write(sc, val); 561 return (0); 562 } 563 564 static int 565 amdsbwd_resume(device_t dev) 566 { 567 struct amdsbwd_softc *sc; 568 569 sc = device_get_softc(dev); 570 wdctrl_write(sc, AMDSB_WD_FIRED); 571 if (sc->active) { 572 amdsbwd_tmr_set(sc, sc->timeout); 573 amdsbwd_tmr_enable(sc); 574 amdsbwd_tmr_reload(sc); 575 } 576 return (0); 577 } 578