forked from xuos/xiuos
add rtc wdt timer for xidatong-riscv64 board
This commit is contained in:
parent
9c15e587c4
commit
f2e633348a
|
@ -59,6 +59,9 @@ extern int HwI2cInit(void);
|
|||
extern int HwTouchInit(void);
|
||||
extern int HwCh438Init(void);
|
||||
extern int HwCh376Init(void);
|
||||
extern int HwTimerInit(void);
|
||||
extern int HwRtcInit(void);
|
||||
extern int HwWdtInit(void);
|
||||
|
||||
#ifdef FS_CH376
|
||||
#include <iot-vfs.h>
|
||||
|
@ -174,6 +177,15 @@ struct InitSequenceDesc _board_init[] =
|
|||
#ifdef BSP_USING_I2C
|
||||
{ "hw_i2c", HwI2cInit },
|
||||
#endif
|
||||
#ifdef BSP_USING_RTC
|
||||
{ "hw_rtc", HwRtcInit },
|
||||
#endif
|
||||
#ifdef BSP_USING_HWTIMER
|
||||
{ "hw_timer" , HwTimerInit },
|
||||
#endif
|
||||
#ifdef BSP_USING_WDT
|
||||
{ "hw_wdt", HwWdtInit },
|
||||
#endif
|
||||
#ifdef BSP_USING_SDIO
|
||||
{ "hw_sdio", HwCh376Init},
|
||||
#endif
|
||||
|
|
|
@ -53,6 +53,22 @@ if BSP_USING_PLIC
|
|||
source "$BSP_DIR/third_party_driver/plic/Kconfig"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_RTC
|
||||
bool "Using RTC device"
|
||||
default n
|
||||
select RESOURCES_RTC
|
||||
if BSP_USING_RTC
|
||||
source "$BSP_DIR/third_party_driver/rtc/Kconfig"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_HWTIMER
|
||||
bool "Using HWTIMER device"
|
||||
default n
|
||||
select RESOURCES_HWTIMER
|
||||
if BSP_USING_HWTIMER
|
||||
source "$BSP_DIR/third_party_driver/timer/Kconfig"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_SYSCLOCK
|
||||
bool "Using SYSCLOCK device"
|
||||
default y
|
||||
|
@ -67,3 +83,11 @@ select RESOURCES_SERIAL
|
|||
if BSP_USING_UART
|
||||
source "$BSP_DIR/third_party_driver/uart/Kconfig"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_WDT
|
||||
bool "Using WATCHDOG device"
|
||||
default n
|
||||
select RESOURCES_WDT
|
||||
if BSP_USING_WDT
|
||||
source "$BSP_DIR/third_party_driver/watchdog/Kconfig"
|
||||
endif
|
||||
|
|
|
@ -28,6 +28,14 @@ ifeq ($(CONFIG_BSP_USING_PLIC),y)
|
|||
SRC_DIR += plic
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_RTC),y)
|
||||
SRC_DIR += rtc
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_HWTIMER),y)
|
||||
SRC_DIR += timer
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_SYSCLOCK),y)
|
||||
SRC_DIR += sys_clock
|
||||
endif
|
||||
|
@ -36,4 +44,8 @@ ifeq ($(CONFIG_BSP_USING_UART),y)
|
|||
SRC_DIR += uart
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_WDT),y)
|
||||
SRC_DIR += watchdog
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_hwtimer.h
|
||||
* @brief define aiit-riscv64-board hwtimer function and struct
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#ifndef CONNECT_HWTIMER_H
|
||||
#define CONNECT_HWTIMER_H
|
||||
|
||||
#include <device.h>
|
||||
#include "hardware_hwtimer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int HwTimerInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_rtc.h
|
||||
* @brief define aiit-riscv64-board rtc function and struct
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#ifndef CONNECT_RTC_H
|
||||
#define CONNECT_RTC_H
|
||||
|
||||
#include <device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int HwRtcInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_wdt.h
|
||||
* @brief define aiit-riscv64-board wdt function and struct
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#ifndef CONNECT_WDT_H
|
||||
#define CONNECT_WDT_H
|
||||
|
||||
#include <device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int HwWdtInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,171 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hardware_hwtimer.h
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#ifndef __HARDWARE_HWTIMER_H__
|
||||
#define __HARDWARE_HWTIMER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* clang-format off */
|
||||
typedef struct _timer_channel
|
||||
{
|
||||
/* TIMER_N Load Count Register (0x00+(N-1)*0x14) */
|
||||
volatile uint32_t load_count;
|
||||
/* TIMER_N Current Value Register (0x04+(N-1)*0x14) */
|
||||
volatile uint32_t current_value;
|
||||
/* TIMER_N Control Register (0x08+(N-1)*0x14) */
|
||||
volatile uint32_t control;
|
||||
/* TIMER_N Interrupt Clear Register (0x0c+(N-1)*0x14) */
|
||||
volatile uint32_t eoi;
|
||||
/* TIMER_N Interrupt Status Register (0x10+(N-1)*0x14) */
|
||||
volatile uint32_t intr_stat;
|
||||
} __attribute__((packed, aligned(4))) timer_channel_t;
|
||||
|
||||
typedef struct _kendryte_timer
|
||||
{
|
||||
/* TIMER_N Register (0x00-0x4c) */
|
||||
volatile timer_channel_t channel[4];
|
||||
/* reserverd (0x50-0x9c) */
|
||||
volatile uint32_t resv1[20];
|
||||
/* TIMER Interrupt Status Register (0xa0) */
|
||||
volatile uint32_t intr_stat;
|
||||
/* TIMER Interrupt Clear Register (0xa4) */
|
||||
volatile uint32_t eoi;
|
||||
/* TIMER Raw Interrupt Status Register (0xa8) */
|
||||
volatile uint32_t raw_intr_stat;
|
||||
/* TIMER Component Version Register (0xac) */
|
||||
volatile uint32_t comp_version;
|
||||
/* TIMER_N Load Count2 Register (0xb0-0xbc) */
|
||||
volatile uint32_t load_count2[4];
|
||||
} __attribute__((packed, aligned(4))) kendryte_timer_t;
|
||||
|
||||
typedef enum _timer_deivce_number
|
||||
{
|
||||
TIMER_DEVICE_0,
|
||||
TIMER_DEVICE_1,
|
||||
TIMER_DEVICE_2,
|
||||
TIMER_DEVICE_MAX,
|
||||
} timer_device_number_t;
|
||||
|
||||
typedef enum _timer_channel_number
|
||||
{
|
||||
TIMER_CHANNEL_0,
|
||||
TIMER_CHANNEL_1,
|
||||
TIMER_CHANNEL_2,
|
||||
TIMER_CHANNEL_3,
|
||||
TIMER_CHANNEL_MAX,
|
||||
} timer_channel_number_t;
|
||||
|
||||
/* TIMER Control Register */
|
||||
#define TIMER_CR_ENABLE 0x00000001
|
||||
#define TIMER_CR_MODE_MASK 0x00000002
|
||||
#define TIMER_CR_FREE_MODE 0x00000000
|
||||
#define TIMER_CR_USER_MODE 0x00000002
|
||||
#define TIMER_CR_INTERRUPT_MASK 0x00000004
|
||||
#define TIMER_CR_PWM_ENABLE 0x00000008
|
||||
/* clang-format on */
|
||||
|
||||
extern volatile kendryte_timer_t *const timer[3];
|
||||
|
||||
/**
|
||||
* @brief Definitions for the timer callbacks
|
||||
*/
|
||||
typedef int (*timer_callback_t)(void *ctx);
|
||||
|
||||
/**
|
||||
* @brief Set timer timeout
|
||||
*
|
||||
* @param[in] timer timer
|
||||
* @param[in] channel channel
|
||||
* @param[in] nanoseconds timeout
|
||||
*
|
||||
* @return the real timeout
|
||||
*/
|
||||
size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds);
|
||||
|
||||
/**
|
||||
* @brief Init timer
|
||||
*
|
||||
* @param[in] timer timer
|
||||
*/
|
||||
void timer_init(timer_device_number_t timer_number);
|
||||
|
||||
/**
|
||||
* @brief [DEPRECATED] Set timer timeout function
|
||||
*
|
||||
* @param[in] timer timer
|
||||
* @param[in] channel channel
|
||||
* @param[in] func timeout function
|
||||
* @param[in] priority interrupt priority
|
||||
*
|
||||
*/
|
||||
void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority);
|
||||
|
||||
/**
|
||||
* @brief Register timer interrupt user callback function
|
||||
*
|
||||
* @param[in] device The timer device number
|
||||
* @param[in] channel The channel
|
||||
* @param[in] is_one_shot Indicates if single shot
|
||||
* @param[in] priority The priority
|
||||
* @param[in] callback The callback function
|
||||
* @param[in] ctx The context
|
||||
*
|
||||
* @return result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx);
|
||||
|
||||
/**
|
||||
* @brief Deregister timer interrupt user callback function
|
||||
*
|
||||
* @param[in] device The timer device number
|
||||
* @param[in] channel The channel
|
||||
*
|
||||
* @return result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel);
|
||||
|
||||
/**
|
||||
* @brief Enable timer
|
||||
*
|
||||
* @param[in] timer timer
|
||||
* @param[in] channel channel
|
||||
* @param[in] enable Enable or disable
|
||||
*
|
||||
*/
|
||||
void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TIMER_H__ */
|
|
@ -0,0 +1,448 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief A real-time clock (RTC) is a computer clock that keeps track of
|
||||
* the current time.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hardware_rtc.h
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#ifndef __HARDWARE_RTC_H__
|
||||
#define __HARDWARE_RTC_H__
|
||||
|
||||
#include <platform.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief RTC timer mode
|
||||
*
|
||||
* Timer mode selector
|
||||
* | Mode | Description |
|
||||
* |------|------------------------|
|
||||
* | 0 | Timer pause |
|
||||
* | 1 | Timer time running |
|
||||
* | 2 | Timer time setting |
|
||||
*/
|
||||
typedef enum _rtc_timer_mode_e
|
||||
{
|
||||
/* 0: Timer pause */
|
||||
RTC_TIMER_PAUSE,
|
||||
/* 1: Timer time running */
|
||||
RTC_TIMER_RUNNING,
|
||||
/* 2: Timer time setting */
|
||||
RTC_TIMER_SETTING,
|
||||
/* Max count of this enum*/
|
||||
RTC_TIMER_MAX
|
||||
} rtc_timer_mode_t;
|
||||
|
||||
/*
|
||||
* @brief RTC tick interrupt mode
|
||||
*
|
||||
* Tick interrupt mode selector
|
||||
* | Mode | Description |
|
||||
* |------|------------------------|
|
||||
* | 0 | Interrupt every second |
|
||||
* | 1 | Interrupt every minute |
|
||||
* | 2 | Interrupt every hour |
|
||||
* | 3 | Interrupt every day |
|
||||
*/
|
||||
typedef enum _rtc_tick_interrupt_mode_e
|
||||
{
|
||||
/* 0: Interrupt every second */
|
||||
RTC_INT_SECOND,
|
||||
/* 1: Interrupt every minute */
|
||||
RTC_INT_MINUTE,
|
||||
/* 2: Interrupt every hour */
|
||||
RTC_INT_HOUR,
|
||||
/* 3: Interrupt every day */
|
||||
RTC_INT_DAY,
|
||||
/* Max count of this enum*/
|
||||
RTC_INT_MAX
|
||||
} rtc_tick_interrupt_mode_t;
|
||||
|
||||
/**
|
||||
* @brief RTC mask structure
|
||||
*
|
||||
* RTC mask structure for common use
|
||||
*/
|
||||
typedef struct _rtc_mask
|
||||
{
|
||||
/* Reserved */
|
||||
uint32_t resv : 1;
|
||||
/* Second mask */
|
||||
uint32_t second : 1;
|
||||
/* Minute mask */
|
||||
uint32_t minute : 1;
|
||||
/* Hour mask */
|
||||
uint32_t hour : 1;
|
||||
/* Week mask */
|
||||
uint32_t week : 1;
|
||||
/* Day mask */
|
||||
uint32_t day : 1;
|
||||
/* Month mask */
|
||||
uint32_t month : 1;
|
||||
/* Year mask */
|
||||
uint32_t year : 1;
|
||||
} __attribute__((packed, aligned(1))) rtc_mask_t;
|
||||
|
||||
/**
|
||||
* @brief RTC register
|
||||
*
|
||||
* @note RTC register table
|
||||
*
|
||||
* | Offset | Name | Description |
|
||||
* |-----------|----------------|-------------------------------------|
|
||||
* | 0x00 | date | Timer date information |
|
||||
* | 0x04 | time | Timer time information |
|
||||
* | 0x08 | alarm_date | Alarm date information |
|
||||
* | 0x0c | alarm_time | Alarm time information |
|
||||
* | 0x10 | initial_count | Timer counter initial value |
|
||||
* | 0x14 | current_count | Timer counter current value |
|
||||
* | 0x18 | interrupt_ctrl | RTC interrupt settings |
|
||||
* | 0x1c | register_ctrl | RTC register settings |
|
||||
* | 0x20 | reserved0 | Reserved |
|
||||
* | 0x24 | reserved1 | Reserved |
|
||||
* | 0x28 | extended | Timer extended information |
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Timer date information
|
||||
*
|
||||
* No. 0 Register (0x00)
|
||||
*/
|
||||
typedef struct _rtc_date
|
||||
{
|
||||
/* Week. Range [0,6]. 0 is Sunday. */
|
||||
uint32_t week : 3;
|
||||
/* Reserved */
|
||||
uint32_t resv0 : 5;
|
||||
/* Day. Range [1,31] or [1,30] or [1,29] or [1,28] */
|
||||
uint32_t day : 5;
|
||||
/* Reserved */
|
||||
uint32_t resv1 : 3;
|
||||
/* Month. Range [1,12] */
|
||||
uint32_t month : 4;
|
||||
/* Year. Range [0,99] */
|
||||
uint32_t year : 12;
|
||||
} __attribute__((packed, aligned(4))) rtc_date_t;
|
||||
|
||||
/**
|
||||
* @brief Timer time information
|
||||
*
|
||||
* No. 1 Register (0x04)
|
||||
*/
|
||||
typedef struct _rtc_time
|
||||
{
|
||||
/* Reserved */
|
||||
uint32_t resv0 : 10;
|
||||
/* Second. Range [0,59] */
|
||||
uint32_t second : 6;
|
||||
/* Minute. Range [0,59] */
|
||||
uint32_t minute : 6;
|
||||
/* Reserved */
|
||||
uint32_t resv1 : 2;
|
||||
/* Hour. Range [0,23] */
|
||||
uint32_t hour : 5;
|
||||
/* Reserved */
|
||||
uint32_t resv2 : 3;
|
||||
} __attribute__((packed, aligned(4))) rtc_time_t;
|
||||
|
||||
/**
|
||||
* @brief Alarm date information
|
||||
*
|
||||
* No. 2 Register (0x08)
|
||||
*/
|
||||
typedef struct _rtc_alarm_date
|
||||
{
|
||||
/* Alarm Week. Range [0,6]. 0 is Sunday. */
|
||||
uint32_t week : 3;
|
||||
/* Reserved */
|
||||
uint32_t resv0 : 5;
|
||||
/* Alarm Day. Range [1,31] or [1,30] or [1,29] or [1,28] */
|
||||
uint32_t day : 5;
|
||||
/* Reserved */
|
||||
uint32_t resv1 : 3;
|
||||
/* Alarm Month. Range [1,12] */
|
||||
uint32_t month : 4;
|
||||
/* Alarm Year. Range [0,99] */
|
||||
uint32_t year : 12;
|
||||
} __attribute__((packed, aligned(4))) rtc_alarm_date_t;
|
||||
|
||||
/**
|
||||
* @brief Alarm time information
|
||||
*
|
||||
* No. 3 Register (0x0c)
|
||||
*/
|
||||
typedef struct _rtc_alarm_time
|
||||
{
|
||||
/* Reserved */
|
||||
uint32_t resv0 : 10;
|
||||
/* Alarm Second. Range [0,59] */
|
||||
uint32_t second : 6;
|
||||
/* Alarm Minute. Range [0,59] */
|
||||
uint32_t minute : 6;
|
||||
/* Reserved */
|
||||
uint32_t resv1 : 2;
|
||||
/* Alarm Hour. Range [0,23] */
|
||||
uint32_t hour : 5;
|
||||
/* Reserved */
|
||||
uint32_t resv2 : 3;
|
||||
} __attribute__((packed, aligned(4))) rtc_alarm_time_t;
|
||||
|
||||
/**
|
||||
* @brief Timer counter initial value
|
||||
*
|
||||
* No. 4 Register (0x10)
|
||||
*/
|
||||
typedef struct _rtc_initial_count
|
||||
{
|
||||
/* RTC counter initial value */
|
||||
uint32_t count : 32;
|
||||
} __attribute__((packed, aligned(4))) rtc_initial_count_t;
|
||||
|
||||
/**
|
||||
* @brief Timer counter current value
|
||||
*
|
||||
* No. 5 Register (0x14)
|
||||
*/
|
||||
typedef struct _rtc_current_count
|
||||
{
|
||||
/* RTC counter current value */
|
||||
uint32_t count : 32;
|
||||
} __attribute__((packed, aligned(4))) rtc_current_count_t;
|
||||
|
||||
/**
|
||||
* @brief RTC interrupt settings
|
||||
*
|
||||
* No. 6 Register (0x18)
|
||||
*/
|
||||
typedef struct _rtc_interrupt_ctrl
|
||||
{
|
||||
/* Reserved */
|
||||
uint32_t tick_enable : 1;
|
||||
/* Alarm interrupt enable */
|
||||
uint32_t alarm_enable : 1;
|
||||
/* Tick interrupt enable */
|
||||
uint32_t tick_int_mode : 2;
|
||||
/* Reserved */
|
||||
uint32_t resv : 20;
|
||||
/* Alarm compare mask for interrupt */
|
||||
uint32_t alarm_compare_mask : 8;
|
||||
} __attribute__((packed, aligned(4))) rtc_interrupt_ctrl_t;
|
||||
|
||||
/**
|
||||
* @brief RTC register settings
|
||||
*
|
||||
* No. 7 Register (0x1c)
|
||||
*/
|
||||
typedef struct _rtc_register_ctrl
|
||||
{
|
||||
/* RTC timer read enable */
|
||||
uint32_t read_enable : 1;
|
||||
/* RTC timer write enable */
|
||||
uint32_t write_enable : 1;
|
||||
/* Reserved */
|
||||
uint32_t resv0 : 11;
|
||||
/* RTC timer mask */
|
||||
uint32_t TimerMask : 8;
|
||||
/* RTC alarm mask */
|
||||
uint32_t alarm_mask : 8;
|
||||
/* RTC counter initial count value mask */
|
||||
uint32_t initial_count_mask : 1;
|
||||
/* RTC interrupt register mask */
|
||||
uint32_t interrupt_register_mask : 1;
|
||||
/* Reserved */
|
||||
uint32_t resv1 : 1;
|
||||
} __attribute__((packed, aligned(4))) rtc_register_ctrl_t;
|
||||
|
||||
/**
|
||||
* @brief Reserved
|
||||
*
|
||||
* No. 8 Register (0x20)
|
||||
*/
|
||||
typedef struct _rtc_reserved0
|
||||
{
|
||||
/* Reserved */
|
||||
uint32_t resv : 32;
|
||||
} __attribute__((packed, aligned(4))) rtc_reserved0_t;
|
||||
|
||||
/**
|
||||
* @brief Reserved
|
||||
*
|
||||
* No. 9 Register (0x24)
|
||||
*/
|
||||
typedef struct _rtc_reserved1
|
||||
{
|
||||
/* Reserved */
|
||||
uint32_t resv : 32;
|
||||
} __attribute__((packed, aligned(4))) rtc_reserved1_t;
|
||||
|
||||
/**
|
||||
* @brief Timer extended information
|
||||
*
|
||||
* No. 10 Register (0x28)
|
||||
*/
|
||||
typedef struct _rtc_extended
|
||||
{
|
||||
/* Century. Range [0,31] */
|
||||
uint32_t century : 5;
|
||||
/* Is leap year. 1 is leap year, 0 is not leap year */
|
||||
uint32_t leap_year : 1;
|
||||
/* Reserved */
|
||||
uint32_t resv : 26;
|
||||
} __attribute__((packed, aligned(4))) rtc_extended_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Real-time clock struct
|
||||
*
|
||||
* A real-time clock (RTC) is a computer clock that keeps track of
|
||||
* the current time.
|
||||
*/
|
||||
typedef struct _rtc
|
||||
{
|
||||
/* No. 0 (0x00): Timer date information */
|
||||
rtc_date_t date;
|
||||
/* No. 1 (0x04): Timer time information */
|
||||
rtc_time_t time;
|
||||
/* No. 2 (0x08): Alarm date information */
|
||||
rtc_alarm_date_t alarm_date;
|
||||
/* No. 3 (0x0c): Alarm time information */
|
||||
rtc_alarm_time_t alarm_time;
|
||||
/* No. 4 (0x10): Timer counter initial value */
|
||||
rtc_initial_count_t initial_count;
|
||||
/* No. 5 (0x14): Timer counter current value */
|
||||
rtc_current_count_t current_count;
|
||||
/* No. 6 (0x18): RTC interrupt settings */
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl;
|
||||
/* No. 7 (0x1c): RTC register settings */
|
||||
rtc_register_ctrl_t register_ctrl;
|
||||
/* No. 8 (0x20): Reserved */
|
||||
rtc_reserved0_t reserved0;
|
||||
/* No. 9 (0x24): Reserved */
|
||||
rtc_reserved1_t reserved1;
|
||||
/* No. 10 (0x28): Timer extended information */
|
||||
rtc_extended_t extended;
|
||||
} __attribute__((packed, aligned(4))) rtc_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Real-time clock object
|
||||
*/
|
||||
extern volatile rtc_t *const rtc;
|
||||
extern volatile uint32_t *const rtc_base;
|
||||
|
||||
/**
|
||||
* @brief Set date time to RTC
|
||||
*
|
||||
* @param[in] year The year
|
||||
* @param[in] month The month
|
||||
* @param[in] day The day
|
||||
* @param[in] hour The hour
|
||||
* @param[in] minute The minute
|
||||
* @param[in] second The second
|
||||
*
|
||||
* @return result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int rtc_timer_set(int year, int month, int day, int hour, int minute, int second);
|
||||
|
||||
/**
|
||||
* @brief Get date time from RTC
|
||||
*
|
||||
* @param year The year
|
||||
* @param month The month
|
||||
* @param day The day
|
||||
* @param hour The hour
|
||||
* @param minute The minute
|
||||
* @param second The second
|
||||
*
|
||||
* @return result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second);
|
||||
|
||||
/**
|
||||
* @brief Initialize RTC
|
||||
*
|
||||
* @return Result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int rtc_init(void);
|
||||
|
||||
/**
|
||||
* @brief Set RTC in protect mode or not
|
||||
*
|
||||
* @param enable Enable flag
|
||||
*
|
||||
* @return result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int rtc_protect_set(int enable);
|
||||
|
||||
/**
|
||||
* @brief Set RTC timer mode
|
||||
*
|
||||
* @param timer_mode Timer mode
|
||||
*
|
||||
*/
|
||||
void rtc_timer_set_mode(rtc_timer_mode_t timer_mode);
|
||||
|
||||
/**
|
||||
* @brief Set RTC timer clock frequency
|
||||
*
|
||||
* @param frequency Frequency
|
||||
*
|
||||
* @return result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int rtc_timer_set_clock_frequency(unsigned int frequency);
|
||||
|
||||
/**
|
||||
* @brief Set RTC timer clock count value
|
||||
*
|
||||
* @param count Count
|
||||
*
|
||||
* @return result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
int rtc_timer_set_clock_count_value(unsigned int count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DRIVER_RTC_H */
|
|
@ -0,0 +1,180 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file wdt.h
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#ifndef __WDT_H__
|
||||
#define __WDT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <plic.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* clang-format off */
|
||||
typedef struct _wdt
|
||||
{
|
||||
/* WDT Control Register (0x00) */
|
||||
volatile uint32_t cr;
|
||||
/* WDT Timeout Range Register (0x04) */
|
||||
volatile uint32_t torr;
|
||||
/* WDT Current Counter Value Register (0x08) */
|
||||
volatile uint32_t ccvr;
|
||||
/* WDT Counter Restart Register (0x0c) */
|
||||
volatile uint32_t crr;
|
||||
/* WDT Interrupt Status Register (0x10) */
|
||||
volatile uint32_t stat;
|
||||
/* WDT Interrupt Clear Register (0x14) */
|
||||
volatile uint32_t eoi;
|
||||
/* reserverd (0x18) */
|
||||
volatile uint32_t resv1;
|
||||
/* WDT Protection level Register (0x1c) */
|
||||
volatile uint32_t prot_level;
|
||||
/* reserved (0x20-0xe0) */
|
||||
volatile uint32_t resv4[49];
|
||||
/* WDT Component Parameters Register 5 (0xe4) */
|
||||
volatile uint32_t comp_param_5;
|
||||
/* WDT Component Parameters Register 4 (0xe8) */
|
||||
volatile uint32_t comp_param_4;
|
||||
/* WDT Component Parameters Register 3 (0xec) */
|
||||
volatile uint32_t comp_param_3;
|
||||
/* WDT Component Parameters Register 2 (0xf0) */
|
||||
volatile uint32_t comp_param_2;
|
||||
/* WDT Component Parameters Register 1 (0xf4) */
|
||||
volatile uint32_t comp_param_1;
|
||||
/* WDT Component Version Register (0xf8) */
|
||||
volatile uint32_t comp_version;
|
||||
/* WDT Component Type Register (0xfc) */
|
||||
volatile uint32_t comp_type;
|
||||
} __attribute__((packed, aligned(4))) wdt_t;
|
||||
|
||||
typedef enum _wdt_device_number
|
||||
{
|
||||
WDT_DEVICE_0,
|
||||
WDT_DEVICE_1,
|
||||
WDT_DEVICE_MAX,
|
||||
} wdt_device_number_t;
|
||||
|
||||
|
||||
#define WDT_RESET_ALL 0x00000000U
|
||||
#define WDT_RESET_CPU 0x00000001U
|
||||
|
||||
/* WDT Control Register */
|
||||
#define WDT_CR_ENABLE 0x00000001U
|
||||
#define WDT_CR_RMOD_MASK 0x00000002U
|
||||
#define WDT_CR_RMOD_RESET 0x00000000U
|
||||
#define WDT_CR_RMOD_INTERRUPT 0x00000002U
|
||||
#define WDT_CR_RPL_MASK 0x0000001CU
|
||||
#define WDT_CR_RPL(x) ((x) << 2)
|
||||
/* WDT Timeout Range Register */
|
||||
#define WDT_TORR_TOP_MASK 0x000000FFU
|
||||
#define WDT_TORR_TOP(x) ((x) << 4 | (x) << 0)
|
||||
/* WDT Current Counter Value Register */
|
||||
#define WDT_CCVR_MASK 0xFFFFFFFFU
|
||||
/* WDT Counter Restart Register */
|
||||
#define WDT_CRR_MASK 0x00000076U
|
||||
/* WDT Interrupt Status Register */
|
||||
#define WDT_STAT_MASK 0x00000001U
|
||||
/* WDT Interrupt Clear Register */
|
||||
#define WDT_EOI_MASK 0x00000001U
|
||||
/* WDT Protection level Register */
|
||||
#define WDT_PROT_LEVEL_MASK 0x00000007U
|
||||
/* WDT Component Parameter Register 5 */
|
||||
#define WDT_COMP_PARAM_5_CP_WDT_USER_TOP_MAX_MASK 0xFFFFFFFFU
|
||||
/* WDT Component Parameter Register 4 */
|
||||
#define WDT_COMP_PARAM_4_CP_WDT_USER_TOP_INIT_MAX_MASK 0xFFFFFFFFU
|
||||
/* WDT Component Parameter Register 3 */
|
||||
#define WDT_COMP_PARAM_3_CD_WDT_TOP_RST_MASK 0xFFFFFFFFU
|
||||
/* WDT Component Parameter Register 2 */
|
||||
#define WDT_COMP_PARAM_3_CP_WDT_CNT_RST_MASK 0xFFFFFFFFU
|
||||
/* WDT Component Parameter Register 1 */
|
||||
#define WDT_COMP_PARAM_1_WDT_ALWAYS_EN_MASK 0x00000001U
|
||||
#define WDT_COMP_PARAM_1_WDT_DFLT_RMOD_MASK 0x00000002U
|
||||
#define WDT_COMP_PARAM_1_WDT_DUAL_TOP_MASK 0x00000004U
|
||||
#define WDT_COMP_PARAM_1_WDT_HC_RMOD_MASK 0x00000008U
|
||||
#define WDT_COMP_PARAM_1_WDT_HC_RPL_MASK 0x00000010U
|
||||
#define WDT_COMP_PARAM_1_WDT_HC_TOP_MASK 0x00000020U
|
||||
#define WDT_COMP_PARAM_1_WDT_USE_FIX_TOP_MASK 0x00000040U
|
||||
#define WDT_COMP_PARAM_1_WDT_PAUSE_MASK 0x00000080U
|
||||
#define WDT_COMP_PARAM_1_APB_DATA_WIDTH_MASK 0x00000300U
|
||||
#define WDT_COMP_PARAM_1_WDT_DFLT_RPL_MASK 0x00001C00U
|
||||
#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_MASK 0x000F0000U
|
||||
#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_INIT_MASK 0x00F00000U
|
||||
#define WDT_COMP_PARAM_1_WDT_CNT_WIDTH_MASK 0x1F000000U
|
||||
/* WDT Component Version Register */
|
||||
#define WDT_COMP_VERSION_MASK 0xFFFFFFFFU
|
||||
/* WDT Component Type Register */
|
||||
#define WDT_COMP_TYPE_MASK 0xFFFFFFFFU
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* @brief Feed wdt
|
||||
*/
|
||||
void wdt_feed(wdt_device_number_t id);
|
||||
|
||||
/**
|
||||
* @brief Start wdt
|
||||
*
|
||||
* @param[in] id Wdt id 0 or 1
|
||||
* @param[in] time_out_ms Wdt trigger time
|
||||
* @param[in] on_irq Wdt interrupt callback
|
||||
*
|
||||
*/
|
||||
void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq);
|
||||
|
||||
/**
|
||||
* @brief Start wdt
|
||||
*
|
||||
* @param[in] id Wdt id 0 or 1
|
||||
* @param[in] time_out_ms Wdt trigger time
|
||||
* @param[in] on_irq Wdt interrupt callback
|
||||
* @param[in] ctx Param of callback
|
||||
*
|
||||
* @return Wdt time
|
||||
*
|
||||
*/
|
||||
uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx);
|
||||
|
||||
/**
|
||||
* @brief Stop wdt
|
||||
*
|
||||
* @param[in] id Wdt id 0 or 1
|
||||
*
|
||||
*/
|
||||
void wdt_stop(wdt_device_number_t id);
|
||||
|
||||
/**
|
||||
* @brief Clear wdt interrupt
|
||||
*
|
||||
* @param[in] id Wdt id 0 or 1
|
||||
*
|
||||
*/
|
||||
void wdt_clear_interrupt(wdt_device_number_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __WDT_H__ */
|
|
@ -0,0 +1,11 @@
|
|||
if BSP_USING_RTC
|
||||
config RTC_BUS_NAME
|
||||
string "rtc bus name"
|
||||
default "rtc"
|
||||
config RTC_DRV_NAME
|
||||
string "rtc bus driver name"
|
||||
default "rtc_drv"
|
||||
config RTC_DEVICE_NAME
|
||||
string "rtc bus device name"
|
||||
default "rtc_dev"
|
||||
endif
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES := connect_rtc.c hardware_rtc.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_rtc.c
|
||||
* @brief support aiit-riscv64-board rtc function and register to bus framework
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <connect_rtc.h>
|
||||
#include <hardware_rtc.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysctl.h>
|
||||
#include <time.h>
|
||||
|
||||
static int GetWeekDay(int year, int month, int day)
|
||||
{
|
||||
/* Magic method to get weekday */
|
||||
int weekday = (day += month < 3 ? year-- : year - 2,
|
||||
23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7;
|
||||
return weekday;
|
||||
}
|
||||
|
||||
static uint32 RtcConfigure(void *drv, struct BusConfigureInfo *configure_info)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
|
||||
struct RtcDriver *rtc_drv = (struct RtcDriver *)drv;
|
||||
struct RtcDrvConfigureParam *drv_param = (struct RtcDrvConfigureParam *)configure_info->private_data;
|
||||
|
||||
int cmd = drv_param->rtc_operation_cmd;
|
||||
time_t *time = drv_param->time;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case OPER_RTC_GET_TIME:
|
||||
{
|
||||
struct tm ct;
|
||||
int year,month,day,hour,minute,second;
|
||||
memset(&ct,0,sizeof(struct tm));
|
||||
|
||||
rtc_timer_get(&year, &month, &day, &hour, &minute, &second);
|
||||
|
||||
ct.tm_year = year - 1900;
|
||||
ct.tm_mon = month - 1;
|
||||
ct.tm_mday = day;
|
||||
ct.tm_wday = GetWeekDay(year, month, day);
|
||||
|
||||
ct.tm_hour = hour;
|
||||
ct.tm_min = minute;
|
||||
ct.tm_sec = second;
|
||||
|
||||
*time = mktime(&ct);
|
||||
}
|
||||
break;
|
||||
case OPER_RTC_SET_TIME:
|
||||
{
|
||||
struct tm *ct;
|
||||
struct tm tm_new;
|
||||
x_base lock;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
ct = localtime(time);
|
||||
memcpy(&tm_new, ct, sizeof(struct tm));
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
sysctl_reset(SYSCTL_RESET_RTC);
|
||||
sysctl_clock_enable(SYSCTL_CLOCK_RTC);
|
||||
rtc_protect_set(0);
|
||||
rtc_timer_set_clock_frequency(SysctlClockGetFreq(SYSCTL_CLOCK_IN0));
|
||||
rtc_timer_set_clock_count_value(1);
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
|
||||
if (rtc_timer_set(tm_new.tm_year+1900,tm_new.tm_mon+1,tm_new.tm_mday,
|
||||
tm_new.tm_hour,tm_new.tm_min,tm_new.tm_sec)==-1)
|
||||
return ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/*manage the rtc device operations*/
|
||||
static const struct RtcDevDone dev_done =
|
||||
{
|
||||
.open = NONE,
|
||||
.close = NONE,
|
||||
.write = NONE,
|
||||
.read = NONE,
|
||||
};
|
||||
|
||||
static int BoardRtcBusInit(struct RtcBus *rtc_bus, struct RtcDriver *rtc_driver)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
/*Init the rtc bus */
|
||||
ret = RtcBusInit(rtc_bus, RTC_BUS_NAME);
|
||||
if (EOK != ret) {
|
||||
KPrintf("HwRtcInit RtcBusInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Init the rtc driver*/
|
||||
ret = RtcDriverInit(rtc_driver, RTC_DRV_NAME);
|
||||
if (EOK != ret) {
|
||||
KPrintf("HwRtcInit RtcDriverInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Attach the rtc driver to the rtc bus*/
|
||||
ret = RtcDriverAttachToBus(RTC_DRV_NAME, RTC_BUS_NAME);
|
||||
if (EOK != ret) {
|
||||
KPrintf("HwRtcInit RtcDriverAttachToBus error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Attach the rtc device to the rtc bus*/
|
||||
static int BoardRtcDevBend(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
static struct RtcHardwareDevice rtc_device;
|
||||
memset(&rtc_device, 0, sizeof(struct RtcHardwareDevice));
|
||||
|
||||
rtc_device.dev_done = &(dev_done);
|
||||
|
||||
ret = RtcDeviceRegister(&rtc_device, NONE, RTC_DEVICE_NAME);
|
||||
if (EOK != ret) {
|
||||
KPrintf("HwRtcInit RtcDeviceInit device %s error %d\n", RTC_DEVICE_NAME, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = RtcDeviceAttachToBus(RTC_DEVICE_NAME, RTC_BUS_NAME);
|
||||
if (EOK != ret) {
|
||||
KPrintf("HwRtcInit RtcDeviceAttachToBus device %s error %d\n", RTC_DEVICE_NAME, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HwRtcInit(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
static struct RtcBus rtc_bus;
|
||||
memset(&rtc_bus, 0, sizeof(struct RtcBus));
|
||||
|
||||
static struct RtcDriver rtc_driver;
|
||||
memset(&rtc_driver, 0, sizeof(struct RtcDriver));
|
||||
|
||||
rtc_driver.configure = &(RtcConfigure);
|
||||
|
||||
ret = BoardRtcBusInit(&rtc_bus, &rtc_driver);
|
||||
if (EOK != ret) {
|
||||
KPrintf("HwRtcInit error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = BoardRtcDevBend();
|
||||
if (EOK != ret) {
|
||||
KPrintf("HwRtcInit error ret %u\n", ret);
|
||||
}
|
||||
|
||||
rtc_init();
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,597 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hardware_rtc.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <encoding.h>
|
||||
#include <hardware_rtc.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysctl.h>
|
||||
#include <time.h>
|
||||
|
||||
volatile rtc_t *const rtc = (volatile rtc_t *)RTC_BASE_ADDR;
|
||||
|
||||
struct tm rtc_date_time;
|
||||
|
||||
void rtc_timer_set_mode(rtc_timer_mode_t timer_mode)
|
||||
{
|
||||
rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
|
||||
|
||||
switch (timer_mode)
|
||||
{
|
||||
case RTC_TIMER_PAUSE:
|
||||
register_ctrl.read_enable = 0;
|
||||
register_ctrl.write_enable = 0;
|
||||
break;
|
||||
case RTC_TIMER_RUNNING:
|
||||
register_ctrl.read_enable = 1;
|
||||
register_ctrl.write_enable = 0;
|
||||
break;
|
||||
case RTC_TIMER_SETTING:
|
||||
register_ctrl.read_enable = 0;
|
||||
register_ctrl.write_enable = 1;
|
||||
break;
|
||||
default:
|
||||
register_ctrl.read_enable = 0;
|
||||
register_ctrl.write_enable = 0;
|
||||
break;
|
||||
}
|
||||
rtc->register_ctrl = register_ctrl;
|
||||
}
|
||||
|
||||
rtc_timer_mode_t rtc_timer_get_mode(void)
|
||||
{
|
||||
rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
|
||||
rtc_timer_mode_t timer_mode = RTC_TIMER_PAUSE;
|
||||
|
||||
if ((!register_ctrl.read_enable) && (!register_ctrl.write_enable))
|
||||
{
|
||||
/* RTC_TIMER_PAUSE */
|
||||
timer_mode = RTC_TIMER_PAUSE;
|
||||
}
|
||||
else if ((register_ctrl.read_enable) && (!register_ctrl.write_enable))
|
||||
{
|
||||
/* RTC_TIMER_RUNNING */
|
||||
timer_mode = RTC_TIMER_RUNNING;
|
||||
}
|
||||
else if ((!register_ctrl.read_enable) && (register_ctrl.write_enable)) {
|
||||
/* RTC_TIMER_SETTING */
|
||||
timer_mode = RTC_TIMER_SETTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Something is error, reset timer mode */
|
||||
rtc_timer_set_mode(timer_mode);
|
||||
}
|
||||
|
||||
return timer_mode;
|
||||
}
|
||||
|
||||
static inline int rtc_in_range(int value, int min, int max)
|
||||
{
|
||||
return ((value >= min) && (value <= max));
|
||||
}
|
||||
|
||||
int rtc_timer_set_tm(const struct tm *tm)
|
||||
{
|
||||
rtc_date_t timer_date;
|
||||
rtc_time_t timer_time;
|
||||
rtc_extended_t timer_extended;
|
||||
|
||||
if (tm)
|
||||
{
|
||||
/*
|
||||
* Range of tm->tm_sec could be [0,61]
|
||||
*
|
||||
* Range of tm->tm_sec allows for a positive leap second. Two
|
||||
* leap seconds in the same minute are not allowed (the C90
|
||||
* range 0..61 was a defect)
|
||||
*/
|
||||
if (rtc_in_range(tm->tm_sec, 0, 59))
|
||||
timer_time.second = tm->tm_sec;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_min could be [0,59] */
|
||||
if (rtc_in_range(tm->tm_min, 0, 59))
|
||||
timer_time.minute = tm->tm_min;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_hour could be [0, 23] */
|
||||
if (rtc_in_range(tm->tm_hour, 0, 23))
|
||||
timer_time.hour = tm->tm_hour;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_mday could be [1, 31] */
|
||||
if (rtc_in_range(tm->tm_mday, 1, 31))
|
||||
timer_date.day = tm->tm_mday;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Range of tm->tm_mon could be [0, 11]
|
||||
* But in this RTC, date.month should be [1, 12]
|
||||
*/
|
||||
if (rtc_in_range(tm->tm_mon, 0, 11))
|
||||
timer_date.month = tm->tm_mon + 1;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Range of tm->tm_year is the years since 1900
|
||||
* But in this RTC, year is split into year and century
|
||||
* In this RTC, century range is [0,31], year range is [0,99]
|
||||
*/
|
||||
int human_year = tm->tm_year + 1900;
|
||||
int rtc_year = human_year % 100;
|
||||
int rtc_century = human_year / 100;
|
||||
|
||||
if (rtc_in_range(rtc_year, 0, 99) &&
|
||||
rtc_in_range(rtc_century, 0, 31))
|
||||
{
|
||||
timer_date.year = rtc_year;
|
||||
timer_extended.century = rtc_century;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_wday could be [0, 6] */
|
||||
if (rtc_in_range(tm->tm_wday, 0, 6))
|
||||
timer_date.week = tm->tm_wday;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Set RTC mode to timer setting mode */
|
||||
rtc_timer_set_mode(RTC_TIMER_SETTING);
|
||||
/* Write value to RTC */
|
||||
rtc->date = timer_date;
|
||||
rtc->time = timer_time;
|
||||
rtc->extended = timer_extended;
|
||||
/* Get CPU current freq */
|
||||
unsigned long freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU);
|
||||
/* Set threshold to 1/26000000 s */
|
||||
freq = freq / 26000000;
|
||||
/* Get current CPU cycle */
|
||||
unsigned long start_cycle = read_cycle();
|
||||
/* Wait for 1/26000000 s to sync data */
|
||||
while (read_cycle() - start_cycle < freq)
|
||||
continue;
|
||||
/* Set RTC mode to timer running mode */
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_timer_set_alarm_tm(const struct tm *tm)
|
||||
{
|
||||
rtc_alarm_date_t alarm_date;
|
||||
rtc_alarm_time_t alarm_time;
|
||||
|
||||
if (tm) {
|
||||
/*
|
||||
* Range of tm->tm_sec could be [0,61]
|
||||
*
|
||||
* Range of tm->tm_sec allows for a positive leap second. Two
|
||||
* leap seconds in the same minute are not allowed (the C90
|
||||
* range 0..61 was a defect)
|
||||
*/
|
||||
if (rtc_in_range(tm->tm_sec, 0, 59))
|
||||
alarm_time.second = tm->tm_sec;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_min could be [0,59] */
|
||||
if (rtc_in_range(tm->tm_min, 0, 59))
|
||||
alarm_time.minute = tm->tm_min;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_hour could be [0, 23] */
|
||||
if (rtc_in_range(tm->tm_hour, 0, 23))
|
||||
alarm_time.hour = tm->tm_hour;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_mday could be [1, 31] */
|
||||
if (rtc_in_range(tm->tm_mday, 1, 31))
|
||||
alarm_date.day = tm->tm_mday;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Range of tm->tm_mon could be [0, 11]
|
||||
* But in this RTC, date.month should be [1, 12]
|
||||
*/
|
||||
if (rtc_in_range(tm->tm_mon, 0, 11))
|
||||
alarm_date.month = tm->tm_mon + 1;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Range of tm->tm_year is the years since 1900
|
||||
* But in this RTC, year is split into year and century
|
||||
* In this RTC, century range is [0,31], year range is [0,99]
|
||||
*/
|
||||
int human_year = tm->tm_year + 1900;
|
||||
int rtc_year = human_year % 100;
|
||||
int rtc_century = human_year / 100;
|
||||
|
||||
if (rtc_in_range(rtc_year, 0, 99) &&
|
||||
rtc_in_range(rtc_century, 0, 31))
|
||||
{
|
||||
alarm_date.year = rtc_year;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
/* Range of tm->tm_wday could be [0, 6] */
|
||||
if (rtc_in_range(tm->tm_wday, 0, 6))
|
||||
alarm_date.week = tm->tm_wday;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Write value to RTC */
|
||||
rtc->alarm_date = alarm_date;
|
||||
rtc->alarm_time = alarm_time;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtc_year_is_leap(int year)
|
||||
{
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
static int rtc_get_yday(int year, int month, int day)
|
||||
{
|
||||
static const int days[2][13] =
|
||||
{
|
||||
{0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
|
||||
{0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
|
||||
};
|
||||
int leap = rtc_year_is_leap(year);
|
||||
|
||||
return days[leap][month] + day;
|
||||
}
|
||||
|
||||
static int rtc_get_wday(int year, int month, int day)
|
||||
{
|
||||
/* Magic method to get weekday */
|
||||
int weekday = (day += month < 3 ? year-- : year - 2, 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7;
|
||||
return weekday;
|
||||
}
|
||||
|
||||
struct tm *rtc_timer_get_tm(void)
|
||||
{
|
||||
if (rtc_timer_get_mode() != RTC_TIMER_RUNNING)
|
||||
return NULL;
|
||||
|
||||
rtc_date_t timer_date = rtc->date;
|
||||
rtc_time_t timer_time = rtc->time;
|
||||
rtc_extended_t timer_extended = rtc->extended;
|
||||
|
||||
struct tm *tm = &rtc_date_time;
|
||||
|
||||
tm->tm_sec = timer_time.second % 60;
|
||||
tm->tm_min = timer_time.minute % 60;
|
||||
tm->tm_hour = timer_time.hour % 24;
|
||||
tm->tm_mday = (timer_date.day - 1) % 31 + 1;
|
||||
tm->tm_mon = (timer_date.month - 1)% 12;
|
||||
tm->tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900;
|
||||
tm->tm_wday = timer_date.week;
|
||||
tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
tm->tm_isdst = -1;
|
||||
|
||||
return tm;
|
||||
}
|
||||
|
||||
struct tm *rtc_timer_get_alarm_tm(void)
|
||||
{
|
||||
if (rtc_timer_get_mode() != RTC_TIMER_RUNNING)
|
||||
return NULL;
|
||||
|
||||
rtc_alarm_date_t alarm_date = rtc->alarm_date;
|
||||
rtc_alarm_time_t alarm_time = rtc->alarm_time;
|
||||
rtc_extended_t timer_extended = rtc->extended;
|
||||
|
||||
struct tm *tm = &rtc_date_time;
|
||||
|
||||
tm->tm_sec = alarm_time.second % 60;
|
||||
tm->tm_min = alarm_time.minute % 60;
|
||||
tm->tm_hour = alarm_time.hour % 24;
|
||||
tm->tm_mday = alarm_date.day % 31;
|
||||
tm->tm_mon = (alarm_date.month % 12) - 1;
|
||||
/* Alarm and Timer use same timer_extended.century */
|
||||
tm->tm_year = (alarm_date.year % 100) + (timer_extended.century * 100) - 1900;
|
||||
tm->tm_wday = alarm_date.week;
|
||||
tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
tm->tm_isdst = -1;
|
||||
|
||||
return tm;
|
||||
}
|
||||
|
||||
int rtc_timer_set(int year, int month, int day, int hour, int minute, int second)
|
||||
{
|
||||
struct tm date_time =
|
||||
{
|
||||
.tm_sec = second,
|
||||
.tm_min = minute,
|
||||
.tm_hour = hour,
|
||||
.tm_mday = day,
|
||||
.tm_mon = month - 1,
|
||||
.tm_year = year - 1900,
|
||||
.tm_wday = rtc_get_wday(year, month, day),
|
||||
.tm_yday = rtc_get_yday(year, month, day),
|
||||
.tm_isdst = -1,
|
||||
};
|
||||
return rtc_timer_set_tm(&date_time);
|
||||
}
|
||||
|
||||
int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second)
|
||||
{
|
||||
struct tm *tm = rtc_timer_get_tm();
|
||||
|
||||
if (tm)
|
||||
{
|
||||
if (year)
|
||||
*year = tm->tm_year + 1900;
|
||||
if (month)
|
||||
*month = tm->tm_mon + 1;
|
||||
if (day)
|
||||
*day = tm->tm_mday;
|
||||
if (hour)
|
||||
*hour = tm->tm_hour;
|
||||
if (minute)
|
||||
*minute = tm->tm_min;
|
||||
if (second)
|
||||
*second = tm->tm_sec;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_timer_set_alarm(int year, int month, int day, int hour, int minute, int second)
|
||||
{
|
||||
struct tm date_time = {
|
||||
.tm_sec = second,
|
||||
.tm_min = minute,
|
||||
.tm_hour = hour,
|
||||
.tm_mday = day,
|
||||
.tm_mon = month - 1,
|
||||
.tm_year = year - 1900,
|
||||
.tm_wday = rtc_get_wday(year, month, day),
|
||||
.tm_yday = rtc_get_yday(year, month, day),
|
||||
.tm_isdst = -1,
|
||||
};
|
||||
|
||||
return rtc_timer_set_alarm_tm(&date_time);
|
||||
}
|
||||
|
||||
int rtc_timer_get_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second)
|
||||
{
|
||||
struct tm *tm = rtc_timer_get_alarm_tm();
|
||||
|
||||
if (tm) {
|
||||
if (year)
|
||||
*year = tm->tm_year + 1900;
|
||||
if (month)
|
||||
*month = tm->tm_mon + 1;
|
||||
if (day)
|
||||
*day = tm->tm_mday;
|
||||
if (hour)
|
||||
*hour = tm->tm_hour;
|
||||
if (minute)
|
||||
*minute = tm->tm_min;
|
||||
if (second)
|
||||
*second = tm->tm_sec;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_timer_set_clock_frequency(unsigned int frequency)
|
||||
{
|
||||
|
||||
rtc_initial_count_t initial_count;
|
||||
|
||||
initial_count.count = frequency;
|
||||
rtc_timer_set_mode(RTC_TIMER_SETTING);
|
||||
rtc->initial_count = initial_count;
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int rtc_timer_get_clock_frequency(void)
|
||||
{
|
||||
return rtc->initial_count.count;
|
||||
}
|
||||
|
||||
int rtc_timer_set_clock_count_value(unsigned int count)
|
||||
{
|
||||
|
||||
rtc_current_count_t current_count;
|
||||
|
||||
current_count.count = count;
|
||||
rtc_timer_set_mode(RTC_TIMER_SETTING);
|
||||
rtc->current_count = current_count;
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int rtc_timer_get_clock_count_value(void)
|
||||
{
|
||||
return rtc->current_count.count;
|
||||
}
|
||||
|
||||
int rtc_tick_interrupt_set(int enable)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
interrupt_ctrl.tick_enable = enable;
|
||||
rtc_timer_set_mode(RTC_TIMER_SETTING);
|
||||
rtc->interrupt_ctrl = interrupt_ctrl;
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_tick_interrupt_get(void)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
|
||||
return interrupt_ctrl.tick_enable;
|
||||
}
|
||||
|
||||
int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_t mode)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
|
||||
interrupt_ctrl.tick_int_mode = mode;
|
||||
rtc_timer_set_mode(RTC_TIMER_SETTING);
|
||||
rtc->interrupt_ctrl = interrupt_ctrl;
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtc_tick_interrupt_mode_t rtc_tick_interrupt_mode_get(void)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
|
||||
return interrupt_ctrl.tick_int_mode;
|
||||
}
|
||||
|
||||
int rtc_alarm_interrupt_set(int enable)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
|
||||
interrupt_ctrl.alarm_enable = enable;
|
||||
rtc->interrupt_ctrl = interrupt_ctrl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_alarm_interrupt_get(void)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
|
||||
return interrupt_ctrl.alarm_enable;
|
||||
}
|
||||
|
||||
int rtc_alarm_interrupt_mask_set(rtc_mask_t mask)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
|
||||
interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask;
|
||||
rtc->interrupt_ctrl = interrupt_ctrl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtc_mask_t rtc_alarm_interrupt_mask_get(void)
|
||||
{
|
||||
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
|
||||
|
||||
uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask;
|
||||
|
||||
return *(rtc_mask_t *)&compare_mask;
|
||||
}
|
||||
|
||||
int rtc_protect_set(int enable)
|
||||
{
|
||||
rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
|
||||
|
||||
rtc_mask_t mask =
|
||||
{
|
||||
.second = 1,
|
||||
/* Second mask */
|
||||
.minute = 1,
|
||||
/* Minute mask */
|
||||
.hour = 1,
|
||||
/* Hour mask */
|
||||
.week = 1,
|
||||
/* Week mask */
|
||||
.day = 1,
|
||||
/* Day mask */
|
||||
.month = 1,
|
||||
/* Month mask */
|
||||
.year = 1,
|
||||
};
|
||||
|
||||
rtc_mask_t unmask =
|
||||
{
|
||||
.second = 0,
|
||||
/* Second mask */
|
||||
.minute = 0,
|
||||
/* Minute mask */
|
||||
.hour = 0,
|
||||
/* Hour mask */
|
||||
.week = 0,
|
||||
/* Week mask */
|
||||
.day = 0,
|
||||
/* Day mask */
|
||||
.month = 0,
|
||||
/* Month mask */
|
||||
.year = 0,
|
||||
};
|
||||
|
||||
if (enable)
|
||||
{
|
||||
/* Turn RTC in protect mode, no one can write time */
|
||||
register_ctrl.TimerMask = *(uint8_t *)&unmask;
|
||||
register_ctrl.alarm_mask = *(uint8_t *)&unmask;
|
||||
register_ctrl.initial_count_mask = 0;
|
||||
register_ctrl.interrupt_register_mask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Turn RTC in unprotect mode, everyone can write time */
|
||||
register_ctrl.TimerMask = *(uint8_t *)&mask;
|
||||
register_ctrl.alarm_mask = *(uint8_t *)&mask;
|
||||
register_ctrl.initial_count_mask = 1;
|
||||
register_ctrl.interrupt_register_mask = 1;
|
||||
}
|
||||
rtc_timer_set_mode(RTC_TIMER_SETTING);
|
||||
rtc->register_ctrl = register_ctrl;
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_init(void)
|
||||
{
|
||||
/* Reset RTC */
|
||||
sysctl_reset(SYSCTL_RESET_RTC);
|
||||
/* Enable RTC */
|
||||
sysctl_clock_enable(SYSCTL_CLOCK_RTC);
|
||||
/* Unprotect RTC */
|
||||
rtc_protect_set(0);
|
||||
/* Set RTC clock frequency */
|
||||
rtc_timer_set_clock_frequency(
|
||||
SysctlClockGetFreq(SYSCTL_CLOCK_IN0)
|
||||
);
|
||||
rtc_timer_set_clock_count_value(1);
|
||||
|
||||
/* Set RTC mode to timer running mode */
|
||||
rtc_timer_set_mode(RTC_TIMER_RUNNING);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
if BSP_USING_HWTIMER
|
||||
config HWTIMER_BUS_NAME_1
|
||||
string "hwtimer bus name"
|
||||
default "hwtim1"
|
||||
|
||||
menuconfig ENABLE_TIM1
|
||||
bool "enable TIM1"
|
||||
default y
|
||||
|
||||
if ENABLE_TIM1
|
||||
config HWTIMER_1_DEVICE_NAME_1
|
||||
string "TIM1 dev name"
|
||||
default "hwtim1_dev1"
|
||||
|
||||
config HWTIMER_DRIVER_NAME_1
|
||||
string "TIM1 drv name"
|
||||
default "hwtim1_drv"
|
||||
endif
|
||||
endif
|
|
@ -0,0 +1,5 @@
|
|||
SRC_FILES := hardware_hwtimer.c connect_hwtimer.c
|
||||
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_hwtimer.c
|
||||
* @brief support aiit-riscv64-board hwtimer function and register to bus framework
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include <connect_hwtimer.h>
|
||||
#include <fpioa.h>
|
||||
#include <plic.h>
|
||||
#include <stdio.h>
|
||||
#include <sysctl.h>
|
||||
#include <syslog.h>
|
||||
|
||||
static struct HwtimerCallBackInfo *ptim2_cb_info = NULL;
|
||||
|
||||
int timer_callback(void *ctx)
|
||||
{
|
||||
if (ptim2_cb_info) {
|
||||
if (ptim2_cb_info->timeout_callback) {
|
||||
ptim2_cb_info->timeout_callback(ptim2_cb_info->param);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 HwtimerOpen(void *dev)
|
||||
{
|
||||
struct HwtimerHardwareDevice *hwtimer_dev = dev;
|
||||
|
||||
ptim2_cb_info = &hwtimer_dev->hwtimer_param.cb_info;
|
||||
|
||||
plic_init();
|
||||
sysctl_enable_irq();
|
||||
timer_init(TIMER_DEVICE_1);
|
||||
|
||||
size_t real_time = timer_set_interval(TIMER_DEVICE_1, TIMER_CHANNEL_1, hwtimer_dev->hwtimer_param.period_millisecond *1000);
|
||||
KPrintf("timer_set_interval -- real_time : %ld\n", real_time);
|
||||
timer_irq_register(TIMER_DEVICE_1, TIMER_CHANNEL_1, !hwtimer_dev->hwtimer_param.repeat, 1, timer_callback, NULL);
|
||||
|
||||
timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 1);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
uint32 HwtimerClose(void *dev)
|
||||
{
|
||||
timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 0);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/*manage the hwtimer device operations*/
|
||||
static const struct HwtimerDevDone dev_done =
|
||||
{
|
||||
.open = HwtimerOpen,
|
||||
.close = HwtimerClose,
|
||||
.write = NONE,
|
||||
.read = NONE,
|
||||
};
|
||||
|
||||
/*Init hwtimer bus*/
|
||||
static int BoardHwtimerBusInit(struct HwtimerBus *hwtimer_bus, struct HwtimerDriver *hwtimer_driver)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
/*Init the hwtimer bus */
|
||||
ret = HwtimerBusInit(hwtimer_bus, HWTIMER_BUS_NAME_1);
|
||||
if (EOK != ret) {
|
||||
KPrintf("board_hwtimer_init HwtimerBusInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Init the hwtimer driver*/
|
||||
hwtimer_driver->configure = NONE;
|
||||
ret = HwtimerDriverInit(hwtimer_driver, HWTIMER_DRIVER_NAME_1);
|
||||
if (EOK != ret) {
|
||||
KPrintf("board_hwtimer_init HwtimerDriverInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Attach the hwtimer driver to the hwtimer bus*/
|
||||
ret = HwtimerDriverAttachToBus(HWTIMER_DRIVER_NAME_1, HWTIMER_BUS_NAME_1);
|
||||
if (EOK != ret) {
|
||||
KPrintf("board_hwtimer_init USEDriverAttachToBus error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Attach the hwtimer device to the hwtimer bus*/
|
||||
static int BoardHwtimerDevBend(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
static struct HwtimerHardwareDevice hwtimer_device_0;
|
||||
memset(&hwtimer_device_0, 0, sizeof(struct HwtimerHardwareDevice));
|
||||
|
||||
hwtimer_device_0.dev_done = &dev_done;
|
||||
|
||||
ret = HwtimerDeviceRegister(&hwtimer_device_0, NONE, HWTIMER_1_DEVICE_NAME_1);
|
||||
if (EOK != ret) {
|
||||
KPrintf("BoardHwtimerDevBend HwtimerDeviceRegister device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = HwtimerDeviceAttachToBus(HWTIMER_1_DEVICE_NAME_1, HWTIMER_BUS_NAME_1);
|
||||
if (EOK != ret) {
|
||||
KPrintf("BoardHwtimerDevBend HwtimerDeviceAttachToBus device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*K210 BOARD HWTIMER INIT*/
|
||||
int HwTimerInit(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
static struct HwtimerBus hwtimer_bus;
|
||||
memset(&hwtimer_bus, 0, sizeof(struct HwtimerBus));
|
||||
|
||||
static struct HwtimerDriver hwtimer_driver;
|
||||
memset(&hwtimer_driver, 0, sizeof(struct HwtimerDriver));
|
||||
|
||||
ret = BoardHwtimerBusInit(&hwtimer_bus, &hwtimer_driver);
|
||||
if (EOK != ret) {
|
||||
KPrintf("board_hwtimer_Init error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = BoardHwtimerDevBend();
|
||||
if (EOK != ret) {
|
||||
KPrintf("board_hwtimer_Init error ret %u\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,407 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hardware_hwtimer.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <hardware_hwtimer.h>
|
||||
#include <io.h>
|
||||
#include <plic.h>
|
||||
#include <stddef.h>
|
||||
#include <sysctl.h>
|
||||
#include <syslog.h>
|
||||
#include <xs_isr.h>
|
||||
#include <utils.h>
|
||||
|
||||
/**
|
||||
* @brief Private definitions for the timer instance
|
||||
*/
|
||||
typedef struct timer_instance
|
||||
{
|
||||
timer_callback_t callback;
|
||||
void *ctx;
|
||||
bool single_shot;
|
||||
} timer_instance_t;
|
||||
|
||||
typedef void(*irq_manager_callback_t)(int irq, void* arg);
|
||||
|
||||
volatile timer_instance_t timer_instance[TIMER_DEVICE_MAX][TIMER_CHANNEL_MAX];
|
||||
|
||||
volatile kendryte_timer_t *const timer[3] =
|
||||
{
|
||||
(volatile kendryte_timer_t *)TIMER0_BASE_ADDR,
|
||||
(volatile kendryte_timer_t *)TIMER1_BASE_ADDR,
|
||||
(volatile kendryte_timer_t *)TIMER2_BASE_ADDR
|
||||
};
|
||||
|
||||
void timer_init(timer_device_number_t timer_number)
|
||||
{
|
||||
for(size_t i = 0; i < TIMER_CHANNEL_MAX; i++)
|
||||
timer_instance[timer_number][i] = (const timer_instance_t) {
|
||||
.callback = NULL,
|
||||
.ctx = NULL,
|
||||
.single_shot = 0,
|
||||
};
|
||||
|
||||
sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + timer_number);
|
||||
}
|
||||
|
||||
void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div)
|
||||
{
|
||||
sysctl_clock_set_threshold(timer_number == 0 ? SYSCTL_THRESHOLD_TIMER0 :
|
||||
timer_number == 1 ? SYSCTL_THRESHOLD_TIMER1 :
|
||||
SYSCTL_THRESHOLD_TIMER2, div);
|
||||
}
|
||||
|
||||
void timer_enable(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
timer[timer_number]->channel[channel].control |= TIMER_CR_ENABLE;
|
||||
}
|
||||
|
||||
void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
timer[timer_number]->channel[channel].control &= (~TIMER_CR_ENABLE);
|
||||
}
|
||||
|
||||
void timer_enable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
timer[timer_number]->channel[channel].control |= TIMER_CR_PWM_ENABLE;
|
||||
}
|
||||
|
||||
void timer_disable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
timer[timer_number]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE);
|
||||
}
|
||||
|
||||
void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
timer[timer_number]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK);
|
||||
}
|
||||
|
||||
void timer_disable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
timer[timer_number]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK;
|
||||
}
|
||||
|
||||
void timer_set_mode(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t mode)
|
||||
{
|
||||
timer[timer_number]->channel[channel].control &= (~TIMER_CR_MODE_MASK);
|
||||
timer[timer_number]->channel[channel].control |= mode;
|
||||
}
|
||||
|
||||
void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count)
|
||||
{
|
||||
timer[timer_number]->channel[channel].load_count = count;
|
||||
}
|
||||
|
||||
void timer_set_reload2(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count)
|
||||
{
|
||||
timer[timer_number]->load_count2[channel] = count;
|
||||
}
|
||||
|
||||
uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
return timer[timer_number]->channel[channel].current_value;
|
||||
}
|
||||
|
||||
uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
return timer[timer_number]->channel[channel].load_count;
|
||||
}
|
||||
|
||||
uint32_t timer_get_reload2(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
return timer[timer_number]->load_count2[channel];
|
||||
}
|
||||
|
||||
uint32_t timer_get_interrupt_status(timer_device_number_t timer_number)
|
||||
{
|
||||
return timer[timer_number]->intr_stat;
|
||||
}
|
||||
|
||||
uint32_t timer_get_raw_interrupt_status(timer_device_number_t timer_number)
|
||||
{
|
||||
return timer[timer_number]->raw_intr_stat;
|
||||
}
|
||||
|
||||
uint32_t timer_channel_get_interrupt_status(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
return timer[timer_number]->channel[channel].intr_stat;
|
||||
}
|
||||
|
||||
void timer_clear_interrupt(timer_device_number_t timer_number)
|
||||
{
|
||||
timer[timer_number]->eoi = timer[timer_number]->eoi;
|
||||
}
|
||||
|
||||
void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
|
||||
{
|
||||
timer[timer_number]->channel[channel].eoi = timer[timer_number]->channel[channel].eoi;
|
||||
}
|
||||
|
||||
void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable)
|
||||
{
|
||||
if (enable)
|
||||
timer[timer_number]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE;
|
||||
else
|
||||
timer[timer_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK;
|
||||
}
|
||||
|
||||
size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t useconds)
|
||||
{
|
||||
uint32_t clk_freq = SysctlClockGetFreq(SYSCTL_CLOCK_TIMER0 + timer_number);
|
||||
|
||||
double min_step = 1e6 / clk_freq;
|
||||
size_t value = (size_t)(useconds / min_step);
|
||||
configASSERT(value > 0 && value < UINT32_MAX);
|
||||
timer[timer_number]->channel[channel].load_count = (uint32_t)value;
|
||||
return (size_t)(min_step * value);
|
||||
}
|
||||
|
||||
typedef void(*timer_ontick)();
|
||||
timer_ontick time_irq[3][4] = { NULL };
|
||||
|
||||
static int timer_isr(void *parm)
|
||||
{
|
||||
uint32_t timer_number;
|
||||
for (timer_number = 0; timer_number < 3; timer_number++)
|
||||
{
|
||||
if (parm == timer[timer_number])
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t channel = timer[timer_number]->intr_stat;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (channel & 1)
|
||||
{
|
||||
if (time_irq[timer_number][i])
|
||||
(time_irq[timer_number][i])();
|
||||
break;
|
||||
}
|
||||
|
||||
channel >>= 1;
|
||||
}
|
||||
|
||||
readl(&timer[timer_number]->eoi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority)
|
||||
{
|
||||
time_irq[timer_number][channel] = func;
|
||||
if (channel < 2)
|
||||
{
|
||||
plic_set_priority(IRQN_TIMER0A_INTERRUPT + timer_number * 2, priority);
|
||||
plic_irq_register(IRQN_TIMER0A_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]);
|
||||
plic_irq_enable(IRQN_TIMER0A_INTERRUPT + timer_number * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
plic_set_priority(IRQN_TIMER0B_INTERRUPT + timer_number * 2, priority);
|
||||
plic_irq_register(IRQN_TIMER0B_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]);
|
||||
plic_irq_enable(IRQN_TIMER0B_INTERRUPT + timer_number * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the timer irqn by device and channel object
|
||||
*
|
||||
* @note Internal function, not public
|
||||
* @param device The device
|
||||
* @param channel The channel
|
||||
* @return plic_irq_t IRQ number
|
||||
*/
|
||||
static plic_irq_t get_timer_irqn_by_device_and_channel(timer_device_number_t device, timer_channel_number_t channel)
|
||||
{
|
||||
if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) {
|
||||
/*
|
||||
* Select timer interrupt part
|
||||
* Hierarchy of Timer interrupt to PLIC
|
||||
* +---------+ +-----------+
|
||||
* | 0+----+ | |
|
||||
* | | +--+0A |
|
||||
* | 1+----+ | |
|
||||
* | TIMER0 | | |
|
||||
* | 2+----+ | |
|
||||
* | | +--+0B |
|
||||
* | 3+----+ | |
|
||||
* +---------+ | |
|
||||
* | |
|
||||
* +---------+ | |
|
||||
* | 0+----+ | |
|
||||
* | | +--+1A |
|
||||
* | 1+----+ | |
|
||||
* | TIMER1 | | PLIC |
|
||||
* | 2+----+ | |
|
||||
* | | +--+1B |
|
||||
* | 3+----+ | |
|
||||
* +---------+ | |
|
||||
* | |
|
||||
* +---------+ | |
|
||||
* | 0+----+ | |
|
||||
* | | +--+2A |
|
||||
* | 1+----+ | |
|
||||
* | TIMER2 | | |
|
||||
* | 2+----+ | |
|
||||
* | | +--+2B |
|
||||
* | 3+----+ | |
|
||||
* +---------+ +-----------+
|
||||
*
|
||||
*/
|
||||
if (channel < 2) {
|
||||
/* It is part A interrupt, offset + 0 */
|
||||
return IRQN_TIMER0A_INTERRUPT + device * 2;
|
||||
}
|
||||
else {
|
||||
/* It is part B interrupt, offset + 1 */
|
||||
return IRQN_TIMER0B_INTERRUPT + device * 2;
|
||||
}
|
||||
}
|
||||
return IRQN_NO_INTERRUPT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Process user callback function
|
||||
*
|
||||
* @note Internal function, not public
|
||||
* @param device The timer device
|
||||
* @param ctx The context
|
||||
* @return int The callback result
|
||||
*/
|
||||
static int timer_interrupt_handler(timer_device_number_t device, void *ctx)
|
||||
{
|
||||
uint32_t channel_int_stat = timer[device]->intr_stat;
|
||||
|
||||
for (size_t i = 0; i < TIMER_CHANNEL_MAX; i++)
|
||||
{
|
||||
/* Check every bit for interrupt status */
|
||||
if (channel_int_stat & 1)
|
||||
{
|
||||
if (timer_instance[device][i].callback) {
|
||||
/* Process user callback function */
|
||||
timer_instance[device][i].callback(timer_instance[device][i].ctx);
|
||||
/* Check if this timer is a single shot timer */
|
||||
if (timer_instance[device][i].single_shot) {
|
||||
/* Single shot timer, disable it */
|
||||
timer_set_enable(device, i, 0);
|
||||
}
|
||||
}
|
||||
/* Clear timer interrupt flag for specific channel */
|
||||
readl(&timer[device]->channel[i].eoi);
|
||||
}
|
||||
channel_int_stat >>= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* Don't read timer[device]->eoi here, or you will lost some interrupt
|
||||
* readl(&timer[device]->eoi);
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function bus for timer interrupt
|
||||
*
|
||||
* @note Internal function, not public
|
||||
* @param ctx The context
|
||||
* @return int The callback result
|
||||
*/
|
||||
static void timer0_interrupt_callback(int irq, void *ctx)
|
||||
{
|
||||
timer_interrupt_handler(TIMER_DEVICE_0, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function bus for timer interrupt
|
||||
*
|
||||
* @note Internal function, not public
|
||||
* @param ctx The context
|
||||
* @return int The callback result
|
||||
*/
|
||||
static void timer1_interrupt_callback(int irq, void *ctx)
|
||||
{
|
||||
timer_interrupt_handler(TIMER_DEVICE_1, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function bus for timer interrupt
|
||||
*
|
||||
* @note Internal function, not public
|
||||
* @param ctx The context
|
||||
* @return int The callback result
|
||||
*/
|
||||
static void timer2_interrupt_callback(int irq, void *ctx)
|
||||
{
|
||||
timer_interrupt_handler(TIMER_DEVICE_2, ctx);
|
||||
}
|
||||
|
||||
int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx)
|
||||
{
|
||||
if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) {
|
||||
plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel);
|
||||
irq_manager_callback_t plic_irq_callback[TIMER_DEVICE_MAX] = {
|
||||
timer0_interrupt_callback,
|
||||
timer1_interrupt_callback,
|
||||
timer2_interrupt_callback,
|
||||
};
|
||||
|
||||
timer_instance[device][channel] = (const timer_instance_t) {
|
||||
.callback = callback,
|
||||
.ctx = ctx,
|
||||
.single_shot = is_single_shot,
|
||||
};
|
||||
|
||||
// plic_set_priority(irq_number, priority);
|
||||
// plic_irq_register(irq_number, plic_irq_callback[device], (void *)&timer_instance[device]);
|
||||
// plic_irq_enable(irq_number);
|
||||
|
||||
isrManager.done->registerIrq(irq_number, plic_irq_callback[device], NULL);
|
||||
isrManager.done->enableIrq(irq_number);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel)
|
||||
{
|
||||
if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) {
|
||||
timer_instance[device][channel] = (const timer_instance_t) {
|
||||
.callback = NULL,
|
||||
.ctx = NULL,
|
||||
.single_shot = 0,
|
||||
};
|
||||
|
||||
/* Combine 0 and 1 to A interrupt, 2 and 3 to B interrupt */
|
||||
if ((!(timer_instance[device][TIMER_CHANNEL_0].callback ||
|
||||
timer_instance[device][TIMER_CHANNEL_1].callback)) ||
|
||||
(!(timer_instance[device][TIMER_CHANNEL_2].callback ||
|
||||
timer_instance[device][TIMER_CHANNEL_3].callback))) {
|
||||
plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel);
|
||||
plic_irq_unregister(irq_number);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
menuconfig BSP_USING_WDT0
|
||||
bool "Using watchdog 0 "
|
||||
default n
|
||||
if BSP_USING_WDT0
|
||||
config WDT_BUS_NAME_0
|
||||
string "watchdog bus 0 name"
|
||||
default "wdt0"
|
||||
|
||||
config WDT_DRIVER_NAME_0
|
||||
string "watchdog driver 0 name"
|
||||
default "wdt0_drv"
|
||||
|
||||
config WDT_0_DEVICE_NAME_0
|
||||
string "watchdog device 0 name"
|
||||
default "wdt0_dev0"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_WDT1
|
||||
bool "Using watchdog 1 "
|
||||
default n
|
||||
if BSP_USING_WDT1
|
||||
config WDT_BUS_NAME_1
|
||||
string "watchdog bus 1 name"
|
||||
default "wdt1"
|
||||
|
||||
config WDT_DRIVER_NAME_1
|
||||
string "watchdog driver 1 name"
|
||||
default "wdt1_drv"
|
||||
|
||||
config WDT_1_DEVICE_NAME_1
|
||||
string "watchdog device 1 name"
|
||||
default "wdt1_dev1"
|
||||
endif
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
SRC_FILES := wdt.c connect_wdt.c
|
||||
|
||||
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_wdt.c
|
||||
* @brief support aiit-riscv64-board watchdog function and register to bus framework
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <connect_wdt.h>
|
||||
#include <wdt.h>
|
||||
|
||||
static uint32 WdtOpen(void *dev)
|
||||
{
|
||||
NULL_PARAM_CHECK(dev);
|
||||
|
||||
wdt_device_number_t id;
|
||||
struct WdtHardwareDevice *wdt = (struct WdtHardwareDevice *)dev;
|
||||
id = *(wdt_device_number_t *)wdt->private_data;
|
||||
|
||||
wdt_init(id, 4095, NONE, NONE);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static uint32 WdtConfigure(void *drv, struct BusConfigureInfo *args)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
NULL_PARAM_CHECK(args);
|
||||
|
||||
struct WdtDriver *wdt = (struct WdtDriver *)drv;
|
||||
wdt_device_number_t id = *(wdt_device_number_t *)wdt->private_data;
|
||||
|
||||
switch (args->configure_cmd)
|
||||
{
|
||||
case OPER_WDT_SET_TIMEOUT:
|
||||
if (wdt_init(id, (uint64_t)*(int *)args->private_data, NONE, NONE) == 0) {
|
||||
return ERROR;
|
||||
}
|
||||
break;
|
||||
case OPER_WDT_KEEPALIVE:
|
||||
wdt_feed(id);
|
||||
break;
|
||||
default:
|
||||
return ERROR;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static const struct WdtDevDone dev_done =
|
||||
{
|
||||
WdtOpen,
|
||||
NONE,
|
||||
NONE,
|
||||
NONE,
|
||||
};
|
||||
|
||||
/**
|
||||
* @description: Watchdog function
|
||||
* @return success: EOK, failure: other
|
||||
*/
|
||||
int StartWatchdog(void)
|
||||
{
|
||||
//add feed watchdog task function
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
int HwWdtInit(void)
|
||||
{
|
||||
wdt_device_number_t id;
|
||||
|
||||
x_err_t ret = EOK;
|
||||
|
||||
#ifdef BSP_USING_WDT0
|
||||
{
|
||||
static struct WdtBus wdt0;
|
||||
|
||||
ret = WdtBusInit(&wdt0, WDT_BUS_NAME_0);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog bus init error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
static struct WdtDriver drv0;
|
||||
drv0.configure = WdtConfigure;
|
||||
id = WDT_DEVICE_0;
|
||||
drv0.private_data = &id;
|
||||
|
||||
ret = WdtDriverInit(&drv0, WDT_DRIVER_NAME_0);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog driver init error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_0, WDT_BUS_NAME_0);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog driver attach error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
static struct WdtHardwareDevice dev0;
|
||||
dev0.dev_done = &dev_done;
|
||||
dev0.private_data = &id;
|
||||
|
||||
ret = WdtDeviceRegister(&dev0, WDT_0_DEVICE_NAME_0);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog device register error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = WdtDeviceAttachToBus(WDT_0_DEVICE_NAME_0, WDT_BUS_NAME_0);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog device register error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_WDT1
|
||||
{
|
||||
static struct WdtBus wdt1;
|
||||
|
||||
ret = WdtBusInit(&wdt1, WDT_BUS_NAME_1);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog bus init error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
static struct WdtDriver drv1;
|
||||
drv1.configure = WdtConfigure;
|
||||
id = WDT_DEVICE_1;
|
||||
drv1.private_data = &id;
|
||||
|
||||
ret = WdtDriverInit(&drv1, WDT_DRIVER_NAME_1);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog driver init error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_1, WDT_BUS_NAME_1);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog driver attach error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
static struct WdtHardwareDevice dev1;
|
||||
dev1.dev_done = &dev_done;
|
||||
dev1.private_data = &id;
|
||||
|
||||
ret = WdtDeviceRegister(&dev1, WDT_1_DEVICE_NAME_1);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog device register error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = WdtDeviceAttachToBus(WDT_1_DEVICE_NAME_1, WDT_BUS_NAME_1);
|
||||
if (ret != EOK) {
|
||||
KPrintf("Watchdog device register error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file wdt.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <platform.h>
|
||||
#include <plic.h>
|
||||
#include <stddef.h>
|
||||
#include <sysctl.h>
|
||||
#include <utils.h>
|
||||
#include <wdt.h>
|
||||
|
||||
volatile wdt_t *const wdt[2] =
|
||||
{
|
||||
(volatile wdt_t *)WDT0_BASE_ADDR,
|
||||
(volatile wdt_t *)WDT1_BASE_ADDR
|
||||
};
|
||||
|
||||
static void wdt_enable(wdt_device_number_t id)
|
||||
{
|
||||
wdt[id]->crr = WDT_CRR_MASK;
|
||||
wdt[id]->cr |= WDT_CR_ENABLE;
|
||||
}
|
||||
|
||||
static void wdt_disable(wdt_device_number_t id)
|
||||
{
|
||||
wdt[id]->crr = WDT_CRR_MASK;
|
||||
wdt[id]->cr &= (~WDT_CR_ENABLE);
|
||||
}
|
||||
|
||||
static void wdt_set_timeout(wdt_device_number_t id, uint8_t timeout)
|
||||
{
|
||||
wdt[id]->torr = WDT_TORR_TOP(timeout);
|
||||
}
|
||||
|
||||
static void wdt_response_mode(wdt_device_number_t id, uint8_t mode)
|
||||
{
|
||||
wdt[id]->cr &= (~WDT_CR_RMOD_MASK);
|
||||
wdt[id]->cr |= mode;
|
||||
}
|
||||
|
||||
static uint64_t wdt_get_pclk(wdt_device_number_t id)
|
||||
{
|
||||
return id ? SysctlClockGetFreq(SYSCTL_CLOCK_WDT1) : SysctlClockGetFreq(SYSCTL_CLOCK_WDT0);
|
||||
}
|
||||
|
||||
static uint8_t wdt_get_top(wdt_device_number_t id, uint64_t timeout_ms)
|
||||
{
|
||||
uint64_t wdt_clk = wdt_get_pclk(id);
|
||||
uint64_t ret = (timeout_ms * wdt_clk / 1000) >> 16;
|
||||
if (ret)
|
||||
ret = (uint32_t)log2(ret);
|
||||
if (ret > 0xf)
|
||||
ret = 0xf;
|
||||
return (uint8_t)ret;
|
||||
}
|
||||
|
||||
void wdt_feed(wdt_device_number_t id)
|
||||
{
|
||||
wdt[id]->crr = WDT_CRR_MASK;
|
||||
}
|
||||
|
||||
void wdt_clear_interrupt(wdt_device_number_t id)
|
||||
{
|
||||
wdt[id]->eoi = wdt[id]->eoi;
|
||||
}
|
||||
|
||||
void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq)
|
||||
{
|
||||
sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0);
|
||||
sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0);
|
||||
sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0);
|
||||
|
||||
plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1);
|
||||
plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT);
|
||||
plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, NULL);
|
||||
|
||||
wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT);
|
||||
uint8_t m_top = wdt_get_top(id, time_out_ms);
|
||||
wdt_set_timeout(id, m_top);
|
||||
wdt_enable(id);
|
||||
}
|
||||
|
||||
uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx)
|
||||
{
|
||||
sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0);
|
||||
sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0);
|
||||
sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0);
|
||||
|
||||
plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1);
|
||||
plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT);
|
||||
plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, ctx);
|
||||
|
||||
wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT);
|
||||
uint8_t m_top = wdt_get_top(id, time_out_ms);
|
||||
wdt_set_timeout(id, m_top);
|
||||
wdt_enable(id);
|
||||
return (1UL << (m_top + 16 + 1)) * 1000UL / wdt_get_pclk(id);
|
||||
}
|
||||
|
||||
void wdt_stop(wdt_device_number_t id)
|
||||
{
|
||||
wdt_disable(id);
|
||||
}
|
||||
|
Loading…
Reference in New Issue