1494 lines
44 KiB
C
1494 lines
44 KiB
C
/*
|
|
* Copyright (c) 2022-2024 HPMicro
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2022-03-08 HPMicro First version
|
|
* 2022-07-28 HPMicro Fix compiling warning if RT_SERIAL_USING_DMA was not defined
|
|
* 2022-08-08 HPMicro Integrate DMA Manager and support dynamic DMA resource assignment'
|
|
* 2023-03-07 HPMicro Fix the issue that the data_width was not initialized before setup dma handshake
|
|
* 2024-06-10 HPMicro Fix memory leakage issue
|
|
*
|
|
*/
|
|
#include <rtthread.h>
|
|
#include <rtdevice.h>
|
|
#include "board.h"
|
|
#include "drv_uart_v2.h"
|
|
#include "hpm_uart_drv.h"
|
|
#include "hpm_sysctl_drv.h"
|
|
#include "hpm_l1c_drv.h"
|
|
#include "hpm_dma_mgr.h"
|
|
#include "hpm_soc.h"
|
|
|
|
|
|
#ifdef RT_USING_SERIAL_V2
|
|
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
#define BOARD_UART_DMAMUX HPM_DMAMUX
|
|
#define UART_DMA_TRIGGER_LEVEL (1U)
|
|
|
|
typedef struct dma_channel {
|
|
struct rt_serial_device *serial;
|
|
dma_resource_t resource;
|
|
void (*tranfer_done)(struct rt_serial_device *serial);
|
|
void (*tranfer_abort)(struct rt_serial_device *serial);
|
|
void (*tranfer_error)(struct rt_serial_device *serial);
|
|
void *ringbuf_ptr;
|
|
} hpm_dma_channel_handle_t;
|
|
|
|
//static struct dma_channel dma_channels[DMA_SOC_CHANNEL_NUM];
|
|
static int hpm_uart_dma_config(struct rt_serial_device *serial, void *arg);
|
|
static void hpm_uart_receive_dma_next(struct rt_serial_device *serial);
|
|
#endif
|
|
|
|
#define UART_ROOT_CLK_FREQ BOARD_APP_UART_SRC_FREQ
|
|
|
|
struct hpm_uart {
|
|
UART_Type *uart_base;
|
|
uint32_t irq_num;
|
|
struct rt_serial_device *serial;
|
|
char *device_name;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uint32_t tx_dma_mux;
|
|
uint32_t rx_dma_mux;
|
|
uint32_t dma_flags;
|
|
hpm_dma_channel_handle_t tx_chn_ctx;
|
|
hpm_dma_channel_handle_t rx_chn_ctx;
|
|
bool tx_resource_allocated;
|
|
bool rx_resource_allocated;
|
|
#if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1) && defined(RT_SERIAL_USING_DMA)
|
|
ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t rx_idle_tmp_buffer[1024];
|
|
#endif
|
|
#endif
|
|
};
|
|
|
|
|
|
extern void init_uart_pins(UART_Type *ptr);
|
|
static void hpm_uart_isr(struct rt_serial_device *serial);
|
|
static rt_err_t hpm_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
|
|
static rt_err_t hpm_uart_control(struct rt_serial_device *serial, int cmd, void *arg);
|
|
static int hpm_uart_putc(struct rt_serial_device *serial, char ch);
|
|
static int hpm_uart_getc(struct rt_serial_device *serial);
|
|
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
int hpm_uart_dma_register_channel(struct rt_serial_device *serial,
|
|
bool is_tx,
|
|
void (*done)(struct rt_serial_device *serial),
|
|
void (*abort)(struct rt_serial_device *serial),
|
|
void (*error)(struct rt_serial_device *serial))
|
|
{
|
|
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
|
|
if (is_tx) {
|
|
uart->tx_chn_ctx.serial = serial;
|
|
uart->tx_chn_ctx.tranfer_done = done;
|
|
uart->tx_chn_ctx.tranfer_abort = abort;
|
|
uart->tx_chn_ctx.tranfer_error = error;
|
|
} else {
|
|
uart->rx_chn_ctx.serial = serial;
|
|
uart->rx_chn_ctx.tranfer_done = done;
|
|
uart->rx_chn_ctx.tranfer_abort = abort;
|
|
uart->rx_chn_ctx.tranfer_error = error;
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
#endif /* RT_SERIAL_USING_DMA */
|
|
|
|
#if defined(BSP_USING_UART0)
|
|
struct rt_serial_device serial0;
|
|
void uart0_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial0);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART0,uart0_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART1)
|
|
struct rt_serial_device serial1;
|
|
void uart1_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial1);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART1,uart1_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART2)
|
|
struct rt_serial_device serial2;
|
|
void uart2_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial2);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART2,uart2_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART3)
|
|
struct rt_serial_device serial3;
|
|
void uart3_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial3);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART3,uart3_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART4)
|
|
struct rt_serial_device serial4;
|
|
void uart4_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial4);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART4,uart4_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART5)
|
|
struct rt_serial_device serial5;
|
|
void uart5_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial5);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART5,uart5_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART6)
|
|
struct rt_serial_device serial6;
|
|
void uart6_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial6);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART6,uart6_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART7)
|
|
struct rt_serial_device serial7;
|
|
void uart7_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial7);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART7,uart7_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART8)
|
|
struct rt_serial_device serial8;
|
|
void uart8_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial8);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART8,uart8_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART9)
|
|
struct rt_serial_device serial9;
|
|
void uart9_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial9);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART9,uart9_isr)
|
|
#endif
|
|
|
|
|
|
#if defined(BSP_USING_UART10)
|
|
struct rt_serial_device serial10;
|
|
void uart10_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial10);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART10,uart10_isr)
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART11)
|
|
struct rt_serial_device serial11;
|
|
void uart11_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial11);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART11,uart11_isr)
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART12)
|
|
struct rt_serial_device serial12;
|
|
void uart12_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial12);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART12,uart12_isr)
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART13)
|
|
struct rt_serial_device serial13;
|
|
void uart13_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial13);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART13,uart13_isr)
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART14)
|
|
struct rt_serial_device serial14;
|
|
void uart14_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial14);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART14,uart14_isr)
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART15)
|
|
struct rt_serial_device serial15;
|
|
void uart15_isr(void)
|
|
{
|
|
hpm_uart_isr(&serial15);
|
|
}
|
|
SDK_DECLARE_EXT_ISR_M(IRQn_UART15,uart15_isr)
|
|
#endif
|
|
|
|
static struct hpm_uart uarts[] =
|
|
{
|
|
#if defined(BSP_USING_UART0)
|
|
{
|
|
HPM_UART0,
|
|
IRQn_UART0,
|
|
&serial0,
|
|
"uart0",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART0_TX,
|
|
HPM_DMA_SRC_UART0_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART1)
|
|
{
|
|
HPM_UART1,
|
|
IRQn_UART1,
|
|
&serial1,
|
|
"uart1",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART1_TX,
|
|
HPM_DMA_SRC_UART1_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART2)
|
|
{
|
|
HPM_UART2,
|
|
IRQn_UART2,
|
|
&serial2,
|
|
"uart2",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART2_TX,
|
|
HPM_DMA_SRC_UART2_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART3)
|
|
{
|
|
HPM_UART3,
|
|
IRQn_UART3,
|
|
&serial3,
|
|
"uart3",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART3_TX,
|
|
HPM_DMA_SRC_UART3_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART4)
|
|
{
|
|
HPM_UART4,
|
|
IRQn_UART4,
|
|
&serial4,
|
|
"uart4",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART4_TX,
|
|
HPM_DMA_SRC_UART4_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART5)
|
|
{
|
|
HPM_UART5,
|
|
IRQn_UART5,
|
|
&serial5,
|
|
"uart5",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART5_TX,
|
|
HPM_DMA_SRC_UART5_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART6)
|
|
{
|
|
HPM_UART6,
|
|
IRQn_UART6,
|
|
&serial6,
|
|
"uart6",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART6_TX,
|
|
HPM_DMA_SRC_UART6_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART7)
|
|
{
|
|
HPM_UART7,
|
|
IRQn_UART7,
|
|
&serial7,
|
|
"uart7",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART7_TX,
|
|
HPM_DMA_SRC_UART7_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART8)
|
|
{
|
|
HPM_UART8,
|
|
IRQn_UART8,
|
|
&serial8,
|
|
"uart8",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART8_TX,
|
|
HPM_DMA_SRC_UART8_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART9)
|
|
{
|
|
HPM_UART9,
|
|
IRQn_UART9,
|
|
&serial9,
|
|
"uart9",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART9_TX,
|
|
HPM_DMA_SRC_UART9_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART10)
|
|
{
|
|
HPM_UART10,
|
|
IRQn_UART10,
|
|
&serial10,
|
|
"uart10",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART10_TX,
|
|
HPM_DMA_SRC_UART10_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART11)
|
|
{
|
|
HPM_UART11,
|
|
IRQn_UART11,
|
|
&serial11,
|
|
"uart11",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART11_TX,
|
|
HPM_DMA_SRC_UART11_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART12)
|
|
{
|
|
HPM_UART12,
|
|
IRQn_UART12,
|
|
&serial12,
|
|
"uart12",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART12_TX,
|
|
HPM_DMA_SRC_UART12_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART13)
|
|
{
|
|
HPM_UART13,
|
|
IRQn_UART13,
|
|
&serial13,
|
|
"uart13",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART13_TX,
|
|
HPM_DMA_SRC_UART13_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART14)
|
|
{
|
|
HPM_UART14,
|
|
IRQn_UART14,
|
|
&serial14,
|
|
"uart14",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART14_TX,
|
|
HPM_DMA_SRC_UART14_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART15)
|
|
{
|
|
HPM_UART15,
|
|
IRQn_UART15,
|
|
&serial15,
|
|
"uart15",
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
HPM_DMA_SRC_UART15_TX,
|
|
HPM_DMA_SRC_UART15_RX,
|
|
0,
|
|
#endif
|
|
},
|
|
#endif
|
|
|
|
};
|
|
|
|
enum
|
|
{
|
|
#if defined(BSP_USING_UART0)
|
|
HPM_UART0_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART1)
|
|
HPM_UART1_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART2)
|
|
HPM_UART2_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART3)
|
|
HPM_UART3_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART4)
|
|
HPM_UART4_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART5)
|
|
HPM_UART5_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART6)
|
|
HPM_UART6_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART7)
|
|
HPM_UART7_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART8)
|
|
HPM_UART8_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART9)
|
|
HPM_UART9_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART10)
|
|
HPM_UART10_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART11)
|
|
HPM_UART11_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART12)
|
|
HPM_UART12_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART13)
|
|
HPM_UART13_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART14)
|
|
HPM_UART14_INDEX,
|
|
#endif
|
|
|
|
#if defined(BSP_USING_UART15)
|
|
HPM_UART15_INDEX,
|
|
#endif
|
|
};
|
|
|
|
#if defined(RT_SERIAL_USING_DMA)
|
|
|
|
static void uart_dma_tc_callback(DMA_Type *base, uint32_t channel, void *user_data)
|
|
{
|
|
hpm_dma_channel_handle_t *dma_handle = (hpm_dma_channel_handle_t*)user_data;
|
|
if ((dma_handle->resource.base != base) || (dma_handle->resource.channel != channel))
|
|
{
|
|
return;
|
|
}
|
|
dma_handle->tranfer_done(dma_handle->serial);
|
|
}
|
|
|
|
static void uart_dma_abort_callback(DMA_Type *base, uint32_t channel, void *user_data)
|
|
{
|
|
hpm_dma_channel_handle_t *dma_handle = (hpm_dma_channel_handle_t*)user_data;
|
|
if ((dma_handle->resource.base != base) || (dma_handle->resource.channel != channel))
|
|
{
|
|
return;
|
|
}
|
|
dma_handle->tranfer_abort(dma_handle->serial);
|
|
}
|
|
|
|
static void uart_dma_error_callback(DMA_Type *base, uint32_t channel, void *user_data)
|
|
{
|
|
hpm_dma_channel_handle_t *dma_handle = (hpm_dma_channel_handle_t*)user_data;
|
|
if ((dma_handle->resource.base != base) || (dma_handle->resource.channel != channel))
|
|
{
|
|
return;
|
|
}
|
|
dma_handle->tranfer_error(dma_handle->serial);
|
|
}
|
|
|
|
static void uart_tx_done(struct rt_serial_device *serial)
|
|
{
|
|
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DMADONE);
|
|
}
|
|
|
|
static void uart_rx_done(struct rt_serial_device *serial)
|
|
{
|
|
struct rt_serial_rx_fifo *rx_fifo;
|
|
rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
|
#if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1) && defined(RT_SERIAL_USING_DMA)
|
|
uint32_t uart_recv_data_count = 0;
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
uint32_t rx_idle_tmp_buffer_size = sizeof(uart->rx_idle_tmp_buffer);
|
|
uart_recv_data_count = rx_idle_tmp_buffer_size - dma_get_remaining_transfer_size(uart->rx_chn_ctx.resource.base, uart->rx_chn_ctx.resource.channel);
|
|
if (l1c_dc_is_enabled()) {
|
|
uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN((uint32_t)uart->rx_idle_tmp_buffer);
|
|
uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP((uint32_t)uart->rx_idle_tmp_buffer + rx_idle_tmp_buffer_size);
|
|
uint32_t aligned_size = aligned_end - aligned_start;
|
|
l1c_dc_invalidate(aligned_start, aligned_size);
|
|
}
|
|
/* if open uart again after closing uart, an idle interrupt may be triggered, but uart initialization is not performed at this time, and the program exits if the rxfifo is empty. */
|
|
if (rx_fifo == RT_NULL) {
|
|
return;
|
|
}
|
|
rt_ringbuffer_put(&(rx_fifo->rb), uart->rx_idle_tmp_buffer, uart_recv_data_count);
|
|
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE);
|
|
#else
|
|
if (l1c_dc_is_enabled()) {
|
|
uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN((uint32_t)rx_fifo->rb.buffer_ptr);
|
|
uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP((uint32_t)rx_fifo->rb.buffer_ptr + serial->config.rx_bufsz);
|
|
uint32_t aligned_size = aligned_end - aligned_start;
|
|
l1c_dc_invalidate(aligned_start, aligned_size);
|
|
}
|
|
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (serial->config.rx_bufsz << 8));
|
|
#endif
|
|
/* prepare for next read */
|
|
hpm_uart_receive_dma_next(serial);
|
|
}
|
|
#endif /* RT_SERIAL_USING_DMA */
|
|
|
|
/**
|
|
* @brief UART common interrupt process. This
|
|
*
|
|
* @param serial Serial device
|
|
*/
|
|
static void hpm_uart_isr(struct rt_serial_device *serial)
|
|
{
|
|
struct hpm_uart *uart;
|
|
rt_uint32_t stat, enabled_irq;
|
|
rt_uint8_t irq_id;
|
|
rt_uint8_t count = 0;
|
|
rt_uint8_t put_char = 0;
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
|
|
uart = (struct hpm_uart *)serial->parent.user_data;
|
|
RT_ASSERT(uart != RT_NULL);
|
|
|
|
struct rt_serial_rx_fifo *rx_fifo;
|
|
rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
|
|
stat = uart_get_status(uart->uart_base);
|
|
irq_id = uart_get_irq_id(uart->uart_base);
|
|
|
|
if (irq_id == uart_intr_id_rx_data_avail) {
|
|
while (uart_check_status(uart->uart_base, uart_stat_data_ready)) {
|
|
count++;
|
|
put_char = uart_read_byte(uart->uart_base);
|
|
rt_ringbuffer_putchar(&(rx_fifo->rb), put_char);
|
|
/*in order to ensure rx fifo there are remaining bytes*/
|
|
if (count > 12) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (irq_id == uart_intr_id_rx_timeout) {
|
|
while ((uart_check_status(uart->uart_base, uart_stat_data_ready)) || (uart_check_status(uart->uart_base, uart_stat_overrun_error))) {
|
|
put_char= uart_read_byte(uart->uart_base);
|
|
rt_ringbuffer_putchar(&(rx_fifo->rb), put_char);
|
|
}
|
|
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
|
|
}
|
|
|
|
if ((irq_id & uart_intr_tx_slot_avail) && (stat & uart_stat_tx_slot_avail)) {
|
|
/* UART in mode Transmitter */
|
|
struct rt_serial_tx_fifo *tx_fifo;
|
|
tx_fifo = (struct rt_serial_tx_fifo *) serial->serial_tx;
|
|
RT_ASSERT(tx_fifo != RT_NULL);
|
|
rt_uint8_t put_char = 0;
|
|
uint32_t fifo_size = 0, ringbuffer_data_len = 0, tx_size = 0;
|
|
uart_disable_irq(uart->uart_base, uart_intr_tx_slot_avail);
|
|
fifo_size = uart_get_fifo_size(uart->uart_base);
|
|
ringbuffer_data_len = rt_ringbuffer_data_len(&tx_fifo->rb);
|
|
if (ringbuffer_data_len <= 0) {
|
|
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
|
|
} else {
|
|
tx_size = (ringbuffer_data_len > fifo_size) ? fifo_size : ringbuffer_data_len;
|
|
for (uint32_t i = 0; i < tx_size; i++) {
|
|
rt_ringbuffer_getchar(&tx_fifo->rb, &put_char);
|
|
uart_write_byte(uart->uart_base, put_char);
|
|
}
|
|
uart_enable_irq(uart->uart_base, uart_intr_tx_slot_avail);
|
|
}
|
|
}
|
|
#if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1) && defined(RT_SERIAL_USING_DMA)
|
|
if (uart_is_rxline_idle(uart->uart_base)) {
|
|
uart_rx_done(serial);
|
|
uart_clear_rxline_idle_flag(uart->uart_base);
|
|
uart_flush(uart->uart_base);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static rt_err_t hpm_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
|
|
{
|
|
|
|
RT_ASSERT(serial != RT_NULL);
|
|
RT_ASSERT(cfg != RT_NULL);
|
|
|
|
uart_config_t uart_config;
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
|
|
init_uart_pins(uart->uart_base);
|
|
uart_default_config(uart->uart_base, &uart_config);
|
|
|
|
uart_config.src_freq_in_hz = board_init_uart_clock(uart->uart_base);
|
|
uart_config.baudrate = cfg->baud_rate;
|
|
uart_config.num_of_stop_bits = cfg->stop_bits;
|
|
uart_config.parity = cfg->parity;
|
|
uart_config.rx_fifo_level = uart_rx_fifo_trg_gt_three_quarters;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
if (uart->dma_flags & (RT_DEVICE_FLAG_DMA_TX | RT_DEVICE_FLAG_DMA_RX)) {
|
|
uart_config.fifo_enable = true;
|
|
uart_config.dma_enable = true;
|
|
if (uart->dma_flags & RT_DEVICE_FLAG_DMA_TX) {
|
|
uart_config.tx_fifo_level = uart_tx_fifo_trg_not_full;
|
|
}
|
|
if (uart->dma_flags & RT_DEVICE_FLAG_DMA_RX) {
|
|
uart_config.rx_fifo_level = uart_rx_fifo_trg_not_empty;
|
|
}
|
|
#if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1)
|
|
uart_config.rxidle_config.detect_enable = true;
|
|
uart_config.rxidle_config.detect_irq_enable = true;
|
|
uart_config.rxidle_config.idle_cond = uart_rxline_idle_cond_rxline_logic_one;
|
|
uart_config.rxidle_config.threshold = 16U; /* 10bit */
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
uart_config.word_length = cfg->data_bits - DATA_BITS_5;
|
|
hpm_stat_t status = uart_init(uart->uart_base, &uart_config);
|
|
return (status != status_success) ? -RT_ERROR : RT_EOK;
|
|
}
|
|
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
|
|
hpm_stat_t hpm_uart_dma_rx_init(struct hpm_uart *uart_ctx)
|
|
{
|
|
hpm_stat_t status = status_fail;
|
|
if (!uart_ctx->rx_resource_allocated)
|
|
{
|
|
status = dma_mgr_request_resource(&uart_ctx->rx_chn_ctx.resource);
|
|
if (status == status_success)
|
|
{
|
|
uart_ctx->dma_flags |= RT_DEVICE_FLAG_DMA_RX;
|
|
uart_ctx->rx_resource_allocated = true;
|
|
dma_mgr_install_chn_tc_callback(&uart_ctx->rx_chn_ctx.resource, uart_dma_tc_callback, &uart_ctx->rx_chn_ctx);
|
|
dma_mgr_install_chn_abort_callback(&uart_ctx->rx_chn_ctx.resource, uart_dma_abort_callback, &uart_ctx->rx_chn_ctx);
|
|
dma_mgr_install_chn_error_callback(&uart_ctx->rx_chn_ctx.resource, uart_dma_error_callback, &uart_ctx->rx_chn_ctx);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
hpm_stat_t hpm_uart_dma_tx_init(struct hpm_uart *uart_ctx)
|
|
{
|
|
hpm_stat_t status = status_fail;
|
|
if (!uart_ctx->tx_resource_allocated)
|
|
{
|
|
status = dma_mgr_request_resource(&uart_ctx->tx_chn_ctx.resource);
|
|
if (status == status_success)
|
|
{
|
|
uart_ctx->dma_flags |= RT_DEVICE_FLAG_DMA_TX;
|
|
uart_ctx->tx_resource_allocated = true;
|
|
dma_mgr_install_chn_tc_callback(&uart_ctx->tx_chn_ctx.resource, uart_dma_tc_callback, &uart_ctx->tx_chn_ctx);
|
|
dma_mgr_install_chn_abort_callback(&uart_ctx->tx_chn_ctx.resource, uart_dma_abort_callback, &uart_ctx->tx_chn_ctx);
|
|
dma_mgr_install_chn_error_callback(&uart_ctx->tx_chn_ctx.resource, uart_dma_error_callback, &uart_ctx->tx_chn_ctx);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static int hpm_uart_dma_config(struct rt_serial_device *serial, void *arg)
|
|
{
|
|
rt_ubase_t ctrl_arg = (rt_ubase_t) arg;
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
struct rt_serial_rx_fifo *rx_fifo;
|
|
dma_mgr_chn_conf_t chg_config;
|
|
dma_mgr_get_default_chn_config(&chg_config);
|
|
if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX) {
|
|
rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
|
chg_config.dst_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_INCREMENT;
|
|
chg_config.dst_mode = DMA_MGR_HANDSHAKE_MODE_NORMAL;
|
|
chg_config.dst_width = DMA_TRANSFER_WIDTH_BYTE;
|
|
chg_config.en_dmamux = true;
|
|
chg_config.dmamux_src = uart->rx_dma_mux;
|
|
chg_config.src_addr = (uint32_t)&(uart->uart_base->RBR);
|
|
chg_config.src_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_FIXED;
|
|
chg_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
|
|
chg_config.src_width = DMA_TRANSFER_WIDTH_BYTE;
|
|
|
|
#if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1)
|
|
chg_config.dst_addr = (uint32_t)uart->rx_idle_tmp_buffer;
|
|
chg_config.size_in_byte = sizeof(uart->rx_idle_tmp_buffer);
|
|
#else
|
|
chg_config.dst_addr = (uint32_t)rx_fifo->rb.buffer_ptr;
|
|
chg_config.size_in_byte = serial->config.rx_bufsz;
|
|
#endif
|
|
if (status_success != dma_mgr_setup_channel(&uart->rx_chn_ctx.resource, &chg_config)) {
|
|
return -RT_ERROR;
|
|
}
|
|
dma_mgr_enable_channel(&uart->rx_chn_ctx.resource);
|
|
dma_mgr_enable_chn_irq(&uart->rx_chn_ctx.resource, DMA_MGR_INTERRUPT_MASK_TC);
|
|
dma_mgr_enable_dma_irq_with_priority(&uart->rx_chn_ctx.resource, 1);
|
|
#if !defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) || (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 0)
|
|
hpm_uart_dma_register_channel(serial, false, uart_rx_done, RT_NULL, RT_NULL);
|
|
#else
|
|
intc_m_enable_irq_with_priority(uart->irq_num, 1);
|
|
#endif
|
|
} else if (ctrl_arg == RT_DEVICE_FLAG_DMA_TX) {
|
|
chg_config.src_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_INCREMENT;
|
|
chg_config.src_mode = DMA_MGR_HANDSHAKE_MODE_NORMAL;
|
|
chg_config.src_width = DMA_TRANSFER_WIDTH_BYTE;
|
|
chg_config.dst_addr = (uint32_t)&uart->uart_base->THR;
|
|
chg_config.dst_addr_ctrl = DMA_MGR_ADDRESS_CONTROL_FIXED;
|
|
chg_config.dst_mode = DMA_MGR_HANDSHAKE_MODE_HANDSHAKE;
|
|
chg_config.dst_width = DMA_TRANSFER_WIDTH_BYTE;
|
|
chg_config.en_dmamux = true;
|
|
chg_config.dmamux_src = uart->tx_dma_mux;
|
|
if (status_success != dma_mgr_setup_channel(&uart->tx_chn_ctx.resource, &chg_config)) {
|
|
return -RT_ERROR;
|
|
}
|
|
dma_mgr_enable_chn_irq(&uart->tx_chn_ctx.resource, DMA_MGR_INTERRUPT_MASK_TC);
|
|
dma_mgr_enable_dma_irq_with_priority(&uart->tx_chn_ctx.resource, 1);
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
|
|
static void hpm_uart_receive_dma_next(struct rt_serial_device *serial)
|
|
{
|
|
uint32_t buf_addr;
|
|
uint32_t buf_size;
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
|
#if defined(HPM_IP_FEATURE_UART_RX_IDLE_DETECT) && (HPM_IP_FEATURE_UART_RX_IDLE_DETECT == 1)
|
|
buf_addr = (uint32_t)uart->rx_idle_tmp_buffer;
|
|
buf_size = sizeof(uart->rx_idle_tmp_buffer);
|
|
#else
|
|
buf_addr = (uint32_t)rx_fifo->rb.buffer_ptr;
|
|
buf_size = serial->config.rx_bufsz;
|
|
#endif
|
|
dma_mgr_set_chn_dst_addr(&uart->rx_chn_ctx.resource, buf_addr);
|
|
dma_mgr_set_chn_transize(&uart->rx_chn_ctx.resource, buf_size);
|
|
dma_mgr_enable_channel(&uart->rx_chn_ctx.resource);
|
|
}
|
|
|
|
static void hpm_uart_transmit_dma(struct rt_serial_device *serial, uint8_t *src, uint32_t size)
|
|
{
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
dma_mgr_set_chn_src_addr(&uart->tx_chn_ctx.resource, (uint32_t)src);
|
|
dma_mgr_set_chn_transize(&uart->tx_chn_ctx.resource, size);
|
|
dma_mgr_enable_channel(&uart->tx_chn_ctx.resource);
|
|
}
|
|
|
|
#endif /* RT_SERIAL_USING_DMA */
|
|
|
|
static rt_err_t hpm_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
|
|
{
|
|
RT_ASSERT(serial != RT_NULL);
|
|
|
|
rt_ubase_t ctrl_arg = (rt_ubase_t) arg;
|
|
uint8_t *tmp_buffer = NULL;
|
|
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
|
|
struct rt_serial_tx_fifo *tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx;
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
|
|
if(ctrl_arg & (RT_DEVICE_FLAG_RX_BLOCKING | RT_DEVICE_FLAG_RX_NON_BLOCKING))
|
|
{
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
if (uart->dma_flags & RT_DEVICE_FLAG_DMA_RX)
|
|
{
|
|
ctrl_arg = RT_DEVICE_FLAG_DMA_RX;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
ctrl_arg = RT_DEVICE_FLAG_INT_RX;
|
|
}
|
|
}
|
|
else if(ctrl_arg & (RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING))
|
|
{
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
if (uart->dma_flags & RT_DEVICE_FLAG_DMA_TX)
|
|
{
|
|
ctrl_arg = RT_DEVICE_FLAG_DMA_TX;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
ctrl_arg = RT_DEVICE_FLAG_INT_TX;
|
|
}
|
|
}
|
|
|
|
switch (cmd) {
|
|
case RT_DEVICE_CTRL_CLR_INT:
|
|
if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) {
|
|
/* disable rx irq */
|
|
uart_disable_irq(uart->uart_base, uart_intr_rx_data_avail_or_timeout);
|
|
intc_m_disable_irq(uart->irq_num);
|
|
}
|
|
else if (ctrl_arg == RT_DEVICE_FLAG_INT_TX) {
|
|
/* disable tx irq */
|
|
uart_disable_irq(uart->uart_base, uart_intr_tx_slot_avail);
|
|
intc_m_disable_irq(uart->irq_num);
|
|
}
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
else if (ctrl_arg == RT_DEVICE_FLAG_DMA_TX) {
|
|
dma_mgr_disable_chn_irq(&uart->tx_chn_ctx.resource, DMA_INTERRUPT_MASK_ALL);
|
|
dma_abort_channel(uart->tx_chn_ctx.resource.base, uart->tx_chn_ctx.resource.channel);
|
|
if (uart->tx_chn_ctx.ringbuf_ptr != RT_NULL) {
|
|
rt_free(uart->tx_chn_ctx.ringbuf_ptr);
|
|
uart->tx_chn_ctx.ringbuf_ptr = RT_NULL;
|
|
}
|
|
} else if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX) {
|
|
dma_mgr_disable_chn_irq(&uart->rx_chn_ctx.resource, DMA_INTERRUPT_MASK_ALL);
|
|
dma_abort_channel(uart->rx_chn_ctx.resource.base, uart->rx_chn_ctx.resource.channel);
|
|
if (uart->rx_chn_ctx.ringbuf_ptr != RT_NULL) {
|
|
rt_free(uart->rx_chn_ctx.ringbuf_ptr);
|
|
uart->rx_chn_ctx.ringbuf_ptr = RT_NULL;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case RT_DEVICE_CTRL_SET_INT:
|
|
if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) {
|
|
/* enable rx irq */
|
|
uart_enable_irq(uart->uart_base, uart_intr_rx_data_avail_or_timeout);
|
|
intc_m_enable_irq_with_priority(uart->irq_num, 2);
|
|
} else if (ctrl_arg == RT_DEVICE_FLAG_INT_TX) {
|
|
/* enable tx irq */
|
|
uart_enable_irq(uart->uart_base, uart_intr_tx_slot_avail);
|
|
intc_m_enable_irq_with_priority(uart->irq_num, 1);
|
|
}
|
|
break;
|
|
|
|
case RT_DEVICE_CTRL_CONFIG:
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
if ((ctrl_arg == RT_DEVICE_FLAG_DMA_RX) || (ctrl_arg == RT_DEVICE_FLAG_INT_RX)) {
|
|
if ((rx_fifo) && (((rt_uint32_t)rx_fifo->rb.buffer_ptr % HPM_L1C_CACHELINE_SIZE) || (rx_fifo->rb.buffer_size % HPM_L1C_CACHELINE_SIZE))) {
|
|
rt_free(rx_fifo);
|
|
rx_fifo = RT_NULL;
|
|
rx_fifo = (struct rt_serial_rx_fifo *) rt_malloc(sizeof(struct rt_serial_rx_fifo));
|
|
RT_ASSERT(rx_fifo != RT_NULL);
|
|
tmp_buffer = rt_malloc(serial->config.rx_bufsz + HPM_L1C_CACHELINE_SIZE);
|
|
RT_ASSERT(tmp_buffer != RT_NULL);
|
|
if (uart->rx_chn_ctx.ringbuf_ptr != RT_NULL) {
|
|
rt_free(uart->rx_chn_ctx.ringbuf_ptr);
|
|
}
|
|
uart->rx_chn_ctx.ringbuf_ptr = (void *)tmp_buffer;
|
|
tmp_buffer += (HPM_L1C_CACHELINE_SIZE - ((rt_ubase_t) tmp_buffer % HPM_L1C_CACHELINE_SIZE));
|
|
rt_ringbuffer_init(&rx_fifo->rb, tmp_buffer, serial->config.rx_bufsz);
|
|
rt_ringbuffer_reset(&rx_fifo->rb);
|
|
serial->serial_rx = rx_fifo;
|
|
}
|
|
}
|
|
|
|
if ((ctrl_arg == RT_DEVICE_FLAG_DMA_TX) || (ctrl_arg == RT_DEVICE_FLAG_INT_TX)) {
|
|
if ((tx_fifo) && (((rt_uint32_t)tx_fifo->rb.buffer_ptr % HPM_L1C_CACHELINE_SIZE) || (tx_fifo->rb.buffer_size % HPM_L1C_CACHELINE_SIZE))) {
|
|
rt_free(tx_fifo);
|
|
tx_fifo = RT_NULL;
|
|
tx_fifo = (struct rt_serial_tx_fifo *) rt_malloc(sizeof(struct rt_serial_tx_fifo));
|
|
RT_ASSERT(tx_fifo != RT_NULL);
|
|
tmp_buffer = rt_malloc(serial->config.tx_bufsz + HPM_L1C_CACHELINE_SIZE);
|
|
RT_ASSERT(tmp_buffer != RT_NULL);
|
|
if (uart->tx_chn_ctx.ringbuf_ptr != RT_NULL) {
|
|
rt_free(uart->tx_chn_ctx.ringbuf_ptr);
|
|
}
|
|
uart->tx_chn_ctx.ringbuf_ptr = (void *)tmp_buffer;
|
|
tmp_buffer += (HPM_L1C_CACHELINE_SIZE - ((rt_ubase_t) tmp_buffer % HPM_L1C_CACHELINE_SIZE));
|
|
rt_ringbuffer_init(&tx_fifo->rb, tmp_buffer, serial->config.tx_bufsz);
|
|
rt_ringbuffer_reset(&tx_fifo->rb);
|
|
tx_fifo->activated = RT_FALSE;
|
|
tx_fifo->put_size = 0;
|
|
serial->serial_tx = tx_fifo;
|
|
}
|
|
}
|
|
|
|
if (ctrl_arg & (RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX)) {
|
|
hpm_uart_dma_config(serial, (void *)ctrl_arg);
|
|
} else
|
|
#endif
|
|
{
|
|
hpm_uart_control(serial, RT_DEVICE_CTRL_SET_INT, (void *)ctrl_arg);
|
|
}
|
|
break;
|
|
case RT_DEVICE_CHECK_OPTMODE:
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
if ((ctrl_arg & RT_DEVICE_FLAG_DMA_TX)) {
|
|
return RT_SERIAL_TX_BLOCKING_NO_BUFFER;
|
|
} else
|
|
#endif
|
|
{
|
|
return RT_SERIAL_TX_BLOCKING_BUFFER;
|
|
}
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
|
|
static int hpm_uart_putc(struct rt_serial_device *serial, char ch)
|
|
{
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
uart_send_byte(uart->uart_base, ch);
|
|
uart_flush(uart->uart_base);
|
|
return ch;
|
|
}
|
|
|
|
static int hpm_uart_getc(struct rt_serial_device *serial)
|
|
{
|
|
int result = -1;
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
|
|
if (uart_check_status(uart->uart_base, uart_stat_data_ready)) {
|
|
uart_receive_byte(uart->uart_base, (uint8_t*)&result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static rt_ssize_t hpm_uart_transmit(struct rt_serial_device *serial,
|
|
rt_uint8_t *buf,
|
|
rt_size_t size,
|
|
rt_uint32_t tx_flag)
|
|
{
|
|
RT_ASSERT(serial != RT_NULL);
|
|
RT_ASSERT(buf != RT_NULL);
|
|
RT_ASSERT(size);
|
|
uint32_t fifo_size = 0, tx_size = 0;
|
|
uint32_t ringbuffer_data_len = 0;
|
|
struct hpm_uart *uart = (struct hpm_uart *)serial->parent.user_data;
|
|
struct rt_serial_tx_fifo *tx_fifo;
|
|
tx_fifo = (struct rt_serial_tx_fifo *) serial->serial_tx;
|
|
uint8_t ch = 0;
|
|
RT_ASSERT(tx_fifo != RT_NULL);
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
if (uart->dma_flags & RT_DEVICE_FLAG_DMA_TX) {
|
|
hpm_uart_dma_register_channel(serial, true, uart_tx_done, RT_NULL, RT_NULL);
|
|
intc_m_enable_irq(uart->tx_chn_ctx.resource.irq_num);
|
|
if (l1c_dc_is_enabled()) {
|
|
uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN((uint32_t)buf);
|
|
uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP((uint32_t)buf + size);
|
|
uint32_t aligned_size = aligned_end - aligned_start;
|
|
l1c_dc_flush(aligned_start, aligned_size);
|
|
}
|
|
hpm_uart_transmit_dma(serial, buf, size);
|
|
return size;
|
|
} else {
|
|
#else
|
|
{
|
|
#endif
|
|
|
|
if (size > 0) {
|
|
if (uart_check_status(uart->uart_base, uart_stat_tx_slot_avail)) {
|
|
uart_disable_irq(uart->uart_base, uart_intr_tx_slot_avail);
|
|
fifo_size = uart_get_fifo_size(uart->uart_base);
|
|
ringbuffer_data_len = rt_ringbuffer_data_len(&tx_fifo->rb);
|
|
tx_size = (ringbuffer_data_len > fifo_size) ? fifo_size : ringbuffer_data_len;
|
|
for (uint32_t i = 0; i < tx_size; i++) {
|
|
rt_ringbuffer_getchar(&tx_fifo->rb, &ch);
|
|
uart_write_byte(uart->uart_base, ch);
|
|
}
|
|
uart_enable_irq(uart->uart_base, uart_intr_tx_slot_avail);
|
|
}
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static const struct rt_uart_ops hpm_uart_ops = {
|
|
hpm_uart_configure,
|
|
hpm_uart_control,
|
|
hpm_uart_putc,
|
|
hpm_uart_getc,
|
|
hpm_uart_transmit,
|
|
};
|
|
|
|
|
|
|
|
static int hpm_uart_config(void)
|
|
{
|
|
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
|
hpm_stat_t status = status_success;
|
|
|
|
#ifdef BSP_USING_UART0
|
|
uarts[HPM_UART0_INDEX].serial->config = config;
|
|
uarts[HPM_UART0_INDEX].serial->config.rx_bufsz = BSP_UART0_RX_BUFSIZE;
|
|
uarts[HPM_UART0_INDEX].serial->config.tx_bufsz = BSP_UART0_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART0_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART0_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART0_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART0_RX_USING_DMA
|
|
#ifdef BSP_UART0_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART0_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART0_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART0
|
|
|
|
#ifdef BSP_USING_UART1
|
|
uarts[HPM_UART1_INDEX].serial->config = config;
|
|
uarts[HPM_UART1_INDEX].serial->config.rx_bufsz = BSP_UART1_RX_BUFSIZE;
|
|
uarts[HPM_UART1_INDEX].serial->config.tx_bufsz = BSP_UART1_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART1_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART1_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART1_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART1_RX_USING_DMA
|
|
#ifdef BSP_UART1_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART1_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART1_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART1
|
|
|
|
#ifdef BSP_USING_UART2
|
|
uarts[HPM_UART2_INDEX].serial->config = config;
|
|
uarts[HPM_UART2_INDEX].serial->config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
|
|
uarts[HPM_UART2_INDEX].serial->config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART2_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART2_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART2_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART2_RX_USING_DMA
|
|
#ifdef BSP_UART2_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART2_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART2_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART2
|
|
|
|
#ifdef BSP_USING_UART3
|
|
uarts[HPM_UART3_INDEX].serial->config = config;
|
|
uarts[HPM_UART3_INDEX].serial->config.rx_bufsz = BSP_UART3_RX_BUFSIZE;
|
|
uarts[HPM_UART3_INDEX].serial->config.tx_bufsz = BSP_UART3_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART3_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART3_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART3_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART3_RX_USING_DMA
|
|
#ifdef BSP_UART3_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART3_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART3_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART3
|
|
|
|
#ifdef BSP_USING_UART4
|
|
uarts[HPM_UART4_INDEX].serial->config = config;
|
|
uarts[HPM_UART4_INDEX].serial->config.rx_bufsz = BSP_UART4_RX_BUFSIZE;
|
|
uarts[HPM_UART4_INDEX].serial->config.tx_bufsz = BSP_UART4_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART4_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART4_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART4_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART4_RX_USING_DMA
|
|
#ifdef BSP_UART4_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART4_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART4_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART4
|
|
|
|
#ifdef BSP_USING_UART5
|
|
uarts[HPM_UART5_INDEX].serial->config = config;
|
|
uarts[HPM_UART5_INDEX].serial->config.rx_bufsz = BSP_UART5_RX_BUFSIZE;
|
|
uarts[HPM_UART5_INDEX].serial->config.tx_bufsz = BSP_UART5_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART5_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART5_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART5_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART5_RX_USING_DMA
|
|
#ifdef BSP_UART5_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART5_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART5_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART5
|
|
|
|
#ifdef BSP_USING_UART6
|
|
uarts[HPM_UART6_INDEX].serial->config = config;
|
|
uarts[HPM_UART6_INDEX].serial->config.rx_bufsz = BSP_UART6_RX_BUFSIZE;
|
|
uarts[HPM_UART6_INDEX].serial->config.tx_bufsz = BSP_UART6_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART6_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART6_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART6_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART6_RX_USING_DMA
|
|
#ifdef BSP_UART6_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART6_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART6_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART6
|
|
|
|
#ifdef BSP_USING_UART7
|
|
uarts[HPM_UART7_INDEX].serial->config = config;
|
|
uarts[HPM_UART7_INDEX].serial->config.rx_bufsz = BSP_UART7_RX_BUFSIZE;
|
|
uarts[HPM_UART7_INDEX].serial->config.tx_bufsz = BSP_UART7_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART7_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART7_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART7_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART7_RX_USING_DMA
|
|
#ifdef BSP_UART7_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART7_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART7_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART7
|
|
|
|
#ifdef BSP_USING_UART8
|
|
uarts[HPM_UART8_INDEX].serial->config = config;
|
|
uarts[HPM_UART8_INDEX].serial->config.rx_bufsz = BSP_UART8_RX_BUFSIZE;
|
|
uarts[HPM_UART8_INDEX].serial->config.tx_bufsz = BSP_UART8_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART8_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART8_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART8_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART8_RX_USING_DMA
|
|
#ifdef BSP_UART8_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART8_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART8_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART8
|
|
|
|
#ifdef BSP_USING_UART9
|
|
uarts[HPM_UART9_INDEX].serial->config = config;
|
|
uarts[HPM_UART9_INDEX].serial->config.rx_bufsz = BSP_UART9_RX_BUFSIZE;
|
|
uarts[HPM_UART9_INDEX].serial->config.tx_bufsz = BSP_UART9_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART9_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART9_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART9_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART9_RX_USING_DMA
|
|
#ifdef BSP_UART9_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART9_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART9_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART9
|
|
|
|
#ifdef BSP_USING_UART10
|
|
uarts[HPM_UART10_INDEX].serial->config = config;
|
|
uarts[HPM_UART10_INDEX].serial->config.rx_bufsz = BSP_UART10_RX_BUFSIZE;
|
|
uarts[HPM_UART10_INDEX].serial->config.tx_bufsz = BSP_UART10_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART10_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART10_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART10_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART10_RX_USING_DMA
|
|
#ifdef BSP_UART10_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART10_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART10_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART10
|
|
|
|
#ifdef BSP_USING_UART11
|
|
uarts[HPM_UART11_INDEX].serial->config = config;
|
|
uarts[HPM_UART11_INDEX].serial->config.rx_bufsz = BSP_UART11_RX_BUFSIZE;
|
|
uarts[HPM_UART11_INDEX].serial->config.tx_bufsz = BSP_UART11_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART11_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART11_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART11_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART11_RX_USING_DMA
|
|
#ifdef BSP_UART11_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART11_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART11_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART11
|
|
|
|
#ifdef BSP_USING_UART12
|
|
uarts[HPM_UART12_INDEX].serial->config = config;
|
|
uarts[HPM_UART12_INDEX].serial->config.rx_bufsz = BSP_UART12_RX_BUFSIZE;
|
|
uarts[HPM_UART12_INDEX].serial->config.tx_bufsz = BSP_UART12_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART12_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART12_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART12_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART12_RX_USING_DMA
|
|
#ifdef BSP_UART12_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART12_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART12_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART12
|
|
|
|
#ifdef BSP_USING_UART13
|
|
uarts[HPM_UART13_INDEX].serial->config = config;
|
|
uarts[HPM_UART13_INDEX].serial->config.rx_bufsz = BSP_UART13_RX_BUFSIZE;
|
|
uarts[HPM_UART13_INDEX].serial->config.tx_bufsz = BSP_UART13_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART13_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART13_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART13_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART13_RX_USING_DMA
|
|
#ifdef BSP_UART13_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART13_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART13_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART13
|
|
|
|
#ifdef BSP_USING_UART14
|
|
uarts[HPM_UART14_INDEX].serial->config = config;
|
|
uarts[HPM_UART14_INDEX].serial->config.rx_bufsz = BSP_UART14_RX_BUFSIZE;
|
|
uarts[HPM_UART14_INDEX].serial->config.tx_bufsz = BSP_UART14_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART14_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART14_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART14_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART14_RX_USING_DMA
|
|
#ifdef BSP_UART14_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART14_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART14_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART14
|
|
|
|
#ifdef BSP_USING_UART15
|
|
uarts[HPM_UART15_INDEX].serial->config = config;
|
|
uarts[HPM_UART15_INDEX].serial->config.rx_bufsz = BSP_UART15_RX_BUFSIZE;
|
|
uarts[HPM_UART15_INDEX].serial->config.tx_bufsz = BSP_UART15_TX_BUFSIZE;
|
|
#ifdef RT_SERIAL_USING_DMA
|
|
uarts[HPM_UART15_INDEX].dma_flags = 0;
|
|
#ifdef BSP_UART15_RX_USING_DMA
|
|
status = hpm_uart_dma_rx_init(&uarts[HPM_UART15_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART15_RX_USING_DMA
|
|
#ifdef BSP_UART15_TX_USING_DMA
|
|
status = hpm_uart_dma_tx_init(&uarts[HPM_UART15_INDEX]);
|
|
if (status != status_success)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
#endif //BSP_UART15_TX_USING_DMA
|
|
#endif // RT_SERIAL_USING_DMA
|
|
#endif //BSP_USING_UART15
|
|
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
int rt_hw_uart_init(void)
|
|
{
|
|
/* Added bypass logic here since the rt_hw_uart_init function will be initialized twice, the 2nd initialization should be bypassed */
|
|
static bool initialized;
|
|
rt_err_t err = RT_EOK;
|
|
if (initialized)
|
|
{
|
|
return err;
|
|
}
|
|
else
|
|
{
|
|
initialized = true;
|
|
}
|
|
|
|
if (RT_EOK != hpm_uart_config()) {
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++) {
|
|
uarts[i].serial->ops = &hpm_uart_ops;
|
|
|
|
/* register UART device */
|
|
err = rt_hw_serial_register(uarts[i].serial,
|
|
uarts[i].device_name,
|
|
RT_DEVICE_FLAG_RDWR,
|
|
(void*)&uarts[i]);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
INIT_BOARD_EXPORT(rt_hw_uart_init);
|
|
|
|
#endif /* RT_USING_SERIAL */
|