thermosphere: refactor tegra uart code, etc.

This commit is contained in:
TuxSH 2020-01-11 01:36:55 +00:00
parent a552c254e0
commit 26bda4f32d
10 changed files with 261 additions and 149 deletions

View file

@ -129,9 +129,6 @@ void initIrq(void)
configureInterrupt(GIC_IRQID_MAINTENANCE, IRQ_PRIORITY_HOST, true);
for(u32 i=32; i < 256+32; i++) {
configureInterrupt(i, IRQ_PRIORITY_HOST, true);
}
recursiveSpinlockUnlockRestoreIrq(&g_irqManager.lock, flags);
}

View file

@ -45,8 +45,9 @@ void thermosphereMain(ExceptionStackFrame *frame)
initIrq();
if (currentCoreCtx->isBootCore) {
uartInit(DEFAULT_UART, 115200, 0);
uartSetInterruptStatus(DEFAULT_UART, false, false);
uartInit(DEFAULT_UART, BAUD_115200, 0);
uartSetInterruptStatus(DEFAULT_UART, DIRECTION_READ, true);
DEBUG("EL2: core %u reached main first!\n", currentCoreCtx->coreId);
}

View file

@ -21,21 +21,21 @@
// For both guest and host
#define MAX_NUM_REGISTERED_INTERRUPTS 512
#define GIC_IRQID_PMU 23
#define GIC_IRQID_MAINTENANCE 25
#define GIC_IRQID_NS_PHYS_HYP_TIMER 26
#define GIC_IRQID_NS_VIRT_TIMER 27
//#define GIC_IRQID_LEGACY_NFIQ 28 not defined?
#define GIC_IRQID_SEC_PHYS_TIMER 29
#define GIC_IRQID_NS_PHYS_TIMER 30
//#define GIC_IRQID_LEGACY_NIRQ 31 not defined?
#define GIC_IRQID_PMU 23
#define GIC_IRQID_MAINTENANCE 25
#define GIC_IRQID_NS_PHYS_HYP_TIMER 26
#define GIC_IRQID_NS_VIRT_TIMER 27
//#define GIC_IRQID_LEGACY_NFIQ 28 not defined?
#define GIC_IRQID_SEC_PHYS_TIMER 29
#define GIC_IRQID_NS_PHYS_TIMER 30
//#define GIC_IRQID_LEGACY_NIRQ 31 not defined?
#define GIC_IRQID_NS_VIRT_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 28. Unimplemented
#define GIC_IRQID_SEC_PHYS_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 20. Unimplemented
#define GIC_IRQID_SEC_VIRT_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 19. Unimplemented
#define GIC_IRQID_UART 33
#define GIC_IRQID_UART (32 + 1)
static inline void initGicV2Pointers(ArmGicV2 *gic)
{

View file

@ -83,12 +83,11 @@ void uartInit(UartDevice dev, u32 baudRate, u32 flags)
uart->icr = PL011_ALL_INTERRUPTS;
// Register the interrupt ID
//configureInterrupt(uartGetIrqId(dev), IRQ_PRIORITY_HOST, true);
configureInterrupt(uartGetIrqId(dev), IRQ_PRIORITY_HOST, true);
// Enable tx, rx, and uart overall
uart->cr = PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN;
uart->imsc = PL011_RTI | PL011_RXI | PL011_RXI;
//uart->imsc = PL011_RTI | PL011_RXI | PL011_RXI;
}
void uartWriteData(UartDevice dev, const void *buffer, size_t size)
@ -120,24 +119,48 @@ size_t uartReadDataMax(UartDevice dev, void *buffer, size_t maxSize)
volatile PL011UartRegisters *uart = uartGetRegisters(dev);
u8 *buf8 = (u8 *)buffer;
size_t i;
size_t count = 0;
for (i = 0; i < maxSize && !(uart->fr & PL011_UARTFR_RXFE); i++) {
for (size_t i = 0; i < maxSize && !(uart->fr & PL011_UARTFR_RXFE); i++) {
buf8[i] = uart->dr;
++count;
}
return 1 + i;
return count;
}
void uartSetInterruptStatus(UartDevice dev, bool read, bool enable)
ReadWriteDirection uartGetInterruptDirection(UartDevice dev)
{
volatile PL011UartRegisters *uart = uartGetRegisters(dev);
u32 ret = 0;
u32 istatus = uart->mis;
if (istatus & (PL011_RTI | PL011_RXI)) {
ret |= DIRECTION_READ;
}
if (istatus & PL011_TXI) {
ret |= DIRECTION_WRITE;
}
return (ReadWriteDirection)ret;
}
void uartSetInterruptStatus(UartDevice dev, ReadWriteDirection direction, bool enable)
{
volatile PL011UartRegisters *uart = uartGetRegisters(dev);
u32 mask = read ? PL011_RTI | PL011_RXI : PL011_RTI;
u32 mask = 0;
if (direction & DIRECTION_READ) {
mask |= PL011_RTI | PL011_RXI;
}
if (direction & DIRECTION_WRITE) {
mask |= PL011_TXI;
}
if (enable) {
uart->imsc |= mask;
} else {
uart->icr = mask;
uart->imsc &= ~mask;
}
}
}

