• 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         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