get runsimsoc2.sh running again, test asynchronous wb bridge,
[ls2.git] / lib / console.c
1 /* This code is directly from Microwatt and is Copyright and Licensed
2 under the same terms as Microwatt source code.
3 https://github.com/antonblanchard/microwatt/blob/master/lib/console.c
4 */
5
6 #include <stdint.h>
7 #include <stdbool.h>
8
9 #include "console.h"
10 #include "microwatt_soc.h"
11 #include "io.h"
12
13 #define UART_BAUDS 115200
14
15 /*
16 * Core UART functions to implement for a port
17 */
18
19 bool uart_is_std;
20
21 static uint64_t uart_base;
22
23 static unsigned long uart_divisor(unsigned long uart_freq, unsigned long bauds)
24 {
25 return uart_freq / (bauds * 16);
26 }
27
28 static uint64_t potato_uart_reg_read(int offset)
29 {
30 return readq(uart_base + offset);
31 }
32
33 static void potato_uart_reg_write(int offset, uint64_t val)
34 {
35 writeq(val, uart_base + offset);
36 }
37
38 static int potato_uart_rx_empty(void)
39 {
40 uint64_t val;
41
42 val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
43
44 if (val & POTATO_CONSOLE_STATUS_RX_EMPTY)
45 return 1;
46
47 return 0;
48 }
49
50 static int potato_uart_tx_full(void)
51 {
52 uint64_t val;
53
54 val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
55
56 if (val & POTATO_CONSOLE_STATUS_TX_FULL)
57 return 1;
58
59 return 0;
60 }
61
62 static char potato_uart_read(void)
63 {
64 uint64_t val;
65
66 val = potato_uart_reg_read(POTATO_CONSOLE_RX);
67
68 return (char)(val & 0x000000ff);
69 }
70
71 static void potato_uart_write(char c)
72 {
73 uint64_t val;
74
75 val = c;
76
77 potato_uart_reg_write(POTATO_CONSOLE_TX, val);
78 }
79
80 static void potato_uart_init(uint64_t uart_freq)
81 {
82 unsigned long div = uart_divisor(uart_freq, UART_BAUDS) - 1;
83 potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, div);
84 }
85
86 static void potato_uart_set_irq_en(bool rx_irq, bool tx_irq)
87 {
88 uint64_t en = 0;
89
90 if (rx_irq)
91 en |= POTATO_CONSOLE_IRQ_RX;
92 if (tx_irq)
93 en |= POTATO_CONSOLE_IRQ_TX;
94 potato_uart_reg_write(POTATO_CONSOLE_IRQ_EN, en);
95 }
96
97 static bool std_uart_rx_empty(void)
98 {
99 return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_DR);
100 }
101
102 static uint8_t std_uart_read(void)
103 {
104 return readb(uart_base + UART_REG_RX);
105 }
106
107 static bool std_uart_tx_full(void)
108 {
109 return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_THRE);
110 }
111
112 static void std_uart_write(uint8_t c)
113 {
114 writeb(c, uart_base + UART_REG_TX);
115 }
116
117 static void std_uart_set_irq_en(bool rx_irq, bool tx_irq)
118 {
119 uint8_t ier = 0;
120
121 if (tx_irq)
122 ier |= UART_REG_IER_THRI;
123 if (rx_irq)
124 ier |= UART_REG_IER_RDI;
125 writeb(ier, uart_base + UART_REG_IER);
126 }
127
128 static void std_uart_init(uint64_t uart_freq)
129 {
130 unsigned long div = uart_divisor(uart_freq, UART_BAUDS);
131
132 writeb(UART_REG_LCR_DLAB, uart_base + UART_REG_LCR);
133 writeb(div & 0xff, uart_base + UART_REG_DLL);
134 writeb(div >> 8, uart_base + UART_REG_DLM);
135 writeb(UART_REG_LCR_8BIT, uart_base + UART_REG_LCR);
136 writeb(UART_REG_MCR_DTR |
137 UART_REG_MCR_RTS, uart_base + UART_REG_MCR);
138 writeb(UART_REG_FCR_EN_FIFO |
139 UART_REG_FCR_CLR_RCVR |
140 UART_REG_FCR_CLR_XMIT, uart_base + UART_REG_FCR);
141 }
142
143 int getchar(void)
144 {
145 if (uart_is_std) {
146 while (std_uart_rx_empty())
147 /* Do nothing */ ;
148 return std_uart_read();
149 } else {
150 while (potato_uart_rx_empty())
151 /* Do nothing */ ;
152 return potato_uart_read();
153 }
154 }
155
156 int putchar(int c)
157 {
158 // return c; // comment this in for icarus simulations (too slow otherwise)
159 if (uart_is_std) {
160 while(std_uart_tx_full())
161 /* Do Nothing */;
162 std_uart_write(c);
163 } else {
164 while (potato_uart_tx_full())
165 /* Do Nothing */;
166 potato_uart_write(c);
167 }
168 return c;
169 }
170
171 int puts(const char *str)
172 {
173 unsigned int i;
174
175 for (i = 0; *str; i++) {
176 char c = *(str++);
177 if (c == 10)
178 putchar(13);
179 putchar(c);
180 }
181 return 0;
182 }
183
184 #ifndef __USE_LIBC
185 size_t strlen(const char *s)
186 {
187 size_t len = 0;
188
189 while (*s++)
190 len++;
191
192 return len;
193 }
194 #endif
195
196 void console_init(void)
197 {
198 uint64_t sys_info;
199 uint64_t proc_freq;
200 uint64_t uart_info = 0;
201 uint64_t uart_freq = 0;
202
203 proc_freq = readq(SYSCON_BASE + SYS_REG_CLKINFO) & SYS_REG_CLKINFO_FREQ_MASK;
204 sys_info = readq(SYSCON_BASE + SYS_REG_INFO);
205
206 if (sys_info & SYS_REG_INFO_HAS_LARGE_SYSCON) {
207 uart_info = readq(SYSCON_BASE + SYS_REG_UART0_INFO);
208 uart_freq = uart_info & 0xffffffff;
209 }
210 if (uart_freq == 0)
211 uart_freq = proc_freq;
212
213 uart_base = UART_BASE;
214 if (uart_info & SYS_REG_UART_IS_16550) {
215 uart_is_std = true;
216 std_uart_init(proc_freq);
217 } else {
218 uart_is_std = false;
219 potato_uart_init(proc_freq);
220 }
221 }
222
223 void console_set_irq_en(bool rx_irq, bool tx_irq)
224 {
225 if (uart_is_std)
226 std_uart_set_irq_en(rx_irq, tx_irq);
227 else
228 potato_uart_set_irq_en(rx_irq, tx_irq);
229 }