1 /*
2 * Copyright (c) 2012 Kent Ryhorchuk
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 <stdarg.h>
9 #include <lk/reg.h>
10 #include <lk/debug.h>
11 #include <stdio.h>
12 #include <assert.h>
13 #include <lib/cbuf.h>
14 #include <kernel/thread.h>
15 #include <platform/debug.h>
16 #include <arch/ops.h>
17 #include <dev/uart.h>
18 #include <target/debugconfig.h>
19 #include <stm32f4xx_rcc.h>
20 #include <stm32f4xx_usart.h>
21 #include <arch/arm/cm.h>
22
23 #ifdef ENABLE_UART1
24 cbuf_t uart1_rx_buf;
25 #ifndef UART1_FLOWCONTROL
26 #define UART1_FLOWCONTROL USART_HardwareFlowControl_None
27 #endif
28 #ifndef UART1_BAUDRATE
29 #define UART1_BAUDRATE 115200
30 #endif
31 #ifndef UART1_RXBUF_SIZE
32 #define UART1_RXBUF_SIZE 64
33 #endif
34 #endif
35
36 #ifdef ENABLE_UART2
37 cbuf_t uart2_rx_buf;
38 #ifndef UART2_FLOWCONTROL
39 #define UART2_FLOWCONTROL USART_HardwareFlowControl_None
40 #endif
41 #ifndef UART2_BAUDRATE
42 #define UART2_BAUDRATE 115200
43 #endif
44 #ifndef UART2_RXBUF_SIZE
45 #define UART2_RXBUF_SIZE 64
46 #endif
47 #endif
48
49 #ifdef ENABLE_UART3
50 cbuf_t uart3_rx_buf;
51 #ifndef UART3_FLOWCONTROL
52 #define UART3_FLOWCONTROL USART_HardwareFlowControl_None
53 #endif
54 #ifndef UART3_BAUDRATE
55 #define UART3_BAUDRATE 115200
56 #endif
57 #ifndef UART3_RXBUF_SIZE
58 #define UART3_RXBUF_SIZE 64
59 #endif
60 #endif
61
62 #ifdef ENABLE_UART6
63 cbuf_t uart6_rx_buf;
64 #ifndef UART6_FLOWCONTROL
65 #define UART6_FLOWCONTROL USART_HardwareFlowControl_None
66 #endif
67 #ifndef UART6_BAUDRATE
68 #define UART6_BAUDRATE 115200
69 #endif
70 #ifndef UART6_RXBUF_SIZE
71 #define UART6_RXBUF_SIZE 64
72 #endif
73 #endif
74
usart_init1_early(USART_TypeDef * usart,uint32_t baud,uint16_t flowcontrol,int irqn)75 static void usart_init1_early(USART_TypeDef *usart, uint32_t baud, uint16_t flowcontrol, int irqn) {
76 USART_InitTypeDef init;
77
78 init.USART_BaudRate = baud;
79 init.USART_WordLength = USART_WordLength_8b;
80 init.USART_StopBits = USART_StopBits_1;
81 init.USART_Parity = USART_Parity_No;
82 init.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
83 init.USART_HardwareFlowControl = flowcontrol;
84
85 USART_Init(usart, &init);
86 USART_ITConfig(usart, USART_IT_RXNE, DISABLE);
87 NVIC_DisableIRQ(irqn);
88 USART_Cmd(usart, ENABLE);
89 }
90
usart_init1(USART_TypeDef * usart,int irqn,cbuf_t * rxbuf,size_t rxsize)91 static void usart_init1(USART_TypeDef *usart, int irqn, cbuf_t *rxbuf, size_t rxsize) {
92 cbuf_initialize(rxbuf, rxsize);
93 USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
94 NVIC_EnableIRQ(irqn);
95 USART_Cmd(usart, ENABLE);
96 }
97
uart_init_early(void)98 void uart_init_early(void) {
99 #ifdef ENABLE_UART1
100 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
101 usart_init1_early(USART1, UART1_BAUDRATE, UART1_FLOWCONTROL, USART1_IRQn);
102 #endif
103 #ifdef ENABLE_UART2
104 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
105 usart_init1_early(USART2, UART2_BAUDRATE, UART2_FLOWCONTROL, USART2_IRQn);
106 #endif
107 #ifdef ENABLE_UART3
108 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
109 usart_init1_early(USART3, UART3_BAUDRATE, UART3_FLOWCONTROL, USART3_IRQn);
110 #endif
111 #ifdef ENABLE_UART6
112 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
113 usart_init1_early(USART6, UART6_BAUDRATE, UART6_FLOWCONTROL, USART6_IRQn);
114 #endif
115 }
116
uart_init(void)117 void uart_init(void) {
118 #ifdef ENABLE_UART1
119 usart_init1(USART1, USART1_IRQn, &uart1_rx_buf, UART1_RXBUF_SIZE);
120 #endif
121 #ifdef ENABLE_UART2
122 usart_init1(USART2, USART2_IRQn, &uart2_rx_buf, UART2_RXBUF_SIZE);
123 #endif
124 #ifdef ENABLE_UART3
125 usart_init1(USART3, USART3_IRQn, &uart3_rx_buf, UART3_RXBUF_SIZE);
126 #endif
127 #ifdef ENABLE_UART6
128 usart_init1(USART6, USART6_IRQn, &uart6_rx_buf, UART6_RXBUF_SIZE);
129 #endif
130 }
131
uart_rx_irq(USART_TypeDef * usart,cbuf_t * rxbuf)132 static void uart_rx_irq(USART_TypeDef *usart, cbuf_t *rxbuf) {
133 arm_cm_irq_entry();
134
135 bool resched = false;
136 while (USART_GetFlagStatus(usart, USART_FLAG_RXNE)) {
137 if (!cbuf_space_avail(rxbuf)) {
138 // Overflow - let flow control do its thing by not
139 // reading the from the FIFO.
140 USART_ITConfig(usart, USART_IT_RXNE, DISABLE);
141 break;
142 }
143
144 char c = USART_ReceiveData(usart);
145 cbuf_write_char(rxbuf, c, false);
146 resched = true;
147 }
148
149 arm_cm_irq_exit(resched);
150 }
151
152 #ifdef ENABLE_UART1
stm32_USART1_IRQ(void)153 void stm32_USART1_IRQ(void) {
154 uart_rx_irq(USART1, &uart1_rx_buf);
155 }
156 #endif
157
158 #ifdef ENABLE_UART2
stm32_USART2_IRQ(void)159 void stm32_USART2_IRQ(void) {
160 uart_rx_irq(USART2, &uart2_rx_buf);
161 }
162 #endif
163
164 #ifdef ENABLE_UART3
stm32_USART3_IRQ(void)165 void stm32_USART3_IRQ(void) {
166 uart_rx_irq(USART3, &uart3_rx_buf);
167 }
168 #endif
169
170 #ifdef ENABLE_UART6
stm32_USART6_IRQ(void)171 void stm32_USART6_IRQ(void) {
172 uart_rx_irq(USART6, &uart6_rx_buf);
173 }
174 #endif
175
usart_putc(USART_TypeDef * usart,char c)176 static void usart_putc(USART_TypeDef *usart, char c) {
177 while (USART_GetFlagStatus(usart, USART_FLAG_TXE) == 0);
178 USART_SendData(usart, c);
179 while (USART_GetFlagStatus(usart, USART_FLAG_TC) == 0);
180 }
181
usart_getc(USART_TypeDef * usart,cbuf_t * rxbuf,bool wait)182 static int usart_getc(USART_TypeDef *usart, cbuf_t *rxbuf, bool wait) {
183 unsigned char c;
184 if (cbuf_read_char(rxbuf, (char *) &c, wait) == 0)
185 return -1;
186 if (cbuf_space_avail(rxbuf) > cbuf_size(rxbuf))
187 USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
188
189 return c;
190 }
191
get_usart(int port)192 static USART_TypeDef *get_usart(int port) {
193 switch (port) {
194 #ifdef ENABLE_UART1
195 case 1:
196 return USART1;
197 #endif
198 #ifdef ENABLE_UART2
199 case 2:
200 return USART2;
201 #endif
202 #ifdef ENABLE_UART3
203 case 3:
204 return USART3;
205 #endif
206 #ifdef ENABLE_UART6
207 case 6:
208 return USART6;
209 #endif
210 default:
211 ASSERT(false);
212 return 0;
213 }
214 }
215
get_rxbuf(int port)216 static cbuf_t *get_rxbuf(int port) {
217 switch (port) {
218 #ifdef ENABLE_UART1
219 case 1:
220 return &uart1_rx_buf;
221 #endif
222 #ifdef ENABLE_UART2
223 case 2:
224 return &uart2_rx_buf;
225 #endif
226 #ifdef ENABLE_UART3
227 case 3:
228 return &uart3_rx_buf;
229 #endif
230 #ifdef ENABLE_UART6
231 case 6:
232 return &uart6_rx_buf;
233 #endif
234 default:
235 ASSERT(false);
236 return 0;
237 }
238 }
239
uart_putc(int port,char c)240 int uart_putc(int port, char c) {
241 USART_TypeDef *usart = get_usart(port);
242 usart_putc(usart, c);
243 return 1;
244 }
245
uart_getc(int port,bool wait)246 int uart_getc(int port, bool wait) {
247 cbuf_t *rxbuf = get_rxbuf(port);
248 USART_TypeDef *usart = get_usart(port);
249
250 return usart_getc(usart, rxbuf, wait);
251 }
252
uart_flush_tx(int port)253 void uart_flush_tx(int port) {}
254
uart_flush_rx(int port)255 void uart_flush_rx(int port) {}
256
uart_init_port(int port,uint baud)257 void uart_init_port(int port, uint baud) {
258 USART_TypeDef *usart = get_usart(port);
259 uint32_t treg = 0;
260 uint32_t apbclk = 0;
261 uint32_t intdiv = 0;
262 uint32_t fracdiv = 0;
263 RCC_ClocksTypeDef RCC_ClksStat;
264
265 RCC_GetClocksFreq(&RCC_ClksStat);
266
267 if ((usart == USART1) || (usart == USART6)) {
268 apbclk = RCC_ClksStat.PCLK2_Frequency;
269 } else {
270 apbclk = RCC_ClksStat.PCLK1_Frequency;
271 }
272
273 if ((usart->CR1 & USART_CR1_OVER8) != 0) {
274 intdiv = ((25 * apbclk) / (2 * (baud)));
275 } else {
276 intdiv = ((25 * apbclk) / (4 * (baud)));
277 }
278 treg = (intdiv / 100) << 4;
279
280 fracdiv = intdiv - (100 * (treg >> 4));
281
282 if ((usart->CR1 & USART_CR1_OVER8) != 0) {
283 treg |= ((((fracdiv * 8) + 50) / 100)) & ((uint8_t) 0x07);
284 } else {
285 treg |= ((((fracdiv * 16) + 50) / 100)) & ((uint8_t) 0x0F);
286 }
287
288 usart->BRR = (uint16_t) treg;
289 }
290
291 // inject a character into the console uart rx buffer
__debugger_console_putc(char c)292 void __debugger_console_putc(char c) {
293 cbuf_t *rxbuf = get_rxbuf(DEBUG_UART);
294 if (rxbuf && cbuf_space_avail(rxbuf)) {
295 cbuf_write_char(rxbuf, c, false);
296 }
297 }
298
299