Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Watchdog driver for the K3 RTI module
0004  *
0005  * (c) Copyright 2019-2020 Texas Instruments Inc.
0006  * All rights reserved.
0007  */
0008 
0009 #include <linux/clk.h>
0010 #include <linux/device.h>
0011 #include <linux/err.h>
0012 #include <linux/io.h>
0013 #include <linux/kernel.h>
0014 #include <linux/mod_devicetable.h>
0015 #include <linux/module.h>
0016 #include <linux/moduleparam.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/pm_runtime.h>
0019 #include <linux/types.h>
0020 #include <linux/watchdog.h>
0021 
0022 #define DEFAULT_HEARTBEAT 60
0023 
0024 /* Max heartbeat is calculated at 32kHz source clock */
0025 #define MAX_HEARTBEAT   1000
0026 
0027 /* Timer register set definition */
0028 #define RTIDWDCTRL  0x90
0029 #define RTIDWDPRLD  0x94
0030 #define RTIWDSTATUS 0x98
0031 #define RTIWDKEY    0x9c
0032 #define RTIDWDCNTR  0xa0
0033 #define RTIWWDRXCTRL    0xa4
0034 #define RTIWWDSIZECTRL  0xa8
0035 
0036 #define RTIWWDRX_NMI    0xa
0037 
0038 #define RTIWWDSIZE_50P      0x50
0039 #define RTIWWDSIZE_25P      0x500
0040 #define RTIWWDSIZE_12P5     0x5000
0041 #define RTIWWDSIZE_6P25     0x50000
0042 #define RTIWWDSIZE_3P125    0x500000
0043 
0044 #define WDENABLE_KEY    0xa98559da
0045 
0046 #define WDKEY_SEQ0      0xe51a
0047 #define WDKEY_SEQ1      0xa35c
0048 
0049 #define WDT_PRELOAD_SHIFT   13
0050 
0051 #define WDT_PRELOAD_MAX     0xfff
0052 
0053 #define DWDST           BIT(1)
0054 
0055 static int heartbeat = DEFAULT_HEARTBEAT;
0056 
0057 /*
0058  * struct to hold data for each WDT device
0059  * @base - base io address of WD device
0060  * @freq - source clock frequency of WDT
0061  * @wdd  - hold watchdog device as is in WDT core
0062  */
0063 struct rti_wdt_device {
0064     void __iomem        *base;
0065     unsigned long       freq;
0066     struct watchdog_device  wdd;
0067 };
0068 
0069 static int rti_wdt_start(struct watchdog_device *wdd)
0070 {
0071     u32 timer_margin;
0072     struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
0073 
0074     /* set timeout period */
0075     timer_margin = (u64)wdd->timeout * wdt->freq;
0076     timer_margin >>= WDT_PRELOAD_SHIFT;
0077     if (timer_margin > WDT_PRELOAD_MAX)
0078         timer_margin = WDT_PRELOAD_MAX;
0079     writel_relaxed(timer_margin, wdt->base + RTIDWDPRLD);
0080 
0081     /*
0082      * RTI only supports a windowed mode, where the watchdog can only
0083      * be petted during the open window; not too early or not too late.
0084      * The HW configuration options only allow for the open window size
0085      * to be 50% or less than that; we obviouly want to configure the open
0086      * window as large as possible so we select the 50% option.
0087      */
0088     wdd->min_hw_heartbeat_ms = 500 * wdd->timeout;
0089 
0090     /* Generate NMI when wdt expires */
0091     writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL);
0092 
0093     /* Open window size 50%; this is the largest window size available */
0094     writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL);
0095 
0096     readl_relaxed(wdt->base + RTIWWDSIZECTRL);
0097 
0098     /* enable watchdog */
0099     writel_relaxed(WDENABLE_KEY, wdt->base + RTIDWDCTRL);
0100     return 0;
0101 }
0102 
0103 static int rti_wdt_ping(struct watchdog_device *wdd)
0104 {
0105     struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
0106 
0107     /* put watchdog in service state */
0108     writel_relaxed(WDKEY_SEQ0, wdt->base + RTIWDKEY);
0109     /* put watchdog in active state */
0110     writel_relaxed(WDKEY_SEQ1, wdt->base + RTIWDKEY);
0111 
0112     return 0;
0113 }
0114 
0115 static int rti_wdt_setup_hw_hb(struct watchdog_device *wdd, u32 wsize)
0116 {
0117     /*
0118      * RTI only supports a windowed mode, where the watchdog can only
0119      * be petted during the open window; not too early or not too late.
0120      * The HW configuration options only allow for the open window size
0121      * to be 50% or less than that.
0122      */
0123     switch (wsize) {
0124     case RTIWWDSIZE_50P:
0125         /* 50% open window => 50% min heartbeat */
0126         wdd->min_hw_heartbeat_ms = 500 * heartbeat;
0127         break;
0128 
0129     case RTIWWDSIZE_25P:
0130         /* 25% open window => 75% min heartbeat */
0131         wdd->min_hw_heartbeat_ms = 750 * heartbeat;
0132         break;
0133 
0134     case RTIWWDSIZE_12P5:
0135         /* 12.5% open window => 87.5% min heartbeat */
0136         wdd->min_hw_heartbeat_ms = 875 * heartbeat;
0137         break;
0138 
0139     case RTIWWDSIZE_6P25:
0140         /* 6.5% open window => 93.5% min heartbeat */
0141         wdd->min_hw_heartbeat_ms = 935 * heartbeat;
0142         break;
0143 
0144     case RTIWWDSIZE_3P125:
0145         /* 3.125% open window => 96.9% min heartbeat */
0146         wdd->min_hw_heartbeat_ms = 969 * heartbeat;
0147         break;
0148 
0149     default:
0150         return -EINVAL;
0151     }
0152 
0153     return 0;
0154 }
0155 
0156 static unsigned int rti_wdt_get_timeleft_ms(struct watchdog_device *wdd)
0157 {
0158     u64 timer_counter;
0159     u32 val;
0160     struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
0161 
0162     /* if timeout has occurred then return 0 */
0163     val = readl_relaxed(wdt->base + RTIWDSTATUS);
0164     if (val & DWDST)
0165         return 0;
0166 
0167     timer_counter = readl_relaxed(wdt->base + RTIDWDCNTR);
0168 
0169     timer_counter *= 1000;
0170 
0171     do_div(timer_counter, wdt->freq);
0172 
0173     return timer_counter;
0174 }
0175 
0176 static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd)
0177 {
0178     return rti_wdt_get_timeleft_ms(wdd) / 1000;
0179 }
0180 
0181 static const struct watchdog_info rti_wdt_info = {
0182     .options = WDIOF_KEEPALIVEPING,
0183     .identity = "K3 RTI Watchdog",
0184 };
0185 
0186 static const struct watchdog_ops rti_wdt_ops = {
0187     .owner      = THIS_MODULE,
0188     .start      = rti_wdt_start,
0189     .ping       = rti_wdt_ping,
0190     .get_timeleft   = rti_wdt_get_timeleft,
0191 };
0192 
0193 static int rti_wdt_probe(struct platform_device *pdev)
0194 {
0195     int ret = 0;
0196     struct device *dev = &pdev->dev;
0197     struct watchdog_device *wdd;
0198     struct rti_wdt_device *wdt;
0199     struct clk *clk;
0200     u32 last_ping = 0;
0201 
0202     wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
0203     if (!wdt)
0204         return -ENOMEM;
0205 
0206     clk = clk_get(dev, NULL);
0207     if (IS_ERR(clk))
0208         return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
0209 
0210     wdt->freq = clk_get_rate(clk);
0211 
0212     clk_put(clk);
0213 
0214     if (!wdt->freq) {
0215         dev_err(dev, "Failed to get fck rate.\n");
0216         return -EINVAL;
0217     }
0218 
0219     /*
0220      * If watchdog is running at 32k clock, it is not accurate.
0221      * Adjust frequency down in this case so that we don't pet
0222      * the watchdog too often.
0223      */
0224     if (wdt->freq < 32768)
0225         wdt->freq = wdt->freq * 9 / 10;
0226 
0227     pm_runtime_enable(dev);
0228     ret = pm_runtime_get_sync(dev);
0229     if (ret < 0) {
0230         pm_runtime_put_noidle(dev);
0231         pm_runtime_disable(&pdev->dev);
0232         return dev_err_probe(dev, ret, "runtime pm failed\n");
0233     }
0234 
0235     platform_set_drvdata(pdev, wdt);
0236 
0237     wdd = &wdt->wdd;
0238     wdd->info = &rti_wdt_info;
0239     wdd->ops = &rti_wdt_ops;
0240     wdd->min_timeout = 1;
0241     wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) /
0242         wdt->freq * 1000;
0243     wdd->parent = dev;
0244 
0245     watchdog_set_drvdata(wdd, wdt);
0246     watchdog_set_nowayout(wdd, 1);
0247     watchdog_set_restart_priority(wdd, 128);
0248 
0249     wdt->base = devm_platform_ioremap_resource(pdev, 0);
0250     if (IS_ERR(wdt->base)) {
0251         ret = PTR_ERR(wdt->base);
0252         goto err_iomap;
0253     }
0254 
0255     if (readl(wdt->base + RTIDWDCTRL) == WDENABLE_KEY) {
0256         int preset_heartbeat;
0257         u32 time_left_ms;
0258         u64 heartbeat_ms;
0259         u32 wsize;
0260 
0261         set_bit(WDOG_HW_RUNNING, &wdd->status);
0262         time_left_ms = rti_wdt_get_timeleft_ms(wdd);
0263         heartbeat_ms = readl(wdt->base + RTIDWDPRLD);
0264         heartbeat_ms <<= WDT_PRELOAD_SHIFT;
0265         heartbeat_ms *= 1000;
0266         do_div(heartbeat_ms, wdt->freq);
0267         preset_heartbeat = heartbeat_ms + 500;
0268         preset_heartbeat /= 1000;
0269         if (preset_heartbeat != heartbeat)
0270             dev_warn(dev, "watchdog already running, ignoring heartbeat config!\n");
0271 
0272         heartbeat = preset_heartbeat;
0273 
0274         wsize = readl(wdt->base + RTIWWDSIZECTRL);
0275         ret = rti_wdt_setup_hw_hb(wdd, wsize);
0276         if (ret) {
0277             dev_err(dev, "bad window size.\n");
0278             goto err_iomap;
0279         }
0280 
0281         last_ping = heartbeat_ms - time_left_ms;
0282         if (time_left_ms > heartbeat_ms) {
0283             dev_warn(dev, "time_left > heartbeat? Assuming last ping just before now.\n");
0284             last_ping = 0;
0285         }
0286     }
0287 
0288     watchdog_init_timeout(wdd, heartbeat, dev);
0289 
0290     ret = watchdog_register_device(wdd);
0291     if (ret) {
0292         dev_err(dev, "cannot register watchdog device\n");
0293         goto err_iomap;
0294     }
0295 
0296     if (last_ping)
0297         watchdog_set_last_hw_keepalive(wdd, last_ping);
0298 
0299     return 0;
0300 
0301 err_iomap:
0302     pm_runtime_put_sync(&pdev->dev);
0303     pm_runtime_disable(&pdev->dev);
0304 
0305     return ret;
0306 }
0307 
0308 static int rti_wdt_remove(struct platform_device *pdev)
0309 {
0310     struct rti_wdt_device *wdt = platform_get_drvdata(pdev);
0311 
0312     watchdog_unregister_device(&wdt->wdd);
0313     pm_runtime_put(&pdev->dev);
0314     pm_runtime_disable(&pdev->dev);
0315 
0316     return 0;
0317 }
0318 
0319 static const struct of_device_id rti_wdt_of_match[] = {
0320     { .compatible = "ti,j7-rti-wdt", },
0321     {},
0322 };
0323 MODULE_DEVICE_TABLE(of, rti_wdt_of_match);
0324 
0325 static struct platform_driver rti_wdt_driver = {
0326     .driver = {
0327         .name = "rti-wdt",
0328         .of_match_table = rti_wdt_of_match,
0329     },
0330     .probe = rti_wdt_probe,
0331     .remove = rti_wdt_remove,
0332 };
0333 
0334 module_platform_driver(rti_wdt_driver);
0335 
0336 MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
0337 MODULE_DESCRIPTION("K3 RTI Watchdog Driver");
0338 
0339 module_param(heartbeat, int, 0);
0340 MODULE_PARM_DESC(heartbeat,
0341          "Watchdog heartbeat period in seconds from 1 to "
0342          __MODULE_STRING(MAX_HEARTBEAT) ", default "
0343          __MODULE_STRING(DEFAULT_HEARTBEAT));
0344 
0345 MODULE_LICENSE("GPL");
0346 MODULE_ALIAS("platform:rti-wdt");