新增所有文件

This commit is contained in:
2025-10-25 21:11:06 +08:00
parent 8cc4755d15
commit 3134504178
8414 changed files with 2995287 additions and 5 deletions

View File

@@ -0,0 +1,759 @@
/**
* @file sdrv_rtc.c
*
* Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*
* Description: sec_rtc driver.
*
* Revision History:
* -----------------
*/
#include <debug.h>
#include <irq.h>
#include <irq_num.h>
#include "sdrv_rtc.h"
#include "sdrv_rtc_reg.h"
#include "udelay/udelay.h"
#define RTC_CLK_HZ (32 * 1024ul)
#define RTC_CLK_SHIFT __builtin_ctz(RTC_CLK_HZ)
#define RTC_TICK_TO_SECOND(t) ((t) >> RTC_CLK_SHIFT)
#define RTC_SECOND_TO_TICK(s) ((s) << RTC_CLK_SHIFT)
#define RTC_TICK_TO_MILLISECOND(t) ((uint64_t)(t) * 1000 / 32768)
#define RTC_MILLISECOND_TO_TICK(s) ((uint64_t)(s) * 32768 / 1000)
#define DELAY_US 240
#define SECONDS_PER_MINUTE (60ul)
#define MINUTES_PER_HOUR (60ul)
#define HOURS_PER_DAY (24ul)
#define SECONDS_PER_HOUR (SECONDS_PER_MINUTE * MINUTES_PER_HOUR)
#define SECONDS_PER_DAY (SECONDS_PER_HOUR * HOURS_PER_DAY)
#define LEAP_YEAR_DAYS (366ul)
#define COMMON_YEAR_DAYS (365ul)
#define TM_START_YEAR (1900ul)
#define EPOCH_START_YEAR (1970ul)
static const uint32_t month_days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
/**
* @brief check RTC time is valid.
*
* @param [in] tm RTC time.
* @return 0 success, otherwise failed.
*/
static status_t sdrv_check_rtc_time(struct rtc_time *tm)
{
if (tm->tm_subsec > 999u) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
if (tm->tm_sec > 61u) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
if (tm->tm_min > 59u) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
if (tm->tm_hour > 23u) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
if ((tm->tm_mday < 1u) || (tm->tm_mday > 31u)) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
if (tm->tm_mon > 11u) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
if (tm->tm_wday > 6u) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
if (tm->tm_year > 365u) {
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
return SDRV_STATUS_OK;
}
/**
* @brief Simple algorithm to convert RTC time to Epoch seconds.
*
* Epoch seconds starts from 1970-1-1, 00:00:01
*
* @param [in] tm RTC time.
* @return uint64_t Number of seconds since Epoch.
*/
uint64_t rtc_to_epoch(struct rtc_time *tm)
{
uint64_t epoch_sec = 0;
uint32_t year = tm->tm_year + TM_START_YEAR;
if (sdrv_check_rtc_time(tm) < 0) {
ssdk_printf(SSDK_WARNING, "%s invalid rtc time!\n", __func__);
return 0;
}
for (uint32_t num = EPOCH_START_YEAR; num < year; num++) {
epoch_sec += SECONDS_PER_DAY *
(is_leap_year(num) ? LEAP_YEAR_DAYS : COMMON_YEAR_DAYS);
}
for (uint32_t num = 0; num < tm->tm_mon; num++) {
epoch_sec += month_days[num] * SECONDS_PER_DAY;
if (is_leap_year(year) && (num == 1)) {
epoch_sec += SECONDS_PER_DAY;
}
}
epoch_sec += (tm->tm_mday - 1) * SECONDS_PER_DAY;
epoch_sec += tm->tm_hour * SECONDS_PER_HOUR;
epoch_sec += tm->tm_min * SECONDS_PER_MINUTE;
epoch_sec += tm->tm_sec;
return epoch_sec;
}
/**
* @brief Simple algorithm to convert epoch seconds to RTC time.
*
* Epoch seconds starts from 1970-1-1, 00:00:01
*
* @param [out] tm
* @param [in] epoch_sec
*/
status_t epoch_to_rtc(struct rtc_time *tm, uint64_t epoch_sec)
{
uint32_t year = EPOCH_START_YEAR;
uint32_t month = 0;
uint32_t days = epoch_sec / SECONDS_PER_DAY;
uint32_t seconds;
tm->tm_wday = (4 + days) % 7;
while (days >= COMMON_YEAR_DAYS) {
if (is_leap_year(year)) {
if (days >= LEAP_YEAR_DAYS) {
days -= LEAP_YEAR_DAYS;
}
else {
break;
}
}
else {
days -= COMMON_YEAR_DAYS;
}
year++;
}
tm->tm_year = year - TM_START_YEAR;
while (days >= 28) {
if (is_leap_year(year) && (month == 1)) {
if (days >= 29) {
days -= 29;
}
else {
break;
}
}
else {
if (days >= month_days[month]) {
days -= month_days[month];
}
else {
break;
}
}
month++;
}
tm->tm_mon = month;
tm->tm_mday = days + 1;
seconds = epoch_sec % SECONDS_PER_DAY;
tm->tm_hour = seconds / 3600;
tm->tm_min = (seconds % 3600) / 60;
tm->tm_sec = (seconds % 3600) % 60;
return sdrv_check_rtc_time(tm);
}
/**
* @brief Simple algorithm to convert RTC time to Epoch milliseconds.
*
* Epoch seconds starts from 1970-1-1, 00:00:00.001
*
* @param [in] tm RTC time.
* @return uint64_t number of milliseconds since epoch.
*/
uint64_t rtc_to_epoch_ms(struct rtc_time *tm)
{
uint64_t epoch_millisec = 0;
uint32_t year = tm->tm_year + TM_START_YEAR;
if (sdrv_check_rtc_time(tm) < 0) {
ssdk_printf(SSDK_WARNING, "%s invalid rtc time!\n", __func__);
return 0;
}
for (uint32_t num = EPOCH_START_YEAR; num < year; num++) {
epoch_millisec += (uint64_t)SECONDS_PER_DAY * 1000 *
(is_leap_year(num) ? LEAP_YEAR_DAYS : COMMON_YEAR_DAYS);
}
for (uint32_t num = 0; num < tm->tm_mon; num++) {
epoch_millisec += (uint64_t)month_days[num] * SECONDS_PER_DAY * 1000;
if (is_leap_year(year) && (num == 1)) {
epoch_millisec += SECONDS_PER_DAY * 1000;
}
}
epoch_millisec += (uint64_t)(tm->tm_mday - 1) * SECONDS_PER_DAY * 1000;
epoch_millisec += (uint64_t)tm->tm_hour * SECONDS_PER_HOUR * 1000;
epoch_millisec += (uint64_t)tm->tm_min * SECONDS_PER_MINUTE * 1000;
epoch_millisec += (uint64_t)tm->tm_sec * 1000;
epoch_millisec += (uint64_t)tm->tm_subsec;
return epoch_millisec;
}
/**
* @brief Simple algorithm to convert epoch milliseconds to RTC time.
*
* Epoch milliseconds starts from 1970-1-1, 00:00:00.001
*
* @param [out] tm
* @param [in] epoch_sec
*/
status_t epoch_ms_to_rtc(struct rtc_time *tm, uint64_t epoch_millisec)
{
uint32_t year = EPOCH_START_YEAR;
uint32_t month = 0;
uint32_t days = epoch_millisec / SECONDS_PER_DAY / 1000;
uint32_t seconds;
tm->tm_wday = (4 + days) % 7;
while (days >= COMMON_YEAR_DAYS) {
if (is_leap_year(year)) {
if (days >= LEAP_YEAR_DAYS) {
days -= LEAP_YEAR_DAYS;
}
else {
break;
}
}
else {
days -= COMMON_YEAR_DAYS;
}
year++;
}
tm->tm_year = year - TM_START_YEAR;
while (days >= 28) {
if (is_leap_year(year) && (month == 1)) {
if (days >= 29) {
days -= 29;
}
else {
break;
}
}
else {
if (days >= month_days[month]) {
days -= month_days[month];
}
else {
break;
}
}
month++;
}
tm->tm_mon = month;
tm->tm_mday = days + 1;
seconds = (epoch_millisec % (SECONDS_PER_DAY * 1000)) / 1000;
tm->tm_hour = seconds / 3600;
tm->tm_min = (seconds % 3600) / 60;
tm->tm_sec = (seconds % 3600) % 60;
tm->tm_subsec = epoch_millisec % 1000;
return sdrv_check_rtc_time(tm);
}
static status_t _rtc_handler(uint32_t source, void *arg)
{
sdrv_rtc_t *dev = arg;
Rtc *rtc = (Rtc *)dev->base;
sdrv_rtc_violation_e vio_status;
/* disable overflow/disable violation intr */
if (source == dev->violation_intr) {
vio_status = sdrv_rtc_get_violation_status(dev);
if (dev->vio_mask & vio_status) {
sdrv_rtc_violation_intr_enable(dev, (sdrv_rtc_violation_e)(dev->vio_mask & vio_status), false);
}
}
else if (source == dev->wakeup_intr) {
sec_rtc_wakeup_enable(rtc,
BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE | BM_WAKEUP_CTRL_REQ_ENABLE,
false);
}
if (dev->cb)
dev->cb(source, arg);
/* overflow/disable violation intr */
if (source == dev->violation_intr) {
sdrv_rtc_clear_violation_status(dev, vio_status);
if (dev->vio_mask & vio_status) {
sdrv_rtc_violation_intr_enable(dev, (sdrv_rtc_violation_e)(dev->vio_mask & vio_status), true);
}
}
return SDRV_STATUS_OK;
}
/**
* @brief sdrv rtc enable.
*
* @param [in] dev sdrv rtc controller
* @param [in] enable enable or disable
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_enable(sdrv_rtc_t *dev, bool enable)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
int ret;
Rtc *rtc = (Rtc *)dev->base;
ret = sec_rtc_local_enable(rtc, enable);
if (ret < 0) {
ssdk_printf(SSDK_ERR, "%s sec rtc enable faild!\n", __func__);
return SDRV_RTC_STATUS_LOCK;
}
udelay(DELAY_US);
return SDRV_STATUS_OK;
}
/**
* @brief sdrv enable rtc wake up.
*
* @param [in] dev sdrv rtc controller
* @param [in] type sdrv rtc wake up type
* @param [in] enable enable or disable
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_wakeup_enable(sdrv_rtc_t *dev,
sdrv_rtc_wakeup_enable_type_e type, bool enable)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
uint8_t vtype = 0;
switch (type) {
case SDRV_WKUP_ENABLE:
vtype = BM_WAKEUP_CTRL_ENABLE;
break;
case SDRV_WKUP_ENABLE_IRQ:
vtype = BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE;
break;
case SDRV_WKUP_ENABLE_REQ:
vtype = BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_REQ_ENABLE;
break;
case SDRV_WKUP_ENABLE_ALL:
vtype = BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE |
BM_WAKEUP_CTRL_REQ_ENABLE;
break;
default:
vtype = BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE |
BM_WAKEUP_CTRL_REQ_ENABLE;
break;
}
sec_rtc_wakeup_enable(rtc, vtype, enable);
return SDRV_STATUS_OK;
}
/**
* @brief sdrv get rtc wake up status.
*
* @param [in] dev sdrv rtc controller
* @return 1 wakeup, 0 not wakeup.
*/
bool sdrv_rtc_get_wakeup_status(sdrv_rtc_t *dev)
{
Rtc *rtc = (Rtc *)dev->base;
return sec_rtc_get_wakeup_status(rtc);
}
/**
* @brief sdrv clear rtc wake up status.
*
* @param [in] dev sdrv rtc controller
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_clear_wakeup_status(sdrv_rtc_t *dev)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
/* rtc wakeup status has been cleared */
if (!sdrv_rtc_get_wakeup_status(dev)) {
return SDRV_STATUS_OK;
}
Rtc *rtc = (Rtc *)dev->base;
if (sec_rtc_is_alarm_enable(rtc)) {
sec_rtc_wakeup_enable(rtc,
BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE | BM_WAKEUP_CTRL_REQ_ENABLE,
false);
}
sec_rtc_clear_wakeup_status(rtc);
return SDRV_STATUS_OK;
}
/**
* @brief sdrv get rtc violation status.
*
* @param [in] dev sdrv rtc controller
* @return 0 no violation, 1 overflow violation, 2 disable violation, 3 overflow & disable
*/
sdrv_rtc_violation_e sdrv_rtc_get_violation_status(sdrv_rtc_t *dev)
{
Rtc *rtc = (Rtc *)dev->base;
return (sdrv_rtc_violation_e)sec_rtc_get_violation_status(rtc);
}
/**
* @brief sdrv clear rtc violation status.
*
* @param [in] dev sdrv rtc controller
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_clear_violation_status(sdrv_rtc_t *dev,
sdrv_rtc_violation_e vio)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
sec_rtc_clear_violation_status(rtc, vio);
if (vio & SDRV_RTC_VIO_OVERFLOW) {
sec_rtc_set_cross_clk_en(rtc);
}
return SDRV_STATUS_OK;
}
/**
* @brief sdrv rtc violation enable.
*
* @param [in] dev sdrv rtc controller
* @param [in] vio_mask sdrv rtc violation type
* @param [in] en violation enable or disable
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_violation_intr_enable(sdrv_rtc_t *dev,
sdrv_rtc_violation_e vio, bool en)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
if (en) {
sec_rtc_set_violation_enable(rtc, vio);
}
else {
sec_rtc_set_violation_disable(rtc, vio);
}
return SDRV_STATUS_OK;
}
/**
* @brief Enable rtc interrupt.
* @param [in] source rtc wakeup/periodical/violation interrupt num.
* @param [in] arg pointer to interrupt arg(rtc device structure).
* @param [in] cb callback function.
*/
status_t sdrv_rtc_enable_it(uint32_t source, void *arg, rtc_cb_t cb)
{
sdrv_rtc_t *dev = arg;
dev->cb = cb;
if (source > 0) {
irq_attach(source, (irq_handler)_rtc_handler, dev);
irq_enable(source);
return SDRV_STATUS_OK;
}
return SDRV_STATUS_INVALID_PARAM;
}
/**
* @brief disable rtc interrput.
* @param source rtc wakeup/periodical/violation interrupt num.
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_disable_it(uint32_t source)
{
if (source > 0) {
irq_detach(source);
irq_disable(source);
return SDRV_STATUS_OK;
}
return SDRV_STATUS_INVALID_PARAM;
}
/**
* @brief rtc get time
*
* Get current rtc time.
*
* @param [in] dev sdrv rtc controller
* @param [in] tm
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_get_time(sdrv_rtc_t *dev, struct rtc_time *tm)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
uint64_t millisecs = RTC_TICK_TO_MILLISECOND(sec_rtc_get_tick(rtc));
return epoch_ms_to_rtc(tm, millisecs);
}
/**
* @brief rtc set time
*
* Set current rtc time.
*
* @param [in] dev
* @param [in] tm
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_set_time(sdrv_rtc_t *dev, struct rtc_time *tm)
{
uint64_t millisecs = rtc_to_epoch_ms(tm);
int ret;
if (millisecs == 0) {
ssdk_printf(SSDK_WARNING, "%s default set rtc time 1970-1-1 00:00:00.000\n", __func__);
}
Rtc *rtc = (Rtc *)dev->base;
ret = sec_rtc_local_enable(rtc, 0);
if (ret < 0) {
ssdk_printf(SSDK_ERR, "%s sec rtc disable failed!\n", __func__);
return SDRV_RTC_STATUS_LOCK;
}
/* writing RTC_L/H, extra waitting 2*240us */
udelay(DELAY_US);
sec_rtc_set_tick(rtc, RTC_MILLISECOND_TO_TICK(millisecs));
sec_rtc_set_cross_clk_en(rtc);
ret = sec_rtc_local_enable(rtc, 1);
if (ret < 0) {
ssdk_printf(SSDK_ERR, "%s sec rtc enable failed!\n", __func__);
return SDRV_RTC_STATUS_LOCK;
}
udelay(DELAY_US);
return SDRV_STATUS_OK;
}
/**
* @brief rtc get alarm
*
* Get rtc alarm time, rtc will trigger interrupt when rtc time arrives at alarm time.
*
* @param [in] dev
* @param [in] alrm
* @return 0
*/
status_t sdrv_rtc_get_alarm(sdrv_rtc_t *dev, struct rtc_wkalrm *alrm)
{
status_t ret = SDRV_STATUS_FAIL;
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
uint64_t millisecs = RTC_TICK_TO_MILLISECOND(sec_rtc_get_alarm_tick(rtc));
ret = epoch_ms_to_rtc(&alrm->tm, millisecs);
alrm->enable = sec_rtc_is_alarm_enable(rtc);
alrm->pending = sec_rtc_get_wakeup_status(rtc);
return ret;
}
/**
* @brief rtc set alarm
*
* Set rtc alarm time, rtc will trigger interrupt when rtc time arrives at alarm time.
*
* @param [in] dev sdrv rtc controller
* @param [in] alrm
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_set_alarm(sdrv_rtc_t *dev, struct rtc_wkalrm *alrm)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
uint64_t millisecs = rtc_to_epoch_ms(&alrm->tm);
if (millisecs == 0) {
ssdk_printf(SSDK_ERR, "%s sec rtc set sec failed!\n", __func__);
return SDRV_RTC_STATUS_INVALID_RTC_TIME;
}
Rtc *rtc = (Rtc *)dev->base;
sec_rtc_set_alarm_tick(rtc, RTC_MILLISECOND_TO_TICK(millisecs));
sec_rtc_set_cross_clk_en(rtc);
return SDRV_STATUS_OK;
}
/**
* @brief Enable rtc alarm.
*
* @param [in] dev sdrv rtc controller
* @param [in] enable enable or disable
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_enable_alarm(sdrv_rtc_t *dev, bool enable)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
sec_rtc_wakeup_enable(rtc,
BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE | BM_WAKEUP_CTRL_REQ_ENABLE,
enable);
if (!enable) {
sec_rtc_clear_wakeup_status(rtc);
}
return SDRV_STATUS_OK;
}
/**
* @brief Read rtc general purpose register.
*
* Data in general purpose register will not be lost until RTC power down.
*
* @param [in] dev sdrv rtc controller
* @param [in] gp_num sdrv general purpose register num
* @return general purpose register value
*/
uint32_t sdrv_rtc_read_general_purpose_reg(sdrv_rtc_t *dev,
sdrv_general_purpose_e gp_num)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
return sec_rtc_read_general_purpose_reg(rtc, gp_num);
}
/**
* @brief Write rtc general purpose register.
*
* @param [in] dev sdrv rtc controller
* @param [in] gp_num sdrv general purpose register num
* @param [in] value general purpose register value
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_write_general_purpose_reg(sdrv_rtc_t *dev,
sdrv_general_purpose_e gp_num, uint32_t value)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
sec_rtc_write_general_purpose_reg(rtc, gp_num, value);
return SDRV_STATUS_OK;
}
/**
* @brief rtc lock.
*
* Once set rtc lock, rtc enable can not be changed until next power on reset.
*
* @param [in] dev sdrv rtc controller
* @return 0 success, otherwise failed.
*/
status_t sdrv_rtc_lock(sdrv_rtc_t *dev)
{
if (dev->base == 0) {
return SDRV_STATUS_INVALID_PARAM;
}
Rtc *rtc = (Rtc *)dev->base;
sec_rtc_lock(rtc);
return SDRV_STATUS_OK;
}

