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