Merge tag 'linux-watchdog-5.18-rc1' of git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 31 Mar 2022 21:14:03 +0000 (14:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 31 Mar 2022 21:14:03 +0000 (14:14 -0700)
Pull watchdog updates from Wim Van Sebroeck:

 - add support for BCM4908

 - renesas_wdt: add R-Car Gen4 support

 - improve watchdog_dev function documentation

 - sp5100_tco: replace the cd6h/cd7h port I/O with MMIO accesses during
   initialization

 - several other small improvements and fixes

* tag 'linux-watchdog-5.18-rc1' of git://www.linux-watchdog.org/linux-watchdog:
  Watchdog: sp5100_tco: Enable Family 17h+ CPUs
  Watchdog: sp5100_tco: Add initialization using EFCH MMIO
  Watchdog: sp5100_tco: Refactor MMIO base address initialization
  Watchdog: sp5100_tco: Move timer initialization into function
  watchdog: ixp4xx: Implement restart
  watchdog: orion_wdt: support pretimeout on Armada-XP
  watchdog: allow building BCM7038_WDT for BCM4908
  watchdog: renesas_wdt: Add R-Car Gen4 support
  dt-bindings: watchdog: renesas-wdt: Document r8a779f0 support
  watchdog: Improve watchdog_dev function documentation
  watchdog: aspeed: add nowayout support
  watchdog: rti-wdt: Add missing pm_runtime_disable() in probe function
  watchdog: imx2_wdg: Alow ping on suspend

Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml
drivers/watchdog/Kconfig
drivers/watchdog/aspeed_wdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/ixp4xx_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/renesas_wdt.c
drivers/watchdog/rti_wdt.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/sp5100_tco.h
drivers/watchdog/watchdog_dev.c

index 91a98cc..d060438 100644 (file)
@@ -55,6 +55,11 @@ properties:
               - renesas,r8a779a0-wdt     # R-Car V3U
           - const: renesas,rcar-gen3-wdt # R-Car Gen3 and RZ/G2
 
+      - items:
+          - enum:
+              - renesas,r8a779f0-wdt     # R-Car S4-8
+          - const: renesas,rcar-gen4-wdt # R-Car Gen4
+
   reg:
     maxItems: 1
 
index 085f5a4..c4e82a8 100644 (file)
@@ -1779,7 +1779,7 @@ config BCM7038_WDT
        tristate "BCM63xx/BCM7038 Watchdog"
        select WATCHDOG_CORE
        depends on HAS_IOMEM
-       depends on ARCH_BRCMSTB || BMIPS_GENERIC || BCM63XX || COMPILE_TEST
+       depends on ARCH_BCM4908 || ARCH_BRCMSTB || BMIPS_GENERIC || BCM63XX || COMPILE_TEST
        help
          Watchdog driver for the built-in hardware in Broadcom 7038 and
          later SoCs used in set-top boxes.  BCM7038 was made public
index 436571b..bd06622 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
 struct aspeed_wdt {
        struct watchdog_device  wdd;
        void __iomem            *base;
@@ -266,6 +271,8 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
        wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;
        watchdog_init_timeout(&wdt->wdd, 0, dev);
 
+       watchdog_set_nowayout(&wdt->wdd, nowayout);
+
        np = dev->of_node;
 
        ofdid = of_match_node(aspeed_wdt_of_table, np);
index 51bfb79..d0c5d47 100644 (file)
@@ -66,6 +66,7 @@ struct imx2_wdt_device {
        struct watchdog_device wdog;
        bool ext_reset;
        bool clk_is_on;
+       bool no_ping;
 };
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -312,12 +313,18 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
 
        wdev->ext_reset = of_property_read_bool(dev->of_node,
                                                "fsl,ext-reset-output");
+       /*
+        * The i.MX7D doesn't support low power mode, so we need to ping the watchdog
+        * during suspend.
+        */
+       wdev->no_ping = !of_device_is_compatible(dev->of_node, "fsl,imx7d-wdt");
        platform_set_drvdata(pdev, wdog);
        watchdog_set_drvdata(wdog, wdev);
        watchdog_set_nowayout(wdog, nowayout);
        watchdog_set_restart_priority(wdog, 128);
        watchdog_init_timeout(wdog, timeout, dev);
-       watchdog_stop_ping_on_suspend(wdog);
+       if (wdev->no_ping)
+               watchdog_stop_ping_on_suspend(wdog);
 
        if (imx2_wdt_is_running(wdev)) {
                imx2_wdt_set_timeout(wdog, wdog->timeout);
@@ -366,9 +373,11 @@ static int __maybe_unused imx2_wdt_suspend(struct device *dev)
                imx2_wdt_ping(wdog);
        }
 
-       clk_disable_unprepare(wdev->clk);
+       if (wdev->no_ping) {
+               clk_disable_unprepare(wdev->clk);
 
-       wdev->clk_is_on = false;
+               wdev->clk_is_on = false;
+       }
 
        return 0;
 }
@@ -380,11 +389,14 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev)
        struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
        int ret;
 