View File

@@ -0,0 +1,317 @@
/**
* @file sdrv_rtc_reg.c
* @brief semidrive sec_rtc driver
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <types.h>
#include <part.h>
#include <sdrv_ckgen.h>
#include "sdrv_rtc_reg.h"
#include "reg.h"
#include "bits.h"
#include "udelay/udelay.h"
#if CONFIG_RTC_SS_DYNAMIC_PCLK
#define RTC_SS_ACCESS_DELAY_CYCLE(n) udelay(35 * n)
#else
#define RTC_SS_ACCESS_DELAY_CYCLE(n)
#endif
uint64_t sec_rtc_get_tick(Rtc *rtc)
{
RTC_SS_ACCESS_START();
RTC_SS_ACCESS_DELAY_CYCLE(1);
uint64_t tick = rtc->RTC_L;
tick = (uint64_t)(rtc->RTC_H_HOLD_SHADOW) << 32;
tick |= rtc->RTC_L_HOLD_SHADOW;
RTC_SS_ACCESS_END();
return tick;
}
void sec_rtc_set_tick(Rtc *rtc, uint64_t v)
{
RTC_SS_ACCESS_START();
uint32_t tick = v & 0xffffffff;
rtc->RTC_L = tick;
rtc->RTC_H = (v >> 32) & 0xffff;
RTC_SS_ACCESS_END();
}
void sec_rtc_lock(Rtc *rtc)
{
RTC_SS_ACCESS_START();
rtc->SEC_RTC_CTRL |= BM_SEC_RTC_CTRL_LOCK;
RTC_SS_ACCESS_END();
}
bool sec_rtc_is_locked(Rtc *rtc)
{
bool locked = false;
if (rtc->SEC_RTC_CTRL & BM_SEC_RTC_CTRL_LOCK)
locked = true;
return locked;
}
int sec_rtc_local_enable(Rtc *rtc, bool en)
{
RTC_SS_ACCESS_START();
if (!sec_rtc_is_locked(rtc)) {
if (en)
rtc->SEC_RTC_CTRL |= BM_SEC_RTC_CTRL_RTC_LOCAL_ENABLE;
else
rtc->SEC_RTC_CTRL &= ~BM_SEC_RTC_CTRL_RTC_LOCAL_ENABLE;
RTC_SS_ACCESS_END();
return 0;
}
RTC_SS_ACCESS_END();
return -1;
}
void sec_rtc_set_alarm_tick(Rtc *rtc, uint64_t val)
{
RTC_SS_ACCESS_START();
rtc->TIMER_L = (uint32_t)(val & 0xffffffff);
rtc->TIMER_H = (val >> 32) & 0xffff;
RTC_SS_ACCESS_END();
}
uint64_t sec_rtc_get_alarm_tick(Rtc *rtc)
{
RTC_SS_ACCESS_START();
uint64_t tick = (uint64_t)(rtc->TIMER_H) << 32;
tick |= rtc->TIMER_L;
RTC_SS_ACCESS_END();
return tick;
}
uint8_t sec_rtc_is_alarm_enable(Rtc *rtc)
{
RTC_SS_ACCESS_START();
uint32_t val = rtc->WAKEUP_CTRL;
RTC_SS_ACCESS_END();
return (val & (BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE |
BM_WAKEUP_CTRL_REQ_ENABLE));
}
bool sec_rtc_get_wakeup_status(Rtc *rtc)
{
RTC_SS_ACCESS_START();
if (rtc->WAKEUP_CTRL & BM_WAKEUP_CTRL_STATUS) {
RTC_SS_ACCESS_END();
return true;
}
RTC_SS_ACCESS_END();
return false;
}
void sec_rtc_clear_wakeup_status(Rtc *rtc)
{
RTC_SS_ACCESS_START();
rtc->WAKEUP_CTRL |= BM_WAKEUP_CTRL_CLEAR;
RTC_SS_ACCESS_END();
sec_rtc_set_cross_clk_en(rtc);
RTC_SS_ACCESS_START();
rtc->WAKEUP_CTRL &= ~BM_WAKEUP_CTRL_CLEAR;
RTC_SS_ACCESS_END();
sec_rtc_set_cross_clk_en(rtc);
}
bool sec_rtc_get_overflow_status(Rtc *rtc)
{
RTC_SS_ACCESS_START();
if (rtc->WAKEUP_CTRL & BM_WAKEUP_CTRL_STATUS) {
RTC_SS_ACCESS_END();
return true;
}
RTC_SS_ACCESS_END();
return false;
}
void sec_rtc_clear_violation_status(Rtc *rtc, uint8_t vio)
{
RTC_SS_ACCESS_START();
rtc->VIOLATION_INT = (rtc->VIOLATION_INT & ~BM_VIOLATION_INT_DISABLE_STATUS) |
(vio << BM_VIOLATION_INT_OVERFLOW_STATS_BIT);
rtc->WAKEUP_CTRL |= (vio << BM_WAKEUP_CTRL_OVERFLOW_CLEAR_BIT);
udelay(150);
rtc->WAKEUP_CTRL &= ~(vio << BM_WAKEUP_CTRL_OVERFLOW_CLEAR_BIT);
udelay(150);
RTC_SS_ACCESS_END();
}
uint64_t sec_rtc_get_hld_tick(Rtc *rtc, uint64_t *tick)
{
if (tick)
*tick = sec_rtc_get_tick(rtc);
RTC_SS_ACCESS_START();
uint64_t tick_hld = (uint64_t)(rtc->RTC_H_HOLD_SHADOW) << 32;
tick_hld |= rtc->RTC_L_HOLD_SHADOW;
RTC_SS_ACCESS_END();
return tick_hld;
}
void sec_rtc_set_rtc_ctrl(Rtc *rtc, uint32_t ctrl)
{
RTC_SS_ACCESS_START();
rtc->SEC_RTC_CTRL = ctrl;
RTC_SS_ACCESS_END();
}
void sec_rtc_set_cross_clk_en(Rtc *rtc)
{
uint32_t cnt = 0;
RTC_SS_ACCESS_START();
rtc->RTC_REGISTER_CROSS_CLOCK |=
BM_RTC_REGISTER_CROSS_CLOCK_REGISTER_CROSS_CLOCK_EN;
udelay(120);
while ((rtc->RTC_REGISTER_CROSS_CLOCK &
BM_RTC_REGISTER_CROSS_CLOCK_REGISTER_CROSS_CLOCK_EN)
&& (cnt < 120)) {
udelay(1);
cnt ++;
};
RTC_SS_ACCESS_END();
udelay(120);
}
void sec_rtc_wakeup_enable(Rtc *rtc, uint8_t vtype, uint8_t en)
{
RTC_SS_ACCESS_START();
uint32_t v = rtc->WAKEUP_CTRL;
if (en)
v |= vtype;
else
v &= ~vtype;
rtc->WAKEUP_CTRL = v;
RTC_SS_ACCESS_END();
sec_rtc_set_cross_clk_en(rtc);
}
void sec_rtc_ms_cfg(Rtc *master, Rtc *slave, uint8_t ctmode1, uint8_t ctmode2)
{
RTC_SS_ACCESS_START();
master->RTC_WORKING_MODE = BM_RTC_WORKING_MODE_RTC_MASTER_SLAVE;
if (ctmode1)
master->RTC_WORKING_MODE |= BM_RTC_WORKING_MODE_RTC_COUNT_MODE;
slave->RTC_WORKING_MODE &= ~BM_RTC_WORKING_MODE_RTC_MASTER_SLAVE;
if (ctmode2)
slave->RTC_WORKING_MODE |= BM_RTC_WORKING_MODE_RTC_COUNT_MODE;
RTC_SS_ACCESS_END();
}
void sec_rtc_set_violation_enable(Rtc *rtc, uint8_t mask)
{
if (rtc) {
/* do not clear BM_VIOLATION_INT_DISABLE_STATUS */
RTC_SS_ACCESS_START();
rtc->VIOLATION_INT = (rtc->VIOLATION_INT & ~BM_VIOLATION_INT_DISABLE_STATUS) |
FV_VIOLATION_INT_MASK(mask);
RTC_SS_ACCESS_END();
}
}
void sec_rtc_set_violation_disable(Rtc *rtc, uint8_t mask)
{
if (rtc) {
RTC_SS_ACCESS_START();
/* do not clear BM_VIOLATION_INT_DISABLE_STATUS */
rtc->VIOLATION_INT &= (~FV_VIOLATION_INT_MASK(mask) &
~BM_VIOLATION_INT_DISABLE_STATUS);
RTC_SS_ACCESS_END();
}
}
uint8_t sec_rtc_get_violation_status(Rtc *rtc)
{
RTC_SS_ACCESS_START();
uint32_t val = rtc->VIOLATION_INT;
RTC_SS_ACCESS_END();
return ((val & (BM_VIOLATION_INT_OVERFLOW_STATS |
BM_VIOLATION_INT_DISABLE_STATUS))
>> BM_VIOLATION_INT_OVERFLOW_STATS_BIT);
}
uint32_t sec_rtc_read_general_purpose_reg(Rtc *rtc, uint8_t gp_num)
{
uint32_t ret = 0;
RTC_SS_ACCESS_START();
switch (gp_num) {
case 0:
ret = rtc->GP0;
break;
case 1:
ret = rtc->GP1;
break;
case 2:
ret = rtc->GP2;
break;
case 3:
ret = rtc->GP3;
break;
default:
ret = rtc->GP0;
break;
}
RTC_SS_ACCESS_END();
return ret;
}
void sec_rtc_write_general_purpose_reg(Rtc *rtc, uint8_t gp_num, uint32_t value)
{
RTC_SS_ACCESS_START();
switch (gp_num) {
case 0:
rtc->GP0 = value;
break;
case 1:
rtc->GP1 = value;
break;
case 2:
rtc->GP2 = value;
break;
case 3:
rtc->GP3 = value;
break;
default:
rtc->GP0 = value;
break;
}
RTC_SS_ACCESS_END();
}

