blob: 531c051e9eae1dd87a3eeee28206b564d7251e1f [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2014 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <reg.h>
24#include <stdio.h>
25#include <trace.h>
26#include <assert.h>
27#include <lib/cbuf.h>
28#include <kernel/thread.h>
29#include <platform/interrupts.h>
30#include <platform/debug.h>
31#include <platform/zynq.h>
32
33#define RXBUF_SIZE 16
34
35static cbuf_t uart_rx_buf[NUM_UARTS];
36
37static inline uintptr_t uart_to_ptr(unsigned int n) { return (n == 0) ? UART0_BASE : UART1_BASE; }
38static inline uint uart_to_irq(unsigned int n) { return (n == 0) ? UART0_INT : UART1_INT; }
39
40#define UART_REG(base, reg) (*REG32((base) + (reg)))
41
42static enum handler_return uart_irq(void *arg)
43{
44 bool resched = false;
45 uint port = (uint)arg;
46 uintptr_t base = uart_to_ptr(port);
47
48 /* read interrupt status and mask */
49 uint32_t isr = UART_REG(base, UART_ISR);
50 isr &= UART_REG(base, UART_IMR);
51
52 if (isr & (1<<0)) { // rxtrig
53 UART_REG(base, UART_ISR) = (1<< 0);
54
55 while ((UART_REG(base, UART_SR) & (1<<1)) == 0) { // ~rempty
56 char c = UART_REG(base, UART_FIFO);
57 cbuf_write_char(&uart_rx_buf[port], c, false);
58
59 resched = true;
60 }
61 }
62
63 return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
64}
65
66void uart_init(void)
67{
68 for (uint i = 0; i < NUM_UARTS; i++) {
69 cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE);
70
71 uintptr_t base = uart_to_ptr(i);
72
73 // clear all irqs
74 UART_REG(base, UART_IDR) = 0xffffffff;
75
76 // set rx fifo trigger to 1
77 UART_REG(base, UART_RXWM) = 1;
78
79 // enable the receiver
80 // NOTE: must clear rxdis and set rxen in the same write
81 UART_REG(base, UART_CR) = (UART_REG(base, UART_CR) & ~(1<<3)) | (1 << 2);
82
83 // enable rx interrupt
84 UART_REG(base, UART_IER) = (1<<0); // rxtrig
85
86 // set up interrupt handler
87 register_int_handler(uart_to_irq(i), &uart_irq, (void *)i);
88 unmask_interrupt(uart_to_irq(i));
89 }
90}
91
92void uart_init_early(void)
93{
94 for (uint i = 0; i < NUM_UARTS; i++) {
95 uintptr_t base = uart_to_ptr(i);
96
97 UART_REG(base, UART_BAUD_DIV) = UART_BRD_DIV(6);
98 UART_REG(base, UART_BAUDGEN) = UART_BRG_DIV(0x3E);
99
100 // reset the tx/rx path
101 UART_REG(base, UART_CR) |= UART_CR_TXRES | UART_CR_RXRES;
102 while ((UART_REG(base, UART_CR) & (UART_CR_TXRES | UART_CR_RXRES)) != 0)
103 ;
104
105 // n81, clock select ref_clk
106 UART_REG(base, UART_MR) = UART_MR_PAR(0x4); // no parity
107
108 // no flow
109 UART_REG(base, UART_MODEMCR) = 0;
110
111 UART_REG(base, UART_CR) = UART_CR_TXEN;
112 }
113
114 /* Configuration for the serial console */
115 /*UART_REG(UART1_BASE, UART_CR) = 0x00000017;*/
116 /*UART_REG(UART1_BASE, UART_MR) = 0x00000020;*/
117}
118
119int uart_putc(int port, char c)
120{
121 DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
122
123 uintptr_t base = uart_to_ptr(port);
124
125 /* spin while fifo is full */
126 while (UART_REG(base, UART_SR) & (1<<4))
127 ;
128 UART_REG(base, UART_FIFO) = c;
129
130 return 1;
131}
132
133int uart_getc(int port, bool wait)
134{
135 DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
136
137 char c;
138 if (cbuf_read_char(&uart_rx_buf[port], &c, wait) == 1)
139 return c;
140
141 return -1;
142}
143
144void uart_flush_tx(int port)
145{
146 DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
147}
148
149void uart_flush_rx(int port)
150{
151 DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
152}
153
154void uart_init_port(int port, uint baud)
155{
156 DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
157
158 PANIC_UNIMPLEMENTED;
159}
160