-       ret = clk_prepare_enable(wdev->clk);
-       if (ret)
-               return ret;
+       if (wdev->no_ping) {
+               ret = clk_prepare_enable(wdev->clk);
 
-       wdev->clk_is_on = true;
+               if (ret)
+                       return ret;
+
+               wdev->clk_is_on = true;
+       }
 
        if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) {
                /*
@@ -407,6 +419,7 @@ static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
 
 static const struct of_device_id imx2_wdt_dt_ids[] = {
        { .compatible = "fsl,imx21-wdt", },
+       { .compatible = "fsl,imx7d-wdt", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);
index 31b03fa..281a48d 100644 (file)
@@ -84,10 +84,24 @@ static int ixp4xx_wdt_set_timeout(struct watchdog_device *wdd,
        return 0;
 }
 
+static int ixp4xx_wdt_restart(struct watchdog_device *wdd,
+                              unsigned long action, void *data)
+{
+       struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);
+
+       __raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
+       __raw_writel(0, iwdt->base + IXP4XX_OSWT_OFFSET);
+       __raw_writel(IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE,
+                    iwdt->base + IXP4XX_OSWE_OFFSET);
+
+       return 0;
+}
+
 static const struct watchdog_ops ixp4xx_wdt_ops = {
        .start = ixp4xx_wdt_start,
        .stop = ixp4xx_wdt_stop,
        .set_timeout = ixp4xx_wdt_set_timeout,
+       .restart = ixp4xx_wdt_restart,
        .owner = THIS_MODULE,
 };
 
index 127eefc..e25e6bf 100644 (file)
@@ -238,8 +238,10 @@ static int armada370_start(struct watchdog_device *wdt_dev)
        atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
 
        /* Enable watchdog timer */
-       atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
-                                               dev->data->wdt_enable_bit);
+       reg = dev->data->wdt_enable_bit;
+       if (dev->wdt.info->options & WDIOF_PRETIMEOUT)
+               reg |= TIMER1_ENABLE_BIT;
+       atomic_io_modify(dev->reg + TIMER_CTRL, reg, reg);
 
        /* Enable reset on watchdog */
        reg = readl(dev->rstout);
@@ -312,7 +314,7 @@ static int armada375_stop(struct watchdog_device *wdt_dev)
 static int armada370_stop(struct watchdog_device *wdt_dev)
 {
        struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
-       u32 reg;
+       u32 reg, mask;
 
        /* Disable reset on watchdog */
        reg = readl(dev->rstout);
@@ -320,7 +322,10 @@ static int armada370_stop(struct watchdog_device *wdt_dev)
        writel(reg, dev->rstout);
 
        /* Disable watchdog timer */
-       atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
+       mask = dev->data->wdt_enable_bit;
+       if (wdt_dev->info->options & WDIOF_PRETIMEOUT)
+               mask |= TIMER1_ENABLE_BIT;
+       atomic_io_modify(dev->reg + TIMER_CTRL, mask, 0);
 
        return 0;
 }
index 5791198..41d58ea 100644 (file)
@@ -327,6 +327,7 @@ static SIMPLE_DEV_PM_OPS(rwdt_pm_ops, rwdt_suspend, rwdt_resume);
 static const struct of_device_id rwdt_ids[] = {
        { .compatible = "renesas,rcar-gen2-wdt", },
        { .compatible = "renesas,rcar-gen3-wdt", },
+       { .compatible = "renesas,rcar-gen4-wdt", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, rwdt_ids);
index 117bc2a..db843f8 100644 (file)
@@ -228,6 +228,7 @@ static int rti_wdt_probe(struct platform_device *pdev)
        ret = pm_runtime_get_sync(dev);
        if (ret) {
                pm_runtime_put_noidle(dev);
+               pm_runtime_disable(&pdev->dev);
                return dev_err_probe(dev, ret, "runtime pm failed\n");
        }
 
index dd9a744..86ffb58 100644 (file)
@@ -49,7 +49,7 @@
 /* internal variables */
 
 enum tco_reg_layout {
-       sp5100, sb800, efch
+       sp5100, sb800, efch, efch_mmio
 };
 
 struct sp5100_tco {
@@ -87,6 +87,10 @@ static enum tco_reg_layout tco_reg_layout(struct pci_dev *dev)
            dev->revision < 0x40) {
                return sp5100;
        } else if (dev->vendor == PCI_VENDOR_ID_AMD &&
+           sp5100_tco_pci->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
+           sp5100_tco_pci->revision >= AMD_ZEN_SMBUS_PCI_REV) {
+               return efch_mmio;
+       } else if (dev->vendor == PCI_VENDOR_ID_AMD &&
            ((dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
             dev->revision >= 0x41) ||
            (dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
@@ -209,6 +213,8 @@ static void tco_timer_enable(struct sp5100_tco *tco)
                                          ~EFCH_PM_WATCHDOG_DISABLE,
                                          EFCH_PM_DECODEEN_SECOND_RES);
                break;
+       default:
+               break;
        }
 }
 
@@ -223,14 +229,195 @@ static u32 sp5100_tco_read_pm_reg32(u8 index)
        return val;
 }
 
