/*************************************************************************** * Copyright (c) 2026 Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5.5). * The AI-generated portions may be considered public domain (CC0-1.0) * and not subject to the project's licence. The human contributor has * reviewed and verified that the code is correct. * * SPDX-License-Identifier: MIT and CC0-1.0 **************************************************************************/ /* Polling console driver for the Erbium UART (original Shakti integration). * * Offset Name Access Description * ────── ──────────── ────── ───────────────────────────────────── * 0x00 BaudReg R/W Divisor: clock / (16 * baud) * 0x08 TxReg W Transmit data * 0x10 RxReg R Receive data * 0x18 StatusReg R FIFO and error status * 0x20 DelayReg R/W Transmit delay * 0x28 ControlReg R/W Character size, parity, stop bits * 0x30 InterruptEn R/W Interrupt enables * 0x40 Rx_Threshold R/W Receive FIFO threshold * * All registers are accessed as 32-bit words. The transmit and receive * FIFOs hold 16 entries each. */ #include "uart.h" #include "csr.h" #include #define UART_DIVISOR (ERBIUM_UART_CLOCK_HZ / (16UL * ERBIUM_UART_BAUD)) #if (UART_DIVISOR == 0) || (UART_DIVISOR > 0xFFFF) #error "The Erbium UART baud divisor must be in the range 1..65535." #endif /* SystemConfig in the system register block gates the UART. */ #define SYSREG_SYSTEM_CONFIG 0x02000008UL #define SYSTEM_CONFIG_UART_EN (1u << 6) #define UART_BAUD 0x00 #define UART_TX 0x08 #define UART_STATUS 0x18 #define UART_DELAY 0x20 #define UART_CONTROL 0x28 #define UART_IEN 0x30 #define UART_RX_THRESHOLD 0x40 #define STATUS_TX_FULL (1u << 1) #define CONTROL_CHARSIZE_SHIFT 5 /* bits 10:5; stop bits and parity 0 */ #define REG32(addr) (*(volatile uint32_t *)(addr)) #define UART_REG(off) REG32(UART0 + (off)) int uart_init(void) { /* Ungate the UART. Read-modify-write keeps the watchdog and the other peripheral enables as the boot flow left them. */ REG32(SYSREG_SYSTEM_CONFIG) = REG32(SYSREG_SYSTEM_CONFIG) | SYSTEM_CONFIG_UART_EN; /* Polling only: no UART interrupts. */ UART_REG(UART_IEN) = 0; /* 8 data bits, no parity, one stop bit. */ UART_REG(UART_BAUD) = (uint32_t)UART_DIVISOR; UART_REG(UART_CONTROL) = 8u << CONTROL_CHARSIZE_SHIFT; UART_REG(UART_DELAY) = 0; UART_REG(UART_RX_THRESHOLD) = 0; puts("[UART0] : Erbium UART initialized"); return 0; } int uart_putc(int ch) { int intr_enable; for (;;) { while ((UART_REG(UART_STATUS) & STATUS_TX_FULL) != 0u) ; intr_enable = riscv_mintr_save(); if ((UART_REG(UART_STATUS) & STATUS_TX_FULL) == 0u) { UART_REG(UART_TX) = (uint32_t)(ch & 0xFF); riscv_mintr_restore(intr_enable); return 1; } riscv_mintr_restore(intr_enable); } } int uart_puts(const char *str) { int i; for (i = 0; str[i] != 0; i++) uart_putc(str[i]); uart_putc('\r'); uart_putc('\n'); return i; }