554 lines
13 KiB
C
Raw Normal View History

2025-10-10 16:07:00 +08:00
// 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 <driver/hal/hal_uart_types.h>
#include <driver/hal/hal_gpio_types.h>
#include "system_hw.h"
#include "uart_hw.h"
#include "hal_port.h"
#include "gpio_map.h"
#ifdef __cplusplus
extern "C" {
#endif
#define UART_LL_REG_BASE(_uart_unit_id) (uart_ll_get_reg_base(_uart_unit_id))
#define CASE_PARITY(parity) case UART_PARITY_##parity: return UART_V_PARITY_##parity
#define CASE_D() default: return 0
#define UART1_FLOW_CTRL_CNT 0xCC
static inline void uart_ll_set_int_enable_status(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->int_enable.v = value;
}
static inline void uart_ll_soft_reset(uart_hw_t *hw)
{
hw->global_ctrl.soft_reset = 1;
}
static inline uint32_t uart_ll_get_device_id(uart_hw_t *hw)
{
return hw->dev_id;
}
static inline uint32_t uart_ll_get_version_id(uart_hw_t *hw)
{
return hw->dev_version;
}
static inline uint32_t uart_ll_get_dev_status(uart_hw_t *hw)
{
return hw->dev_status;
}
static inline void uart_ll_init(uart_hw_t *hw)
{
uart_ll_soft_reset(hw);
}
static inline gpio_id_t uart_ll_get_tx_pin(uart_id_t id)
{
switch (id) {
case UART_ID_0:
return UART0_TX_PIN;
case UART_ID_1:
return UART1_TX_PIN;
case UART_ID_2:
return UART2_TX_PIN;
default:
return SOC_GPIO_NUM;
}
}
static inline gpio_id_t uart_ll_get_rx_pin(uart_id_t id)
{
switch (id) {
case UART_ID_0:
return UART0_RX_PIN;
case UART_ID_1:
return UART1_RX_PIN;
case UART_ID_2:
return UART2_RX_PIN;
default:
return SOC_GPIO_NUM;
}
}
static inline gpio_id_t uart_ll_get_cts_pin(uart_id_t id)
{
switch (id) {
case UART_ID_0:
return UART0_CTS_PIN;
default:
return SOC_GPIO_NUM;
}
}
static inline gpio_id_t uart_ll_get_rts_pin(uart_id_t id)
{
switch (id) {
case UART_ID_0:
return UART0_RTS_PIN;
default:
return SOC_GPIO_NUM;
}
}
static inline uint32_t uart_ll_get_reg_base(uart_id_t id)
{
switch (id) {
case UART_ID_0:
return UART0_R_BASE;
case UART_ID_1:
return UART1_R_BASE;
case UART_ID_2:
return UART2_R_BASE;
default:
return BK_ERR_UART_BASE;
}
}
static inline uint32_t uart_ll_to_reg_parity(uart_parity_t parity)
{
switch (parity) {
CASE_PARITY(ODD);
CASE_PARITY(EVEN);
CASE_D();
}
}
static inline bool uart_ll_get_tx_enable(uart_hw_t *hw)
{
return hw->config.tx_enable;
}
static inline void uart_ll_set_tx_enable(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->config.tx_enable = value & 0x01;
}
static inline void uart_ll_enable_tx(uart_hw_t *hw, uart_id_t id)
{
uart_ll_set_tx_enable(hw, id, 1);
}
static inline void uart_ll_disable_tx(uart_hw_t *hw, uart_id_t id)
{
uart_ll_set_tx_enable(hw, id, 0);
}
static inline bool uart_ll_get_rx_enable(uart_hw_t *hw)
{
return hw->config.rx_enable;
}
static inline void uart_ll_set_rx_enable(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->config.rx_enable = value & 0x1;
}
static inline void uart_ll_enable_rx(uart_hw_t *hw, uart_id_t id)
{
uart_ll_set_rx_enable(hw, id, 1);
}
#define uart_ll_set_frame_mode(hw, id, mode)
#define uart_ll_set_mode_uart(hw, id)
static inline void uart_ll_disable_rx(uart_hw_t *hw, uart_id_t id)
{
uart_ll_set_rx_enable(hw, id, 0);
}
static inline void uart_ll_set_data_bits(uart_hw_t *hw, uart_id_t id, uart_data_bits_t value)
{
hw->config.data_bits = value & 0x3;
}
static inline void uart_ll_enable_parity(uart_hw_t *hw, uart_id_t id)
{
hw->config.parity_en = 1;
}
static inline void uart_ll_disable_parity(uart_hw_t *hw, uart_id_t id)
{
hw->config.parity_en = 0;
}
static inline void uart_ll_set_parity(uart_hw_t *hw, uart_id_t id, uart_parity_t value)
{
hw->config.parity = uart_ll_to_reg_parity(value);
}
static inline void uart_ll_set_stop_bits(uart_hw_t *hw, uart_id_t id, uart_stop_bits_t value)
{
hw->config.stop_bits = value;
}
static inline void uart_ll_set_clk_div(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->config.clk_div = value & UART_F_CLK_DIV_M;
}
static inline void uart_ll_set_tx_fifo_threshold(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->fifo_config.tx_fifo_threshold = value & 0xff;
}
static inline void uart_ll_set_rx_fifo_threshold(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->fifo_config.rx_fifo_threshold = value & 0xff;
}
static inline void uart_ll_set_rx_stop_detect_time(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->fifo_config.rx_stop_detect_time = value & 0x3;
}
static inline void uart_ll_reset_config_to_default(uart_hw_t *hw, uart_id_t id)
{
hw->config.v = 0;
hw->fifo_config.v = 0;
}
static inline uint32_t uart_ll_get_tx_fifo_cnt(uart_hw_t *hw, uart_id_t id)
{
return hw->fifo_status.tx_fifo_count;
}
static inline uint32_t uart_ll_get_rx_fifo_cnt(uart_hw_t *hw, uart_id_t id)
{
return hw->fifo_status.rx_fifo_count;
}
static inline bool uart_ll_is_tx_fifo_full(uart_hw_t *hw, uart_id_t id)
{
return !!(hw->fifo_status.tx_fifo_full);
}
static inline bool uart_ll_is_tx_fifo_empty(uart_hw_t *hw, uart_id_t id)
{
return !!(hw->fifo_status.tx_fifo_empty);
}
static inline bool uart_ll_is_rx_fifo_full(uart_hw_t *hw, uart_id_t id)
{
return !!(hw->fifo_status.rx_fifo_full);
}
static inline bool uart_ll_is_rx_fifo_empty(uart_hw_t *hw, uart_id_t id)
{
return !!(hw->fifo_status.rx_fifo_empty);
}
static inline bool uart_ll_is_fifo_write_ready(uart_hw_t *hw, uart_id_t id)
{
return !!(hw->fifo_status.fifo_wr_ready);
}
static inline bool uart_ll_is_fifo_read_ready(uart_hw_t *hw, uart_id_t id)
{
return !!(hw->fifo_status.fifo_rd_ready);
}
static inline void uart_ll_reset_fifo_port_to_default(uart_hw_t *hw, uart_id_t id)
{
hw->fifo_port.v = 0xffff;
}
static inline void uart_ll_write_byte(uart_hw_t *hw, uart_id_t id, uint8_t data)
{
/* note: hw->fifo_port.tx_fifo_data_in = data; is incorrect */
hw->fifo_port.v = data & 0xff;
}
static inline uint8_t uart_ll_read_byte(uart_hw_t *hw, uart_id_t id)
{
return hw->fifo_port.rx_fifo_data_out;
}
static inline uint8_t *uart_ll_get_write_data_addr(uart_hw_t *hw, uart_id_t id)
{
return (uint8_t *)(&hw->fifo_port);
}
static inline uint8_t *uart_ll_get_read_data_addr(uart_hw_t *hw, uart_id_t id)
{
return (uint8_t *)(((uint32_t)&hw->fifo_port)+1);
}
static inline void uart_ll_reset_int_en_to_default(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.v = 0;
}
static inline void uart_ll_enable_rx_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_fifo_need_read = 1;
hw->int_enable.rx_finish = 1;
}
static inline void uart_ll_disable_rx_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_fifo_need_read = 0;
hw->int_enable.rx_finish = 0;
}
static inline void uart_ll_enable_tx_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.tx_fifo_need_write = 1;
}
static inline void uart_ll_disable_tx_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.tx_fifo_need_write = 0;
}
static inline void uart_ll_enable_fifo_over_flow_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_fifo_overflow = 1;
}
static inline void uart_ll_disable_fifo_over_flow_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_fifo_overflow = 0;
}
static inline void uart_ll_enable_parity_err_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_parity_err = 1;
}
static inline void uart_ll_disable_parity_err_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_parity_err = 0;
}
static inline void uart_ll_enable_stop_bit_err_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_stop_bits_err = 1;
}
static inline void uart_ll_disable_stop_bit_err_interrupt(uart_hw_t *hw, uart_id_t id)
{
hw->int_enable.rx_stop_bits_err = 0;
}
static inline uint32_t uart_ll_get_int_enable_status(uart_hw_t *hw, uart_id_t id)
{
return hw->int_enable.v & 0xff;
}
static inline uint32_t uart_ll_get_interrupt_status(uart_hw_t *hw, uart_id_t id)
{
return hw->int_status.v & 0xff;
}
static inline void uart_ll_clear_interrupt_status(uart_hw_t *hw, uart_id_t id, uint32_t status)
{
hw->int_status.v = status & 0xff;
}
static inline void uart_ll_clear_id_interrupt_status(uart_hw_t *hw, uart_id_t id)
{
hw->int_status.v = 0xff;
}
static inline void uart_ll_clear_id_tx_interrupt_status(uart_hw_t *hw, uart_id_t id)
{
/*
* WARNING:This REG has many bits which attribute is write 1 to clear.
* If uses union bit operation, the asm codes will read data from REG
* and write it back, maybe the other bits is 1 and cleared by this function.
*/
#if 0
hw->int_status.tx_fifo_need_write = 1;
hw->int_status.tx_finish = 1;
#endif
//BIT(0):need write, BIT(5): tx finish
hw->int_status.v = (BIT(0) | BIT(5));
}
static inline void uart_ll_clear_id_rx_interrupt_status(uart_hw_t *hw, uart_id_t id)
{
/*
* WARNING:This REG has many bits which attribute is write 1 to clear.
* If uses union bit operation, the asm codes will read data from REG
* and write it back, maybe the other bits is 1 and cleared by this function.
*/
#if 0
hw->int_status.rx_fifo_need_read = 1;
hw->int_status.rx_finish = 1;
#endif
//BIT(1):need read, BIT(6): rx finish
hw->int_status.v = (BIT(1) | BIT(6));
}
static inline bool uart_ll_is_rx_interrupt_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
{
return !!(status & (BIT(1) | BIT(6)));
}
static inline bool uart_ll_is_rx_recv_fini_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
{
return !!(status & BIT(6));
}
static inline bool uart_ll_is_tx_interrupt_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
{
return !!(status & BIT(0));
}
static inline bool uart_ll_is_rx_over_flow_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
{
return !!(status & BIT(2));
}
static inline bool uart_ll_is_rx_parity_err_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
{
return !!(status & BIT(3));
}
static inline bool uart_ll_is_rx_stop_bits_err_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
{
return !!(status & BIT(4));
}
static inline void uart_ll_reset_flow_control_to_default(uart_hw_t *hw, uart_id_t id)
{
hw->flow_ctrl_config.v = 0;
}
static inline void uart_ll_enable_flow_control(uart_hw_t *hw, uart_id_t id)
{
hw->flow_ctrl_config.flow_ctrl_en = 1;
}
static inline void uart_ll_disable_flow_control(uart_hw_t *hw, uart_id_t id)
{
hw->flow_ctrl_config.flow_ctrl_en = 0;
}
static inline bool uart_ll_is_flow_control_enabled(uart_hw_t *hw, uart_id_t id)
{
return !!(hw->flow_ctrl_config.flow_ctrl_en);
}
static inline void uart_ll_set_flow_control_low_cnt(uart_hw_t *hw, uart_id_t id, uint32_t cnt)
{
hw->flow_ctrl_config.flow_ctrl_low_cnt = cnt & 0xff;
}
static inline void uart_ll_set_flow_control_high_cnt(uart_hw_t *hw, uart_id_t id, uint32_t cnt)
{
hw->flow_ctrl_config.flow_ctrl_high_cnt = cnt & 0xff;
}
static inline void uart_ll_set_rts_polarity(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->flow_ctrl_config.rts_polarity_sel = value & 0x1;
}
static inline void uart_ll_set_cts_polarity(uart_hw_t *hw, uart_id_t id, uint32_t value)
{
hw->flow_ctrl_config.cts_polarity_sel = value & 0x1;
}
static inline void uart_ll_reset_wake_config_to_default(uart_hw_t *hw, uart_id_t id)
{
hw->wake_config.v = 0;
}
#if CONFIG_UART_PM_CB_SUPPORT
#define UART_PM_BACKUP_REG_NUM (6)
static inline void uart_ll_backup(uart_hw_t *hw, uint32_t *pm_backup)
{
pm_backup[0] = hw->config.v;
pm_backup[1] = hw->fifo_config.v;
pm_backup[2] = hw->int_enable.v;
pm_backup[3] = hw->flow_ctrl_config.v;
pm_backup[4] = hw->wake_config.v;
pm_backup[5] = hw->global_ctrl.v;
}
static inline void uart_ll_restore(uart_hw_t *hw, uint32_t *pm_backup)
{
hw->config.v = pm_backup[0];
hw->fifo_config.v = pm_backup[1];
hw->int_enable.v = pm_backup[2];
hw->flow_ctrl_config.v = pm_backup[3];
hw->wake_config.v = pm_backup[4];
hw->global_ctrl.v = pm_backup[5];
}
#endif
#if CONFIG_ENABLE_FILTER_GLITCH
static inline void uart_ll_set_glitch_width(uart_hw_t *hw, uint32_t width)
{
hw->glitch_cancel_config.glitch_width = width & 0x7fff;
}
static inline uint32_t uart_ll_get_glitch_width(uart_hw_t *hw)
{
return hw->glitch_cancel_config.glitch_width;
}
static inline void uart_ll_enable_glitch_cancel(uart_hw_t *hw)
{
hw->glitch_cancel_config.cancel_en = 1;
}
static inline void uart_ll_disable_glitch_cancel(uart_hw_t *hw)
{
hw->glitch_cancel_config.cancel_en = 0;
}
#endif // CONFIG_ENABLE_FILTER_GLITCH
static inline uint32_t uart_ll_wait_tx_over(void)
{
uint32_t uart_wait_us;
uint32_t baudrate0;
uint32_t baudrate1;
uint32_t baudrate2;
uart_hw_t *hw0 = (uart_hw_t *)UART_LL_REG_BASE(0);
uart_hw_t *hw1 = (uart_hw_t *)UART_LL_REG_BASE(1);
uart_hw_t *hw2 = (uart_hw_t *)UART_LL_REG_BASE(2);
baudrate0 = UART_CLOCK / (hw0->config.clk_div + 1);
baudrate1 = UART_CLOCK / (hw1->config.clk_div + 1);
baudrate2 = UART_CLOCK / (hw2->config.clk_div + 1);
uart_wait_us = 1000000 * hw2->fifo_status.tx_fifo_count * 10 / baudrate2
+ 1000000 * hw1->fifo_status.tx_fifo_count * 10 / baudrate1
+ 1000000 * hw0->fifo_status.tx_fifo_count * 10 / baudrate0;
while (!hw2->fifo_status.tx_fifo_empty);
while (!hw1->fifo_status.tx_fifo_empty);
while (!hw0->fifo_status.tx_fifo_empty);
return uart_wait_us;
}
#ifdef __cplusplus
}
#endif