+static u32 sp5100_tco_request_region(struct device *dev,
+                                    u32 mmio_addr,
+                                    const char *dev_name)
+{
+       if (!devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE,
+                                    dev_name)) {
+               dev_dbg(dev, "MMIO address 0x%08x already in use\n", mmio_addr);
+               return 0;
+       }
+
+       return mmio_addr;
+}
+
+static u32 sp5100_tco_prepare_base(struct sp5100_tco *tco,
+                                  u32 mmio_addr,
+                                  u32 alt_mmio_addr,
+                                  const char *dev_name)
+{
+       struct device *dev = tco->wdd.parent;
+
+       dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n", mmio_addr);
+
+       if (!mmio_addr && !alt_mmio_addr)
+               return -ENODEV;
+
+       /* Check for MMIO address and alternate MMIO address conflicts */
+       if (mmio_addr)
+               mmio_addr = sp5100_tco_request_region(dev, mmio_addr, dev_name);
+
+       if (!mmio_addr && alt_mmio_addr)
+               mmio_addr = sp5100_tco_request_region(dev, alt_mmio_addr, dev_name);
+
+       if (!mmio_addr) {
+               dev_err(dev, "Failed to reserve MMIO or alternate MMIO region\n");
+               return -EBUSY;
+       }
+
+       tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
+       if (!tco->tcobase) {
+               dev_err(dev, "MMIO address 0x%08x failed mapping\n", mmio_addr);
+               devm_release_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
+               return -ENOMEM;
+       }
+
+       dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr);
+
+       return 0;
+}
+
+static int sp5100_tco_timer_init(struct sp5100_tco *tco)
+{
+       struct watchdog_device *wdd = &tco->wdd;
+       struct device *dev = wdd->parent;
+       u32 val;
+
+       val = readl(SP5100_WDT_CONTROL(tco->tcobase));
+       if (val & SP5100_WDT_DISABLED) {
+               dev_err(dev, "Watchdog hardware is disabled\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Save WatchDogFired status, because WatchDogFired flag is
+        * cleared here.
+        */
+       if (val & SP5100_WDT_FIRED)
+               wdd->bootstatus = WDIOF_CARDRESET;
+
+       /* Set watchdog action to reset the system */
+       val &= ~SP5100_WDT_ACTION_RESET;
+       writel(val, SP5100_WDT_CONTROL(tco->tcobase));
+
+       /* Set a reasonable heartbeat before we stop the timer */
+       tco_timer_set_timeout(wdd, wdd->timeout);
+
+       /*
+        * Stop the TCO before we change anything so we don't race with
+        * a zeroed timer.
+        */
+       tco_timer_stop(wdd);
+
+       return 0;
+}
+
+static u8 efch_read_pm_reg8(void __iomem *addr, u8 index)
+{
+       return readb(addr + index);
+}
+
+static void efch_update_pm_reg8(void __iomem *addr, u8 index, u8 reset, u8 set)
+{
+       u8 val;
+
+       val = readb(addr + index);
+       val &= reset;
+       val |= set;
+       writeb(val, addr + index);
+}
+
+static void tco_timer_enable_mmio(void __iomem *addr)
+{
+       efch_update_pm_reg8(addr, EFCH_PM_DECODEEN3,
+                           ~EFCH_PM_WATCHDOG_DISABLE,
+                           EFCH_PM_DECODEEN_SECOND_RES);
+}
+
+static int sp5100_tco_setupdevice_mmio(struct device *dev,
+                                      struct watchdog_device *wdd)
+{
+       struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
+       const char *dev_name = SB800_DEVNAME;
+       u32 mmio_addr = 0, alt_mmio_addr = 0;
+       struct resource *res;
+       void __iomem *addr;
+       int ret;
+       u32 val;
+
+       res = request_mem_region_muxed(EFCH_PM_ACPI_MMIO_PM_ADDR,
+                                      EFCH_PM_ACPI_MMIO_PM_SIZE,
+                                      "sp5100_tco");
+
+       if (!res) {
+               dev_err(dev,
+                       "Memory region 0x%08x already in use\n",
+                       EFCH_PM_ACPI_MMIO_PM_ADDR);
+               return -EBUSY;
+       }
+
+       addr = ioremap(EFCH_PM_ACPI_MMIO_PM_ADDR, EFCH_PM_ACPI_MMIO_PM_SIZE);
+       if (!addr) {
+               dev_err(dev, "Address mapping failed\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * EFCH_PM_DECODEEN_WDT_TMREN is dual purpose. This bitfield
+        * enables sp5100_tco register MMIO space decoding. The bitfield
+        * also starts the timer operation. Enable if not already enabled.
+        */
+       val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
+       if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
+               efch_update_pm_reg8(addr, EFCH_PM_DECODEEN, 0xff,
+                                   EFCH_PM_DECODEEN_WDT_TMREN);
+       }
+
+       /* Error if the timer could not be enabled */
+       val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
+       if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
+               dev_err(dev, "Failed to enable the timer\n");
+               ret = -EFAULT;
+               goto out;
+       }
+
+       mmio_addr = EFCH_PM_WDT_ADDR;
+
+       /* Determine alternate MMIO base address */
+       val = efch_read_pm_reg8(addr, EFCH_PM_ISACONTROL);
+       if (val & EFCH_PM_ISACONTROL_MMIOEN)
+               alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
+                       EFCH_PM_ACPI_MMIO_WDT_OFFSET;
+
+       ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
+       if (!ret) {
+               tco_timer_enable_mmio(addr);
+               ret = sp5100_tco_timer_init(tco);
+       }
+
+out:
+       if (addr)
+               iounmap(addr);
+
+       release_resource(res);
+
+       return ret;
+}
+
 static int sp5100_tco_setupdevice(struct device *dev,
                                  struct watchdog_device *wdd)
 {
        struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
        const char *dev_name;
        u32 mmio_addr = 0, val;
+       u32 alt_mmio_addr = 0;
        int ret;
 
+       if (tco->tco_reg_layout == efch_mmio)
+               return sp5100_tco_setupdevice_mmio(dev, wdd);
+
        /* Request the IO ports used by this driver */
        if (!request_muxed_region(SP5100_IO_PM_INDEX_REG,
                                  SP5100_PM_IOPORTS_SIZE, "sp5100_tco")) {
@@ -247,138 +434,55 @@ static int sp5100_tco_setupdevice(struct device *dev,
                dev_name = SP5100_DEVNAME;
                mmio_addr = sp5100_tco_read_pm_reg32(SP5100_PM_WATCHDOG_BASE) &
                                                                0xfffffff8;
+
+               /*
+                * Secondly, find the watchdog timer MMIO address
+                * from SBResource_MMIO register.
+                */
+
+               /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
+               pci_read_config_dword(sp5100_tco_pci,
+                                     SP5100_SB_RESOURCE_MMIO_BASE,
+                                     &val);
+
+               /* Verify MMIO is enabled and using bar0 */
+               if ((val & SB800_ACPI_MMIO_MASK) == SB800_ACPI_MMIO_DECODE_EN)
+                       alt_mmio_addr = (val & ~0xfff) + SB800_PM_WDT_MMIO_OFFSET;
                break;
        case sb800:
                dev_name = SB800_DEVNAME;
                mmio_addr = sp5100_tco_read_pm_reg32(SB800_PM_WATCHDOG_BASE) &
                                                                0xfffffff8;
+
+               /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
+               val = sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
+
+               /* Verify MMIO is enabled and using bar0 */
+               if ((val & SB800_ACPI_MMIO_MASK) == SB800_ACPI_MMIO_DECODE_EN)
+                       alt_mmio_addr = (val & ~0xfff) + SB800_PM_WDT_MMIO_OFFSET;
                break;
        case efch:
                dev_name = SB800_DEVNAME;
-               /*
-                * On Family 17h devices, the EFCH_PM_DECODEEN_WDT_TMREN bit of
-                * EFCH_PM_DECODEEN not only enables the EFCH_PM_WDT_ADDR memory
-                * region, it also enables the watchdog itself.
-                */
-               if (boot_cpu_data.x86 == 0x17) {
-                       val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
-                       if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
-                               sp5100_tco_update_pm_reg8(EFCH_PM_DECODEEN, 0xff,
-                                                         EFCH_PM_DECODEEN_WDT_TMREN);
-                       }
-               }
                val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
                if (val & EFCH_PM_DECODEEN_WDT_TMREN)
                        mmio_addr = EFCH_PM_WDT_ADDR;
+
+               val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
+               if (val & EFCH_PM_ISACONTROL_MMIOEN)
+                       alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
+                               EFCH_PM_ACPI_MMIO_WDT_OFFSET;
                break;
        default:
                return -ENODEV;
        }
 
-       /* Check MMIO address conflict */
-       if (!mmio_addr ||
-           !devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE,
-                                    dev_name)) {
-               if (mmio_addr)
-                       dev_dbg(dev, "MMIO address 0x%08x already in use\n",
-                               mmio_addr);
-               switch (tco->tco_reg_layout) {
-               case sp5100:
-                       /*
-                        * Secondly, Find the watchdog timer MMIO address
-                        * from SBResource_MMIO register.
-                        */
-                       /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
-                       pci_read_config_dword(sp5100_tco_pci,
-                                             SP5100_SB_RESOURCE_MMIO_BASE,
-                                             &mmio_addr);
-                       if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
-                                         SB800_ACPI_MMIO_SEL)) !=
-                                                 SB800_ACPI_MMIO_DECODE_EN) {
-                               ret = -ENODEV;
-                               goto unreg_region;
-                       }
-                       mmio_addr &= ~0xFFF;
-                       mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
-                       break;
-               case sb800:
-                       /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
-                       mmio_addr =
-                               sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
-                       if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
-                                         SB800_ACPI_MMIO_SEL)) !=
-                                                 SB800_ACPI_MMIO_DECODE_EN) {
-                               ret = -ENODEV;
-                               goto unreg_region;
-                       }
-                       mmio_addr &= ~0xFFF;
-                       mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
-                       break;
-               case efch:
-                       val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
-                       if (!(val & EFCH_PM_ISACONTROL_MMIOEN)) {
-                               ret = -ENODEV;
-                               goto unreg_region;
-                       }
-                       mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
-                                   EFCH_PM_ACPI_MMIO_WDT_OFFSET;
-                       break;
-               }
-               dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n",
-                       mmio_addr);
-               if (!devm_request_mem_region(dev, mmio_addr,
-                                            SP5100_WDT_MEM_MAP_SIZE,
-                                            dev_name)) {
-                       dev_dbg(dev, "MMIO address 0x%08x already in use\n",
-                               mmio_addr);
-                       ret = -EBUSY;
-                       goto unreg_region;
-               }
-       }
-
-       tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
-       if (!tco->tcobase) {
-               dev_err(dev, "failed to get tcobase address\n");
-               ret = -ENOMEM;
-               goto unreg_region;
-       }
-
-       dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr);
-
-       /* Setup the watchdog timer */
-       tco_timer_enable(tco);
-
-       val = readl(SP5100_WDT_CONTROL(tco->tcobase));
-       if (val & SP5100_WDT_DISABLED) {
-               dev_err(dev, "Watchdog hardware is disabled\n");
-               ret = -ENODEV;
-               goto unreg_region;
+       ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
+       if (!ret) {
+               /* Setup the watchdog timer */
+               tco_timer_enable(tco);
+               ret = sp5100_tco_timer_init(tco);
        }
 
-       /*
-        * Save WatchDogFired status, because WatchDogFired flag is
-        * cleared here.
-        */
-       if (val & SP5100_WDT_FIRED)
-               wdd->bootstatus = WDIOF_CARDRESET;
-       /* Set watchdog action to reset the system */
-       val &= ~SP5100_WDT_ACTION_RESET;
-       writel(val, SP5100_WDT_CONTROL(tco->tcobase));
-
-       /* Set a reasonable heartbeat before we stop the timer */
-       tco_timer_set_timeout(wdd, wdd->timeout);
-
-       /*
-        * Stop the TCO before we change anything so we don't race with
-        * a zeroed timer.
-        */
-       tco_timer_stop(wdd);
-
-       release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
-
-       return 0;
-
-unreg_region:
        release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
        return ret;
 }
