1 /*
2 * Copyright (c) 2014 Travis Geiselbrecht
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 #include <lk/reg.h>
9 #include <lk/bits.h>
10 #include <stdio.h>
11 #include <lk/trace.h>
12 #include <lib/cbuf.h>
13 #include <dev/uart.h>
14 #include <kernel/thread.h>
15 #include <kernel/spinlock.h>
16 #include <platform/interrupts.h>
17 #include <platform/debug.h>
18 #include <platform/alterasoc.h>
19
20 #define UART_THR (0x00)
21 #define UART_RBR (0x00)
22 #define UART_DLL (0x00)
23 #define UART_IER (0x04)
24 #define UART_DLH (0x04)
25 #define UART_IIR (0x08)
26 #define UART_FCR (0x08)
27 #define UART_LCR (0x0c)
28 #define UART_MCR (0x10)
29 #define UART_LSR (0x14)
30 #define UART_MSR (0x18)
31 #define UART_SCR (0x1c)
32 #define UART_USR (0x7c)
33 #define UART_TFL (0x80)
34 #define UART_RFL (0x84)
35 #define UART_SRR (0x88)
36
37 #define UARTREG(base, reg) (*REG32((base) + (reg)))
38
39 #define RXBUF_SIZE 16
40
41 static cbuf_t uart0_rx_buf;
42 static cbuf_t uart1_rx_buf;
43
uart_to_ptr(unsigned int n)44 static inline uintptr_t uart_to_ptr(unsigned int n) { return (n == 0) ? UART0_BASE : UART1_BASE; }
uart_to_rxbuf(unsigned int n)45 static inline cbuf_t *uart_to_rxbuf(unsigned int n) { return (n == 0) ? &uart0_rx_buf : &uart1_rx_buf; }
46
47 static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE;
48
uart_irq(void * arg)49 static enum handler_return uart_irq(void *arg) {
50 bool resched = false;
51 uint port = (uint)arg;
52 uintptr_t base = uart_to_ptr(port);
53
54 /* read interrupt identity */
55 uint32_t iir = UARTREG(base, UART_IIR);
56
57 /* receive data available */
58 if (BITS(iir, 3, 0) == 0x4) {
59 cbuf_t *rxbuf = uart_to_rxbuf(port);
60
61 /* while receive fifo not empty, read a char */
62 while ((UARTREG(base, UART_USR) & (1<<3))) {
63 char c = UARTREG(base, UART_RBR);
64 cbuf_write_char(rxbuf, c, false);
65
66 resched = true;
67 }
68 }
69
70 return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
71 }
72
uart_init(void)73 void uart_init(void) {
74 cbuf_initialize(&uart0_rx_buf, RXBUF_SIZE);
75 cbuf_initialize(&uart1_rx_buf, RXBUF_SIZE);
76
77 register_int_handler(UART0_INT, &uart_irq, (void *)0);
78 register_int_handler(UART1_INT, &uart_irq, (void *)1);
79
80 // enable the fifo
81 UARTREG(uart_to_ptr(0), UART_FCR) = (1<<0); // enable rx fifo, set tx trigger to 0, set rx trigger to 0
82 UARTREG(uart_to_ptr(1), UART_FCR) = (1<<0); // enable rx fifo, set tx trigger to 0, set rx trigger to 0
83
84 // enable rx interrupt
85 UARTREG(uart_to_ptr(0), UART_IER) = (1<<0); // receive data interrupt
86 UARTREG(uart_to_ptr(1), UART_IER) = (1<<0); // receive data interrupt
87
88 unmask_interrupt(UART0_INT);
89 unmask_interrupt(UART1_INT);
90 }
91
uart_init_early(void)92 void uart_init_early(void) {
93 #if 0
94 UARTREG(uart_to_ptr(0), UART_CR) = (1<<4); // txen
95 UARTREG(uart_to_ptr(1), UART_CR) = (1<<4); // txen
96 #endif
97 }
98
uart_putc(int port,char c)99 int uart_putc(int port, char c) {
100 uintptr_t base = uart_to_ptr(port);
101
102 spin_lock_saved_state_t state;
103 spin_lock_irqsave(&lock, state);
104
105 /* spin while fifo is full */
106 while ((UARTREG(base, UART_USR) & (1<<1)) == 0) {
107 }
108 UARTREG(base, UART_THR) = c;
109
110 spin_unlock_irqrestore(&lock, state);
111
112 return 1;
113 }
114
uart_getc(int port,bool wait)115 int uart_getc(int port, bool wait) {
116 cbuf_t *rxbuf = uart_to_rxbuf(port);
117
118 char c;
119 if (cbuf_read_char(rxbuf, &c, wait) == 1)
120 return c;
121
122 return -1;
123 }
124
uart_flush_tx(int port)125 void uart_flush_tx(int port) {
126 }
127
uart_flush_rx(int port)128 void uart_flush_rx(int port) {
129 }
130
uart_init_port(int port,uint baud)131 void uart_init_port(int port, uint baud) {
132 }
133
134