serial: stm32: Add setparity support

Add possibility to update the serial parity used.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index eeaa8ab..f262345 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -47,6 +47,45 @@
 	return 0;
 }
 
+static int stm32_serial_setparity(struct udevice *dev, enum serial_par parity)
+{
+	struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
+	bool stm32f4 = plat->uart_info->stm32f4;
+	u8 uart_enable_bit = plat->uart_info->uart_enable_bit;
+	u32 cr1 = plat->base + CR1_OFFSET(stm32f4);
+	u32 config = 0;
+
+	if (stm32f4)
+		return -EINVAL; /* not supported in driver*/
+
+	clrbits_le32(cr1, USART_CR1_RE | USART_CR1_TE | BIT(uart_enable_bit));
+	/* update usart configuration (uart need to be disable)
+	 * PCE: parity check control
+	 * PS : '0' : Even / '1' : Odd
+	 * M[1:0] = '00' : 8 Data bits
+	 * M[1:0] = '01' : 9 Data bits with parity
+	 */
+	switch (parity) {
+	default:
+	case SERIAL_PAR_NONE:
+		config = 0;
+		break;
+	case SERIAL_PAR_ODD:
+		config = USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0;
+		break;
+	case SERIAL_PAR_EVEN:
+		config = USART_CR1_PCE | USART_CR1_M0;
+		break;
+	}
+	clrsetbits_le32(cr1,
+			USART_CR1_PCE | USART_CR1_PS | USART_CR1_M1 |
+			USART_CR1_M0,
+			config);
+	setbits_le32(cr1, USART_CR1_RE | USART_CR1_TE | BIT(uart_enable_bit));
+
+	return 0;
+}
+
 static int stm32_serial_getc(struct udevice *dev)
 {
 	struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
@@ -57,9 +96,10 @@
 	if ((isr & USART_ISR_RXNE) == 0)
 		return -EAGAIN;
 
-	if (isr & (USART_ISR_ORE)) {
+	if (isr & (USART_ISR_PE | USART_ISR_ORE)) {
 		if (!stm32f4)
-			setbits_le32(base + ICR_OFFSET, USART_ICR_ORECF);
+			setbits_le32(base + ICR_OFFSET,
+				     USART_ICR_PCECF | USART_ICR_ORECF);
 		else
 			readl(base + RDR_OFFSET(stm32f4));
 		return -EIO;
@@ -170,6 +210,7 @@
 	.pending = stm32_serial_pending,
 	.getc = stm32_serial_getc,
 	.setbrg = stm32_serial_setbrg,
+	.setparity = stm32_serial_setparity
 };
 
 U_BOOT_DRIVER(serial_stm32) = {
diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h
index c478e35..ccafa31 100644
--- a/drivers/serial/serial_stm32.h
+++ b/drivers/serial/serial_stm32.h
@@ -13,6 +13,7 @@
 #define ISR_OFFSET(x)	(x ? 0x00 : 0x1c)
 
 #define ICR_OFFSET	0x20
+
 /*
  * STM32F4 has one Data Register (DR) for received or transmitted
  * data, so map Receive Data Register (RDR) and Transmit Data
@@ -53,7 +54,11 @@
 };
 
 #define USART_CR1_FIFOEN		BIT(29)
+#define USART_CR1_M1			BIT(28)
 #define USART_CR1_OVER8			BIT(15)
+#define USART_CR1_M0			BIT(12)
+#define USART_CR1_PCE			BIT(10)
+#define USART_CR1_PS			BIT(9)
 #define USART_CR1_TE			BIT(3)
 #define USART_CR1_RE			BIT(2)
 
@@ -62,10 +67,13 @@
 #define USART_ISR_TXE			BIT(7)
 #define USART_ISR_RXNE			BIT(5)
 #define USART_ISR_ORE			BIT(3)
+#define USART_ISR_PE			BIT(0)
 
 #define USART_BRR_F_MASK		GENMASK(7, 0)
 #define USART_BRR_M_SHIFT		4
 #define USART_BRR_M_MASK		GENMASK(15, 4)
 
 #define USART_ICR_ORECF			BIT(3)
+#define USART_ICR_PCECF			BIT(0)
+
 #endif