index adf015a..6a0986d 100644 (file)
@@ -58,6 +58,7 @@
 #define SB800_PM_WATCHDOG_SECOND_RES   GENMASK(1, 0)
 #define SB800_ACPI_MMIO_DECODE_EN      BIT(0)
 #define SB800_ACPI_MMIO_SEL            BIT(1)
+#define SB800_ACPI_MMIO_MASK           GENMASK(1, 0)
 
 #define SB800_PM_WDT_MMIO_OFFSET       0xB00
 
 #define EFCH_PM_ISACONTROL_MMIOEN      BIT(1)
 
 #define EFCH_PM_ACPI_MMIO_ADDR         0xfed80000
+#define EFCH_PM_ACPI_MMIO_PM_OFFSET    0x00000300
 #define EFCH_PM_ACPI_MMIO_WDT_OFFSET   0x00000b00
+
+#define EFCH_PM_ACPI_MMIO_PM_ADDR      (EFCH_PM_ACPI_MMIO_ADDR +       \
+                                        EFCH_PM_ACPI_MMIO_PM_OFFSET)
+#define EFCH_PM_ACPI_MMIO_PM_SIZE      8
+#define AMD_ZEN_SMBUS_PCI_REV          0x51
index 3a3d8b5..54903f3 100644 (file)
@@ -171,17 +171,17 @@ static int __watchdog_ping(struct watchdog_device *wdd)
 }
 
 /*
- *     watchdog_ping: ping the watchdog.
- *     @wdd: the watchdog device to ping
+ * watchdog_ping - ping the watchdog
+ * @wdd: The watchdog device to ping
  *
- *     The caller must hold wd_data->lock.
+ * If the watchdog has no own ping operation then it needs to be
+ * restarted via the start operation. This wrapper function does
+ * exactly that.
+ * We only ping when the watchdog device is running.
+ * The caller must hold wd_data->lock.
  *
- *     If the watchdog has no own ping operation then it needs to be
- *     restarted via the start operation. This wrapper function does
- *     exactly that.
- *     We only ping when the watchdog device is running.
+ * Return: 0 on success, error otherwise.
  */
