@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019-2020 CTCaer
|
||||
* Copyright (c) 2019-2022 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,45 +17,58 @@
|
||||
|
||||
#include <soc/uart.h>
|
||||
#include <soc/clock.h>
|
||||
#include <soc/timer.h>
|
||||
#include <soc/t210.h>
|
||||
#include <utils/util.h>
|
||||
|
||||
/* UART A, B, C, D and E. */
|
||||
static const u32 uart_baseoff[5] = { 0, 0x40, 0x200, 0x300, 0x400 };
|
||||
|
||||
void uart_init(u32 idx, u32 baud)
|
||||
void uart_init(u32 idx, u32 baud, u32 mode)
|
||||
{
|
||||
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||
|
||||
// Make sure no data is being sent.
|
||||
uart_wait_idle(idx, UART_TX_IDLE);
|
||||
if (!(mode & (UART_MCR_CTS_EN | UART_MCR_DTR)))
|
||||
uart_wait_xfer(idx, UART_TX_IDLE);
|
||||
|
||||
// Set clock.
|
||||
bool clk_type = clock_uart_use_src_div(idx, baud);
|
||||
|
||||
// 2 STOP bits for rates > 1M. (Reduced efficiency but less errors on high baudrates).
|
||||
u32 uart_lcr_stop = baud > 1000000 ? UART_LCR_STOP : 0;
|
||||
|
||||
// Misc settings.
|
||||
u32 div = clk_type ? ((8 * baud + 408000000) / (16 * baud)) : 1; // DIV_ROUND_CLOSEST.
|
||||
uart->UART_IER_DLAB = 0; // Disable interrupts.
|
||||
uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.
|
||||
uart->UART_THR_DLAB = (u8)div; // Divisor latch LSB.
|
||||
uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.
|
||||
uart->UART_THR_DLAB = (u8)div; // Divisor latch LSB.
|
||||
uart->UART_IER_DLAB = (u8)(div >> 8); // Divisor latch MSB.
|
||||
uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Disable DLAB.
|
||||
|
||||
// Disable DLAB and set STOP bits setting if applicable.
|
||||
uart->UART_LCR = uart_lcr_stop | UART_LCR_WORD_LENGTH_8;
|
||||
(void)uart->UART_SPR;
|
||||
|
||||
// Setup and flush fifo.
|
||||
// Enable fifo.
|
||||
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO;
|
||||
(void)uart->UART_SPR;
|
||||
usleep(20);
|
||||
uart->UART_MCR = 0; // Disable hardware flow control.
|
||||
|
||||
// Disable hardware flow control.
|
||||
uart->UART_MCR = 0;
|
||||
usleep(96);
|
||||
|
||||
// Clear tx/rx fifos.
|
||||
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
|
||||
|
||||
// Set hardware flow control.
|
||||
uart->UART_MCR = mode;
|
||||
|
||||
// Wait 3 symbols for baudrate change.
|
||||
usleep(3 * ((baud + 999999) / baud));
|
||||
uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE);
|
||||
uart_wait_xfer(idx, UART_TX_IDLE | UART_RX_RDYR);
|
||||
}
|
||||
|
||||
void uart_wait_idle(u32 idx, u32 which)
|
||||
void uart_wait_xfer(u32 idx, u32 which)
|
||||
{
|
||||
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||
if (UART_TX_IDLE & which)
|
||||
@@ -63,10 +76,10 @@ void uart_wait_idle(u32 idx, u32 which)
|
||||
while (!(uart->UART_LSR & UART_LSR_TMTY))
|
||||
;
|
||||
}
|
||||
if (UART_RX_IDLE & which)
|
||||
if (UART_RX_RDYR & which)
|
||||
{
|
||||
while (uart->UART_LSR & UART_LSR_RDR)
|
||||
;
|
||||
(void)uart->UART_THR_DLAB;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,26 +98,31 @@ void uart_send(u32 idx, const u8 *buf, u32 len)
|
||||
u32 uart_recv(u32 idx, u8 *buf, u32 len)
|
||||
{
|
||||
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||
bool manual_mode = uart->UART_MCR & UART_MCR_RTS;
|
||||
u32 timeout = get_tmr_us() + 250;
|
||||
u32 i;
|
||||
|
||||
if (manual_mode)
|
||||
uart->UART_MCR &= ~UART_MCR_RTS;
|
||||
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
while (!(uart->UART_LSR & UART_LSR_RDR))
|
||||
{
|
||||
if (timeout < get_tmr_us())
|
||||
break;
|
||||
if (len && len < i)
|
||||
break;
|
||||
}
|
||||
if (timeout < get_tmr_us())
|
||||
if (len && len <= i)
|
||||
break;
|
||||
|
||||
while (!(uart->UART_LSR & UART_LSR_RDR))
|
||||
if (timeout < get_tmr_us())
|
||||
goto out;
|
||||
|
||||
buf[i] = uart->UART_THR_DLAB;
|
||||
timeout = get_tmr_us() + 250;
|
||||
}
|
||||
|
||||
return i ? (len ? (i - 1) : i) : 0;
|
||||
out:
|
||||
if (manual_mode)
|
||||
uart->UART_MCR |= UART_MCR_RTS;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void uart_invert(u32 idx, bool enable, u32 invert_mask)
|
||||
@@ -118,6 +136,14 @@ void uart_invert(u32 idx, bool enable, u32 invert_mask)
|
||||
(void)uart->UART_SPR;
|
||||
}
|
||||
|
||||
void uart_set_mode(u32 idx, u32 mode)
|
||||
{
|
||||
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||
|
||||
uart->UART_MCR = mode;
|
||||
(void)uart->UART_SPR;
|
||||
}
|
||||
|
||||
u32 uart_get_IIR(u32 idx)
|
||||
{
|
||||
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
|
||||
@@ -172,3 +198,24 @@ void uart_empty_fifo(u32 idx, u32 which)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UART_PORT
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utils/sprintf.h>
|
||||
|
||||
void uart_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
//! NOTE: Anything more and it will hang. Heap usage is out of the question.
|
||||
char text[256];
|
||||
|
||||
va_start(ap, fmt);
|
||||
s_vprintf(text, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
uart_send(DEBUG_UART_PORT, (u8 *)text, strlen(text));
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user