• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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