diff options
Diffstat (limited to 'uart.c')
-rw-r--r-- | uart.c | 95 |
1 files changed, 60 insertions, 35 deletions
@@ -3,18 +3,6 @@ #include <uart.h> #include <global.h> -// Memory-Mapped I/O output -static inline void mmio_write(uint32_t reg, uint32_t data) -{ - *(volatile uint32_t*)reg = data; -} - -// Memory-Mapped I/O input -static inline uint32_t mmio_read(uint32_t reg) -{ - return *(volatile uint32_t*)reg; -} - // Loop <delay> times in a way that the compiler won't optimize away static inline void delay(int32_t count) { @@ -24,23 +12,21 @@ static inline void delay(int32_t count) void uart_init() { - // Disable UART0. - mmio_write(UART0_CR, 0x00000000); + // Disable PL011_UART. + wr32(PL011_UART_CR, 0); + // Setup the GPIO pin 14 && 15. // Disable pull up/down for all GPIO pins & delay for 150 cycles. - mmio_write(GPPUD, 0x00000000); + wr32(GPPUD, 0); delay(150); // Disable pull up/down for pin 14,15 & delay for 150 cycles. - mmio_write(GPPUDCLK0, (1 << 14) | (1 << 15)); + wr32(GPPUDCLK0, (1 << 14) | (1 << 15)); delay(150); // Write 0 to GPPUDCLK0 to make it take effect. - mmio_write(GPPUDCLK0, 0x00000000); - - // Clear pending interrupts. - mmio_write(UART0_ICR, 0x7FF); + wr32(GPPUDCLK0, 0); // Set integer & fractional part of baud rate. // Divider = UART_CLOCK/(16 * Baud) @@ -48,31 +34,70 @@ void uart_init() // UART_CLOCK = 3000000; Baud = 115200. // Divider = 3000000 / (16 * 115200) = 1.627 = ~1. - mmio_write(UART0_IBRD, 1); + wr32(PL011_UART_IBRD, 1); // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. - mmio_write(UART0_FBRD, 40); + wr32(PL011_UART_FBRD, 40); + + // Set 8 bit data transmission (1 stop bit, no parity) + // and disable FIFO to be able to receive interrupt every received + // char, not every 2 chars + wr32(PL011_UART_LCRH, (1 << 5) | (1 << 6)); + + // set interrupt to come when transmit FIFO becomes ≤ 1/8 full + // or receive FIFO becomes ≥ 1/8 full + // (not really matters, since we disabled FIFOs) + wr32(PL011_UART_IFLS, 0); - // Enable FIFO & 8 bit data transmission (1 stop bit, no parity). - mmio_write(UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); + // Enable PL011_UART, receive & transfer part of UART.2 + wr32(PL011_UART_CR, (1 << 0) | (1 << 8) | (1 << 9)); - // Mask all interrupts. - mmio_write(UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | - (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)); + // At first, it's probably safer to disable interrupts :) + uart_irq_disable(); - // Enable UART0, receive & transfer part of UART. - mmio_write(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); + // The above disables the entire uart irq; + // Also disable single sources within it + wr32(PL011_UART_IMSC, 0); +} + +inline static _Bool can_transmit(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 5)); +} + +inline static _Bool can_receive(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 4)); } void putchar(char c) { - // Wait for UART to become ready to transmit. - while ( mmio_read(UART0_FR) & (1 << 5) ) { } - mmio_write(UART0_DR, c); + while (!can_transmit()); + + wr32(PL011_UART_DR, c); } char getchar(void) { - // Wait for UART to have received something. - while ( mmio_read(UART0_FR) & (1 << 4) ) { } - return mmio_read(UART0_DR); + while (!can_receive()); + + return rd32(PL011_UART_DR); +} + +_Bool putchar_non_blocking(char c) +{ + if (can_transmit()) + { + wr32(PL011_UART_DR, c); + return 0; + } + + return 1; +} + +int getchar_non_blocking(void) +{ + if (can_receive()) + return rd32(PL011_UART_DR); + + return -1; } |