#include #include #include #include #include #include #include #include #define DEFAULT_BAUDRATE 115200 #define SERIAL_BUF_SIZE 0x1000 #define SERIAL_BUF_MASK (SERIAL_BUF_SIZE - 1) /* NOTE(dinosaure): [serial.c] is usable only **after** the initialization of * the .bss section: * memset (&__bss_start, 0, (uintptr_t) _end - (uintptr_t) __bss_start); * * TODO(dinosaure): we should probably initialize .bss in [startup.S] */ static bool initialized = false; static uint8_t tx_buf[SERIAL_BUF_SIZE] = {0}; static uint8_t tx_rd = 0; static uint8_t tx_wr = 0; // static uint32_t spinlock = 0; static void flush_tx_buf(void) { assert(initialized); while (tx_rd != tx_wr) { if (!(read32(ARM_UART0_FR) & 0x20)) { write32(ARM_UART0_DR, tx_buf[tx_rd++]); tx_rd &= SERIAL_BUF_MASK; } } } void gilbraltar_serial_init(void) { if (initialized) return; uint32_t baudrate = DEFAULT_BAUDRATE; uint32_t clock_rate = gilbraltar_get_rate_of_clock(2); // UART clock uint32_t baud16 = baudrate * 16; uint32_t int_div = clock_rate / baud16; uint32_t fract_div_2 = (clock_rate % baud16) * 8 / baudrate; uint32_t fract_div = fract_div_2 / 2 + fract_div_2 % 2; write32(ARM_UART0_IMSC, 0); write32(ARM_UART0_ICR, 0x7ff); write32(ARM_UART0_IBRD, int_div); write32(ARM_UART0_FBRD, fract_div); write32(ARM_UART0_LCRH, (1 << 4) | (3 << 5)); write32(ARM_UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); initialized = true; flush_tx_buf(); } void gilbraltar_serial_send(uint8_t chr) { if (initialized) { while (1) if (!(read32(ARM_UART0_FR) & 0x20)) break; write32(ARM_UART0_DR, chr); } else { // gilbraltar_spinlock_acquire(IRQ, &spinlock); if (((tx_wr + 1) & SERIAL_BUF_MASK) != tx_rd) { tx_buf[tx_wr++] = chr; tx_wr &= SERIAL_BUF_MASK; } // gilbraltar_spinlock_release(IRQ, &spinlock); } } uint8_t gilbraltar_serial_recv(void) { while (1) if (!(read32(ARM_UART0_FR) & 0x10)) break; return (read32(ARM_UART0_DR) & 0xff); } void gilbraltar_serial_puts(const char *str) { while (*str) gilbraltar_serial_send(*str++); } void gilbraltar_serial_putchar(int chr) { gilbraltar_serial_send(chr & 0xff); } void gilbraltar_serial_write(const char *str, size_t len) { while (len--) gilbraltar_serial_send(*str++); }