1 /*
2 * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <errno.h>
18 #include "duet_cm4.h"
19 #include "duet.h"
20 #include "duet_wdg.h"
21 #ifdef ALIOS_SUPPORT
22 #include "lega_rhino.h"
23 #else
24 #include "lega_rtos.h"
25 #endif
26 // WDG APB CLOCK 0-15 BIT 4-7
27 #define APB_DIV_1 0
28 #define APB_DIV_2 1
29 #define APB_DIV_3 2
30 #define APB_DIV_4 3
31 #define APB_DIV_5 4
32 #define APB_DIV_6 5
33 #define APB_DIV_7 6
34 #define APB_DIV_8 7
35 #define APB_DIV_9 8
36 #define APB_DIV_10 9
37 #define APB_DIV_11 10
38 #define APB_DIV_12 11
39 #define APB_DIV_13 12
40 #define APB_DIV_14 13
41 #define APB_DIV_15 14
42 #define APB_DIV_16 15
43 #define WDG_APB_DIV APB_DIV_1
44 #define WDG_APB_DIV_REG 0X40000854
45
hw_watchdog_unlock(void)46 void hw_watchdog_unlock(void)
47 {
48 WATCHDOG->LOCK = WDG_LOCK_TOKEN;
49 }
50
hw_watchdog_lock(void)51 void hw_watchdog_lock(void)
52 {
53 WATCHDOG->LOCK = ~(WDG_LOCK_TOKEN);
54 }
55
hw_watchdog_disable(void)56 void hw_watchdog_disable(void)
57 {
58 hw_watchdog_unlock();
59 WATCHDOG->CONTROL = 0x0;
60 WATCHDOG->LOAD = 0xffffffff;
61 hw_watchdog_lock();
62 }
63
hw_watchdog_isr(unsigned int delay)64 void hw_watchdog_isr(unsigned int delay)
65 {
66 hw_watchdog_unlock();
67 WATCHDOG->CONTROL = WDG_INTEN;
68 WATCHDOG->LOAD = delay;
69 hw_watchdog_lock();
70 }
71
hw_watchdog_reset(unsigned int delay)72 void hw_watchdog_reset(unsigned int delay)
73 {
74 hw_watchdog_unlock();
75 WATCHDOG->CONTROL = WDG_RESEN | WDG_INTEN;
76 WATCHDOG->LOAD = delay;
77 hw_watchdog_lock();
78 }
79
hw_watchdog_isr_clr(void)80 void hw_watchdog_isr_clr(void)
81 {
82 hw_watchdog_unlock();
83 WATCHDOG->INTCLR = 0x1;
84 hw_watchdog_lock();
85 }
86
WDG_IRQHandler(void)87 void WDG_IRQHandler(void)
88 {
89 duet_intrpt_enter();
90 NVIC_DisableIRQ(WDG_IRQn);
91 duet_intrpt_exit();
92 }
93
94 /**
95 * This function will initialize the on board CPU hardware watch dog
96 *
97 * @param[in] wdg the watch dog device
98 *
99 * @return 0 : on success, EIO : if an error occurred with any step
100 */
duet_wdg_init(duet_wdg_dev_t * wdg)101 int32_t duet_wdg_init(duet_wdg_dev_t *wdg)
102 {
103 uint32_t reg_value;
104 if (NULL == wdg) {
105 return EIO;
106 }
107 if (0 == wdg->port) {
108 // OPEN WDG CLOCK
109 reg_value = REG_RD(PERI_CLK_EN_REG1) & (~WDG_BUS_CLK_BIT);
110 REG_WR(PERI_CLK_EN_REG1, (reg_value | (WDG_BUS_CLK_BIT)));
111 // WDG CLOCK DIV SET
112 reg_value = REG_RD(WDG_APB_DIV_REG);
113 REG_WR(WDG_APB_DIV_REG, (reg_value | (WDG_APB_DIV << 4)));
114 hw_watchdog_reset(wdg->config.timeout * (SYSTEM_CLOCK / (WDG_APB_DIV + 1) / 1000 /
115 2)); // 1000 for ms, 2 for watchdog feature
116 // ENABLE WDG IRQ
117 reg_value = REG_RD(DUTE_IRQ_EN_REG) & (~WDG_IRQ_BIT);
118 REG_WR(DUTE_IRQ_EN_REG, (reg_value | (WDG_IRQ_BIT)));
119 NVIC_EnableIRQ(WDG_IRQn);
120 return 0;
121 } else {
122 return EIO;
123 }
124 }
125
126 /**
127 * Reload watchdog counter.
128 *
129 * @param[in] wdg the watch dog device
130 */
duet_wdg_reload(duet_wdg_dev_t * wdg)131 void duet_wdg_reload(duet_wdg_dev_t *wdg)
132 {
133 if (NULL == wdg) {
134 return;
135 }
136 if (0 == wdg->port) {
137 lega_rtos_declare_critical();
138 lega_rtos_enter_critical();
139 hw_watchdog_isr_clr();
140 NVIC_ClearPendingIRQ(WDG_IRQn);
141 NVIC_EnableIRQ(WDG_IRQn);
142 lega_rtos_exit_critical();
143 }
144 }
145
146 /**
147 * This function performs any platform-specific cleanup needed for hardware watch dog.
148 *
149 * @param[in] wdg the watch dog device
150 *
151 * @return 0 : on success, EIO : if an error occurred with any step
152 */
duet_wdg_finalize(duet_wdg_dev_t * wdg)153 int32_t duet_wdg_finalize(duet_wdg_dev_t *wdg)
154 {
155 uint32_t reg_value;
156 if (NULL == wdg) {
157 return EIO;
158 }
159 if (0 == wdg->port) {
160 // DIS WDG IRQ
161 reg_value = REG_RD(DUTE_IRQ_DIS_REG) & (~WDG_IRQ_BIT);
162 REG_WR(DUTE_IRQ_DIS_REG, (reg_value | (WDG_IRQ_BIT)));
163 NVIC_DisableIRQ(WDG_IRQn);
164 hw_watchdog_disable();
165 // Set WDG Clock Disable
166 reg_value = REG_RD(PERI_CLK_DIS_REG1) & (~WDG_BUS_CLK_BIT);
167 REG_WR(PERI_CLK_DIS_REG1, (reg_value | (WDG_BUS_CLK_BIT)));
168 return 0;
169 } else {
170 return EIO;
171 }
172 }
173
174