Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  w83627hf/thf WDT driver
0004  *
0005  *  (c) Copyright 2013 Guenter Roeck
0006  *      converted to watchdog infrastructure
0007  *
0008  *  (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
0009  *      added support for W83627THF.
0010  *
0011  *  (c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com>
0012  *
0013  *  Based on advantechwdt.c which is based on wdt.c.
0014  *  Original copyright messages:
0015  *
0016  *  (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
0017  *
0018  *  (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
0019  *                      All Rights Reserved.
0020  *
0021  *  Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
0022  *  warranty for any of this software. This material is provided
0023  *  "AS-IS" and at no charge.
0024  *
0025  *  (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
0026  */
0027 
0028 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0029 
0030 #include <linux/module.h>
0031 #include <linux/moduleparam.h>
0032 #include <linux/types.h>
0033 #include <linux/watchdog.h>
0034 #include <linux/ioport.h>
0035 #include <linux/init.h>
0036 #include <linux/io.h>
0037 #include <linux/dmi.h>
0038 
0039 #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
0040 #define WATCHDOG_TIMEOUT 60     /* 60 sec default timeout */
0041 
0042 static int wdt_io;
0043 static int cr_wdt_timeout;  /* WDT timeout register */
0044 static int cr_wdt_control;  /* WDT control register */
0045 static int cr_wdt_csr;      /* WDT control & status register */
0046 static int wdt_cfg_enter = 0x87;/* key to unlock configuration space */
0047 static int wdt_cfg_leave = 0xAA;/* key to lock configuration space */
0048 
0049 enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
0050          w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
0051          w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
0052          nct6795, nct6796, nct6102, nct6116 };
0053 
0054 static int timeout;         /* in seconds */
0055 module_param(timeout, int, 0);
0056 MODULE_PARM_DESC(timeout,
0057         "Watchdog timeout in seconds. 1 <= timeout <= 255, default="
0058                 __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
0059 
0060 static bool nowayout = WATCHDOG_NOWAYOUT;
0061 module_param(nowayout, bool, 0);
0062 MODULE_PARM_DESC(nowayout,
0063         "Watchdog cannot be stopped once started (default="
0064                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0065 
0066 static int early_disable;
0067 module_param(early_disable, int, 0);
0068 MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
0069 
0070 /*
0071  *  Kernel methods.
0072  */
0073 
0074 #define WDT_EFER (wdt_io+0)   /* Extended Function Enable Registers */
0075 #define WDT_EFIR (wdt_io+0)   /* Extended Function Index Register
0076                             (same as EFER) */
0077 #define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
0078 
0079 #define W83627HF_LD_WDT     0x08
0080 
0081 #define W83627HF_ID     0x52
0082 #define W83627S_ID      0x59
0083 #define W83697HF_ID     0x60
0084 #define W83697UG_ID     0x68
0085 #define W83637HF_ID     0x70
0086 #define W83627THF_ID        0x82
0087 #define W83687THF_ID        0x85
0088 #define W83627EHF_ID        0x88
0089 #define W83627DHG_ID        0xa0
0090 #define W83627UHG_ID        0xa2
0091 #define W83667HG_ID     0xa5
0092 #define W83627DHG_P_ID      0xb0
0093 #define W83667HG_B_ID       0xb3
0094 #define NCT6775_ID      0xb4
0095 #define NCT6776_ID      0xc3
0096 #define NCT6102_ID      0xc4
0097 #define NCT6116_ID      0xd2
0098 #define NCT6779_ID      0xc5
0099 #define NCT6791_ID      0xc8
0100 #define NCT6792_ID      0xc9
0101 #define NCT6793_ID      0xd1
0102 #define NCT6795_ID      0xd3
0103 #define NCT6796_ID      0xd4    /* also NCT9697D, NCT9698D */
0104 
0105 #define W83627HF_WDT_TIMEOUT    0xf6
0106 #define W83697HF_WDT_TIMEOUT    0xf4
0107 #define NCT6102D_WDT_TIMEOUT    0xf1
0108 
0109 #define W83627HF_WDT_CONTROL    0xf5
0110 #define W83697HF_WDT_CONTROL    0xf3
0111 #define NCT6102D_WDT_CONTROL    0xf0
0112 
0113 #define W836X7HF_WDT_CSR    0xf7
0114 #define NCT6102D_WDT_CSR    0xf2
0115 
0116 static void superio_outb(int reg, int val)
0117 {
0118     outb(reg, WDT_EFER);
0119     outb(val, WDT_EFDR);
0120 }
0121 
0122 static inline int superio_inb(int reg)
0123 {
0124     outb(reg, WDT_EFER);
0125     return inb(WDT_EFDR);
0126 }
0127 
0128 static int superio_enter(void)
0129 {
0130     if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME))
0131         return -EBUSY;
0132 
0133     outb_p(wdt_cfg_enter, WDT_EFER); /* Enter extended function mode */
0134     outb_p(wdt_cfg_enter, WDT_EFER); /* Again according to manual */
0135 
0136     return 0;
0137 }
0138 
0139 static void superio_select(int ld)
0140 {
0141     superio_outb(0x07, ld);
0142 }
0143 
0144 static void superio_exit(void)
0145 {
0146     outb_p(wdt_cfg_leave, WDT_EFER); /* Leave extended function mode */
0147     release_region(wdt_io, 2);
0148 }
0149 
0150 static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
0151 {
0152     int ret;
0153     unsigned char t;
0154 
0155     ret = superio_enter();
0156     if (ret)
0157         return ret;
0158 
0159     superio_select(W83627HF_LD_WDT);
0160 
0161     /* set CR30 bit 0 to activate GPIO2 */
0162     t = superio_inb(0x30);
0163     if (!(t & 0x01))
0164         superio_outb(0x30, t | 0x01);
0165 
0166     switch (chip) {
0167     case w83627hf:
0168     case w83627s:
0169         t = superio_inb(0x2B) & ~0x10;
0170         superio_outb(0x2B, t); /* set GPIO24 to WDT0 */
0171         break;
0172     case w83697hf:
0173         /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
0174         t = superio_inb(0x29) & ~0x60;
0175         t |= 0x20;
0176         superio_outb(0x29, t);
0177         break;
0178     case w83697ug:
0179         /* Set pin 118 to WDTO# mode */
0180         t = superio_inb(0x2b) & ~0x04;
0181         superio_outb(0x2b, t);
0182         break;
0183     case w83627thf:
0184         t = (superio_inb(0x2B) & ~0x08) | 0x04;
0185         superio_outb(0x2B, t); /* set GPIO3 to WDT0 */
0186         break;
0187     case w83627dhg:
0188     case w83627dhg_p:
0189         t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */
0190         superio_outb(0x2D, t); /* set GPIO5 to WDT0 */
0191         t = superio_inb(cr_wdt_control);
0192         t |= 0x02;  /* enable the WDTO# output low pulse
0193                  * to the KBRST# pin */
0194         superio_outb(cr_wdt_control, t);
0195         break;
0196     case w83637hf:
0197         break;
0198     case w83687thf:
0199         t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */
0200         superio_outb(0x2C, t);
0201         break;
0202     case w83627ehf:
0203     case w83627uhg:
0204     case w83667hg:
0205     case w83667hg_b:
0206     case nct6775:
0207     case nct6776:
0208     case nct6779:
0209     case nct6791:
0210     case nct6792:
0211     case nct6793:
0212     case nct6795:
0213     case nct6796:
0214     case nct6102:
0215     case nct6116:
0216         /*
0217          * These chips have a fixed WDTO# output pin (W83627UHG),
0218          * or support more than one WDTO# output pin.
0219          * Don't touch its configuration, and hope the BIOS
0220          * does the right thing.
0221          */
0222         t = superio_inb(cr_wdt_control);
0223         t |= 0x02;  /* enable the WDTO# output low pulse
0224                  * to the KBRST# pin */
0225         superio_outb(cr_wdt_control, t);
0226         break;
0227     default:
0228         break;
0229     }
0230 
0231     t = superio_inb(cr_wdt_timeout);
0232     if (t != 0) {
0233         if (early_disable) {
0234             pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
0235             superio_outb(cr_wdt_timeout, 0);
0236         } else {
0237             pr_info("Watchdog already running. Resetting timeout to %d sec\n",
0238                 wdog->timeout);
0239             superio_outb(cr_wdt_timeout, wdog->timeout);
0240         }
0241     }
0242 
0243     /* set second mode & disable keyboard turning off watchdog */
0244     t = superio_inb(cr_wdt_control) & ~0x0C;
0245     superio_outb(cr_wdt_control, t);
0246 
0247     /* reset trigger, disable keyboard & mouse turning off watchdog */
0248     t = superio_inb(cr_wdt_csr) & ~0xD0;
0249     superio_outb(cr_wdt_csr, t);
0250 
0251     superio_exit();
0252 
0253     return 0;
0254 }
0255 
0256 static int wdt_set_time(unsigned int timeout)
0257 {
0258     int ret;
0259 
0260     ret = superio_enter();
0261     if (ret)
0262         return ret;
0263 
0264     superio_select(W83627HF_LD_WDT);
0265     superio_outb(cr_wdt_timeout, timeout);
0266     superio_exit();
0267 
0268     return 0;
0269 }
0270 
0271 static int wdt_start(struct watchdog_device *wdog)
0272 {
0273     return wdt_set_time(wdog->timeout);
0274 }
0275 
0276 static int wdt_stop(struct watchdog_device *wdog)
0277 {
0278     return wdt_set_time(0);
0279 }
0280 
0281 static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
0282 {
0283     wdog->timeout = timeout;
0284 
0285     return 0;
0286 }
0287 
0288 static unsigned int wdt_get_time(struct watchdog_device *wdog)
0289 {
0290     unsigned int timeleft;
0291     int ret;
0292 
0293     ret = superio_enter();
0294     if (ret)
0295         return 0;
0296 
0297     superio_select(W83627HF_LD_WDT);
0298     timeleft = superio_inb(cr_wdt_timeout);
0299     superio_exit();
0300 
0301     return timeleft;
0302 }
0303 
0304 /*
0305  *  Kernel Interfaces
0306  */
0307 
0308 static const struct watchdog_info wdt_info = {
0309     .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0310     .identity = "W83627HF Watchdog",
0311 };
0312 
0313 static const struct watchdog_ops wdt_ops = {
0314     .owner = THIS_MODULE,
0315     .start = wdt_start,
0316     .stop = wdt_stop,
0317     .set_timeout = wdt_set_timeout,
0318     .get_timeleft = wdt_get_time,
0319 };
0320 
0321 static struct watchdog_device wdt_dev = {
0322     .info = &wdt_info,
0323     .ops = &wdt_ops,
0324     .timeout = WATCHDOG_TIMEOUT,
0325     .min_timeout = 1,
0326     .max_timeout = 255,
0327 };
0328 
0329 /*
0330  *  The WDT needs to learn about soft shutdowns in order to
0331  *  turn the timebomb registers off.
0332  */
0333 
0334 static int wdt_find(int addr)
0335 {
0336     u8 val;
0337     int ret;
0338 
0339     cr_wdt_timeout = W83627HF_WDT_TIMEOUT;
0340     cr_wdt_control = W83627HF_WDT_CONTROL;
0341     cr_wdt_csr = W836X7HF_WDT_CSR;
0342 
0343     ret = superio_enter();
0344     if (ret)
0345         return ret;
0346     superio_select(W83627HF_LD_WDT);
0347     val = superio_inb(0x20);
0348     switch (val) {
0349     case W83627HF_ID:
0350         ret = w83627hf;
0351         break;
0352     case W83627S_ID:
0353         ret = w83627s;
0354         break;
0355     case W83697HF_ID:
0356         ret = w83697hf;
0357         cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
0358         cr_wdt_control = W83697HF_WDT_CONTROL;
0359         break;
0360     case W83697UG_ID:
0361         ret = w83697ug;
0362         cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
0363         cr_wdt_control = W83697HF_WDT_CONTROL;
0364         break;
0365     case W83637HF_ID:
0366         ret = w83637hf;
0367         break;
0368     case W83627THF_ID:
0369         ret = w83627thf;
0370         break;
0371     case W83687THF_ID:
0372         ret = w83687thf;
0373         break;
0374     case W83627EHF_ID:
0375         ret = w83627ehf;
0376         break;
0377     case W83627DHG_ID:
0378         ret = w83627dhg;
0379         break;
0380     case W83627DHG_P_ID:
0381         ret = w83627dhg_p;
0382         break;
0383     case W83627UHG_ID:
0384         ret = w83627uhg;
0385         break;
0386     case W83667HG_ID:
0387         ret = w83667hg;
0388         break;
0389     case W83667HG_B_ID:
0390         ret = w83667hg_b;
0391         break;
0392     case NCT6775_ID:
0393         ret = nct6775;
0394         break;
0395     case NCT6776_ID:
0396         ret = nct6776;
0397         break;
0398     case NCT6779_ID:
0399         ret = nct6779;
0400         break;
0401     case NCT6791_ID:
0402         ret = nct6791;
0403         break;
0404     case NCT6792_ID:
0405         ret = nct6792;
0406         break;
0407     case NCT6793_ID:
0408         ret = nct6793;
0409         break;
0410     case NCT6795_ID:
0411         ret = nct6795;
0412         break;
0413     case NCT6796_ID:
0414         ret = nct6796;
0415         break;
0416     case NCT6102_ID:
0417         ret = nct6102;
0418         cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
0419         cr_wdt_control = NCT6102D_WDT_CONTROL;
0420         cr_wdt_csr = NCT6102D_WDT_CSR;
0421         break;
0422     case NCT6116_ID:
0423         ret = nct6116;
0424         cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
0425         cr_wdt_control = NCT6102D_WDT_CONTROL;
0426         cr_wdt_csr = NCT6102D_WDT_CSR;
0427         break;
0428     case 0xff:
0429         ret = -ENODEV;
0430         break;
0431     default:
0432         ret = -ENODEV;
0433         pr_err("Unsupported chip ID: 0x%02x\n", val);
0434         break;
0435     }
0436     superio_exit();
0437     return ret;
0438 }
0439 
0440 /*
0441  * On some systems, the NCT6791D comes with a companion chip and the
0442  * watchdog function is in this companion chip. We must use a different
0443  * unlocking sequence to access the companion chip.
0444  */
0445 static int __init wdt_use_alt_key(const struct dmi_system_id *d)
0446 {
0447     wdt_cfg_enter = 0x88;
0448     wdt_cfg_leave = 0xBB;
0449 
0450     return 0;
0451 }
0452 
0453 static const struct dmi_system_id wdt_dmi_table[] __initconst = {
0454     {
0455         .matches = {
0456             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "INVES"),
0457             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CTS"),
0458             DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "INVES"),
0459             DMI_EXACT_MATCH(DMI_BOARD_NAME, "SHARKBAY"),
0460         },
0461         .callback = wdt_use_alt_key,
0462     },
0463     {}
0464 };
0465 
0466 static int __init wdt_init(void)
0467 {
0468     int ret;
0469     int chip;
0470     static const char * const chip_name[] = {
0471         "W83627HF",
0472         "W83627S",
0473         "W83697HF",
0474         "W83697UG",
0475         "W83637HF",
0476         "W83627THF",
0477         "W83687THF",
0478         "W83627EHF",
0479         "W83627DHG",
0480         "W83627UHG",
0481         "W83667HG",
0482         "W83667DHG-P",
0483         "W83667HG-B",
0484         "NCT6775",
0485         "NCT6776",
0486         "NCT6779",
0487         "NCT6791",
0488         "NCT6792",
0489         "NCT6793",
0490         "NCT6795",
0491         "NCT6796",
0492         "NCT6102",
0493         "NCT6116",
0494     };
0495 
0496     /* Apply system-specific quirks */
0497     dmi_check_system(wdt_dmi_table);
0498 
0499     wdt_io = 0x2e;
0500     chip = wdt_find(0x2e);
0501     if (chip < 0) {
0502         wdt_io = 0x4e;
0503         chip = wdt_find(0x4e);
0504         if (chip < 0)
0505             return chip;
0506     }
0507 
0508     pr_info("WDT driver for %s Super I/O chip initialising\n",
0509         chip_name[chip]);
0510 
0511     watchdog_init_timeout(&wdt_dev, timeout, NULL);
0512     watchdog_set_nowayout(&wdt_dev, nowayout);
0513     watchdog_stop_on_reboot(&wdt_dev);
0514 
0515     ret = w83627hf_init(&wdt_dev, chip);
0516     if (ret) {
0517         pr_err("failed to initialize watchdog (err=%d)\n", ret);
0518         return ret;
0519     }
0520 
0521     ret = watchdog_register_device(&wdt_dev);
0522     if (ret)
0523         return ret;
0524 
0525     pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
0526         wdt_dev.timeout, nowayout);
0527 
0528     return ret;
0529 }
0530 
0531 static void __exit wdt_exit(void)
0532 {
0533     watchdog_unregister_device(&wdt_dev);
0534 }
0535 
0536 module_init(wdt_init);
0537 module_exit(wdt_exit);
0538 
0539 MODULE_LICENSE("GPL");
0540 MODULE_AUTHOR("Pádraig  Brady <P@draigBrady.com>");
0541 MODULE_DESCRIPTION("w83627hf/thf WDT driver");