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