blob: b8f229bed60aeb1205fbee7b125e23a918179f10 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2016 Gurjant Kalsi
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
24// TODO(gkalsi): Unify the two UART codepaths and use the port parameter to
25// select between the real uart and the miniuart.
26
27#include <assert.h>
28#include <kernel/thread.h>
29#include <lib/cbuf.h>
30#include <platform/bcm28xx.h>
31#include <platform/debug.h>
32#include <platform/interrupts.h>
33#include <reg.h>
34#include <stdio.h>
35#include <trace.h>
36
37#define RXBUF_SIZE 16
38
39static cbuf_t uart_rx_buf;
40
41struct bcm283x_mu_regs {
42 uint32_t io;
43 uint32_t ier;
44 uint32_t iir;
45 uint32_t lcr;
46 uint32_t mcr;
47 uint32_t lsr;
48 uint32_t msr;
49 uint32_t scratch;
50 uint32_t cntl;
51 uint32_t stat;
52 uint32_t baud;
53};
54
55struct bcm283x_aux_regs {
56 uint32_t auxirq;
57 uint32_t auxenb;
58};
59
60#define AUX_IRQ_MINIUART (1 << 0)
61#define AUX_ENB_MINIUART (1 << 0)
62
63#define MU_IIR_BYTE_AVAIL (1 << 2) // For reading
64#define MU_IIR_CLR_XMIT_FIFO (1 << 2) // For writing.
65#define MU_IIR_CLR_RECV_FIFO (1 << 1)
66
67#define MU_IIR_EN_RX_IRQ (1 << 0) // Enable the recv interrupt.
68
69#define MU_LSR_TX_EMPTY (1 << 5)
70
71static enum handler_return aux_irq(void *arg)
72{
73 volatile struct bcm283x_mu_regs *mu_regs =
74 (struct bcm283x_mu_regs *)MINIUART_BASE;
75 volatile struct bcm283x_aux_regs *aux_regs =
76 (struct bcm283x_aux_regs *)AUX_BASE;
77
78 // Make sure this interrupt is intended for the miniuart.
79 uint32_t auxirq = readl(&aux_regs->auxirq);
80 if ((auxirq & AUX_IRQ_MINIUART) == 0) {
81 return INT_NO_RESCHEDULE;
82 }
83
84 bool resched = false;
85
86 while (true) {
87 uint32_t iir = readl(&mu_regs->iir);
88 if ((iir & MU_IIR_BYTE_AVAIL) == 0) break;
89
90 resched = true;
91 char ch = readl(&mu_regs->io);
92 cbuf_write_char(&uart_rx_buf, ch, false);
93 }
94
95 return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
96}
97
98int uart_putc(int port, char c)
99{
100 // There's only one UART for now.
101 // TODO(gkalsi): Unify the two UART code paths using the port.
102 struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)MINIUART_BASE;
103
104 /* Wait until there is space in the FIFO */
105 while (!(readl(&regs->lsr) & MU_LSR_TX_EMPTY))
106 ;
107
108 /* Send the character */
109 writel(c, &regs->io);
110
111 return 1;
112}
113
114void uart_init(void)
115{
116 volatile struct bcm283x_mu_regs *mu_regs =
117 (struct bcm283x_mu_regs *)MINIUART_BASE;
118 volatile struct bcm283x_aux_regs *aux_regs =
119 (struct bcm283x_aux_regs *)AUX_BASE;
120
121 // Create circular buffer to hold received data.
122 cbuf_initialize(&uart_rx_buf, RXBUF_SIZE);
123
124 // AUX Interrupt handler handles interrupts for SPI1, SPI2, and miniuart
125 // Interrupt handler must decode IRQ.
126 register_int_handler(INTERRUPT_AUX, &aux_irq, NULL);
127
128 // Enable the Interrupt.
129 unmask_interrupt(INTERRUPT_AUX);
130
131 writel(MU_IIR_CLR_RECV_FIFO | MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir);
132
133 // Enable the miniuart peripheral. This also enables Miniuart register
134 // access. It's likely that the VideoCore chip already enables this
135 // peripheral for us, but we hit the enable bit just to be sure.
136 writel(AUX_ENB_MINIUART, &aux_regs->auxenb);
137
138 // Enable the receive interrupt on the UART peripheral.
139 writel(MU_IIR_EN_RX_IRQ, &mu_regs->ier);
140}
141
142void uart_init_early(void)
143{
144}
145
146int uart_getc(int port, bool wait)
147{
148 cbuf_t *rxbuf = &uart_rx_buf;
149
150 char c;
151 if (cbuf_read_char(rxbuf, &c, wait) == 1)
152 return c;
153
154 return -1;
155}
156
157void uart_flush_tx(int port)
158{
159 volatile struct bcm283x_mu_regs *mu_regs =
160 (struct bcm283x_mu_regs *)MINIUART_BASE;
161 writel(MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir);
162}
163
164void uart_flush_rx(int port)
165{
166 volatile struct bcm283x_mu_regs *mu_regs =
167 (struct bcm283x_mu_regs *)MINIUART_BASE;
168 writel(MU_IIR_CLR_RECV_FIFO, &mu_regs->iir);
169}
170
171void uart_init_port(int port, uint baud)
172{
173}
174
175
176