1 /*
2  * Copyright (c) 2012 Kent Ryhorchuk
3  * Copyright (c) 2016 Erik Gilling
4  *
5  * Use of this source code is governed by a MIT-style
6  * license that can be found in the LICENSE file or at
7  * https://opensource.org/licenses/MIT
8  */
9 
10 #include <arch/arm/cm.h>
11 #include <assert.h>
12 #include <dev/uart.h>
13 #include <lib/cbuf.h>
14 #include <lib/io.h>
15 #include <platform/rcc.h>
16 #include <stdint.h>
17 #include <stm32f0xx.h>
18 #include <target/debugconfig.h>
19 
20 typedef USART_TypeDef stm32_usart_t;
21 
22 #define RXBUF_SIZE 16
23 
24 #ifdef ENABLE_UART1
25 cbuf_t uart1_rx_buf;
26 #ifndef UART1_FLOWCONTROL
27 #define UART1_FLOWCONTROL 0x0
28 #endif
29 #endif
30 
31 #ifdef ENABLE_UART2
32 cbuf_t uart2_rx_buf;
33 #ifndef UART2_FLOWCONTROL
34 #define UART2_FLOWCONTROL 0x0
35 #endif
36 #endif
37 
38 #ifdef ENABLE_UART3
39 cbuf_t uart3_rx_buf;
40 #ifndef UART3_FLOWCONTROL
41 #define UART3_FLOWCONTROL 0x0
42 #endif
43 #endif
44 
45 #ifdef ENABLE_UART4
46 cbuf_t uart4_rx_buf;
47 #ifndef UART4_FLOWCONTROL
48 #define UART4_FLOWCONTROL 0x0
49 #endif
50 #endif
51 
stm32_usart_init1_early(stm32_usart_t * usart,uint16_t flow_control,int irqn)52 static void stm32_usart_init1_early(stm32_usart_t *usart,
53                                     uint16_t flow_control, int irqn) {
54     uint32_t baud_rate = 115200;
55 
56     // Ensure USART is disabled before configuring it.
57     usart->CR1 = 0;
58 
59     // Set stop bits to 1 (CR2[13:12] = 00b)
60     usart->CR2 = 0;
61 
62 
63     // Go with the defaults of:
64     //   word length: 8 bits
65     //   parity: disabled
66     // Enable TX and RX.
67     usart->CR1 = USART_CR1_TE | USART_CR1_RE;
68 
69     usart->CR3 = flow_control;
70 
71     // TODO(konkers): Add rcc API for querying clock freq.
72     uint32_t apb_clock = 48000000;
73 
74     usart->BRR = (apb_clock + baud_rate / 2) / baud_rate;
75 
76     // Leave IRQs disabled until init.
77     NVIC_DisableIRQ(irqn);
78 
79     // Enable UART.
80     usart->CR1 |= USART_CR1_UE;
81 }
82 
stm32_usart_init1(stm32_usart_t * usart,int irqn,cbuf_t * rxbuf)83 static void stm32_usart_init1(stm32_usart_t *usart, int irqn, cbuf_t *rxbuf) {
84     cbuf_initialize(rxbuf, RXBUF_SIZE);
85     // Enable RX not empty interrupt.
86     usart->CR1 |= USART_CR1_RXNEIE;
87     NVIC_EnableIRQ(irqn);
88 }
89 
90 #if defined(ENABLE_UART3) && defined(ENABLE_UART4)
91 #error UART3 and 4 share an interrupt; not supported
92 #endif
93 
uart_init_early(void)94 void uart_init_early(void) {
95 #ifdef ENABLE_UART1
96     stm32_rcc_set_enable(STM32_RCC_CLK_USART1, true);
97 #endif
98 #ifdef ENABLE_UART2
99     stm32_rcc_set_enable(STM32_RCC_CLK_USART2, true);
100 #endif
101 #ifdef ENABLE_UART3
102     stm32_rcc_set_enable(STM32_RCC_CLK_USART3, true);
103 #endif
104 #ifdef ENABLE_UART4
105     stm32_rcc_set_enable(STM32_RCC_CLK_USART4, true);
106 #endif
107 
108 #ifdef ENABLE_UART1
109     stm32_usart_init1_early(USART1, UART1_FLOWCONTROL, USART1_IRQn);
110 #endif
111 #ifdef ENABLE_UART2
112     stm32_usart_init1_early(USART2, UART2_FLOWCONTROL, USART2_IRQn);
113 #endif
114 #ifdef ENABLE_UART3
115     stm32_usart_init1_early(USART3, UART3_FLOWCONTROL, USART3_4_IRQn);
116 #endif
117 #ifdef ENABLE_UART4
118     stm32_usart_init1_early(USART4, UART4_FLOWCONTROL, USART3_4_IRQn);
119 #endif
120 }
121 
uart_init(void)122 void uart_init(void) {
123 #ifdef ENABLE_UART1
124     stm32_usart_init1(USART1, USART1_IRQn, &uart1_rx_buf);
125 #endif
126 #ifdef ENABLE_UART2
127     stm32_usart_init1(USART2, USART2_IRQn, &uart2_rx_buf);
128 #endif
129 #ifdef ENABLE_UART3
130     stm32_usart_init1(USART3, USART3_4_IRQn, &uart3_rx_buf);
131 #endif
132 #ifdef ENABLE_UART4
133     stm32_usart_init1(USART4, USART3_4_IRQn, &uart4_rx_buf);
134 #endif
135 }
136 
137 // I'm seeing a weird issue with my nucleo-f072rb board where rx interrupts
138 // don't fire right after a reset by the on board programmer.  If I hit
139 // the reset button, rx works fine.  I can live with this. YMMV.
stm32_uart_rx_irq(stm32_usart_t * usart,cbuf_t * rxbuf)140 static void stm32_uart_rx_irq(stm32_usart_t *usart, cbuf_t *rxbuf) {
141     arm_cm_irq_entry();
142 
143     bool resched = false;
144     while (usart->ISR & USART_ISR_RXNE) {
145         if (!cbuf_space_avail(rxbuf)) {
146             // Overflow - let flow control do its thing by not
147             // reading the from the FIFO.
148             usart->CR1 &= ~USART_CR1_RXNEIE;
149             break;
150         }
151 
152         char c = usart->RDR;
153         cbuf_write_char(rxbuf, c, false);
154         resched = true;
155     }
156 
157     arm_cm_irq_exit(resched);
158 }
159 
stm32_get_rxbuf(int port)160 static cbuf_t *stm32_get_rxbuf(int port) {
161 #if CONSOLE_HAS_INPUT_BUFFER
162     if (DEBUG_UART == port) {
163         return &console_input_cbuf;
164     }
165 #endif
166     switch (port) {
167 #ifdef ENABLE_UART1
168         case 1:
169             return &uart1_rx_buf;
170 #endif
171 #ifdef ENABLE_UART2
172         case 2:
173             return &uart2_rx_buf;
174 #endif
175 #ifdef ENABLE_UART3
176         case 3:
177             return &uart3_rx_buf;
178 #endif
179 #ifdef ENABLE_UART4
180         case 4:
181             return &uart4_rx_buf;
182 #endif
183         default:
184             ASSERT(false);
185             return 0;
186     }
187 }
188 
189 #ifdef ENABLE_UART1
stm32_USART1_IRQ(void)190 void stm32_USART1_IRQ(void) {
191     stm32_uart_rx_irq(USART1, stm32_get_rxbuf(1));
192 }
193 #endif
194 
195 #ifdef ENABLE_UART2
stm32_USART2_IRQ(void)196 void stm32_USART2_IRQ(void) {
197     stm32_uart_rx_irq(USART2, stm32_get_rxbuf(2));
198 }
199 #endif
200 
201 #ifdef ENABLE_UART3
stm32_USART3_4_IRQ(void)202 void stm32_USART3_4_IRQ(void) {
203     stm32_uart_rx_irq(USART3, stm32_get_rxbuf(3));
204 }
205 #endif
206 
207 #ifdef ENABLE_UART4
stm32_USART3_4_IRQ(void)208 void stm32_USART3_4_IRQ(void) {
209     stm32_uart_rx_irq(USART4, stm32_get_rxbuf(4));
210 }
211 #endif
212 
213 
stm32_usart_putc(stm32_usart_t * usart,char c)214 static void stm32_usart_putc(stm32_usart_t *usart, char c) {
215     while ((usart->ISR & USART_ISR_TXE) == 0);
216     usart->TDR = c;
217     while ((usart->ISR & USART_ISR_TC) == 0);
218 }
219 
stm32_usart_getc(stm32_usart_t * usart,cbuf_t * rxbuf,bool wait)220 static int stm32_usart_getc(stm32_usart_t *usart, cbuf_t *rxbuf, bool wait) {
221     char c;
222     cbuf_read_char(rxbuf, &c, wait);
223     if (cbuf_space_avail(rxbuf) > RXBUF_SIZE/2)
224         usart->CR1 |= USART_CR1_RXNEIE;
225 
226     return c;
227 }
228 
stm32_get_usart(int port)229 static stm32_usart_t *stm32_get_usart(int port) {
230     switch (port) {
231 #ifdef ENABLE_UART1
232         case 1:
233             return USART1;
234 #endif
235 #ifdef ENABLE_UART2
236         case 2:
237             return USART2;
238 #endif
239 #ifdef ENABLE_UART3
240         case 3:
241             return USART3;
242 #endif
243 #ifdef ENABLE_UART4
244         case 4:
245             return USART4;
246 #endif
247         default:
248             ASSERT(false);
249             return 0;
250     }
251 
252 }
253 
uart_putc(int port,char c)254 int uart_putc(int port, char c) {
255     stm32_usart_t *usart = stm32_get_usart(port);
256     stm32_usart_putc(usart, c);
257     return 1;
258 }
259 
uart_getc(int port,bool wait)260 int uart_getc(int port, bool wait) {
261     cbuf_t *rxbuf = stm32_get_rxbuf(port);
262     stm32_usart_t *usart = stm32_get_usart(port);
263 
264     return stm32_usart_getc(usart, rxbuf, wait);
265 }
266 
uart_flush_tx(int port)267 void uart_flush_tx(int port) {}
268 
uart_flush_rx(int port)269 void uart_flush_rx(int port) {}
270 
uart_init_port(int port,uint baud)271 void uart_init_port(int port, uint baud) {
272     // TODO - later
273     PANIC_UNIMPLEMENTED;
274 }
275