1 /* 2 * sp5100_tco : TCO timer driver for sp5100 chipsets 3 * 4 * (c) Copyright 2009 Google Inc., All Rights Reserved. 5 * 6 * Based on i8xx_tco.c: 7 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights 8 * Reserved. 9 * http://www.kernelconcepts.de 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 14 * 2 of the License, or (at your option) any later version. 15 * 16 * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide", 17 * AMD Publication 45482 "AMD SB800-Series Southbridges Register 18 * Reference Guide" 19 * AMD Publication 48751 "BIOS and Kernel Developer’s Guide (BKDG) 20 * for AMD Family 16h Models 00h-0Fh Processors" 21 * AMD Publication 51192 "AMD Bolton FCH Register Reference Guide" 22 * AMD Publication 52740 "BIOS and Kernel Developer’s Guide (BKDG) 23 * for AMD Family 16h Models 30h-3Fh Processors" 24 */ 25 26 /* 27 * Includes, defines, variables, module parameters, ... 28 */ 29 30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 31 32 #include <linux/init.h> 33 #include <linux/io.h> 34 #include <linux/ioport.h> 35 #include <linux/module.h> 36 #include <linux/moduleparam.h> 37 #include <linux/pci.h> 38 #include <linux/platform_device.h> 39 #include <linux/types.h> 40 #include <linux/watchdog.h> 41 42 #include "sp5100_tco.h" 43 44 #define TCO_DRIVER_NAME "sp5100-tco" 45 46 /* internal variables */ 47 48 enum tco_reg_layout { 49 sp5100, sb800, efch 50 }; 51 52 struct sp5100_tco { 53 struct watchdog_device wdd; 54 void __iomem *tcobase; 55 enum tco_reg_layout tco_reg_layout; 56 }; 57 58 /* the watchdog platform device */ 59 static struct platform_device *sp5100_tco_platform_device; 60 /* the associated PCI device */ 61 static struct pci_dev *sp5100_tco_pci; 62 63 /* module parameters */ 64 65 #define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat. */ 66 static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ 67 module_param(heartbeat, int, 0); 68 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default=" 69 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); 70 71 static bool nowayout = WATCHDOG_NOWAYOUT; 72 module_param(nowayout, bool, 0); 73 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started." 74 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 75 76 /* 77 * Some TCO specific functions 78 */ 79 80 static enum tco_reg_layout tco_reg_layout(struct pci_dev *dev) 81 { 82 if (dev->vendor == PCI_VENDOR_ID_ATI && 83 dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && 84 dev->revision < 0x40) { 85 return sp5100; 86 } else if (dev->vendor == PCI_VENDOR_ID_AMD && 87 ((dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS && 88 dev->revision >= 0x41) || 89 (dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS && 90 dev->revision >= 0x49))) { 91 return efch; 92 } 93 return sb800; 94 } 95 96 static int tco_timer_start(struct watchdog_device *wdd) 97 { 98 struct sp5100_tco *tco = watchdog_get_drvdata(wdd); 99 u32 val; 100 101 val = readl(SP5100_WDT_CONTROL(tco->tcobase)); 102 val |= SP5100_WDT_START_STOP_BIT; 103 writel(val, SP5100_WDT_CONTROL(tco->tcobase)); 104 105 return 0; 106 } 107 108 static int tco_timer_stop(struct watchdog_device *wdd) 109 { 110 struct sp5100_tco *tco = watchdog_get_drvdata(wdd); 111 u32 val; 112 113 val = readl(SP5100_WDT_CONTROL(tco->tcobase)); 114 val &= ~SP5100_WDT_START_STOP_BIT; 115 writel(val, SP5100_WDT_CONTROL(tco->tcobase)); 116 117 return 0; 118 } 119 120 static int tco_timer_ping(struct watchdog_device *wdd) 121 { 122 struct sp5100_tco *tco = watchdog_get_drvdata(wdd); 123 u32 val; 124 125 val = readl(SP5100_WDT_CONTROL(tco->tcobase)); 126 val |= SP5100_WDT_TRIGGER_BIT; 127 writel(val, SP5100_WDT_CONTROL(tco->tcobase)); 128 129 return 0; 130 } 131 132 static int tco_timer_set_timeout(struct watchdog_device *wdd, 133 unsigned int t) 134 { 135 struct sp5100_tco *tco = watchdog_get_drvdata(wdd); 136 137 /* Write new heartbeat to watchdog */ 138 writel(t, SP5100_WDT_COUNT(tco->tcobase)); 139 140 wdd->timeout = t; 141 142 return 0; 143 } 144 145 static u8 sp5100_tco_read_pm_reg8(u8 index) 146 { 147 outb(index, SP5100_IO_PM_INDEX_REG); 148 return inb(SP5100_IO_PM_DATA_REG); 149 } 150 151 static void sp5100_tco_update_pm_reg8(u8 index, u8 reset, u8 set) 152 { 153 u8 val; 154 155 outb(index, SP5100_IO_PM_INDEX_REG); 156 val = inb(SP5100_IO_PM_DATA_REG); 157 val &= reset; 158 val |= set; 159 outb(val, SP5100_IO_PM_DATA_REG); 160 } 161 162 static void tco_timer_enable(struct sp5100_tco *tco) 163 { 164 u32 val; 165 166 switch (tco->tco_reg_layout) { 167 case sb800: 168 /* For SB800 or later */ 169 /* Set the Watchdog timer resolution to 1 sec */ 170 sp5100_tco_update_pm_reg8(SB800_PM_WATCHDOG_CONFIG, 171 0xff, SB800_PM_WATCHDOG_SECOND_RES); 172 173 /* Enable watchdog decode bit and watchdog timer */ 174 sp5100_tco_update_pm_reg8(SB800_PM_WATCHDOG_CONTROL, 175 ~SB800_PM_WATCHDOG_DISABLE, 176 SB800_PCI_WATCHDOG_DECODE_EN); 177 break; 178 case sp5100: 179 /* For SP5100 or SB7x0 */ 180 /* Enable watchdog decode bit */ 181 pci_read_config_dword(sp5100_tco_pci, 182 SP5100_PCI_WATCHDOG_MISC_REG, 183 &val); 184 185 val |= SP5100_PCI_WATCHDOG_DECODE_EN; 186 187 pci_write_config_dword(sp5100_tco_pci, 188 SP5100_PCI_WATCHDOG_MISC_REG, 189 val); 190 191 /* Enable Watchdog timer and set the resolution to 1 sec */ 192 sp5100_tco_update_pm_reg8(SP5100_PM_WATCHDOG_CONTROL, 193 ~SP5100_PM_WATCHDOG_DISABLE, 194 SP5100_PM_WATCHDOG_SECOND_RES); 195 break; 196 case efch: 197 /* Set the Watchdog timer resolution to 1 sec and enable */ 198 sp5100_tco_update_pm_reg8(EFCH_PM_DECODEEN3, 199 ~EFCH_PM_WATCHDOG_DISABLE, 200 EFCH_PM_DECODEEN_SECOND_RES); 201 break; 202 } 203 } 204 205 static u32 sp5100_tco_read_pm_reg32(u8 index) 206 { 207 u32 val = 0; 208 int i; 209 210 for (i = 3; i >= 0; i--) 211 val = (val << 8) + sp5100_tco_read_pm_reg8(index + i); 212 213 return val; 214 } 215 216 static int sp5100_tco_setupdevice(struct device *dev, 217 struct watchdog_device *wdd) 218 { 219 struct sp5100_tco *tco = watchdog_get_drvdata(wdd); 220 const char *dev_name; 221 u32 mmio_addr = 0, val; 222 int ret; 223 224 /* Request the IO ports used by this driver */ 225 if (!request_muxed_region(SP5100_IO_PM_INDEX_REG, 226 SP5100_PM_IOPORTS_SIZE, "sp5100_tco")) { 227 dev_err(dev, "I/O address 0x%04x already in use\n", 228 SP5100_IO_PM_INDEX_REG); 229 return -EBUSY; 230 } 231 232 /* 233 * Determine type of southbridge chipset. 234 */ 235 switch (tco->tco_reg_layout) { 236 case sp5100: 237 dev_name = SP5100_DEVNAME; 238 mmio_addr = sp5100_tco_read_pm_reg32(SP5100_PM_WATCHDOG_BASE) & 239 0xfffffff8; 240 break; 241 case sb800: 242 dev_name = SB800_DEVNAME; 243 mmio_addr = sp5100_tco_read_pm_reg32(SB800_PM_WATCHDOG_BASE) & 244 0xfffffff8; 245 break; 246 case efch: 247 dev_name = SB800_DEVNAME; 248 val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN); 249 if (val & EFCH_PM_DECODEEN_WDT_TMREN) 250 mmio_addr = EFCH_PM_WDT_ADDR; 251 break; 252 default: 253 return -ENODEV; 254 } 255 256 /* Check MMIO address conflict */ 257 if (!mmio_addr || 258 !devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE, 259 dev_name)) { 260 if (mmio_addr) 261 dev_dbg(dev, "MMIO address 0x%08x already in use\n", 262 mmio_addr); 263 switch (tco->tco_reg_layout) { 264 case sp5100: 265 /* 266 * Secondly, Find the watchdog timer MMIO address 267 * from SBResource_MMIO register. 268 */ 269 /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */ 270 pci_read_config_dword(sp5100_tco_pci, 271 SP5100_SB_RESOURCE_MMIO_BASE, 272 &mmio_addr); 273 if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN | 274 SB800_ACPI_MMIO_SEL)) != 275 SB800_ACPI_MMIO_DECODE_EN) { 276 ret = -ENODEV; 277 goto unreg_region; 278 } 279 mmio_addr &= ~0xFFF; 280 mmio_addr += SB800_PM_WDT_MMIO_OFFSET; 281 break; 282 case sb800: 283 /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */ 284 mmio_addr = 285 sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN); 286 if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN | 287 SB800_ACPI_MMIO_SEL)) != 288 SB800_ACPI_MMIO_DECODE_EN) { 289 ret = -ENODEV; 290 goto unreg_region; 291 } 292 mmio_addr &= ~0xFFF; 293 mmio_addr += SB800_PM_WDT_MMIO_OFFSET; 294 break; 295 case efch: 296 val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL); 297 if (!(val & EFCH_PM_ISACONTROL_MMIOEN)) { 298 ret = -ENODEV; 299 goto unreg_region; 300 } 301 mmio_addr = EFCH_PM_ACPI_MMIO_ADDR + 302 EFCH_PM_ACPI_MMIO_WDT_OFFSET; 303 break; 304 } 305 dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n", 306 mmio_addr); 307 if (!devm_request_mem_region(dev, mmio_addr, 308 SP5100_WDT_MEM_MAP_SIZE, 309 dev_name)) { 310 dev_dbg(dev, "MMIO address 0x%08x already in use\n", 311 mmio_addr); 312 ret = -EBUSY; 313 goto unreg_region; 314 } 315 } 316 317 tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE); 318 if (!tco->tcobase) { 319 dev_err(dev, "failed to get tcobase address\n"); 320 ret = -ENOMEM; 321 goto unreg_region; 322 } 323 324 dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr); 325 326 /* Setup the watchdog timer */ 327 tco_timer_enable(tco); 328 329 val = readl(SP5100_WDT_CONTROL(tco->tcobase)); 330 if (val & SP5100_WDT_DISABLED) { 331 dev_err(dev, "Watchdog hardware is disabled\n"); 332 ret = -ENODEV; 333 goto unreg_region; 334 } 335 336 /* 337 * Save WatchDogFired status, because WatchDogFired flag is 338 * cleared here. 339 */ 340 if (val & SP5100_WDT_FIRED) 341 wdd->bootstatus = WDIOF_CARDRESET; 342 /* Set watchdog action to reset the system */ 343 val &= ~SP5100_WDT_ACTION_RESET; 344 writel(val, SP5100_WDT_CONTROL(tco->tcobase)); 345 346 /* Set a reasonable heartbeat before we stop the timer */ 347 tco_timer_set_timeout(wdd, wdd->timeout); 348 349 /* 350 * Stop the TCO before we change anything so we don't race with 351 * a zeroed timer. 352 */ 353 tco_timer_stop(wdd); 354 355 release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE); 356 357 return 0; 358 359 unreg_region: 360 release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE); 361 return ret; 362 } 363 364 static struct watchdog_info sp5100_tco_wdt_info = { 365 .identity = "SP5100 TCO timer", 366 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 367 }; 368 369 static const struct watchdog_ops sp5100_tco_wdt_ops = { 370 .owner = THIS_MODULE, 371 .start = tco_timer_start, 372 .stop = tco_timer_stop, 373 .ping = tco_timer_ping, 374 .set_timeout = tco_timer_set_timeout, 375 }; 376 377 static int sp5100_tco_probe(struct platform_device *pdev) 378 { 379 struct device *dev = &pdev->dev; 380 struct watchdog_device *wdd; 381 struct sp5100_tco *tco; 382 int ret; 383 384 tco = devm_kzalloc(dev, sizeof(*tco), GFP_KERNEL); 385 if (!tco) 386 return -ENOMEM; 387 388 tco->tco_reg_layout = tco_reg_layout(sp5100_tco_pci); 389 390 wdd = &tco->wdd; 391 wdd->parent = dev; 392 wdd->info = &sp5100_tco_wdt_info; 393 wdd->ops = &sp5100_tco_wdt_ops; 394 wdd->timeout = WATCHDOG_HEARTBEAT; 395 wdd->min_timeout = 1; 396 wdd->max_timeout = 0xffff; 397 398 watchdog_init_timeout(wdd, heartbeat, NULL); 399 watchdog_set_nowayout(wdd, nowayout); 400 watchdog_stop_on_reboot(wdd); 401 watchdog_stop_on_unregister(wdd); 402 watchdog_set_drvdata(wdd, tco); 403 404 ret = sp5100_tco_setupdevice(dev, wdd); 405 if (ret) 406 return ret; 407 408 ret = devm_watchdog_register_device(dev, wdd); 409 if (ret) { 410 dev_err(dev, "cannot register watchdog device (err=%d)\n", ret); 411 return ret; 412 } 413 414 /* Show module parameters */ 415 dev_info(dev, "initialized. heartbeat=%d sec (nowayout=%d)\n", 416 wdd->timeout, nowayout); 417 418 return 0; 419 } 420 421 static struct platform_driver sp5100_tco_driver = { 422 .probe = sp5100_tco_probe, 423 .driver = { 424 .name = TCO_DRIVER_NAME, 425 }, 426 }; 427 428 /* 429 * Data for PCI driver interface 430 * 431 * This data only exists for exporting the supported 432 * PCI ids via MODULE_DEVICE_TABLE. We do not actually 433 * register a pci_driver, because someone else might 434 * want to register another driver on the same PCI id. 435 */ 436 static const struct pci_device_id sp5100_tco_pci_tbl[] = { 437 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID, 438 PCI_ANY_ID, }, 439 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, PCI_ANY_ID, 440 PCI_ANY_ID, }, 441 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, PCI_ANY_ID, 442 PCI_ANY_ID, }, 443 { 0, }, /* End of list */ 444 }; 445 MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl); 446 447 static int __init sp5100_tco_init(void) 448 { 449 struct pci_dev *dev = NULL; 450 int err; 451 452 /* Match the PCI device */ 453 for_each_pci_dev(dev) { 454 if (pci_match_id(sp5100_tco_pci_tbl, dev) != NULL) { 455 sp5100_tco_pci = dev; 456 break; 457 } 458 } 459 460 if (!sp5100_tco_pci) 461 return -ENODEV; 462 463 pr_info("SP5100/SB800 TCO WatchDog Timer Driver\n"); 464 465 err = platform_driver_register(&sp5100_tco_driver); 466 if (err) 467 return err; 468 469 sp5100_tco_platform_device = 470 platform_device_register_simple(TCO_DRIVER_NAME, -1, NULL, 0); 471 if (IS_ERR(sp5100_tco_platform_device)) { 472 err = PTR_ERR(sp5100_tco_platform_device); 473 goto unreg_platform_driver; 474 } 475 476 return 0; 477 478 unreg_platform_driver: 479 platform_driver_unregister(&sp5100_tco_driver); 480 return err; 481 } 482 483 static void __exit sp5100_tco_exit(void) 484 { 485 platform_device_unregister(sp5100_tco_platform_device); 486 platform_driver_unregister(&sp5100_tco_driver); 487 } 488 489 module_init(sp5100_tco_init); 490 module_exit(sp5100_tco_exit); 491 492 MODULE_AUTHOR("Priyanka Gupta"); 493 MODULE_DESCRIPTION("TCO timer driver for SP5100/SB800 chipset"); 494 MODULE_LICENSE("GPL"); 495