1 /*
2  * Copyright (c) 2018 The Fuchsia Authors
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 #include <lk/reg.h>
10 #include <stdio.h>
11 #include <lk/trace.h>
12 #include <lib/cbuf.h>
13 #include <kernel/thread.h>
14 #include <platform/interrupts.h>
15 #include <platform/s912d.h>
16 #include <dev/uart.h>
17 
18 #define S912D_UART_WFIFO            (0x00)
19 #define S912D_UART_RFIFO            (0x04)
20 #define S912D_UART_CONTROL          (0x08)
21 #define S912D_UART_STATUS           (0x0C)
22 #define S912D_UART_IRQ_CONTROL      (0x10)
23 #define S912D_UART_REG5             (0x14)
24 
25 #define S912D_UART_CONTROL_INVRTS    (1 << 31)
26 #define S912D_UART_CONTROL_MASKERR   (1 << 30)
27 #define S912D_UART_CONTROL_INVCTS    (1 << 29)
28 #define S912D_UART_CONTROL_TXINTEN   (1 << 28)
29 #define S912D_UART_CONTROL_RXINTEN   (1 << 27)
30 #define S912D_UART_CONTROL_INVTX     (1 << 26)
31 #define S912D_UART_CONTROL_INVRX     (1 << 25)
32 #define S912D_UART_CONTROL_CLRERR    (1 << 24)
33 #define S912D_UART_CONTROL_RSTRX     (1 << 23)
34 #define S912D_UART_CONTROL_RSTTX     (1 << 22)
35 #define S912D_UART_CONTROL_XMITLEN   (1 << 20)
36 #define S912D_UART_CONTROL_XMITLEN_MASK   (0x3 << 20)
37 #define S912D_UART_CONTROL_PAREN     (1 << 19)
38 #define S912D_UART_CONTROL_PARTYPE   (1 << 18)
39 #define S912D_UART_CONTROL_STOPLEN   (1 << 16)
40 #define S912D_UART_CONTROL_STOPLEN_MASK   (0x3 << 16)
41 #define S912D_UART_CONTROL_TWOWIRE   (1 << 15)
42 #define S912D_UART_CONTROL_RXEN      (1 << 13)
43 #define S912D_UART_CONTROL_TXEN      (1 << 12)
44 #define S912D_UART_CONTROL_BAUD0     (1 << 0)
45 #define S912D_UART_CONTROL_BAUD0_MASK     (0xfff << 0)
46 
47 #define S912D_UART_STATUS_RXBUSY         (1 << 26)
48 #define S912D_UART_STATUS_TXBUSY         (1 << 25)
49 #define S912D_UART_STATUS_RXOVRFLW       (1 << 24)
50 #define S912D_UART_STATUS_CTSLEVEL       (1 << 23)
51 #define S912D_UART_STATUS_TXEMPTY        (1 << 22)
52 #define S912D_UART_STATUS_TXFULL         (1 << 21)
53 #define S912D_UART_STATUS_RXEMPTY        (1 << 20)
54 #define S912D_UART_STATUS_RXFULL         (1 << 19)
55 #define S912D_UART_STATUS_TXOVRFLW       (1 << 18)
56 #define S912D_UART_STATUS_FRAMEERR       (1 << 17)
57 #define S912D_UART_STATUS_PARERR         (1 << 16)
58 #define S912D_UART_STATUS_TXCOUNT_POS    (8)
59 #define S912D_UART_STATUS_TXCOUNT_MASK   (0x7f << S912D_UART_STATUS_TXCOUNT_POS)
60 #define S912D_UART_STATUS_RXCOUNT_POS    (0)
61 #define S912D_UART_STATUS_RXCOUNT_MASK   (0x7f << S912D_UART_STATUS_RXCOUNT_POS)
62 
63 
64 #define UARTREG(base, reg)          (*(volatile uint32_t*)((base)  + (reg)))
65 
66 #define RXBUF_SIZE 16
67 #define NUM_UART 1
68 
69 static cbuf_t uart_rx_buf;
70 static uintptr_t uart_base = 0;
71 static uint32_t uart_irq = 0;
72 
73 
uart_putc(int port,char c)74 int uart_putc(int port, char c) {
75     while (UARTREG(uart_base, S912D_UART_STATUS) & S912D_UART_STATUS_TXFULL)
76         ;
77     UARTREG(uart_base, S912D_UART_WFIFO) = c;
78 
79     return 0;
80 }
81 
uart_getc(int port,bool wait)82 int uart_getc(int port, bool wait) {
83     char c;
84     if (cbuf_read_char(&uart_rx_buf, &c, wait) == 1) {
85         return c;
86     } else {
87         return -1;
88     }
89 }
90 
uart_irq_handler(void * arg)91 static enum handler_return uart_irq_handler(void *arg) {
92     while ( (UARTREG(uart_base, S912D_UART_STATUS) & S912D_UART_STATUS_RXCOUNT_MASK) > 0 ) {
93         if (cbuf_space_avail(&uart_rx_buf) == 0) {
94             break;
95         }
96         char c = UARTREG(uart_base, S912D_UART_RFIFO);
97         cbuf_write_char(&uart_rx_buf, c,false);
98     }
99 
100     return INT_RESCHEDULE;
101 }
102 
uart_init_early(void)103 void uart_init_early(void) {
104     uart_base = UART0_AO_BASE;
105     uart_irq = UART0_IRQ;
106 
107     // reset port
108     UARTREG(uart_base,S912D_UART_CONTROL) |=  S912D_UART_CONTROL_RSTRX |
109             S912D_UART_CONTROL_RSTTX |
110             S912D_UART_CONTROL_CLRERR;
111     UARTREG(uart_base,S912D_UART_CONTROL) &= ~(S912D_UART_CONTROL_RSTRX |
112             S912D_UART_CONTROL_RSTTX |
113             S912D_UART_CONTROL_CLRERR);
114 
115     // enable rx and tx
116     UARTREG(uart_base,S912D_UART_CONTROL) |= S912D_UART_CONTROL_TXEN |
117             S912D_UART_CONTROL_RXEN;
118 
119     UARTREG(uart_base,S912D_UART_CONTROL) |= S912D_UART_CONTROL_INVRTS |
120             S912D_UART_CONTROL_RXINTEN |
121             S912D_UART_CONTROL_TWOWIRE;
122 
123 }
uart_init(void)124 void uart_init(void) {
125     uart_base = UART0_AO_BASE;
126     uart_irq = UART0_IRQ;
127 
128     // create a circular buufer to hold rx data
129     cbuf_initialize(&uart_rx_buf, RXBUF_SIZE);
130 
131     // register uart irq
132     register_int_handler(uart_irq, &uart_irq_handler, NULL);
133 
134     // reset port
135     UARTREG(uart_base,S912D_UART_CONTROL) |=  S912D_UART_CONTROL_RSTRX |
136             S912D_UART_CONTROL_RSTTX |
137             S912D_UART_CONTROL_CLRERR;
138     UARTREG(uart_base,S912D_UART_CONTROL) &= ~(S912D_UART_CONTROL_RSTRX |
139             S912D_UART_CONTROL_RSTTX |
140             S912D_UART_CONTROL_CLRERR);
141 
142     // enable rx and tx
143     UARTREG(uart_base,S912D_UART_CONTROL) |= S912D_UART_CONTROL_TXEN |
144             S912D_UART_CONTROL_RXEN;
145 
146     UARTREG(uart_base,S912D_UART_CONTROL) |= S912D_UART_CONTROL_INVRTS |
147             S912D_UART_CONTROL_RXINTEN |
148             S912D_UART_CONTROL_TWOWIRE;
149 
150     // Set to interrupt every 1 rx byte
151     uint32_t temp2 = UARTREG(uart_base,S912D_UART_IRQ_CONTROL);
152     temp2 &= 0xffff0000;
153     temp2 |= (1 << 8) | ( 1 );
154     UARTREG(uart_base,S912D_UART_IRQ_CONTROL) = temp2;
155 
156     // TODO: Look into adding baud rate support
157 
158     // enable interrupts
159     unmask_interrupt(uart_irq);
160 
161 }
162