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
10 #include "microwatt_soc.h"
13 #define UART_BAUDS 115200
16 * Core UART functions to implement for a port
21 static uint64_t uart_base
;
23 static unsigned long uart_divisor(unsigned long uart_freq
, unsigned long bauds
)
25 return uart_freq
/ (bauds
* 16);
28 static uint64_t potato_uart_reg_read(int offset
)
30 return readq(uart_base
+ offset
);
33 static void potato_uart_reg_write(int offset
, uint64_t val
)
35 writeq(val
, uart_base
+ offset
);
38 static int potato_uart_rx_empty(void)
42 val
= potato_uart_reg_read(POTATO_CONSOLE_STATUS
);
44 if (val
& POTATO_CONSOLE_STATUS_RX_EMPTY
)
50 static int potato_uart_tx_full(void)
54 val
= potato_uart_reg_read(POTATO_CONSOLE_STATUS
);
56 if (val
& POTATO_CONSOLE_STATUS_TX_FULL
)
62 static char potato_uart_read(void)
66 val
= potato_uart_reg_read(POTATO_CONSOLE_RX
);
68 return (char)(val
& 0x000000ff);
71 static void potato_uart_write(char c
)
77 potato_uart_reg_write(POTATO_CONSOLE_TX
, val
);
80 static void potato_uart_init(uint64_t uart_freq
)
82 unsigned long div
= uart_divisor(uart_freq
, UART_BAUDS
) - 1;
83 potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV
, div
);
86 static void potato_uart_set_irq_en(bool rx_irq
, bool tx_irq
)
91 en
|= POTATO_CONSOLE_IRQ_RX
;
93 en
|= POTATO_CONSOLE_IRQ_TX
;
94 potato_uart_reg_write(POTATO_CONSOLE_IRQ_EN
, en
);
97 static bool std_uart_rx_empty(void)
99 return !(readb(uart_base
+ UART_REG_LSR
) & UART_REG_LSR_DR
);
102 static uint8_t std_uart_read(void)
104 return readb(uart_base
+ UART_REG_RX
);
107 static bool std_uart_tx_full(void)
109 return !(readb(uart_base
+ UART_REG_LSR
) & UART_REG_LSR_THRE
);
112 static void std_uart_write(uint8_t c
)
114 writeb(c
, uart_base
+ UART_REG_TX
);
117 static void std_uart_set_irq_en(bool rx_irq
, bool tx_irq
)
122 ier
|= UART_REG_IER_THRI
;
124 ier
|= UART_REG_IER_RDI
;
125 writeb(ier
, uart_base
+ UART_REG_IER
);
128 static void std_uart_init(uint64_t uart_freq
)
130 unsigned long div
= uart_divisor(uart_freq
, UART_BAUDS
);
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
);
146 while (std_uart_rx_empty())
148 return std_uart_read();
150 while (potato_uart_rx_empty())
152 return potato_uart_read();
158 // return c; // comment this in for icarus simulations (too slow otherwise)
160 while(std_uart_tx_full())
164 while (potato_uart_tx_full())
166 potato_uart_write(c
);
171 int puts(const char *str
)
175 for (i
= 0; *str
; i
++) {
185 size_t strlen(const char *s
)
196 void console_init(void)
200 uint64_t uart_info
= 0;
201 uint64_t uart_freq
= 0;
203 proc_freq
= readq(SYSCON_BASE
+ SYS_REG_CLKINFO
) & SYS_REG_CLKINFO_FREQ_MASK
;
204 sys_info
= readq(SYSCON_BASE
+ SYS_REG_INFO
);
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;
211 uart_freq
= proc_freq
;
213 uart_base
= UART_BASE
;
214 if (uart_info
& SYS_REG_UART_IS_16550
) {
216 std_uart_init(proc_freq
);
219 potato_uart_init(proc_freq
);
223 void console_set_irq_en(bool rx_irq
, bool tx_irq
)
226 std_uart_set_irq_en(rx_irq
, tx_irq
);
228 potato_uart_set_irq_en(rx_irq
, tx_irq
);