diff options
Diffstat (limited to 'ports/risc-v64/gnu/example_build/erbium/uart.c')
| -rw-r--r-- | ports/risc-v64/gnu/example_build/erbium/uart.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/ports/risc-v64/gnu/example_build/erbium/uart.c b/ports/risc-v64/gnu/example_build/erbium/uart.c new file mode 100644 index 00000000..1b8f2dfc --- /dev/null +++ b/ports/risc-v64/gnu/example_build/erbium/uart.c @@ -0,0 +1,109 @@ +/*************************************************************************** + * 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 <stdint.h> + +#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; +} |
