phaser-ags / firmware /hal /uart.c
SNAPKITTYWEST's picture
October 2026 main drop: mirror from GitHub
829b19c verified
Raw History Blame Contribute Delete
3.27 kB
/*
* HAL — UART driver for OMAP3530 (NS16550A-compatible)
*/
#include "uart.h"
void uart_init(uart_dev_t *dev, uint32_t base, uint32_t clock_hz) {
dev->base = (hw_reg32_t)base;
dev->clock_hz = clock_hz;
}
void uart_configure(uart_dev_t *dev, uint32_t baud, uint8_t data_bits, uint8_t parity, uint8_t stop_bits) {
hw_reg32_t base = dev->base;
/* Switch to UART mode (disable IrDA / disable modem) */
reg_write32(base + UART_MDR1, 0x07); /* Disable UART */
delay_cycles(100);
/* Reset TX/RX FIFOs and enable FIFO mode */
reg_write32(base + UART_FCR, UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR);
delay_cycles(10);
/* Set DLAB to access divisor registers */
reg32_t lcr = 0;
switch (data_bits) {
case 5: lcr |= 0x00; break;
case 6: lcr |= 0x01; break;
case 7: lcr |= 0x02; break;
case 8:
default: lcr |= 0x03; break;
}
switch (parity) {
case 0: break; /* No parity */
case 1: lcr |= (1 << 3); break; /* Odd parity */
case 2: lcr |= (3 << 3); break; /* Even parity */
}
if (stop_bits == 2)
lcr |= (1 << 2);
/* Set DLAB, write divisor, clear DLAB */
reg_write32(base + UART_LCR, lcr | UART_LCR_DLAB);
uint16_t divisor = (uint16_t)(dev->clock_hz / (16 * baud));
reg_write32(base + UART_DLL, divisor & 0xFF);
reg_write32(base + UART_DLH, (divisor >> 8) & 0xFF);
/* Clear DLAB — restore normal register access */
reg_write32(base + UART_LCR, lcr);
/* No flow control, no interrupts */
reg_write32(base + UART_IER, 0x00);
reg_write32(base + UART_MCR, 0x00);
/* Enable FIFOs with 8-byte trigger */
reg_write32(base + UART_FCR, UART_FCR_FIFO_EN | (0x3 << 6));
/* Re-enable UART in 16x mode */
reg_write32(base + UART_MDR1, 0x00);
}
void uart_putc(uart_dev_t *dev, char c) {
hw_reg32_t base = dev->base;
/* Wait for TX holding register empty */
while (!(reg_read32(base + UART_LSR) & UART_LSR_THRE))
;
reg_write32(base + UART_THR, (reg32_t)c);
}
char uart_getc(uart_dev_t *dev) {
hw_reg32_t base = dev->base;
/* Wait for data ready */
while (!(reg_read32(base + UART_LSR) & UART_LSR_DR))
;
return (char)(reg_read32(base + UART_RBR) & 0xFF);
}
int uart_try_getc(uart_dev_t *dev) {
hw_reg32_t base = dev->base;
if (reg_read32(base + UART_LSR) & UART_LSR_DR)
return (int)(reg_read32(base + UART_RBR) & 0xFF);
return -1;
}
void uart_puts(uart_dev_t *dev, const char *s) {
while (*s) {
if (*s == '\n')
uart_putc(dev, '\r');
uart_putc(dev, *s++);
}
}
void uart_put_hex_byte(uart_dev_t *dev, uint8_t val) {
static const char hex[] = "0123456789ABCDEF";
uart_putc(dev, hex[(val >> 4) & 0xF]);
uart_putc(dev, hex[val & 0xF]);
}
void uart_put_hex(uart_dev_t *dev, uint32_t val) {
uart_puts(dev, "0x");
uart_put_hex_byte(dev, (val >> 24) & 0xFF);
uart_put_hex_byte(dev, (val >> 16) & 0xFF);
uart_put_hex_byte(dev, (val >> 8) & 0xFF);
uart_put_hex_byte(dev, val & 0xFF);
}
void uart_flush(uart_dev_t *dev) {
hw_reg32_t base = dev->base;
while (!(reg_read32(base + UART_LSR) & UART_LSR_TEMT))
;
}