blob: d1b51f84bcda9fa12a7da9373b24dc1eef46c283 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2012 Kent Ryhorchuk
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <stdarg.h>
24#include <reg.h>
25#include <debug.h>
26#include <stdio.h>
27#include <assert.h>
28#include <lib/cbuf.h>
29#include <kernel/thread.h>
30#include <platform/debug.h>
31#include <arch/ops.h>
32#include <dev/uart.h>
33#include <target/debugconfig.h>
34#include <stm32f4xx_rcc.h>
35#include <stm32f4xx_usart.h>
36#include <arch/arm/cm.h>
37
38#ifdef ENABLE_UART1
39cbuf_t uart1_rx_buf;
40#ifndef UART1_FLOWCONTROL
41#define UART1_FLOWCONTROL USART_HardwareFlowControl_None
42#endif
43#ifndef UART1_BAUDRATE
44#define UART1_BAUDRATE 115200
45#endif
46#ifndef UART1_RXBUF_SIZE
47#define UART1_RXBUF_SIZE 64
48#endif
49#endif
50
51#ifdef ENABLE_UART2
52cbuf_t uart2_rx_buf;
53#ifndef UART2_FLOWCONTROL
54#define UART2_FLOWCONTROL USART_HardwareFlowControl_None
55#endif
56#ifndef UART2_BAUDRATE
57#define UART2_BAUDRATE 115200
58#endif
59#ifndef UART2_RXBUF_SIZE
60#define UART2_RXBUF_SIZE 64
61#endif
62#endif
63
64#ifdef ENABLE_UART3
65cbuf_t uart3_rx_buf;
66#ifndef UART3_FLOWCONTROL
67#define UART3_FLOWCONTROL USART_HardwareFlowControl_None
68#endif
69#ifndef UART3_BAUDRATE
70#define UART3_BAUDRATE 115200
71#endif
72#ifndef UART3_RXBUF_SIZE
73#define UART3_RXBUF_SIZE 64
74#endif
75#endif
76
77#ifdef ENABLE_UART6
78cbuf_t uart6_rx_buf;
79#ifndef UART6_FLOWCONTROL
80#define UART6_FLOWCONTROL USART_HardwareFlowControl_None
81#endif
82#ifndef UART6_BAUDRATE
83#define UART6_BAUDRATE 115200
84#endif
85#ifndef UART6_RXBUF_SIZE
86#define UART6_RXBUF_SIZE 64
87#endif
88#endif
89
90static void usart_init1_early(USART_TypeDef *usart, uint32_t baud, uint16_t flowcontrol, int irqn)
91{
92 USART_InitTypeDef init;
93
94 init.USART_BaudRate = baud;
95 init.USART_WordLength = USART_WordLength_8b;
96 init.USART_StopBits = USART_StopBits_1;
97 init.USART_Parity = USART_Parity_No;
98 init.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
99 init.USART_HardwareFlowControl = flowcontrol;
100
101 USART_Init(usart, &init);
102 USART_ITConfig(usart, USART_IT_RXNE, DISABLE);
103 NVIC_DisableIRQ(irqn);
104 USART_Cmd(usart, ENABLE);
105}
106
107static void usart_init1(USART_TypeDef *usart, int irqn, cbuf_t *rxbuf, size_t rxsize)
108{
109 cbuf_initialize(rxbuf, rxsize);
110 USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
111 NVIC_EnableIRQ(irqn);
112 USART_Cmd(usart, ENABLE);
113}
114
115void uart_init_early(void)
116{
117#ifdef ENABLE_UART1
118 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
119 usart_init1_early(USART1, UART1_BAUDRATE, UART1_FLOWCONTROL, USART1_IRQn);
120#endif
121#ifdef ENABLE_UART2
122 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
123 usart_init1_early(USART2, UART2_BAUDRATE, UART2_FLOWCONTROL, USART2_IRQn);
124#endif
125#ifdef ENABLE_UART3
126 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
127 usart_init1_early(USART3, UART3_BAUDRATE, UART3_FLOWCONTROL, USART3_IRQn);
128#endif
129#ifdef ENABLE_UART6
130 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
131 usart_init1_early(USART6, UART6_BAUDRATE, UART6_FLOWCONTROL, USART6_IRQn);
132#endif
133}
134
135void uart_init(void)
136{
137#ifdef ENABLE_UART1
138 usart_init1(USART1, USART1_IRQn, &uart1_rx_buf, UART1_RXBUF_SIZE);
139#endif
140#ifdef ENABLE_UART2
141 usart_init1(USART2, USART2_IRQn, &uart2_rx_buf, UART2_RXBUF_SIZE);
142#endif
143#ifdef ENABLE_UART3
144 usart_init1(USART3, USART3_IRQn, &uart3_rx_buf, UART3_RXBUF_SIZE);
145#endif
146#ifdef ENABLE_UART6
147 usart_init1(USART6, USART6_IRQn, &uart6_rx_buf, UART6_RXBUF_SIZE);
148#endif
149}
150
151void uart_rx_irq(USART_TypeDef *usart, cbuf_t *rxbuf)
152{
153 arm_cm_irq_entry();
154
155 bool resched = false;
156 while (USART_GetFlagStatus(usart, USART_FLAG_RXNE)) {
157 if (!cbuf_space_avail(rxbuf)) {
158 // Overflow - let flow control do its thing by not
159 // reading the from the FIFO.
160 USART_ITConfig(usart, USART_IT_RXNE, DISABLE);
161 break;
162 }
163
164 char c = USART_ReceiveData(usart);
165 cbuf_write_char(rxbuf, c, false);
166 resched = true;
167 }
168
169 arm_cm_irq_exit(resched);
170}
171
172#ifdef ENABLE_UART1
173void stm32_USART1_IRQ(void)
174{
175 uart_rx_irq(USART1, &uart1_rx_buf);
176}
177#endif
178
179#ifdef ENABLE_UART2
180void stm32_USART2_IRQ(void)
181{
182 uart_rx_irq(USART2, &uart2_rx_buf);
183}
184#endif
185
186#ifdef ENABLE_UART3
187void stm32_USART3_IRQ(void)
188{
189 uart_rx_irq(USART3, &uart3_rx_buf);
190}
191#endif
192
193#ifdef ENABLE_UART6
194void stm32_USART6_IRQ(void)
195{
196 uart_rx_irq(USART6, &uart6_rx_buf);
197}
198#endif
199
200static void usart_putc(USART_TypeDef *usart, char c)
201{
202 while (USART_GetFlagStatus(usart, USART_FLAG_TXE) == 0);
203 USART_SendData(usart, c);
204 while (USART_GetFlagStatus(usart, USART_FLAG_TC) == 0);
205}
206
207static int usart_getc(USART_TypeDef *usart, cbuf_t *rxbuf, bool wait)
208{
209 unsigned char c;
210 if (cbuf_read_char(rxbuf, (char*) &c, wait) == 0)
211 return -1;
212 if (cbuf_space_avail(rxbuf) > cbuf_size(rxbuf))
213 USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
214
215 return c;
216}
217
218static USART_TypeDef *get_usart(int port)
219{
220 switch (port) {
221#ifdef ENABLE_UART1
222 case 1: return USART1;
223#endif
224#ifdef ENABLE_UART2
225 case 2: return USART2;
226#endif
227#ifdef ENABLE_UART3
228 case 3: return USART3;
229#endif
230#ifdef ENABLE_UART6
231 case 6: return USART6;
232#endif
233 default:
234 ASSERT(false);
235 return 0;
236 }
237}
238
239static cbuf_t *get_rxbuf(int port)
240{
241 switch (port) {
242#ifdef ENABLE_UART1
243 case 1: return &uart1_rx_buf;
244#endif
245#ifdef ENABLE_UART2
246 case 2: return &uart2_rx_buf;
247#endif
248#ifdef ENABLE_UART3
249 case 3: return &uart3_rx_buf;
250#endif
251#ifdef ENABLE_UART6
252 case 6: return &uart6_rx_buf;
253#endif
254 default:
255 ASSERT(false);
256 return 0;
257 }
258}
259
260int uart_putc(int port, char c)
261{
262 USART_TypeDef *usart = get_usart(port);
263 usart_putc(usart, c);
264 return 1;
265}
266
267int uart_getc(int port, bool wait)
268{
269 cbuf_t *rxbuf = get_rxbuf(port);
270 USART_TypeDef *usart = get_usart(port);
271
272 return usart_getc(usart, rxbuf, wait);
273}
274
275void uart_flush_tx(int port) {}
276
277void uart_flush_rx(int port) {}
278
279void uart_init_port(int port, uint baud) {
280 USART_TypeDef *usart = get_usart(port);
281 uint32_t treg = 0;
282 uint32_t apbclk = 0;
283 uint32_t intdiv = 0;
284 uint32_t fracdiv = 0;
285 RCC_ClocksTypeDef RCC_ClksStat;
286
287 RCC_GetClocksFreq(&RCC_ClksStat);
288
289 if ((usart == USART1) || (usart == USART6)) {
290 apbclk = RCC_ClksStat.PCLK2_Frequency;
291 } else {
292 apbclk = RCC_ClksStat.PCLK1_Frequency;
293 }
294
295 if ((usart->CR1 & USART_CR1_OVER8) != 0) {
296 intdiv = ((25 * apbclk) / (2 * (baud)));
297 } else {
298 intdiv = ((25 * apbclk) / (4 * (baud)));
299 }
300 treg = (intdiv / 100) << 4;
301
302 fracdiv = intdiv - (100 * (treg >> 4));
303
304 if ((usart->CR1 & USART_CR1_OVER8) != 0) {
305 treg |= ((((fracdiv * 8) + 50) / 100)) & ((uint8_t) 0x07);
306 } else {
307 treg |= ((((fracdiv * 16) + 50) / 100)) & ((uint8_t) 0x0F);
308 }
309
310 usart->BRR = (uint16_t) treg;
311}
312
313// inject a character into the console uart rx buffer
314void __debugger_console_putc(char c) {
315 cbuf_t *rxbuf = get_rxbuf(DEBUG_UART);
316 if (rxbuf && cbuf_space_avail(rxbuf)) {
317 cbuf_write_char(rxbuf, c, false);
318 }
319}
320