add rtc wdt timer for xidatong-riscv64 board

This commit is contained in:
Wang_Weigen 2022-10-18 10:01:39 +08:00
parent 9c15e587c4
commit f2e633348a
21 changed files with 2675 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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__ */

View File

@ -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 */

View File

@ -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__ */

View File

@ -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

View File

@ -0,0 +1,3 @@
SRC_FILES := connect_rtc.c hardware_rtc.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,5 @@
SRC_FILES := hardware_hwtimer.c connect_hwtimer.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,6 @@
SRC_FILES := wdt.c connect_wdt.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -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;
}

View File

@ -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);
}