Feat:Try to bring UART(Not Tested)

Because my board didn't have any UART port.
This commit is contained in:
hydrogenium2020 2024-01-31 16:41:45 +08:00
parent d4a5b5f87f
commit 621ec31ea6
6 changed files with 221 additions and 0 deletions

View File

@ -16,3 +16,17 @@
*/
#include "t124.h"
#include "pinmux.h"
void pinmux_config_uart(u32 idx)
{
PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0;
PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0;
PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
}
void pinmux_config_i2c(u32 idx)
{
PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE;
}

View File

@ -14,6 +14,38 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
enum {
PINMUX_FUNC_MASK = 3 << 0,
PINMUX_PULL_MASK = 3 << 2,
PINMUX_PULL_NONE = 0 << 2,
PINMUX_PULL_DOWN = 1 << 2,
PINMUX_PULL_UP = 2 << 2,
PINMUX_TRISTATE = 1 << 4,
PINMUX_PARKED = 1 << 5,
PINMUX_INPUT_ENABLE = 1 << 6,
PINMUX_LOCK = 1 << 7,
PINMUX_LPDR = 1 << 8,
PINMUX_HSM = 1 << 9,
PINMUX_IO_HV = 1 << 10,
PINMUX_OPEN_DRAIN = 1 << 11,
PINMUX_SCHMT = 1 << 12,
PINMUX_DRIVE_1X = 0 << 13,
PINMUX_DRIVE_2X = 1 << 13,
PINMUX_DRIVE_3X = 2 << 13,
PINMUX_DRIVE_4X = 3 << 13,
};
/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */
#define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x))
#define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x))
#define PINMUX_AUX_UARTX_RTS(x) (0xEC + 0x10 * (x))
#define PINMUX_AUX_UARTX_CTS(x) (0xF0 + 0x10 * (x))
/*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */
#define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x))
#define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x))
void pinmux_config_uart(u32 idx);
void pinmux_config_i2c(u32 idx);

View File

@ -28,6 +28,8 @@
#define SYSCTR0_BASE 0x700F0000
#define APB_MISC_BASE 0x70000000
#define PINMUX_AUX_BASE 0x70003000
#define I2C_BASE 0x7000C000
#define UART_BASE 0x70006000
#define MMIO_REG32(base, off) *(vu32 *)((base) + (off))
@ -40,6 +42,8 @@
#define SYSCTR0(off) MMIO_REG32(SYSCTR0_BASE, off)
#define APB_MISC(off) MMIO_REG32(APB_MISC_BASE, off)
#define PINMUX_AUX(off) MMIO_REG32(PINMUX_AUX_BASE, off)
#define I2C(off) MMIO_REG32(I2C_BASE, off)
#define UART(off) MMIO_REG32(UART_BASE, off)
//PMC
#define APBDEV_PMC_CRYPTO_OP 0xF4

View File

@ -34,4 +34,5 @@ typedef u32 size_t;
typedef u32 uintptr_t;
#define BIT(n) (1U << (n))
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#endif

87
loader/uart.c Normal file
View File

@ -0,0 +1,87 @@
#include "uart.h"
#include "t124.h"
#include "util.h"
#include "clock.h"
/* UART A, B, C, D and E. */
static const u16 _uart_base_offsets[5] = { 0, 0x40, 0x200, 0x300, 0x400 };
void uart_wait_xfer(u32 idx, u32 which)
{
uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);
if (UART_TX_IDLE & which)
{
while (!(uart->UART_LSR & UART_LSR_TMTY))
;
}
if (UART_RX_RDYR & which)
{
while (uart->UART_LSR & UART_LSR_RDR)
(void)uart->UART_THR_DLAB;
}
}
void uart_send(u32 idx, const u8 *buf, u32 len)
{
uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);
for (u32 i = 0; i != len; i++)
{
while (!(uart->UART_LSR & UART_LSR_THRE))
;
uart->UART_THR_DLAB = buf[i];
}
}
void uart_invert(u32 idx, u32 enable, u32 invert_mask)
{
uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);
if (enable)
uart->UART_IRDA_CSR |= invert_mask;
else
uart->UART_IRDA_CSR &= ~invert_mask;
(void)uart->UART_SPR;
}
void uart_init(u32 idx, u32 baud, u32 mode)
{
uart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);
// Make sure no data is being sent.
if (!(mode & (UART_MCR_CTS_EN | UART_MCR_DTR)))
uart_wait_xfer(idx, UART_TX_IDLE);
// Set clock. bool type
u32 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_IER_DLAB = (u8)(div >> 8); // Divisor latch MSB.
// Disable DLAB and set STOP bits setting if applicable.
uart->UART_LCR = uart_lcr_stop | UART_LCR_WORD_LENGTH_8;
(void)uart->UART_SPR;
// Enable fifo.
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO;
(void)uart->UART_SPR;
sleep(20);
// Disable hardware flow control.
uart->UART_MCR = 0;
sleep(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.
sleep(3 * ((baud + 999999) / baud));
uart_wait_xfer(idx, UART_TX_IDLE | UART_RX_RDYR);
}

