Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  *  Copyright (C) 2010 John Crispin <john@phrozen.org>
0005  *  Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
0006  *  Based on EP93xx wdt driver
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/bitops.h>
0011 #include <linux/watchdog.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/uaccess.h>
0014 #include <linux/clk.h>
0015 #include <linux/io.h>
0016 #include <linux/regmap.h>
0017 #include <linux/mfd/syscon.h>
0018 
0019 #include <lantiq_soc.h>
0020 
0021 #define LTQ_XRX_RCU_RST_STAT        0x0014
0022 #define LTQ_XRX_RCU_RST_STAT_WDT    BIT(31)
0023 
0024 /* CPU0 Reset Source Register */
0025 #define LTQ_FALCON_SYS1_CPU0RS      0x0060
0026 /* reset cause mask */
0027 #define LTQ_FALCON_SYS1_CPU0RS_MASK 0x0007
0028 #define LTQ_FALCON_SYS1_CPU0RS_WDT  0x02
0029 
0030 /*
0031  * Section 3.4 of the datasheet
0032  * The password sequence protects the WDT control register from unintended
0033  * write actions, which might cause malfunction of the WDT.
0034  *
0035  * essentially the following two magic passwords need to be written to allow
0036  * IO access to the WDT core
0037  */
0038 #define LTQ_WDT_CR_PW1      0x00BE0000
0039 #define LTQ_WDT_CR_PW2      0x00DC0000
0040 
0041 #define LTQ_WDT_CR      0x0     /* watchdog control register */
0042 #define  LTQ_WDT_CR_GEN     BIT(31)     /* enable bit */
0043 /* Pre-warning limit set to 1/16 of max WDT period */
0044 #define  LTQ_WDT_CR_PWL     (0x3 << 26)
0045 /* set clock divider to 0x40000 */
0046 #define  LTQ_WDT_CR_CLKDIV  (0x3 << 24)
0047 #define  LTQ_WDT_CR_PW_MASK GENMASK(23, 16) /* Password field */
0048 #define  LTQ_WDT_CR_MAX_TIMEOUT ((1 << 16) - 1) /* The reload field is 16 bit */
0049 #define LTQ_WDT_SR      0x8     /* watchdog status register */
0050 #define  LTQ_WDT_SR_EN      BIT(31)     /* Enable */
0051 #define  LTQ_WDT_SR_VALUE_MASK  GENMASK(15, 0)  /* Timer value */
0052 
0053 #define LTQ_WDT_DIVIDER     0x40000
0054 
0055 static bool nowayout = WATCHDOG_NOWAYOUT;
0056 
0057 struct ltq_wdt_hw {
0058     int (*bootstatus_get)(struct device *dev);
0059 };
0060 
0061 struct ltq_wdt_priv {
0062     struct watchdog_device wdt;
0063     void __iomem *membase;
0064     unsigned long clk_rate;
0065 };
0066 
0067 static u32 ltq_wdt_r32(struct ltq_wdt_priv *priv, u32 offset)
0068 {
0069     return __raw_readl(priv->membase + offset);
0070 }
0071 
0072 static void ltq_wdt_w32(struct ltq_wdt_priv *priv, u32 val, u32 offset)
0073 {
0074     __raw_writel(val, priv->membase + offset);
0075 }
0076 
0077 static void ltq_wdt_mask(struct ltq_wdt_priv *priv, u32 clear, u32 set,
0078              u32 offset)
0079 {
0080     u32 val = ltq_wdt_r32(priv, offset);
0081 
0082     val &= ~(clear);
0083     val |= set;
0084     ltq_wdt_w32(priv, val, offset);
0085 }
0086 
0087 static struct ltq_wdt_priv *ltq_wdt_get_priv(struct watchdog_device *wdt)
0088 {
0089     return container_of(wdt, struct ltq_wdt_priv, wdt);
0090 }
0091 
0092 static struct watchdog_info ltq_wdt_info = {
0093     .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
0094            WDIOF_CARDRESET,
0095     .identity = "ltq_wdt",
0096 };
0097 
0098 static int ltq_wdt_start(struct watchdog_device *wdt)
0099 {
0100     struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
0101     u32 timeout;
0102 
0103     timeout = wdt->timeout * priv->clk_rate;
0104 
0105     ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
0106     /* write the second magic plus the configuration and new timeout */
0107     ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK | LTQ_WDT_CR_MAX_TIMEOUT,
0108              LTQ_WDT_CR_GEN | LTQ_WDT_CR_PWL | LTQ_WDT_CR_CLKDIV |
0109              LTQ_WDT_CR_PW2 | timeout,
0110              LTQ_WDT_CR);
0111 
0112     return 0;
0113 }
0114 
0115 static int ltq_wdt_stop(struct watchdog_device *wdt)
0116 {
0117     struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
0118 
0119     ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
0120     ltq_wdt_mask(priv, LTQ_WDT_CR_GEN | LTQ_WDT_CR_PW_MASK,
0121              LTQ_WDT_CR_PW2, LTQ_WDT_CR);
0122 
0123     return 0;
0124 }
0125 
0126 static int ltq_wdt_ping(struct watchdog_device *wdt)
0127 {
0128     struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
0129     u32 timeout;
0130 
0131     timeout = wdt->timeout * priv->clk_rate;
0132 
0133     ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
0134     /* write the second magic plus the configuration and new timeout */
0135     ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK | LTQ_WDT_CR_MAX_TIMEOUT,
0136              LTQ_WDT_CR_PW2 | timeout, LTQ_WDT_CR);
0137 
0138     return 0;
0139 }
0140 
0141 static unsigned int ltq_wdt_get_timeleft(struct watchdog_device *wdt)
0142 {
0143     struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
0144     u64 timeout;
0145 
0146     timeout = ltq_wdt_r32(priv, LTQ_WDT_SR) & LTQ_WDT_SR_VALUE_MASK;
0147     return do_div(timeout, priv->clk_rate);
0148 }
0149 
0150 static const struct watchdog_ops ltq_wdt_ops = {
0151     .owner      = THIS_MODULE,
0152     .start      = ltq_wdt_start,
0153     .stop       = ltq_wdt_stop,
0154     .ping       = ltq_wdt_ping,
0155     .get_timeleft   = ltq_wdt_get_timeleft,
0156 };
0157 
0158 static int ltq_wdt_xrx_bootstatus_get(struct device *dev)
0159 {
0160     struct regmap *rcu_regmap;
0161     u32 val;
0162     int err;
0163 
0164     rcu_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap");
0165     if (IS_ERR(rcu_regmap))
0166         return PTR_ERR(rcu_regmap);
0167 
0168     err = regmap_read(rcu_regmap, LTQ_XRX_RCU_RST_STAT, &val);
0169     if (err)
0170         return err;
0171 
0172     if (val & LTQ_XRX_RCU_RST_STAT_WDT)
0173         return WDIOF_CARDRESET;
0174 
0175     return 0;
0176 }
0177 
0178 static int ltq_wdt_falcon_bootstatus_get(struct device *dev)
0179 {
0180     struct regmap *rcu_regmap;
0181     u32 val;
0182     int err;
0183 
0184     rcu_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
0185                              "lantiq,rcu");
0186     if (IS_ERR(rcu_regmap))
0187         return PTR_ERR(rcu_regmap);
0188 
0189     err = regmap_read(rcu_regmap, LTQ_FALCON_SYS1_CPU0RS, &val);
0190     if (err)
0191         return err;
0192 
0193     if ((val & LTQ_FALCON_SYS1_CPU0RS_MASK) == LTQ_FALCON_SYS1_CPU0RS_WDT)
0194         return WDIOF_CARDRESET;
0195 
0196     return 0;
0197 }
0198 
0199 static int ltq_wdt_probe(struct platform_device *pdev)
0200 {
0201     struct device *dev = &pdev->dev;
0202     struct ltq_wdt_priv *priv;
0203     struct watchdog_device *wdt;
0204     struct clk *clk;
0205     const struct ltq_wdt_hw *ltq_wdt_hw;
0206     int ret;
0207     u32 status;
0208 
0209     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0210     if (!priv)
0211         return -ENOMEM;
0212 
0213     priv->membase = devm_platform_ioremap_resource(pdev, 0);
0214     if (IS_ERR(priv->membase))
0215         return PTR_ERR(priv->membase);
0216 
0217     /* we do not need to enable the clock as it is always running */
0218     clk = clk_get_io();
0219     priv->clk_rate = clk_get_rate(clk) / LTQ_WDT_DIVIDER;
0220     if (!priv->clk_rate) {
0221         dev_err(dev, "clock rate less than divider %i\n",
0222             LTQ_WDT_DIVIDER);
0223         return -EINVAL;
0224     }
0225 
0226     wdt = &priv->wdt;
0227     wdt->info       = &ltq_wdt_info;
0228     wdt->ops        = &ltq_wdt_ops;
0229     wdt->min_timeout    = 1;
0230     wdt->max_timeout    = LTQ_WDT_CR_MAX_TIMEOUT / priv->clk_rate;
0231     wdt->timeout        = wdt->max_timeout;
0232     wdt->parent     = dev;
0233 
0234     ltq_wdt_hw = of_device_get_match_data(dev);
0235     if (ltq_wdt_hw && ltq_wdt_hw->bootstatus_get) {
0236         ret = ltq_wdt_hw->bootstatus_get(dev);
0237         if (ret >= 0)
0238             wdt->bootstatus = ret;
0239     }
0240 
0241     watchdog_set_nowayout(wdt, nowayout);
0242     watchdog_init_timeout(wdt, 0, dev);
0243 
0244     status = ltq_wdt_r32(priv, LTQ_WDT_SR);
0245     if (status & LTQ_WDT_SR_EN) {
0246         /*
0247          * If the watchdog is already running overwrite it with our
0248          * new settings. Stop is not needed as the start call will
0249          * replace all settings anyway.
0250          */
0251         ltq_wdt_start(wdt);
0252         set_bit(WDOG_HW_RUNNING, &wdt->status);
0253     }
0254 
0255     return devm_watchdog_register_device(dev, wdt);
0256 }
0257 
0258 static const struct ltq_wdt_hw ltq_wdt_xrx100 = {
0259     .bootstatus_get = ltq_wdt_xrx_bootstatus_get,
0260 };
0261 
0262 static const struct ltq_wdt_hw ltq_wdt_falcon = {
0263     .bootstatus_get = ltq_wdt_falcon_bootstatus_get,
0264 };
0265 
0266 static const struct of_device_id ltq_wdt_match[] = {
0267     { .compatible = "lantiq,wdt", .data = NULL },
0268     { .compatible = "lantiq,xrx100-wdt", .data = &ltq_wdt_xrx100 },
0269     { .compatible = "lantiq,falcon-wdt", .data = &ltq_wdt_falcon },
0270     {},
0271 };
0272 MODULE_DEVICE_TABLE(of, ltq_wdt_match);
0273 
0274 static struct platform_driver ltq_wdt_driver = {
0275     .probe = ltq_wdt_probe,
0276     .driver = {
0277         .name = "wdt",
0278         .of_match_table = ltq_wdt_match,
0279     },
0280 };
0281 
0282 module_platform_driver(ltq_wdt_driver);
0283 
0284 module_param(nowayout, bool, 0);
0285 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
0286 MODULE_AUTHOR("John Crispin <john@phrozen.org>");
0287 MODULE_DESCRIPTION("Lantiq SoC Watchdog");
0288 MODULE_LICENSE("GPL");