From 621ec31ea6a771a5a02a9b12e6fd0126d3ea96c5 Mon Sep 17 00:00:00 2001 From: hydrogenium2020 <107231979+hydrogenium2020-offical@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:41:45 +0800 Subject: [PATCH] Feat:Try to bring UART(Not Tested) Because my board didn't have any UART port. --- loader/pinmux.c | 14 ++++++++ loader/pinmux.h | 32 ++++++++++++++++++ loader/t124.h | 4 +++ loader/types.h | 1 + loader/uart.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ loader/uart.h | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 221 insertions(+) create mode 100644 loader/uart.c create mode 100644 loader/uart.h diff --git a/loader/pinmux.c b/loader/pinmux.c index 90e22f7..7bd4b2d 100644 --- a/loader/pinmux.c +++ b/loader/pinmux.c @@ -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; +} diff --git a/loader/pinmux.h b/loader/pinmux.h index e05311e..60399a5 100644 --- a/loader/pinmux.h +++ b/loader/pinmux.h @@ -14,6 +14,38 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +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); diff --git a/loader/t124.h b/loader/t124.h index 558c9bb..feacc8f 100644 --- a/loader/t124.h +++ b/loader/t124.h @@ -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 diff --git a/loader/types.h b/loader/types.h index df2f09c..da4ea03 100644 --- a/loader/types.h +++ b/loader/types.h @@ -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 diff --git a/loader/uart.c b/loader/uart.c new file mode 100644 index 0000000..0d72e0c --- /dev/null +++ b/loader/uart.c @@ -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); +} \ No newline at end of file diff --git a/loader/uart.h b/loader/uart.h new file mode 100644 index 0000000..4a2adf4 --- /dev/null +++ b/loader/uart.h @@ -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); \ No newline at end of file