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