blob: 7ef0effb4aac0071011d3546e7805cf695c28fa4 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2015 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 <lib/cbuf.h>
27#include <kernel/thread.h>
28#include <platform/interrupts.h>
29#include <platform/debug.h>
30#include <platform/bcm28xx.h>
31
32/* TODO: extract this into a generic PL011 driver */
33
34/* PL011 implementation */
35#define UART_DR (0x00)
36#define UART_RSR (0x04)
37#define UART_TFR (0x18)
38#define UART_ILPR (0x20)
39#define UART_IBRD (0x24)
40#define UART_FBRD (0x28)
41#define UART_LCRH (0x2c)
42#define UART_CR (0x30)
43#define UART_IFLS (0x34)
44#define UART_IMSC (0x38)
45#define UART_TRIS (0x3c)
46#define UART_TMIS (0x40)
47#define UART_ICR (0x44)
48#define UART_DMACR (0x48)
49
50#define UARTREG(base, reg) (*REG32((base) + (reg)))
51
52#define RXBUF_SIZE 16
53#define NUM_UART 1
54
55static cbuf_t uart_rx_buf[NUM_UART];
56
57static inline uintptr_t uart_to_ptr(unsigned int n)
58{
59 switch (n) {
60 default:
61 case 0:
62 return UART0_BASE;
63 }
64}
65
66static enum handler_return uart_irq(void *arg)
67{
68 bool resched = false;
69 uint port = (uint)arg;
70 uintptr_t base = uart_to_ptr(port);
71
72 /* read interrupt status and mask */
73 uint32_t isr = UARTREG(base, UART_TMIS);
74
75 if (isr & ((1<<6) | (1<<4))) { // rtmis, rxmis
76 UARTREG(base, UART_ICR) = (1<<4);
77 cbuf_t *rxbuf = &uart_rx_buf[port];
78
79 /* while fifo is not empty, read chars out of it */
80 while ((UARTREG(base, UART_TFR) & (1<<4)) == 0) {
81 char c = UARTREG(base, UART_DR);
82 cbuf_write_char(rxbuf, c, false);
83
84 resched = true;
85 }
86 }
87
88 return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
89}
90
91void uart_init(void)
92{
93 for (size_t i = 0; i < NUM_UART; i++) {
94 // create circular buffer to hold received data
95 cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE);
96
97 // assumes interrupts are contiguous
98 register_int_handler(INTERRUPT_VC_UART + i, &uart_irq, (void *)i);
99
100 // clear all irqs
101 UARTREG(uart_to_ptr(i), UART_ICR) = 0x3ff;
102
103 // set fifo trigger level
104 UARTREG(uart_to_ptr(i), UART_IFLS) = 0; // 1/8 rxfifo, 1/8 txfifo
105
106 // enable rx interrupt
107 UARTREG(uart_to_ptr(i), UART_IMSC) = (1<<6)|(1<<4); // rtim, rxim
108
109 // enable receive
110 UARTREG(uart_to_ptr(i), UART_CR) |= (1<<9); // rxen
111
112 // enable interrupt
113 unmask_interrupt(INTERRUPT_VC_UART + i);
114 }
115}
116
117void uart_init_early(void)
118{
119 for (size_t i = 0; i < NUM_UART; i++) {
120 UARTREG(uart_to_ptr(i), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten
121 }
122}
123
124int uart_putc(int port, char c)
125{
126 uintptr_t base = uart_to_ptr(port);
127
128 /* spin while fifo is full */
129 while (UARTREG(base, UART_TFR) & (1<<5))
130 ;
131 UARTREG(base, UART_DR) = c;
132
133 return 1;
134}
135
136int uart_getc(int port, bool wait)
137{
138 cbuf_t *rxbuf = &uart_rx_buf[port];
139
140 char c;
141 if (cbuf_read_char(rxbuf, &c, wait) == 1)
142 return c;
143
144 return -1;
145}
146
147void uart_flush_tx(int port)
148{
149}
150
151void uart_flush_rx(int port)
152{
153}
154
155void uart_init_port(int port, uint baud)
156{
157}
158
159