-
 static int watchdog_ping(struct watchdog_device *wdd)
 {
        struct watchdog_core_data *wd_data = wdd->wd_data;
@@ -231,16 +231,14 @@ static enum hrtimer_restart watchdog_timer_expired(struct hrtimer *timer)
 }
 
 /*
- *     watchdog_start: wrapper to start the watchdog.
- *     @wdd: the watchdog device to start
+ * watchdog_start - wrapper to start the watchdog
+ * @wdd: The watchdog device to start
  *
- *     The caller must hold wd_data->lock.
+ * Start the watchdog if it is not active and mark it active.
+ * The caller must hold wd_data->lock.
  *
- *     Start the watchdog if it is not active and mark it active.
- *     This function returns zero on success or a negative errno code for
- *     failure.
+ * Return: 0 on success or a negative errno code for failure.
  */
-
 static int watchdog_start(struct watchdog_device *wdd)
 {
        struct watchdog_core_data *wd_data = wdd->wd_data;
@@ -274,17 +272,15 @@ static int watchdog_start(struct watchdog_device *wdd)
 }
 
 /*
- *     watchdog_stop: wrapper to stop the watchdog.
- *     @wdd: the watchdog device to stop
+ * watchdog_stop - wrapper to stop the watchdog
+ * @wdd: The watchdog device to stop
  *
- *     The caller must hold wd_data->lock.
+ * Stop the watchdog if it is still active and unmark it active.
+ * If the 'nowayout' feature was set, the watchdog cannot be stopped.
+ * The caller must hold wd_data->lock.
  *
- *     Stop the watchdog if it is still active and unmark it active.
- *     This function returns zero on success or a negative errno code for
- *     failure.
- *     If the 'nowayout' feature was set, the watchdog cannot be stopped.
+ * Return: 0 on success or a negative errno code for failure.
  */
