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 <stdio.h>
10 #include <lk/trace.h>
11 #include <assert.h>
12 #include <lib/cbuf.h>
13 #include <kernel/thread.h>
14 #include <dev/uart.h>
15 #include <platform/interrupts.h>
16 #include <platform/debug.h>
17 #include <platform/zynq.h>
18 
19 #define RXBUF_SIZE 16
20 
21 static cbuf_t uart_rx_buf[NUM_UARTS];
22 
uart_to_ptr(unsigned int n)23 static inline uintptr_t uart_to_ptr(unsigned int n) { return (n == 0) ? UART0_BASE : UART1_BASE; }
uart_to_irq(unsigned int n)24 static inline uint uart_to_irq(unsigned int n) { return (n == 0) ? UART0_INT : UART1_INT; }
25 
26 #define UART_REG(base, reg)  (*REG32((base)  + (reg)))
27 
uart_irq(void * arg)28 static enum handler_return uart_irq(void *arg) {
29     bool resched = false;
30     uint port = (uint)arg;
31     uintptr_t base = uart_to_ptr(port);
32 
33     /* read interrupt status and mask */
34     uint32_t isr = UART_REG(base, UART_ISR);
35     isr &= UART_REG(base, UART_IMR);
36 
37     if (isr & (1<<0)) { // rxtrig
38         UART_REG(base, UART_ISR) = (1<< 0);
39 
40         while ((UART_REG(base, UART_SR) & (1<<1)) == 0) { // ~rempty
41             char c = UART_REG(base, UART_FIFO);
42             cbuf_write_char(&uart_rx_buf[port], c, false);
43 
44             resched = true;
45         }
46     }
47 
48     return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
49 }
50 
uart_init(void)51 void uart_init(void) {
52     for (uint i = 0; i < NUM_UARTS; i++) {
53         cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE);
54 
55         uintptr_t base = uart_to_ptr(i);
56 
57         // clear all irqs
58         UART_REG(base, UART_IDR) = 0xffffffff;
59 
60         // set rx fifo trigger to 1
61         UART_REG(base, UART_RXWM) = 1;
62 
63         // enable the receiver
64         // NOTE: must clear rxdis and set rxen in the same write
65         UART_REG(base, UART_CR) = (UART_REG(base, UART_CR) & ~(1<<3)) | (1 << 2);
66 
67         // enable rx interrupt
68         UART_REG(base, UART_IER) = (1<<0); // rxtrig
69 
70         // set up interrupt handler
71         register_int_handler(uart_to_irq(i), &uart_irq, (void *)i);
72         unmask_interrupt(uart_to_irq(i));
73     }
74 }
75 
uart_init_early(void)76 void uart_init_early(void) {
77     for (uint i = 0; i < NUM_UARTS; i++) {
78         uintptr_t base = uart_to_ptr(i);
79 
80         UART_REG(base, UART_BAUD_DIV) = UART_BRD_DIV(6);
81         UART_REG(base, UART_BAUDGEN) = UART_BRG_DIV(0x3E);
82 
83         // reset the tx/rx path
84         UART_REG(base, UART_CR) |= UART_CR_TXRES | UART_CR_RXRES;
85         while ((UART_REG(base, UART_CR) & (UART_CR_TXRES | UART_CR_RXRES)) != 0)
86             ;
87 
88         // n81, clock select ref_clk
89         UART_REG(base, UART_MR) = UART_MR_PAR(0x4); // no parity
90 
91         // no flow
92         UART_REG(base, UART_MODEMCR) = 0;
93 
94         UART_REG(base, UART_CR) = UART_CR_TXEN;
95     }
96 
97     /* Configuration for the serial console */
98     /*UART_REG(UART1_BASE, UART_CR) = 0x00000017;*/
99     /*UART_REG(UART1_BASE, UART_MR) = 0x00000020;*/
100 }
101 
uart_putc(int port,char c)102 int uart_putc(int port, char c) {
103     DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
104 
105     uintptr_t base = uart_to_ptr(port);
106 
107     /* spin while fifo is full */
108     while (UART_REG(base, UART_SR) & (1<<4))
109         ;
110     UART_REG(base, UART_FIFO) = c;
111 
112     return 1;
113 }
114 
uart_getc(int port,bool wait)115 int uart_getc(int port, bool wait) {
116     DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
117 
118     char c;
119     if (cbuf_read_char(&uart_rx_buf[port], &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     DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
127 }
128 
uart_flush_rx(int port)129 void uart_flush_rx(int port) {
130     DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
131 }
132 
uart_init_port(int port,uint baud)133 void uart_init_port(int port, uint baud) {
134     DEBUG_ASSERT(port >= 0 && port < NUM_UARTS);
135 
136     PANIC_UNIMPLEMENTED;
137 }
138 
139