2025-10-10 16:07:00 +08:00

663 lines
16 KiB
C
Executable File

// 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 "gpio_hw.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef volatile struct {
uint32_t gpio_0_31_int_status;
uint32_t gpio_32_64_int_status;
} gpio_interrupt_status_t;
#define GPIO_LL_REG_BASE (SOC_AON_GPIO_REG_BASE)
#define GPIO_LL_SYSTEM_REG_BASE (SOC_SYS_REG_BASE + 0x30 * 4)
#define GPIO_NUM_MAX (SOC_GPIO_NUM)
#define GPIO_EXIST (0xffffffffffff)
//TODO fix me in v5
#if CONFIG_SPE
#define GPIO_IS_SECURE(gpio_id) false
#else
#define GPIO_IS_SECURE(gpio_id) ((gpio_id) < 2)
#endif
static system_gpio_func_mode_hw_t *gpio_system_gpio_func_mode;
static inline void gpio_ll_init(gpio_hw_t *hw)
{
gpio_system_gpio_func_mode = (system_gpio_func_mode_hw_t *)GPIO_LL_SYSTEM_REG_BASE;
}
//some special code re-use a GPIO, it doesn't care the GPIO setting value, just bake/restore value.
static inline void gpio_ll_set_value(gpio_hw_t *hw, uint32 index, uint32_t v)
{
*(volatile uint32_t *)&hw->gpio_num[index] = v;
}
//some special code re-use a GPIO, it doesn't care the GPIO setting value, just bake/restore value.
static inline uint32_t gpio_ll_get_value(gpio_hw_t *hw, uint32 index)
{
return *(volatile uint32_t *)&hw->gpio_num[index];
}
static inline void gpio_ll_set_io_mode(gpio_hw_t *hw, uint32 index, const gpio_config_t *config)
{
uint32 io_mode = 0;
switch (config->io_mode) {
case GPIO_OUTPUT_ENABLE:
io_mode = 0;
break;
case GPIO_INPUT_ENABLE:
io_mode = 3;
break;
case GPIO_IO_DISABLE:
io_mode = 2;
break;
default:
break;
}
REG_SET_BITS(&hw->gpio_num[index], GPIO_F_IO_MODE_SET(io_mode), GPIO_F_IO_MODE_EN_M) ;
}
static inline void gpio_ll_set_pull_mode(gpio_hw_t *hw, uint32 index, const gpio_config_t *config)
{
uint32 pull_mode = 0;
switch (config->pull_mode) {
case GPIO_PULL_DISABLE:
pull_mode = 0;
break;
case GPIO_PULL_DOWN_EN:
pull_mode = 2;
break;
case GPIO_PULL_UP_EN:
pull_mode = 3;
break;
default:
break;
}
REG_SET_BITS(&hw->gpio_num[index], GPIO_F_PULL_SET(pull_mode), GPIO_F_PULL_EN_M) ;
}
static inline void gpio_ll_set_func_mode(gpio_hw_t *hw, uint32 index, const gpio_config_t *config)
{
switch (config->func_mode) {
case GPIO_SECOND_FUNC_DISABLE:
REG_CLR_BIT(&hw->gpio_num[index], BIT(6));
break;
case GPIO_SECOND_FUNC_ENABLE:
REG_SET_BIT(&hw->gpio_num[index], BIT(6));
break;
default:
break;
}
}
static inline void gpio_ll_set_mode(gpio_hw_t *hw, uint32 index, const gpio_config_t *config)
{
gpio_ll_set_io_mode(hw, index, config);
gpio_ll_set_pull_mode(hw, index, config);
gpio_ll_set_func_mode(hw, index, config);
}
//GPIO output enbale low active
static inline void gpio_ll_output_enable(gpio_hw_t *hw, uint32 index, uint32_t enable)
{
if (enable)
enable = 0;
else
enable = 1;
hw->gpio_num[index].cfg.gpio_output_en = enable;
}
//GPIO input enable, high active
static inline void gpio_ll_input_enable(gpio_hw_t *hw, uint32 index, uint32_t enable)
{
hw->gpio_num[index].cfg.gpio_input_en = enable;
}
static inline void gpio_ll_pull_up_enable(gpio_hw_t *hw, uint32 index, uint32_t enable)
{
hw->gpio_num[index].cfg.gpio_pull_mode = enable;
}
static inline void gpio_ll_pull_enable(gpio_hw_t *hw, uint32 index, uint32_t enable)
{
hw->gpio_num[index].cfg.gpio_pull_mode_en = enable;
}
static inline void gpio_ll_second_function_enable(gpio_hw_t *hw, uint32 index, uint32_t enable)
{
hw->gpio_num[index].cfg.gpio_2_func_en = enable;
}
static inline void gpio_ll_monitor_input_value_enable(gpio_hw_t *hw, uint32 index, uint32_t enable)
{
hw->gpio_num[index].cfg.gpio_input_monitor = enable;
}
static inline void gpio_ll_set_capacity(gpio_hw_t *hw, uint32 index, uint32_t capacity)
{
hw->gpio_num[index].cfg.gpio_capacity = capacity;
}
static inline uint32 gpio_ll_check_func_mode_enable(gpio_hw_t *hw, uint32 index)
{
return (hw->gpio_num[index].cfg.gpio_2_func_en == 1);
}
static inline uint32 gpio_ll_check_output_enable(gpio_hw_t *hw, uint32 index)
{
return (hw->gpio_num[index].cfg.gpio_output_en == 0);
}
static inline uint32 gpio_ll_check_input_enable(gpio_hw_t *hw, uint32 index)
{
return (hw->gpio_num[index].cfg.gpio_input_en == 1);
}
static inline void gpio_ll_set_output_value(gpio_hw_t *hw, uint32 index, bool value)
{
hw->gpio_num[index].cfg.gpio_output = value;
}
static inline bool gpio_ll_get_output_value(gpio_hw_t *hw, uint32 index)
{
return hw->gpio_num[index].cfg.gpio_output;
}
static inline bool gpio_ll_get_input_value(gpio_hw_t *hw, uint32 index)
{
return hw->gpio_num[index].cfg.gpio_input;
}
#define gpio_ll_set_gpio_output_value(hw,index,value) gpio_ll_set_output_value(hw, index, value)
#define gpio_ll_get_gpio_output_value(hw,index) gpio_ll_get_output_value(hw, index)
#define gpio_ll_get_gpio_input_value(hw,index) gpio_ll_get_input_value(hw, index)
static inline void gpio_ll_set_interrupt_type(gpio_hw_t *hw, uint32 index, gpio_int_type_t mode)
{
hw->gpio_num[index].cfg.gpio_int_type = mode;
}
static inline void gpio_ll_enable_interrupt(gpio_hw_t *hw, uint32 index)
{
hw->gpio_num[index].cfg.gpio_int_en = 1;
}
static inline void gpio_ll_disable_interrupt(gpio_hw_t *hw, uint32 index)
{
hw->gpio_num[index].cfg.gpio_int_en = 0;
}
static inline void gpio_ll_get_interrupt_status(gpio_hw_t *hw, gpio_interrupt_status_t *gpio_status)
{
gpio_status->gpio_0_31_int_status = REG_READ(&hw->gpio_0_31_int_st);
gpio_status->gpio_32_64_int_status = REG_READ(&hw->gpio_32_55_int_st);
}
static inline void gpio_ll_clear_interrupt_status(gpio_hw_t *hw, gpio_interrupt_status_t *gpio_status)
{
if (gpio_status->gpio_0_31_int_status) {
REG_WRITE(&hw->gpio_0_31_int_st, gpio_status->gpio_0_31_int_status);
}
if (gpio_status->gpio_32_64_int_status) {
REG_WRITE(&hw->gpio_32_55_int_st, gpio_status->gpio_32_64_int_status);
}
}
static inline void gpio_ll_clear_chan_interrupt_status(gpio_hw_t *hw, uint32 index)
{
hw->gpio_num[index].cfg.gpio_int_clear = 1;
}
static inline bool gpio_ll_is_interrupt_triggered(gpio_hw_t *hw, uint32 index, gpio_interrupt_status_t *gpio_status)
{
if (index < GPIO_32)
return !!((gpio_status->gpio_0_31_int_status) & (GPIO_F_INT_EN << (GPIO_F_INT_EN_MS(index))));
else
return !!((gpio_status->gpio_32_64_int_status) & (GPIO_F_INT_EN << (GPIO_F_INT_EN_MS(index - GPIO_32))));
}
static inline void gpio_ll_set_perial_mode(gpio_hw_t *hw, uint32 index, uint32_t mode)
{
if (index < GPIO_8)
REG_MCHAN_SET_FIELD(index, &gpio_system_gpio_func_mode->gpio_sys_num[0], GPIO_F_PERIAL_MODE, mode);
else if (index < GPIO_16)
REG_MCHAN_SET_FIELD(index-GPIO_8, &gpio_system_gpio_func_mode->gpio_sys_num[1], GPIO_F_PERIAL_MODE, mode);
else if (index < GPIO_24)
REG_MCHAN_SET_FIELD(index-GPIO_16, &gpio_system_gpio_func_mode->gpio_sys_num[2], GPIO_F_PERIAL_MODE, mode);
else if (index < GPIO_32)
REG_MCHAN_SET_FIELD(index-GPIO_24, &gpio_system_gpio_func_mode->gpio_sys_num[3], GPIO_F_PERIAL_MODE, mode);
else if (index < GPIO_40)
REG_MCHAN_SET_FIELD(index-GPIO_32, &gpio_system_gpio_func_mode->gpio_sys_num[4], GPIO_F_PERIAL_MODE, mode);
else if (index < GPIO_48)
REG_MCHAN_SET_FIELD(index-GPIO_40, &gpio_system_gpio_func_mode->gpio_sys_num[5], GPIO_F_PERIAL_MODE, mode);
else
REG_MCHAN_SET_FIELD(index-GPIO_48, &gpio_system_gpio_func_mode->gpio_sys_num[6], GPIO_F_PERIAL_MODE, mode);
}
static inline uint32 gpio_ll_get_perial_mode(gpio_hw_t *hw, uint32 index)
{
if (index < GPIO_8)
return (REG_MCHAN_GET_FIELD(index, &gpio_system_gpio_func_mode->gpio_sys_num[0], GPIO_F_PERIAL_MODE));
else if (index < GPIO_16)
return ((REG_MCHAN_GET_FIELD(index-GPIO_8, &gpio_system_gpio_func_mode->gpio_sys_num[1], GPIO_F_PERIAL_MODE)));
else if (index < GPIO_24)
return ((REG_MCHAN_GET_FIELD(index-GPIO_16, &gpio_system_gpio_func_mode->gpio_sys_num[2], GPIO_F_PERIAL_MODE)));
else if (index < GPIO_32)
return ((REG_MCHAN_GET_FIELD(index-GPIO_24, &gpio_system_gpio_func_mode->gpio_sys_num[3], GPIO_F_PERIAL_MODE)));
else if (index < GPIO_40)
return ((REG_MCHAN_GET_FIELD(index-GPIO_32, &gpio_system_gpio_func_mode->gpio_sys_num[4], GPIO_F_PERIAL_MODE)));
else if (index < GPIO_48)
return ((REG_MCHAN_GET_FIELD(index-GPIO_40, &gpio_system_gpio_func_mode->gpio_sys_num[5], GPIO_F_PERIAL_MODE)));
else
return ((REG_MCHAN_GET_FIELD(index-GPIO_48, &gpio_system_gpio_func_mode->gpio_sys_num[6], GPIO_F_PERIAL_MODE)));
}
#define gpio_ll_set_gpio_perial_mode(hw, index, mode) gpio_ll_set_perial_mode(hw, index, mode)
#define gpio_ll_get_gpio_perial_mode(hw, index) gpio_ll_get_perial_mode(hw, index)
#if CONFIG_GPIO_WAKEUP_SUPPORT
/* gpio bak configs:just bak only low 16bits of GPIO config:input/output/pull en/... , not include interrupt */
static inline void gpio_ll_bak_configs(uint16_t *gpio_cfg, uint32_t count)
{
uint32_t i = 0;
if (gpio_cfg == NULL)
return;
for (i = 0; i < count; i++) {
if (GPIO_IS_SECURE(i)) {
continue;
}
gpio_cfg[i] = (uint16_t)REG_READ(GPIO_LL_REG_BASE+i*4);
}
}
/* gpio bak configs:just restore only low 16bits of GPIO config:input/output/pull en/... , not include interrupt */
static inline void gpio_ll_restore_configs(uint16_t *gpio_cfg, uint32_t count)
{
uint32_t i = 0;
uint32_t val = 0;
if (gpio_cfg == NULL)
return;
for (i = 0; i < count; i++) {
if (GPIO_IS_SECURE(i)) {
continue;
}
val = REG_READ(GPIO_LL_REG_BASE+i*4);
val &= 0xffff0000;
val |= gpio_cfg[i];
REG_WRITE((GPIO_LL_REG_BASE+i*4), val);
}
}
static inline void gpio_ll_bak_int_type_configs(uint32_t *gpio_int_cfg, uint32_t count)
{
uint32_t int_cfg_index = 0;
uint32_t gpio_id = 0;
uint32_t reg = 0;
if (gpio_int_cfg == NULL)
return;
gpio_int_cfg[int_cfg_index] = 0x0;
for (gpio_id = 0; gpio_id < SOC_GPIO_NUM; gpio_id++) {
if (GPIO_IS_SECURE(gpio_id)) {
continue;
}
reg = REG_READ(GPIO_LL_REG_BASE + 0x04 *gpio_id);
if(((gpio_id % 16) == 0) && (gpio_id != 0)) {
int_cfg_index++;
gpio_int_cfg[int_cfg_index] = 0x0;
}
if(!(int_cfg_index < count))
break;
gpio_int_cfg[int_cfg_index] |= (((0xC00 & reg) >> 10) << ((gpio_id % 16) * 2));
}
}
static inline void gpio_ll_restore_int_type_configs(uint32_t *gpio_int_cfg, uint32_t count)
{
uint32_t int_cfg_index = 0;
uint32_t gpio_id = 0;
uint32_t reg = 0;
if (gpio_int_cfg == NULL)
return;
for (gpio_id = 0; gpio_id < SOC_GPIO_NUM; gpio_id++) {
if (GPIO_IS_SECURE(gpio_id)) {
continue;
}
reg = REG_READ(GPIO_LL_REG_BASE + 0x04 *gpio_id);
if(((gpio_id % 16) == 0) && (gpio_id != 0))
int_cfg_index++;
if(!(int_cfg_index < count))
break;
reg |= (((gpio_int_cfg[int_cfg_index] >> ((gpio_id % 16) * 2)) & 0x3) << 10);
REG_WRITE(GPIO_LL_REG_BASE + 0x04 *gpio_id, reg);
}
}
static inline void gpio_ll_bak_int_enable_configs(uint32_t *gpio_int_cfg, uint32_t count)
{
uint32_t int_cfg_index = 0;
uint32_t gpio_id = 0;
uint32_t reg = 0;
if (gpio_int_cfg == NULL)
return;
gpio_int_cfg[int_cfg_index] = 0x0;
for (gpio_id = 0; gpio_id < SOC_GPIO_NUM; gpio_id++) {
if (GPIO_IS_SECURE(gpio_id)) {
continue;
}
reg = REG_READ(GPIO_LL_REG_BASE + 0x04 *gpio_id);
if(((gpio_id % 32) == 0) && (gpio_id != 0)) {
int_cfg_index++;
gpio_int_cfg[int_cfg_index] = 0x0;
}
if(!(int_cfg_index < count))
break;
gpio_int_cfg[int_cfg_index] |= (((0x1000 & reg) >> 12) << (gpio_id % 32));
}
}
static inline void gpio_ll_restore_int_enable_configs(uint32_t *gpio_int_cfg, uint32_t count)
{
uint32_t int_cfg_index = 0;
uint32_t gpio_id = 0;
uint32_t reg = 0;
if (gpio_int_cfg == NULL)
return;
for (gpio_id = 0; gpio_id < SOC_GPIO_NUM; gpio_id++) {
if (GPIO_IS_SECURE(gpio_id)) {
continue;
}
reg = REG_READ(GPIO_LL_REG_BASE + 0x04 *gpio_id);
if(((gpio_id % 32) == 0) && (gpio_id != 0))
int_cfg_index++;
if(!(int_cfg_index < count))
break;
reg |= (((gpio_int_cfg[int_cfg_index] >> (gpio_id % 32)) & 0x1) << 12);
REG_WRITE(GPIO_LL_REG_BASE + 0x04 *gpio_id, reg);
}
}
/* gpio switch to low power status:set all gpios to input mode */
static inline void gpio_ll_switch_to_low_power_status(uint64_t skip_io)
{
uint32_t i = 0;
uint32_t val = 0;
for(i = 0; i < GPIO_NUM_MAX; i ++) {
if (GPIO_IS_SECURE(i)) {
continue;
}
if(skip_io & (0x1ULL << i))
continue;
val = REG_READ(GPIO_LL_REG_BASE+i*4);
val &= 0xffff0000;
val |= 0x0008;
REG_WRITE((GPIO_LL_REG_BASE+i*4), val);
}
}
#else
/* gpio save */
static inline void gpio_ll_reg_save(uint32_t* gpio_cfg)
{
int i = 0;
if(gpio_cfg == NULL)
return;
for(i = 0; i < GPIO_NUM_MAX; i ++)
{
if (GPIO_IS_SECURE(i)) {
continue;
}
//if(GPIO_EXIST & BIT(i))//temp modify
{
gpio_cfg[i] = REG_READ(GPIO_LL_REG_BASE+i*4);
}
}
}
/* gpio restore */
static inline void gpio_ll_reg_restore(uint32_t* gpio_cfg)
{
int i = 0;
if(gpio_cfg == NULL)
return;
for(i = 0; i < GPIO_NUM_MAX; i ++)
{
if (GPIO_IS_SECURE(i)) {
continue;
}
//if(GPIO_EXIST & BIT(i))//temp modify
{
REG_WRITE(GPIO_LL_REG_BASE+i*4, gpio_cfg[i]);
}
}
}
/* config gpio wakeup type and enable. @type_l: low/high or pos/nege. @type_h: level or edge */
static inline void gpio_ll_wakeup_enable(uint64_t index, uint64_t type_l, uint64_t type_h)
{
int i = 0;
uint32_t rdata = 0;
uint64_t index_ini = index;
/* clear all int enable */
REG_WRITE(GPIO_LL_REG_BASE+0x43*4, 0x0);
REG_WRITE(GPIO_LL_REG_BASE+0x44*4, 0x0);
rdata = REG_READ(GPIO_LL_REG_BASE+0x40*4);
for(i = 0; i < 16; i ++)
{
if (GPIO_IS_SECURE(i)) {
continue;
}
if(index & BIT(i))
{
REG_WRITE(GPIO_LL_REG_BASE+i*4, 0x3c);
rdata &= ~(0x3 << i*2);
if(type_l & BIT(i)) rdata |= BIT(2*i);
if(type_h & BIT(i)) rdata |= BIT(2*i+1);
}
else
{
REG_WRITE(GPIO_LL_REG_BASE+i*4, 0x08);
}
}
REG_WRITE(GPIO_LL_REG_BASE+0x40*4, rdata);
index = index >> 16;
type_l = type_l >> 16;
type_h = type_h >> 16;
rdata = REG_READ(GPIO_LL_REG_BASE+0x41*4);
for(i = 0; i < 16; i ++)
{
if (GPIO_IS_SECURE(i)) {
continue;
}
if(index & BIT(i))
{
REG_WRITE(GPIO_LL_REG_BASE+0x40+i*4, 0x0c);
rdata &= ~(0x3 << i*2);
if(type_l & BIT(i)) rdata |= BIT(2*i);
if(type_h & BIT(i)) rdata |= BIT(2*i+1);
}
else
{
REG_WRITE(GPIO_LL_REG_BASE+0x40+i*4, 0x08);
}
}
REG_WRITE(GPIO_LL_REG_BASE+0x41*4, rdata);
index = index >> 16;
type_l = type_l >> 16;
type_h = type_h >> 16;
rdata = REG_READ(GPIO_LL_REG_BASE+0x42*4);
for(i = 0; i < 16; i ++)
{
if (GPIO_IS_SECURE(i)) {
continue;
}
if(index & BIT(i))
{
REG_WRITE(GPIO_LL_REG_BASE+0x80+i*4, 0x0c);
rdata &= ~(0x3 << i*2);
if(type_l & BIT(i)) rdata |= BIT(2*i);
if(type_h & BIT(i)) rdata |= BIT(2*i+1);
}
else
{
REG_WRITE(GPIO_LL_REG_BASE+0x80+i*4, 0x08);
}
}
REG_WRITE(GPIO_LL_REG_BASE+0x42*4, rdata);
extern void delay(INT32 num);
delay(10);
REG_WRITE(GPIO_LL_REG_BASE+0x47*4, 0xffffffff);
REG_WRITE(GPIO_LL_REG_BASE+0x48*4, 0xffffffff);
index = index_ini;
rdata = 0;
for(i = 0; i < 32; i ++)
{
if(index & BIT(i))
{
rdata |= BIT(i);
}
}
REG_WRITE(GPIO_LL_REG_BASE+0x43*4, rdata);
index = index >> 32;
rdata = 0;
for(i = 0; i < 16; i ++)
{
if(index & BIT(i))
{
rdata |= BIT(i);
}
}
REG_WRITE(GPIO_LL_REG_BASE+0x44*4, rdata);
}
static inline void gpio_ll_wakeup_interrupt_clear()
{
uint64_t int_state = 0;
uint32_t int_state1 = 0;
uint32_t int_en_state = 0;
uint32_t int_en_state1 = 0;
uint32_t i = 0;
int_state = REG_READ(GPIO_LL_REG_BASE+0x46*4);
int_state1 = REG_READ(GPIO_LL_REG_BASE+0x45*4);
int_en_state = REG_READ(GPIO_LL_REG_BASE+0x43*4);
int_en_state1 = REG_READ(GPIO_LL_REG_BASE+0x44*4);
int_state = (int_state << 32) | (int_state1);
for(i = 0; i < GPIO_NUM_MAX; i ++)
{
if(int_state & BIT(i))
{
break;
}
}
if(i > 31)
{
int_en_state1 &= ~(BIT(i));
REG_WRITE(GPIO_LL_REG_BASE+0x44*4, int_en_state1);
}
else
{
int_en_state &= ~(BIT(i));
REG_WRITE(GPIO_LL_REG_BASE+0x43*4, int_en_state);
}
REG_WRITE(GPIO_LL_REG_BASE+0x47*4, (REG_READ(GPIO_LL_REG_BASE+0x47*4))|int_state);
REG_WRITE(GPIO_LL_REG_BASE+0x48*4, (REG_READ(GPIO_LL_REG_BASE+0x48*4))|(int_state >> 32));
extern void delay(INT32 num);
delay(10);
REG_WRITE(GPIO_LL_REG_BASE+0x47*4, 0xffffffff);
REG_WRITE(GPIO_LL_REG_BASE+0x48*4, 0xffffffff);
}
#endif
#ifdef __cplusplus
}
#endif