mbed-os/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/watchdog_api.c

307 lines
9.9 KiB
C

/****************************************************************************
*
* Copyright 2020 Samsung Electronics All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <string.h>
#include <stdio.h>
#include "cmsis_os.h"
#include "cmsis.h"
#if DEVICE_WATCHDOG
#define WATCHDOG_RESET_ENABLED 1
#include "watchdog_api.h"
/****************************************************************************
* Private Functions
****************************************************************************/
static void s5js100_watchdog_irq_enable(void);
static void s5js100_watchdog_irq_disable(void);
static void s5js100_watchdog_ack_irq(void);
static void s5js100_watchdog_reset_enable(void);
static void s5js100_watchdog_reset_disable(void);
static void s5js100_watchdog_enable(void);
static void s5js100_watchdog_disable(void);
static uint32_t s5js100_watchdog_getclock(void);
static void s5js100_watchdog_handler(void);
static void s5js100_watchdog_set_reload_val(uint32_t time_ms);
static void s5js100_watchdog_set_load_val_diff(uint32_t time_ms);
static uint32_t s5js100_watchdog_get_curr(void);
static void s5js100_watchdog_set_curr(unsigned int curr_val);
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
// REGISTERS
#define rWDOG_CTRL 0x00
#define bWDOG_CNT_EN (2)
#define bWDOG_PCLK_EN (1)
#define bWDOG_WCLK_EN (0)
#define rWDOG_LOAD_VAL 0x04
#define rWDOG_LOAD 0x08
#define rWDOG_RESET_REQ_EN 0x0C
#define rWDOG_INT_EN 0x10
#define rWDOG_INT_STAT_RAW 0x14
#define rWDOG_INT_STAT_MASKED 0x18
#define rWDOG_INT_CLR 0x1C
#define rWDOG_CNT_UPD_EN 0x20
#define rWDOG_CNT_VAL 0x24
#define rWDOG_RESET_REQN_STAT 0x28
#define rWDOG_LOAD_VAL_DIFF 0x2C
#define rWDOG_BLK_CTRL 0x800
#define EXT_SLPCLK 32768
/* Hold initially-configured timeout in hal_watchdog_init */
static uint32_t wdt_timeout_reload_ms = 0;
static uint32_t s5js100_watchdog_getclock(void)
{
/* TODO: get TCLKB from CLK DRIVER */
return EXT_SLPCLK;
}
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
{
/* Check validity of arguments */
if (! config || ! config->timeout_ms) {
return WATCHDOG_STATUS_INVALID_ARGUMENT;
}
wdt_timeout_reload_ms = config->timeout_ms;
//clear Watchdog
s5js100_watchdog_disable();
// Set WDT interrupt
NVIC_SetVector(S5JS100_IRQ_WDG, (uint32_t) s5js100_watchdog_handler);
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
SCB_InvalidateICache();
#endif
NVIC_EnableIRQ(S5JS100_IRQ_WDG);
#if WATCHDOG_RESET_ENABLED
s5js100_watchdog_reset_enable();
#endif
s5js100_watchdog_set_reload_val(wdt_timeout_reload_ms);
s5js100_watchdog_enable();
return WATCHDOG_STATUS_OK;
}
void hal_watchdog_kick(void)
{
s5js100_watchdog_set_reload_val(wdt_timeout_reload_ms);
}
watchdog_status_t hal_watchdog_stop(void)
{
s5js100_watchdog_disable();
return WATCHDOG_STATUS_OK;
}
uint32_t hal_watchdog_get_reload_value(void)
{
return wdt_timeout_reload_ms;
}
watchdog_features_t hal_watchdog_get_platform_features(void)
{
watchdog_features_t wdt_feat;
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
wdt_feat.max_timeout = UINT32_MAX;
/* Support re-configuring watchdog timer */
wdt_feat.update_config = 1;
/* Support stopping watchdog timer */
wdt_feat.disable_watchdog = 1;
return wdt_feat;
}
static void s5js100_watchdog_handler(void)
{
s5js100_watchdog_ack_irq();
}
/****************************************************************************
* Name: s5js100_watchdog_disable
*
* Description:
* Disable the watchdog timer. The S5J always boots with the watchdog
* timer enabled at timeout of 10 - 20 seconds by the second stage boot
* loader to detect any boot failure. So, the watchdog timer must be
* disabled as part of the start up logic.
*
****************************************************************************/
static void s5js100_watchdog_disable(void)
{
putreg32(0, S5JS100_WDT_BASE + rWDOG_CNT_UPD_EN);
modifyreg32(S5JS100_WDT_BASE + rWDOG_CTRL, (1 << bWDOG_CNT_EN), 0);
}
/****************************************************************************
* Name: s5js100_watchdog_enable
*
* Description:
* Enable watchdog operation.
* Should be correctly configured before enabling.
*
****************************************************************************/
static void s5js100_watchdog_enable(void)
{
putreg32(1, S5JS100_WDT_BASE + rWDOG_CNT_UPD_EN);
modifyreg32(S5JS100_WDT_BASE + rWDOG_CTRL, (0x1 << bWDOG_CNT_EN), (0x1 << bWDOG_CNT_EN));
}
/****************************************************************************
* Name: s5js100_watchdog_reset_disable
*
* Description:
* When WD timer expires, it can issue HW reset.
* This function disables reset feature.
* Watchdog will be reloaded with value written in reload register.
* and continue its operation.
*
****************************************************************************/
static void s5js100_watchdog_reset_disable(void)
{
putreg32(0, S5JS100_WDT_BASE + rWDOG_RESET_REQ_EN);
}
/****************************************************************************
* Name: s5js100_watchdog_reset_enable
*
* Description:
* When WD timer expires, it can issue HW reset.
* This function enables reset feature.
*
****************************************************************************/
static void s5js100_watchdog_reset_enable(void)
{
putreg32(1, S5JS100_WDT_BASE + rWDOG_RESET_REQ_EN);
putreg32(1 << 1, 0x82020018);
}
static void s5js100_watchdog_ack_irq(void)
{
putreg32(0, S5JS100_WDT_BASE + rWDOG_INT_CLR);
}
/****************************************************************************
* Name: s5js100_watchdog_irq_disable
*
* Description:
* When WD timer expires, it can issue interrupt.
* This function disables reset feature.
*
****************************************************************************/
static void s5js100_watchdog_irq_disable(void)
{
putreg32(0, S5JS100_WDT_BASE + rWDOG_INT_EN);
}
/****************************************************************************
* Name: s5js100_watchdog_irq_enable
*
* Description:
* When WD timer expires, it can issue interrupt.
* This function enables reset feature.
*
****************************************************************************/
static void s5js100_watchdog_irq_enable(void)
{
putreg32(1, S5JS100_WDT_BASE + rWDOG_INT_EN);
}
/****************************************************************************
* Name: s5js100_watchdog_set_reload_val
*
* Description:
* When WD timer expires, if reset is disabled, will be reloaded with value
* defined by this function call.
*
****************************************************************************/
static void s5js100_watchdog_set_reload_val(uint32_t time_ms)
{
uint32_t slp_clk = s5js100_watchdog_getclock();
uint32_t load_value;
load_value = (time_ms * slp_clk) / 1000;
putreg32(load_value, S5JS100_WDT_BASE + rWDOG_LOAD_VAL);
putreg32(0x1, S5JS100_WDT_BASE + rWDOG_LOAD);
}
/****************************************************************************
* Name: s5js100_watchdog_set_load_val_diff
*
* Description:
* Funtion s5js100_watchdog_set_load_val_diff set LOAD_VAL_DIFF value.
* This value sets the difference between interrupt assertion time and
* the reset request assertion time. The interrupt assertion occurs before
* the reset request as this value. This value should be stable before writing
* 1 to LOAD register.
*
****************************************************************************/
static void s5js100_watchdog_set_load_val_diff(uint32_t time_ms)
{
uint32_t slp_clk = s5js100_watchdog_getclock();
uint32_t load_diff;
load_diff = (time_ms * slp_clk) / 1000;
putreg32(load_diff, S5JS100_WDT_BASE + rWDOG_LOAD_VAL_DIFF);
}
/****************************************************************************
* Name: s5js100_watchdog_get_curr
*
* Description:
* Function s5js100_watchdog_get_curr returns current WD counter value.
****************************************************************************/
static uint32_t s5js100_watchdog_get_curr(void)
{
uint32_t slp_clk = s5js100_watchdog_getclock();
uint32_t load_value;
load_value = getreg32(S5JS100_WDT_BASE + rWDOG_CNT_VAL);
return ((load_value * 1000) / slp_clk);
}
/****************************************************************************
* Name: s5js100_watchdog_set_curr
*
* Description:
* Function s5js100_watchdog_set_curr sets immediately current WD counter value.
* Use this function to set initial WD timer value before running operation.
****************************************************************************/
static void s5js100_watchdog_set_curr(unsigned int curr_val)
{
putreg32(curr_val, S5JS100_WDT_BASE + rWDOG_LOAD_VAL);
putreg32(0x1, S5JS100_WDT_BASE + rWDOG_LOAD);
}
#endif