diff --git a/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.cpp b/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.cpp index 64ad9b015..5725b2cae 100644 --- a/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.cpp +++ b/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.cpp @@ -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(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(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; } } diff --git a/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.hpp b/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.hpp index bf11c7109..c85a1dc9d 100644 --- a/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.hpp +++ b/thermosphere/src/drivers/arm/hvisor_drivers_arm_pl011.hpp @@ -51,6 +51,8 @@ namespace ams::hvisor::drivers::arm { u32 icr; u32 dmacr; }; + static_assert(std::is_standard_layout_v); + static_assert(std::is_trivial_v); 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;