11bd4fe43Sopenharmony_ci/* 21bd4fe43Sopenharmony_ci * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. 31bd4fe43Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 41bd4fe43Sopenharmony_ci * you may not use this file except in compliance with the License. 51bd4fe43Sopenharmony_ci * You may obtain a copy of the License at 61bd4fe43Sopenharmony_ci * 71bd4fe43Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 81bd4fe43Sopenharmony_ci * 91bd4fe43Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 101bd4fe43Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 111bd4fe43Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 121bd4fe43Sopenharmony_ci * See the License for the specific language governing permissions and 131bd4fe43Sopenharmony_ci * limitations under the License. 141bd4fe43Sopenharmony_ci */ 151bd4fe43Sopenharmony_ci 161bd4fe43Sopenharmony_ci#include "device_resource_if.h" 171bd4fe43Sopenharmony_ci#include "hdf_device_desc.h" 181bd4fe43Sopenharmony_ci#include "hdf_log.h" 191bd4fe43Sopenharmony_ci#include "osal_io.h" 201bd4fe43Sopenharmony_ci#include "osal_mem.h" 211bd4fe43Sopenharmony_ci#include "osal_spinlock.h" 221bd4fe43Sopenharmony_ci#include "watchdog_core.h" 231bd4fe43Sopenharmony_ci#include "watchdog_if.h" 241bd4fe43Sopenharmony_ci 251bd4fe43Sopenharmony_ci#define HDF_LOG_TAG watchdog_hi35xx 261bd4fe43Sopenharmony_ci 271bd4fe43Sopenharmony_ci#define HIWDT_UNLOCK_VAL 0x1ACCE551 281bd4fe43Sopenharmony_ci#define HIWDT_EN_RST_INTR 0x03 291bd4fe43Sopenharmony_ci 301bd4fe43Sopenharmony_ci#define HIWDT_LOAD 0x000 311bd4fe43Sopenharmony_ci#define HIWDT_VALUE 0x004 321bd4fe43Sopenharmony_ci#define HIWDT_CTRL 0x008 331bd4fe43Sopenharmony_ci#define HIWDT_INTCLR 0x00C 341bd4fe43Sopenharmony_ci#define HIWDT_RIS 0x010 351bd4fe43Sopenharmony_ci#define HIWDT_MIS 0x014 361bd4fe43Sopenharmony_ci#define HIWDT_LOCK 0xC00 371bd4fe43Sopenharmony_ci 381bd4fe43Sopenharmony_cistruct Hi35xxWatchdog { 391bd4fe43Sopenharmony_ci struct WatchdogCntlr wdt; 401bd4fe43Sopenharmony_ci volatile unsigned char *regBase; 411bd4fe43Sopenharmony_ci uint32_t phyBase; 421bd4fe43Sopenharmony_ci uint32_t regStep; 431bd4fe43Sopenharmony_ci OsalSpinlock lock; 441bd4fe43Sopenharmony_ci}; 451bd4fe43Sopenharmony_ci 461bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogGetStatus(struct WatchdogCntlr *wdt, int32_t *status) 471bd4fe43Sopenharmony_ci{ 481bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 491bd4fe43Sopenharmony_ci unsigned int ctlValue; 501bd4fe43Sopenharmony_ci 511bd4fe43Sopenharmony_ci if (wdt == NULL) { 521bd4fe43Sopenharmony_ci HDF_LOGE("%s: wdt is NULL!", __func__); 531bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 541bd4fe43Sopenharmony_ci } 551bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)wdt; 561bd4fe43Sopenharmony_ci 571bd4fe43Sopenharmony_ci ctlValue = (unsigned int)OSAL_READL(hwdt->regBase + HIWDT_CTRL); 581bd4fe43Sopenharmony_ci *status = ((ctlValue & 0x01) == 0) ? WATCHDOG_STOP : WATCHDOG_START; 591bd4fe43Sopenharmony_ci return HDF_SUCCESS; 601bd4fe43Sopenharmony_ci} 611bd4fe43Sopenharmony_ci 621bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogStart(struct WatchdogCntlr *wdt) 631bd4fe43Sopenharmony_ci{ 641bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 651bd4fe43Sopenharmony_ci 661bd4fe43Sopenharmony_ci if (wdt == NULL) { 671bd4fe43Sopenharmony_ci HDF_LOGE("%s: wdt is NULL!", __func__); 681bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 691bd4fe43Sopenharmony_ci } 701bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)wdt; 711bd4fe43Sopenharmony_ci /* unlock watchdog */ 721bd4fe43Sopenharmony_ci OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK); 731bd4fe43Sopenharmony_ci /* 0x00: disable watchdog reset and interrupt */ 741bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_CTRL); 751bd4fe43Sopenharmony_ci /* 0x00: clear interrupt */ 761bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_INTCLR); 771bd4fe43Sopenharmony_ci /* 0x03: disable watchdog reset and interrupt */ 781bd4fe43Sopenharmony_ci OSAL_WRITEL(HIWDT_EN_RST_INTR, hwdt->regBase + HIWDT_CTRL); 791bd4fe43Sopenharmony_ci /* write any value to lock watchdog */ 801bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK); 811bd4fe43Sopenharmony_ci return HDF_SUCCESS; 821bd4fe43Sopenharmony_ci} 831bd4fe43Sopenharmony_ci 841bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogStop(struct WatchdogCntlr *wdt) 851bd4fe43Sopenharmony_ci{ 861bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 871bd4fe43Sopenharmony_ci 881bd4fe43Sopenharmony_ci if (wdt == NULL) { 891bd4fe43Sopenharmony_ci HDF_LOGE("%s: wdt is NULL!", __func__); 901bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 911bd4fe43Sopenharmony_ci } 921bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)wdt; 931bd4fe43Sopenharmony_ci 941bd4fe43Sopenharmony_ci /* unlock watchdog */ 951bd4fe43Sopenharmony_ci OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK); 961bd4fe43Sopenharmony_ci /* 0x00: disable watchdog reset and interrupt */ 971bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_CTRL); 981bd4fe43Sopenharmony_ci /* 0x00: clear interrupt */ 991bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_INTCLR); 1001bd4fe43Sopenharmony_ci /* write any value to lock watchdog */ 1011bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK); 1021bd4fe43Sopenharmony_ci 1031bd4fe43Sopenharmony_ci return HDF_SUCCESS; 1041bd4fe43Sopenharmony_ci} 1051bd4fe43Sopenharmony_ci 1061bd4fe43Sopenharmony_ci#define HIWDT_CLOCK_HZ (3 * 1000 * 1000) 1071bd4fe43Sopenharmony_ci 1081bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogSetTimeout(struct WatchdogCntlr *wdt, uint32_t seconds) 1091bd4fe43Sopenharmony_ci{ 1101bd4fe43Sopenharmony_ci unsigned int value; 1111bd4fe43Sopenharmony_ci unsigned int maxCnt = ~0x00; 1121bd4fe43Sopenharmony_ci unsigned int maxSeconds = maxCnt / HIWDT_CLOCK_HZ; 1131bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 1141bd4fe43Sopenharmony_ci 1151bd4fe43Sopenharmony_ci if (seconds == 0 || seconds > maxSeconds) { 1161bd4fe43Sopenharmony_ci value = maxCnt; 1171bd4fe43Sopenharmony_ci } else { 1181bd4fe43Sopenharmony_ci value = seconds * HIWDT_CLOCK_HZ; 1191bd4fe43Sopenharmony_ci } 1201bd4fe43Sopenharmony_ci 1211bd4fe43Sopenharmony_ci if (wdt == NULL) { 1221bd4fe43Sopenharmony_ci HDF_LOGE("%s: wdt is NULL!", __func__); 1231bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 1241bd4fe43Sopenharmony_ci } 1251bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)wdt; 1261bd4fe43Sopenharmony_ci 1271bd4fe43Sopenharmony_ci /* unlock watchdog */ 1281bd4fe43Sopenharmony_ci OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK); 1291bd4fe43Sopenharmony_ci OSAL_WRITEL(value, hwdt->regBase + HIWDT_LOAD); 1301bd4fe43Sopenharmony_ci OSAL_WRITEL(value, hwdt->regBase + HIWDT_VALUE); 1311bd4fe43Sopenharmony_ci /* write any value to lock watchdog */ 1321bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK); 1331bd4fe43Sopenharmony_ci 1341bd4fe43Sopenharmony_ci return HDF_SUCCESS; 1351bd4fe43Sopenharmony_ci} 1361bd4fe43Sopenharmony_ci 1371bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogGetTimeout(struct WatchdogCntlr *wdt, uint32_t *seconds) 1381bd4fe43Sopenharmony_ci{ 1391bd4fe43Sopenharmony_ci unsigned int value; 1401bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 1411bd4fe43Sopenharmony_ci 1421bd4fe43Sopenharmony_ci if (wdt == NULL) { 1431bd4fe43Sopenharmony_ci HDF_LOGE("%s: wdt is NULL!", __func__); 1441bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 1451bd4fe43Sopenharmony_ci } 1461bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)wdt; 1471bd4fe43Sopenharmony_ci 1481bd4fe43Sopenharmony_ci value = (unsigned int)OSAL_READL(hwdt->regBase + HIWDT_LOAD); 1491bd4fe43Sopenharmony_ci *seconds = value / HIWDT_CLOCK_HZ; 1501bd4fe43Sopenharmony_ci return HDF_SUCCESS; 1511bd4fe43Sopenharmony_ci} 1521bd4fe43Sopenharmony_ci 1531bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogFeed(struct WatchdogCntlr *wdt) 1541bd4fe43Sopenharmony_ci{ 1551bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 1561bd4fe43Sopenharmony_ci 1571bd4fe43Sopenharmony_ci if (wdt == NULL) { 1581bd4fe43Sopenharmony_ci HDF_LOGE("%s: wdt is NULL!", __func__); 1591bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 1601bd4fe43Sopenharmony_ci } 1611bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)wdt; 1621bd4fe43Sopenharmony_ci 1631bd4fe43Sopenharmony_ci /* unlock watchdog */ 1641bd4fe43Sopenharmony_ci OSAL_WRITEL(HIWDT_UNLOCK_VAL, hwdt->regBase + HIWDT_LOCK); 1651bd4fe43Sopenharmony_ci /* 0x00: clear interrupt */ 1661bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_INTCLR); 1671bd4fe43Sopenharmony_ci /* write any value to lock watchdog */ 1681bd4fe43Sopenharmony_ci OSAL_WRITEL(0x00, hwdt->regBase + HIWDT_LOCK); 1691bd4fe43Sopenharmony_ci 1701bd4fe43Sopenharmony_ci return HDF_SUCCESS; 1711bd4fe43Sopenharmony_ci} 1721bd4fe43Sopenharmony_ci 1731bd4fe43Sopenharmony_cistatic struct WatchdogMethod g_method = { 1741bd4fe43Sopenharmony_ci .getStatus = Hi35xxWatchdogGetStatus, 1751bd4fe43Sopenharmony_ci .start = Hi35xxWatchdogStart, 1761bd4fe43Sopenharmony_ci .stop = Hi35xxWatchdogStop, 1771bd4fe43Sopenharmony_ci .setTimeout = Hi35xxWatchdogSetTimeout, 1781bd4fe43Sopenharmony_ci .getTimeout = Hi35xxWatchdogGetTimeout, 1791bd4fe43Sopenharmony_ci .feed = Hi35xxWatchdogFeed, 1801bd4fe43Sopenharmony_ci}; 1811bd4fe43Sopenharmony_ci 1821bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogReadDrs(struct Hi35xxWatchdog *hwdt, const struct DeviceResourceNode *node) 1831bd4fe43Sopenharmony_ci{ 1841bd4fe43Sopenharmony_ci int32_t ret; 1851bd4fe43Sopenharmony_ci struct DeviceResourceIface *drsOps = NULL; 1861bd4fe43Sopenharmony_ci 1871bd4fe43Sopenharmony_ci drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 1881bd4fe43Sopenharmony_ci if (drsOps == NULL || drsOps->GetUint32 == NULL) { 1891bd4fe43Sopenharmony_ci HDF_LOGE("%s: invalid drs ops!", __func__); 1901bd4fe43Sopenharmony_ci return HDF_FAILURE; 1911bd4fe43Sopenharmony_ci } 1921bd4fe43Sopenharmony_ci 1931bd4fe43Sopenharmony_ci ret = drsOps->GetUint32(node, "regBase", &hwdt->phyBase, 0); 1941bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 1951bd4fe43Sopenharmony_ci HDF_LOGE("%s: read regBase fail!", __func__); 1961bd4fe43Sopenharmony_ci return ret; 1971bd4fe43Sopenharmony_ci } 1981bd4fe43Sopenharmony_ci 1991bd4fe43Sopenharmony_ci ret = drsOps->GetUint32(node, "regStep", &hwdt->regStep, 0); 2001bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 2011bd4fe43Sopenharmony_ci HDF_LOGE("%s: read regStep fail!", __func__); 2021bd4fe43Sopenharmony_ci return ret; 2031bd4fe43Sopenharmony_ci } 2041bd4fe43Sopenharmony_ci 2051bd4fe43Sopenharmony_ci return HDF_SUCCESS; 2061bd4fe43Sopenharmony_ci} 2071bd4fe43Sopenharmony_ci 2081bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogBind(struct HdfDeviceObject *device) 2091bd4fe43Sopenharmony_ci{ 2101bd4fe43Sopenharmony_ci int32_t ret; 2111bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 2121bd4fe43Sopenharmony_ci 2131bd4fe43Sopenharmony_ci if (device == NULL || device->property == NULL) { 2141bd4fe43Sopenharmony_ci HDF_LOGE("%s: device or property is null!", __func__); 2151bd4fe43Sopenharmony_ci return HDF_ERR_INVALID_OBJECT; 2161bd4fe43Sopenharmony_ci } 2171bd4fe43Sopenharmony_ci 2181bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)OsalMemCalloc(sizeof(*hwdt)); 2191bd4fe43Sopenharmony_ci if (hwdt == NULL) { 2201bd4fe43Sopenharmony_ci HDF_LOGE("%s: malloc hwdt fail!", __func__); 2211bd4fe43Sopenharmony_ci return HDF_ERR_MALLOC_FAIL; 2221bd4fe43Sopenharmony_ci } 2231bd4fe43Sopenharmony_ci 2241bd4fe43Sopenharmony_ci ret = Hi35xxWatchdogReadDrs(hwdt, device->property); 2251bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 2261bd4fe43Sopenharmony_ci HDF_LOGE("%s: read drs fail:%d", __func__, ret); 2271bd4fe43Sopenharmony_ci OsalMemFree(hwdt); 2281bd4fe43Sopenharmony_ci return ret; 2291bd4fe43Sopenharmony_ci } 2301bd4fe43Sopenharmony_ci 2311bd4fe43Sopenharmony_ci hwdt->regBase = OsalIoRemap(hwdt->phyBase, hwdt->regStep); 2321bd4fe43Sopenharmony_ci if (hwdt->regBase == NULL) { 2331bd4fe43Sopenharmony_ci HDF_LOGE("%s: ioremap regbase fail!", __func__); 2341bd4fe43Sopenharmony_ci OsalMemFree(hwdt); 2351bd4fe43Sopenharmony_ci return HDF_ERR_IO; 2361bd4fe43Sopenharmony_ci } 2371bd4fe43Sopenharmony_ci 2381bd4fe43Sopenharmony_ci hwdt->wdt.priv = (void *)device->property; 2391bd4fe43Sopenharmony_ci hwdt->wdt.ops = &g_method; 2401bd4fe43Sopenharmony_ci hwdt->wdt.device = device; 2411bd4fe43Sopenharmony_ci ret = WatchdogCntlrAdd(&hwdt->wdt); 2421bd4fe43Sopenharmony_ci if (ret != HDF_SUCCESS) { 2431bd4fe43Sopenharmony_ci HDF_LOGE("%s: err add watchdog:%d", __func__, ret); 2441bd4fe43Sopenharmony_ci OsalIoUnmap((void *)hwdt->regBase); 2451bd4fe43Sopenharmony_ci OsalMemFree(hwdt); 2461bd4fe43Sopenharmony_ci return ret; 2471bd4fe43Sopenharmony_ci } 2481bd4fe43Sopenharmony_ci HDF_LOGI("%s: dev service %s bind success!", __func__, HdfDeviceGetServiceName(device)); 2491bd4fe43Sopenharmony_ci return HDF_SUCCESS; 2501bd4fe43Sopenharmony_ci} 2511bd4fe43Sopenharmony_ci 2521bd4fe43Sopenharmony_cistatic int32_t Hi35xxWatchdogInit(struct HdfDeviceObject *device) 2531bd4fe43Sopenharmony_ci{ 2541bd4fe43Sopenharmony_ci (void)device; 2551bd4fe43Sopenharmony_ci return HDF_SUCCESS; 2561bd4fe43Sopenharmony_ci} 2571bd4fe43Sopenharmony_ci 2581bd4fe43Sopenharmony_cistatic void Hi35xxWatchdogRelease(struct HdfDeviceObject *device) 2591bd4fe43Sopenharmony_ci{ 2601bd4fe43Sopenharmony_ci struct WatchdogCntlr *wdt = NULL; 2611bd4fe43Sopenharmony_ci struct Hi35xxWatchdog *hwdt = NULL; 2621bd4fe43Sopenharmony_ci 2631bd4fe43Sopenharmony_ci HDF_LOGI("%s: enter", __func__); 2641bd4fe43Sopenharmony_ci if (device == NULL) { 2651bd4fe43Sopenharmony_ci HDF_LOGE("%s: device is NULL!", __func__); 2661bd4fe43Sopenharmony_ci return; 2671bd4fe43Sopenharmony_ci } 2681bd4fe43Sopenharmony_ci 2691bd4fe43Sopenharmony_ci wdt = WatchdogCntlrFromDevice(device); 2701bd4fe43Sopenharmony_ci if (wdt == NULL) { 2711bd4fe43Sopenharmony_ci HDF_LOGE("%s: wdt is NULL!", __func__); 2721bd4fe43Sopenharmony_ci return; 2731bd4fe43Sopenharmony_ci } 2741bd4fe43Sopenharmony_ci WatchdogCntlrRemove(wdt); 2751bd4fe43Sopenharmony_ci 2761bd4fe43Sopenharmony_ci hwdt = (struct Hi35xxWatchdog *)wdt; 2771bd4fe43Sopenharmony_ci if (hwdt->regBase != NULL) { 2781bd4fe43Sopenharmony_ci OsalIoUnmap((void *)hwdt->regBase); 2791bd4fe43Sopenharmony_ci hwdt->regBase = NULL; 2801bd4fe43Sopenharmony_ci } 2811bd4fe43Sopenharmony_ci OsalMemFree(hwdt); 2821bd4fe43Sopenharmony_ci} 2831bd4fe43Sopenharmony_ci 2841bd4fe43Sopenharmony_cistruct HdfDriverEntry g_watchdogDriverEntry = { 2851bd4fe43Sopenharmony_ci .moduleVersion = 1, 2861bd4fe43Sopenharmony_ci .Bind = Hi35xxWatchdogBind, 2871bd4fe43Sopenharmony_ci .Init = Hi35xxWatchdogInit, 2881bd4fe43Sopenharmony_ci .Release = Hi35xxWatchdogRelease, 2891bd4fe43Sopenharmony_ci .moduleName = "HDF_PLATFORM_WATCHDOG", 2901bd4fe43Sopenharmony_ci}; 2911bd4fe43Sopenharmony_ciHDF_INIT(g_watchdogDriverEntry); 292