blob: 1b8f2dfc7cabb2987823c85b1579f317cde396ad (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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;
}
|