Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Siemens SIMATIC IPC driver for Watchdogs
0004  *
0005  * Copyright (c) Siemens AG, 2020-2021
0006  *
0007  * Authors:
0008  *  Gerd Haeussler <gerd.haeussler.ext@siemens.com>
0009  */
0010 
0011 #include <linux/device.h>
0012 #include <linux/errno.h>
0013 #include <linux/init.h>
0014 #include <linux/io.h>
0015 #include <linux/ioport.h>
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/pci.h>
0019 #include <linux/platform_data/x86/p2sb.h>
0020 #include <linux/platform_data/x86/simatic-ipc-base.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/sizes.h>
0023 #include <linux/util_macros.h>
0024 #include <linux/watchdog.h>
0025 
0026 #define WD_ENABLE_IOADR         0x62
0027 #define WD_TRIGGER_IOADR        0x66
0028 #define GPIO_COMMUNITY0_PORT_ID     0xaf
0029 #define PAD_CFG_DW0_GPP_A_23        0x4b8
0030 #define SAFE_EN_N_427E          0x01
0031 #define SAFE_EN_N_227E          0x04
0032 #define WD_ENABLED          0x01
0033 #define WD_TRIGGERED            0x80
0034 #define WD_MACROMODE            0x02
0035 
0036 #define TIMEOUT_MIN 2
0037 #define TIMEOUT_DEF 64
0038 #define TIMEOUT_MAX 64
0039 
0040 #define GP_STATUS_REG_227E  0x404D  /* IO PORT for SAFE_EN_N on 227E */
0041 
0042 static bool nowayout = WATCHDOG_NOWAYOUT;
0043 module_param(nowayout, bool, 0000);
0044 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
0045          __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0046 
0047 static struct resource gp_status_reg_227e_res =
0048     DEFINE_RES_IO_NAMED(GP_STATUS_REG_227E, SZ_1, KBUILD_MODNAME);
0049 
0050 static struct resource io_resource_enable =
0051     DEFINE_RES_IO_NAMED(WD_ENABLE_IOADR, SZ_1,
0052                 KBUILD_MODNAME " WD_ENABLE_IOADR");
0053 
0054 static struct resource io_resource_trigger =
0055     DEFINE_RES_IO_NAMED(WD_TRIGGER_IOADR, SZ_1,
0056                 KBUILD_MODNAME " WD_TRIGGER_IOADR");
0057 
0058 /* the actual start will be discovered with p2sb, 0 is a placeholder */
0059 static struct resource mem_resource =
0060     DEFINE_RES_MEM_NAMED(0, 0, "WD_RESET_BASE_ADR");
0061 
0062 static u32 wd_timeout_table[] = {2, 4, 6, 8, 16, 32, 48, 64 };
0063 static void __iomem *wd_reset_base_addr;
0064 
0065 static int wd_start(struct watchdog_device *wdd)
0066 {
0067     outb(inb(WD_ENABLE_IOADR) | WD_ENABLED, WD_ENABLE_IOADR);
0068     return 0;
0069 }
0070 
0071 static int wd_stop(struct watchdog_device *wdd)
0072 {
0073     outb(inb(WD_ENABLE_IOADR) & ~WD_ENABLED, WD_ENABLE_IOADR);
0074     return 0;
0075 }
0076 
0077 static int wd_ping(struct watchdog_device *wdd)
0078 {
0079     inb(WD_TRIGGER_IOADR);
0080     return 0;
0081 }
0082 
0083 static int wd_set_timeout(struct watchdog_device *wdd, unsigned int t)
0084 {
0085     int timeout_idx = find_closest(t, wd_timeout_table,
0086                        ARRAY_SIZE(wd_timeout_table));
0087 
0088     outb((inb(WD_ENABLE_IOADR) & 0xc7) | timeout_idx << 3, WD_ENABLE_IOADR);
0089     wdd->timeout = wd_timeout_table[timeout_idx];
0090     return 0;
0091 }
0092 
0093 static const struct watchdog_info wdt_ident = {
0094     .options    = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
0095               WDIOF_SETTIMEOUT,
0096     .identity   = KBUILD_MODNAME,
0097 };
0098 
0099 static const struct watchdog_ops wdt_ops = {
0100     .owner      = THIS_MODULE,
0101     .start      = wd_start,
0102     .stop       = wd_stop,
0103     .ping       = wd_ping,
0104     .set_timeout    = wd_set_timeout,
0105 };
0106 
0107 static void wd_secondary_enable(u32 wdtmode)
0108 {
0109     u16 resetbit;
0110 
0111     /* set safe_en_n so we are not just WDIOF_ALARMONLY */
0112     if (wdtmode == SIMATIC_IPC_DEVICE_227E) {
0113         /* enable SAFE_EN_N on GP_STATUS_REG_227E */
0114         resetbit = inb(GP_STATUS_REG_227E);
0115         outb(resetbit & ~SAFE_EN_N_227E, GP_STATUS_REG_227E);
0116     } else {
0117         /* enable SAFE_EN_N on PCH D1600 */
0118         resetbit = ioread16(wd_reset_base_addr);
0119         iowrite16(resetbit & ~SAFE_EN_N_427E, wd_reset_base_addr);
0120     }
0121 }
0122 
0123 static int wd_setup(u32 wdtmode)
0124 {
0125     unsigned int bootstatus = 0;
0126     int timeout_idx;
0127 
0128     timeout_idx = find_closest(TIMEOUT_DEF, wd_timeout_table,
0129                    ARRAY_SIZE(wd_timeout_table));
0130 
0131     if (inb(WD_ENABLE_IOADR) & WD_TRIGGERED)
0132         bootstatus |= WDIOF_CARDRESET;
0133 
0134     /* reset alarm bit, set macro mode, and set timeout */
0135     outb(WD_TRIGGERED | WD_MACROMODE | timeout_idx << 3, WD_ENABLE_IOADR);
0136 
0137     wd_secondary_enable(wdtmode);
0138 
0139     return bootstatus;
0140 }
0141 
0142 static struct watchdog_device wdd_data = {
0143     .info = &wdt_ident,
0144     .ops = &wdt_ops,
0145     .min_timeout = TIMEOUT_MIN,
0146     .max_timeout = TIMEOUT_MAX
0147 };
0148 
0149 static int simatic_ipc_wdt_probe(struct platform_device *pdev)
0150 {
0151     struct simatic_ipc_platform *plat = pdev->dev.platform_data;
0152     struct device *dev = &pdev->dev;
0153     struct resource *res;
0154     int ret;
0155 
0156     switch (plat->devmode) {
0157     case SIMATIC_IPC_DEVICE_227E:
0158         if (!devm_request_region(dev, gp_status_reg_227e_res.start,
0159                      resource_size(&gp_status_reg_227e_res),
0160                      KBUILD_MODNAME)) {
0161             dev_err(dev,
0162                 "Unable to register IO resource at %pR\n",
0163                 &gp_status_reg_227e_res);
0164             return -EBUSY;
0165         }
0166         fallthrough;
0167     case SIMATIC_IPC_DEVICE_427E:
0168         wdd_data.parent = dev;
0169         break;
0170     default:
0171         return -EINVAL;
0172     }
0173 
0174     if (!devm_request_region(dev, io_resource_enable.start,
0175                  resource_size(&io_resource_enable),
0176                  io_resource_enable.name)) {
0177         dev_err(dev,
0178             "Unable to register IO resource at %#x\n",
0179             WD_ENABLE_IOADR);
0180         return -EBUSY;
0181     }
0182 
0183     if (!devm_request_region(dev, io_resource_trigger.start,
0184                  resource_size(&io_resource_trigger),
0185                  io_resource_trigger.name)) {
0186         dev_err(dev,
0187             "Unable to register IO resource at %#x\n",
0188             WD_TRIGGER_IOADR);
0189         return -EBUSY;
0190     }
0191 
0192     if (plat->devmode == SIMATIC_IPC_DEVICE_427E) {
0193         res = &mem_resource;
0194 
0195         ret = p2sb_bar(NULL, 0, res);
0196         if (ret)
0197             return ret;
0198 
0199         /* do the final address calculation */
0200         res->start = res->start + (GPIO_COMMUNITY0_PORT_ID << 16) +
0201                  PAD_CFG_DW0_GPP_A_23;
0202         res->end = res->start + SZ_4 - 1;
0203 
0204         wd_reset_base_addr = devm_ioremap_resource(dev, res);
0205         if (IS_ERR(wd_reset_base_addr))
0206             return PTR_ERR(wd_reset_base_addr);
0207     }
0208 
0209     wdd_data.bootstatus = wd_setup(plat->devmode);
0210     if (wdd_data.bootstatus)
0211         dev_warn(dev, "last reboot caused by watchdog reset\n");
0212 
0213     watchdog_set_nowayout(&wdd_data, nowayout);
0214     watchdog_stop_on_reboot(&wdd_data);
0215     return devm_watchdog_register_device(dev, &wdd_data);
0216 }
0217 
0218 static struct platform_driver simatic_ipc_wdt_driver = {
0219     .probe = simatic_ipc_wdt_probe,
0220     .driver = {
0221         .name = KBUILD_MODNAME,
0222     },
0223 };
0224 
0225 module_platform_driver(simatic_ipc_wdt_driver);
0226 
0227 MODULE_LICENSE("GPL v2");
0228 MODULE_ALIAS("platform:" KBUILD_MODNAME);
0229 MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>");