From 60a996bacb74052f7e3966a875dfdebee036d446 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 27 Sep 2017 15:44:50 +0200 Subject: [PATCH] serial: stm32x7: prepare the ground to STM32F4 support STM32F4 serial IP is similar to F7 and H7, but registers are not located at the same offset and some feature are only supported by F7 and H7 version. Registers offset must be added for each version and also some flags indicated the supported feature. Update registers name to match with datasheet (sr to isr, rx_dr to rdr and tx_dr to tdr) and remove unused regs (cr2, gtpr, rtor, and rqr). Signed-off-by: Patrice Chotard --- drivers/serial/serial_stm32x7.c | 72 ++++++++++++++++++++++++----------------- drivers/serial/serial_stm32x7.h | 38 ++++++++++++++-------- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c index bafcc36..81a2308 100644 --- a/drivers/serial/serial_stm32x7.c +++ b/drivers/serial/serial_stm32x7.c @@ -17,67 +17,79 @@ DECLARE_GLOBAL_DATA_PTR; static int stm32_serial_setbrg(struct udevice *dev, int baudrate) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; u32 int_div, mantissa, fraction, oversampling; int_div = DIV_ROUND_CLOSEST(plat->clock_rate, baudrate); if (int_div < 16) { oversampling = 8; - setbits_le32(&usart->cr1, USART_CR1_OVER8); + setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8); } else { oversampling = 16; - clrbits_le32(&usart->cr1, USART_CR1_OVER8); + clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8); } mantissa = (int_div / oversampling) << USART_BRR_M_SHIFT; fraction = int_div % oversampling; - writel(mantissa | fraction, &usart->brr); + writel(mantissa | fraction, base + BRR_OFFSET(stm32f4)); return 0; } static int stm32_serial_getc(struct udevice *dev) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; - if ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0) + if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_RXNE) == 0) return -EAGAIN; - return readl(&usart->rd_dr); + return readl(base + RDR_OFFSET(stm32f4)); } static int stm32_serial_putc(struct udevice *dev, const char c) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; - if ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0) + if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_TXE) == 0) return -EAGAIN; - writel(c, &usart->tx_dr); + writel(c, base + TDR_OFFSET(stm32f4)); return 0; } static int stm32_serial_pending(struct udevice *dev, bool input) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; if (input) - return readl(&usart->sr) & USART_SR_FLAG_RXNE ? 1 : 0; + return readl(base + ISR_OFFSET(stm32f4)) & + USART_SR_FLAG_RXNE ? 1 : 0; else - return readl(&usart->sr) & USART_SR_FLAG_TXE ? 0 : 1; + return readl(base + ISR_OFFSET(stm32f4)) & + USART_SR_FLAG_TXE ? 0 : 1; } static int stm32_serial_probe(struct udevice *dev) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + fdt_addr_t base = plat->base; + bool stm32f4; + u8 uart_enable_bit; + + plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev); + stm32f4 = plat->uart_info->stm32f4; + uart_enable_bit = plat->uart_info->uart_enable_bit; #ifdef CONFIG_CLK int ret; @@ -100,32 +112,32 @@ static int stm32_serial_probe(struct udevice *dev) return plat->clock_rate; }; - /* Disable usart-> disable overrun-> enable usart */ - clrbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); - setbits_le32(&usart->cr3, USART_CR3_OVRDIS); - setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); + /* Disable uart-> disable overrun-> enable uart */ + clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | + BIT(uart_enable_bit)); + if (plat->uart_info->has_overrun_disable) + setbits_le32(base + CR3_OFFSET(stm32f4), USART_CR3_OVRDIS); + setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | + BIT(uart_enable_bit)); return 0; } #if CONFIG_IS_ENABLED(OF_CONTROL) static const struct udevice_id stm32_serial_id[] = { - {.compatible = "st,stm32f7-uart"}, - {.compatible = "st,stm32h7-uart"}, + { .compatible = "st,stm32f7-uart", .data = (ulong)&stm32x7_info}, + { .compatible = "st,stm32h7-uart", .data = (ulong)&stm32x7_info}, {} }; static int stm32_serial_ofdata_to_platdata(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); - fdt_addr_t addr; - addr = devfdt_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) + plat->base = devfdt_get_addr(dev); + if (plat->base == FDT_ADDR_T_NONE) return -EINVAL; - plat->base = (struct stm32_usart *)addr; - return 0; } #endif diff --git a/drivers/serial/serial_stm32x7.h b/drivers/serial/serial_stm32x7.h index 6d36b74..4c6b7d4 100644 --- a/drivers/serial/serial_stm32x7.h +++ b/drivers/serial/serial_stm32x7.h @@ -8,30 +8,40 @@ #ifndef _SERIAL_STM32_X7_ #define _SERIAL_STM32_X7_ -struct stm32_usart { - u32 cr1; - u32 cr2; - u32 cr3; - u32 brr; - u32 gtpr; - u32 rtor; - u32 rqr; - u32 sr; - u32 icr; - u32 rd_dr; - u32 tx_dr; +#define CR1_OFFSET(x) (x ? 0x0c : 0x00) +#define CR3_OFFSET(x) (x ? 0x14 : 0x08) +#define BRR_OFFSET(x) (x ? 0x08 : 0x0c) +#define ISR_OFFSET(x) (x ? 0x00 : 0x1c) +/* + * STM32F4 has one Data Register (DR) for received or transmitted + * data, so map Receive Data Register (RDR) and Transmit Data + * Register (TDR) at the same offset + */ +#define RDR_OFFSET(x) (x ? 0x04 : 0x24) +#define TDR_OFFSET(x) (x ? 0x04 : 0x28) + +struct stm32_uart_info { + u8 uart_enable_bit; /* UART_CR1_UE */ + bool stm32f4; /* true for STM32F4, false otherwise */ + bool has_overrun_disable; +}; + +struct stm32_uart_info stm32x7_info = { + .uart_enable_bit = 0, + .stm32f4 = false, + .has_overrun_disable = true, }; /* Information about a serial port */ struct stm32x7_serial_platdata { - struct stm32_usart *base; /* address of registers in physical memory */ + fdt_addr_t base; /* address of registers in physical memory */ + struct stm32_uart_info *uart_info; unsigned long int clock_rate; }; #define USART_CR1_OVER8 BIT(15) #define USART_CR1_TE BIT(3) #define USART_CR1_RE BIT(2) -#define USART_CR1_UE BIT(0) #define USART_CR3_OVRDIS BIT(12) -- 2.7.4