| 1 |
/* uart.c — PL011 UART driver for QEMU virt / Pi 5 */ |
| 2 |
#include "uart.h" |
| 3 |
|
| 4 |
/* PL011 register offsets */ |
| 5 |
#define UART_DR 0x00 |
| 6 |
#define UART_FR 0x18 |
| 7 |
#define UART_IBRD 0x24 |
| 8 |
#define UART_FBRD 0x28 |
| 9 |
#define UART_LCRH 0x2C |
| 10 |
#define UART_CR 0x30 |
| 11 |
#define UART_IMSC 0x38 |
| 12 |
#define UART_ICR 0x44 |
| 13 |
|
| 14 |
static inline void mmio_write(unsigned long off, unsigned int val) { |
| 15 |
*(volatile unsigned int *)(UART0_BASE + off) = val; |
| 16 |
} |
| 17 |
static inline unsigned int mmio_read(unsigned long off) { |
| 18 |
return *(volatile unsigned int *)(UART0_BASE + off); |
| 19 |
} |
| 20 |
|
| 21 |
void uart_init(void) { |
| 22 |
/* Disable UART */ |
| 23 |
mmio_write(UART_CR, 0); |
| 24 |
/* Wait for TX to finish */ |
| 25 |
while (mmio_read(UART_FR) & (1 << 3)) {} |
| 26 |
/* Clear interrupts */ |
| 27 |
mmio_write(UART_ICR, 0x7FF); |
| 28 |
/* Baud rate: 115200 (IBRD=26, FBRD=3 for 48MHz clock) */ |
| 29 |
mmio_write(UART_IBRD, 26); |
| 30 |
mmio_write(UART_FBRD, 3); |
| 31 |
/* 8-bit word, FIFO enabled */ |
| 32 |
mmio_write(UART_LCRH, (3 << 5) | (1 << 4)); |
| 33 |
/* Mask all interrupts */ |
| 34 |
mmio_write(UART_IMSC, 0); |
| 35 |
/* Enable UART, TX, RX */ |
| 36 |
mmio_write(UART_CR, (1 << 0) | (1 << 8) | (1 << 9)); |
| 37 |
} |
| 38 |
|
| 39 |
void uart_putc(char c) { |
| 40 |
while (mmio_read(UART_FR) & (1 << 5)) {} |
| 41 |
mmio_write(UART_DR, (unsigned int)c); |
| 42 |
} |
| 43 |
|
| 44 |
void uart_puts(const char *s) { |
| 45 |
while (*s) uart_putc(*s++); |
| 46 |
} |
| 47 |
|
| 48 |
int uart_getc(void) { |
| 49 |
if (mmio_read(UART_FR) & (1 << 4)) return -1; |
| 50 |
return (int)(mmio_read(UART_DR) & 0xFF); |
| 51 |
} |
| 52 |
|
| 53 |
int uart_poll(void) { |
| 54 |
return !(mmio_read(UART_FR) & (1 << 4)); |
| 55 |
} |
| 56 |
|