Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2016 IBM Corporation
0004  *
0005  * Joel Stanley <joel@jms.id.au>
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/watchdog.h>
0015 
0016 static bool nowayout = WATCHDOG_NOWAYOUT;
0017 module_param(nowayout, bool, 0);
0018 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
0019                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0020 
0021 struct aspeed_wdt {
0022     struct watchdog_device  wdd;
0023     void __iomem        *base;
0024     u32         ctrl;
0025 };
0026 
0027 struct aspeed_wdt_config {
0028     u32 ext_pulse_width_mask;
0029 };
0030 
0031 static const struct aspeed_wdt_config ast2400_config = {
0032     .ext_pulse_width_mask = 0xff,
0033 };
0034 
0035 static const struct aspeed_wdt_config ast2500_config = {
0036     .ext_pulse_width_mask = 0xfffff,
0037 };
0038 
0039 static const struct of_device_id aspeed_wdt_of_table[] = {
0040     { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config },
0041     { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config },
0042     { .compatible = "aspeed,ast2600-wdt", .data = &ast2500_config },
0043     { },
0044 };
0045 MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);
0046 
0047 #define WDT_STATUS      0x00
0048 #define WDT_RELOAD_VALUE    0x04
0049 #define WDT_RESTART     0x08
0050 #define WDT_CTRL        0x0C
0051 #define   WDT_CTRL_BOOT_SECONDARY   BIT(7)
0052 #define   WDT_CTRL_RESET_MODE_SOC   (0x00 << 5)
0053 #define   WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5)
0054 #define   WDT_CTRL_RESET_MODE_ARM_CPU   (0x10 << 5)
0055 #define   WDT_CTRL_1MHZ_CLK     BIT(4)
0056 #define   WDT_CTRL_WDT_EXT      BIT(3)
0057 #define   WDT_CTRL_WDT_INTR     BIT(2)
0058 #define   WDT_CTRL_RESET_SYSTEM     BIT(1)
0059 #define   WDT_CTRL_ENABLE       BIT(0)
0060 #define WDT_TIMEOUT_STATUS  0x10
0061 #define   WDT_TIMEOUT_STATUS_BOOT_SECONDARY BIT(1)
0062 #define WDT_CLEAR_TIMEOUT_STATUS    0x14
0063 #define   WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0)
0064 
0065 /*
0066  * WDT_RESET_WIDTH controls the characteristics of the external pulse (if
0067  * enabled), specifically:
0068  *
0069  * * Pulse duration
0070  * * Drive mode: push-pull vs open-drain
0071  * * Polarity: Active high or active low
0072  *
0073  * Pulse duration configuration is available on both the AST2400 and AST2500,
0074  * though the field changes between SoCs:
0075  *
0076  * AST2400: Bits 7:0
0077  * AST2500: Bits 19:0
0078  *
0079  * This difference is captured in struct aspeed_wdt_config.
0080  *
0081  * The AST2500 exposes the drive mode and polarity options, but not in a
0082  * regular fashion. For read purposes, bit 31 represents active high or low,
0083  * and bit 30 represents push-pull or open-drain. With respect to write, magic
0084  * values need to be written to the top byte to change the state of the drive
0085  * mode and polarity bits. Any other value written to the top byte has no
0086  * effect on the state of the drive mode or polarity bits. However, the pulse
0087  * width value must be preserved (as desired) if written.
0088  */
0089 #define WDT_RESET_WIDTH     0x18
0090 #define   WDT_RESET_WIDTH_ACTIVE_HIGH   BIT(31)
0091 #define     WDT_ACTIVE_HIGH_MAGIC   (0xA5 << 24)
0092 #define     WDT_ACTIVE_LOW_MAGIC    (0x5A << 24)
0093 #define   WDT_RESET_WIDTH_PUSH_PULL BIT(30)
0094 #define     WDT_PUSH_PULL_MAGIC     (0xA8 << 24)
0095 #define     WDT_OPEN_DRAIN_MAGIC    (0x8A << 24)
0096 
0097 #define WDT_RESTART_MAGIC   0x4755
0098 
0099 /* 32 bits at 1MHz, in milliseconds */
0100 #define WDT_MAX_TIMEOUT_MS  4294967
0101 #define WDT_DEFAULT_TIMEOUT 30
0102 #define WDT_RATE_1MHZ       1000000
0103 
0104 static struct aspeed_wdt *to_aspeed_wdt(struct watchdog_device *wdd)
0105 {
0106     return container_of(wdd, struct aspeed_wdt, wdd);
0107 }
0108 
0109 static void aspeed_wdt_enable(struct aspeed_wdt *wdt, int count)
0110 {
0111     wdt->ctrl |= WDT_CTRL_ENABLE;
0112 
0113     writel(0, wdt->base + WDT_CTRL);
0114     writel(count, wdt->base + WDT_RELOAD_VALUE);
0115     writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
0116     writel(wdt->ctrl, wdt->base + WDT_CTRL);
0117 }
0118 
0119 static int aspeed_wdt_start(struct watchdog_device *wdd)
0120 {
0121     struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
0122 
0123     aspeed_wdt_enable(wdt, wdd->timeout * WDT_RATE_1MHZ);
0124 
0125     return 0;
0126 }
0127 
0128 static int aspeed_wdt_stop(struct watchdog_device *wdd)
0129 {
0130     struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
0131 
0132     wdt->ctrl &= ~WDT_CTRL_ENABLE;
0133     writel(wdt->ctrl, wdt->base + WDT_CTRL);
0134 
0135     return 0;
0136 }
0137 
0138 static int aspeed_wdt_ping(struct watchdog_device *wdd)
0139 {
0140     struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
0141 
0142     writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
0143 
0144     return 0;
0145 }
0146 
0147 static int aspeed_wdt_set_timeout(struct watchdog_device *wdd,
0148                   unsigned int timeout)
0149 {
0150     struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
0151     u32 actual;
0152 
0153     wdd->timeout = timeout;
0154 
0155     actual = min(timeout, wdd->max_hw_heartbeat_ms / 1000);
0156 
0157     writel(actual * WDT_RATE_1MHZ, wdt->base + WDT_RELOAD_VALUE);
0158     writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
0159 
0160     return 0;
0161 }
0162 
0163 static int aspeed_wdt_restart(struct watchdog_device *wdd,
0164                   unsigned long action, void *data)
0165 {
0166     struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
0167 
0168     wdt->ctrl &= ~WDT_CTRL_BOOT_SECONDARY;
0169     aspeed_wdt_enable(wdt, 128 * WDT_RATE_1MHZ / 1000);
0170 
0171     mdelay(1000);
0172 
0173     return 0;
0174 }
0175 
0176 /* access_cs0 shows if cs0 is accessible, hence the reverted bit */
0177 static ssize_t access_cs0_show(struct device *dev,
0178                    struct device_attribute *attr, char *buf)
0179 {
0180     struct aspeed_wdt *wdt = dev_get_drvdata(dev);
0181     u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS);
0182 
0183     return sysfs_emit(buf, "%u\n",
0184               !(status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY));
0185 }
0186 
0187 static ssize_t access_cs0_store(struct device *dev,
0188                 struct device_attribute *attr, const char *buf,
0189                 size_t size)
0190 {
0191     struct aspeed_wdt *wdt = dev_get_drvdata(dev);
0192     unsigned long val;
0193 
0194     if (kstrtoul(buf, 10, &val))
0195         return -EINVAL;
0196 
0197     if (val)
0198         writel(WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION,
0199                wdt->base + WDT_CLEAR_TIMEOUT_STATUS);
0200 
0201     return size;
0202 }
0203 
0204 /*
0205  * This attribute exists only if the system has booted from the alternate
0206  * flash with 'alt-boot' option.
0207  *
0208  * At alternate flash the 'access_cs0' sysfs node provides:
0209  *   ast2400: a way to get access to the primary SPI flash chip at CS0
0210  *            after booting from the alternate chip at CS1.
0211  *   ast2500: a way to restore the normal address mapping from
0212  *            (CS0->CS1, CS1->CS0) to (CS0->CS0, CS1->CS1).
0213  *
0214  * Clearing the boot code selection and timeout counter also resets to the
0215  * initial state the chip select line mapping. When the SoC is in normal
0216  * mapping state (i.e. booted from CS0), clearing those bits does nothing for
0217  * both versions of the SoC. For alternate boot mode (booted from CS1 due to
0218  * wdt2 expiration) the behavior differs as described above.
0219  *
0220  * This option can be used with wdt2 (watchdog1) only.
0221  */
0222 static DEVICE_ATTR_RW(access_cs0);
0223 
0224 static struct attribute *bswitch_attrs[] = {
0225     &dev_attr_access_cs0.attr,
0226     NULL
0227 };
0228 ATTRIBUTE_GROUPS(bswitch);
0229 
0230 static const struct watchdog_ops aspeed_wdt_ops = {
0231     .start      = aspeed_wdt_start,
0232     .stop       = aspeed_wdt_stop,
0233     .ping       = aspeed_wdt_ping,
0234     .set_timeout    = aspeed_wdt_set_timeout,
0235     .restart    = aspeed_wdt_restart,
0236     .owner      = THIS_MODULE,
0237 };
0238 
0239 static const struct watchdog_info aspeed_wdt_info = {
0240     .options    = WDIOF_KEEPALIVEPING
0241             | WDIOF_MAGICCLOSE
0242             | WDIOF_SETTIMEOUT,
0243     .identity   = KBUILD_MODNAME,
0244 };
0245 
0246 static int aspeed_wdt_probe(struct platform_device *pdev)
0247 {
0248     struct device *dev = &pdev->dev;
0249     const struct aspeed_wdt_config *config;
0250     const struct of_device_id *ofdid;
0251     struct aspeed_wdt *wdt;
0252     struct device_node *np;
0253     const char *reset_type;
0254     u32 duration;
0255     u32 status;
0256     int ret;
0257 
0258     wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
0259     if (!wdt)
0260         return -ENOMEM;
0261 
0262     wdt->base = devm_platform_ioremap_resource(pdev, 0);
0263     if (IS_ERR(wdt->base))
0264         return PTR_ERR(wdt->base);
0265 
0266     wdt->wdd.info = &aspeed_wdt_info;
0267     wdt->wdd.ops = &aspeed_wdt_ops;
0268     wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS;
0269     wdt->wdd.parent = dev;
0270 
0271     wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;
0272     watchdog_init_timeout(&wdt->wdd, 0, dev);
0273 
0274     watchdog_set_nowayout(&wdt->wdd, nowayout);
0275 
0276     np = dev->of_node;
0277 
0278     ofdid = of_match_node(aspeed_wdt_of_table, np);
0279     if (!ofdid)
0280         return -EINVAL;
0281     config = ofdid->data;
0282 
0283     /*
0284      * On clock rates:
0285      *  - ast2400 wdt can run at PCLK, or 1MHz
0286      *  - ast2500 only runs at 1MHz, hard coding bit 4 to 1
0287      *  - ast2600 always runs at 1MHz
0288      *
0289      * Set the ast2400 to run at 1MHz as it simplifies the driver.
0290      */
0291     if (of_device_is_compatible(np, "aspeed,ast2400-wdt"))
0292         wdt->ctrl = WDT_CTRL_1MHZ_CLK;
0293 
0294     /*
0295      * Control reset on a per-device basis to ensure the
0296      * host is not affected by a BMC reboot
0297      */
0298     ret = of_property_read_string(np, "aspeed,reset-type", &reset_type);
0299     if (ret) {
0300         wdt->ctrl |= WDT_CTRL_RESET_MODE_SOC | WDT_CTRL_RESET_SYSTEM;
0301     } else {
0302         if (!strcmp(reset_type, "cpu"))
0303             wdt->ctrl |= WDT_CTRL_RESET_MODE_ARM_CPU |
0304                      WDT_CTRL_RESET_SYSTEM;
0305         else if (!strcmp(reset_type, "soc"))
0306             wdt->ctrl |= WDT_CTRL_RESET_MODE_SOC |
0307                      WDT_CTRL_RESET_SYSTEM;
0308         else if (!strcmp(reset_type, "system"))
0309             wdt->ctrl |= WDT_CTRL_RESET_MODE_FULL_CHIP |
0310                      WDT_CTRL_RESET_SYSTEM;
0311         else if (strcmp(reset_type, "none"))
0312             return -EINVAL;
0313     }
0314     if (of_property_read_bool(np, "aspeed,external-signal"))
0315         wdt->ctrl |= WDT_CTRL_WDT_EXT;
0316     if (of_property_read_bool(np, "aspeed,alt-boot"))
0317         wdt->ctrl |= WDT_CTRL_BOOT_SECONDARY;
0318 
0319     if (readl(wdt->base + WDT_CTRL) & WDT_CTRL_ENABLE)  {
0320         /*
0321          * The watchdog is running, but invoke aspeed_wdt_start() to
0322          * write wdt->ctrl to WDT_CTRL to ensure the watchdog's
0323          * configuration conforms to the driver's expectations.
0324          * Primarily, ensure we're using the 1MHz clock source.
0325          */
0326         aspeed_wdt_start(&wdt->wdd);
0327         set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
0328     }
0329 
0330     if ((of_device_is_compatible(np, "aspeed,ast2500-wdt")) ||
0331         (of_device_is_compatible(np, "aspeed,ast2600-wdt"))) {
0332         u32 reg = readl(wdt->base + WDT_RESET_WIDTH);
0333 
0334         reg &= config->ext_pulse_width_mask;
0335         if (of_property_read_bool(np, "aspeed,ext-push-pull"))
0336             reg |= WDT_PUSH_PULL_MAGIC;
0337         else
0338             reg |= WDT_OPEN_DRAIN_MAGIC;
0339 
0340         writel(reg, wdt->base + WDT_RESET_WIDTH);
0341 
0342         reg &= config->ext_pulse_width_mask;
0343         if (of_property_read_bool(np, "aspeed,ext-active-high"))
0344             reg |= WDT_ACTIVE_HIGH_MAGIC;
0345         else
0346             reg |= WDT_ACTIVE_LOW_MAGIC;
0347 
0348         writel(reg, wdt->base + WDT_RESET_WIDTH);
0349     }
0350 
0351     if (!of_property_read_u32(np, "aspeed,ext-pulse-duration", &duration)) {
0352         u32 max_duration = config->ext_pulse_width_mask + 1;
0353 
0354         if (duration == 0 || duration > max_duration) {
0355             dev_err(dev, "Invalid pulse duration: %uus\n",
0356                 duration);
0357             duration = max(1U, min(max_duration, duration));
0358             dev_info(dev, "Pulse duration set to %uus\n",
0359                  duration);
0360         }
0361 
0362         /*
0363          * The watchdog is always configured with a 1MHz source, so
0364          * there is no need to scale the microsecond value. However we
0365          * need to offset it - from the datasheet:
0366          *
0367          * "This register decides the asserting duration of wdt_ext and
0368          * wdt_rstarm signal. The default value is 0xFF. It means the
0369          * default asserting duration of wdt_ext and wdt_rstarm is
0370          * 256us."
0371          *
0372          * This implies a value of 0 gives a 1us pulse.
0373          */
0374         writel(duration - 1, wdt->base + WDT_RESET_WIDTH);
0375     }
0376 
0377     status = readl(wdt->base + WDT_TIMEOUT_STATUS);
0378     if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) {
0379         wdt->wdd.bootstatus = WDIOF_CARDRESET;
0380 
0381         if (of_device_is_compatible(np, "aspeed,ast2400-wdt") ||
0382             of_device_is_compatible(np, "aspeed,ast2500-wdt"))
0383             wdt->wdd.groups = bswitch_groups;
0384     }
0385 
0386     dev_set_drvdata(dev, wdt);
0387 
0388     return devm_watchdog_register_device(dev, &wdt->wdd);
0389 }
0390 
0391 static struct platform_driver aspeed_watchdog_driver = {
0392     .probe = aspeed_wdt_probe,
0393     .driver = {
0394         .name = KBUILD_MODNAME,
0395         .of_match_table = of_match_ptr(aspeed_wdt_of_table),
0396     },
0397 };
0398 
0399 static int __init aspeed_wdt_init(void)
0400 {
0401     return platform_driver_register(&aspeed_watchdog_driver);
0402 }
0403 arch_initcall(aspeed_wdt_init);
0404 
0405 static void __exit aspeed_wdt_exit(void)
0406 {
0407     platform_driver_unregister(&aspeed_watchdog_driver);
0408 }
0409 module_exit(aspeed_wdt_exit);
0410 
0411 MODULE_DESCRIPTION("Aspeed Watchdog Driver");
0412 MODULE_LICENSE("GPL");