Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * drivers/char/watchdog/davinci_wdt.c
0004  *
0005  * Watchdog driver for DaVinci DM644x/DM646x processors
0006  *
0007  * Copyright (C) 2006-2013 Texas Instruments.
0008  *
0009  * 2007 (c) MontaVista Software, Inc.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/moduleparam.h>
0014 #include <linux/mod_devicetable.h>
0015 #include <linux/types.h>
0016 #include <linux/kernel.h>
0017 #include <linux/watchdog.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/io.h>
0020 #include <linux/device.h>
0021 #include <linux/clk.h>
0022 #include <linux/err.h>
0023 
0024 #define MODULE_NAME "DAVINCI-WDT: "
0025 
0026 #define DEFAULT_HEARTBEAT 60
0027 #define MAX_HEARTBEAT     600   /* really the max margin is 264/27MHz*/
0028 
0029 /* Timer register set definition */
0030 #define PID12   (0x0)
0031 #define EMUMGT  (0x4)
0032 #define TIM12   (0x10)
0033 #define TIM34   (0x14)
0034 #define PRD12   (0x18)
0035 #define PRD34   (0x1C)
0036 #define TCR (0x20)
0037 #define TGCR    (0x24)
0038 #define WDTCR   (0x28)
0039 
0040 /* TCR bit definitions */
0041 #define ENAMODE12_DISABLED  (0 << 6)
0042 #define ENAMODE12_ONESHOT   (1 << 6)
0043 #define ENAMODE12_PERIODIC  (2 << 6)
0044 
0045 /* TGCR bit definitions */
0046 #define TIM12RS_UNRESET     (1 << 0)
0047 #define TIM34RS_UNRESET     (1 << 1)
0048 #define TIMMODE_64BIT_WDOG      (2 << 2)
0049 
0050 /* WDTCR bit definitions */
0051 #define WDEN            (1 << 14)
0052 #define WDFLAG          (1 << 15)
0053 #define WDKEY_SEQ0      (0xa5c6 << 16)
0054 #define WDKEY_SEQ1      (0xda7e << 16)
0055 
0056 static int heartbeat;
0057 
0058 /*
0059  * struct to hold data for each WDT device
0060  * @base - base io address of WD device
0061  * @clk - source clock of WDT
0062  * @wdd - hold watchdog device as is in WDT core
0063  */
0064 struct davinci_wdt_device {
0065     void __iomem        *base;
0066     struct clk      *clk;
0067     struct watchdog_device  wdd;
0068 };
0069 
0070 static int davinci_wdt_start(struct watchdog_device *wdd)
0071 {
0072     u32 tgcr;
0073     u32 timer_margin;
0074     unsigned long wdt_freq;
0075     struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0076 
0077     wdt_freq = clk_get_rate(davinci_wdt->clk);
0078 
0079     /* disable, internal clock source */
0080     iowrite32(0, davinci_wdt->base + TCR);
0081     /* reset timer, set mode to 64-bit watchdog, and unreset */
0082     iowrite32(0, davinci_wdt->base + TGCR);
0083     tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
0084     iowrite32(tgcr, davinci_wdt->base + TGCR);
0085     /* clear counter regs */
0086     iowrite32(0, davinci_wdt->base + TIM12);
0087     iowrite32(0, davinci_wdt->base + TIM34);
0088     /* set timeout period */
0089     timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff);
0090     iowrite32(timer_margin, davinci_wdt->base + PRD12);
0091     timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32);
0092     iowrite32(timer_margin, davinci_wdt->base + PRD34);
0093     /* enable run continuously */
0094     iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR);
0095     /* Once the WDT is in pre-active state write to
0096      * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
0097      * write protected (except for the WDKEY field)
0098      */
0099     /* put watchdog in pre-active state */
0100     iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR);
0101     /* put watchdog in active state */
0102     iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR);
0103     return 0;
0104 }
0105 
0106 static int davinci_wdt_ping(struct watchdog_device *wdd)
0107 {
0108     struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0109 
0110     /* put watchdog in service state */
0111     iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR);
0112     /* put watchdog in active state */
0113     iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR);
0114     return 0;
0115 }
0116 
0117 static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
0118 {
0119     u64 timer_counter;
0120     unsigned long freq;
0121     u32 val;
0122     struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0123 
0124     /* if timeout has occured then return 0 */
0125     val = ioread32(davinci_wdt->base + WDTCR);
0126     if (val & WDFLAG)
0127         return 0;
0128 
0129     freq = clk_get_rate(davinci_wdt->clk);
0130 
0131     if (!freq)
0132         return 0;
0133 
0134     timer_counter = ioread32(davinci_wdt->base + TIM12);
0135     timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32);
0136 
0137     timer_counter = div64_ul(timer_counter, freq);
0138 
0139     return wdd->timeout - timer_counter;
0140 }
0141 
0142 static int davinci_wdt_restart(struct watchdog_device *wdd,
0143                    unsigned long action, void *data)
0144 {
0145     struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0146     u32 tgcr, wdtcr;
0147 
0148     /* disable, internal clock source */
0149     iowrite32(0, davinci_wdt->base + TCR);
0150 
0151     /* reset timer, set mode to 64-bit watchdog, and unreset */
0152     tgcr = 0;
0153     iowrite32(tgcr, davinci_wdt->base + TGCR);
0154     tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
0155     iowrite32(tgcr, davinci_wdt->base + TGCR);
0156 
0157     /* clear counter and period regs */
0158     iowrite32(0, davinci_wdt->base + TIM12);
0159     iowrite32(0, davinci_wdt->base + TIM34);
0160     iowrite32(0, davinci_wdt->base + PRD12);
0161     iowrite32(0, davinci_wdt->base + PRD34);
0162 
0163     /* put watchdog in pre-active state */
0164     wdtcr = WDKEY_SEQ0 | WDEN;
0165     iowrite32(wdtcr, davinci_wdt->base + WDTCR);
0166 
0167     /* put watchdog in active state */
0168     wdtcr = WDKEY_SEQ1 | WDEN;
0169     iowrite32(wdtcr, davinci_wdt->base + WDTCR);
0170 
0171     /* write an invalid value to the WDKEY field to trigger a restart */
0172     wdtcr = 0x00004000;
0173     iowrite32(wdtcr, davinci_wdt->base + WDTCR);
0174 
0175     return 0;
0176 }
0177 
0178 static const struct watchdog_info davinci_wdt_info = {
0179     .options = WDIOF_KEEPALIVEPING,
0180     .identity = "DaVinci/Keystone Watchdog",
0181 };
0182 
0183 static const struct watchdog_ops davinci_wdt_ops = {
0184     .owner      = THIS_MODULE,
0185     .start      = davinci_wdt_start,
0186     .stop       = davinci_wdt_ping,
0187     .ping       = davinci_wdt_ping,
0188     .get_timeleft   = davinci_wdt_get_timeleft,
0189     .restart    = davinci_wdt_restart,
0190 };
0191 
0192 static void davinci_clk_disable_unprepare(void *data)
0193 {
0194     clk_disable_unprepare(data);
0195 }
0196 
0197 static int davinci_wdt_probe(struct platform_device *pdev)
0198 {
0199     int ret = 0;
0200     struct device *dev = &pdev->dev;
0201     struct watchdog_device *wdd;
0202     struct davinci_wdt_device *davinci_wdt;
0203 
0204     davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL);
0205     if (!davinci_wdt)
0206         return -ENOMEM;
0207 
0208     davinci_wdt->clk = devm_clk_get(dev, NULL);
0209     if (IS_ERR(davinci_wdt->clk))
0210         return dev_err_probe(dev, PTR_ERR(davinci_wdt->clk),
0211                      "failed to get clock node\n");
0212 
0213     ret = clk_prepare_enable(davinci_wdt->clk);
0214     if (ret) {
0215         dev_err(dev, "failed to prepare clock\n");
0216         return ret;
0217     }
0218     ret = devm_add_action_or_reset(dev, davinci_clk_disable_unprepare,
0219                        davinci_wdt->clk);
0220     if (ret)
0221         return ret;
0222 
0223     platform_set_drvdata(pdev, davinci_wdt);
0224 
0225     wdd         = &davinci_wdt->wdd;
0226     wdd->info       = &davinci_wdt_info;
0227     wdd->ops        = &davinci_wdt_ops;
0228     wdd->min_timeout    = 1;
0229     wdd->max_timeout    = MAX_HEARTBEAT;
0230     wdd->timeout        = DEFAULT_HEARTBEAT;
0231     wdd->parent     = dev;
0232 
0233     watchdog_init_timeout(wdd, heartbeat, dev);
0234 
0235     dev_info(dev, "heartbeat %d sec\n", wdd->timeout);
0236 
0237     watchdog_set_drvdata(wdd, davinci_wdt);
0238     watchdog_set_nowayout(wdd, 1);
0239     watchdog_set_restart_priority(wdd, 128);
0240 
0241     davinci_wdt->base = devm_platform_ioremap_resource(pdev, 0);
0242     if (IS_ERR(davinci_wdt->base))
0243         return PTR_ERR(davinci_wdt->base);
0244 
0245     return devm_watchdog_register_device(dev, wdd);
0246 }
0247 
0248 static const struct of_device_id davinci_wdt_of_match[] = {
0249     { .compatible = "ti,davinci-wdt", },
0250     {},
0251 };
0252 MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
0253 
0254 static struct platform_driver platform_wdt_driver = {
0255     .driver = {
0256         .name = "davinci-wdt",
0257         .of_match_table = davinci_wdt_of_match,
0258     },
0259     .probe = davinci_wdt_probe,
0260 };
0261 
0262 module_platform_driver(platform_wdt_driver);
0263 
0264 MODULE_AUTHOR("Texas Instruments");
0265 MODULE_DESCRIPTION("DaVinci Watchdog Driver");
0266 
0267 module_param(heartbeat, int, 0);
0268 MODULE_PARM_DESC(heartbeat,
0269          "Watchdog heartbeat period in seconds from 1 to "
0270          __MODULE_STRING(MAX_HEARTBEAT) ", default "
0271          __MODULE_STRING(DEFAULT_HEARTBEAT));
0272 
0273 MODULE_LICENSE("GPL");
0274 MODULE_ALIAS("platform:davinci-wdt");