View File

@@ -0,0 +1,106 @@
/**
* @file sdrv_rtc_reg.h
* @brief sdrv rtc_reg api header.
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#ifndef _SDRV_RTC_REG_H_
#define _SDRV_RTC_REG_H_
#include <stdint.h>
#ifdef __cplusplus
#define __I volatile /**< Defines 'read-only' permissions */
#else
#define __I volatile const /**< Defines 'read-only' permissions */
#endif
#define __O volatile /**< Defines 'write-only' permissions */
#define __IO volatile /**< Defines 'read/write' permissions */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef struct {
__IO uint32_t SEC_RTC_CTRL; /*offset 0*/
__IO uint32_t RTC_H; /*offset 4*/
__IO uint32_t RTC_L; /*offset 8*/
__IO uint32_t AUTO_ADJUST; /*offset c*/
__IO uint32_t TIMER_H; /*offset 10*/
__IO uint32_t TIMER_L; /*offset 14*/
__IO uint32_t WAKEUP_CTRL; /*offset 18*/
__IO uint32_t PERIODICAL_CTRL; /*offset 1c*/
__IO uint32_t VIOLATION_INT; /*offset 20*/
__IO uint32_t APB_MONITOR_ERR_INJ_EN; /*offset 24*/
__IO uint32_t APB_MONITOR_ERR_INJ_ECC; /*offset 28*/
__IO uint32_t APB_MONITOR_ERR_INJ_WDATA; /*offset 2C*/
__IO uint32_t SAFETY_ERR_IRQ_STAT; /*offset 0x30*/
__IO uint32_t SAFETY_ERR_IRQ_STAT_EN; /*offset 0x34*/
__IO uint32_t SAFETY_ERR_IRQ_SIG_EN; /*offset 0x38*/
__IO uint32_t IRQ_ERR_INJ; /*offset 0x3C*/
__IO uint32_t IRQ_ERR_EJ_EN; /*offset 0x40*/
__IO uint32_t GP0; /*offset 0x44*/
__IO uint32_t GP1; /*offset 0X48*/
__IO uint32_t GP2; /*offset 0x4c*/
__IO uint32_t GP3; /*offset 0x50*/
__IO uint32_t RTC_H_HOLD_SHADOW; /*offset 0x54*/
__IO uint32_t RTC_L_HOLD_SHADOW; /*offset 0x58*/
__IO uint32_t RTC_WORKING_MODE; /*offset 0x5c*/
__IO uint32_t RTC_REGISTER_CROSS_CLOCK; /*offset 60*/
__IO uint32_t RTC_PARITY_ERR_INT_STAT; /*offset 0x64*/
__IO uint32_t RTC_PARITY_ERR_INT_STAT_EN; /*offset 0x68*/
__IO uint32_t RTC_PARITY_ERR_INT_SIG_EN; /*offset 0x6c*/
__IO uint32_t PRDATAINJ; /*offset 0x70*/
__IO uint32_t RTC_OUT_ERR_INJ; /*offset 0x74*/
} Rtc;
#endif
#define BM_SEC_RTC_CTRL_LOCK (0x01U << 31U)
#define BM_SEC_RTC_CTRL_RTC_LOCAL_ENABLE (0x01U << 0U)
#define BM_WAKEUP_CTRL_STATUS (0x01U << 3U)
#define BM_WAKEUP_CTRL_ENABLE (0x01U << 0U)
#define BM_WAKEUP_CTRL_IRQ_ENABLE (0x01U << 1U)
#define BM_WAKEUP_CTRL_REQ_ENABLE (0x01U << 2U)
#define BM_WAKEUP_CTRL_CLEAR (0x01U << 4U)
#define BM_SEC_RTC_CTRL_SECURE_ENABLE (0x01U << 1U)
#define BM_SEC_RTC_CTRL_PRIVILEGE_ENABLE (0x01U << 2U)
#define BM_RTC_REGISTER_CROSS_CLOCK_REGISTER_CROSS_CLOCK_EN (0x01U << 0U)
#define BM_WAKEUP_CTRL_OVERFLOW_CLEAR_BIT (5U)
#define BM_WAKEUP_CTRL_DISABLE_CLEAR_BIT (6U)
#define BM_RTC_WORKING_MODE_RTC_MASTER_SLAVE (0x01U << 0U)
#define BM_RTC_WORKING_MODE_RTC_COUNT_MODE (0x01U << 1U)
#define BM_VIOLATION_INT_OVERFLOW_STATS (0x01U << 2U)
#define BM_VIOLATION_INT_OVERFLOW_STATS_BIT (2U)
#define BM_PERIODICAL_CRTL_IRQ_ENABLE (0x01U << 0U)
#define BM_VIOLATION_INT_DISABLE_STATUS (0x01U << 3U)
#define FM_VIOLATION_INT_MASK (0x3U << 0U)
#define FV_VIOLATION_INT_MASK(v) \
(((v) << 0U) & FM_VIOLATION_INT_MASK)
#define FM_PERIODICAL_CRTL_FREQ (0xfU << 3U)
#define FV_PERIODICAL_CRTL_FREQ(v) \
(((v) << 3U) & FM_PERIODICAL_CRTL_FREQ)
#define FM_PERIODICAL_CRTL_FREQ (0xfU << 3U)
#define GFV_PERIODICAL_CRTL_FREQ(v) \
(((v) & FM_PERIODICAL_CRTL_FREQ) >> 3U)
void sec_rtc_set_cross_clk_en(Rtc *rtc);
void sec_rtc_set_rtc_ctrl(Rtc *rtc, uint32_t ctrl);
void sec_rtc_wakeup_enable(Rtc *rtc, uint8_t vtype, uint8_t en);
void sec_rtc_clear_wakeup_status(Rtc *rtc);
void sec_rtc_clear_violation_status(Rtc *rtc, uint8_t vio);
void sec_rtc_set_violation_enable(Rtc *rtc, uint8_t mask);
void sec_rtc_set_violation_disable(Rtc *rtc, uint8_t mask);
uint64_t sec_rtc_get_tick(Rtc *rtc);
uint8_t sec_rtc_get_violation_status(Rtc *rtc);
void sec_rtc_enable_periodical(Rtc *rtc, uint8_t en);
int sec_rtc_local_enable(Rtc *rtc, bool en);
void sec_rtc_set_tick(Rtc *rtc, uint64_t v);
uint64_t sec_rtc_get_alarm_tick(Rtc *rtc);
uint8_t sec_rtc_is_alarm_enable(Rtc *rtc);
bool sec_rtc_get_wakeup_status(Rtc *rtc);
void sec_rtc_set_alarm_tick(Rtc *rtc, uint64_t val);
uint64_t sec_rtc_get_hld_tick(Rtc *rtc, uint64_t *tick);
uint32_t sec_rtc_read_general_purpose_reg(Rtc *rtc, uint8_t gp_num);
void sec_rtc_write_general_purpose_reg(Rtc *rtc, uint8_t gp_num, uint32_t value);
void sec_rtc_lock(Rtc *rtc);
#endif /*_SDRV_RTC_REG_H_*/