· 8 years ago · Apr 03, 2018, 05:54 PM
1/*
2 * (C) Copyright 2018 Chris Blake <chrisrblake93 at gmail.com>
3 *
4 * This file is licensed under the terms of the GNU General Public
5 * License version 2. This program is licensed "as is" without
6 * any warranty of any kind, whether express or implied.
7 */
8
9#include <common.h>
10#include <watchdog.h>
11#include <asm/arch/timer.h>
12#include <asm/io.h>
13
14#define WDT_CTRL_RESTART (0x1 << 0)
15#define WDT_CTRL_KEY (0x0a57 << 1)
16#define WDT_MODE_EN (0x1 << 0)
17#define WDT_MODE_RESET_EN (0x1 << 1)
18#define WDT_CFG_RESET (0x1)
19#define WDT_TIMEOUT_MASK (0xf)
20
21struct sunxi_wdt_reg {
22 u32 wdt_ctl;
23 u32 wdt_cfg;
24 u32 wdt_mode;
25 u32 wdt_reset_mask;
26 u32 wdt_reset_mode;
27};
28
29static const struct sunxi_wdt_reg sun6i_dog_regs = {
30 .wdt_ctrl = 0x10,
31 .wdt_cfg = 0x14,
32 .wdt_mode = 0x18,
33 .wdt_timeout_shift = 4,
34 .wdt_reset_mask = 0x03,
35 .wdt_reset_val = 0x01,
36};
37
38static const int wdt_timeout_map[] = {
39 [1] = 0x1, /* 1s */
40 [2] = 0x2, /* 2s */
41 [3] = 0x3, /* 3s */
42 [4] = 0x4, /* 4s */
43 [5] = 0x5, /* 5s */
44 [6] = 0x6, /* 6s */
45 [8] = 0x7, /* 8s */
46 [10] = 0x8, /* 10s */
47 [12] = 0x9, /* 12s */
48 [14] = 0xA, /* 14s */
49 [16] = 0xB, /* 16s */
50};
51
52static const struct sunxi_wdt_reg *regs = &sun6i_dog_regs;
53
54static void *wdt_base = &((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog;
55
56void hw_watchdog_reset(void)
57{
58 /* reload the watchdog */
59 writel(WDT_CTRL_KEY | WDT_CTRL_RESTART, wdt_base + regs->wdt_ctrl);
60}
61
62void hw_watchdog_disable(void)
63{
64 /* Reset WDT Config */
65 writel(WDT_CFG_RESET, wdt_base + regs->wdt_cfg);
66}
67
68void hw_watchdog_init(void)
69{
70 const u32 timeout = CONFIG_SUNXI_WDT_TIMEOUT;
71 u32 reg;
72
73 reg = readl(wdt_base + regs->wdt_mode);
74 reg &= ~(WDT_TIMEOUT_MASK << regs->wdt_timeout_shift);
75 reg |= wdt_timeout_map[timeout] << regs->wdt_timeout_shift;
76 writel(reg, wdt_base + regs->wdt_mode);
77
78 hw_watchdog_reset();
79
80 /* Set system reset function */
81 reg = readl(wdt_base + regs->wdt_cfg);
82 reg &= ~(regs->wdt_reset_mask);
83 reg |= regs->wdt_reset_val;
84 writel(reg, wdt_base + regs->wdt_cfg);
85
86 /* Enable watchdog */
87 reg = readl(wdt_base + regs->wdt_mode);
88 reg |= WDT_MODE_EN;
89 writel(reg, wdt_base + regs->wdt_mode);
90 }