1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 "device_resource_if.h"
17 #include "hdf_device_desc.h"
18 #include "hdf_log.h"
19 #include "osal_io.h"
20 #include "osal_mem.h"
21 #include "osal_spinlock.h"
22 #include "watchdog_core.h"
23 #include "watchdog_if.h"
24
25 #define HDF_LOG_TAG watchdog_hi35xx
26
27 #define HIWDT_UNLOCK_VAL 0x1ACCE551
28 #define HIWDT_EN_RST_INTR 0x03
29
30 #define HIWDT_LOAD 0x000
31 #define HIWDT_VALUE 0x004
32 #define HIWDT_CTRL 0x008
33 #define HIWDT_INTCLR 0x00C
34 #define HIWDT_RIS 0x010
35 #define HIWDT_MIS 0x014
36 #define HIWDT_LOCK 0xC00
37
38 struct Hi35xxWatchdog {
39 struct WatchdogCntlr wdt;
40 volatile unsigned char *regBase;
41 uint32_t phyBase;
42 uint32_t regStep;
43 OsalSpinlock lock;
44 };
45
Hi35xxWatchdogGetStatus(struct WatchdogCntlr * wdt,int32_t * status)46 static int32_t Hi35xxWatchdogGetStatus(struct WatchdogCntlr *wdt, int32_t *status)
47 {
48 struct Hi35xxWatchdog *hwdt = NULL;
49 unsigned int ctlValue;
50
51 if (wdt == NULL) {
52 return HDF_ERR_INVALID_OBJECT;
53 }
54 hwdt = (struct Hi35xxWatchdog *)wdt;
55
56 ctlValue = (unsigned int)OSAL_READL(hwdt->regBase + HIWDT_CTRL);
57 *status = ((ctlValue & 0x01) == 0) ? WATCHDOG_STOP : WATCHDOG_START;
58 return HDF_SUCCESS;
59 }
60
Hi35xxWatchdogStart(struct WatchdogCntlr * wdt)61 static int32_t Hi35xxWatchdogStart(struct WatchdogCntlr *wdt)
62 {
63 struct Hi35xxWatchdog *hwdt = NULL;
64
65 if (wdt == NULL) {
66 return HDF_ERR_INVALID_OBJECT;
67 }
68 hwdt = (struct Hi35xxWatchdog *)wdt;
69 /* unlock watchdog */
70 OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK);
71 /* 0x00: disable watchdog reset and interrupt */
72 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_CTRL);
73 /* 0x00: clear interrupt */
74 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_INTCLR);
75 /* 0x03: disable watchdog reset and interrupt */
76 OSAL_WRITEL(HIWDT_EN_RST_INTR, hwdt->regBase + HIWDT_CTRL);
77 /* write any value to lock watchdog */
78 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK);
79 return HDF_SUCCESS;
80 }
81
Hi35xxWatchdogStop(struct WatchdogCntlr * wdt)82 static int32_t Hi35xxWatchdogStop(struct WatchdogCntlr *wdt)
83 {
84 struct Hi35xxWatchdog *hwdt = NULL;
85
86 if (wdt == NULL) {
87 return HDF_ERR_INVALID_OBJECT;
88 }
89 hwdt = (struct Hi35xxWatchdog *)wdt;
90
91 /* unlock watchdog */
92 OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK);
93 /* 0x00: disable watchdog reset and interrupt */
94 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_CTRL);
95 /* 0x00: clear interrupt */
96 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_INTCLR);
97 /* write any value to lock watchdog */
98 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK);
99
100 return HDF_SUCCESS;
101 }
102
103 #define HIWDT_CLOCK_HZ (3 * 1000 * 1000)
104
Hi35xxWatchdogSetTimeout(struct WatchdogCntlr * wdt,uint32_t seconds)105 static int32_t Hi35xxWatchdogSetTimeout(struct WatchdogCntlr *wdt, uint32_t seconds)
106 {
107 unsigned int value;
108 unsigned int maxCnt = ~0x00;
109 unsigned int maxSeconds = maxCnt / HIWDT_CLOCK_HZ;
110 struct Hi35xxWatchdog *hwdt = NULL;
111
112 if (seconds == 0 || seconds > maxSeconds) {
113 value = maxCnt;
114 } else {
115 value = seconds * HIWDT_CLOCK_HZ;
116 }
117
118 if (wdt == NULL) {
119 return HDF_ERR_INVALID_OBJECT;
120 }
121 hwdt = (struct Hi35xxWatchdog *)wdt;
122
123 /* unlock watchdog */
124 OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK);
125 OSAL_WRITEL(value, hwdt->regBase + HIWDT_LOAD);
126 OSAL_WRITEL(value, hwdt->regBase + HIWDT_VALUE);
127 /* write any value to lock watchdog */
128 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK);
129
130 return HDF_SUCCESS;
131 }
132
Hi35xxWatchdogGetTimeout(struct WatchdogCntlr * wdt,uint32_t * seconds)133 static int32_t Hi35xxWatchdogGetTimeout(struct WatchdogCntlr *wdt, uint32_t *seconds)
134 {
135 unsigned int value;
136 struct Hi35xxWatchdog *hwdt = NULL;
137
138 if (wdt == NULL) {
139 return HDF_ERR_INVALID_OBJECT;
140 }
141 hwdt = (struct Hi35xxWatchdog *)wdt;
142
143 value = (unsigned int)OSAL_READL(hwdt->regBase + HIWDT_LOAD);
144 *seconds = value / HIWDT_CLOCK_HZ;
145 return HDF_SUCCESS;
146 }
147
Hi35xxWatchdogFeed(struct WatchdogCntlr * wdt)148 static int32_t Hi35xxWatchdogFeed(struct WatchdogCntlr *wdt)
149 {
150 struct Hi35xxWatchdog *hwdt = NULL;
151
152 if (wdt == NULL) {
153 return HDF_ERR_INVALID_OBJECT;
154 }
155 hwdt = (struct Hi35xxWatchdog *)wdt;
156
157 /* unlock watchdog */
158 OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK);
159 /* 0x00: clear interrupt */
160 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_INTCLR);
161 /* write any value to lock watchdog */
162 OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK);
163
164 return HDF_SUCCESS;
165 }
166
167 static struct WatchdogMethod g_method = {
168 .getStatus = Hi35xxWatchdogGetStatus,
169 .start = Hi35xxWatchdogStart,
170 .stop = Hi35xxWatchdogStop,
171 .setTimeout = Hi35xxWatchdogSetTimeout,
172 .getTimeout = Hi35xxWatchdogGetTimeout,
173 .feed = Hi35xxWatchdogFeed,
174 };
175
Hi35xxWatchdogReadDrs(struct Hi35xxWatchdog * hwdt,const struct DeviceResourceNode * node)176 static int32_t Hi35xxWatchdogReadDrs(struct Hi35xxWatchdog *hwdt, const struct DeviceResourceNode *node)
177 {
178 int32_t ret;
179 struct DeviceResourceIface *drsOps = NULL;
180
181 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
182 if (drsOps == NULL || drsOps->GetUint32 == NULL) {
183 HDF_LOGE("%s: invalid drs ops!", __func__);
184 return HDF_FAILURE;
185 }
186
187 ret = drsOps->GetUint32(node, "regBase", &hwdt->phyBase, 0);
188 if (ret != HDF_SUCCESS) {
189 HDF_LOGE("%s: read regBase fail!", __func__);
190 return ret;
191 }
192
193 ret = drsOps->GetUint32(node, "regStep", &hwdt->regStep, 0);
194 if (ret != HDF_SUCCESS) {
195 HDF_LOGE("%s: read regStep fail!", __func__);
196 return ret;
197 }
198
199 return HDF_SUCCESS;
200 }
201
Hi35xxWatchdogBind(struct HdfDeviceObject * device)202 static int32_t Hi35xxWatchdogBind(struct HdfDeviceObject *device)
203 {
204 int32_t ret;
205 struct Hi35xxWatchdog *hwdt = NULL;
206
207 HDF_LOGI("%s: Enter", __func__);
208 if (device == NULL || device->property == NULL) {
209 HDF_LOGE("%s: device or property is null!", __func__);
210 return HDF_ERR_INVALID_OBJECT;
211 }
212
213 hwdt = (struct Hi35xxWatchdog *)OsalMemCalloc(sizeof(*hwdt));
214 if (hwdt == NULL) {
215 HDF_LOGE("%s: malloc hwdt fail!", __func__);
216 return HDF_ERR_MALLOC_FAIL;
217 }
218
219 ret = Hi35xxWatchdogReadDrs(hwdt, device->property);
220 if (ret != HDF_SUCCESS) {
221 HDF_LOGE("%s: read drs fail:%d", __func__, ret);
222 OsalMemFree(hwdt);
223 return ret;
224 }
225
226 hwdt->regBase = OsalIoRemap(hwdt->phyBase, hwdt->regStep);
227 if (hwdt->regBase == NULL) {
228 HDF_LOGE("%s: ioremap regbase fail!", __func__);
229 OsalMemFree(hwdt);
230 return HDF_ERR_IO;
231 }
232
233 hwdt->wdt.priv = (void *)device->property;
234 hwdt->wdt.ops = &g_method;
235 hwdt->wdt.device = device;
236 ret = WatchdogCntlrAdd(&hwdt->wdt);
237 if (ret != HDF_SUCCESS) {
238 HDF_LOGE("%s: err add watchdog:%d", __func__, ret);
239 OsalIoUnmap((void *)hwdt->regBase);
240 OsalMemFree(hwdt);
241 return ret;
242 }
243 HDF_LOGI("%s: dev service %s init success!", __func__, HdfDeviceGetServiceName(device));
244 return HDF_SUCCESS;
245 }
246
Hi35xxWatchdogInit(struct HdfDeviceObject * device)247 static int32_t Hi35xxWatchdogInit(struct HdfDeviceObject *device)
248 {
249 (void)device;
250 return HDF_SUCCESS;
251 }
252
Hi35xxWatchdogRelease(struct HdfDeviceObject * device)253 static void Hi35xxWatchdogRelease(struct HdfDeviceObject *device)
254 {
255 struct WatchdogCntlr *wdt = NULL;
256 struct Hi35xxWatchdog *hwdt = NULL;
257
258 HDF_LOGI("%s: enter", __func__);
259 if (device == NULL) {
260 return;
261 }
262
263 wdt = WatchdogCntlrFromDevice(device);
264 if (wdt == NULL) {
265 return;
266 }
267 WatchdogCntlrRemove(wdt);
268
269 hwdt = (struct Hi35xxWatchdog *)wdt;
270 if (hwdt->regBase != NULL) {
271 OsalIoUnmap((void *)hwdt->regBase);
272 hwdt->regBase = NULL;
273 }
274 OsalMemFree(hwdt);
275 }
276
277 struct HdfDriverEntry g_watchdogDriverEntry = {
278 .moduleVersion = 1,
279 .Bind = Hi35xxWatchdogBind,
280 .Init = Hi35xxWatchdogInit,
281 .Release = Hi35xxWatchdogRelease,
282 .moduleName = "HDF_PLATFORM_WATCHDOG",
283 };
284 HDF_INIT(g_watchdogDriverEntry);
285