View file

@ -132,7 +132,8 @@ void uartInit(UartDevice dev, u32 baudRate, u32 flags);
void uartWriteData(UartDevice dev, const void *buffer, size_t size);
void uartReadData(UartDevice dev, void *buffer, size_t size);
size_t uartReadDataMax(UartDevice dev, void *buffer, size_t maxSize);
void uartSetInterruptStatus(UartDevice dev, bool read, bool enable);
ReadWriteDirection uartGetInterruptDirection(UartDevice dev);
void uartSetInterruptStatus(UartDevice dev, ReadWriteDirection direction, bool enable);
static inline u16 uartGetIrqId(UartDevice dev)
{
@ -142,4 +143,4 @@ static inline u16 uartGetIrqId(UartDevice dev)
default:
return GIC_IRQID_SPURIOUS;
}
}
}

View file

@ -33,6 +33,11 @@
#define GIC_IRQID_SEC_PHYS_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 20. Unimplemented
#define GIC_IRQID_SEC_VIRT_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 19. Unimplemented
#define GIC_IRQID_UARTA (32 + 36)
#define GIC_IRQID_UARTB (32 + 37)
#define GIC_IRQID_UARTC (32 + 46)
#define GIC_IRQID_UARTD (32 + 90)
static inline void initGicV2Pointers(ArmGicV2 *gic)
{
gic->gicd = (volatile ArmGicV2Distributor *)0x50041000ull;

View file

@ -20,18 +20,27 @@
#include "pinmux.h"
#include "gpio.h"
#include "car.h"
#include "../../irq.h"
static inline void uart_wait_cycles(uint32_t baud, uint32_t num)
#define UART_BASE 0x70006000
static inline volatile tegra_uart_t *uartGetRegisters(UartDevice dev)
{
static const size_t offsets[] = { 0, 0x40, 0x200, 0x300, 0x400 };
return (volatile tegra_uart_t *)(UART_BASE + offsets[dev]);
}
static inline void uartWaitCycles(u32 baud, u32 num)
{
udelay((num * 1000000 + 16 * baud - 1) / (16 * baud));
}
static inline void uart_wait_syms(uint32_t baud, uint32_t num)
static inline void uartWaitSyms(u32 baud, u32 num)
{
udelay((num * 1000000 + baud - 1) / baud);
}
void uart_config(UartDevice dev) {
static void uartSetPinmuxConfig(UartDevice dev) {
volatile tegra_pinmux_t *pinmux = pinmux_get_regs();
switch (dev) {
@ -60,15 +69,15 @@ void uart_config(UartDevice dev) {
pinmux->uart4_cts = (PINMUX_INPUT | PINMUX_PULL_DOWN);
break;
case UART_E:
/* Unused. */
// Unused.
break;
default: break;
}
}
void uart_reset(UartDevice dev)
static void uartReset(UartDevice dev)
{
CarDevice uartCarDevs[] = { CARDEVICE_UARTA, CARDEVICE_UARTB, CARDEVICE_UARTC, CARDEVICE_UARTD };
static const CarDevice uartCarDevs[] = { CARDEVICE_UARTA, CARDEVICE_UARTB, CARDEVICE_UARTC, CARDEVICE_UARTD };
if (dev == UART_B) {
gpio_configure_mode(TEGRA_GPIO(G, 0), GPIO_MODE_SFIO);
} else {
@ -81,88 +90,143 @@ void uart_reset(UartDevice dev)
gpio_configure_mode(TEGRA_GPIO(D, 1), GPIO_MODE_GPIO);
}
uart_config(dev);
uartSetPinmuxConfig(dev);
clkrst_reboot(uartCarDevs[dev]);
}
void uart_init(UartDevice dev, uint32_t baud, bool inverted) {
volatile tegra_uart_t *uart = uart_get_regs(dev);
/* Wait for idle state. */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE);
// This function blocks until the UART device is in the desired state.
void uartWaitIdle(UartDevice dev, UartVendorStatus status)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
/* Calculate baud rate, round to nearest. */
uint32_t rate = (8 * baud + 408000000) / (16 * baud);
/* Setup UART in FIFO mode. */
uart->UART_IER_DLAB = 0;
uart->UART_MCR = 0;
uart->UART_LCR = (UART_LCR_DLAB | UART_LCR_WD_LENGTH_8); /* Enable DLAB and set word length 8. */
uart->UART_THR_DLAB = (uint8_t)rate; /* Divisor latch LSB. */
uart->UART_IER_DLAB = (uint8_t)(rate >> 8); /* Divisor latch MSB. */
uart->UART_LCR &= ~(UART_LCR_DLAB); /* Disable DLAB. */
uart->UART_SPR; /* Dummy read. */
uart_wait_syms(baud, 3); /* Wait for 3 symbols at the new baudrate. */
/* Enable FIFO with default settings. */
uart->UART_IIR_FCR = UART_FCR_FCR_EN_FIFO;
uart->UART_IRDA_CSR = inverted ? 2 : 0; /* Invert TX if needed */
uart->UART_SPR; /* Dummy read as mandated by TRM. */
uart_wait_cycles(baud, 3); /* Wait for 3 baud cycles, as mandated by TRM (erratum). */
/* Flush FIFO. */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE); /* Make sure there's no data being written in TX FIFO (TRM). */
uart->UART_IIR_FCR |= UART_FCR_RX_CLR | UART_FCR_TX_CLR; /* Clear TX and RX FIFOs. */
uart_wait_cycles(baud, 32); /* Wait for 32 baud cycles (TRM, erratum). */
/* Wait for idle state (TRM). */
uart_wait_idle(dev, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE);
}
/* This function blocks until the UART device is in the desired state. */
void uart_wait_idle(UartDevice dev, UartVendorStatus status) {
volatile tegra_uart_t *uart = uart_get_regs(dev);
if (status & UART_VENDOR_STATE_TX_IDLE) {
while (!(uart->UART_LSR & UART_LSR_TMTY)) {
/* Wait */
}
while (!(uart->lsr & UART_LSR_TMTY));
}
if (status & UART_VENDOR_STATE_RX_IDLE) {
while (uart->UART_LSR & UART_LSR_RDR) {
/* Wait */
}
while (uart->lsr & UART_LSR_RDR);
}
}
void uart_send(UartDevice dev, const void *buf, size_t len) {
volatile tegra_uart_t *uart = uart_get_regs(dev);
void uartInit(UartDevice dev, u32 baud, u32 flags)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
bool inverted = (flags & BIT(0)) != 0;
for (size_t i = 0; i < len; i++) {
while (!(uart->UART_LSR & UART_LSR_THRE)) {
/* Wait until it's possible to send data. */
}
uart->UART_THR_DLAB = *((const uint8_t *)buf + i);
// Set pinmux, gpio, clock
uartReset(dev);
// Wait for idle state.
uartWaitIdle(dev, UART_VENDOR_STATE_TX_IDLE);
// Calculate baud rate, round to nearest.
u32 rate = (8 * baud + 408000000) / (16 * baud);
uart->lcr &= ~UART_LCR_DLAB; // Disable DLAB.
uart->ier = 0; // Disable all interrupts.
uart->mcr = 0;
// Setup UART in FIFO mode
uart->lcr = UART_LCR_DLAB | UART_LCR_WD_LENGTH_8; // Enable DLAB and set word length 8.
uart->dll = (u8)rate; // Divisor latch LSB.
uart->dlh = (u8)(rate >> 8); // Divisor latch MSB.
uart->lcr &= ~UART_LCR_DLAB; // Disable DLAB.
uart->spr; // Dummy read.
uartWaitSyms(baud, 3); // Wait for 3 symbols at the new baudrate.
// Enable FIFO with default settings.
uart->fcr = UART_FCR_FCR_EN_FIFO;
uart->irda_csr = inverted ? UART_IRDA_CSR_INVERT_TXD : 0; // Invert TX if needed
uart->spr; // Dummy read as mandated by TRM.
uartWaitCycles(baud, 3); // Wait for 3 baud cycles, as mandated by TRM (erratum).
// Flush FIFO.
uartWaitIdle(dev, UART_VENDOR_STATE_TX_IDLE); // Make sure there's no data being written in TX FIFO (TRM).
uart->fcr |= UART_FCR_RX_CLR | UART_FCR_TX_CLR; // Clear TX and RX FIFOs.
uartWaitCycles(baud, 32); // Wait for 32 baud cycles (TRM, erratum).
// Wait for idle state (TRM).
uartWaitIdle(dev, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE);
// Set scratch register to 0. We'll use it to backup write-only IER later
uart->spr = 0;
// Register the interrupt ID
configureInterrupt(uartGetIrqId(dev), IRQ_PRIORITY_HOST, true);
}
void uartWriteData(UartDevice dev, const void *buffer, size_t size)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
const u8 *buf8 = (const u8 *)buffer;
for (size_t i = 0; i < size; i++) {
while (!(uart->lsr & UART_LSR_THRE)); // Wait until it's possible to send data.
uart->thr = buf8[i];
}
}
void uart_recv(UartDevice dev, void *buf, size_t len) {
volatile tegra_uart_t *uart = uart_get_regs(dev);
void uartReadData(UartDevice dev, void *buffer, size_t size)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
u8 *buf8 = (u8 *)buffer;
for (size_t i = 0; i < len; i++) {
while (!(uart->UART_LSR & UART_LSR_RDR)) {
/* Wait until it's possible to receive data. */
}
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
for (size_t i = 0; i < size; i++) {
while (!(uart->lsr & UART_LSR_RDR)) // Wait until it's possible to receive data.
buf8[i] = uart->rbr;
}
}
size_t uart_recv_max(UartDevice dev, void *buf, size_t max_len) {
volatile tegra_uart_t *uart = uart_get_regs(dev);
size_t i;
size_t uartReadDataMax(UartDevice dev, void *buffer, size_t maxSize)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
u8 *buf8 = (u8 *)buffer;
size_t count = 0;
for (i = 0; i < max_len && (uart->UART_LSR & UART_LSR_RDR); i++) {
*((uint8_t *)buf + i) = uart->UART_THR_DLAB;
for (size_t i = 0; i < maxSize && (uart->lsr & UART_LSR_RDR); i++) {
buf8[i] = uart->rbr;
++count;
}
return 1 + i;
return count;
}
ReadWriteDirection uartGetInterruptDirection(UartDevice dev)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
u32 ret = 0;
u32 iir = uart->iir & 0xF;
if (iir == 8 || iir == 12) {
// Data ready or data timeout
ret |= DIRECTION_READ;
} else if (iir == 2) {
// TX FIFO empty
ret |= DIRECTION_WRITE;
}
return (ReadWriteDirection)ret;
}
void uartSetInterruptStatus(UartDevice dev, ReadWriteDirection direction, bool enable)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
u32 mask = 0;
if (direction & DIRECTION_READ) {
mask |= UART_IER_IE_RX_TIMEOUT | UART_IER_IE_RHR;
}
if (direction & DIRECTION_WRITE) {
mask |= UART_IER_IE_THR;
}
if (enable) {
uart->spr |= mask;
uart->ier = uart->spr;
} else {
uart->spr &= ~mask;
uart->ier = uart->spr;
}
}

View file

@ -18,18 +18,17 @@
#pragma once
#include "../../utils.h"
#define UART_BASE 0x70006000
#define BAUD_115200 115200
#include "interrupt_config.h"
/* UART devices */
typedef enum {
typedef enum UartDevice {
UART_A = 0,
UART_B = 1,
UART_C = 2,
UART_D = 3,
UART_E = 4,
UART_MAX = UART_E, // Treat UART_E as if it didn't exist
} UartDevice;
/* 36.3.12 UART_VENDOR_STATUS_0_0 */
@ -123,6 +122,17 @@ typedef enum {
UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_16 = 3 << 6,
} UartFifoControl;
/* 36.3.2 UART_IER_DLAB_0_0 */
typedef enum {
UART_IER_IE_RHR = 1 << 0, /* Interrupt enable for Received Data Interrupt */
UART_IER_IE_THR = 1 << 1, /* Interrupt enable for Transmitter Holding Register Empty interrupt */
UART_IER_IE_RXS = 1 << 2, /* Interrupt enable for Receiver Line Status Interrupt */
UART_IER_IE_MSI = 1 << 3, /* Interrupt enable for Modem Status Interrupt */
UART_IER_IE_RX_TIMEOUT = 1 << 4, /* Interrupt enable for RX FIFO timeout */
UART_IER_IE_EORD = 1 << 5, /* Interrupt enable for Interrupt Enable for End of Received Data */
} UartInterruptEnable;
/* 36.3.3 UART_IIR_FCR_0 */
typedef enum {
UART_IIR_IS_STA = 1 << 0, /* Interrupt Pending if ZERO */
@ -139,32 +149,57 @@ typedef enum {
UART_IIR_MODE_16550 = 1 << 6,
} UartInterruptIdentification;
/* 36.3.9 UART_IRDA_CSR_0 */
typedef enum {
UART_IRDA_CSR_INVERT_RXD = 1 << 0,
UART_IRDA_CSR_INVERT_TXD = 1 << 1,
UART_IRDA_CSR_INVERT_CTS = 1 << 2,
UART_IRDA_CSR_INVERT_RTS = 1 << 3,
UART_IRDA_CSR_PWT_A_BAUD_PULSE_3_14 = 0 << 6,
UART_IRDA_CSR_PWT_A_BAUD_PULSE_4_14 = 1 << 6,
UART_IRDA_CSR_SIR_A = 1 << 7,
} UartIrDAPulseCodingCSR;
typedef struct {
uint32_t UART_THR_DLAB;
uint32_t UART_IER_DLAB;
uint32_t UART_IIR_FCR;
uint32_t UART_LCR;
uint32_t UART_MCR;
uint32_t UART_LSR;
uint32_t UART_MSR;
uint32_t UART_SPR;
uint32_t UART_IRDA_CSR;
uint32_t UART_RX_FIFO_CFG;
uint32_t UART_MIE;
uint32_t UART_VENDOR_STATUS;
uint8_t _0x30[0x0C];
uint32_t UART_ASR;
union {
// UART_THR_DLAB_0
u32 thr;
u32 rbr;
u32 dll;
};
union {
// UART_IER_DLAB_0
u32 ier;
u32 dlh;
};
union {
// UART_IIR_FCR_0
u32 iir;
u32 fcr;
};
u32 lcr;
u32 mcr;
u32 lsr;
u32 msr;
u32 spr;
u32 irda_csr;
u32 rx_fifo_cfg;
u32 mie;
u32 vendor_status;
u8 _0x30[0x0C];
u32 asr;
} tegra_uart_t;
void uart_config(UartDevice dev);
void uart_reset(UartDevice dev);
void uart_init(UartDevice dev, uint32_t baud, bool inverted);
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);
size_t uart_recv_max(UartDevice dev, void *buf, size_t max_len);
void uartInit(UartDevice dev, u32 baud, u32 flags);
void uartWriteData(UartDevice dev, const void *buffer, size_t size);
void uartReadData(UartDevice dev, void *buffer, size_t size);
size_t uartReadDataMax(UartDevice dev, void *buffer, size_t maxSize);
ReadWriteDirection uartGetInterruptDirection(UartDevice dev);
void uartSetInterruptStatus(UartDevice dev, ReadWriteDirection direction, bool enable);
static inline volatile tegra_uart_t *uart_get_regs(UartDevice dev) {
static const size_t offsets[] = {0, 0x40, 0x200, 0x300, 0x400};
return (volatile tegra_uart_t *)(UART_BASE + offsets[dev]);
static inline u16 uartGetIrqId(UartDevice dev)
{
static const u16 irqIds[] = { GIC_IRQID_UARTA, GIC_IRQID_UARTB, GIC_IRQID_UARTC, GIC_IRQID_UARTD };
return dev < UART_MAX ? irqIds[dev] : GIC_IRQID_SPURIOUS;
}

View file

@ -16,39 +16,19 @@
#pragma once
#if PLATFORM_TEGRA
// TODO
#define BAUD_115200 115200
/*#include "tegra/uart.h"
#if PLATFORM_TEGRA
#include "tegra/uart.h"
#define DEFAULT_UART UART_C
#define DEFAULT_UARTINV_STATUS true
static inline void uartInit(u32 baudRate)
{
uart_reset(DEFAULT_UART);
uart_init(DEFAULT_UART, baudRate, DEFAULT_UARTINV_STATUS);
}
static inline void uartWriteData(const void *buffer, size_t size)
{
uart_send(DEFAULT_UART, buffer, size);
}
static inline void uartReadData(void *buffer, size_t size)
{
uart_recv(DEFAULT_UART, buffer, size);
}
static inline size_t uartReadDataMax(void *buffer, size_t maxSize)
{
return uart_recv_max(DEFAULT_UART, buffer, maxSize);
}
*/
#define DEFAULT_UART_FLAGS 1
#elif defined(PLATFORM_QEMU)
#define DEFAULT_UART UART_A
#define DEFAULT_UART_FLAGS 0
#include "qemu/uart.h"
@ -56,4 +36,4 @@ static inline size_t uartReadDataMax(void *buffer, size_t maxSize)
#error "Error: platform not defined"
#endif
#endif

View file

@ -56,6 +56,12 @@ static inline u##sz __##op##sz(u##sz n)\
_DECLARE_ASM_ARITHMETIC_UNARY_HELPER64(rbit)
_DECLARE_ASM_ARITHMETIC_UNARY_HELPER32(rbit)
typedef enum ReadWriteDirection {
DIRECTION_READ = BIT(0),
DIRECTION_WRITE = BIT(1),
DIRECTION_READWRITE = DIRECTION_READ | DIRECTION_WRITE,
} ReadWriteDirection;
static inline void __dmb_sy(void)
{
__asm__ __volatile__ ("dmb sy" ::: "memory");