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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
/*
* Copyright (C) 2012 Spreadtrum Communications Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _SPRD_WDT_SYS_H_
#define _SPRD_WDT_SYS_H_
#include <linux/spinlock.h>
#include <linux/bitops.h>
#include <soc/sprd/adi.h>
#include <soc/sprd/sci_glb_regs.h>
#include <soc/sprd/sci.h>
#include <soc/sprd/hardware.h>
unsigned long ap_wdt_addr;
unsigned long a7_wdt_addr;
#define AP_WDG_LOAD_LOW (ap_wdt_addr + 0x00)
#define AP_WDG_LOAD_HIGH (ap_wdt_addr + 0x04)
#define AP_WDG_CTRL (ap_wdt_addr + 0x08)
#define AP_WDG_INT_CLR (ap_wdt_addr + 0x0C)
#define AP_WDG_INT_RAW (ap_wdt_addr + 0x10)
#define AP_WDG_INT_MSK (ap_wdt_addr + 0x14)
#define AP_WDG_CNT_LOW (ap_wdt_addr + 0x18)
#define AP_WDG_CNT_HIGH (ap_wdt_addr + 0x1C)
#define AP_WDG_LOCK (ap_wdt_addr + 0x20)
#define CA7_WDG_LOAD_LOW (a7_wdt_addr + 0x00)
#define CA7_WDG_LOAD_HIGH (a7_wdt_addr + 0x04)
#define CA7_WDG_CTRL (a7_wdt_addr + 0x08)
#define CA7_WDG_INT_CLR (a7_wdt_addr + 0x0C)
#define CA7_WDG_INT_RAW (a7_wdt_addr + 0x10)
#define CA7_WDG_INT_MSK (a7_wdt_addr + 0x14)
#define CA7_WDG_CNT_LOW (a7_wdt_addr + 0x18)
#define CA7_WDG_CNT_HIGH (a7_wdt_addr + 0x1C)
#define CA7_WDG_LOCK (a7_wdt_addr + 0x20)
#define CA7_WDG_IRQ_LOAD_LOW (a7_wdt_addr + 0x2c)
#define CA7_WDG_IRQ_LOAD_HIGH (a7_wdt_addr + 0x30)
#define AP_WDG_LOAD_TIMER_VALUE(value) \
do { \
uint32_t cnt = 0;\
sci_glb_write( AP_WDG_LOAD_HIGH, (uint16_t)(((value) >> 16 ) & 0xffff), -1UL); \
sci_glb_write( AP_WDG_LOAD_LOW , (uint16_t)((value) & 0xffff), -1UL ); \
while((sci_glb_read(AP_WDG_INT_RAW, -1UL) & WDG_LD_BUSY_BIT) && ( cnt < ANA_WDG_LOAD_TIMEOUT_NUM )) cnt++; \
} while (0)
#define CA7_WDG_LOAD_TIMER_VALUE(margin, irq) \
do { \
uint32_t cnt = 0; \
sci_glb_write( CA7_WDG_LOAD_HIGH, (uint16_t)(((margin) >> 16 ) & 0xffff), -1UL); \
sci_glb_write( CA7_WDG_LOAD_LOW , (uint16_t)((margin) & 0xffff), -1UL ); \
sci_glb_write( CA7_WDG_IRQ_LOAD_HIGH, (uint16_t)(((irq) >> 16 ) & 0xffff), -1UL); \
sci_glb_write( CA7_WDG_IRQ_LOAD_LOW , (uint16_t)((irq) & 0xffff), -1UL ); \
while((sci_glb_read(CA7_WDG_INT_RAW, -1UL) & WDG_LD_BUSY_BIT) && ( cnt < ANA_WDG_LOAD_TIMEOUT_NUM )) cnt++; \
} while (0)
#ifdef CONFIG_SC_INTERNAL_WATCHDOG
static inline void FEED_ALL_WDG(int chip_margin, int ap_margin,
int ca7_margin, int ca7_irq_margin)
{
AP_WDG_LOAD_TIMER_VALUE(ap_margin * WDG_CLK);
WDG_LOAD_TIMER_VALUE(chip_margin * WDG_CLK);
CA7_WDG_LOAD_TIMER_VALUE(ca7_margin * WDG_CLK, (ca7_margin - ca7_irq_margin) * WDG_CLK);
}
#else
static inline void FEED_ALL_WDG(int chip_margin, int ap_margin,
int ca7_margin, int ca7_irq_margin) { }
#endif
#define ENABLE_ALL_WDG() \
do { \
sci_adi_set(WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
sci_glb_set(AP_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
sci_glb_set(CA7_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT | WDG_INT_EN_BIT); \
} while (0)
#define DISABLE_ALL_WDG() \
do { \
sci_adi_clr(WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
sci_glb_clr(AP_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); \
sci_glb_clr(CA7_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT | WDG_INT_EN_BIT); \
} while (0)
#define WATCHDOG_THREAD_USER_BIT 0
#define WATCHDOG_THREAD_KERNEL_BIT 1
#define WATCHDOG_FEED_BY_USER_ST_BIT (0)
#define WATCHDOG_FEED_BY_USER_BIT (1)
#define WATCHDOG_FEED_BY_KERNEL_BIT (2)
#define WATCHDOG_FEED_ENABLE_BIT (30)
#define WATCHDOG_FEED_START_BIT (31)
#define WATCHDOG_FEED_BY_KERNEL_THREAD ( \
(1 << WATCHDOG_FEED_BY_USER_BIT) | \
(1 << WATCHDOG_FEED_BY_KERNEL_BIT) \
)
#define WATCHDOG_FEED_BY_USER_THREAD ( \
(1 << WATCHDOG_FEED_BY_USER_ST_BIT) \
)
#define WATCHDOG_FEED_BY_THREAD \
(WATCHDOG_FEED_BY_KERNEL_THREAD | WATCHDOG_FEED_BY_USER_THREAD)
#ifdef CONFIG_SC_INTERNAL_WATCHDOG
static inline void watchdog_start(int chip_margin, int ap_margin,
int ca7_margin, int ca7_irq_margin)
{
/* start the chip watchdog */
sci_adi_set(ANA_AGEN, AGEN_WDG_EN);
sci_adi_set(ANA_RTC_CLK_EN, AGEN_RTC_WDG_EN);
sci_adi_raw_write(WDG_LOCK, WDG_UNLOCK_KEY);
sci_adi_set(WDG_CTRL, WDG_NEW_VER_EN);
WDG_LOAD_TIMER_VALUE(chip_margin * WDG_CLK);
sci_adi_set(WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT);
/* start ap watchdog */
sci_glb_set(REG_AON_APB_APB_EB0, BIT_AP_WDG_EB);
sci_glb_set(REG_AON_APB_APB_RTC_EB, BIT_AP_WDG_RTC_EB);
sci_glb_write(AP_WDG_LOCK, WDG_UNLOCK_KEY, -1UL);
sci_glb_set(AP_WDG_CTRL, WDG_NEW_VER_EN);
AP_WDG_LOAD_TIMER_VALUE(ap_margin * WDG_CLK);
sci_glb_set(AP_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT);
/* start ca7 watchdog */
sci_glb_set(REG_AON_APB_APB_EB1, BIT_CA7_WDG_EB);
sci_glb_set(REG_AON_APB_APB_RTC_EB, BIT_CA7_WDG_RTC_EB);
sci_glb_write(CA7_WDG_LOCK, WDG_UNLOCK_KEY, -1UL);
sci_glb_set(CA7_WDG_CTRL, WDG_NEW_VER_EN);
CA7_WDG_LOAD_TIMER_VALUE(ca7_margin * WDG_CLK, (ca7_margin - ca7_irq_margin) * WDG_CLK);
sci_glb_set(CA7_WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT | WDG_INT_EN_BIT);
}
#else
static inline void watchdog_start(int chip_margin, int ap_margin,
int ca7_margin, int ca7_irq_margin) { }
#endif
#endif
|