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