aboutsummaryrefslogtreecommitdiff
path: root/uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'uart.c')
-rw-r--r--uart.c95
1 files changed, 60 insertions, 35 deletions
diff --git a/uart.c b/uart.c
index 2030538..2d4e176 100644
--- a/uart.c
+++ b/uart.c
@@ -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;
}