-
 static int watchdog_stop(struct watchdog_device *wdd)
 {
        int err = 0;
@@ -315,14 +311,14 @@ static int watchdog_stop(struct watchdog_device *wdd)
 }
 
 /*
- *     watchdog_get_status: wrapper to get the watchdog status
- *     @wdd: the watchdog device to get the status from
+ * watchdog_get_status - wrapper to get the watchdog status
+ * @wdd: The watchdog device to get the status from
  *
- *     The caller must hold wd_data->lock.
+ * Get the watchdog's status flags.
+ * The caller must hold wd_data->lock.
  *
- *     Get the watchdog's status flags.
+ * Return: watchdog's status flags.
  */
-
 static unsigned int watchdog_get_status(struct watchdog_device *wdd)
 {
        struct watchdog_core_data *wd_data = wdd->wd_data;
@@ -352,13 +348,14 @@ static unsigned int watchdog_get_status(struct watchdog_device *wdd)
 }
 
 /*
- *     watchdog_set_timeout: set the watchdog timer timeout
- *     @wdd: the watchdog device to set the timeout for
- *     @timeout: timeout to set in seconds
+ * watchdog_set_timeout - set the watchdog timer timeout
+ * @wdd:       The watchdog device to set the timeout for
+ * @timeout:   Timeout to set in seconds
+ *
+ * The caller must hold wd_data->lock.
  *
- *     The caller must hold wd_data->lock.
+ * Return: 0 if successful, error otherwise.
  */
