diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
commit | 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch) | |
tree | bcf648efac40ca6139842707f0eba5a4496a6dd2 /drivers/imx/uart | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.tar.xz arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.zip |
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/imx/uart')
-rw-r--r-- | drivers/imx/uart/imx_crash_uart.S | 131 | ||||
-rw-r--r-- | drivers/imx/uart/imx_uart.c | 181 | ||||
-rw-r--r-- | drivers/imx/uart/imx_uart.h | 163 |
3 files changed, 475 insertions, 0 deletions
diff --git a/drivers/imx/uart/imx_crash_uart.S b/drivers/imx/uart/imx_crash_uart.S new file mode 100644 index 0000000..aa987b3 --- /dev/null +++ b/drivers/imx/uart/imx_crash_uart.S @@ -0,0 +1,131 @@ +/* + * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <arch.h> +#include <asm_macros.S> +#include <assert_macros.S> +#include <imx_uart.h> +#include <platform_def.h> + + .globl imx_crash_uart_init + .globl imx_crash_uart_putc + + /* ----------------------------------------------- + * int imx_crash_uart_init(uintptr_t base_addr, + * unsigned int uart_clk, unsigned int baud_rate) + * Function to initialize the console without a + * C Runtime to print debug information. This + * function will be accessed by console_init and + * crash reporting. + * In: r0 - console base address + * r1 - Uart clock in Hz + * r2 - Baud rate + * Out: return 1 on success else 0 on error + * Clobber list : r1, r2, r3, r4 + * ----------------------------------------------- + */ +func imx_crash_uart_init + /* Free up r1 as a scratch reg */ + mov r4, r0 + mov r0, r1 + + /* Reset UART via CR2 */ + add r1, r4, #IMX_UART_CR2_OFFSET + movs r3, #0 + str r3, [r4, #IMX_UART_CR2_OFFSET] + + /* Wait for reset complete */ +__wait_cr2_reset: + ldr r3, [r1, #0] + ands r3, #IMX_UART_CR2_SRST + beq __wait_cr2_reset + + /* Enable UART */ + movs r3, #IMX_UART_CR1_UARTEN + mov r1, r2 + str r3, [r4, #IMX_UART_CR1_OFFSET] + + /* + * Ignore RTC/CTS - disable reset + * Magic value #16423 => + * IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST + */ + movw r3, #16423 + str r3, [r4, #IMX_UART_CR2_OFFSET] + + /* + * No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) + * Magic value => #132 + * IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL + */ + movs r3, #132 + str r3, [r4, #IMX_UART_CR3_OFFSET] + + /* + * Set CTS FIFO trigger to 32 bytes bits 15:10 + * Magic value => #32768 + * FIFO trigger bitmask 100000 + * */ + mov r3, #32768 + str r3, [r4, #IMX_UART_CR4_OFFSET] + + /* + * TX/RX-thresh = 2 bytes, DCE (bit6 = 0), refclk @24MHz / 4 + * Magic value #2562 + * IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | IMX_UART_FCR_RFDIV2 + */ + #ifdef IMX_UART_DTE + movw r3, #2626 + #else + movw r3, #2562 + #endif + str r3, [r4, #IMX_UART_FCR_OFFSET] + + /* This BIR should be set to 0x0F prior to writing the BMR */ + movs r3, #15 + str r3, [r4, #IMX_UART_BIR_OFFSET] + + /* Hard-code to 115200 @ 24 MHz */ + movs r0, #104 + str r0, [r4, #IMX_UART_BMR_OFFSET] + + /* Indicate success */ + movs r0, #1 + bx lr +endfunc imx_crash_uart_init + + /* -------------------------------------------------------- + * int imx_crash_uart_putc(int c, uintptr_t base_addr) + * Function to output a character over the console. It + * returns the character printed on success or -1 on error. + * In : r0 - character to be printed + * r1 - console base address + * Out : return -1 on error else return character. + * Clobber list : r2 + * -------------------------------------------------------- + */ +func imx_crash_uart_putc + /* Output specified character to UART shift-register */ + str r0, [r1, #IMX_UART_TXD_OFFSET] + + /* Wait for transmit IMX_UART_STAT2_OFFSET.IMX_UART_STAT2_TXDC == 1 */ +__putc_spin_ready: + ldr r2, [r1, #IMX_UART_STAT2_OFFSET] + ands r2, #IMX_UART_STAT2_TXDC + beq __putc_spin_ready + + /* Transmit complete do we need to fixup \n to \n\r */ + cmp r0, #10 + beq __putc_fixup_lf + + /* No fixup necessary - exit here */ + movs r0, #0 + bx lr + + /* Fixup \n to \n\r */ +__putc_fixup_lf: + movs r0, #13 + b imx_crash_uart_putc +endfunc imx_crash_uart_putc diff --git a/drivers/imx/uart/imx_uart.c b/drivers/imx/uart/imx_uart.c new file mode 100644 index 0000000..dfe2e92 --- /dev/null +++ b/drivers/imx/uart/imx_uart.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <platform_def.h> + +#include <arch.h> +#include <lib/mmio.h> + +#include <imx_uart.h> + +/* TX/RX FIFO threshold */ +#define TX_RX_THRESH 2 + +struct clk_div_factors { + uint32_t fcr_div; + uint32_t bmr_div; +}; + +static struct clk_div_factors clk_div[] = { + { + .fcr_div = IMX_UART_FCR_RFDIV1, + .bmr_div = 1, + }, + { + .fcr_div = IMX_UART_FCR_RFDIV2, + .bmr_div = 2, + }, + { + .fcr_div = IMX_UART_FCR_RFDIV3, + .bmr_div = 3, + }, + { + .fcr_div = IMX_UART_FCR_RFDIV4, + .bmr_div = 4, + }, + { + .fcr_div = IMX_UART_FCR_RFDIV5, + .bmr_div = 5, + }, + { + .fcr_div = IMX_UART_FCR_RFDIV6, + .bmr_div = 6, + }, + { + .fcr_div = IMX_UART_FCR_RFDIV7, + .bmr_div = 7, + }, +}; + +static void write_reg(uintptr_t base, uint32_t offset, uint32_t val) +{ + mmio_write_32(base + offset, val); +} + +static uint32_t read_reg(uintptr_t base, uint32_t offset) +{ + return mmio_read_32(base + offset); +} + +int console_imx_uart_core_init(uintptr_t base_addr, unsigned int uart_clk, + unsigned int baud_rate) +{ + uint32_t val; + uint8_t clk_idx = 1; + + /* Reset UART */ + write_reg(base_addr, IMX_UART_CR2_OFFSET, 0); + do { + val = read_reg(base_addr, IMX_UART_CR2_OFFSET); + } while (!(val & IMX_UART_CR2_SRST)); + + /* Enable UART */ + write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN); + + /* Ignore RTS, 8N1, enable tx/rx, disable reset */ + val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | + IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST); + write_reg(base_addr, IMX_UART_CR2_OFFSET, val); + + /* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */ + val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL; + write_reg(base_addr, IMX_UART_CR3_OFFSET, val); + + /* Set CTS FIFO trigger to 32 bytes bits 15:10 */ + write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000); + + /* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */ + val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | + clk_div[clk_idx].fcr_div; + #ifdef IMX_UART_DTE + /* Set DTE (bit6 = 1) */ + val |= IMX_UART_FCR_DCEDTE; + #endif + write_reg(base_addr, IMX_UART_FCR_OFFSET, val); + + /* + * The equation for BAUD rate calculation is + * RefClk = Supplied clock / FCR_DIVx + * + * BAUD = Refclk + * ------------ + * 16 x (UBMR + 1/ UBIR + 1) + * + * We write 0x0f into UBIR to remove the 16 mult + * BAUD = 6000000 + * ------------ + * 16 x (UBMR + 1/ 15 + 1) + */ + + write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f); + val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1; + write_reg(base_addr, IMX_UART_BMR_OFFSET, val); + + return 0; +} + +/* -------------------------------------------------------- + * int console_core_putc(int c, uintptr_t base_addr) + * Function to output a character over the console. It + * returns the character printed on success or -1 on error. + * In : r0 - character to be printed + * r1 - console base address + * Out : return -1 on error else return character. + * Clobber list : r2 + * -------------------------------------------------------- + */ +int console_imx_uart_core_putc(int c, uintptr_t base_addr) +{ + uint32_t val; + + if (c == '\n') + console_imx_uart_core_putc('\r', base_addr); + + /* Write data */ + write_reg(base_addr, IMX_UART_TXD_OFFSET, c); + + /* Wait for transmit */ + do { + val = read_reg(base_addr, IMX_UART_STAT2_OFFSET); + } while (!(val & IMX_UART_STAT2_TXDC)); + + return 0; +} + +/* + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 on error. + * In : r0 - console base address + * Clobber list : r0, r1 + * --------------------------------------------- + */ +int console_imx_uart_core_getc(uintptr_t base_addr) +{ + uint32_t val; + + val = read_reg(base_addr, IMX_UART_TS_OFFSET); + if (val & IMX_UART_TS_RXEMPTY) + return -1; + + val = read_reg(base_addr, IMX_UART_RXD_OFFSET); + return (int)(val & 0x000000FF); +} + +/* + * Function to force a write of all buffered + * data that hasn't been output. + * In : r0 - console base address + * Out : void + * Clobber list : r0, r1 + * --------------------------------------------- + */ +void console_imx_uart_core_flush(uintptr_t base_addr) +{ +} + diff --git a/drivers/imx/uart/imx_uart.h b/drivers/imx/uart/imx_uart.h new file mode 100644 index 0000000..a133024 --- /dev/null +++ b/drivers/imx/uart/imx_uart.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef IMX_UART_H +#define IMX_UART_H + +#include <drivers/console.h> + +#define IMX_UART_RXD_OFFSET 0x00 +#define IMX_UART_RXD_CHARRDY BIT(15) +#define IMX_UART_RXD_ERR BIT(14) +#define IMX_UART_RXD_OVERRUN BIT(13) +#define IMX_UART_RXD_FRMERR BIT(12) +#define IMX_UART_RXD_BRK BIT(11) +#define IMX_UART_RXD_PRERR BIT(10) + +#define IMX_UART_TXD_OFFSET 0x40 + +#define IMX_UART_CR1_OFFSET 0x80 +#define IMX_UART_CR1_ADEN BIT(15) +#define IMX_UART_CR1_ADBR BIT(14) +#define IMX_UART_CR1_TRDYEN BIT(13) +#define IMX_UART_CR1_IDEN BIT(12) +#define IMX_UART_CR1_RRDYEN BIT(9) +#define IMX_UART_CR1_RXDMAEN BIT(8) +#define IMX_UART_CR1_IREN BIT(7) +#define IMX_UART_CR1_TXMPTYEN BIT(6) +#define IMX_UART_CR1_RTSDEN BIT(5) +#define IMX_UART_CR1_SNDBRK BIT(4) +#define IMX_UART_CR1_TXDMAEN BIT(3) +#define IMX_UART_CR1_ATDMAEN BIT(2) +#define IMX_UART_CR1_DOZE BIT(1) +#define IMX_UART_CR1_UARTEN BIT(0) + +#define IMX_UART_CR2_OFFSET 0x84 +#define IMX_UART_CR2_ESCI BIT(15) +#define IMX_UART_CR2_IRTS BIT(14) +#define IMX_UART_CR2_CTSC BIT(13) +#define IMX_UART_CR2_CTS BIT(12) +#define IMX_UART_CR2_ESCEN BIT(11) +#define IMX_UART_CR2_PREN BIT(8) +#define IMX_UART_CR2_PROE BIT(7) +#define IMX_UART_CR2_STPB BIT(6) +#define IMX_UART_CR2_WS BIT(5) +#define IMX_UART_CR2_RTSEN BIT(4) +#define IMX_UART_CR2_ATEN BIT(3) +#define IMX_UART_CR2_TXEN BIT(2) +#define IMX_UART_CR2_RXEN BIT(1) +#define IMX_UART_CR2_SRST BIT(0) + +#define IMX_UART_CR3_OFFSET 0x88 +#define IMX_UART_CR3_DTREN BIT(13) +#define IMX_UART_CR3_PARERREN BIT(12) +#define IMX_UART_CR3_FARERREN BIT(11) +#define IMX_UART_CR3_DSD BIT(10) +#define IMX_UART_CR3_DCD BIT(9) +#define IMX_UART_CR3_RI BIT(8) +#define IMX_UART_CR3_ADNIMP BIT(7) +#define IMX_UART_CR3_RXDSEN BIT(6) +#define IMX_UART_CR3_AIRINTEN BIT(5) +#define IMX_UART_CR3_AWAKEN BIT(4) +#define IMX_UART_CR3_DTRDEN BIT(3) +#define IMX_UART_CR3_RXDMUXSEL BIT(2) +#define IMX_UART_CR3_INVT BIT(1) +#define IMX_UART_CR3_ACIEN BIT(0) + +#define IMX_UART_CR4_OFFSET 0x8c +#define IMX_UART_CR4_INVR BIT(9) +#define IMX_UART_CR4_ENIRI BIT(8) +#define IMX_UART_CR4_WKEN BIT(7) +#define IMX_UART_CR4_IDDMAEN BIT(6) +#define IMX_UART_CR4_IRSC BIT(5) +#define IMX_UART_CR4_LPBYP BIT(4) +#define IMX_UART_CR4_TCEN BIT(3) +#define IMX_UART_CR4_BKEN BIT(2) +#define IMX_UART_CR4_OREN BIT(1) +#define IMX_UART_CR4_DREN BIT(0) + +#define IMX_UART_FCR_OFFSET 0x90 +#define IMX_UART_FCR_TXTL_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) |\ + BIT(11) | BIT(10)) +#define IMX_UART_FCR_TXTL(x) ((x) << 10) +#define IMX_UART_FCR_RFDIV_MASK (BIT(9) | BIT(8) | BIT(7)) +#define IMX_UART_FCR_RFDIV7 (BIT(9) | BIT(8)) +#define IMX_UART_FCR_RFDIV1 (BIT(9) | BIT(7)) +#define IMX_UART_FCR_RFDIV2 BIT(9) +#define IMX_UART_FCR_RFDIV3 (BIT(8) | BIT(7)) +#define IMX_UART_FCR_RFDIV4 BIT(8) +#define IMX_UART_FCR_RFDIV5 BIT(7) +#define IMX_UART_FCR_RFDIV6 0 +#define IMX_UART_FCR_DCEDTE BIT(6) +#define IMX_UART_FCR_RXTL_MASK (BIT(5) | BIT(4) | BIT(3) | BIT(2) |\ + BIT(1) | BIT(0)) +#define IMX_UART_FCR_RXTL(x) x + +#define IMX_UART_STAT1_OFFSET 0x94 +#define IMX_UART_STAT1_PARITYERR BIT(15) +#define IMX_UART_STAT1_RTSS BIT(14) +#define IMX_UART_STAT1_TRDY BIT(13) +#define IMX_UART_STAT1_RTSD BIT(12) +#define IMX_UART_STAT1_ESCF BIT(11) +#define IMX_UART_STAT1_FRAMEERR BIT(10) +#define IMX_UART_STAT1_RRDY BIT(9) +#define IMX_UART_STAT1_AGTIM BIT(8) +#define IMX_UART_STAT1_DTRD BIT(7) +#define IMX_UART_STAT1_RXDS BIT(6) +#define IMX_UART_STAT1_AIRINT BIT(5) +#define IMX_UART_STAT1_AWAKE BIT(4) +#define IMX_UART_STAT1_SAD BIT(3) + +#define IMX_UART_STAT2_OFFSET 0x98 +#define IMX_UART_STAT2_ADET BIT(15) +#define IMX_UART_STAT2_TXFE BIT(14) +#define IMX_UART_STAT2_DTRF BIT(13) +#define IMX_UART_STAT2_IDLE BIT(12) +#define IMX_UART_STAT2_ACST BIT(11) +#define IMX_UART_STAT2_RIDELT BIT(10) +#define IMX_UART_STAT2_RIIN BIT(9) +#define IMX_UART_STAT2_IRINT BIT(8) +#define IMX_UART_STAT2_WAKE BIT(7) +#define IMX_UART_STAT2_DCDDELT BIT(6) +#define IMX_UART_STAT2_DCDIN BIT(5) +#define IMX_UART_STAT2_RTSF BIT(4) +#define IMX_UART_STAT2_TXDC BIT(3) +#define IMX_UART_STAT2_BRCD BIT(2) +#define IMX_UART_STAT2_ORE BIT(1) +#define IMX_UART_STAT2_RCR BIT(0) + +#define IMX_UART_ESC_OFFSET 0x9c + +#define IMX_UART_TIM_OFFSET 0xa0 + +#define IMX_UART_BIR_OFFSET 0xa4 + +#define IMX_UART_BMR_OFFSET 0xa8 + +#define IMX_UART_BRC_OFFSET 0xac + +#define IMX_UART_ONEMS_OFFSET 0xb0 + +#define IMX_UART_TS_OFFSET 0xb4 +#define IMX_UART_TS_FRCPERR BIT(13) +#define IMX_UART_TS_LOOP BIT(12) +#define IMX_UART_TS_DBGEN BIT(11) +#define IMX_UART_TS_LOOPIR BIT(10) +#define IMX_UART_TS_RXDBG BIT(9) +#define IMX_UART_TS_TXEMPTY BIT(6) +#define IMX_UART_TS_RXEMPTY BIT(5) +#define IMX_UART_TS_TXFULL BIT(4) +#define IMX_UART_TS_RXFULL BIT(3) +#define IMX_UART_TS_SOFTRST BIT(0) + +#ifndef __ASSEMBLER__ + +int console_imx_uart_register(uintptr_t baseaddr, + uint32_t clock, + uint32_t baud, + console_t *console); +#endif /*__ASSEMBLER__*/ + +#endif /* IMX_UART_H */ |