2018-09-07 16:00:13 +01:00
/*
* Copyright ( c ) 2018 naehrwert
* Copyright ( c ) 2018 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 < http : //www.gnu.org/licenses/>.
*/
2018-02-22 19:27:01 +00:00
# ifndef EXOSPHERE_UART_H
# define EXOSPHERE_UART_H
# include <stdint.h>
2018-02-24 16:13:42 +00:00
# include "memory_map.h"
2018-02-22 19:27:01 +00:00
/* Exosphere driver for the Tegra X1 UARTs. */
2018-03-08 00:02:45 +00:00
static inline uintptr_t get_uart_base ( void ) {
return MMIO_GET_DEVICE_ADDRESS ( MMIO_DEVID_UART ) ;
2018-02-26 21:09:35 +00:00
}
2018-03-08 00:02:45 +00:00
# define UART_BASE (get_uart_base())
2018-04-27 22:57:20 +01:00
# define BAUD_115200 115200
2018-03-08 00:02:45 +00:00
/* 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 ;
2018-04-27 23:58:42 +01:00
/* 36.3.12 UART_VENDOR_STATUS_0_0 */
2018-04-27 22:57:20 +01:00
typedef enum {
2018-04-28 00:27:16 +01:00
UART_VENDOR_STATE_TX_IDLE = 1 < < 0 ,
2018-05-01 17:33:39 +01:00
UART_VENDOR_STATE_RX_IDLE = 1 < < 1 ,
2018-04-27 22:57:20 +01:00
/* 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
2018-04-27 23:54:43 +01:00
1 = UNDERRUN
*/
2018-05-01 17:33:39 +01:00
UART_VENDOR_STATE_RX_UNDERRUN = 1 < < 2 ,
2018-04-27 22:57:20 +01:00
/* 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
2018-04-27 23:54:43 +01:00
1 = OVERRUN
*/
2018-05-01 17:33:39 +01:00
UART_VENDOR_STATE_TX_OVERRUN = 1 < < 3 ,
2018-04-27 22:57:20 +01:00
2018-05-01 17:33:39 +01:00
UART_VENDOR_STATE_RX_FIFO_COUNTER = 0 b111111 < < 16 , /* reflects number of current entries in RX FIFO */
UART_VENDOR_STATE_TX_FIFO_COUNTER = 0 b111111 < < 24 /* reflects number of current entries in TX FIFO */
2018-04-27 22:57:20 +01:00
} UartVendorStatus ;
2018-04-27 23:58:42 +01:00
/* 36.3.6 UART_LSR_0 */
2018-04-27 22:57:20 +01:00
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 ;
2018-04-27 23:58:42 +01:00
/* 36.3.4 UART_LCR_0 */
2018-04-27 22:57:20 +01:00
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 */
2018-03-08 00:02:45 +00:00
2018-04-27 22:57:20 +01:00
/* STOP:
0 = Transmit 1 stop bit
2018-04-27 23:54:43 +01:00
1 = Transmit 2 stop bits ( receiver always checks for 1 stop bit )
*/
2018-04-27 22:57:20 +01:00
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 ;
2018-03-08 00:02:45 +00:00
2018-04-27 23:58:42 +01:00
/* 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 ;
2018-03-08 00:02:45 +00:00
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 ) ;
2018-04-27 22:57:20 +01:00
void uart_wait_idle ( UartDevice dev , UartVendorStatus status ) ;
2018-03-08 00:02:45 +00:00
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 ] ) ;
}
2018-02-22 19:27:01 +00:00
2018-02-24 16:13:42 +00:00
# endif