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