/* * Copyright (c) 2025, LISTENAI * * SPDX-License-Identifier: Apache-2.0 */ /** * @file lisa_wdt_arcs.c * @brief LISA WDT ARCS 平台适配层 * * 此文件实现 ARCS 芯片平台的看门狗定时器硬件适配 */ #include "lisa_wdt.h" #include "Driver_WDT.h" #include "arcs_ap.h" #include #include #include #define LOG_TAG "lisa_wdt_arcs" #include #define DEVICE_LOCK(priv) \ do { \ if (priv->mutex) { \ lisa_mutex_lock(priv->mutex, LISA_OS_WAIT_FOREVER); \ } \ } while (0) #define DEVICE_UNLOCK(priv) \ do { \ if (priv->mutex) { \ lisa_mutex_unlock(priv->mutex); \ } \ } while (0) /* ===== WDT 时钟频率定义 ===== */ #define WDT_CLK_32K_HZ 32000UL /* 32K 时钟频率 (Hz) */ #define WDT_CLK_APB_HZ PCLKFREQ() /* APB 时钟频率 (Hz),运行时获取 */ /* ===== WDT 设备私有数据 ===== */ typedef struct { void *hal_handler; /* HAL WDT 句柄 */ lisa_mutex_t *mutex; /* 互斥锁 */ lisa_wdt_config_t config; /* 当前配置 */ lisa_wdt_state_t state; /* 当前状态 */ lisa_wdt_callback_t callback; /* 超时回调函数 */ void *user_data; /* 用户数据 */ hal_driver_wdt_clk_src clk_src; /* 时钟源 */ hal_driver_wdt_int_time int_time; /* 中断时间配置 */ hal_driver_wdt_rst_time rst_time; /* 复位时间配置 */ uint32_t configured_timeout_ms; /* 已配置的超时时间(毫秒)*/ } lisa_wdt_priv_t; /* ===== WDT 设备静态实例 ===== */ static lisa_wdt_priv_t wdt0_priv; /* ===== 内部辅助函数 ===== */ /** * @brief HAL中断回调函数 * * 注意:此函数在中断上下文中执行,应尽量简短快速 * 不要在中断回调中调用可能阻塞的函数(如mutex操作) */ static void wdt_hal_irq_callback(void *workspace) { lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)workspace; if (!priv) { LISA_LOGE(LOG_TAG, "[IRQ] WDT callback: invalid workspace"); return; } /* 更新状态为已超时(在中断上下文中,直接赋值是安全的) */ priv->state = LISA_WDT_STATE_EXPIRED; LISA_LOGW(LOG_TAG, "[IRQ] WDT interrupt triggered! State updated to EXPIRED"); /* 调用用户回调函数 */ if (priv->callback) { LISA_LOGD(LOG_TAG, "[IRQ] Calling user callback"); priv->callback(priv->user_data); LISA_LOGD(LOG_TAG, "[IRQ] User callback returned"); } else { LISA_LOGW(LOG_TAG, "[IRQ] WDT interrupt triggered but no user callback registered"); } } /** * @brief 将毫秒转换为中断时间枚举值 * * @param timeout_ms 超时时间(毫秒) * @param clk_src 时钟源 * @param int_time 输出参数,中断时间枚举值 * * @return 0 成功 * @return LISA_DEVICE_ERR_RANGE 超时时间超出范围 */ static int ms_to_int_time(uint32_t timeout_ms, hal_driver_wdt_clk_src clk_src, hal_driver_wdt_int_time *int_time) { uint32_t clk_freq = (clk_src == hal_driver_wdt_clk_src_32k) ? WDT_CLK_32K_HZ : WDT_CLK_APB_HZ; uint64_t clk_period_ns = 1000000000ULL / clk_freq; /* 时钟周期(纳秒)*/ uint64_t timeout_ns = (uint64_t)timeout_ms * 1000000ULL; /* 超时时间(纳秒)*/ uint64_t clk_count = timeout_ns / clk_period_ns; /* 需要的时钟周期数 */ /* 查找大于等于所需周期数的最小 2^N 值(向上取整) */ /* 这样可以确保实际超时时间不会小于配置的时间 */ if (clk_count <= (1ULL << 6)) { *int_time = hal_driver_wdt_int_time_6; } else if (clk_count <= (1ULL << 8)) { *int_time = hal_driver_wdt_int_time_8; } else if (clk_count <= (1ULL << 10)) { *int_time = hal_driver_wdt_int_time_10; } else if (clk_count <= (1ULL << 11)) { *int_time = hal_driver_wdt_int_time_11; } else if (clk_count <= (1ULL << 12)) { *int_time = hal_driver_wdt_int_time_12; } else if (clk_count <= (1ULL << 13)) { *int_time = hal_driver_wdt_int_time_13; } else if (clk_count <= (1ULL << 14)) { *int_time = hal_driver_wdt_int_time_14; } else if (clk_count <= (1ULL << 15)) { *int_time = hal_driver_wdt_int_time_15; } else if (clk_count <= (1ULL << 17)) { *int_time = hal_driver_wdt_int_time_17; } else if (clk_count <= (1ULL << 19)) { *int_time = hal_driver_wdt_int_time_19; } else if (clk_count <= (1ULL << 21)) { *int_time = hal_driver_wdt_int_time_21; } else if (clk_count <= (1ULL << 23)) { *int_time = hal_driver_wdt_int_time_23; } else if (clk_count <= (1ULL << 25)) { *int_time = hal_driver_wdt_int_time_25; } else if (clk_count <= (1ULL << 27)) { *int_time = hal_driver_wdt_int_time_27; } else if (clk_count <= (1ULL << 29)) { *int_time = hal_driver_wdt_int_time_29; } else if (clk_count <= (1ULL << 31)) { *int_time = hal_driver_wdt_int_time_31; } else { return LISA_DEVICE_ERR_RANGE; } /* 计算实际超时时间用于日志 - 需要根据枚举值映射到实际的2^N值 */ uint64_t actual_clk_count; int exp; switch ((int)*int_time) { case 0: exp = 6; break; /* int_time_6 */ case 1: exp = 8; break; /* int_time_8 */ case 2: exp = 10; break; /* int_time_10 */ case 3: exp = 11; break; /* int_time_11 */ case 4: exp = 12; break; /* int_time_12 */ case 5: exp = 13; break; /* int_time_13 */ case 6: exp = 14; break; /* int_time_14 */ case 7: exp = 15; break; /* int_time_15 */ case 8: exp = 17; break; /* int_time_17 */ case 9: exp = 19; break; /* int_time_19 */ case 10: exp = 21; break; /* int_time_21 */ case 11: exp = 23; break; /* int_time_23 */ case 12: exp = 25; break; /* int_time_25 */ case 13: exp = 27; break; /* int_time_27 */ case 14: exp = 29; break; /* int_time_29 */ case 15: exp = 31; break; /* int_time_31 */ default: exp = 6; break; } actual_clk_count = (1ULL << exp); uint64_t actual_timeout_ms = (actual_clk_count * clk_period_ns) / 1000000ULL; LISA_LOGD(LOG_TAG, "ms_to_int_time: requested=%lu ms, clk_freq=%lu Hz, clk_count=%llu, selected=int_time_%d (2^%d=%llu cycles, ≈%llu ms)", timeout_ms, clk_freq, clk_count, (int)*int_time, exp, actual_clk_count, actual_timeout_ms); return LISA_DEVICE_OK; } /** * @brief 将毫秒转换为复位时间枚举值 * * @param timeout_ms 超时时间(毫秒) * @param clk_src 时钟源 * @param rst_time 输出参数,复位时间枚举值 * * @return 0 成功 * @return LISA_DEVICE_ERR_RANGE 超时时间超出范围 */ static int ms_to_rst_time(uint32_t timeout_ms, hal_driver_wdt_clk_src clk_src, hal_driver_wdt_rst_time *rst_time) { uint32_t clk_freq = (clk_src == hal_driver_wdt_clk_src_32k) ? WDT_CLK_32K_HZ : WDT_CLK_APB_HZ; uint64_t clk_period_ns = 1000000000ULL / clk_freq; /* 时钟周期(纳秒)*/ uint64_t timeout_ns = (uint64_t)timeout_ms * 1000000ULL; /* 超时时间(纳秒)*/ uint64_t clk_count = timeout_ns / clk_period_ns; /* 需要的时钟周期数 */ /* 查找大于等于所需周期数的最小 2^N 值(向上取整) */ /* 这样可以确保实际超时时间不会小于配置的时间 */ if (clk_count <= (1ULL << 7)) { *rst_time = hal_driver_wdt_rst_time_7; } else if (clk_count <= (1ULL << 8)) { *rst_time = hal_driver_wdt_rst_time_8; } else if (clk_count <= (1ULL << 9)) { *rst_time = hal_driver_wdt_rst_time_9; } else if (clk_count <= (1ULL << 10)) { *rst_time = hal_driver_wdt_rst_time_10; } else if (clk_count <= (1ULL << 11)) { *rst_time = hal_driver_wdt_rst_time_11; } else if (clk_count <= (1ULL << 12)) { *rst_time = hal_driver_wdt_rst_time_12; } else if (clk_count <= (1ULL << 13)) { *rst_time = hal_driver_wdt_rst_time_13; } else if (clk_count <= (1ULL << 14)) { *rst_time = hal_driver_wdt_rst_time_14; } else { return LISA_DEVICE_ERR_RANGE; } /* 计算实际超时时间用于日志 - rst_time枚举值直接对应2^(7+枚举值) */ int exp = 7 + (int)*rst_time; uint64_t actual_clk_count = (1ULL << exp); uint64_t actual_timeout_ms = (actual_clk_count * clk_period_ns) / 1000000ULL; LISA_LOGD(LOG_TAG, "ms_to_rst_time: requested=%lu ms, clk_freq=%lu Hz, clk_count=%llu, selected=rst_time_%d (2^%d=%llu cycles, ≈%llu ms)", timeout_ms, clk_freq, clk_count, (int)*rst_time, exp, actual_clk_count, actual_timeout_ms); return LISA_DEVICE_OK; } /* ===== ARCS平台WDT实现函数 ===== */ /** * @brief 配置看门狗设备 */ static int arcs_wdt_setup(lisa_device_t *dev, const lisa_wdt_config_t *config) { if (!lisa_device_is_initialized(dev) || !config) { return LISA_DEVICE_ERR_INVALID; } /* 验证配置参数 */ if (config->int_timeout_ms == 0) { LISA_LOGE(LOG_TAG, "Invalid int_timeout_ms: %lu ms", config->int_timeout_ms); return LISA_DEVICE_ERR_INVALID; } lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)dev->priv_data; DEVICE_LOCK(priv); /* 如果看门狗正在运行,先停止 */ if (priv->state == LISA_WDT_STATE_RUNNING) { if (WDT_Disable(priv->hal_handler) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to disable WDT before setup"); return LISA_DEVICE_ERR_IO; } priv->state = LISA_WDT_STATE_IDLE; } /* 保存配置 */ priv->config = *config; /* 默认使用 32K 时钟源 */ priv->clk_src = hal_driver_wdt_clk_src_32k; /* 计算中断时间(从启动开始) */ if (ms_to_int_time(config->int_timeout_ms, priv->clk_src, &priv->int_time) != LISA_DEVICE_OK) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Invalid interrupt time for int_timeout_ms: %lu ms", config->int_timeout_ms); return LISA_DEVICE_ERR_RANGE; } /* 计算复位时间(从中断触发后开始计算,到系统复位) */ /* 注意:根据HAL库注释,rst_time是复位阶段的时间,从中断触发后开始计算 */ /* HAL库示例:int_time=15(1s), rst_time=14(0.5s),时间线:启动->[1s]中断->[0.5s]复位 */ if (ms_to_rst_time(config->rst_timeout_ms, priv->clk_src, &priv->rst_time) != LISA_DEVICE_OK) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Invalid reset time for rst_timeout_ms: %lu ms", config->rst_timeout_ms); return LISA_DEVICE_ERR_RANGE; } /* 确保中断回调已注册(在配置之前注册,确保配置时回调已存在) */ /* 注意:即使没有用户回调,我们也需要注册HAL回调来更新状态 */ if (WDT_Initialize(priv->hal_handler, wdt_hal_irq_callback, priv) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to register WDT callback before configuration"); return LISA_DEVICE_ERR_IO; } LISA_LOGD(LOG_TAG, "WDT callback registered: %p, workspace: %p", wdt_hal_irq_callback, priv); /* 配置 HAL WDT */ hal_driver_wdt_cfg_t hal_cfg = { .clk_src = priv->clk_src, .int_time = priv->int_time, .rst_time = priv->rst_time, }; if (WDT_Control(priv->hal_handler, &hal_cfg) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to configure WDT"); return LISA_DEVICE_ERR_IO; } LISA_LOGD(LOG_TAG, "WDT configured: int_time=%d, rst_time=%d", priv->int_time, priv->rst_time); /* 保存配置的总超时时间(用于剩余时间查询) */ priv->configured_timeout_ms = config->int_timeout_ms; priv->state = LISA_WDT_STATE_IDLE; DEVICE_UNLOCK(priv); uint32_t total_rst_timeout_ms = config->int_timeout_ms + config->rst_timeout_ms; LISA_LOGI(LOG_TAG, "WDT configured: int_timeout=%lu ms, rst_timeout=%lu ms (total=%lu ms), clk_src=%d, int_time=%d, rst_time=%d", config->int_timeout_ms, config->rst_timeout_ms, total_rst_timeout_ms, priv->clk_src, priv->int_time, priv->rst_time); return LISA_DEVICE_OK; } /** * @brief 启动看门狗 */ static int arcs_wdt_start(lisa_device_t *dev) { if (!lisa_device_is_initialized(dev)) { return LISA_DEVICE_ERR_INVALID; } lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)dev->priv_data; DEVICE_LOCK(priv); /* 检查是否已配置 */ if (priv->configured_timeout_ms == 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "WDT not configured, call setup first"); return LISA_DEVICE_ERR_NOT_READY; } /* 如果已经在运行,直接返回 */ if (priv->state == LISA_WDT_STATE_RUNNING) { DEVICE_UNLOCK(priv); return LISA_DEVICE_OK; } /* 确保回调已注册(双重检查) */ if (WDT_Initialize(priv->hal_handler, wdt_hal_irq_callback, priv) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to register WDT callback before start"); return LISA_DEVICE_ERR_IO; } /* 启动 HAL WDT(这会同时使能中断和复位) */ if (WDT_Enable(priv->hal_handler) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to enable WDT"); return LISA_DEVICE_ERR_IO; } priv->state = LISA_WDT_STATE_RUNNING; DEVICE_UNLOCK(priv); LISA_LOGI(LOG_TAG, "WDT started with int_time=%d, rst_time=%d, callback=%p", priv->int_time, priv->rst_time, wdt_hal_irq_callback); return LISA_DEVICE_OK; } /** * @brief 停止看门狗 */ static int arcs_wdt_stop(lisa_device_t *dev) { if (!lisa_device_is_initialized(dev)) { return LISA_DEVICE_ERR_INVALID; } lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)dev->priv_data; DEVICE_LOCK(priv); if (priv->state != LISA_WDT_STATE_RUNNING) { DEVICE_UNLOCK(priv); return LISA_DEVICE_OK; } /* 停止 HAL WDT */ if (WDT_Disable(priv->hal_handler) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to disable WDT"); return LISA_DEVICE_ERR_IO; } priv->state = LISA_WDT_STATE_IDLE; DEVICE_UNLOCK(priv); LISA_LOGI(LOG_TAG, "WDT stopped"); return LISA_DEVICE_OK; } /** * @brief 喂狗(重置看门狗计数器) */ static int arcs_wdt_feed(lisa_device_t *dev) { if (!lisa_device_is_initialized(dev)) { return LISA_DEVICE_ERR_INVALID; } lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)dev->priv_data; DEVICE_LOCK(priv); if (priv->state != LISA_WDT_STATE_RUNNING) { DEVICE_UNLOCK(priv); LISA_LOGW(LOG_TAG, "WDT not running, feed ignored"); return LISA_DEVICE_ERR_NOT_READY; } /* 喂狗 */ if (WDT_Refresh(priv->hal_handler) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to refresh WDT"); return LISA_DEVICE_ERR_IO; } DEVICE_UNLOCK(priv); LISA_LOGD(LOG_TAG, "WDT fed"); return LISA_DEVICE_OK; } /** * @brief 获取剩余时间 */ static int arcs_wdt_get_remaining_time(lisa_device_t *dev, uint32_t *remaining_ms) { if (!lisa_device_is_initialized(dev) || !remaining_ms) { return LISA_DEVICE_ERR_INVALID; } lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)dev->priv_data; DEVICE_LOCK(priv); if (priv->state != LISA_WDT_STATE_RUNNING) { DEVICE_UNLOCK(priv); *remaining_ms = 0; return LISA_DEVICE_ERR_NOT_READY; } /* ARCS WDT HAL 不支持直接读取剩余时间,返回配置的超时时间 */ *remaining_ms = priv->configured_timeout_ms; DEVICE_UNLOCK(priv); return LISA_DEVICE_OK; } /** * @brief 获取看门狗状态 */ static int arcs_wdt_get_state(lisa_device_t *dev, lisa_wdt_state_t *state) { if (!lisa_device_is_initialized(dev) || !state) { return LISA_DEVICE_ERR_INVALID; } lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)dev->priv_data; DEVICE_LOCK(priv); *state = priv->state; DEVICE_UNLOCK(priv); return LISA_DEVICE_OK; } /** * @brief 设置超时回调函数 */ static int arcs_wdt_set_callback(lisa_device_t *dev, lisa_wdt_callback_t callback, void *user_data) { if (!lisa_device_is_initialized(dev)) { return LISA_DEVICE_ERR_INVALID; } lisa_wdt_priv_t *priv = (lisa_wdt_priv_t *)dev->priv_data; DEVICE_LOCK(priv); priv->callback = callback; priv->user_data = user_data; /* 注意:HAL回调始终注册,用于更新状态和调用用户回调 */ /* 即使用户没有设置回调,我们也需要HAL回调来更新状态 */ if (WDT_Initialize(priv->hal_handler, wdt_hal_irq_callback, priv) != 0) { DEVICE_UNLOCK(priv); LISA_LOGE(LOG_TAG, "Failed to update WDT callback"); return LISA_DEVICE_ERR_IO; } DEVICE_UNLOCK(priv); LISA_LOGD(LOG_TAG, "WDT callback %s", callback ? "set" : "cleared"); return LISA_DEVICE_OK; } /* ===== ARCS WDT API 实例 ===== */ static const lisa_wdt_api_t arcs_wdt_api = { .setup = arcs_wdt_setup, .start = arcs_wdt_start, .stop = arcs_wdt_stop, .feed = arcs_wdt_feed, .get_remaining_time = arcs_wdt_get_remaining_time, .get_state = arcs_wdt_get_state, .set_callback = arcs_wdt_set_callback, }; /* ===== 设备初始化函数 ===== */ static int arcs_wdt0_init(void) { /* 清空私有数据 */ memset(&wdt0_priv, 0, sizeof(lisa_wdt_priv_t)); /* 获取 HAL WDT 句柄 */ wdt0_priv.hal_handler = WDT(); if (!wdt0_priv.hal_handler) { LISA_LOGE(LOG_TAG, "Failed to get WDT handler"); return LISA_DEVICE_ERR_INIT_FAIL; } /* 创建互斥锁 */ wdt0_priv.mutex = lisa_mutex_create(); if (!wdt0_priv.mutex) { LISA_LOGE(LOG_TAG, "Failed to create mutex"); return LISA_DEVICE_ERR_INIT_FAIL; } /* 初始化 HAL WDT,注册中断回调 */ if (WDT_Initialize(wdt0_priv.hal_handler, wdt_hal_irq_callback, &wdt0_priv) != 0) { LISA_LOGE(LOG_TAG, "Failed to initialize WDT"); return LISA_DEVICE_ERR_INIT_FAIL; } /* 上电 WDT */ if (WDT_PowerControl(wdt0_priv.hal_handler, CSK_POWER_FULL) != 0) { LISA_LOGE(LOG_TAG, "Failed to power on WDT"); return LISA_DEVICE_ERR_INIT_FAIL; } wdt0_priv.state = LISA_WDT_STATE_IDLE; LISA_LOGI(LOG_TAG, "WDT0 initialized successfully"); return LISA_DEVICE_OK; } /* ===== 设备注册 ===== */ LISA_DEVICE_REGISTER(wdt0, /* 设备名称 */ &arcs_wdt_api, /* API指针 */ &wdt0_priv, /* 私有数据指针 */ NULL, /* 用户数据 */ arcs_wdt0_init, /* 初始化函数 */ LISA_DEVICE_PRIORITY_NORMAL); /* 优先级 */