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.
*/
// First, disable the UART. Flush the receive FIFO, wait for tx to complete, and disable both FIFOs.
m_regs->cr &= ~UARTCR_UARTEN;
while (!(m_regs->fr & UARTFR_RXFE)) {
m_regs->cr &= ~CR_UARTEN;
while (!(m_regs->fr & FR_RXFE)) {
m_regs->dr;
}
while (m_regs->fr & UARTFR_BUSY);
while (m_regs->fr & FR_BUSY);
// 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
u32 divisor = (4 * clkRate) / baudRate;
m_regs->ibrd = divisor >> 6;
m_regs->fbrd = divisor & 0x3F;
// Divisor = clkRate / (16 * baudRate). Integer part (16 bits) in IBRD, 6 fractional bits in FBRD (fixed point)
// This means the encoded divisor is 2^6 * divisor = 4*clkRate / baudRate
u32 rawDivisor = (4 * clkRate) / baudRate;
m_regs->ibrd = (rawDivisor >> 6) & 0xFFFF;
m_regs->fbrd = rawDivisor & 0x3F;
// Select FIFO fill levels for interrupts
m_regs->ifls = IFLS_RX4_8 | IFLS_TX4_8;
// 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
// RX timeout and TX/RX fill interrupts
@ -59,17 +60,17 @@ namespace ams::hvisor::drivers::arm {
m_regs->ecr = 0;
// Clear all interrupts
m_regs->icr = ALL_INTERRUPTS;
m_regs->icr = ALL_INTERRUPTS_MASK;
// 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
{
const u8 *buf8 = reinterpret_cast<const u8 *>(buffer);
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];
}
@ -81,7 +82,7 @@ namespace ams::hvisor::drivers::arm {
size_t i;
for (i = 0; i < size; i++) {
while (m_regs->fr & UARTFR_RXFE);
while (m_regs->fr & FR_RXFE);
buf8[i] = m_regs->dr;
}
@ -92,7 +93,7 @@ namespace ams::hvisor::drivers::arm {
u8 *buf8 = reinterpret_cast<u8 *>(buffer);
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;
++count;
}
@ -106,7 +107,7 @@ namespace ams::hvisor::drivers::arm {
size_t count = 0;
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;
++count;
if (buffer[i] == delimiter) {
@ -121,11 +122,8 @@ namespace ams::hvisor::drivers::arm {
{
constexpr u32 mask = RTI | RXI;
if (enabled) {
m_regs->imsc |= mask;
} else {
m_regs->imsc &= ~mask;
}
// We don't support any other interrupt here.
m_regs->imsc = enabled ? mask : 0;
}
}

View file

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