83
loader/uart.h Normal file
View File

@ -0,0 +1,83 @@
#include "types.h"
#define UART_A 0
#define UART_B 1
#define UART_C 2
#define UART_D 3
#define BAUD_115200 115200
#define UART_TX_IDLE BIT(0)
#define UART_RX_RDYR BIT(1)
#define UART_TX_FIFO_FULL BIT(8)
#define UART_RX_FIFO_EMPTY BIT(9)
#define UART_INVERT_RXD BIT(0)
#define UART_INVERT_TXD BIT(1)
#define UART_INVERT_CTS BIT(2)
#define UART_INVERT_RTS BIT(3)
#define UART_IER_DLAB_IE_EORD BIT(5)
#define UART_LCR_WORD_LENGTH_8 0x3
#define UART_LCR_STOP BIT(2)
#define UART_LCR_DLAB BIT(7)
#define UART_LSR_RDR BIT(0)
#define UART_LSR_THRE BIT(5)
#define UART_LSR_TMTY BIT(6)
#define UART_LSR_FIFOE BIT(7)
#define UART_IIR_FCR_EN_FIFO BIT(0)
#define UART_IIR_FCR_RX_CLR BIT(1)
#define UART_IIR_FCR_TX_CLR BIT(2)
#define UART_IIR_NO_INT BIT(0)
#define UART_IIR_INT_MASK 0xF
/* Custom returned interrupt results. Actual interrupts are -1 */
#define UART_IIR_NOI 0 // No interrupt.
#define UART_IIR_MSI 1 // Modem status interrupt.
#define UART_IIR_THRI 2 // Transmitter holding register empty.
#define UART_IIR_RDI 3 // Receiver data interrupt.
#define UART_IIR_ERROR 4 // Overrun Error, Parity Error, Framing Error, Break.
#define UART_IIR_REDI 5 // Receiver end of data interrupt.
#define UART_IIR_RDTI 7 // Receiver data timeout interrupt.
#define UART_MCR_DTR BIT(0)
#define UART_MCR_RTS BIT(1)
#define UART_MCR_CTS_EN BIT(5)
#define UART_MCR_RTS_EN BIT(6)
//! TODO: Commented out modes are not supported yet.
typedef enum _uart_mode_t
{
UART_AO_TX_AO_RX = 0,
//UART_MN_TX_AO_RX = UART_MCR_RTS | UART_MCR_DTR,
UART_AO_TX_MN_RX = UART_MCR_RTS, // Up to 36 bytes read.
//UART_MN_TX_AO_RX = UART_MCR_DTR,
//UART_HW_TX_HW_RX = UART_MCR_RTS_EN | UART_MCR_CTS_EN,
UART_AO_TX_HW_RX = UART_MCR_RTS_EN,
//UART_HW_TX_AO_RX = UART_MCR_CTS_EN,
} uart_mode_t;
typedef struct _uart_t
{
/* 0x00 */ vu32 UART_THR_DLAB;
/* 0x04 */ vu32 UART_IER_DLAB;
/* 0x08 */ vu32 UART_IIR_FCR;
/* 0x0C */ vu32 UART_LCR;
/* 0x10 */ vu32 UART_MCR;
/* 0x14 */ vu32 UART_LSR;
/* 0x18 */ vu32 UART_MSR;
/* 0x1C */ vu32 UART_SPR;
/* 0x20 */ vu32 UART_IRDA_CSR;
/* 0x24 */ vu32 UART_RX_FIFO_CFG;
/* 0x28 */ vu32 UART_MIE;
/* 0x2C */ vu32 UART_VENDOR_STATUS;
/* 0x30 */ u8 _pad_30[0xC];
/* 0x3C */ vu32 UART_ASR;
} uart_t;
void uart_wait_xfer(u32 idx, u32 which);
void uart_invert(u32 idx, u32 enable, u32 invert_mask);
void uart_init(u32 idx, u32 baud, u32 mode);
void uart_send(u32 idx, const u8 *buf, u32 len);