thermosphere: refactor pl011 driver a bit more

This commit is contained in:
TuxSH 2020-03-06 18:54:02 +00:00
parent a8f28ab96d
commit cefd66e7af
2 changed files with 53 additions and 52 deletions

View file

@ -32,24 +32,25 @@ namespace ams::hvisor::drivers::arm {
5. Enable the UART. 5. Enable the UART.
*/ */
// First, disable the UART. Flush the receive FIFO, wait for tx to complete, and disable both FIFOs. // First, disable the UART. Flush the receive FIFO, wait for tx to complete, and disable both FIFOs.
m_regs->cr &= ~UARTCR_UARTEN; m_regs->cr &= ~CR_UARTEN;
while (!(m_regs->fr & UARTFR_RXFE)) { while (!(m_regs->fr & FR_RXFE)) {
m_regs->dr; m_regs->dr;
} }
while (m_regs->fr & UARTFR_BUSY); while (m_regs->fr & FR_BUSY);
// This flushes the transmit FIFO: // This flushes the transmit FIFO:
m_regs->lcr_h &= ~UARTLCR_H_FEN; m_regs->lcr_h &= ~LCR_H_FEN;
// Set baudrate, Divisor = (Uart clock * 4) / baudrate; stored in IBRD|FBRD // Divisor = clkRate / (16 * baudRate). Integer part (16 bits) in IBRD, 6 fractional bits in FBRD (fixed point)
u32 divisor = (4 * clkRate) / baudRate; // This means the encoded divisor is 2^6 * divisor = 4*clkRate / baudRate
m_regs->ibrd = divisor >> 6; u32 rawDivisor = (4 * clkRate) / baudRate;
m_regs->fbrd = divisor & 0x3F; m_regs->ibrd = (rawDivisor >> 6) & 0xFFFF;
m_regs->fbrd = rawDivisor & 0x3F;
// Select FIFO fill levels for interrupts // Select FIFO fill levels for interrupts
m_regs->ifls = IFLS_RX4_8 | IFLS_TX4_8; m_regs->ifls = IFLS_RX4_8 | IFLS_TX4_8;
// FIFO Enabled / No Parity / 8 Data bit / One Stop Bit // FIFO Enabled / No Parity / 8 Data bit / One Stop Bit
m_regs->lcr_h = UARTLCR_H_FEN | UARTLCR_H_WLEN_8; m_regs->lcr_h = LCR_H_FEN | LCR_H_WLEN_8;
// Select the interrupts we want to have // Select the interrupts we want to have
// RX timeout and TX/RX fill interrupts // RX timeout and TX/RX fill interrupts
@ -59,17 +60,17 @@ namespace ams::hvisor::drivers::arm {
m_regs->ecr = 0; m_regs->ecr = 0;
// Clear all interrupts // Clear all interrupts
m_regs->icr = ALL_INTERRUPTS; m_regs->icr = ALL_INTERRUPTS_MASK;
// Enable tx, rx, and uart overall // Enable tx, rx, and uart overall
m_regs->cr = UARTCR_RXE | UARTCR_TXE | UARTCR_UARTEN; m_regs->cr = CR_RXE | CR_TXE | CR_UARTEN;
} }
void PL011::WriteData(const void *buffer, size_t size) const void PL011::WriteData(const void *buffer, size_t size) const
{ {
const u8 *buf8 = reinterpret_cast<const u8 *>(buffer); const u8 *buf8 = reinterpret_cast<const u8 *>(buffer);
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
while (m_regs->fr & UARTFR_TXFF); // while TX FIFO full while (m_regs->fr & FR_TXFF); // while TX FIFO full
m_regs->dr = buf8[i]; m_regs->dr = buf8[i];
} }
@ -81,7 +82,7 @@ namespace ams::hvisor::drivers::arm {
size_t i; size_t i;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
while (m_regs->fr & UARTFR_RXFE); while (m_regs->fr & FR_RXFE);
buf8[i] = m_regs->dr; buf8[i] = m_regs->dr;
} }
@ -92,7 +93,7 @@ namespace ams::hvisor::drivers::arm {
u8 *buf8 = reinterpret_cast<u8 *>(buffer); u8 *buf8 = reinterpret_cast<u8 *>(buffer);
size_t count = 0; size_t count = 0;
for (size_t i = 0; i < maxSize && !(m_regs->fr & UARTFR_RXFE); i++) { for (size_t i = 0; i < maxSize && !(m_regs->fr & FR_RXFE); i++) {
buf8[i] = m_regs->dr; buf8[i] = m_regs->dr;
++count; ++count;
} }
@ -106,7 +107,7 @@ namespace ams::hvisor::drivers::arm {
size_t count = 0; size_t count = 0;
for (size_t i = 0; i < maxSize; i++) { for (size_t i = 0; i < maxSize; i++) {
while (m_regs->fr & UARTFR_RXFE); while (m_regs->fr & FR_RXFE);
buffer[i] = m_regs->dr; buffer[i] = m_regs->dr;
++count; ++count;
if (buffer[i] == delimiter) { if (buffer[i] == delimiter) {
@ -121,11 +122,8 @@ namespace ams::hvisor::drivers::arm {
{ {
constexpr u32 mask = RTI | RXI; constexpr u32 mask = RTI | RXI;
if (enabled) { // We don't support any other interrupt here.
m_regs->imsc |= mask; m_regs->imsc = enabled ? mask : 0;
} else {
m_regs->imsc &= ~mask;
}
} }
} }

View file

@ -51,6 +51,8 @@ namespace ams::hvisor::drivers::arm {
u32 icr; u32 icr;
u32 dmacr; u32 dmacr;
}; };
static_assert(std::is_standard_layout_v<Registers>);
static_assert(std::is_trivial_v<Registers>);
enum Mask : u32 { enum Mask : u32 {
DATA_ERROR_MASK = 0x0F00, // Data status bits DATA_ERROR_MASK = 0x0F00, // Data status bits
@ -76,46 +78,46 @@ namespace ams::hvisor::drivers::arm {
DCDMI = BIT(2), // DCD modem interrupt DCDMI = BIT(2), // DCD modem interrupt
CTSMI = BIT(1), // CTS modem interrupt CTSMI = BIT(1), // CTS modem interrupt
RIMI = BIT(0), // RI modem interrupt RIMI = BIT(0), // RI modem interrupt
ALL_INTERRUPTS = MASK(11), ALL_INTERRUPTS_MASK = MASK(11),
}; };
// Flag reg bits // Flag reg bits
enum FrFlags : u32 { enum FrFlags : u32 {
UARTFR_RI = BIT(8), // Ring indicator FR_RI = BIT(8), // Ring indicator
UARTFR_TXFE = BIT(7), // Transmit FIFO empty FR_TXFE = BIT(7), // Transmit FIFO empty
UARTFR_RXFF = BIT(6), // Receive FIFO full FR_RXFF = BIT(6), // Receive FIFO full
UARTFR_TXFF = BIT(5), // Transmit FIFO full FR_TXFF = BIT(5), // Transmit FIFO full
UARTFR_RXFE = BIT(4), // Receive FIFO empty FR_RXFE = BIT(4), // Receive FIFO empty
UARTFR_BUSY = BIT(3), // UART busy FR_BUSY = BIT(3), // UART busy
UARTFR_DCD = BIT(2), // Data carrier detect FR_DCD = BIT(2), // Data carrier detect
UARTFR_DSR = BIT(1), // Data set ready FR_DSR = BIT(1), // Data set ready
UARTFR_CTS = BIT(0), // Clear to send FR_CTS = BIT(0), // Clear to send
}; };
// Control reg bits // Control reg bits
enum CrFlags : u32 { enum CrFlags : u32 {
UARTCR_CTSEN = BIT(15), // CTS hardware flow control enable CR_CTSEN = BIT(15), // CTS hardware flow control enable
UARTCR_RTSEN = BIT(14), // RTS hardware flow control enable CR_RTSEN = BIT(14), // RTS hardware flow control enable
UARTCR_RTS = BIT(11), // Request to send CR_RTS = BIT(11), // Request to send
UARTCR_DTR = BIT(10), // Data transmit ready. CR_DTR = BIT(10), // Data transmit ready.
UARTCR_RXE = BIT(9), // Receive enable CR_RXE = BIT(9), // Receive enable
UARTCR_TXE = BIT(8), // Transmit enable CR_TXE = BIT(8), // Transmit enable
UARTCR_LBE = BIT(7), // Loopback enable CR_LBE = BIT(7), // Loopback enable
UARTCR_UARTEN = BIT(0), // UART Enable CR_UARTEN = BIT(0), // UART Enable
}; };
// Line Control Register Bits // Line Control Register Bits
enum LcrFlags : u32 { enum LcrFlags : u32 {
UARTLCR_H_SPS = BIT(7), // Stick parity select LCR_H_SPS = BIT(7), // Stick parity select
UARTLCR_H_WLEN_8 = (3 << 5), LCR_H_WLEN_8 = (3 << 5),
UARTLCR_H_WLEN_7 = (2 << 5), LCR_H_WLEN_7 = (2 << 5),
UARTLCR_H_WLEN_6 = BIT(5), LCR_H_WLEN_6 = BIT(5),
UARTLCR_H_WLEN_5 = (0 << 5), LCR_H_WLEN_5 = (0 << 5),
UARTLCR_H_FEN = BIT(4), // FIFOs Enable LCR_H_FEN = BIT(4), // FIFOs Enable
UARTLCR_H_STP2 = BIT(3), // Two stop bits select LCR_H_STP2 = BIT(3), // Two stop bits select
UARTLCR_H_EPS = BIT(2), // Even parity select LCR_H_EPS = BIT(2), // Even parity select
UARTLCR_H_PEN = BIT(1), // Parity Enable LCR_H_PEN = BIT(1), // Parity Enable
UARTLCR_H_BRK = BIT(0), // Send break LCR_H_BRK = BIT(0), // Send break
}; };
// FIFO level select register // FIFO level select register
@ -133,12 +135,13 @@ namespace ams::hvisor::drivers::arm {
}; };
private: private:
volatile Registers *m_regs = nullptr;
void Initialize(u32 baudRate, u32 clkRate = 1) const;
// TODO friend // TODO friend
public: volatile Registers *m_regs = nullptr;
private:
void Initialize(u32 baudRate, u32 clkRate) const;
public:
void WriteData(const void *buffer, size_t size) const; void WriteData(const void *buffer, size_t size) const;
void ReadData(void *buffer, size_t size) const; void ReadData(void *buffer, size_t size) const;
size_t ReadDataMax(void *buffer, size_t maxSize) const; size_t ReadDataMax(void *buffer, size_t maxSize) const;