hc
2023-11-23 7d07b3ae8ddad407913c5301877e694430a3263f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2008 Simtec Electronics
//    Ben Dooks <ben@simtec.co.uk>
//
// Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
//
// Watchdog reset support for Samsung SoCs.
 
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_address.h>
 
#define S3C2410_WTCON            0x00
#define S3C2410_WTDAT            0x04
#define S3C2410_WTCNT            0x08
 
#define S3C2410_WTCON_ENABLE        (1 << 5)
#define S3C2410_WTCON_DIV16        (0 << 3)
#define S3C2410_WTCON_RSTEN        (1 << 0)
#define S3C2410_WTCON_PRESCALE(x)    ((x) << 8)
 
static void __iomem *wdt_base;
static struct clk *wdt_clock;
 
void samsung_wdt_reset(void)
{
   if (!wdt_base) {
       pr_err("%s: wdt reset not initialized\n", __func__);
       /* delay to allow the serial port to show the message */
       mdelay(50);
       return;
   }
 
   if (!IS_ERR(wdt_clock))
       clk_prepare_enable(wdt_clock);
 
   /* disable watchdog, to be safe  */
   __raw_writel(0, wdt_base + S3C2410_WTCON);
 
   /* put initial values into count and data */
   __raw_writel(0x80, wdt_base + S3C2410_WTCNT);
   __raw_writel(0x80, wdt_base + S3C2410_WTDAT);
 
   /* set the watchdog to go and reset... */
   __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
           S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
           wdt_base + S3C2410_WTCON);
 
   /* wait for reset to assert... */
   mdelay(500);
 
   pr_err("Watchdog reset failed to assert reset\n");
 
   /* delay to allow the serial port to show the message */
   mdelay(50);
}
 
#ifdef CONFIG_OF
static const struct of_device_id s3c2410_wdt_match[] = {
   { .compatible = "samsung,s3c2410-wdt" },
   { .compatible = "samsung,s3c6410-wdt" },
   {},
};
 
void __init samsung_wdt_reset_of_init(void)
{
   struct device_node *np;
 
   np = of_find_matching_node(NULL, s3c2410_wdt_match);
   if (!np) {
       pr_err("%s: failed to find watchdog node\n", __func__);
       return;
   }
 
   wdt_base = of_iomap(np, 0);
   if (!wdt_base) {
       pr_err("%s: failed to map watchdog registers\n", __func__);
       return;
   }
 
   wdt_clock = of_clk_get(np, 0);
}
#endif
 
void __init samsung_wdt_reset_init(void __iomem *base)
{
   wdt_base = base;
   wdt_clock = clk_get(NULL, "watchdog");
}