/* uart.c — PL011 UART driver for QEMU virt / Pi 5 */ #include "uart.h" /* PL011 register offsets */ #define UART_DR 0x00 #define UART_FR 0x18 #define UART_IBRD 0x24 #define UART_FBRD 0x28 #define UART_LCRH 0x2C #define UART_CR 0x30 #define UART_IMSC 0x38 #define UART_ICR 0x44 static inline void mmio_write(unsigned long off, unsigned int val) { *(volatile unsigned int *)(UART0_BASE + off) = val; } static inline unsigned int mmio_read(unsigned long off) { return *(volatile unsigned int *)(UART0_BASE + off); } void uart_init(void) { /* Disable UART */ mmio_write(UART_CR, 0); /* Wait for TX to finish */ while (mmio_read(UART_FR) & (1 << 3)) {} /* Clear interrupts */ mmio_write(UART_ICR, 0x7FF); /* Baud rate: 115200 (IBRD=26, FBRD=3 for 48MHz clock) */ mmio_write(UART_IBRD, 26); mmio_write(UART_FBRD, 3); /* 8-bit word, FIFO enabled */ mmio_write(UART_LCRH, (3 << 5) | (1 << 4)); /* Mask all interrupts */ mmio_write(UART_IMSC, 0); /* Enable UART, TX, RX */ mmio_write(UART_CR, (1 << 0) | (1 << 8) | (1 << 9)); } void uart_putc(char c) { while (mmio_read(UART_FR) & (1 << 5)) {} mmio_write(UART_DR, (unsigned int)c); } void uart_puts(const char *s) { while (*s) uart_putc(*s++); } int uart_getc(void) { if (mmio_read(UART_FR) & (1 << 4)) return -1; return (int)(mmio_read(UART_DR) & 0xFF); } int uart_poll(void) { return !(mmio_read(UART_FR) & (1 << 4)); }