blob: 08bd77b9a24f77aa7df27f4f128c420a0d08bb44 [file] [log] [blame]
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +02001/*
Patrick Delaunay98b4fb82022-03-02 15:29:08 +01002 * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <errno.h>
9#include <string.h>
10
11#include <common/bl_common.h>
12#include <drivers/delay_timer.h>
13#include <drivers/st/stm32_uart.h>
14#include <drivers/st/stm32_uart_regs.h>
15#include <drivers/st/stm32mp_clkfunc.h>
16#include <lib/mmio.h>
17
18#include <platform_def.h>
19
20/* UART time-out value */
21#define STM32_UART_TIMEOUT_US 20000U
22
23/* Mask to clear ALL the configuration registers */
24
25#define STM32_UART_CR1_FIELDS \
26 (USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \
27 USART_CR1_RE | USART_CR1_OVER8 | USART_CR1_FIFOEN)
28
29#define STM32_UART_CR2_FIELDS \
30 (USART_CR2_SLVEN | USART_CR2_DIS_NSS | USART_CR2_ADDM7 | \
31 USART_CR2_LBDL | USART_CR2_LBDIE | USART_CR2_LBCL | \
32 USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | \
33 USART_CR2_STOP | USART_CR2_LINEN | USART_CR2_SWAP | \
34 USART_CR2_RXINV | USART_CR2_TXINV | USART_CR2_DATAINV | \
35 USART_CR2_MSBFIRST | USART_CR2_ABREN | USART_CR2_ABRMODE | \
36 USART_CR2_RTOEN | USART_CR2_ADD)
37
38#define STM32_UART_CR3_FIELDS \
39 (USART_CR3_EIE | USART_CR3_IREN | USART_CR3_IRLP | \
40 USART_CR3_HDSEL | USART_CR3_NACK | USART_CR3_SCEN | \
41 USART_CR3_DMAR | USART_CR3_DMAT | USART_CR3_RTSE | \
42 USART_CR3_CTSE | USART_CR3_CTSIE | USART_CR3_ONEBIT | \
43 USART_CR3_OVRDIS | USART_CR3_DDRE | USART_CR3_DEM | \
44 USART_CR3_DEP | USART_CR3_SCARCNT | USART_CR3_WUS | \
45 USART_CR3_WUFIE | USART_CR3_TXFTIE | USART_CR3_TCBGTIE | \
46 USART_CR3_RXFTCFG | USART_CR3_RXFTIE | USART_CR3_TXFTCFG)
47
48#define STM32_UART_ISR_ERRORS \
49 (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE | USART_ISR_PE)
50
51static const uint16_t presc_table[STM32_UART_PRESCALER_NB] = {
52 1U, 2U, 4U, 6U, 8U, 10U, 12U, 16U, 32U, 64U, 128U, 256U
53};
54
55/* @brief BRR division operation to set BRR register in 8-bit oversampling
56 * mode.
57 * @param clockfreq: UART clock.
58 * @param baud_rate: Baud rate set by the user.
59 * @param prescaler: UART prescaler value.
60 * @retval Division result.
61 */
62static uint32_t uart_div_sampling8(unsigned long clockfreq,
63 uint32_t baud_rate,
64 uint32_t prescaler)
65{
66 uint32_t scaled_freq = clockfreq / presc_table[prescaler];
67
68 return ((scaled_freq * 2) + (baud_rate / 2)) / baud_rate;
69
70}
71
72/* @brief BRR division operation to set BRR register in 16-bit oversampling
73 * mode.
74 * @param clockfreq: UART clock.
75 * @param baud_rate: Baud rate set by the user.
76 * @param prescaler: UART prescaler value.
77 * @retval Division result.
78 */
79static uint32_t uart_div_sampling16(unsigned long clockfreq,
80 uint32_t baud_rate,
81 uint32_t prescaler)
82{
83 uint32_t scaled_freq = clockfreq / presc_table[prescaler];
84
85 return (scaled_freq + (baud_rate / 2)) / baud_rate;
86
87}
88
89/*
90 * @brief Return the UART clock frequency.
91 * @param huart: UART handle.
92 * @retval Frequency value in Hz.
93 */
94static unsigned long uart_get_clock_freq(struct stm32_uart_handle_s *huart)
95{
96 return fdt_get_uart_clock_freq((uintptr_t)huart->base);
97}
98
99/*
100 * @brief Configure the UART peripheral.
101 * @param huart: UART handle.
102 * @retval UART status.
103 */
104static int uart_set_config(struct stm32_uart_handle_s *huart,
105 const struct stm32_uart_init_s *init)
106{
107 uint32_t tmpreg;
108 unsigned long clockfreq;
Patrick Delaunay98b4fb82022-03-02 15:29:08 +0100109 unsigned long int_div;
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200110 uint32_t brrtemp;
Patrick Delaunay98b4fb82022-03-02 15:29:08 +0100111 uint32_t over_sampling;
112
113 /*---------------------- USART BRR configuration --------------------*/
114 clockfreq = uart_get_clock_freq(huart);
115 if (clockfreq == 0UL) {
116 return -ENODEV;
117 }
118
119 int_div = clockfreq / init->baud_rate;
120 if (int_div < 16U) {
121 uint32_t usartdiv = uart_div_sampling8(clockfreq,
122 init->baud_rate,
123 init->prescaler);
124
125 brrtemp = (usartdiv & USART_BRR_DIV_MANTISSA) |
126 ((usartdiv & USART_BRR_DIV_FRACTION) >> 1);
127 over_sampling = USART_CR1_OVER8;
128 } else {
129 brrtemp = uart_div_sampling16(clockfreq,
130 init->baud_rate,
131 init->prescaler) &
132 (USART_BRR_DIV_FRACTION | USART_BRR_DIV_MANTISSA);
133 over_sampling = 0x0U;
134 }
135 mmio_write_32(huart->base + USART_BRR, brrtemp);
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200136
137 /*
138 * ---------------------- USART CR1 Configuration --------------------
139 * Clear M, PCE, PS, TE, RE and OVER8 bits and configure
140 * the UART word length, parity, mode and oversampling:
141 * - set the M bits according to init->word_length value,
142 * - set PCE and PS bits according to init->parity value,
143 * - set TE and RE bits according to init->mode value,
Patrick Delaunay98b4fb82022-03-02 15:29:08 +0100144 * - set OVER8 bit according baudrate and clock.
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200145 */
146 tmpreg = init->word_length |
147 init->parity |
148 init->mode |
Patrick Delaunay98b4fb82022-03-02 15:29:08 +0100149 over_sampling |
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200150 init->fifo_mode;
151 mmio_clrsetbits_32(huart->base + USART_CR1, STM32_UART_CR1_FIELDS, tmpreg);
152
153 /*
154 * --------------------- USART CR2 Configuration ---------------------
155 * Configure the UART Stop Bits: Set STOP[13:12] bits according
156 * to init->stop_bits value.
157 */
158 mmio_clrsetbits_32(huart->base + USART_CR2, STM32_UART_CR2_FIELDS,
159 init->stop_bits);
160
161 /*
162 * --------------------- USART CR3 Configuration ---------------------
163 * Configure:
164 * - UART HardWare Flow Control: set CTSE and RTSE bits according
165 * to init->hw_flow_control value,
166 * - one-bit sampling method versus three samples' majority rule
167 * according to init->one_bit_sampling (not applicable to
168 * LPUART),
169 * - set TXFTCFG bit according to init->tx_fifo_threshold value,
170 * - set RXFTCFG bit according to init->rx_fifo_threshold value.
171 */
172 tmpreg = init->hw_flow_control | init->one_bit_sampling;
173
174 if (init->fifo_mode == USART_CR1_FIFOEN) {
175 tmpreg |= init->tx_fifo_threshold |
176 init->rx_fifo_threshold;
177 }
178
179 mmio_clrsetbits_32(huart->base + USART_CR3, STM32_UART_CR3_FIELDS, tmpreg);
180
181 /*
182 * --------------------- USART PRESC Configuration -------------------
183 * Configure UART Clock Prescaler : set PRESCALER according to
184 * init->prescaler value.
185 */
186 assert(init->prescaler < STM32_UART_PRESCALER_NB);
187 mmio_clrsetbits_32(huart->base + USART_PRESC, USART_PRESC_PRESCALER,
188 init->prescaler);
189
Nicolas Le Bayondc08ebe2019-09-11 11:46:40 +0200190 return 0;
191}
192
193/*
194 * @brief Handle UART communication timeout.
195 * @param huart: UART handle.
196 * @param flag: Specifies the UART flag to check.
197 * @retval UART status.
198 */
199static int stm32_uart_wait_flag(struct stm32_uart_handle_s *huart, uint32_t flag)
200{
201 uint64_t timeout_ref = timeout_init_us(STM32_UART_TIMEOUT_US);
202
203 while ((mmio_read_32(huart->base + USART_ISR) & flag) == 0U) {
204 if (timeout_elapsed(timeout_ref)) {
205 return -ETIMEDOUT;
206 }
207 }
208
209 return 0;
210}
211
212/*
213 * @brief Check the UART idle State.
214 * @param huart: UART handle.
215 * @retval UART status.
216 */
217static int stm32_uart_check_idle(struct stm32_uart_handle_s *huart)
218{
219 int ret;
220
221 /* Check if the transmitter is enabled */
222 if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_TE) == USART_CR1_TE) {
223 ret = stm32_uart_wait_flag(huart, USART_ISR_TEACK);
224 if (ret != 0) {
225 return ret;
226 }
227 }
228
229 /* Check if the receiver is enabled */
230 if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_RE) == USART_CR1_RE) {
231 ret = stm32_uart_wait_flag(huart, USART_ISR_REACK);
232 if (ret != 0) {
233 return ret;
234 }
235 }
236
237 return 0;
238}
239
240/*
241 * @brief Compute RDR register mask depending on word length.
242 * @param huart: UART handle.
243 * @retval Mask value.
244 */
245static unsigned int stm32_uart_rdr_mask(const struct stm32_uart_init_s *init)
246{
247 unsigned int mask = 0U;
248
249 switch (init->word_length) {
250 case STM32_UART_WORDLENGTH_9B:
251 mask = GENMASK(8, 0);
252 break;
253 case STM32_UART_WORDLENGTH_8B:
254 mask = GENMASK(7, 0);
255 break;
256 case STM32_UART_WORDLENGTH_7B:
257 mask = GENMASK(6, 0);
258 break;
259 default:
260 break; /* not reached */
261 }
262
263 if (init->parity != STM32_UART_PARITY_NONE) {
264 mask >>= 1;
265 }
266
267 return mask;
268}
269
270/*
271 * @brief Check interrupt and status errors.
272 * @retval True if error detected, false otherwise.
273 */
274static bool stm32_uart_error_detected(struct stm32_uart_handle_s *huart)
275{
276 return (mmio_read_32(huart->base + USART_ISR) & STM32_UART_ISR_ERRORS) != 0U;
277}
278
279/*
280 * @brief Clear status errors.
281 */
282static void stm32_uart_error_clear(struct stm32_uart_handle_s *huart)
283{
284 mmio_write_32(huart->base + USART_ICR, STM32_UART_ISR_ERRORS);
285}
286
287/*
288 * @brief Stop the UART.
289 * @param base: UART base address.
290 */
291void stm32_uart_stop(uintptr_t base)
292{
293 mmio_clrbits_32(base + USART_CR1, USART_CR1_UE);
294}
295
296/*
297 * @brief Initialize UART.
298 * @param huart: UART handle.
299 * @param base_addr: base address of UART.
300 * @param init: UART initialization parameter.
301 * @retval UART status.
302 */
303
304int stm32_uart_init(struct stm32_uart_handle_s *huart,
305 uintptr_t base_addr,
306 const struct stm32_uart_init_s *init)
307{
308 int ret;
309
310 if (huart == NULL || init == NULL || base_addr == 0U) {
311 return -EINVAL;
312 }
313
314 huart->base = base_addr;
315
316 /* Disable the peripheral */
317 stm32_uart_stop(huart->base);
318
319 /* Computation of UART mask to apply to RDR register */
320 huart->rdr_mask = stm32_uart_rdr_mask(init);
321
322 /* Init the peripheral */
323 ret = uart_set_config(huart, init);
324 if (ret != 0) {
325 return ret;
326 }
327
328 /* Enable the peripheral */
329 mmio_setbits_32(huart->base + USART_CR1, USART_CR1_UE);
330
331 /* TEACK and/or REACK to check */
332 return stm32_uart_check_idle(huart);
333}
334
335/*
336 * @brief Transmit one data in no blocking mode.
337 * @param huart: UART handle.
338 * @param c: data to sent.
339 * @retval UART status.
340 */
341int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c)
342{
343 int ret;
344
345 if (huart == NULL) {
346 return -EINVAL;
347 }
348
349 ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
350 if (ret != 0) {
351 return ret;
352 }
353
354 mmio_write_32(huart->base + USART_TDR, c);
355 if (stm32_uart_error_detected(huart)) {
356 stm32_uart_error_clear(huart);
357 return -EFAULT;
358 }
359
360 return 0;
361}
362
363/*
364 * @brief Flush TX Transmit fifo
365 * @param huart: UART handle.
366 * @retval UART status.
367 */
368int stm32_uart_flush(struct stm32_uart_handle_s *huart)
369{
370 int ret;
371
372 if (huart == NULL) {
373 return -EINVAL;
374 }
375
376 ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
377 if (ret != 0) {
378 return ret;
379 }
380
381 return stm32_uart_wait_flag(huart, USART_ISR_TC);
382}
383
384/*
385 * @brief Receive a data in no blocking mode.
386 * @retval value if >0 or UART status.
387 */
388int stm32_uart_getc(struct stm32_uart_handle_s *huart)
389{
390 uint32_t data;
391
392 if (huart == NULL) {
393 return -EINVAL;
394 }
395
396 /* Check if data is available */
397 if ((mmio_read_32(huart->base + USART_ISR) & USART_ISR_RXNE) == 0U) {
398 return -EAGAIN;
399 }
400
401 data = mmio_read_32(huart->base + USART_RDR) & huart->rdr_mask;
402
403 if (stm32_uart_error_detected(huart)) {
404 stm32_uart_error_clear(huart);
405 return -EFAULT;
406 }
407
408 return (int)data;
409}