276 lines
8.2 KiB
C
276 lines
8.2 KiB
C
// Copyright 2020-2021 Beken
|
|
//
|
|
// 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.
|
|
|
|
#pragma once
|
|
|
|
#include <soc/soc.h>
|
|
#include "timer_hw.h"
|
|
#include "hal_port.h"
|
|
#include <driver/hal/hal_timer_types.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define TIMER_LL_REG_BASE(_timer_unit_id) (SOC_TIMER0_REG_BASE)
|
|
#define TIMER_LL_GROUP(chan) ((chan) / SOC_TIMER_CHAN_NUM_PER_GROUP)
|
|
#define TIMER_LL_CHAN(chan) ((chan) % SOC_TIMER_CHAN_NUM_PER_GROUP)
|
|
|
|
typedef enum {
|
|
TIMER_GROUP_CHAN0 = 0,
|
|
TIMER_GROUP_CHAN1 = 1,
|
|
TIMRE_GROUP_CHAN2 = 2,
|
|
} timer_group_chan_t;
|
|
|
|
static inline void timer_ll_soft_reset(timer_hw_t *hw, uint32_t group)
|
|
{
|
|
hw->group[group].global_ctrl.soft_reset = 1;
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_device_id(timer_hw_t *hw, uint32_t group)
|
|
{
|
|
return hw->group[group].dev_id;
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_version_id(timer_hw_t *hw, uint32_t group)
|
|
{
|
|
return hw->group[group].dev_version;
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_dev_status(timer_hw_t *hw, uint32_t group)
|
|
{
|
|
return hw->group[group].dev_status;
|
|
}
|
|
|
|
static inline void timer_ll_init(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
#if CONFIG_TIMER_SUPPORT_ID_BITS
|
|
if ((~CONFIG_TIMER_SUPPORT_ID_BITS) & BIT(chan)) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
uint32_t group = TIMER_LL_GROUP(chan);
|
|
uint32_t group_chan = TIMER_LL_CHAN(chan);
|
|
|
|
if (TIMER_GROUP_CHAN0 == group_chan) {
|
|
hw->group[group].ctrl.timer0_en = 0;
|
|
hw->group[group].ctrl.timer0_int_en = 0;
|
|
} else if (TIMER_GROUP_CHAN1 == group_chan) {
|
|
hw->group[group].ctrl.timer1_en = 0;
|
|
hw->group[group].ctrl.timer1_int_en = 0;
|
|
} else {
|
|
hw->group[group].ctrl.timer2_en = 0;
|
|
hw->group[group].ctrl.timer2_int_en = 0;
|
|
}
|
|
|
|
hw->group[group].read_ctrl.v = 0;
|
|
hw->group[group].timer_read_value = 0;
|
|
timer_ll_soft_reset(hw, group);
|
|
}
|
|
|
|
static inline void timer_ll_set_enable(timer_hw_t *hw, uint32_t group, uint32_t chan, uint32_t value)
|
|
{
|
|
if (chan == TIMER_GROUP_CHAN0)
|
|
hw->group[group].ctrl.timer0_en = value;
|
|
else if (chan == TIMER_GROUP_CHAN1)
|
|
hw->group[group].ctrl.timer1_en = value;
|
|
else
|
|
hw->group[group].ctrl.timer2_en = value;
|
|
}
|
|
|
|
static inline void timer_ll_enable(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
timer_ll_set_enable(hw, TIMER_LL_GROUP(chan), TIMER_LL_CHAN(chan), 1);
|
|
}
|
|
|
|
static inline void timer_ll_disable(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
timer_ll_set_enable(hw, TIMER_LL_GROUP(chan), TIMER_LL_CHAN(chan), 0);
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_enable_status(timer_hw_t *hw)
|
|
{
|
|
uint32_t bit_pos = 0;
|
|
uint32_t status = 0;
|
|
|
|
for (int group = 0; group < SOC_TIMER_GROUP_NUM; group++) {
|
|
status |= hw->group[group].ctrl.timer0_en << (bit_pos++);
|
|
status |= hw->group[group].ctrl.timer1_en << (bit_pos++);
|
|
status |= hw->group[group].ctrl.timer2_en << (bit_pos++);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static inline void timer_ll_set_interrupt(timer_hw_t *hw, uint32_t group, uint32_t chan, uint32_t value)
|
|
{
|
|
if (chan == TIMER_GROUP_CHAN0)
|
|
hw->group[group].ctrl.timer0_int_en = value;
|
|
else if (chan == TIMER_GROUP_CHAN1)
|
|
hw->group[group].ctrl.timer1_int_en = value;
|
|
else
|
|
hw->group[group].ctrl.timer2_int_en = value;
|
|
}
|
|
|
|
static inline void timer_ll_enable_interrupt(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
timer_ll_set_interrupt(hw, TIMER_LL_GROUP(chan), TIMER_LL_CHAN(chan), 1);
|
|
}
|
|
|
|
static inline void timer_ll_disable_interrupt(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
timer_ll_set_interrupt(hw, TIMER_LL_GROUP(chan), TIMER_LL_CHAN(chan), 0);
|
|
}
|
|
|
|
static inline bool timer_ll_is_interrupt_triggered(timer_hw_t *hw, uint32_t chan, uint32_t status)
|
|
{
|
|
return (status & BIT(chan));
|
|
}
|
|
|
|
static inline void timer_ll_set_chan_interrupt_status(timer_hw_t *hw, uint32_t chan, uint32_t value)
|
|
{
|
|
uint32_t group = TIMER_LL_GROUP(chan);
|
|
uint32_t group_chan = TIMER_LL_CHAN(chan);
|
|
|
|
if (group_chan == TIMER_GROUP_CHAN0)
|
|
hw->group[group].ctrl.timer0_int_en = value;
|
|
else if (group_chan == TIMER_GROUP_CHAN1)
|
|
hw->group[group].ctrl.timer1_int_en = value;
|
|
else
|
|
hw->group[group].ctrl.timer2_int_en = value;
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_chan_interrupt_status(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
uint32_t group = TIMER_LL_GROUP(chan);
|
|
uint32_t group_chan = TIMER_LL_CHAN(chan);
|
|
|
|
if (TIMER_GROUP_CHAN0 == group_chan)
|
|
return hw->group[group].ctrl.timer0_int_en;
|
|
else if (TIMER_GROUP_CHAN1 == group_chan)
|
|
return hw->group[group].ctrl.timer1_int_en;
|
|
else
|
|
return hw->group[group].ctrl.timer2_int_en;
|
|
}
|
|
|
|
static inline void timer_ll_clear_chan_interrupt_status(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
BK_DO_WHILE(timer_ll_set_chan_interrupt_status(hw, chan, 1),
|
|
timer_ll_get_chan_interrupt_status(hw, chan));
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_interrupt_status(timer_hw_t *hw)
|
|
{
|
|
uint32_t bit_pos = 0;
|
|
uint32_t status = 0;
|
|
|
|
for (int group = 0; group < SOC_TIMER_GROUP_NUM; group++) {
|
|
status |= hw->group[group].ctrl.timer0_int_en << (bit_pos++);
|
|
status |= hw->group[group].ctrl.timer1_int_en << (bit_pos++);
|
|
status |= hw->group[group].ctrl.timer2_int_en << (bit_pos++);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static inline void timer_ll_clear_interrupt_status(timer_hw_t *hw, uint32_t status)
|
|
{
|
|
for (int id = 0; id < SOC_TIMER_CHAN_NUM_PER_UNIT; id++) {
|
|
if (status & BIT(id)) {
|
|
timer_ll_clear_chan_interrupt_status(hw, id);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void timer_ll_set_end_count(timer_hw_t *hw, uint32_t chan, uint32_t timer_cnt)
|
|
{
|
|
hw->group[TIMER_LL_GROUP(chan)].timer_cnt[TIMER_LL_CHAN(chan)] = timer_cnt;
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_end_count(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
return hw->group[TIMER_LL_GROUP(chan)].timer_cnt[TIMER_LL_CHAN(chan)];
|
|
}
|
|
|
|
static inline void timer_ll_set_clk_div(timer_hw_t *hw, uint32_t chan, uint32_t clk_div)
|
|
{
|
|
hw->group[TIMER_LL_GROUP(chan)].ctrl.clk_div = clk_div & TIMER_F_CLK_DIV_V;
|
|
}
|
|
|
|
static inline void timer_ll_set_cnt_read(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
hw->group[TIMER_LL_GROUP(chan)].read_ctrl.timer_cnt_read = 1;
|
|
}
|
|
|
|
static inline bool timer_ll_is_cnt_read_valid(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
return !(hw->group[TIMER_LL_GROUP(chan)].read_ctrl.timer_cnt_read & 0x1);
|
|
}
|
|
|
|
static inline void timer_ll_set_read_index(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
hw->group[TIMER_LL_GROUP(chan)].read_ctrl.timer_index = TIMER_LL_CHAN(chan);
|
|
}
|
|
|
|
static inline void timer_ll_clear_timer_count(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
hw->group[TIMER_LL_GROUP(chan)].timer_read_value = 0;
|
|
}
|
|
|
|
static inline uint32_t timer_ll_get_timer_count(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
return hw->group[TIMER_LL_GROUP(chan)].timer_read_value;
|
|
}
|
|
|
|
static inline void timer_ll_reset_config_to_default(timer_hw_t *hw, uint32_t chan)
|
|
{
|
|
timer_ll_set_end_count(hw, chan, 0);
|
|
timer_ll_set_clk_div(hw, chan, 0);
|
|
}
|
|
|
|
#if CONFIG_TIMER_PM_CB_SUPPORT
|
|
#define TIMER_CTRL_MASK (0x3F)
|
|
#define TIMER_PM_BACKUP_REG_NUM (5)
|
|
|
|
static inline void timer_ll_backup(timer_hw_t *hw, uint32_t group_id, uint32_t *pm_backup)
|
|
{
|
|
pm_backup[0] = hw->group[group_id].global_ctrl.v;
|
|
pm_backup[1] = hw->group[group_id].timer_cnt[0];
|
|
pm_backup[2] = hw->group[group_id].timer_cnt[1];
|
|
pm_backup[3] = hw->group[group_id].timer_cnt[2];
|
|
pm_backup[4] = hw->group[group_id].ctrl.v & TIMER_CTRL_MASK;
|
|
//confs[5] = hw->group[group_id].read_ctrl.v;
|
|
|
|
for(uint32_t i = 0; i < SOC_TIMER_CHAN_NUM_PER_GROUP; i++) // disable timer after backup
|
|
{
|
|
timer_ll_set_enable(hw, group_id, i, 0);
|
|
}
|
|
}
|
|
|
|
static inline void timer_ll_restore(timer_hw_t *hw, uint32_t group_id, uint32_t *pm_backup)
|
|
{
|
|
hw->group[group_id].global_ctrl.v = pm_backup[0];
|
|
hw->group[group_id].timer_cnt[0] = pm_backup[1];
|
|
hw->group[group_id].timer_cnt[1] = pm_backup[2];
|
|
hw->group[group_id].timer_cnt[2] = pm_backup[3];
|
|
hw->group[group_id].ctrl.v = pm_backup[4];
|
|
//hw->group[group_id].read_ctrl.v = confs[5];
|
|
}
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|