-
 static int watchdog_set_timeout(struct watchdog_device *wdd,
                                                        unsigned int timeout)
 {
@@ -385,11 +382,12 @@ static int watchdog_set_timeout(struct watchdog_device *wdd,
 }
 
 /*
- *     watchdog_set_pretimeout: set the watchdog timer pretimeout
- *     @wdd: the watchdog device to set the timeout for
- *     @timeout: pretimeout to set in seconds
+ * watchdog_set_pretimeout - set the watchdog timer pretimeout
+ * @wdd:       The watchdog device to set the timeout for
+ * @timeout:   pretimeout to set in seconds
+ *
+ * Return: 0 if successful, error otherwise.
  */
-
 static int watchdog_set_pretimeout(struct watchdog_device *wdd,
                                   unsigned int timeout)
 {
@@ -410,15 +408,15 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd,
 }
 
 /*
- *     watchdog_get_timeleft: wrapper to get the time left before a reboot
- *     @wdd: the watchdog device to get the remaining time from
- *     @timeleft: the time that's left
+ * watchdog_get_timeleft - wrapper to get the time left before a reboot
+ * @wdd:       The watchdog device to get the remaining time from
+ * @timeleft:  The time that's left
  *
- *     The caller must hold wd_data->lock.
+ * Get the time before a watchdog will reboot (if not pinged).
+ * The caller must hold wd_data->lock.
  *
- *     Get the time before a watchdog will reboot (if not pinged).
+ * Return: 0 if successful, error otherwise.
  */
-
 static int watchdog_get_timeleft(struct watchdog_device *wdd,
                                                        unsigned int *timeleft)
 {
@@ -635,14 +633,15 @@ __ATTRIBUTE_GROUPS(wdt);
 #endif
 
 /*
- *     watchdog_ioctl_op: call the watchdog drivers ioctl op if defined
- *     @wdd: the watchdog device to do the ioctl on
- *     @cmd: watchdog command
- *     @arg: argument pointer
+ * watchdog_ioctl_op - call the watchdog drivers ioctl op if defined
+ * @wdd: The watchdog device to do the ioctl on
+ * @cmd: Watchdog command
+ * @arg: Argument pointer
  *
- *     The caller must hold wd_data->lock.
+ * The caller must hold wd_data->lock.
+ *
+ * Return: 0 if successful, error otherwise.
  */
-
 static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd,
                                                        unsigned long arg)
 {
@@ -653,17 +652,18 @@ static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd,
 }
 
 /*
- *     watchdog_write: writes to the watchdog.
- *     @file: file from VFS
- *     @data: user address of data
- *     @len: length of data
- *     @ppos: pointer to the file offset
+ * watchdog_write - writes to the watchdog
+ * @file:      File from VFS
+ * @data:      User address of data
+ * @len:       Length of data
+ * @ppos:      Pointer to the file offset
  *
- *     A write to a watchdog device is defined as a keepalive ping.
- *     Writing the magic 'V' sequence allows the next close to turn
- *     off the watchdog (if 'nowayout' is not set).
+ * A write to a watchdog device is defined as a keepalive ping.
+ * Writing the magic 'V' sequence allows the next close to turn
+ * off the watchdog (if 'nowayout' is not set).
+ *
+ * Return: @len if successful, error otherwise.
  */
-
 static ssize_t watchdog_write(struct file *file, const char __user *data,
                                                size_t len, loff_t *ppos)
 {
@@ -706,13 +706,15 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
 }
 
 /*
- *     watchdog_ioctl: handle the different ioctl's for the watchdog device.
- *     @file: file handle to the device
- *     @cmd: watchdog command
- *     @arg: argument pointer
+ * watchdog_ioctl - handle the different ioctl's for the watchdog device
+ * @file:      File handle to the device
+ * @cmd:       Watchdog command
+ * @arg:       Argument pointer
  *
- *     The watchdog API defines a common set of functions for all watchdogs
- *     according to their available features.
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features.
+ *
+ * Return: 0 if successful, error otherwise.
  */
 
 static long watchdog_ioctl(struct file *file, unsigned int cmd,
@@ -819,15 +821,16 @@ out_ioctl:
 }
 
 /*
- *     watchdog_open: open the /dev/watchdog* devices.
- *     @inode: inode of device
- *     @file: file handle to device
+ * watchdog_open - open the /dev/watchdog* devices
+ * @inode:     Inode of device
+ * @file:      File handle to device
+ *
+ * When the /dev/watchdog* device gets opened, we start the watchdog.
+ * Watch out: the /dev/watchdog device is single open, so we make sure
+ * it can only be opened once.
  *
- *     When the /dev/watchdog* device gets opened, we start the watchdog.
- *     Watch out: the /dev/watchdog device is single open, so we make sure
- *     it can only be opened once.
+ * Return: 0 if successful, error otherwise.
  */
-
 static int watchdog_open(struct inode *inode, struct file *file)
 {
        struct watchdog_core_data *wd_data;
@@ -896,15 +899,16 @@ static void watchdog_core_data_release(struct device *dev)
 }
 
 /*
- *     watchdog_release: release the watchdog device.
- *     @inode: inode of device
- *     @file: file handle to device
+ * watchdog_release - release the watchdog device
+ * @inode:     Inode of device
+ * @file:      File handle to device
+ *
+ * This is the code for when /dev/watchdog gets closed. We will only
+ * stop the watchdog when we have received the magic char (and nowayout
+ * was not set), else the watchdog will keep running.
  *
- *     This is the code for when /dev/watchdog gets closed. We will only
- *     stop the watchdog when we have received the magic char (and nowayout
- *     was not set), else the watchdog will keep running.
+ * Always returns 0.
  */
-
 static int watchdog_release(struct inode *inode, struct file *file)
 {
        struct watchdog_core_data *wd_data = file->private_data;
@@ -977,14 +981,15 @@ static struct class watchdog_class = {
 };
 
 /*
- *     watchdog_cdev_register: register watchdog character device
- *     @wdd: watchdog device
+ * watchdog_cdev_register - register watchdog character device
+ * @wdd: Watchdog device
+ *
+ * Register a watchdog character device including handling the legacy
+ * /dev/watchdog node. /dev/watchdog is actually a miscdevice and
+ * thus we set it up like that.
  *
- *     Register a watchdog character device including handling the legacy
- *     /dev/watchdog node. /dev/watchdog is actually a miscdevice and
- *     thus we set it up like that.
+ * Return: 0 if successful, error otherwise.
  */
-
 static int watchdog_cdev_register(struct watchdog_device *wdd)
 {
        struct watchdog_core_data *wd_data;
@@ -1074,13 +1079,12 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
 }
 
 /*
- *     watchdog_cdev_unregister: unregister watchdog character device
- *     @watchdog: watchdog device
+ * watchdog_cdev_unregister - unregister watchdog character device
+ * @wdd: Watchdog device
  *
- *     Unregister watchdog character device and if needed the legacy
- *     /dev/watchdog device.
+ * Unregister watchdog character device and if needed the legacy
+ * /dev/watchdog device.
  */
-
 static void watchdog_cdev_unregister(struct watchdog_device *wdd)
 {
        struct watchdog_core_data *wd_data = wdd->wd_data;
@@ -1109,15 +1113,16 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
        put_device(&wd_data->dev);
 }
 
-/*
- *     watchdog_dev_register: register a watchdog device
- *     @wdd: watchdog device
+/**
+ * watchdog_dev_register - register a watchdog device
+ * @wdd: Watchdog device
+ *
+ * Register a watchdog device including handling the legacy
+ * /dev/watchdog node. /dev/watchdog is actually a miscdevice and
+ * thus we set it up like that.
  *
- *     Register a watchdog device including handling the legacy
- *     /dev/watchdog node. /dev/watchdog is actually a miscdevice and
- *     thus we set it up like that.
+ * Return: 0 if successful, error otherwise.
  */
-
 int watchdog_dev_register(struct watchdog_device *wdd)
 {
        int ret;
@@ -1133,30 +1138,31 @@ int watchdog_dev_register(struct watchdog_device *wdd)
        return ret;
 }
 
-/*
- *     watchdog_dev_unregister: unregister a watchdog device
- *     @watchdog: watchdog device
+/**
+ * watchdog_dev_unregister - unregister a watchdog device
+ * @wdd: watchdog device
  *
- *     Unregister watchdog device and if needed the legacy
- *     /dev/watchdog device.
+ * Unregister watchdog device and if needed the legacy
+ * /dev/watchdog device.
  */
-
 void watchdog_dev_unregister(struct watchdog_device *wdd)
 {
        watchdog_unregister_pretimeout(wdd);
        watchdog_cdev_unregister(wdd);
 }
 
-/*
- *     watchdog_set_last_hw_keepalive: set last HW keepalive time for watchdog
- *     @wdd: watchdog device
- *     @last_ping_ms: time since last HW heartbeat
+/**
+ * watchdog_set_last_hw_keepalive - set last HW keepalive time for watchdog
+ * @wdd:               Watchdog device
+ * @last_ping_ms:      Time since last HW heartbeat
  *
- *     Adjusts the last known HW keepalive time for a watchdog timer.
- *     This is needed if the watchdog is already running when the probe
- *     function is called, and it can't be pinged immediately. This
- *     function must be called immediately after watchdog registration,
- *     and min_hw_heartbeat_ms must be set for this to be useful.
+ * Adjusts the last known HW keepalive time for a watchdog timer.
+ * This is needed if the watchdog is already running when the probe
+ * function is called, and it can't be pinged immediately. This
+ * function must be called immediately after watchdog registration,
+ * and min_hw_heartbeat_ms must be set for this to be useful.
+ *
+ * Return: 0 if successful, error otherwise.
  */
 int watchdog_set_last_hw_keepalive(struct watchdog_device *wdd,
                                   unsigned int last_ping_ms)
@@ -1180,12 +1186,13 @@ int watchdog_set_last_hw_keepalive(struct watchdog_device *wdd,
 }
 EXPORT_SYMBOL_GPL(watchdog_set_last_hw_keepalive);
 
-/*
- *     watchdog_dev_init: init dev part of watchdog core
+/**
+ * watchdog_dev_init - init dev part of watchdog core
  *
- *     Allocate a range of chardev nodes to use for watchdog devices
+ * Allocate a range of chardev nodes to use for watchdog devices.
+ *
+ * Return: 0 if successful, error otherwise.
  */
-
 int __init watchdog_dev_init(void)
 {
        int err;
@@ -1218,12 +1225,11 @@ err_register:
        return err;
 }
 
-/*
- *     watchdog_dev_exit: exit dev part of watchdog core
+/**
+ * watchdog_dev_exit - exit dev part of watchdog core
  *
- *     Release the range of chardev nodes used for watchdog devices
+ * Release the range of chardev nodes used for watchdog devices.
  */
-
 void __exit watchdog_dev_exit(void)
 {
        unregister_chrdev_region(watchdog_devt, MAX_DOGS);