mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
thermosphere: refactor pl011 driver a bit more
This commit is contained in:
parent
a8f28ab96d
commit
cefd66e7af
2 changed files with 53 additions and 52 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue