/* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2019 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EXOSPHERE_UART_H #define EXOSPHERE_UART_H #include #include "memory_map.h" /* Exosphere driver for the Tegra X1 UARTs. */ static inline uintptr_t get_uart_base(void) { return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_UART); } #define UART_BASE (get_uart_base()) #define BAUD_115200 115200 /* Exosphère: add the clkreset values for UART C,D,E */ typedef enum { UART_A = 0, UART_B = 1, UART_C = 2, UART_D = 3, UART_E = 4, } UartDevice; /* 36.3.12 UART_VENDOR_STATUS_0_0 */ typedef enum { UART_VENDOR_STATE_TX_IDLE = 1 << 0, UART_VENDOR_STATE_RX_IDLE = 1 << 1, /* This bit is set to 1 when a read is issued to an empty FIFO and gets cleared on register read (sticky bit until read) 0 = NO_UNDERRUN 1 = UNDERRUN */ UART_VENDOR_STATE_RX_UNDERRUN = 1 << 2, /* This bit is set to 1 when write data is issued to the TX FIFO when it is already full and gets cleared on register read (sticky bit until read) 0 = NO_OVERRUN 1 = OVERRUN */ UART_VENDOR_STATE_TX_OVERRUN = 1 << 3, UART_VENDOR_STATE_RX_FIFO_COUNTER = 0b111111 << 16, /* reflects number of current entries in RX FIFO */ UART_VENDOR_STATE_TX_FIFO_COUNTER = 0b111111 << 24 /* reflects number of current entries in TX FIFO */ } UartVendorStatus; /* 36.3.6 UART_LSR_0 */ typedef enum { UART_LSR_RDR = 1 << 0, /* Receiver Data Ready */ UART_LSR_OVRF = 1 << 1, /* Receiver Overrun Error */ UART_LSR_PERR = 1 << 2, /* Parity Error */ UART_LSR_FERR = 1 << 3, /* Framing Error */ UART_LSR_BRK = 1 << 4, /* BREAK condition detected on line */ UART_LSR_THRE = 1 << 5, /* Transmit Holding Register is Empty -- OK to write data */ UART_LSR_TMTY = 1 << 6, /* Transmit Shift Register empty status */ UART_LSR_FIFOE = 1 << 7, /* Receive FIFO Error */ UART_LSR_TX_FIFO_FULL = 1 << 8, /* Transmitter FIFO full status */ UART_LSR_RX_FIFO_EMPTY = 1 << 9, /* Receiver FIFO empty status */ } UartLineStatus; /* 36.3.4 UART_LCR_0 */ typedef enum { UART_LCR_WD_LENGTH_5 = 0, /* word length 5 */ UART_LCR_WD_LENGTH_6 = 1, /* word length 6 */ UART_LCR_WD_LENGTH_7 = 2, /* word length 7 */ UART_LCR_WD_LENGTH_8 = 3, /* word length 8 */ /* STOP: 0 = Transmit 1 stop bit 1 = Transmit 2 stop bits (receiver always checks for 1 stop bit) */ UART_LCR_STOP = 1 << 2, UART_LCR_PAR = 1 << 3, /* Parity enabled */ UART_LCR_EVEN = 1 << 4, /* Even parity format. There will always be an even number of 1s in the binary representation (PAR = 1) */ UART_LCR_SET_P = 1 << 5, /* Set (force) parity to value in LCR[4] */ UART_LCR_SET_B = 1 << 6, /* Set BREAK condition -- Transmitter sends all zeroes to indicate BREAK */ UART_LCR_DLAB = 1 << 7, /* Divisor Latch Access Bit (set to allow programming of the DLH, DLM Divisors) */ } UartLineControl; /* 36.3.3 UART_IIR_FCR_0 */ typedef enum { UART_FCR_FCR_EN_FIFO = 1 << 0, /* Enable the transmit and receive FIFOs. This bit should be enabled */ UART_FCR_RX_CLR = 1 << 1, /* Clears the contents of the receive FIFO and resets its counter logic to 0 (the receive shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */ UART_FCR_TX_CLR = 1 << 2, /* Clears the contents of the transmit FIFO and resets its counter logic to 0 (the transmit shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */ /* DMA: 0 = DMA_MODE_0 1 = DMA_MODE_1 */ UART_FCR_DMA = 1 << 3, /* TX_TRIG 0 = FIFO_COUNT_GREATER_16 1 = FIFO_COUNT_GREATER_8 2 = FIFO_COUNT_GREATER_4 3 = FIFO_COUNT_GREATER_1 */ UART_FCR_TX_TRIG = 3 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_16 = 0 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_8 = 1 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_4 = 2 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_1 = 3 << 4, /* RX_TRIG 0 = FIFO_COUNT_GREATER_1 1 = FIFO_COUNT_GREATER_4 2 = FIFO_COUNT_GREATER_8 3 = FIFO_COUNT_GREATER_16 */ UART_FCR_RX_TRIG = 3 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_1 = 0 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_4 = 1 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_8 = 2 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_16 = 3 << 6, } UartFifoControl; /* 36.3.3 UART_IIR_FCR_0 */ typedef enum { UART_IIR_IS_STA = 1 << 0, /* Interrupt Pending if ZERO */ UART_IIR_IS_PRI0 = 1 << 1, /* Encoded Interrupt ID Refer to IIR[3:0] table [36.3.3] */ UART_IIR_IS_PRI1 = 1 << 2, /* Encoded Interrupt ID Refer to IIR[3:0] table */ UART_IIR_IS_PRI2 = 1 << 3, /* Encoded Interrupt ID Refer to IIR[3:0] table */ /* FIFO Mode Status 0 = 16450 mode (no FIFO) 1 = 16550 mode (FIFO) */ UART_IIR_EN_FIFO = 3 << 6, UART_IIR_MODE_16450 = 0 << 6, UART_IIR_MODE_16550 = 1 << 6, } UartInterruptIdentification; typedef struct { /* 0x00 */ uint32_t UART_THR_DLAB; /* 0x04 */ uint32_t UART_IER_DLAB; /* 0x08 */ uint32_t UART_IIR_FCR; /* 0x0C */ uint32_t UART_LCR; /* 0x10 */ uint32_t UART_MCR; /* 0x14 */ uint32_t UART_LSR; /* 0x18 */ uint32_t UART_MSR; /* 0x1C */ uint32_t UART_SPR; /* 0x20 */ uint32_t UART_IRDA_CSR; /* 0x24 */ uint32_t UART_RX_FIFO_CFG; /* 0x28 */ uint32_t UART_MIE; /* 0x2C */ uint32_t UART_VENDOR_STATUS; /* 0x30 */ uint8_t _pad_30[0x0C]; /* 0x3C */ uint32_t UART_ASR; } uart_t; void uart_select(UartDevice dev); void uart_init(UartDevice dev, uint32_t baud); void uart_wait_idle(UartDevice dev, UartVendorStatus status); void uart_send(UartDevice dev, const void *buf, size_t len); void uart_recv(UartDevice dev, void *buf, size_t len); static inline volatile uart_t *get_uart_device(UartDevice dev) { static const size_t offsets[] = {0, 0x40, 0x200, 0x300, 0x400}; return (volatile uart_t *)(UART_BASE + offsets[dev]); } #endif