diff options
Diffstat (limited to 'drivers/serial/serial_stm32.c')
-rw-r--r-- | drivers/serial/serial_stm32.c | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index 2ba92bf9c48..0085113f674 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -18,6 +18,7 @@ #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/delay.h> +#include <linux/iopoll.h> #include "serial_stm32.h" #include <dm/device_compat.h> @@ -28,6 +29,10 @@ static void _stm32_serial_setbrg(fdt_addr_t base, { bool stm32f4 = uart_info->stm32f4; u32 int_div, mantissa, fraction, oversampling; + u8 uart_enable_bit = uart_info->uart_enable_bit; + + /* BRR register must be set when uart is disabled */ + clrbits_le32(base + CR1_OFFSET(stm32f4), BIT(uart_enable_bit)); int_div = DIV_ROUND_CLOSEST(clock_rate, baudrate); @@ -43,6 +48,8 @@ static void _stm32_serial_setbrg(fdt_addr_t base, fraction = int_div % oversampling; writel(mantissa | fraction, base + BRR_OFFSET(stm32f4)); + + setbits_le32(base + CR1_OFFSET(stm32f4), BIT(uart_enable_bit)); } static int stm32_serial_setbrg(struct udevice *dev, int baudrate) @@ -181,9 +188,12 @@ static int stm32_serial_probe(struct udevice *dev) struct stm32x7_serial_plat *plat = dev_get_plat(dev); struct clk clk; struct reset_ctl reset; + u32 isr; int ret; + bool stm32f4; plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev); + stm32f4 = plat->uart_info->stm32f4; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) @@ -195,6 +205,17 @@ static int stm32_serial_probe(struct udevice *dev) return ret; } + /* + * before uart initialization, wait for TC bit (Transmission Complete) + * in case there is still chars from previous bootstage to transmit + */ + ret = read_poll_timeout(readl, isr, isr & USART_ISR_TC, 10, 150, + plat->base + ISR_OFFSET(stm32f4)); + if (ret) { + clk_disable(&clk); + return ret; + } + ret = reset_get_by_index(dev, 0, &reset); if (!ret) { reset_assert(&reset); |