blob: 5c3d5ab68ce30336bb01420938e10ca7d8fb3d8b [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/bcm2835.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: return UART0_BASE;
62 }
63}
64
65static enum handler_return uart_irq(void *arg)
66{
67 bool resched = false;
68 uint port = (uint)arg;
69 uintptr_t base = uart_to_ptr(port);
70
71 /* read interrupt status and mask */
72 uint32_t isr = UARTREG(base, UART_TMIS);
73
74 if (isr & ((1<<6) | (1<<4))) { // rtmis, rxmis
75 UARTREG(base, UART_ICR) = (1<<4);
76 cbuf_t *rxbuf = &uart_rx_buf[port];
77
78 /* while fifo is not empty, read chars out of it */
79 while ((UARTREG(base, UART_TFR) & (1<<4)) == 0) {
80 char c = UARTREG(base, UART_DR);
81 cbuf_write_char(rxbuf, c, false);
82
83 resched = true;
84 }
85 }
86
87 return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
88}
89
90void uart_init(void)
91{
92 for (size_t i = 0; i < NUM_UART; i++) {
93 // create circular buffer to hold received data
94 cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE);
95
96 // assumes interrupts are contiguous
97 register_int_handler(INTERRUPT_VC_UART + i, &uart_irq, (void *)i);
98
99 // clear all irqs
100 UARTREG(uart_to_ptr(i), UART_ICR) = 0x3ff;
101
102 // set fifo trigger level
103 UARTREG(uart_to_ptr(i), UART_IFLS) = 0; // 1/8 rxfifo, 1/8 txfifo
104
105 // enable rx interrupt
106 UARTREG(uart_to_ptr(i), UART_IMSC) = (1<<6)|(1<<4); // rtim, rxim
107
108 // enable receive
109 UARTREG(uart_to_ptr(i), UART_CR) |= (1<<9); // rxen
110
111 // enable interrupt
112 unmask_interrupt(INTERRUPT_VC_UART + i);
113 }
114}
115
116void uart_init_early(void)
117{
118 for (size_t i = 0; i < NUM_UART; i++) {
119 UARTREG(uart_to_ptr(i), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten
120 }
121}
122
123int uart_putc(int port, char c)
124{
125 uintptr_t base = uart_to_ptr(port);
126
127 /* spin while fifo is full */
128 while (UARTREG(base, UART_TFR) & (1<<5))
129 ;
130 UARTREG(base, UART_DR) = c;
131
132 return 1;
133}
134
135int uart_getc(int port, bool wait)
136{
137 cbuf_t *rxbuf = &uart_rx_buf[port];
138
139 char c;
140 if (cbuf_read_char(rxbuf, &c, wait) == 1)
141 return c;
142
143 return -1;
144}
145
146void uart_flush_tx(int port)
147{
148}
149
150void uart_flush_rx(int port)
151{
152}
153
154void uart_init_port(int port, uint baud)
155{
156}
157
158