mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-03 11:11: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.
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue