Re: [PATCH v2] serial: stm32: optimize spin lock usage

2021-04-15 Thread Erwan LE RAY

Hi Dillon,

STM32MP151 is mono-core, but both STM32MP153 and STM32MP157 are 
dual-core (see 
https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-arm-cortex-mpus.html).

So your point is fully relevant, thanks.

ST already fixed the same issue in st-asc.c driver in the past (see 
ef49ffd8), because a systematic deadlock was detected with RT kernel.


You proposed a first implementation in your patch, and a second one in 
the discussion. It seems that your initial proposal (ie your V2 patch) 
is the most standard one (implemented in 6 drivers). The second 
implementation is implemented by only 1 company.


It looks that the solution is to avoid locking in the sysrq case and 
trylock in the oops_in_progress case (see detailed analysis in 
677fe555cbfb1).


So your initial patch looks to the right proposal, but it would be safer 
if Greg could confirm it.


BR, Erwan.


On 4/13/21 1:44 AM, dillon min wrote:

Hi Johan, Erwan

It seems still a bit of a problem in the current version, not deadlock
but access register at the same time.

For driver , we should consider it running under smp, let's think
about it for this case:

static void stm32_usart_console_write(struct console *co, const char *s,
   unsigned int cnt)
{
  .
  local_irq_save(flags);
  if (port->sysrq)
 locked = 0;
  .
  access register cr1, tdr, isr
  .

  local_irq_restore(flags);
}

if port->sysrq is 1, stm32_usart_console_write() just disable local
irq response by local_irq_save(), at the time of access register cr1,
tdr, isr. an TXE interrupt raised, for other cores(I know stm32
mpu/mcu do not have multi cores, just assume it has), it still has a
chance to handle interrupt.  Then there is no lock to protect the uart
register.

changes to below, should be more safe:

.
if (port->sysrq || oops_in_progress)
   locked = spin_trylock_irqsave(>lock, flags);
else
   spin_lock_irqsave(>lock, flags);



if (locked)
  spin_unlock_irqrestore(>lock, flags);

For current stm32 soc, it shouldn't happen. just a reminder for future.

Thanks.

Dillon

On Mon, Apr 12, 2021 at 10:04 PM dillon min  wrote:


Hi Johan,

Yes, there is no deadlock. my fault.
I forget the local_irq_save() plus spin_lock() is spin_lock_irqsave().

Thanks for your review. please ignore this patch.

Best regards

Dillon

On Mon, Apr 12, 2021 at 9:08 PM Johan Hovold  wrote:


On Mon, Apr 12, 2021 at 05:31:38PM +0800, dillon.min...@gmail.com wrote:

From: dillon min 

To avoid potential deadlock in spin_lock usage, use spin_lock_irqsave,
spin_trylock_irqsave(), spin_unlock_irqrestore() in process context.


This doesn't make much sense as console_write can be called in any
context. And where's the deadlock you claim to be fixing here?


remove unused local_irq_save/restore call.

Cc: Alexandre Torgue 
Cc: Maxime Coquelin 
Cc: Gerald Baeza 
Cc: Erwan Le Ray 
Reported-by: kernel test robot 
Signed-off-by: dillon min 
---
v2: remove unused code from stm32_usart_threaded_interrupt() according from
 Greg's review.

  drivers/tty/serial/stm32-usart.c | 8 +++-
  1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index b3675cf25a69..b1ba5e36e36e 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1354,13 +1354,12 @@ static void stm32_usart_console_write(struct console 
*co, const char *s,
   u32 old_cr1, new_cr1;
   int locked = 1;

- local_irq_save(flags);
   if (port->sysrq)
   locked = 0;
   else if (oops_in_progress)
- locked = spin_trylock(>lock);
+ locked = spin_trylock_irqsave(>lock, flags);
   else
- spin_lock(>lock);
+ spin_lock_irqsave(>lock, flags);

   /* Save and disable interrupts, enable the transmitter */
   old_cr1 = readl_relaxed(port->membase + ofs->cr1);
@@ -1374,8 +1373,7 @@ static void stm32_usart_console_write(struct console *co, 
const char *s,
   writel_relaxed(old_cr1, port->membase + ofs->cr1);

   if (locked)
- spin_unlock(>lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(>lock, flags);
  }

  static int stm32_usart_console_setup(struct console *co, char *options)


Johan


[PATCH v2 1/4] dt-bindings: serial: add RX and TX FIFO properties

2021-04-13 Thread Erwan Le Ray
Add two optional DT properties to configure RX and TX FIFO thresholds:
- rx-threshold
- tx-threshold

Signed-off-by: Erwan Le Ray 

diff --git a/Documentation/devicetree/bindings/serial/serial.yaml 
b/Documentation/devicetree/bindings/serial/serial.yaml
index 65e75d040521..f368d58e8086 100644
--- a/Documentation/devicetree/bindings/serial/serial.yaml
+++ b/Documentation/devicetree/bindings/serial/serial.yaml
@@ -75,6 +75,16 @@ properties:
 type: boolean
 description: CTS and RTS pins are swapped.
 
+  rx-threshold:
+$ref: /schemas/types.yaml#/definitions/uint32
+description:
+  RX FIFO threshold configuration (in bytes).
+
+  tx-threshold:
+$ref: /schemas/types.yaml#/definitions/uint32
+description:
+  TX FIFO threshold configuration (in bytes).
+
 if:
   required:
 - uart-has-rtscts
-- 
2.17.1



[PATCH v2 3/4] dt-bindings: serial: 8250: update TX FIFO trigger level

2021-04-13 Thread Erwan Le Ray
Remove data type from tx-threshold trigger level as defined now as a
serial generic property.

Signed-off-by: Erwan Le Ray 

diff --git a/Documentation/devicetree/bindings/serial/8250.yaml 
b/Documentation/devicetree/bindings/serial/8250.yaml
index c0e292cdaa6b..ff0fa9b2a390 100644
--- a/Documentation/devicetree/bindings/serial/8250.yaml
+++ b/Documentation/devicetree/bindings/serial/8250.yaml
@@ -166,7 +166,6 @@ properties:
   property.
 
   tx-threshold:
-$ref: /schemas/types.yaml#/definitions/uint32
 description: |
   Specify the TX FIFO low water indication for parts with programmable
   TX FIFO thresholds.
-- 
2.17.1



[PATCH v2 0/4] stm32 usart add fifo threshold configuration

2021-04-13 Thread Erwan Le Ray
This series adds the support for two optional DT properties to configure
RX and TX FIFO thresholds:
 - rx-threshold
 - tx-threshold
This replaces hard-coded 8 bytes threshold. No functional change expected
if unspecified (keep 8 as default).

Changes in v2:
Change added properties naming and factorize it in serial.yaml as proposed
by Rob Herring. 

Erwan Le Ray (3):
  dt-bindings: serial: add RX and TX FIFO properties
  dt-bindings: serial: stm32: override FIFO threshold properties
  dt-bindings: serial: 8250: update TX FIFO trigger level

Fabrice Gasnier (1):
  serial: stm32: add FIFO threshold configuration

 .../devicetree/bindings/serial/8250.yaml  |  1 -
 .../devicetree/bindings/serial/serial.yaml| 10 
 .../bindings/serial/st,stm32-uart.yaml| 27 +-
 drivers/tty/serial/stm32-usart.c  | 53 ---
 drivers/tty/serial/stm32-usart.h  |  8 +--
 5 files changed, 85 insertions(+), 14 deletions(-)

-- 
2.17.1



[PATCH v2 2/4] dt-bindings: serial: stm32: override FIFO threshold properties

2021-04-13 Thread Erwan Le Ray
Override rx-threshold and tx-threshold properties:
- extend description
- provide default and expected values

Signed-off-by: Fabrice Gasnier 
Signed-off-by: Erwan Le Ray 

Changes in v2:
Change added properties naming and factorize it in serial.yaml as proposed
by Rob Herring.

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml 
b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
index c69f8464cdf3..71a6426bc558 100644
--- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
@@ -65,6 +65,18 @@ properties:
   linux,rs485-enabled-at-boot-time: true
   rs485-rx-during-tx: true
 
+  rx-threshold:
+description:
+  If value is set to 1, RX FIFO threshold is disabled.
+enum: [1, 2, 4, 8, 12, 14, 16]
+default: 8
+
+  tx-threshold:
+description:
+  If value is set to 1, TX FIFO threshold is disabled.
+enum: [1, 2, 4, 8, 12, 14, 16]
+default: 8
+
 allOf:
   - $ref: rs485.yaml#
   - $ref: serial.yaml#
@@ -82,6 +94,17 @@ allOf:
 then:
   properties:
 rx-tx-swap: false
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - st,stm32-uart
+  - st,stm32f7-uart
+then:
+  properties:
+rx-threshold: false
+tx-threshold: false
 
 required:
   - compatible
@@ -96,13 +119,15 @@ examples:
   - |
 #include 
 usart1: serial@40011000 {
-  compatible = "st,stm32-uart";
+  compatible = "st,stm32h7-uart";
   reg = <0x40011000 0x400>;
   interrupts = <37>;
   clocks = < 0 164>;
   dmas = < 2 4 0x414 0x0>,
  < 7 4 0x414 0x0>;
   dma-names = "rx", "tx";
+  rx-threshold = <4>;
+  tx-threshold = <4>;
   rs485-rts-active-low;
 };
 
-- 
2.17.1



[PATCH v2 4/4] serial: stm32: add FIFO threshold configuration

2021-04-13 Thread Erwan Le Ray
From: Fabrice Gasnier 

Add the support for two optional DT properties, to configure RX and TX
FIFO thresholds:
- rx-threshold
- tx-threshold
This replaces hard-coded 8 bytes threshold. Keep 8 as the default value if
not specified, for backward compatibility.

Signed-off-by: Fabrice Gasnier 
Signed-off-by: Erwan Le Ray 

Changes in v2:
Change added properties naming as proposed by Rob Herring.

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 4d277804c63e..409cfd15a933 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -312,7 +312,7 @@ static void stm32_usart_tx_interrupt_enable(struct 
uart_port *port)
 * Enables TX FIFO threashold irq when FIFO is enabled,
 * or TX empty irq when FIFO is disabled
 */
-   if (stm32_port->fifoen)
+   if (stm32_port->fifoen && stm32_port->txftcfg >= 0)
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE);
else
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
@@ -323,7 +323,7 @@ static void stm32_usart_tx_interrupt_disable(struct 
uart_port *port)
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
 
-   if (stm32_port->fifoen)
+   if (stm32_port->fifoen && stm32_port->txftcfg >= 0)
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE);
else
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
@@ -801,9 +801,10 @@ static void stm32_usart_set_termios(struct uart_port *port,
cr3 = readl_relaxed(port->membase + ofs->cr3);
cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE;
if (stm32_port->fifoen) {
-   cr3 &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
-   cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
-   cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
+   if (stm32_port->txftcfg >= 0)
+   cr3 |= stm32_port->txftcfg << USART_CR3_TXFTCFG_SHIFT;
+   if (stm32_port->rxftcfg >= 0)
+   cr3 |= stm32_port->rxftcfg << USART_CR3_RXFTCFG_SHIFT;
}
 
if (cflag & CSTOPB)
@@ -833,7 +834,8 @@ static void stm32_usart_set_termios(struct uart_port *port,
, bits);
 
if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch ||
-  stm32_port->fifoen)) {
+  (stm32_port->fifoen &&
+   stm32_port->rxftcfg >= 0))) {
if (cflag & CSTOPB)
bits = bits + 3; /* 1 start bit + 2 stop bits */
else
@@ -1021,6 +1023,39 @@ static const struct uart_ops stm32_uart_ops = {
.verify_port= stm32_usart_verify_port,
 };
 
+/*
+ * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG)
+ * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case,
+ * RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE.
+ * So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1.
+ */
+static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 };
+
+static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p,
+ int *ftcfg)
+{
+   u32 bytes, i;
+
+   /* DT option to get RX & TX FIFO threshold (default to 8 bytes) */
+   if (of_property_read_u32(pdev->dev.of_node, p, ))
+   bytes = 8;
+
+   for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++)
+   if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes)
+   break;
+   if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg))
+   i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1;
+
+   dev_dbg(>dev, "%s set to %d bytes\n", p,
+   stm32h7_usart_fifo_thresh_cfg[i]);
+
+   /* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */
+   if (i)
+   *ftcfg = i - 1;
+   else
+   *ftcfg = -EINVAL;
+}
+
 static void stm32_usart_deinit_port(struct stm32_port *stm32port)
 {
clk_disable_unprepare(stm32port->clk);
@@ -1057,6 +1092,12 @@ static int stm32_usart_init_port(struct stm32_port 
*stm32port,
of_property_read_bool(pdev->dev.of_node, "rx-tx-swap");
 
stm32port->fifoen = stm32port->info->cfg.has_fifo;
+   if (stm32port->fifoen) {
+   stm32_usart_get_ftcfg(pdev, "rx-threshold",
+ >rxftcfg);
+   stm32_usart_get_ftcfg(pdev, "tx-threshold",
+ >txftcfg);

Re: [Linux-stm32] [PATCH] serial: stm32: optimize spin lock usage

2021-04-12 Thread Erwan LE RAY

Hi Dillon,

Thanks for your patch.

Could you please elaborate the use case in your commit message ?

Best Regards, Erwan.

On 4/12/21 10:54 AM, dillon min wrote:

Hi Greg,

On Mon, Apr 12, 2021 at 4:25 PM Greg KH  wrote:


On Mon, Apr 12, 2021 at 02:50:20PM +0800, dillon min wrote:

Hi Gregļ¼Œ

Thanks for the quick response, please ignore the last private mail.

On Mon, Apr 12, 2021 at 1:52 PM Greg KH  wrote:


On Mon, Apr 12, 2021 at 12:34:21PM +0800, dillon.min...@gmail.com wrote:

From: dillon min 

To avoid potential deadlock in spin_lock usage, change to use
spin_lock_irqsave(), spin_unlock_irqrestore() in process(thread_fn) context.
spin_lock(), spin_unlock() under handler context.

remove unused local_irq_save/restore call.

Signed-off-by: dillon min 
---
Was verified on stm32f469-disco board. need more test on stm32mp platform.

  drivers/tty/serial/stm32-usart.c | 27 +--
  1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index b3675cf25a69..c4c859b34367 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -214,7 +214,7 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
   struct tty_port *tport = >state->port;
   struct stm32_port *stm32_port = to_stm32_port(port);
   const struct stm32_usart_offsets *ofs = _port->info->ofs;
- unsigned long c;
+ unsigned long c, flags;
   u32 sr;
   char flag;

@@ -276,9 +276,17 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
   uart_insert_char(port, sr, USART_SR_ORE, c, flag);
   }

- spin_unlock(>lock);
+ if (threaded)
+ spin_unlock_irqrestore(>lock, flags);
+ else
+ spin_unlock(>lock);


You shouldn't have to check for this, see the other patches on the list
recently that fixed this up to not be an issue for irq handlers.

Can you help to give more hints, or the commit id of the patch which
fixed this. thanks.

I'm still confused with this.

The stm32_usart_threaded_interrupt() is a kthread context, once
port->lock holds by this function, another serial interrupts raised,
such as USART_SR_TXE,stm32_usart_interrupt() can't get the lock,
there will be a deadlock. isn't it?

  So, shouldn't I use spin_lock{_irqsave} according to the caller's context ?


Please see 81e2073c175b ("genirq: Disable interrupts for force threaded
handlers") for when threaded irq handlers have irqs disabled, isn't that
the case you are trying to "protect" from here?

Why is the "threaded" flag used at all?  The driver should not care.

Also see 9baedb7baeda ("serial: imx: drop workaround for forced irq
threading") in linux-next for an example of how this was fixed up in a
serial driver.

does that help?


Yes, it's really helpful. and 81e2073c175b should be highlighted in a doc.
In my past knowledge, we should care about hard irq & thread_fn lock conflict.
This patch has totally avoided patching code in the separate driver side.
thanks.

I will just keep the changes in stm32_usart_console_write(), remove
these code in
thread_fn. update version 2 for you.

thanks.

Dillon,

thanks,

greg k-h

___
Linux-stm32 mailing list
linux-st...@st-md-mailman.stormreply.com
https://st-md-mailman.stormreply.com/mailman/listinfo/linux-stm32



[irqchip: irq/irqchip-next] irqchip/stm32: Add usart instances exti direct event support

2021-04-07 Thread irqchip-bot for Erwan Le Ray
The following commit has been merged into the irq/irqchip-next branch of 
irqchip:

Commit-ID: e12c455055e9abc7403ce532616c0124a9d85ee7
Gitweb:
https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/e12c455055e9abc7403ce532616c0124a9d85ee7
Author:Erwan Le Ray 
AuthorDate:Fri, 19 Mar 2021 19:42:51 +01:00
Committer: Marc Zyngier 
CommitterDate: Wed, 07 Apr 2021 13:25:52 +01:00

irqchip/stm32: Add usart instances exti direct event support

Add following usart instances exti direct event support (used for UART wake
up).
- exti 26 (USART1) is mapped to GIC 37
- exti 27 (USART2) is mapped to GIC 38
- exti 28 (USART3) is mapped to GIC 39
- exti 29 (USART6) is mapped to GIC 71
- exti 31 (UART5) is mapped to GIC 53
- exti 32 (UART7) is mapped to GIC 82
- exti 33 (UART8) is mapped to GIC 83

Signed-off-by: Erwan Le Ray 
Signed-off-by: Marc Zyngier 
Link: https://lore.kernel.org/r/20210319184253.5841-4-erwan.le...@foss.st.com
---
 drivers/irqchip/irq-stm32-exti.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 8662d7b..b9db90c 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -193,7 +193,14 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = {
{ .exti = 23, .irq_parent = 72, .chip = _exti_h_chip_direct },
{ .exti = 24, .irq_parent = 95, .chip = _exti_h_chip_direct },
{ .exti = 25, .irq_parent = 107, .chip = _exti_h_chip_direct },
+   { .exti = 26, .irq_parent = 37, .chip = _exti_h_chip_direct },
+   { .exti = 27, .irq_parent = 38, .chip = _exti_h_chip_direct },
+   { .exti = 28, .irq_parent = 39, .chip = _exti_h_chip_direct },
+   { .exti = 29, .irq_parent = 71, .chip = _exti_h_chip_direct },
{ .exti = 30, .irq_parent = 52, .chip = _exti_h_chip_direct },
+   { .exti = 31, .irq_parent = 53, .chip = _exti_h_chip_direct },
+   { .exti = 32, .irq_parent = 82, .chip = _exti_h_chip_direct },
+   { .exti = 33, .irq_parent = 83, .chip = _exti_h_chip_direct },
{ .exti = 47, .irq_parent = 93, .chip = _exti_h_chip_direct },
{ .exti = 48, .irq_parent = 138, .chip = _exti_h_chip_direct },
{ .exti = 50, .irq_parent = 139, .chip = _exti_h_chip_direct },


[PATCH 2/2] serial: stm32: add fifo threshold configuration

2021-04-06 Thread Erwan Le Ray
From: Fabrice Gasnier 

Add the support for two optional DT properties, to configure RX and TX
FIFO thresholds::
- st,rx-fifo-threshold-bytes
- st,tx-fifo-threshold-bytes
This replaces hard-coded 8 bytes threshold. Keep 8 as the default value if
not specified, for backward compatibility.

Signed-off-by: Fabrice Gasnier 
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 4d277804c63e..1be5b69ee567 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -312,7 +312,7 @@ static void stm32_usart_tx_interrupt_enable(struct 
uart_port *port)
 * Enables TX FIFO threashold irq when FIFO is enabled,
 * or TX empty irq when FIFO is disabled
 */
-   if (stm32_port->fifoen)
+   if (stm32_port->fifoen && stm32_port->txftcfg >= 0)
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE);
else
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
@@ -323,7 +323,7 @@ static void stm32_usart_tx_interrupt_disable(struct 
uart_port *port)
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
 
-   if (stm32_port->fifoen)
+   if (stm32_port->fifoen && stm32_port->txftcfg >= 0)
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE);
else
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
@@ -801,9 +801,10 @@ static void stm32_usart_set_termios(struct uart_port *port,
cr3 = readl_relaxed(port->membase + ofs->cr3);
cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE;
if (stm32_port->fifoen) {
-   cr3 &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
-   cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
-   cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
+   if (stm32_port->txftcfg >= 0)
+   cr3 |= stm32_port->txftcfg << USART_CR3_TXFTCFG_SHIFT;
+   if (stm32_port->rxftcfg >= 0)
+   cr3 |= stm32_port->rxftcfg << USART_CR3_RXFTCFG_SHIFT;
}
 
if (cflag & CSTOPB)
@@ -833,7 +834,8 @@ static void stm32_usart_set_termios(struct uart_port *port,
, bits);
 
if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch ||
-  stm32_port->fifoen)) {
+  (stm32_port->fifoen &&
+   stm32_port->rxftcfg >= 0))) {
if (cflag & CSTOPB)
bits = bits + 3; /* 1 start bit + 2 stop bits */
else
@@ -1021,6 +1023,39 @@ static const struct uart_ops stm32_uart_ops = {
.verify_port= stm32_usart_verify_port,
 };
 
+/*
+ * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG)
+ * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case,
+ * RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE.
+ * So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1.
+ */
+static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 };
+
+static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p,
+ int *ftcfg)
+{
+   u32 bytes, i;
+
+   /* DT option to get RX & TX FIFO threshold (default to 8 bytes) */
+   if (of_property_read_u32(pdev->dev.of_node, p, ))
+   bytes = 8;
+
+   for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++)
+   if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes)
+   break;
+   if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg))
+   i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1;
+
+   dev_dbg(>dev, "%s set to %d bytes\n", p,
+   stm32h7_usart_fifo_thresh_cfg[i]);
+
+   /* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */
+   if (i)
+   *ftcfg = i - 1;
+   else
+   *ftcfg = -EINVAL;
+}
+
 static void stm32_usart_deinit_port(struct stm32_port *stm32port)
 {
clk_disable_unprepare(stm32port->clk);
@@ -1057,6 +1092,12 @@ static int stm32_usart_init_port(struct stm32_port 
*stm32port,
of_property_read_bool(pdev->dev.of_node, "rx-tx-swap");
 
stm32port->fifoen = stm32port->info->cfg.has_fifo;
+   if (stm32port->fifoen) {
+   stm32_usart_get_ftcfg(pdev, "st,rx-fifo-threshold-bytes",
+ >rxftcfg);
+   stm32_usart_get_ftcfg(pdev, "st,tx-fifo-threshold-bytes",
+ >txftcfg);
+   }
 

[PATCH 1/2] dt-bindings: serial: stm32: add fifo threshold configuration

2021-04-06 Thread Erwan Le Ray
Add two optional DT properties, to configure RX and TX fifo threshold:
- st,rx-fifo-threshold-bytes
- st,tx-fifo-threshold-bytes

This patch depends on patch ("dt-bindings: serial: Add rx-tx-swap to 
stm32-usart").

Signed-off-by: Fabrice Gasnier 
Signed-off-by: Erwan Le Ray 

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml 
b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
index c69f8464cdf3..e163449bf39e 100644
--- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
@@ -65,6 +65,22 @@ properties:
   linux,rs485-enabled-at-boot-time: true
   rs485-rx-during-tx: true
 
+  st,rx-fifo-threshold-bytes:
+description:
+  RX FIFO threshold configuration in bytes.
+  If value is set to 1, RX FIFO threshold is disabled.
+$ref: /schemas/types.yaml#/definitions/uint32
+enum: [1, 2, 4, 8, 12, 14, 16]
+default: 8
+
+  st,tx-fifo-threshold-bytes:
+description:
+  TX FIFO threshold configuration in bytes.
+  If value is set to 1, TX FIFO threshold is disabled.
+$ref: /schemas/types.yaml#/definitions/uint32
+enum: [1, 2, 4, 8, 12, 14, 16]
+default: 8
+
 allOf:
   - $ref: rs485.yaml#
   - $ref: serial.yaml#
@@ -82,6 +98,17 @@ allOf:
 then:
   properties:
 rx-tx-swap: false
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - st,stm32-uart
+  - st,stm32f7-uart
+then:
+  properties:
+st,rx-fifo-threshold-bytes: false
+st,tx-fifo-threshold-bytes: false
 
 required:
   - compatible
@@ -96,13 +123,15 @@ examples:
   - |
 #include 
 usart1: serial@40011000 {
-  compatible = "st,stm32-uart";
+  compatible = "st,stm32h7-uart";
   reg = <0x40011000 0x400>;
   interrupts = <37>;
   clocks = < 0 164>;
   dmas = < 2 4 0x414 0x0>,
  < 7 4 0x414 0x0>;
   dma-names = "rx", "tx";
+  st,rx-fifo-threshold-bytes = <4>;
+  st,tx-fifo-threshold-bytes = <4>;
   rs485-rts-active-low;
 };
 
-- 
2.17.1



[PATCH 0/2] stm32 usart add fifo threshold configuration

2021-04-06 Thread Erwan Le Ray
This series adds the support for two optional DT properties, to configure
RX and TX FIFO thresholds:
 - st,rx-fifo-threshold-bytes
 - st,tx-fifo-threshold-bytes
This replaces hard-coded 8 bytes threshold. No functional change expected
if unspecified (keep 8 as default).

Erwan Le Ray (1):
  dt-bindings: serial: stm32: add fifo threshold configuration

Fabrice Gasnier (1):
  serial: stm32: add fifo threshold configuration

 .../bindings/serial/st,stm32-uart.yaml| 31 ++-
 drivers/tty/serial/stm32-usart.c  | 53 ---
 drivers/tty/serial/stm32-usart.h  |  8 +--
 3 files changed, 79 insertions(+), 13 deletions(-)

-- 
2.17.1



[PATCH 5/5] ARM: dts: stm32: Add wakeup management on stm32mp15x UART nodes

2021-03-19 Thread Erwan Le Ray
Add EXTI lines to the following UART nodes which are used for
wakeup from CStop.
- EXTI line 26 to USART1
- EXTI line 27 to USART2
- EXTI line 28 to USART3
- EXTI line 29 to USART6
- EXTI line 30 to UART4
- EXTI line 31 to UART5
- EXTI line 32 to UART7
- EXTI line 33 to UART8

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp151.dtsi 
b/arch/arm/boot/dts/stm32mp151.dtsi
index 4b8031782555..e242d7211059 100644
--- a/arch/arm/boot/dts/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/stm32mp151.dtsi
@@ -452,32 +452,36 @@
usart2: serial@4000e000 {
compatible = "st,stm32h7-uart";
reg = <0x4000e000 0x400>;
-   interrupts = ;
+   interrupts-extended = < 27 IRQ_TYPE_LEVEL_HIGH>;
clocks = < USART2_K>;
+   wakeup-source;
status = "disabled";
};
 
usart3: serial@4000f000 {
compatible = "st,stm32h7-uart";
reg = <0x4000f000 0x400>;
-   interrupts = ;
+   interrupts-extended = < 28 IRQ_TYPE_LEVEL_HIGH>;
clocks = < USART3_K>;
+   wakeup-source;
status = "disabled";
};
 
uart4: serial@4001 {
compatible = "st,stm32h7-uart";
reg = <0x4001 0x400>;
-   interrupts = ;
+   interrupts-extended = < 30 IRQ_TYPE_LEVEL_HIGH>;
clocks = < UART4_K>;
+   wakeup-source;
status = "disabled";
};
 
uart5: serial@40011000 {
compatible = "st,stm32h7-uart";
reg = <0x40011000 0x400>;
-   interrupts = ;
+   interrupts-extended = < 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = < UART5_K>;
+   wakeup-source;
status = "disabled";
};
 
@@ -577,16 +581,18 @@
uart7: serial@40018000 {
compatible = "st,stm32h7-uart";
reg = <0x40018000 0x400>;
-   interrupts = ;
+   interrupts-extended = < 32 IRQ_TYPE_LEVEL_HIGH>;
clocks = < UART7_K>;
+   wakeup-source;
status = "disabled";
};
 
uart8: serial@40019000 {
compatible = "st,stm32h7-uart";
reg = <0x40019000 0x400>;
-   interrupts = ;
+   interrupts-extended = < 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = < UART8_K>;
+   wakeup-source;
status = "disabled";
};
 
@@ -665,8 +671,9 @@
usart6: serial@44003000 {
compatible = "st,stm32h7-uart";
reg = <0x44003000 0x400>;
-   interrupts = ;
+   interrupts-extended = < 29 IRQ_TYPE_LEVEL_HIGH>;
clocks = < USART6_K>;
+   wakeup-source;
status = "disabled";
};
 
@@ -1505,8 +1512,9 @@
usart1: serial@5c00 {
compatible = "st,stm32h7-uart";
reg = <0x5c00 0x400>;
-   interrupts = ;
+   interrupts-extended = < 26 IRQ_TYPE_LEVEL_HIGH>;
clocks = < USART1_K>;
+   wakeup-source;
status = "disabled";
};
 
-- 
2.17.1



[PATCH 1/5] serial: stm32: rework wakeup management

2021-03-19 Thread Erwan Le Ray
Rework wakeup management by activating uart as wakeup source when usart
device OR its tty virtual device parent is wakeup source.

This patch aim to avoid potential misalignment between serial and tty
wakeup flags.

Signed-off-by: Patrice Chotard 
Signed-off-by: Alexandre Torgue 
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 9db6708e3d9f..11656b6b7c0f 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1534,7 +1534,7 @@ static int __maybe_unused 
stm32_usart_serial_suspend(struct device *dev)
 
uart_suspend_port(_usart_driver, port);
 
-   if (device_may_wakeup(dev))
+   if (device_may_wakeup(dev) || device_wakeup_path(dev))
stm32_usart_serial_en_wakeup(port, true);
else
stm32_usart_serial_en_wakeup(port, false);
@@ -1546,7 +1546,7 @@ static int __maybe_unused 
stm32_usart_serial_suspend(struct device *dev)
 * capabilities.
 */
if (console_suspend_enabled || !uart_console(port)) {
-   if (device_may_wakeup(dev))
+   if (device_may_wakeup(dev) || device_wakeup_path(dev))
pinctrl_pm_select_idle_state(dev);
else
pinctrl_pm_select_sleep_state(dev);
@@ -1561,7 +1561,7 @@ static int __maybe_unused 
stm32_usart_serial_resume(struct device *dev)
 
pinctrl_pm_select_default_state(dev);
 
-   if (device_may_wakeup(dev))
+   if (device_may_wakeup(dev) || device_wakeup_path(dev))
stm32_usart_serial_en_wakeup(port, false);
 
return uart_resume_port(_usart_driver, port);
-- 
2.17.1



[PATCH 3/5] irqchip/stm32: add usart instances exti direct event support

2021-03-19 Thread Erwan Le Ray
Add following usart instances exti direct event support (used for UART wake
up).
- exti 26 (USART1) is mapped to GIC 37
- exti 27 (USART2) is mapped to GIC 38
- exti 28 (USART3) is mapped to GIC 39
- exti 29 (USART6) is mapped to GIC 71
- exti 31 (UART5) is mapped to GIC 53
- exti 32 (UART7) is mapped to GIC 82
- exti 33 (UART8) is mapped to GIC 83

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 8662d7b7b262..b9db90c4aa56 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -193,7 +193,14 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = {
{ .exti = 23, .irq_parent = 72, .chip = _exti_h_chip_direct },
{ .exti = 24, .irq_parent = 95, .chip = _exti_h_chip_direct },
{ .exti = 25, .irq_parent = 107, .chip = _exti_h_chip_direct },
+   { .exti = 26, .irq_parent = 37, .chip = _exti_h_chip_direct },
+   { .exti = 27, .irq_parent = 38, .chip = _exti_h_chip_direct },
+   { .exti = 28, .irq_parent = 39, .chip = _exti_h_chip_direct },
+   { .exti = 29, .irq_parent = 71, .chip = _exti_h_chip_direct },
{ .exti = 30, .irq_parent = 52, .chip = _exti_h_chip_direct },
+   { .exti = 31, .irq_parent = 53, .chip = _exti_h_chip_direct },
+   { .exti = 32, .irq_parent = 82, .chip = _exti_h_chip_direct },
+   { .exti = 33, .irq_parent = 83, .chip = _exti_h_chip_direct },
{ .exti = 47, .irq_parent = 93, .chip = _exti_h_chip_direct },
{ .exti = 48, .irq_parent = 138, .chip = _exti_h_chip_direct },
{ .exti = 50, .irq_parent = 139, .chip = _exti_h_chip_direct },
-- 
2.17.1



[PATCH 4/5] serial: stm32: update wakeup IRQ management

2021-03-19 Thread Erwan Le Ray
From: Alexandre Torgue 

The wakeup specific IRQ management is no more needed to wake up the stm32
plaform. A relationship has been established between the EXTI and
the EVENT IRQ, just need to declare the EXTI interrupt instead of the
UART event IRQ.

Signed-off-by: Alexandre Torgue 
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index cc054f07bd83..cba4f4ddf164 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -924,7 +924,7 @@ static void stm32_usart_set_termios(struct uart_port *port,
}
 
/* Configure wake up from low power on start bit detection */
-   if (stm32_port->wakeirq > 0) {
+   if (stm32_port->wakeup_src) {
cr3 &= ~USART_CR3_WUS_MASK;
cr3 |= USART_CR3_WUS_START_BIT;
}
@@ -1044,11 +1044,8 @@ static int stm32_usart_init_port(struct stm32_port 
*stm32port,
if (ret)
return ret;
 
-   if (stm32port->info->cfg.has_wakeup) {
-   stm32port->wakeirq = platform_get_irq_optional(pdev, 1);
-   if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO)
-   return stm32port->wakeirq ? : -ENODEV;
-   }
+   stm32port->wakeup_src = stm32port->info->cfg.has_wakeup &&
+   of_property_read_bool(pdev->dev.of_node, "wakeup-source");
 
stm32port->fifoen = stm32port->info->cfg.has_fifo;
 
@@ -1283,17 +1280,11 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
if (ret)
return ret;
 
-   if (stm32port->wakeirq > 0) {
-   ret = device_init_wakeup(>dev, true);
-   if (ret)
-   goto err_uninit;
-
-   ret = dev_pm_set_dedicated_wake_irq(>dev,
-   stm32port->wakeirq);
+   if (stm32port->wakeup_src) {
+   device_set_wakeup_capable(>dev, true);
+   ret = dev_pm_set_wake_irq(>dev, stm32port->port.irq);
if (ret)
goto err_nowup;
-
-   device_set_wakeup_enable(>dev, false);
}
 
ret = stm32_usart_of_dma_rx_probe(stm32port, pdev);
@@ -1343,14 +1334,13 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
  TX_BUF_L, stm32port->tx_buf,
  stm32port->tx_dma_buf);
 
-   if (stm32port->wakeirq > 0)
+   if (stm32port->wakeup_src)
dev_pm_clear_wake_irq(>dev);
 
 err_nowup:
-   if (stm32port->wakeirq > 0)
-   device_init_wakeup(>dev, false);
+   if (stm32port->wakeup_src)
+   device_set_wakeup_capable(>dev, false);
 
-err_uninit:
stm32_usart_deinit_port(stm32port);
 
return ret;
@@ -1396,7 +1386,7 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
  TX_BUF_L, stm32_port->tx_buf,
  stm32_port->tx_dma_buf);
 
-   if (stm32_port->wakeirq > 0) {
+   if (stm32_port->wakeup_src) {
dev_pm_clear_wake_irq(>dev);
device_init_wakeup(>dev, false);
}
@@ -1512,7 +1502,7 @@ static void __maybe_unused 
stm32_usart_serial_en_wakeup(struct uart_port *port,
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
 
-   if (stm32_port->wakeirq <= 0)
+   if (!stm32_port->wakeup_src)
return;
 
/*
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index 94b568aa46bb..a86773f1a4c4 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -269,7 +269,7 @@ struct stm32_port {
bool tx_dma_busy;/* dma tx busy   */
bool hw_flow_control;
bool fifoen;
-   int wakeirq;
+   bool wakeup_src;
int rdr_mask;   /* receive data register mask */
struct mctrl_gpios *gpios; /* modem control gpios */
 };
-- 
2.17.1



[PATCH 0/5] stm32 usart wakeup rework

2021-03-19 Thread Erwan Le Ray
This series reworks stm32 usart wakeup management.

Alexandre Torgue (1):
  serial: stm32: update wakeup IRQ management

Erwan Le Ray (4):
  serial: stm32: rework wakeup management
  serial: stm32: clean wakeup handling in serial_suspend
  irqchip/stm32: add usart instances exti direct event support
  ARM: dts: stm32: Add wakeup management on stm32mp15x UART nodes

 arch/arm/boot/dts/stm32mp151.dtsi | 24 ---
 drivers/irqchip/irq-stm32-exti.c  |  7 ++
 drivers/tty/serial/stm32-usart.c  | 40 +++
 drivers/tty/serial/stm32-usart.h  |  2 +-
 4 files changed, 38 insertions(+), 35 deletions(-)

-- 
2.17.1



[PATCH 2/5] serial: stm32: clean wakeup handling in serial_suspend

2021-03-19 Thread Erwan Le Ray
Remove useless call to stm32_usart_serial_en_wakeup() routine in suspend
callback. When called with "false" argument, this routine is clearing UESM
and WUFIE bits if usart is not wakeup source. Those bits are already
cleared in set_termios(), and then in serial_resume() callback when usart
is wakeup source.

Signed-off-by: Alexandre Torgue 
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 11656b6b7c0f..cc054f07bd83 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1536,8 +1536,6 @@ static int __maybe_unused 
stm32_usart_serial_suspend(struct device *dev)
 
if (device_may_wakeup(dev) || device_wakeup_path(dev))
stm32_usart_serial_en_wakeup(port, true);
-   else
-   stm32_usart_serial_en_wakeup(port, false);
 
/*
 * When "no_console_suspend" is enabled, keep the pinctrl default state
-- 
2.17.1



[PATCH v2 12/13] serial: stm32: fix tx_empty condition

2021-03-04 Thread Erwan Le Ray
In "tx_empty", we should poll TC bit in both DMA and PIO modes (instead of
TXE) to check transmission data register has been transmitted independently
of the FIFO mode. TC indicates that both transmit register and shift
register are empty. When shift register is empty, tx_empty should return
TIOCSER_TEMT instead of TC value.

Cleans the USART_CR_TC TCCF register define (transmission complete clear
flag) as it is duplicate of USART_ICR_TCCF.

Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index d205fce1950a..99dfa884cbef 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -515,7 +515,10 @@ static unsigned int stm32_usart_tx_empty(struct uart_port 
*port)
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
 
-   return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE;
+   if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC)
+   return TIOCSER_TEMT;
+
+   return 0;
 }
 
 static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl)
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index cb4f327c46db..94b568aa46bb 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -127,9 +127,6 @@ struct stm32_usart_info stm32h7_info = {
 /* Dummy bits */
 #define USART_SR_DUMMY_RX  BIT(16)
 
-/* USART_ICR (F7) */
-#define USART_CR_TCBIT(6)
-
 /* USART_DR */
 #define USART_DR_MASK  GENMASK(8, 0)
 
-- 
2.17.1



[PATCH v2 08/13] serial: stm32: fix tx dma completion, release channel

2021-03-04 Thread Erwan Le Ray
This patch add a proper release of dma channels when completing dma tx.

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index a381ee52168a..74046ae3a412 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -292,6 +292,7 @@ static void stm32_usart_tx_dma_complete(void *arg)
struct stm32_port *stm32port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = >info->ofs;
 
+   dmaengine_terminate_async(stm32port->tx_ch);
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32port->tx_dma_busy = false;
 
-- 
2.17.1



[PATCH v2 13/13] serial: stm32: add support for "flush_buffer" ops

2021-03-04 Thread Erwan Le Ray
Add the support for "flush_buffer" ops in order to flush any write buffers,
reset any DMA state and stop any ongoing DMA transfers when the
port->state->xmit circular buffer is cleared.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 99dfa884cbef..9db6708e3d9f 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -597,6 +597,19 @@ static void stm32_usart_start_tx(struct uart_port *port)
stm32_usart_transmit_chars(port);
 }
 
+/* Flush the transmit buffer. */
+static void stm32_usart_flush_buffer(struct uart_port *port)
+{
+   struct stm32_port *stm32_port = to_stm32_port(port);
+   const struct stm32_usart_offsets *ofs = _port->info->ofs;
+
+   if (stm32_port->tx_ch) {
+   dmaengine_terminate_async(stm32_port->tx_ch);
+   stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+   stm32_port->tx_dma_busy = false;
+   }
+}
+
 /* Throttle the remote when input buffer is about to overflow. */
 static void stm32_usart_throttle(struct uart_port *port)
 {
@@ -992,6 +1005,7 @@ static const struct uart_ops stm32_uart_ops = {
.break_ctl  = stm32_usart_break_ctl,
.startup= stm32_usart_startup,
.shutdown   = stm32_usart_shutdown,
+   .flush_buffer   = stm32_usart_flush_buffer,
.set_termios= stm32_usart_set_termios,
.pm = stm32_usart_pm,
.type   = stm32_usart_type,
-- 
2.17.1



[PATCH v2 05/13] serial: stm32: fix a deadlock condition with wakeup event

2021-03-04 Thread Erwan Le Ray
Deadlock issue is seen when enabling CONFIG_PROVE_LOCKING=Y, and uart
console as wakeup source. Deadlock occurs when resuming from low power
mode if system is waked up via usart console.
The deadlock is triggered 100% when also disabling console suspend prior
to go to suspend.

Simplified call stack, deadlock condition:
- stm32_console_write <-- spin_lock already held
- print_circular_bug
- pm_wakeup_dev_event <-- triggers lockdep as seen above
- stm32_receive_chars
- stm32_interrupt <-- wakeup via uart console, takes the lock

So, revisit spin_lock in stm32-usart driver:
- there is no need to hold the lock to access ICR (atomic clear of status
  flags)
- only hold the lock inside stm32_receive_chars() routine (no need to
  call pm_wakeup_dev_event with lock held)
- keep stm32_transmit_chars() routine called with lock held

Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: Erwan Le Ray 
Signed-off-by: Fabrice Gasnier 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 223cec70c57c..370141445780 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -214,13 +214,18 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
struct tty_port *tport = >state->port;
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
-   unsigned long c;
+   unsigned long c, flags;
u32 sr;
char flag;
 
if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0);
 
+   if (threaded)
+   spin_lock_irqsave(>lock, flags);
+   else
+   spin_lock(>lock);
+
while (stm32_usart_pending_rx(port, , _port->last_res,
  threaded)) {
sr |= USART_SR_DUMMY_RX;
@@ -276,9 +281,12 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
uart_insert_char(port, sr, USART_SR_ORE, c, flag);
}
 
-   spin_unlock(>lock);
+   if (threaded)
+   spin_unlock_irqrestore(>lock, flags);
+   else
+   spin_unlock(>lock);
+
tty_flip_buffer_push(tport);
-   spin_lock(>lock);
 }
 
 static void stm32_usart_tx_dma_complete(void *arg)
@@ -459,8 +467,6 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
const struct stm32_usart_offsets *ofs = _port->info->ofs;
u32 sr;
 
-   spin_lock(>lock);
-
sr = readl_relaxed(port->membase + ofs->isr);
 
if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
@@ -474,10 +480,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void 
*ptr)
if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
stm32_usart_receive_chars(port, false);
 
-   if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch))
+   if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
+   spin_lock(>lock);
stm32_usart_transmit_chars(port);
-
-   spin_unlock(>lock);
+   spin_unlock(>lock);
+   }
 
if (stm32_port->rx_ch)
return IRQ_WAKE_THREAD;
@@ -490,13 +497,9 @@ static irqreturn_t stm32_usart_threaded_interrupt(int irq, 
void *ptr)
struct uart_port *port = ptr;
struct stm32_port *stm32_port = to_stm32_port(port);
 
-   spin_lock(>lock);
-
if (stm32_port->rx_ch)
stm32_usart_receive_chars(port, true);
 
-   spin_unlock(>lock);
-
return IRQ_HANDLED;
 }
 
-- 
2.17.1



[PATCH v2 09/13] serial: stm32: call stm32_transmit_chars locked

2021-03-04 Thread Erwan Le Ray
stm32_transmit_chars should be called under lock also in tx DMA callback.

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 
Signed-off-by: Fabrice Gasnier 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 74046ae3a412..2bdd04a47f91 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -291,13 +291,16 @@ static void stm32_usart_tx_dma_complete(void *arg)
struct uart_port *port = arg;
struct stm32_port *stm32port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = >info->ofs;
+   unsigned long flags;
 
dmaengine_terminate_async(stm32port->tx_ch);
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32port->tx_dma_busy = false;
 
/* Let's see if we have pending data to send */
+   spin_lock_irqsave(>lock, flags);
stm32_usart_transmit_chars(port);
+   spin_unlock_irqrestore(>lock, flags);
 }
 
 static void stm32_usart_tx_interrupt_enable(struct uart_port *port)
-- 
2.17.1



[PATCH v2 06/13] serial: stm32: fix wake-up flag handling

2021-03-04 Thread Erwan Le Ray
This patch fixes several issue with wake-up handling:
- the WUF irq is handled several times at wake-up
- the USART is disabled / enabled at suspend to set wake-up flag.
It can cause glitches during RX.

This patch fix those issues:
- clear wake-up flag and disable wake-up irq in WUF irq handling
- enable wake-up from low power on start bit detection at port
configuration
- Unmask the wake-up flag irq at suspend and mask it at resume

In addition, pm_wakeup_event handling is moved from receice_chars to WUF
irq handling.

Fixes: 270e5a74fe4c ("serial: stm32: add wakeup mechanism")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 370141445780..326f300dd410 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -218,9 +218,6 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
u32 sr;
char flag;
 
-   if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
-   pm_wakeup_event(tport->tty->dev, 0);
-
if (threaded)
spin_lock_irqsave(>lock, flags);
else
@@ -463,6 +460,7 @@ static void stm32_usart_transmit_chars(struct uart_port 
*port)
 static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
 {
struct uart_port *port = ptr;
+   struct tty_port *tport = >state->port;
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
u32 sr;
@@ -473,9 +471,14 @@ static irqreturn_t stm32_usart_interrupt(int irq, void 
*ptr)
writel_relaxed(USART_ICR_RTOCF,
   port->membase + ofs->icr);
 
-   if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG)
+   if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) {
+   /* Clear wake up flag and disable wake up interrupt */
writel_relaxed(USART_ICR_WUCF,
   port->membase + ofs->icr);
+   stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
+   if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
+   pm_wakeup_event(tport->tty->dev, 0);
+   }
 
if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
stm32_usart_receive_chars(port, false);
@@ -901,6 +904,12 @@ static void stm32_usart_set_termios(struct uart_port *port,
cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
}
 
+   /* Configure wake up from low power on start bit detection */
+   if (stm32_port->wakeirq > 0) {
+   cr3 &= ~USART_CR3_WUS_MASK;
+   cr3 |= USART_CR3_WUS_START_BIT;
+   }
+
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr2, port->membase + ofs->cr2);
writel_relaxed(cr1, port->membase + ofs->cr1);
@@ -1476,23 +1485,20 @@ static void __maybe_unused 
stm32_usart_serial_en_wakeup(struct uart_port *port,
 {
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
-   const struct stm32_usart_config *cfg = _port->info->cfg;
-   u32 val;
 
if (stm32_port->wakeirq <= 0)
return;
 
+   /*
+* Enable low-power wake-up and wake-up irq if argument is set to
+* "enable", disable low-power wake-up and wake-up irq otherwise
+*/
if (enable) {
-   stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM);
-   val = readl_relaxed(port->membase + ofs->cr3);
-   val &= ~USART_CR3_WUS_MASK;
-   /* Enable Wake up interrupt from low power on start bit */
-   val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE;
-   writel_relaxed(val, port->membase + ofs->cr3);
-   stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+   stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE);
} else {
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM);
+   stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
}
 }
 
-- 
2.17.1



[PATCH v2 11/13] serial: stm32: add FIFO flush when port is closed

2021-03-04 Thread Erwan Le Ray
Transmission complete error is sent when ISR_TC is not set. If port closure
is requested despite data in TDR / TX FIFO has not been sent (because of
flow control), ISR_TC is not set and error message is sent on port closure
but also when a new port is opened.

Flush the data when port is closed, so the error isn't printed twice upon
next port opening.

Fixes: 64c32eab6603 ("serial: stm32: Add support of TC bit status check")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 183c76ddb165..d205fce1950a 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -691,6 +691,11 @@ static void stm32_usart_shutdown(struct uart_port *port)
if (ret)
dev_err(port->dev, "Transmission is not complete\n");
 
+   /* flush RX & TX FIFO */
+   if (ofs->rqr != UNDEF_REG)
+   writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ,
+  port->membase + ofs->rqr);
+
stm32_usart_clr_bits(port, ofs->cr1, val);
 
free_irq(port->irq, port);
-- 
2.17.1



[PATCH v2 10/13] serial: stm32: fix FIFO flush in startup and set_termios

2021-03-04 Thread Erwan Le Ray
Fifo flush set USART_RQR register by calling stm32_usart_set_bits
routine (Read/Modify/Write). USART_RQR register is a write only
register. So, read before write isn't correct / relevant to flush
the FIFOs.
Replace stm32_usart_set_bits call by writel_relaxed.

Fixes: 84872dc448fe ("serial: stm32: add RX and TX FIFO flush")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 2bdd04a47f91..183c76ddb165 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -657,7 +657,7 @@ static int stm32_usart_startup(struct uart_port *port)
 
/* RX FIFO Flush */
if (ofs->rqr != UNDEF_REG)
-   stm32_usart_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
+   writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr);
 
/* RX enabling */
val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
@@ -762,8 +762,8 @@ static void stm32_usart_set_termios(struct uart_port *port,
 
/* flush RX & TX FIFO */
if (ofs->rqr != UNDEF_REG)
-   stm32_usart_set_bits(port, ofs->rqr,
-USART_RQR_TXFRQ | USART_RQR_RXFRQ);
+   writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ,
+  port->membase + ofs->rqr);
 
cr1 = USART_CR1_TE | USART_CR1_RE;
if (stm32_port->fifoen)
-- 
2.17.1



[PATCH v2 02/13] serial: stm32: fix startup by enabling usart for reception

2021-03-04 Thread Erwan Le Ray
RX is configured, but usart is not enabled in startup function.
Kernel documentation specifies that startup should enable the port for
reception.
Fix the startup by enabling usart for reception.

Fixes: 84872dc448fe ("serial: stm32: add RX and TX FIFO flush")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 3d58824ac2af..c6ca8f964c69 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -634,6 +634,7 @@ static int stm32_usart_startup(struct uart_port *port)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = _port->info->ofs;
+   const struct stm32_usart_config *cfg = _port->info->cfg;
const char *name = to_platform_device(port->dev)->name;
u32 val;
int ret;
@@ -658,7 +659,7 @@ static int stm32_usart_startup(struct uart_port *port)
}
 
/* RX FIFO enabling */
-   val = stm32_port->cr1_irq | USART_CR1_RE;
+   val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
stm32_usart_set_bits(port, ofs->cr1, val);
-- 
2.17.1



[PATCH v2 03/13] serial: stm32: fix incorrect characters on console

2021-03-04 Thread Erwan Le Ray
Incorrect characters are observed on console during boot. This issue occurs
when init/main.c is modifying termios settings to open /dev/console on the
rootfs.

This patch adds a waiting loop in set_termios to wait for TX shift register
empty (and TX FIFO if any) before stopping serial port.

Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index c6ca8f964c69..eae54b8cf5e2 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -738,8 +738,9 @@ static void stm32_usart_set_termios(struct uart_port *port,
unsigned int baud, bits;
u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag;
-   u32 cr1, cr2, cr3;
+   u32 cr1, cr2, cr3, isr;
unsigned long flags;
+   int ret;
 
if (!stm32_port->hw_flow_control)
cflag &= ~CRTSCTS;
@@ -748,6 +749,15 @@ static void stm32_usart_set_termios(struct uart_port *port,
 
spin_lock_irqsave(>lock, flags);
 
+   ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
+   isr,
+   (isr & USART_SR_TC),
+   10, 10);
+
+   /* Send the TC error message only when ISR_TC is not set. */
+   if (ret)
+   dev_err(port->dev, "Transmission is not complete\n");
+
/* Stop serial port and reset value */
writel_relaxed(0, port->membase + ofs->cr1);
 
-- 
2.17.1



[PATCH v2 01/13] serial: stm32: fix probe and remove order for dma

2021-03-04 Thread Erwan Le Ray
The probe and remove orders are wrong as the uart_port is registered
before saving device data in the probe, and unregistered after DMA
resource deallocation in the remove. uart_port registering should be
done at the end of probe and unregistering should be done at the begin of
remove to avoid resource allocation issues.

Fix probe and remove orders. This enforce resource allocation occur at
proper time.
Terminate both DMA rx and tx transfers before removing device.

Move pm_runtime after uart_remove_one_port() call in remove() to keep the
probe error path.

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index b3675cf25a69..3d58824ac2af 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1252,10 +1252,6 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
device_set_wakeup_enable(>dev, false);
}
 
-   ret = uart_add_one_port(_usart_driver, >port);
-   if (ret)
-   goto err_wirq;
-
ret = stm32_usart_of_dma_rx_probe(stm32port, pdev);
if (ret)
dev_info(>dev, "interrupt mode used for rx (no dma)\n");
@@ -1269,11 +1265,40 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
pm_runtime_get_noresume(>dev);
pm_runtime_set_active(>dev);
pm_runtime_enable(>dev);
+
+   ret = uart_add_one_port(_usart_driver, >port);
+   if (ret)
+   goto err_port;
+
pm_runtime_put_sync(>dev);
 
return 0;
 
-err_wirq:
+err_port:
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_put_noidle(>dev);
+
+   if (stm32port->rx_ch) {
+   dmaengine_terminate_async(stm32port->rx_ch);
+   dma_release_channel(stm32port->rx_ch);
+   }
+
+   if (stm32port->rx_dma_buf)
+   dma_free_coherent(>dev,
+ RX_BUF_L, stm32port->rx_buf,
+ stm32port->rx_dma_buf);
+
+   if (stm32port->tx_ch) {
+   dmaengine_terminate_async(stm32port->tx_ch);
+   dma_release_channel(stm32port->tx_ch);
+   }
+
+   if (stm32port->tx_dma_buf)
+   dma_free_coherent(>dev,
+ TX_BUF_L, stm32port->tx_buf,
+ stm32port->tx_dma_buf);
+
if (stm32port->wakeirq > 0)
dev_pm_clear_wake_irq(>dev);
 
@@ -1295,11 +1320,20 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
int err;
 
pm_runtime_get_sync(>dev);
+   err = uart_remove_one_port(_usart_driver, port);
+   if (err)
+   return(err);
+
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_put_noidle(>dev);
 
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
 
-   if (stm32_port->rx_ch)
+   if (stm32_port->rx_ch) {
+   dmaengine_terminate_async(stm32_port->rx_ch);
dma_release_channel(stm32_port->rx_ch);
+   }
 
if (stm32_port->rx_dma_buf)
dma_free_coherent(>dev,
@@ -1308,8 +1342,10 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
 
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
 
-   if (stm32_port->tx_ch)
+   if (stm32_port->tx_ch) {
+   dmaengine_terminate_async(stm32_port->tx_ch);
dma_release_channel(stm32_port->tx_ch);
+   }
 
if (stm32_port->tx_dma_buf)
dma_free_coherent(>dev,
@@ -1323,12 +1359,7 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
 
stm32_usart_deinit_port(stm32_port);
 
-   err = uart_remove_one_port(_usart_driver, port);
-
-   pm_runtime_disable(>dev);
-   pm_runtime_put_noidle(>dev);
-
-   return err;
+   return 0;
 }
 
 #ifdef CONFIG_SERIAL_STM32_CONSOLE
-- 
2.17.1



[PATCH v2 07/13] serial: stm32: fix a deadlock in set_termios

2021-03-04 Thread Erwan Le Ray
CTS/RTS GPIOs support that has been added recently to STM32 UART driver has
introduced scheduled code in a set_termios part protected by a spin lock.
This generates a potential deadlock scenario:

Chain exists of:
_desc_lock_class --> console_owner --> _lock_key

Possible unsafe locking scenario:

 CPU0CPU1
 
lock(_lock_key);
   lock(console_owner);
   lock(_lock_key);
lock(_desc_lock_class);

*** DEADLOCK ***
4 locks held by stty/766:

Move the scheduled code after the spinlock.

Fixes: 6cf61b9bd7cc ("tty: serial: Add modem control gpio support for STM32 
UART")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 326f300dd410..a381ee52168a 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -829,12 +829,6 @@ static void stm32_usart_set_termios(struct uart_port *port,
cr3 |= USART_CR3_CTSE | USART_CR3_RTSE;
}
 
-   /* Handle modem control interrupts */
-   if (UART_ENABLE_MS(port, termios->c_cflag))
-   stm32_usart_enable_ms(port);
-   else
-   stm32_usart_disable_ms(port);
-
usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
 
/*
@@ -916,6 +910,12 @@ static void stm32_usart_set_termios(struct uart_port *port,
 
stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
spin_unlock_irqrestore(>lock, flags);
+
+   /* Handle modem control interrupts */
+   if (UART_ENABLE_MS(port, termios->c_cflag))
+   stm32_usart_enable_ms(port);
+   else
+   stm32_usart_disable_ms(port);
 }
 
 static const char *stm32_usart_type(struct uart_port *port)
-- 
2.17.1



[PATCH v2 00/13] stm32 usart various fixes

2021-03-04 Thread Erwan Le Ray
Changes in v2:
Rebase on latest 5.12-rc1 requested by maintainer because of merge
conflict.

Erwan Le Ray (13):
  serial: stm32: fix probe and remove order for dma
  serial: stm32: fix startup by enabling usart for reception
  serial: stm32: fix incorrect characters on console
  serial: stm32: fix TX and RX FIFO thresholds
  serial: stm32: fix a deadlock condition with wakeup event
  serial: stm32: fix wake-up flag handling
  serial: stm32: fix a deadlock in set_termios
  serial: stm32: fix tx dma completion, release channel
  serial: stm32: call stm32_transmit_chars locked
  serial: stm32: fix FIFO flush in startup and set_termios
  serial: stm32: add FIFO flush when port is closed
  serial: stm32: fix tx_empty condition
  serial: stm32: add support for "flush_buffer" ops

 drivers/tty/serial/stm32-usart.c | 198 +--
 drivers/tty/serial/stm32-usart.h |   3 -
 2 files changed, 135 insertions(+), 66 deletions(-)

-- 
2.17.1



[PATCH v2 04/13] serial: stm32: fix TX and RX FIFO thresholds

2021-03-04 Thread Erwan Le Ray
TX and RX FIFO thresholds may be cleared after suspend/resume, depending
on the low power mode.

Those configurations (done in startup) are not effective for UART console,
as:
- the reference manual indicates that FIFOEN bit can only be written when
  the USART is disabled (UE=0)
- a set_termios (where UE is set) is requested firstly for console
  enabling, before the startup.

Fixes: 84872dc448fe ("serial: stm32: add RX and TX FIFO flush")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index eae54b8cf5e2..223cec70c57c 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -649,19 +649,8 @@ static int stm32_usart_startup(struct uart_port *port)
if (ofs->rqr != UNDEF_REG)
stm32_usart_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
 
-   /* Tx and RX FIFO configuration */
-   if (stm32_port->fifoen) {
-   val = readl_relaxed(port->membase + ofs->cr3);
-   val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
-   val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
-   val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
-   writel_relaxed(val, port->membase + ofs->cr3);
-   }
-
-   /* RX FIFO enabling */
+   /* RX enabling */
val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
-   if (stm32_port->fifoen)
-   val |= USART_CR1_FIFOEN;
stm32_usart_set_bits(port, ofs->cr1, val);
 
return 0;
@@ -770,9 +759,15 @@ static void stm32_usart_set_termios(struct uart_port *port,
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
cr2 = 0;
+
+   /* Tx and RX FIFO configuration */
cr3 = readl_relaxed(port->membase + ofs->cr3);
-   cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE
-   | USART_CR3_TXFTCFG_MASK;
+   cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE;
+   if (stm32_port->fifoen) {
+   cr3 &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
+   cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
+   cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
+   }
 
if (cflag & CSTOPB)
cr2 |= USART_CR2_STOP_2B;
-- 
2.17.1



[PATCH 13/13] serial: stm32: add support for "flush_buffer" ops

2021-02-19 Thread Erwan Le Ray
Add the support for "flush_buffer" ops in order to flush any write buffers,
reset any DMA state and stop any ongoing DMA transfers when the
port->state->xmit circular buffer is cleared.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 114408f3892a..92836068e5ec 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -597,6 +597,19 @@ static void stm32_usart_start_tx(struct uart_port *port)
stm32_usart_transmit_chars(port);
 }
 
+/* Flush the transmit buffer. */
+static void stm32_usart_flush_buffer(struct uart_port *port)
+{
+   struct stm32_port *stm32_port = to_stm32_port(port);
+   struct stm32_usart_offsets *ofs = _port->info->ofs;
+
+   if (stm32_port->tx_ch) {
+   dmaengine_terminate_async(stm32_port->tx_ch);
+   stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+   stm32_port->tx_dma_busy = false;
+   }
+}
+
 /* Throttle the remote when input buffer is about to overflow. */
 static void stm32_usart_throttle(struct uart_port *port)
 {
@@ -992,6 +1005,7 @@ static const struct uart_ops stm32_uart_ops = {
.break_ctl  = stm32_usart_break_ctl,
.startup= stm32_usart_startup,
.shutdown   = stm32_usart_shutdown,
+   .flush_buffer   = stm32_usart_flush_buffer,
.set_termios= stm32_usart_set_termios,
.pm = stm32_usart_pm,
.type   = stm32_usart_type,
-- 
2.17.1



[PATCH 11/13] serial: stm32: add FIFO flush when port is closed

2021-02-19 Thread Erwan Le Ray
Transmission complete error is sent when ISR_TC is not set. If port closure
is requested despite data in TDR / TX FIFO has not been sent (because of
flow control), ISR_TC is not set and error message is sent on port closure
but also when a new port is opened.

Flush the data when port is closed, so the error isn't printed twice upon
next port opening.

Fixes: 64c32eab6603 ("serial: stm32: Add support of TC bit status check")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 45203648172b..dcc309fd5d2f 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -691,6 +691,11 @@ static void stm32_usart_shutdown(struct uart_port *port)
if (ret)
dev_err(port->dev, "Transmission is not complete\n");
 
+   /* flush RX & TX FIFO */
+   if (ofs->rqr != UNDEF_REG)
+   writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ,
+  port->membase + ofs->rqr);
+
stm32_usart_clr_bits(port, ofs->cr1, val);
 
free_irq(port->irq, port);
-- 
2.17.1



[PATCH 12/13] serial: stm32: fix tx_empty condition

2021-02-19 Thread Erwan Le Ray
In "tx_empty", we should poll TC bit in both DMA and PIO modes (instead of
TXE) to check transmission data register has been transmitted independently
of the FIFO mode. TC indicates that both transmit register and shift
register are empty. When shift register is empty, tx_empty should return
TIOCSER_TEMT instead of TC value.

Cleans the USART_CR_TC TCCF register define (transmission complete clear
flag) as it is duplicate of USART_ICR_TCCF.

Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index dcc309fd5d2f..114408f3892a 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -515,7 +515,10 @@ static unsigned int stm32_usart_tx_empty(struct uart_port 
*port)
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
 
-   return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE;
+   if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC)
+   return TIOCSER_TEMT;
+
+   return 0;
 }
 
 static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl)
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index d4c916e78d40..e305462d0de6 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -127,9 +127,6 @@ struct stm32_usart_info stm32h7_info = {
 /* Dummy bits */
 #define USART_SR_DUMMY_RX  BIT(16)
 
-/* USART_ICR (F7) */
-#define USART_CR_TCBIT(6)
-
 /* USART_DR */
 #define USART_DR_MASK  GENMASK(8, 0)
 
-- 
2.17.1



[PATCH 10/13] serial: stm32: fix FIFO flush in startup and set_termios

2021-02-19 Thread Erwan Le Ray
Fifo flush set USART_RQR register by calling stm32_usart_set_bits
routine (Read/Modify/Write). USART_RQR register is a write only
register. So, read before write isn't correct / relevant to flush
the FIFOs.
Replace stm32_usart_set_bits call by writel_relaxed.

Fixes: 84872dc448fe ("serial: stm32: add RX and TX FIFO flush")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index bdd7ca490021..45203648172b 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -657,7 +657,7 @@ static int stm32_usart_startup(struct uart_port *port)
 
/* RX FIFO Flush */
if (ofs->rqr != UNDEF_REG)
-   stm32_usart_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
+   writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr);
 
/* RX enabling */
val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
@@ -762,8 +762,8 @@ static void stm32_usart_set_termios(struct uart_port *port,
 
/* flush RX & TX FIFO */
if (ofs->rqr != UNDEF_REG)
-   stm32_usart_set_bits(port, ofs->rqr,
-USART_RQR_TXFRQ | USART_RQR_RXFRQ);
+   writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ,
+  port->membase + ofs->rqr);
 
cr1 = USART_CR1_TE | USART_CR1_RE;
if (stm32_port->fifoen)
-- 
2.17.1



[PATCH 08/13] serial: stm32: fix tx dma completion, release channel

2021-02-19 Thread Erwan Le Ray
This patch add a proper release of dma channels when completing dma tx.

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 4ba164820904..7da16d468b84 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -292,6 +292,7 @@ static void stm32_usart_tx_dma_complete(void *arg)
struct stm32_port *stm32port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = >info->ofs;
 
+   dmaengine_terminate_async(stm32port->tx_ch);
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32port->tx_dma_busy = false;
 
-- 
2.17.1



[PATCH 01/13] serial: stm32: fix probe and remove order for dma

2021-02-19 Thread Erwan Le Ray
The probe and remove orders are wrong as the uart_port is registered
before saving device data in the probe, and unregistered after DMA
resource deallocation in the remove. uart_port registering should be
done at the end of probe and unregistering should be done at the begin of
remove to avoid resource allocation issues.

Fix probe and remove orders. This enforce resource allocation occur at
proper time.
Terminate both DMA rx and tx transfers before removing device.

Move pm_runtime after uart_remove_one_port() call in remove() to keep the
probe error path.

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index dde6d526362d..c67029ebcac8 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1255,10 +1255,6 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
device_set_wakeup_enable(>dev, false);
}
 
-   ret = uart_add_one_port(_usart_driver, >port);
-   if (ret)
-   goto err_wirq;
-
ret = stm32_usart_of_dma_rx_probe(stm32port, pdev);
if (ret)
dev_info(>dev, "interrupt mode used for rx (no dma)\n");
@@ -1272,11 +1268,40 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
pm_runtime_get_noresume(>dev);
pm_runtime_set_active(>dev);
pm_runtime_enable(>dev);
+
+   ret = uart_add_one_port(_usart_driver, >port);
+   if (ret)
+   goto err_port;
+
pm_runtime_put_sync(>dev);
 
return 0;
 
-err_wirq:
+err_port:
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_put_noidle(>dev);
+
+   if (stm32port->rx_ch) {
+   dmaengine_terminate_async(stm32port->rx_ch);
+   dma_release_channel(stm32port->rx_ch);
+   }
+
+   if (stm32port->rx_dma_buf)
+   dma_free_coherent(>dev,
+ RX_BUF_L, stm32port->rx_buf,
+ stm32port->rx_dma_buf);
+
+   if (stm32port->tx_ch) {
+   dmaengine_terminate_async(stm32port->tx_ch);
+   dma_release_channel(stm32port->tx_ch);
+   }
+
+   if (stm32port->tx_dma_buf)
+   dma_free_coherent(>dev,
+ TX_BUF_L, stm32port->tx_buf,
+ stm32port->tx_dma_buf);
+
if (stm32port->wakeirq > 0)
dev_pm_clear_wake_irq(>dev);
 
@@ -1298,11 +1323,20 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
int err;
 
pm_runtime_get_sync(>dev);
+   err = uart_remove_one_port(_usart_driver, port);
+   if (err)
+   return(err);
+
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_put_noidle(>dev);
 
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
 
-   if (stm32_port->rx_ch)
+   if (stm32_port->rx_ch) {
+   dmaengine_terminate_async(stm32_port->rx_ch);
dma_release_channel(stm32_port->rx_ch);
+   }
 
if (stm32_port->rx_dma_buf)
dma_free_coherent(>dev,
@@ -1311,8 +1345,10 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
 
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
 
-   if (stm32_port->tx_ch)
+   if (stm32_port->tx_ch) {
+   dmaengine_terminate_async(stm32_port->tx_ch);
dma_release_channel(stm32_port->tx_ch);
+   }
 
if (stm32_port->tx_dma_buf)
dma_free_coherent(>dev,
@@ -1326,12 +1362,7 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
 
stm32_usart_deinit_port(stm32_port);
 
-   err = uart_remove_one_port(_usart_driver, port);
-
-   pm_runtime_disable(>dev);
-   pm_runtime_put_noidle(>dev);
-
-   return err;
+   return 0;
 }
 
 #ifdef CONFIG_SERIAL_STM32_CONSOLE
-- 
2.17.1



[PATCH 07/13] serial: stm32: fix a deadlock in set_termios

2021-02-19 Thread Erwan Le Ray
CTS/RTS GPIOs support that has been added recently to STM32 UART driver has
introduced scheduled code in a set_termios part protected by a spin lock.
This generates a potential deadlock scenario:

Chain exists of:
_desc_lock_class --> console_owner --> _lock_key

Possible unsafe locking scenario:

 CPU0CPU1
 
lock(_lock_key);
   lock(console_owner);
   lock(_lock_key);
lock(_desc_lock_class);

*** DEADLOCK ***
4 locks held by stty/766:

Move the scheduled code after the spinlock.

Fixes: 6cf61b9bd7cc ("tty: serial: Add modem control gpio support for STM32 
UART")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 14011183edfe..4ba164820904 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -829,12 +829,6 @@ static void stm32_usart_set_termios(struct uart_port *port,
cr3 |= USART_CR3_CTSE | USART_CR3_RTSE;
}
 
-   /* Handle modem control interrupts */
-   if (UART_ENABLE_MS(port, termios->c_cflag))
-   stm32_usart_enable_ms(port);
-   else
-   stm32_usart_disable_ms(port);
-
usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
 
/*
@@ -916,6 +910,12 @@ static void stm32_usart_set_termios(struct uart_port *port,
 
stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
spin_unlock_irqrestore(>lock, flags);
+
+   /* Handle modem control interrupts */
+   if (UART_ENABLE_MS(port, termios->c_cflag))
+   stm32_usart_enable_ms(port);
+   else
+   stm32_usart_disable_ms(port);
 }
 
 static const char *stm32_usart_type(struct uart_port *port)
-- 
2.17.1



[PATCH 09/13] serial: stm32: call stm32_transmit_chars locked

2021-02-19 Thread Erwan Le Ray
stm32_transmit_chars should be called under lock also in tx DMA callback.

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 
Signed-off-by: Fabrice Gasnier 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 7da16d468b84..bdd7ca490021 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -291,13 +291,16 @@ static void stm32_usart_tx_dma_complete(void *arg)
struct uart_port *port = arg;
struct stm32_port *stm32port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = >info->ofs;
+   unsigned long flags;
 
dmaengine_terminate_async(stm32port->tx_ch);
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32port->tx_dma_busy = false;
 
/* Let's see if we have pending data to send */
+   spin_lock_irqsave(>lock, flags);
stm32_usart_transmit_chars(port);
+   spin_unlock_irqrestore(>lock, flags);
 }
 
 static void stm32_usart_tx_interrupt_enable(struct uart_port *port)
-- 
2.17.1



[PATCH 06/13] serial: stm32: fix wake-up flag handling

2021-02-19 Thread Erwan Le Ray
This patch fixes several issue with wake-up handling:
- the WUF irq is handled several times at wake-up
- the USART is disabled / enabled at suspend to set wake-up flag.
It can cause glitches during RX.

This patch fix those issues:
- clear wake-up flag and disable wake-up irq in WUF irq handling
- enable wake-up from low power on start bit detection at port
configuration
- Unmask the wake-up flag irq at suspend and mask it at resume

In addition, pm_wakeup_event handling is moved from receice_chars to WUF
irq handling.

Fixes: 270e5a74fe4c ("serial: stm32: add wakeup mechanism")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 524c55751023..14011183edfe 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -218,9 +218,6 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
u32 sr;
char flag;
 
-   if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
-   pm_wakeup_event(tport->tty->dev, 0);
-
if (threaded)
spin_lock_irqsave(>lock, flags);
else
@@ -463,6 +460,7 @@ static void stm32_usart_transmit_chars(struct uart_port 
*port)
 static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
 {
struct uart_port *port = ptr;
+   struct tty_port *tport = >state->port;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
u32 sr;
@@ -473,9 +471,14 @@ static irqreturn_t stm32_usart_interrupt(int irq, void 
*ptr)
writel_relaxed(USART_ICR_RTOCF,
   port->membase + ofs->icr);
 
-   if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG)
+   if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) {
+   /* Clear wake up flag and disable wake up interrupt */
writel_relaxed(USART_ICR_WUCF,
   port->membase + ofs->icr);
+   stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
+   if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
+   pm_wakeup_event(tport->tty->dev, 0);
+   }
 
if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
stm32_usart_receive_chars(port, false);
@@ -901,6 +904,12 @@ static void stm32_usart_set_termios(struct uart_port *port,
cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
}
 
+   /* Configure wake up from low power on start bit detection */
+   if (stm32_port->wakeirq > 0) {
+   cr3 &= ~USART_CR3_WUS_MASK;
+   cr3 |= USART_CR3_WUS_START_BIT;
+   }
+
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr2, port->membase + ofs->cr2);
writel_relaxed(cr1, port->membase + ofs->cr1);
@@ -1479,23 +1488,20 @@ static void __maybe_unused 
stm32_usart_serial_en_wakeup(struct uart_port *port,
 {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
-   struct stm32_usart_config *cfg = _port->info->cfg;
-   u32 val;
 
if (stm32_port->wakeirq <= 0)
return;
 
+   /*
+* Enable low-power wake-up and wake-up irq if argument is set to
+* "enable", disable low-power wake-up and wake-up irq otherwise
+*/
if (enable) {
-   stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM);
-   val = readl_relaxed(port->membase + ofs->cr3);
-   val &= ~USART_CR3_WUS_MASK;
-   /* Enable Wake up interrupt from low power on start bit */
-   val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE;
-   writel_relaxed(val, port->membase + ofs->cr3);
-   stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+   stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE);
} else {
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM);
+   stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
}
 }
 
-- 
2.17.1



[PATCH 00/13] stm32 usart various fixes

2021-02-19 Thread Erwan Le Ray
This series brings various fixes to stm32-usart driver.

Erwan Le Ray (13):
  serial: stm32: fix probe and remove order for dma
  serial: stm32: fix startup by enabling usart for reception
  serial: stm32: fix incorrect characters on console
  serial: stm32: fix TX and RX FIFO thresholds
  serial: stm32: fix a deadlock condition with wakeup event
  serial: stm32: fix wake-up flag handling
  serial: stm32: fix a deadlock in set_termios
  serial: stm32: fix tx dma completion, release channel
  serial: stm32: call stm32_transmit_chars locked
  serial: stm32: fix FIFO flush in startup and set_termios
  serial: stm32: add FIFO flush when port is closed
  serial: stm32: fix tx_empty condition
  serial: stm32: add support for "flush_buffer" ops

 drivers/tty/serial/stm32-usart.c | 198 +--
 drivers/tty/serial/stm32-usart.h |   3 -
 2 files changed, 135 insertions(+), 66 deletions(-)

-- 
2.17.1



[PATCH 02/13] serial: stm32: fix startup by enabling usart for reception

2021-02-19 Thread Erwan Le Ray
RX is configured, but usart is not enabled in startup function.
Kernel documentation specifies that startup should enable the port for
reception.
Fix the startup by enabling usart for reception.

Fixes: 84872dc448fe ("serial: stm32: add RX and TX FIFO flush")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index c67029ebcac8..33a479062948 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -634,6 +634,7 @@ static int stm32_usart_startup(struct uart_port *port)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
+   struct stm32_usart_config *cfg = _port->info->cfg;
const char *name = to_platform_device(port->dev)->name;
u32 val;
int ret;
@@ -658,7 +659,7 @@ static int stm32_usart_startup(struct uart_port *port)
}
 
/* RX FIFO enabling */
-   val = stm32_port->cr1_irq | USART_CR1_RE;
+   val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
stm32_usart_set_bits(port, ofs->cr1, val);
-- 
2.17.1



[PATCH 04/13] serial: stm32: fix TX and RX FIFO thresholds

2021-02-19 Thread Erwan Le Ray
TX and RX FIFO thresholds may be cleared after suspend/resume, depending
on the low power mode.

Those configurations (done in startup) are not effective for UART console,
as:
- the reference manual indicates that FIFOEN bit can only be written when
  the USART is disabled (UE=0)
- a set_termios (where UE is set) is requested firstly for console
  enabling, before the startup.

Fixes: 84872dc448fe ("serial: stm32: add RX and TX FIFO flush")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 7710de947aa3..d409a23806b1 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -649,19 +649,8 @@ static int stm32_usart_startup(struct uart_port *port)
if (ofs->rqr != UNDEF_REG)
stm32_usart_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
 
-   /* Tx and RX FIFO configuration */
-   if (stm32_port->fifoen) {
-   val = readl_relaxed(port->membase + ofs->cr3);
-   val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
-   val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
-   val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
-   writel_relaxed(val, port->membase + ofs->cr3);
-   }
-
-   /* RX FIFO enabling */
+   /* RX enabling */
val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
-   if (stm32_port->fifoen)
-   val |= USART_CR1_FIFOEN;
stm32_usart_set_bits(port, ofs->cr1, val);
 
return 0;
@@ -770,9 +759,15 @@ static void stm32_usart_set_termios(struct uart_port *port,
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
cr2 = 0;
+
+   /* Tx and RX FIFO configuration */
cr3 = readl_relaxed(port->membase + ofs->cr3);
-   cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE
-   | USART_CR3_TXFTCFG_MASK;
+   cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE;
+   if (stm32_port->fifoen) {
+   cr3 &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
+   cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
+   cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
+   }
 
if (cflag & CSTOPB)
cr2 |= USART_CR2_STOP_2B;
-- 
2.17.1



[PATCH 05/13] serial: stm32: fix a deadlock condition with wakeup event

2021-02-19 Thread Erwan Le Ray
Deadlock issue is seen when enabling CONFIG_PROVE_LOCKING=Y, and uart
console as wakeup source. Deadlock occurs when resuming from low power
mode if system is waked up via usart console.
The deadlock is triggered 100% when also disabling console suspend prior
to go to suspend.

Simplified call stack, deadlock condition:
- stm32_console_write <-- spin_lock already held
- print_circular_bug
- pm_wakeup_dev_event <-- triggers lockdep as seen above
- stm32_receive_chars
- stm32_interrupt <-- wakeup via uart console, takes the lock

So, revisit spin_lock in stm32-usart driver:
- there is no need to hold the lock to access ICR (atomic clear of status
  flags)
- only hold the lock inside stm32_receive_chars() routine (no need to
  call pm_wakeup_dev_event with lock held)
- keep stm32_transmit_chars() routine called with lock held

Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: Erwan Le Ray 
Signed-off-by: Fabrice Gasnier 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index d409a23806b1..524c55751023 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -214,13 +214,18 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
struct tty_port *tport = >state->port;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
-   unsigned long c;
+   unsigned long c, flags;
u32 sr;
char flag;
 
if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0);
 
+   if (threaded)
+   spin_lock_irqsave(>lock, flags);
+   else
+   spin_lock(>lock);
+
while (stm32_usart_pending_rx(port, , _port->last_res,
  threaded)) {
sr |= USART_SR_DUMMY_RX;
@@ -276,9 +281,12 @@ static void stm32_usart_receive_chars(struct uart_port 
*port, bool threaded)
uart_insert_char(port, sr, USART_SR_ORE, c, flag);
}
 
-   spin_unlock(>lock);
+   if (threaded)
+   spin_unlock_irqrestore(>lock, flags);
+   else
+   spin_unlock(>lock);
+
tty_flip_buffer_push(tport);
-   spin_lock(>lock);
 }
 
 static void stm32_usart_tx_dma_complete(void *arg)
@@ -459,8 +467,6 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
struct stm32_usart_offsets *ofs = _port->info->ofs;
u32 sr;
 
-   spin_lock(>lock);
-
sr = readl_relaxed(port->membase + ofs->isr);
 
if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
@@ -474,10 +480,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void 
*ptr)
if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
stm32_usart_receive_chars(port, false);
 
-   if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch))
+   if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
+   spin_lock(>lock);
stm32_usart_transmit_chars(port);
-
-   spin_unlock(>lock);
+   spin_unlock(>lock);
+   }
 
if (stm32_port->rx_ch)
return IRQ_WAKE_THREAD;
@@ -490,13 +497,9 @@ static irqreturn_t stm32_usart_threaded_interrupt(int irq, 
void *ptr)
struct uart_port *port = ptr;
struct stm32_port *stm32_port = to_stm32_port(port);
 
-   spin_lock(>lock);
-
if (stm32_port->rx_ch)
stm32_usart_receive_chars(port, true);
 
-   spin_unlock(>lock);
-
return IRQ_HANDLED;
 }
 
-- 
2.17.1



[PATCH 03/13] serial: stm32: fix incorrect characters on console

2021-02-19 Thread Erwan Le Ray
Incorrect characters are observed on console during boot. This issue occurs
when init/main.c is modifying termios settings to open /dev/console on the
rootfs.

This patch adds a waiting loop in set_termios to wait for TX shift register
empty (and TX FIFO if any) before stopping serial port.

Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 33a479062948..7710de947aa3 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -738,8 +738,9 @@ static void stm32_usart_set_termios(struct uart_port *port,
unsigned int baud, bits;
u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag;
-   u32 cr1, cr2, cr3;
+   u32 cr1, cr2, cr3, isr;
unsigned long flags;
+   int ret;
 
if (!stm32_port->hw_flow_control)
cflag &= ~CRTSCTS;
@@ -748,6 +749,15 @@ static void stm32_usart_set_termios(struct uart_port *port,
 
spin_lock_irqsave(>lock, flags);
 
+   ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
+   isr,
+   (isr & USART_SR_TC),
+   10, 10);
+
+   /* Send the TC error message only when ISR_TC is not set. */
+   if (ret)
+   dev_err(port->dev, "Transmission is not complete\n");
+
/* Stop serial port and reset value */
writel_relaxed(0, port->membase + ofs->cr1);
 
-- 
2.17.1



[PATCH 1/1] serial: stm32: improve platform_get_irq condition handling in init_port

2021-01-21 Thread Erwan Le Ray
Replace "ret" variable by "irq" variable from platform_get_irq condition
handling in stm32_init_port as suggested by Jiri in "STM32 uart cleanup and
improvement" series review.
This change will prevent port->irq to be unexpectly modified by a potential
change of "ret" value introduced by a new patch.

Suggested-by: Jiri Slaby 
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 6a9a5ef5f5ba..dde6d526362d 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -981,11 +981,11 @@ static int stm32_usart_init_port(struct stm32_port 
*stm32port,
 {
struct uart_port *port = >port;
struct resource *res;
-   int ret;
+   int ret, irq;
 
-   ret = platform_get_irq(pdev, 0);
-   if (ret <= 0)
-   return ret ? : -ENODEV;
+   irq = platform_get_irq(pdev, 0);
+   if (irq <= 0)
+   return irq ? : -ENODEV;
 
port->iotype= UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
@@ -993,7 +993,7 @@ static int stm32_usart_init_port(struct stm32_port 
*stm32port,
port->dev   = >dev;
port->fifosize  = stm32port->info->cfg.fifosize;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
-   port->irq = ret;
+   port->irq = irq;
port->rs485_config = stm32_usart_config_rs485;
 
ret = stm32_usart_init_rs485(port, pdev);
-- 
2.17.1



Re: [PATCH v2 2/8] serial: stm32: fix code cleaning warnings and checks

2021-01-12 Thread Erwan LE RAY

Hello Greg,

As the V2 is already in your tty-next branch, how do want me to proceed 
to deliver the fix for Jiri remark ?

Do you expect a V3 or a new fix ?

Best Regards, Erwan.


On 1/11/21 10:58 AM, Jiri Slaby wrote:

On 06. 01. 21, 17:21, Erwan Le Ray wrote:

--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c

...
@@ -973,18 +971,17 @@ static int stm32_init_port(struct stm32_port 
*stm32port,

Ā  struct resource *res;
Ā  int ret;
+Ā Ā Ā  ret = platform_get_irq(pdev, 0);
+Ā Ā Ā  if (ret <= 0)
+Ā Ā Ā  return ret ? : -ENODEV;
+
Ā  port->iotypeĀ Ā Ā  = UPIO_MEM;
Ā  port->flagsĀ Ā Ā  = UPF_BOOT_AUTOCONF;
Ā  port->opsĀ Ā Ā  = _uart_ops;
Ā  port->devĀ Ā Ā  = >dev;
Ā  port->fifosizeĀ Ā Ā  = stm32port->info->cfg.fifosize;
Ā  port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
-
-Ā Ā Ā  ret = platform_get_irq(pdev, 0);
-Ā Ā Ā  if (ret <= 0)
-Ā Ā Ā  return ret ? : -ENODEV;
Ā  port->irq = ret;


I would move this set from ret above too. Or introduce a new variable, 
e.g. "irq".


thanks,


[PATCH v2 7/8] serial: stm32: clean probe and remove port deinit

2021-01-06 Thread Erwan Le Ray
Clean probe and remove port deinit by moving clk_disable_unprepare in a
new dedicated deinit_port function.

Signed-off-by: Erwan Le Ray 
Signed-off-by: Etienne Carriere 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 0d6c7f3375f0..9d73f6976586 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -970,6 +970,11 @@ static const struct uart_ops stm32_uart_ops = {
.verify_port= stm32_usart_verify_port,
 };
 
+static void stm32_usart_deinit_port(struct stm32_port *stm32port)
+{
+   clk_disable_unprepare(stm32port->clk);
+}
+
 static int stm32_usart_init_port(struct stm32_port *stm32port,
 struct platform_device *pdev)
 {
@@ -1279,7 +1284,7 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
device_init_wakeup(>dev, false);
 
 err_uninit:
-   clk_disable_unprepare(stm32port->clk);
+   stm32_usart_deinit_port(stm32port);
 
return ret;
 }
@@ -1318,7 +1323,7 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
device_init_wakeup(>dev, false);
}
 
-   clk_disable_unprepare(stm32_port->clk);
+   stm32_usart_deinit_port(stm32_port);
 
err = uart_remove_one_port(_usart_driver, port);
 
-- 
2.17.1



[PATCH v2 8/8] serial: stm32: update transmission complete error message in shutdown

2021-01-06 Thread Erwan Le Ray
The transmission complete error message provides the status of the
ISR_USART_TC bit. This bit, when set, indicates that the transmission
has not been completed.
The bit status indication is not a very understandable information.
The error message sent on console should indicate that the transmission is
not complete, instead of providing USART_TC bit status.
Update the error message and add a comment for better understanding.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 9d73f6976586..6a9a5ef5f5ba 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -687,8 +687,9 @@ static void stm32_usart_shutdown(struct uart_port *port)
 isr, (isr & USART_SR_TC),
 10, 10);
 
+   /* Send the TC error message only when ISR_TC is not set */
if (ret)
-   dev_err(port->dev, "transmission complete not set\n");
+   dev_err(port->dev, "Transmission is not complete\n");
 
stm32_usart_clr_bits(port, ofs->cr1, val);
 
-- 
2.17.1



[PATCH v2 6/8] serial: stm32: update conflicting RTS/CTS config comment

2021-01-06 Thread Erwan Le Ray
The comment for conflicting RTS/CTS config refers to "st, hw-flow-ctrl",
but this property is deprecated since the generic RTS/CTS property has
been introduced by the patch 'serial: stm32: Use generic DT binding for
announcing RTS/CTS lines'.
Update the comment to refer to both generic and deprecated RTS/CTS
properties.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 938d2c4aeaed..0d6c7f3375f0 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1031,7 +1031,10 @@ static int stm32_usart_init_port(struct stm32_port 
*stm32port,
goto err_clk;
}
 
-   /* Both CTS/RTS gpios and "st,hw-flow-ctrl" should not be specified */
+   /*
+* Both CTS/RTS gpios and "st,hw-flow-ctrl" (deprecated) or 
"uart-has-rtscts"
+* properties should not be specified.
+*/
if (stm32port->hw_flow_control) {
if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) ||
mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) {
-- 
2.17.1



[PATCH v2 5/8] dt-bindings: serial: stm32: update rts-gpios and cts-gpios

2021-01-06 Thread Erwan Le Ray
Update rts-gpios and cts-gpios:
- remove max-items as already defined in serial.yaml
- add a note describing rts-gpios and cts-gpios usage with stm32

Document the use of cts-gpios and rts-gpios for flow control in STM32 UART
controller. These properties can be used instead of 'uart-has-rtscts' or
'st,hw-flow-ctrl' (deprecated) for making use of any gpio pins for flow
control instead of dedicated pins.
It should be noted that both cts-gpios/rts-gpios and 'uart-has-rtscts' or
'st,hw-flow-ctrl' (deprecated) properties cannot co-exist in a design.

Acked-by: Rob Herring 
Signed-off-by: Erwan Le Ray 

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml 
b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
index 06d5f251ec88..8631678283f9 100644
--- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
@@ -50,11 +50,14 @@ properties:
 minItems: 1
 maxItems: 2
 
-  cts-gpios:
-maxItems: 1
-
-  rts-gpios:
-maxItems: 1
+# cts-gpios and rts-gpios properties can be used instead of 'uart-has-rtscts'
+# or 'st,hw-flow-ctrl' (deprecated) for making use of any gpio pins for flow
+# control instead of dedicated pins.
+#
+# It should be noted that both cts-gpios/rts-gpios and 'uart-has-rtscts' or
+# 'st,hw-flow-ctrl' (deprecated) properties cannot co-exist in a design.
+  cts-gpios: true
+  rts-gpios: true
 
   wakeup-source: true
 
-- 
2.17.1



[PATCH v2 3/8] serial: stm32: add "_usart" prefix in functions name

2021-01-06 Thread Erwan Le Ray
Adds the prefix "_usart" in the name of stm32 usart functions in order to
ease the usage of kernel trace and tools, such as f-trace.
Allows to trace "stm32_usart_*" functions with f-trace. Without this patch,
all the driver functions needs to be added manually in f-trace filter.

Signed-off-by: Erwan Le Ray 
Signed-off-by: Valentin Caron 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index a0ef86d71317..717a97759928 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -34,15 +34,15 @@
 #include "serial_mctrl_gpio.h"
 #include "stm32-usart.h"
 
-static void stm32_stop_tx(struct uart_port *port);
-static void stm32_transmit_chars(struct uart_port *port);
+static void stm32_usart_stop_tx(struct uart_port *port);
+static void stm32_usart_transmit_chars(struct uart_port *port);
 
 static inline struct stm32_port *to_stm32_port(struct uart_port *port)
 {
return container_of(port, struct stm32_port, port);
 }
 
-static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+static void stm32_usart_set_bits(struct uart_port *port, u32 reg, u32 bits)
 {
u32 val;
 
@@ -51,7 +51,7 @@ static void stm32_set_bits(struct uart_port *port, u32 reg, 
u32 bits)
writel_relaxed(val, port->membase + reg);
 }
 
-static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits)
 {
u32 val;
 
@@ -60,8 +60,8 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, 
u32 bits)
writel_relaxed(val, port->membase + reg);
 }
 
-static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
-  u32 delay_DDE, u32 baud)
+static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
+u32 delay_DDE, u32 baud)
 {
u32 rs485_deat_dedt;
u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT);
@@ -95,8 +95,8 @@ static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 
delay_ADE,
*cr1 |= rs485_deat_dedt;
 }
 
-static int stm32_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+static int stm32_usart_config_rs485(struct uart_port *port,
+   struct serial_rs485 *rs485conf)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
@@ -104,7 +104,7 @@ static int stm32_config_rs485(struct uart_port *port,
u32 usartdiv, baud, cr1, cr3;
bool over8;
 
-   stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+   stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
 
port->rs485 = *rs485conf;
 
@@ -122,9 +122,10 @@ static int stm32_config_rs485(struct uart_port *port,
   << USART_BRR_04_R_SHIFT;
 
baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv);
-   stm32_config_reg_rs485(, ,
-  rs485conf->delay_rts_before_send,
-  rs485conf->delay_rts_after_send, baud);
+   stm32_usart_config_reg_rs485(, ,
+rs485conf->delay_rts_before_send,
+rs485conf->delay_rts_after_send,
+baud);
 
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
cr3 &= ~USART_CR3_DEP;
@@ -137,18 +138,19 @@ static int stm32_config_rs485(struct uart_port *port,
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr1, port->membase + ofs->cr1);
} else {
-   stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP);
-   stm32_clr_bits(port, ofs->cr1,
-  USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
+   stm32_usart_clr_bits(port, ofs->cr3,
+USART_CR3_DEM | USART_CR3_DEP);
+   stm32_usart_clr_bits(port, ofs->cr1,
+USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
}
 
-   stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+   stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
 
return 0;
 }
 
-static int stm32_init_rs485(struct uart_port *port,
-   struct platform_device *pdev)
+static int stm32_usart_init_rs485(struct uart_port *port,
+ struct platform_device *pdev)
 {
struct serial_rs485 *rs485conf = >rs485;
 
@@ -162,8 +164,8 @@ static int stm32_init_rs485(struct uart_port *port,
return uart_get_rs485_mode

[PATCH v2 4/8] serial: stm32: add author

2021-01-06 Thread Erwan Le Ray
Update email address add new author in authors list.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 717a97759928..938d2c4aeaed 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -3,7 +3,8 @@
  * Copyright (C) Maxime Coquelin 2015
  * Copyright (C) STMicroelectronics SA 2017
  * Authors:  Maxime Coquelin 
- *  Gerald Baeza 
+ *  Gerald Baeza 
+ *  Erwan Le Ray 
  *
  * Inspired by st-asc.c from STMicroelectronics (c)
  */
-- 
2.17.1



[PATCH v2 2/8] serial: stm32: fix code cleaning warnings and checks

2021-01-06 Thread Erwan Le Ray
Fixes checkpatch --strict warnings and checks:
- checkpatch --strict "Unnecessary parentheses"
- checkpatch --strict "Blank lines aren't necessary before a close brace
- checkpatch --strict "Alignment should match open parenthesis"
- checkpatch --strict "Please don't use multiple blank lines"
- checkpatch --strict "Comparison to NULL could be written ..."
- visual check code ordering warning

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 6248304a001f..a0ef86d71317 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -176,8 +176,7 @@ static int stm32_pending_rx(struct uart_port *port, u32 
*sr, int *last_res,
status = dmaengine_tx_status(stm32_port->rx_ch,
 stm32_port->rx_ch->cookie,
 );
-   if ((status == DMA_IN_PROGRESS) &&
-   (*last_res != state.residue))
+   if (status == DMA_IN_PROGRESS && (*last_res != state.residue))
return 1;
else
return 0;
@@ -464,7 +463,7 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
writel_relaxed(USART_ICR_RTOCF,
   port->membase + ofs->icr);
 
-   if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG))
+   if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG)
writel_relaxed(USART_ICR_WUCF,
   port->membase + ofs->icr);
 
@@ -620,7 +619,6 @@ static void stm32_stop_rx(struct uart_port *port)
stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
if (stm32_port->cr3_irq)
stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
-
 }
 
 /* Handle breaks - ignored by us */
@@ -724,7 +722,7 @@ static unsigned int stm32_get_databits(struct ktermios 
*termios)
 }
 
 static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
-   struct ktermios *old)
+ struct ktermios *old)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
@@ -923,7 +921,7 @@ stm32_verify_port(struct uart_port *port, struct 
serial_struct *ser)
 }
 
 static void stm32_pm(struct uart_port *port, unsigned int state,
-   unsigned int oldstate)
+unsigned int oldstate)
 {
struct stm32_port *stm32port = container_of(port,
struct stm32_port, port);
@@ -973,18 +971,17 @@ static int stm32_init_port(struct stm32_port *stm32port,
struct resource *res;
int ret;
 
+   ret = platform_get_irq(pdev, 0);
+   if (ret <= 0)
+   return ret ? : -ENODEV;
+
port->iotype= UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops   = _uart_ops;
port->dev   = >dev;
port->fifosize  = stm32port->info->cfg.fifosize;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
-
-   ret = platform_get_irq(pdev, 0);
-   if (ret <= 0)
-   return ret ? : -ENODEV;
port->irq = ret;
-
port->rs485_config = stm32_config_rs485;
 
ret = stm32_init_rs485(port, pdev);
@@ -1101,8 +1098,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port 
*stm32port,
return -ENODEV;
}
stm32port->rx_buf = dma_alloc_coherent(>dev, RX_BUF_L,
->rx_dma_buf,
-GFP_KERNEL);
+  >rx_dma_buf,
+  GFP_KERNEL);
if (!stm32port->rx_buf) {
ret = -ENOMEM;
goto alloc_err;
@@ -1177,8 +1174,8 @@ static int stm32_of_dma_tx_probe(struct stm32_port 
*stm32port,
return -ENODEV;
}
stm32port->tx_buf = dma_alloc_coherent(>dev, TX_BUF_L,
->tx_dma_buf,
-GFP_KERNEL);
+  >tx_dma_buf,
+  GFP_KERNEL);
if (!stm32port->tx_buf) {
ret = -ENOMEM;
goto alloc_err;
@@ -1322,7 +1319,6 @@ static int stm32_serial_remove(struct platform_device 
*pdev)
return err;
 }
 
-
 #ifdef CONFIG_SERIAL_STM32_CONSOLE
 static void stm32_console_putchar(struct uart_port *port, int ch)
 {
@@ -1335,7 +1331,8 @@ static void stm32_console_putchar(struct uart_port *port, 
int ch)
writel_relaxed(ch, port->membase + ofs->tdr);
 }
 
-static vo

[PATCH 0/7] STM32 uart cleanup and improvements

2021-01-06 Thread Erwan Le Ray
This series brings various fixes, cleanups and improvements to stm32-usart
driver.

Changes in v2:
- delete DMA cookie variables removal from V1 patch as already done by a
previous patch
- update commit message as DMA cookie variables removal is no more
included in this patch

Erwan Le Ray (8):
  serial: stm32: fix DMA initialization error handling
  serial: stm32: fix code cleaning warnings and checks
  serial: stm32: add "_usart" prefix in functions name
  serial: stm32: add author
  dt-bindings: serial: stm32: update rts-gpios and cts-gpios
  serial: stm32: update conflicting RTS/CTS config comment
  serial: stm32: clean probe and remove port deinit
  serial: stm32: update transmission complete error message in shutdown

 .../bindings/serial/st,stm32-uart.yaml|  13 +-
 drivers/tty/serial/stm32-usart.c  | 415 +-
 2 files changed, 227 insertions(+), 201 deletions(-)

-- 
2.17.1



[PATCH v2 1/8] serial: stm32: fix DMA initialization error handling

2021-01-06 Thread Erwan Le Ray
DMA initialization error handling is not properly implemented in the
driver.
Fix DMA initialization error handling by:
- moving TX DMA descriptor request error handling in a new dedicated
fallback_err label
- adding error handling to TX DMA descriptor submission
- adding error handling to RX DMA descriptor submission

This patch depends on '24832ca3ee85 ("tty: serial: stm32-usart: Remove set
but unused 'cookie' variables")' which unfortunately doesn't include a
"Fixes" tag.

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 
---
Changes in v2:
- delete DMA cookie variables removal from V1 patch as already done by a
previous patch
- update commit message as DMA cookie variables removal is no more
included in this patch

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index f4de32d3f2af..6248304a001f 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -383,17 +383,18 @@ static void stm32_transmit_chars_dma(struct uart_port 
*port)
   DMA_MEM_TO_DEV,
   DMA_PREP_INTERRUPT);
 
-   if (!desc) {
-   for (i = count; i > 0; i--)
-   stm32_transmit_chars_pio(port);
-   return;
-   }
+   if (!desc)
+   goto fallback_err;
 
desc->callback = stm32_tx_dma_complete;
desc->callback_param = port;
 
/* Push current DMA TX transaction in the pending queue */
-   dmaengine_submit(desc);
+   if (dma_submit_error(dmaengine_submit(desc))) {
+   /* dma no yet started, safe to free resources */
+   dmaengine_terminate_async(stm32port->tx_ch);
+   goto fallback_err;
+   }
 
/* Issue pending DMA TX requests */
dma_async_issue_pending(stm32port->tx_ch);
@@ -402,6 +403,11 @@ static void stm32_transmit_chars_dma(struct uart_port 
*port)
 
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
port->icount.tx += count;
+   return;
+
+fallback_err:
+   for (i = count; i > 0; i--)
+   stm32_transmit_chars_pio(port);
 }
 
 static void stm32_transmit_chars(struct uart_port *port)
@@ -1130,7 +1136,11 @@ static int stm32_of_dma_rx_probe(struct stm32_port 
*stm32port,
desc->callback_param = NULL;
 
/* Push current DMA transaction in the pending queue */
-   dmaengine_submit(desc);
+   ret = dma_submit_error(dmaengine_submit(desc));
+   if (ret) {
+   dmaengine_terminate_sync(stm32port->rx_ch);
+   goto config_err;
+   }
 
/* Issue pending DMA requests */
dma_async_issue_pending(stm32port->rx_ch);
-- 
2.17.1



[PATCH 8/8] serial: stm32: update transmission complete error message in shutdown

2020-12-18 Thread Erwan Le Ray
The transmission complete error message provides the status of the
ISR_USART_TC bit. This bit, when set, indicates that the transmission
has not been completed.
The bit status indication is not a very understandable information.
The error message sent on console should indicate that the transmission is
not complete, instead of providing USART_TC bit status.
Update the error message and add a comment for better understanding.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 9d73f6976586..6a9a5ef5f5ba 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -687,8 +687,9 @@ static void stm32_usart_shutdown(struct uart_port *port)
 isr, (isr & USART_SR_TC),
 10, 10);
 
+   /* Send the TC error message only when ISR_TC is not set */
if (ret)
-   dev_err(port->dev, "transmission complete not set\n");
+   dev_err(port->dev, "Transmission is not complete\n");
 
stm32_usart_clr_bits(port, ofs->cr1, val);
 
-- 
2.17.1



[PATCH 0/7] STM32 uart cleanup and improvements

2020-12-18 Thread Erwan Le Ray
This series brings various fixes, cleanups and improvements to stm32-usart
driver.

Erwan Le Ray (8):
  serial: stm32: fix -Wall W=1 compilation warnings
  serial: stm32: fix code cleaning warnings and checks
  serial: stm32: add "_usart" prefix in functions name
  serial: stm32: add author
  dt-bindings: serial: stm32: update rts-gpios and cts-gpios
  serial: stm32: update conflicting RTS/CTS config comment
  serial: stm32: clean probe and remove port deinit
  serial: stm32: update transmission complete error message in shutdown

 .../bindings/serial/st,stm32-uart.yaml|  13 +-
 drivers/tty/serial/stm32-usart.c  | 417 +-
 2 files changed, 227 insertions(+), 203 deletions(-)

-- 
2.17.1



[PATCH 2/8] serial: stm32: fix code cleaning warnings and checks

2020-12-18 Thread Erwan Le Ray
Fixes checkpatch --strict warnings and checks:
- checkpatch --strict "Unnecessary parentheses"
- checkpatch --strict "Blank lines aren't necessary before a close brace
- checkpatch --strict "Alignment should match open parenthesis"
- checkpatch --strict "Please don't use multiple blank lines"
- checkpatch --strict "Comparison to NULL could be written ..."
- visual check code ordering warning

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 6248304a001f..a0ef86d71317 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -176,8 +176,7 @@ static int stm32_pending_rx(struct uart_port *port, u32 
*sr, int *last_res,
status = dmaengine_tx_status(stm32_port->rx_ch,
 stm32_port->rx_ch->cookie,
 );
-   if ((status == DMA_IN_PROGRESS) &&
-   (*last_res != state.residue))
+   if (status == DMA_IN_PROGRESS && (*last_res != state.residue))
return 1;
else
return 0;
@@ -464,7 +463,7 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
writel_relaxed(USART_ICR_RTOCF,
   port->membase + ofs->icr);
 
-   if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG))
+   if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG)
writel_relaxed(USART_ICR_WUCF,
   port->membase + ofs->icr);
 
@@ -620,7 +619,6 @@ static void stm32_stop_rx(struct uart_port *port)
stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
if (stm32_port->cr3_irq)
stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
-
 }
 
 /* Handle breaks - ignored by us */
@@ -724,7 +722,7 @@ static unsigned int stm32_get_databits(struct ktermios 
*termios)
 }
 
 static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
-   struct ktermios *old)
+ struct ktermios *old)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
@@ -923,7 +921,7 @@ stm32_verify_port(struct uart_port *port, struct 
serial_struct *ser)
 }
 
 static void stm32_pm(struct uart_port *port, unsigned int state,
-   unsigned int oldstate)
+unsigned int oldstate)
 {
struct stm32_port *stm32port = container_of(port,
struct stm32_port, port);
@@ -973,18 +971,17 @@ static int stm32_init_port(struct stm32_port *stm32port,
struct resource *res;
int ret;
 
+   ret = platform_get_irq(pdev, 0);
+   if (ret <= 0)
+   return ret ? : -ENODEV;
+
port->iotype= UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops   = _uart_ops;
port->dev   = >dev;
port->fifosize  = stm32port->info->cfg.fifosize;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
-
-   ret = platform_get_irq(pdev, 0);
-   if (ret <= 0)
-   return ret ? : -ENODEV;
port->irq = ret;
-
port->rs485_config = stm32_config_rs485;
 
ret = stm32_init_rs485(port, pdev);
@@ -1101,8 +1098,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port 
*stm32port,
return -ENODEV;
}
stm32port->rx_buf = dma_alloc_coherent(>dev, RX_BUF_L,
->rx_dma_buf,
-GFP_KERNEL);
+  >rx_dma_buf,
+  GFP_KERNEL);
if (!stm32port->rx_buf) {
ret = -ENOMEM;
goto alloc_err;
@@ -1177,8 +1174,8 @@ static int stm32_of_dma_tx_probe(struct stm32_port 
*stm32port,
return -ENODEV;
}
stm32port->tx_buf = dma_alloc_coherent(>dev, TX_BUF_L,
->tx_dma_buf,
-GFP_KERNEL);
+  >tx_dma_buf,
+  GFP_KERNEL);
if (!stm32port->tx_buf) {
ret = -ENOMEM;
goto alloc_err;
@@ -1322,7 +1319,6 @@ static int stm32_serial_remove(struct platform_device 
*pdev)
return err;
 }
 
-
 #ifdef CONFIG_SERIAL_STM32_CONSOLE
 static void stm32_console_putchar(struct uart_port *port, int ch)
 {
@@ -1335,7 +1331,8 @@ static void stm32_console_putchar(struct uart_port *port, 
int ch)
writel_relaxed(ch, port->membase + ofs->tdr);
 }
 
-static vo

[PATCH 6/8] serial: stm32: update conflicting RTS/CTS config comment

2020-12-18 Thread Erwan Le Ray
The comment for conflicting RTS/CTS config refers to "st, hw-flow-ctrl",
but this property is deprecated since the generic RTS/CTS property has
been introduced by the patch 'serial: stm32: Use generic DT binding for
announcing RTS/CTS lines'.
Update the comment to refer to both generic and deprecated RTS/CTS
properties.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 938d2c4aeaed..0d6c7f3375f0 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1031,7 +1031,10 @@ static int stm32_usart_init_port(struct stm32_port 
*stm32port,
goto err_clk;
}
 
-   /* Both CTS/RTS gpios and "st,hw-flow-ctrl" should not be specified */
+   /*
+* Both CTS/RTS gpios and "st,hw-flow-ctrl" (deprecated) or 
"uart-has-rtscts"
+* properties should not be specified.
+*/
if (stm32port->hw_flow_control) {
if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) ||
mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) {
-- 
2.17.1



[PATCH 3/8] serial: stm32: add "_usart" prefix in functions name

2020-12-18 Thread Erwan Le Ray
Adds the prefix "_usart" in the name of stm32 usart functions in order to
ease the usage of kernel trace and tools, such as f-trace.
Allows to trace "stm32_usart_*" functions with f-trace. Without this patch,
all the driver functions needs to be added manually in f-trace filter.

Signed-off-by: Erwan Le Ray 
Signed-off-by: Valentin Caron 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index a0ef86d71317..717a97759928 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -34,15 +34,15 @@
 #include "serial_mctrl_gpio.h"
 #include "stm32-usart.h"
 
-static void stm32_stop_tx(struct uart_port *port);
-static void stm32_transmit_chars(struct uart_port *port);
+static void stm32_usart_stop_tx(struct uart_port *port);
+static void stm32_usart_transmit_chars(struct uart_port *port);
 
 static inline struct stm32_port *to_stm32_port(struct uart_port *port)
 {
return container_of(port, struct stm32_port, port);
 }
 
-static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+static void stm32_usart_set_bits(struct uart_port *port, u32 reg, u32 bits)
 {
u32 val;
 
@@ -51,7 +51,7 @@ static void stm32_set_bits(struct uart_port *port, u32 reg, 
u32 bits)
writel_relaxed(val, port->membase + reg);
 }
 
-static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits)
 {
u32 val;
 
@@ -60,8 +60,8 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, 
u32 bits)
writel_relaxed(val, port->membase + reg);
 }
 
-static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
-  u32 delay_DDE, u32 baud)
+static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
+u32 delay_DDE, u32 baud)
 {
u32 rs485_deat_dedt;
u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT);
@@ -95,8 +95,8 @@ static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 
delay_ADE,
*cr1 |= rs485_deat_dedt;
 }
 
-static int stm32_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+static int stm32_usart_config_rs485(struct uart_port *port,
+   struct serial_rs485 *rs485conf)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
@@ -104,7 +104,7 @@ static int stm32_config_rs485(struct uart_port *port,
u32 usartdiv, baud, cr1, cr3;
bool over8;
 
-   stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+   stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
 
port->rs485 = *rs485conf;
 
@@ -122,9 +122,10 @@ static int stm32_config_rs485(struct uart_port *port,
   << USART_BRR_04_R_SHIFT;
 
baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv);
-   stm32_config_reg_rs485(, ,
-  rs485conf->delay_rts_before_send,
-  rs485conf->delay_rts_after_send, baud);
+   stm32_usart_config_reg_rs485(, ,
+rs485conf->delay_rts_before_send,
+rs485conf->delay_rts_after_send,
+baud);
 
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
cr3 &= ~USART_CR3_DEP;
@@ -137,18 +138,19 @@ static int stm32_config_rs485(struct uart_port *port,
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr1, port->membase + ofs->cr1);
} else {
-   stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP);
-   stm32_clr_bits(port, ofs->cr1,
-  USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
+   stm32_usart_clr_bits(port, ofs->cr3,
+USART_CR3_DEM | USART_CR3_DEP);
+   stm32_usart_clr_bits(port, ofs->cr1,
+USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
}
 
-   stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+   stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
 
return 0;
 }
 
-static int stm32_init_rs485(struct uart_port *port,
-   struct platform_device *pdev)
+static int stm32_usart_init_rs485(struct uart_port *port,
+ struct platform_device *pdev)
 {
struct serial_rs485 *rs485conf = >rs485;
 
@@ -162,8 +164,8 @@ static int stm32_init_rs485(struct uart_port *port,
return uart_get_rs485_mode

[PATCH 5/8] dt-bindings: serial: stm32: update rts-gpios and cts-gpios

2020-12-18 Thread Erwan Le Ray
Update rts-gpios and cts-gpios:
- remove max-items as already defined in serial.yaml
- add a note describing rts-gpios and cts-gpios usage with stm32

Document the use of cts-gpios and rts-gpios for flow control in STM32 UART
controller. These properties can be used instead of 'uart-has-rtscts' or
'st,hw-flow-ctrl' (deprecated) for making use of any gpio pins for flow
control instead of dedicated pins.
It should be noted that both cts-gpios/rts-gpios and 'uart-has-rtscts' or
'st,hw-flow-ctrl' (deprecated) properties cannot co-exist in a design.

Signed-off-by: Erwan Le Ray 

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml 
b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
index 06d5f251ec88..8631678283f9 100644
--- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
@@ -50,11 +50,14 @@ properties:
 minItems: 1
 maxItems: 2
 
-  cts-gpios:
-maxItems: 1
-
-  rts-gpios:
-maxItems: 1
+# cts-gpios and rts-gpios properties can be used instead of 'uart-has-rtscts'
+# or 'st,hw-flow-ctrl' (deprecated) for making use of any gpio pins for flow
+# control instead of dedicated pins.
+#
+# It should be noted that both cts-gpios/rts-gpios and 'uart-has-rtscts' or
+# 'st,hw-flow-ctrl' (deprecated) properties cannot co-exist in a design.
+  cts-gpios: true
+  rts-gpios: true
 
   wakeup-source: true
 
-- 
2.17.1



[PATCH 7/8] serial: stm32: clean probe and remove port deinit

2020-12-18 Thread Erwan Le Ray
Clean probe and remove port deinit by moving clk_disable_unprepare in a
new dedicated deinit_port function.

Signed-off-by: Erwan Le Ray 
Signed-off-by: Etienne Carriere 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 0d6c7f3375f0..9d73f6976586 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -970,6 +970,11 @@ static const struct uart_ops stm32_uart_ops = {
.verify_port= stm32_usart_verify_port,
 };
 
+static void stm32_usart_deinit_port(struct stm32_port *stm32port)
+{
+   clk_disable_unprepare(stm32port->clk);
+}
+
 static int stm32_usart_init_port(struct stm32_port *stm32port,
 struct platform_device *pdev)
 {
@@ -1279,7 +1284,7 @@ static int stm32_usart_serial_probe(struct 
platform_device *pdev)
device_init_wakeup(>dev, false);
 
 err_uninit:
-   clk_disable_unprepare(stm32port->clk);
+   stm32_usart_deinit_port(stm32port);
 
return ret;
 }
@@ -1318,7 +1323,7 @@ static int stm32_usart_serial_remove(struct 
platform_device *pdev)
device_init_wakeup(>dev, false);
}
 
-   clk_disable_unprepare(stm32_port->clk);
+   stm32_usart_deinit_port(stm32_port);
 
err = uart_remove_one_port(_usart_driver, port);
 
-- 
2.17.1



[PATCH 4/8] serial: stm32: add author

2020-12-18 Thread Erwan Le Ray
Update email address add new author in authors list.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 717a97759928..938d2c4aeaed 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -3,7 +3,8 @@
  * Copyright (C) Maxime Coquelin 2015
  * Copyright (C) STMicroelectronics SA 2017
  * Authors:  Maxime Coquelin 
- *  Gerald Baeza 
+ *  Gerald Baeza 
+ *  Erwan Le Ray 
  *
  * Inspired by st-asc.c from STMicroelectronics (c)
  */
-- 
2.17.1



[PATCH 1/8] serial: stm32: fix -Wall W=1 compilation warnings

2020-12-18 Thread Erwan Le Ray
Fix compilations warning detected by -Wall W=1 compilation option:
- warning: variable ā€˜cookieā€™ set but not used

Fixes: 3489187204eb ("serial: stm32: adding dma support")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index ee6c7762d355..6248304a001f 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -350,7 +350,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port)
struct stm32_usart_offsets *ofs = >info->ofs;
struct circ_buf *xmit = >state->xmit;
struct dma_async_tx_descriptor *desc = NULL;
-   dma_cookie_t cookie;
unsigned int count, i;
 
if (stm32port->tx_dma_busy)
@@ -384,17 +383,18 @@ static void stm32_transmit_chars_dma(struct uart_port 
*port)
   DMA_MEM_TO_DEV,
   DMA_PREP_INTERRUPT);
 
-   if (!desc) {
-   for (i = count; i > 0; i--)
-   stm32_transmit_chars_pio(port);
-   return;
-   }
+   if (!desc)
+   goto fallback_err;
 
desc->callback = stm32_tx_dma_complete;
desc->callback_param = port;
 
/* Push current DMA TX transaction in the pending queue */
-   cookie = dmaengine_submit(desc);
+   if (dma_submit_error(dmaengine_submit(desc))) {
+   /* dma no yet started, safe to free resources */
+   dmaengine_terminate_async(stm32port->tx_ch);
+   goto fallback_err;
+   }
 
/* Issue pending DMA TX requests */
dma_async_issue_pending(stm32port->tx_ch);
@@ -403,6 +403,11 @@ static void stm32_transmit_chars_dma(struct uart_port 
*port)
 
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
port->icount.tx += count;
+   return;
+
+fallback_err:
+   for (i = count; i > 0; i--)
+   stm32_transmit_chars_pio(port);
 }
 
 static void stm32_transmit_chars(struct uart_port *port)
@@ -1087,7 +1092,6 @@ static int stm32_of_dma_rx_probe(struct stm32_port 
*stm32port,
struct device *dev = >dev;
struct dma_slave_config config;
struct dma_async_tx_descriptor *desc = NULL;
-   dma_cookie_t cookie;
int ret;
 
/* Request DMA RX channel */
@@ -1132,7 +1136,11 @@ static int stm32_of_dma_rx_probe(struct stm32_port 
*stm32port,
desc->callback_param = NULL;
 
/* Push current DMA transaction in the pending queue */
-   cookie = dmaengine_submit(desc);
+   ret = dma_submit_error(dmaengine_submit(desc));
+   if (ret) {
+   dmaengine_terminate_sync(stm32port->rx_ch);
+   goto config_err;
+   }
 
/* Issue pending DMA requests */
dma_async_issue_pending(stm32port->rx_ch);
-- 
2.17.1



Re: [PATCH 1/2] dt-bindings: serial: add generic DT binding for announcing RTS/CTS lines

2020-06-29 Thread Erwan LE RAY

On 6/27/20 4:18 PM, Greg Kroah-Hartman wrote:
> On Wed, May 20, 2020 at 03:39:31PM +0200, Erwan Le Ray wrote:
>> Add support of generic DT binding for annoucing RTS/CTS lines. The initial
>> binding 'st,hw-flow-control' is not needed anymore since generic binding
>> is available, but is kept for backward compatibility.
>>
>> Signed-off-by: Erwan Le Ray 
>>
>> diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml 
>> b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
>> index 75b8521eb7cb..06d5f251ec88 100644
>> --- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
>> +++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
>> @@ -35,9 +35,11 @@ properties:
>>   description: label associated with this uart
>>   
>> st,hw-flow-ctrl:
>> -description: enable hardware flow control
>> +description: enable hardware flow control (deprecated)
>>   $ref: /schemas/types.yaml#/definitions/flag
>>   
>> +  uart-has-rtscts: true
>> +
>> dmas:
>>   minItems: 1
>>   maxItems: 2
>> -- 
>> 2.17.1
>>
> Did this get ignored by the DT maintainers?  :(

Hi Rob,

Gentle reminder. Could you please provide your feedback on this patch ?

Best Regards, Erwan.


[PATCH v2 3/5] ARM: dts: stm32: add usart3 node to stm32mp157c-ev1

2020-06-18 Thread Erwan Le Ray
Adds the usart3 node to stm32mp157c-ev1 board. usart3 pins are connected to
GPIO Expansion connector. usart3 is disabled by default.

Signed-off-by: Erwan Le Ray 

Changes in v2:
 - Add a comment to indicate how to wire USART3_RTS flow control to the GPIO
   expansion connector on ev1. 

diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts 
b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index b19056557ef0..85628e16d2d5 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -19,6 +19,7 @@
 
aliases {
serial0 = 
+   serial1 = 
ethernet0 = 
};
 
@@ -341,6 +342,20 @@
};
 };
 
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_b>;
+   pinctrl-1 = <_sleep_pins_b>;
+   pinctrl-2 = <_idle_pins_b>;
+   /*
+* HW flow control USART3_RTS is optional, and isn't default wired to
+* the connector. SB23 needs to be soldered in order to use it, and R77
+* (ETH_CLK) should be removed.
+*/
+   uart-has-rtscts;
+   status = "disabled";
+};
+
 _ehci {
phys = <_port0>;
status = "okay";
-- 
2.17.1



[PATCH v2 5/5] ARM: dts: stm32: add usart2 node to stm32mp157c-dk2

2020-06-18 Thread Erwan Le Ray
Adds the usart2 node to stm32mp157c-dk2 board. usart2 pins are connected
to Bluetooth component. usart2 is disabled by default.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts 
b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index ffbae4a8753d..045636555ddd 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -21,6 +21,7 @@
serial0 = 
serial1 = 
serial2 = 
+   serial3 = 
};
 
chosen {
@@ -86,3 +87,11 @@
};
};
 };
+
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_c>;
+   pinctrl-1 = <_sleep_pins_c>;
+   pinctrl-2 = <_idle_pins_c>;
+   status = "disabled";
+};
-- 
2.17.1



[PATCH v2 2/5] ARM: dts: stm32: add usart3 node to stm32mp15xx-dkx boards

2020-06-18 Thread Erwan Le Ray
Adds usart3 node to stm32mp15xx-dkx and usart3 alias to stm32mp157a-dk1
and stm32mp157c-dk2 boards. usart3 pins are connected to GPIO Expansion
connector. usart3 is disabled by default.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts 
b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index d03d4cd2606a..65ee61b7667a 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -18,6 +18,7 @@
aliases {
ethernet0 = 
serial0 = 
+   serial1 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts 
b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index 9a8a26710ac1..fb690a817e28 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -19,6 +19,7 @@
aliases {
ethernet0 = 
serial0 = 
+   serial1 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi 
b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
index e5fdbc149bf4..243aa4b2063d 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
@@ -591,6 +591,15 @@
status = "okay";
 };
 
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_c>;
+   pinctrl-1 = <_sleep_pins_c>;
+   pinctrl-2 = <_idle_pins_c>;
+   uart-has-rtscts;
+   status = "disabled";
+};
+
 _ehci {
phys = <_port0>;
status = "okay";
-- 
2.17.1



[PATCH v2 0/5] STM32 add usart nodes support

2020-06-18 Thread Erwan Le Ray
Add the support of uart instances available on STM32MP157 boards:
- usart3 on stm32mp157c-ev1, stm32mp157a-dk1, and stm32mp157c-dk2
- uart7 on stm32mp157a-dk1 and stm32mp157c-dk2
- usart2 on stm32mp157c-dk2

Erwan Le Ray (5):
  ARM: dts: stm32: add usart2, usart3 and uart7 pins in
stm32mp15-pinctrl
  ARM: dts: stm32: add usart3 node to stm32mp15xx-dkx boards
  ARM: dts: stm32: add usart3 node to stm32mp157c-ev1
  ARM: dts: stm32: add uart7 support to stm32mp15xx-dkx boards
  ARM: dts: stm32: add usart2 node to stm32mp157c-dk2

 arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 138 +++
 arch/arm/boot/dts/stm32mp157a-dk1.dts|   2 +
 arch/arm/boot/dts/stm32mp157c-dk2.dts|  11 ++
 arch/arm/boot/dts/stm32mp157c-ev1.dts|  15 +++
 arch/arm/boot/dts/stm32mp15xx-dkx.dtsi   |  17 +++
 5 files changed, 183 insertions(+)

-- 
2.17.1



[PATCH v2 4/5] ARM: dts: stm32: add uart7 support to stm32mp15xx-dkx boards

2020-06-18 Thread Erwan Le Ray
Adds uart7 node to stm32mp15xx-dkx and uart7 alias to stm32mp157a-dk1 and
stm32mp157c-dk2 boards. uart7 pins are connected to Arduino connector.
uart7 is disabled by default.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts 
b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index 65ee61b7667a..4c8be9c8eb20 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -19,6 +19,7 @@
ethernet0 = 
serial0 = 
serial1 = 
+   serial2 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts 
b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index fb690a817e28..ffbae4a8753d 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -20,6 +20,7 @@
ethernet0 = 
serial0 = 
serial1 = 
+   serial2 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi 
b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
index 243aa4b2063d..cfbe3e2afef2 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
@@ -591,6 +591,14 @@
status = "okay";
 };
 
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_c>;
+   pinctrl-1 = <_sleep_pins_c>;
+   pinctrl-2 = <_idle_pins_c>;
+   status = "disabled";
+};
+
  {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <_pins_c>;
-- 
2.17.1



[PATCH v2 1/5] ARM: dts: stm32: add usart2, usart3 and uart7 pins in stm32mp15-pinctrl

2020-06-18 Thread Erwan Le Ray
Adds usart2_pins_c, usart3_pins_b, usart3_pins_c and uart7_pins_c pins
configurations in stm32mp15-pinctrl.
- usart2_pins_c pins are connected to Bluetooth chip on dk2 board.
- usart3_pins_b pins are connected to GPIO expansion connector on evx board.
- usart3_pins_c pins are connected to GPIO expansion connector on dkx board.
- uart7_pins_c pins are connected to Arduino Uno connector on dkx board.

Signed-off-by: Erwan Le Ray 

Changes in v2:
 - Update UART7 pins comments. Comments indicated "USART" instead of "UART".

diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
index fb98a66977fe..21b0906accf3 100644
--- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
@@ -1658,6 +1658,36 @@
};
};
 
+   uart7_pins_c: uart7-1 {
+   pins1 {
+   pinmux = ; /* UART7_TX */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = ; /* UART7_RX */
+   bias-disable;
+   };
+   };
+
+   uart7_idle_pins_c: uart7-idle-1 {
+   pins1 {
+   pinmux = ; /* UART7_TX */
+   };
+   pins2 {
+   pinmux = ; /* UART7_RX */
+   bias-disable;
+   };
+   };
+
+   uart7_sleep_pins_c: uart7-sleep-1 {
+   pins {
+   pinmux = , /* UART7_TX */
+; /* UART7_RX */
+   };
+   };
+
uart8_pins_a: uart8-0 {
pins1 {
pinmux = ; /* UART8_TX */
@@ -1719,6 +1749,42 @@
};
};
 
+   usart2_pins_c: usart2-0 {
+   pins1 {
+   pinmux = , /* USART2_TX */
+; /* USART2_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <3>;
+   };
+   pins2 {
+   pinmux = , /* USART2_RX */
+; /* USART2_CTS_NSS 
*/
+   bias-disable;
+   };
+   };
+
+   usart2_idle_pins_c: usart2-idle-0 {
+   pins1 {
+   pinmux = , /* USART2_TX */
+, /* USART2_RTS 
*/
+; /* 
USART2_CTS_NSS */
+   };
+   pins2 {
+   pinmux = ; /* USART2_RX */
+   bias-disable;
+   };
+   };
+
+   usart2_sleep_pins_c: usart2-sleep-0 {
+   pins {
+   pinmux = , /* USART2_TX */
+, /* USART2_RTS 
*/
+, /* USART2_RX */
+; /* 
USART2_CTS_NSS */
+   };
+   };
+
usart3_pins_a: usart3-0 {
pins1 {
pinmux = ; /* USART3_TX */
@@ -1732,6 +1798,78 @@
};
};
 
+   usart3_pins_b: usart3-0 {
+   pins1 {
+   pinmux = , /* USART3_TX */
+; /* USART3_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = , /* USART3_RX */
+; /* 
USART3_CTS_NSS */
+   bias-disable;
+   };
+   };
+
+   usart3_idle_pins_b: usart3-idle-0 {
+   pins1 {
+   pinmux = , /* USART3_TX 
*/
+, /* USART3_RTS 
*/
+; /* 
USART3_CTS_NSS */
+   };
+   pins2 {
+   pinmux = ; /* USART3_RX */
+   bias-disable;
+   };
+   };
+
+   usart3_sleep_pins_b: usart3-sleep-0 {
+   pins {
+   pinmux = , /* USART3_TX 
*/
+, /* USART3_RTS 
*/
+, /* 
USART3_CTS_NSS */
+; /* USART3_RX 
*/
+   };
+   };
+
+   usart3_pins_c: usart3-1 {
+   pins1 {
+   pinmux = , /* USART3_TX */
+; /* USART3_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = , /* USART3_RX */
+; /* 
USART3_CTS_NSS */
+   bias-disable;
+   };
+   };
+
+   usart3_idle_p

[PATCH 1/5] ARM: dts: stm32: add usart2, usart3 and uart7 pins in stm32mp15-pinctrl

2020-05-28 Thread Erwan Le Ray
Adds usart2_pins_c, usart3_pins_b, usart3_pins_c and uart7_pins_c pins
configurations in stm32mp15-pinctrl.
- usart2_pins_c pins are connected to Bluetooth chip on dk2 board.
- usart3_pins_b pins are connected to GPIO expansion connector on evx board.
- usart3_pins_c pins are connected to GPIO expansion connector on dkx board.
- uart7_pins_c pins are connected to Arduino Uno connector on dkx board.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
index fb98a66977fe..99e399e4e4c3 100644
--- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
@@ -1658,6 +1658,36 @@
};
};
 
+   uart7_pins_c: uart7-1 {
+   pins1 {
+   pinmux = ; /* USART7_TX */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = ; /* USART7_RX */
+   bias-disable;
+   };
+   };
+
+   uart7_idle_pins_c: uart7-idle-1 {
+   pins1 {
+   pinmux = ; /* USART7_TX */
+   };
+   pins2 {
+   pinmux = ; /* USART7_RX */
+   bias-disable;
+   };
+   };
+
+   uart7_sleep_pins_c: uart7-sleep-1 {
+   pins {
+   pinmux = , /* USART7_TX */
+; /* USART7_RX */
+   };
+   };
+
uart8_pins_a: uart8-0 {
pins1 {
pinmux = ; /* UART8_TX */
@@ -1719,6 +1749,42 @@
};
};
 
+   usart2_pins_c: usart2-0 {
+   pins1 {
+   pinmux = , /* USART2_TX */
+; /* USART2_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <3>;
+   };
+   pins2 {
+   pinmux = , /* USART2_RX */
+; /* USART2_CTS_NSS 
*/
+   bias-disable;
+   };
+   };
+
+   usart2_idle_pins_c: usart2-idle-0 {
+   pins1 {
+   pinmux = , /* USART2_TX */
+, /* USART2_RTS 
*/
+; /* 
USART2_CTS_NSS */
+   };
+   pins2 {
+   pinmux = ; /* USART2_RX */
+   bias-disable;
+   };
+   };
+
+   usart2_sleep_pins_c: usart2-sleep-0 {
+   pins {
+   pinmux = , /* USART2_TX */
+, /* USART2_RTS 
*/
+, /* USART2_RX */
+; /* 
USART2_CTS_NSS */
+   };
+   };
+
usart3_pins_a: usart3-0 {
pins1 {
pinmux = ; /* USART3_TX */
@@ -1732,6 +1798,78 @@
};
};
 
+   usart3_pins_b: usart3-0 {
+   pins1 {
+   pinmux = , /* USART3_TX */
+; /* USART3_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = , /* USART3_RX */
+; /* 
USART3_CTS_NSS */
+   bias-disable;
+   };
+   };
+
+   usart3_idle_pins_b: usart3-idle-0 {
+   pins1 {
+   pinmux = , /* USART3_TX 
*/
+, /* USART3_RTS 
*/
+; /* 
USART3_CTS_NSS */
+   };
+   pins2 {
+   pinmux = ; /* USART3_RX */
+   bias-disable;
+   };
+   };
+
+   usart3_sleep_pins_b: usart3-sleep-0 {
+   pins {
+   pinmux = , /* USART3_TX 
*/
+, /* USART3_RTS 
*/
+, /* 
USART3_CTS_NSS */
+; /* USART3_RX 
*/
+   };
+   };
+
+   usart3_pins_c: usart3-1 {
+   pins1 {
+   pinmux = , /* USART3_TX */
+; /* USART3_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = , /* USART3_RX */
+; /* 
USART3_CTS_NSS */
+   bias-disable;
+   };
+   };
+
+   usart3_idle_pins_c: usart3-idle-1 {
+   pins1 {
+  

[PATCH 1/2] ARM: dts: stm32: fix uart nodes ordering in stm32mp15-pinctrl

2020-05-28 Thread Erwan Le Ray
Fix usart and uart nodes ordering. Several usart nodes didn't respect
expecting ordering.

Fixes: 077e0638fc83 ("ARM: dts: stm32: Add alternate pinmux for USART2 pins on 
stm32mp15")

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
index 7cf535dc05f5..5ff1323236e1 100644
--- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
@@ -1574,67 +1574,6 @@
};
};
 
-   usart2_pins_a: usart2-0 {
-   pins1 {
-   pinmux = , /* USART2_TX */
-; /* USART2_RTS */
-   bias-disable;
-   drive-push-pull;
-   slew-rate = <0>;
-   };
-   pins2 {
-   pinmux = , /* USART2_RX */
-; /* USART2_CTS_NSS 
*/
-   bias-disable;
-   };
-   };
-
-   usart2_sleep_pins_a: usart2-sleep-0 {
-   pins {
-   pinmux = , /* USART2_TX */
-, /* USART2_RTS 
*/
-, /* USART2_RX */
-; /* 
USART2_CTS_NSS */
-   };
-   };
-
-   usart2_pins_b: usart2-1 {
-   pins1 {
-   pinmux = , /* USART2_TX */
-; /* USART2_RTS */
-   bias-disable;
-   drive-push-pull;
-   slew-rate = <0>;
-   };
-   pins2 {
-   pinmux = , /* USART2_RX */
-; /* 
USART2_CTS_NSS */
-   bias-disable;
-   };
-   };
-
-   usart2_sleep_pins_b: usart2-sleep-1 {
-   pins {
-   pinmux = , /* USART2_TX */
-, /* USART2_RTS 
*/
-, /* USART2_RX */
-; /* 
USART2_CTS_NSS */
-   };
-   };
-
-   usart3_pins_a: usart3-0 {
-   pins1 {
-   pinmux = ; /* USART3_TX */
-   bias-disable;
-   drive-push-pull;
-   slew-rate = <0>;
-   };
-   pins2 {
-   pinmux = ; /* USART3_RX */
-   bias-disable;
-   };
-   };
-
uart4_pins_a: uart4-0 {
pins1 {
pinmux = ; /* UART4_TX */
@@ -1732,6 +1671,67 @@
};
};
 
+   usart2_pins_a: usart2-0 {
+   pins1 {
+   pinmux = , /* USART2_TX */
+; /* USART2_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = , /* USART2_RX */
+; /* USART2_CTS_NSS 
*/
+   bias-disable;
+   };
+   };
+
+   usart2_sleep_pins_a: usart2-sleep-0 {
+   pins {
+   pinmux = , /* USART2_TX */
+, /* USART2_RTS 
*/
+, /* USART2_RX */
+; /* 
USART2_CTS_NSS */
+   };
+   };
+
+   usart2_pins_b: usart2-1 {
+   pins1 {
+   pinmux = , /* USART2_TX */
+; /* USART2_RTS */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = , /* USART2_RX */
+; /* 
USART2_CTS_NSS */
+   bias-disable;
+   };
+   };
+
+   usart2_sleep_pins_b: usart2-sleep-1 {
+   pins {
+   pinmux = , /* USART2_TX */
+, /* USART2_RTS 
*/
+, /* USART2_RX */
+; /* 
USART2_CTS_NSS */
+   };
+   };
+
+   usart3_pins_a: usart3-0 {
+   pins1 {
+   pinmux = ; /* USART3_TX */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   pins2 {
+   pinmux = ; /* USART3_RX */
+   bias-disable;
+   };
+   };
+
usbotg_hs_pins_a: usbotg-hs-0 {
pins {
pinmux = ; /* OTG_ID */
-- 
2.17.1



[PATCH 3/5] ARM: dts: stm32: add usart3 node to stm32mp157c-ev1

2020-05-28 Thread Erwan Le Ray
Adds the usart3 node to stm32mp157c-ev1 board. usart3 pins are connected to
GPIO Expansion connector. usart3 is disabled by default.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts 
b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index b19056557ef0..e56dde8d20f8 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -19,6 +19,7 @@
 
aliases {
serial0 = 
+   serial1 = 
ethernet0 = 
};
 
@@ -341,6 +342,15 @@
};
 };
 
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_b>;
+   pinctrl-1 = <_sleep_pins_b>;
+   pinctrl-2 = <_idle_pins_b>;
+   uart-has-rtscts;
+   status = "disabled";
+};
+
 _ehci {
phys = <_port0>;
status = "okay";
-- 
2.17.1



[PATCH 4/5] ARM: dts: stm32: add uart7 support to stm32mp15xx-dkx boards

2020-05-28 Thread Erwan Le Ray
Adds uart7 node to stm32mp15xx-dkx and uart7 alias to stm32mp157a-dk1 and
stm32mp157c-dk2 boards. uart7 pins are connected to Arduino connector.
uart7 is disabled by default.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts 
b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index 65ee61b7667a..4c8be9c8eb20 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -19,6 +19,7 @@
ethernet0 = 
serial0 = 
serial1 = 
+   serial2 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts 
b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index fb690a817e28..ffbae4a8753d 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -20,6 +20,7 @@
ethernet0 = 
serial0 = 
serial1 = 
+   serial2 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi 
b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
index 243aa4b2063d..cfbe3e2afef2 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
@@ -591,6 +591,14 @@
status = "okay";
 };
 
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_c>;
+   pinctrl-1 = <_sleep_pins_c>;
+   pinctrl-2 = <_idle_pins_c>;
+   status = "disabled";
+};
+
  {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <_pins_c>;
-- 
2.17.1



[PATCH 2/5] ARM: dts: stm32: add usart3 node to stm32mp15xx-dkx boards

2020-05-28 Thread Erwan Le Ray
Adds usart3 node to stm32mp15xx-dkx and usart3 alias to stm32mp157a-dk1
and stm32mp157c-dk2 boards. usart3 pins are connected to GPIO Expansion
connector. usart3 is disabled by default.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts 
b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index d03d4cd2606a..65ee61b7667a 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -18,6 +18,7 @@
aliases {
ethernet0 = 
serial0 = 
+   serial1 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts 
b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index 9a8a26710ac1..fb690a817e28 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -19,6 +19,7 @@
aliases {
ethernet0 = 
serial0 = 
+   serial1 = 
};
 
chosen {
diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi 
b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
index e5fdbc149bf4..243aa4b2063d 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
@@ -591,6 +591,15 @@
status = "okay";
 };
 
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_c>;
+   pinctrl-1 = <_sleep_pins_c>;
+   pinctrl-2 = <_idle_pins_c>;
+   uart-has-rtscts;
+   status = "disabled";
+};
+
 _ehci {
phys = <_port0>;
status = "okay";
-- 
2.17.1



[PATCH 5/5] ARM: dts: stm32: add usart2 node to stm32mp157c-dk2

2020-05-28 Thread Erwan Le Ray
Adds the usart2 node to stm32mp157c-dk2 board. usart2 pins are connected
to Bluetooth component. usart2 is disabled by default.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts 
b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index ffbae4a8753d..045636555ddd 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -21,6 +21,7 @@
serial0 = 
serial1 = 
serial2 = 
+   serial3 = 
};
 
chosen {
@@ -86,3 +87,11 @@
};
};
 };
+
+ {
+   pinctrl-names = "default", "sleep", "idle";
+   pinctrl-0 = <_pins_c>;
+   pinctrl-1 = <_sleep_pins_c>;
+   pinctrl-2 = <_idle_pins_c>;
+   status = "disabled";
+};
-- 
2.17.1



[PATCH 2/2] ARM: dts: stm32: fix uart7_pins_a comments in stm32mp15-pinctrl

2020-05-28 Thread Erwan Le Ray
Fix uart7_pins_a comments to indicate UART7 pins instead of UART4 pins.

Fixes: bf4b5f379fed ("ARM: dts: stm32: Add missing pinctrl definitions for 
STM32MP157")

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
index 5ff1323236e1..fb98a66977fe 100644
--- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
@@ -1632,15 +1632,15 @@
 
uart7_pins_a: uart7-0 {
pins1 {
-   pinmux = ; /* UART4_TX */
+   pinmux = ; /* UART7_TX */
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
-   pinmux = , /* UART4_RX */
-, /* UART4_CTS */
-; /* UART4_RTS */
+   pinmux = , /* UART7_RX */
+, /* UART7_CTS */
+; /* UART7_RTS */
bias-disable;
};
};
-- 
2.17.1



[PATCH 0/5] STM32 add usart nodes support

2020-05-28 Thread Erwan Le Ray
Add the support of uart instances available on STM32MP157 boards:
- usart3 on stm32mp157c-ev1, stm32mp157a-dk1, and stm32mp157c-dk2
- uart7 on stm32mp157a-dk1 and stm32mp157c-dk2
- usart2 on stm32mp157c-dk2

The aliases are following this order.

Erwan Le Ray (5):
  ARM: dts: stm32: add usart2, usart3 and uart7 pins in
stm32mp15-pinctrl
  ARM: dts: stm32: add usart3 node to stm32mp15xx-dkx boards
  ARM: dts: stm32: add usart3 node to stm32mp157c-ev1
  ARM: dts: stm32: add uart7 support to stm32mp15xx-dkx boards
  ARM: dts: stm32: add usart2 node to stm32mp157c-dk2

 arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 138 +++
 arch/arm/boot/dts/stm32mp157a-dk1.dts|   2 +
 arch/arm/boot/dts/stm32mp157c-dk2.dts|  11 ++
 arch/arm/boot/dts/stm32mp157c-ev1.dts|  10 ++
 arch/arm/boot/dts/stm32mp15xx-dkx.dtsi   |  17 +++
 5 files changed, 178 insertions(+)

-- 
2.17.1



[PATCH 0/2] STM32 Fix uart nodes in stm32mp15-pinctrl

2020-05-28 Thread Erwan Le Ray
Fix uart nodes ordering and uart7_pins_a comments in stm32mp15-pinctrl.

Erwan Le Ray (2):
  ARM: dts: stm32: fix uart nodes ordering in stm32mp15-pinctrl
  ARM: dts: stm32: fix uart7_pins_a comments in stm32mp15-pinctrl

 arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 130 +++
 1 file changed, 65 insertions(+), 65 deletions(-)

-- 
2.17.1



[PATCH 1/3] ARM: dts: stm32: update uart4 pin configuration for low power on stm32mp157

2020-05-28 Thread Erwan Le Ray
Sleep pin configuration is refined for low power modes:
- "sleep" (no wakeup & console suspend enabled): put pins in analog state
  to optimize power
- "idle" (wakeup capability): keep Rx pin in alternate function

Signed-off-by: Bich Hemon 
Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
index 7eb858732d6d..7cf535dc05f5 100644
--- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
@@ -1648,6 +1648,23 @@
};
};
 
+   uart4_idle_pins_a: uart4-idle-0 {
+  pins1 {
+pinmux = ; /* UART4_TX 
*/
+  };
+  pins2 {
+pinmux = ; /* UART4_RX */
+bias-disable;
+  };
+   };
+
+   uart4_sleep_pins_a: uart4-sleep-0 {
+  pins {
+   pinmux = , /* UART4_TX */
+; /* UART4_RX */
+   };
+   };
+
uart4_pins_b: uart4-1 {
pins1 {
pinmux = ; /* UART4_TX */
-- 
2.17.1



[PATCH 3/3] ARM: dts: stm32: Update UART4 pin states on stm32mp15xx-dkx

2020-05-28 Thread Erwan Le Ray
Add sleep and idle states to uart4 pin configuration.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi 
b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
index 70db923a45f7..e5fdbc149bf4 100644
--- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
+++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi
@@ -584,8 +584,10 @@
 };
 
  {
-   pinctrl-names = "default";
+   pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <_pins_a>;
+   pinctrl-1 = <_sleep_pins_a>;
+   pinctrl-2 = <_idle_pins_a>;
status = "okay";
 };
 
-- 
2.17.1



[PATCH 2/3] ARM: dts: stm32: Update pin states for uart4 on stm32mp157c-ed1

2020-05-28 Thread Erwan Le Ray
Add sleep and idle states to uart4 pin configuration.

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts 
b/arch/arm/boot/dts/stm32mp157c-ed1.dts
index 32ccd50b4144..ca109dc18238 100644
--- a/arch/arm/boot/dts/stm32mp157c-ed1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts
@@ -353,8 +353,10 @@
 };
 
  {
-   pinctrl-names = "default";
+   pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <_pins_a>;
+   pinctrl-1 = <_sleep_pins_a>;
+   pinctrl-2 = <_idle_pins_a>;
status = "okay";
 };
 
-- 
2.17.1



[PATCH 0/3] STM32 update uart4 pin configuration for low power

2020-05-28 Thread Erwan Le Ray
Update uart4 pin configuration for low power in pinctrl, and for ed/ev
and dkx boards.

Erwan Le Ray (3):
  ARM: dts: stm32: update uart4 pin configuration for low power on
stm32mp157
  ARM: dts: stm32: Update pin states for uart4 on stm32mp157c-ed1
  ARM: dts: stm32: Update UART4 pin states on stm32mp15xx-dkx

 arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 17 +
 arch/arm/boot/dts/stm32mp157c-ed1.dts|  4 +++-
 arch/arm/boot/dts/stm32mp15xx-dkx.dtsi   |  4 +++-
 3 files changed, 23 insertions(+), 2 deletions(-)

-- 
2.17.1



[PATCH 1/2] dt-bindings: serial: add generic DT binding for announcing RTS/CTS lines

2020-05-20 Thread Erwan Le Ray
Add support of generic DT binding for annoucing RTS/CTS lines. The initial
binding 'st,hw-flow-control' is not needed anymore since generic binding
is available, but is kept for backward compatibility.

Signed-off-by: Erwan Le Ray 

diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml 
b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
index 75b8521eb7cb..06d5f251ec88 100644
--- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
@@ -35,9 +35,11 @@ properties:
 description: label associated with this uart
 
   st,hw-flow-ctrl:
-description: enable hardware flow control
+description: enable hardware flow control (deprecated)
 $ref: /schemas/types.yaml#/definitions/flag
 
+  uart-has-rtscts: true
+
   dmas:
 minItems: 1
 maxItems: 2
-- 
2.17.1



[PATCH 0/2] add generic DT binding for RTS/CTS

2020-05-20 Thread Erwan Le Ray
Add support of generic DT binding for annoucing RTS/CTS lines. The initial
binding 'st,hw-flow-control' is not needed anymore since generic binding
is available, but is kept for backward compatibility.

Erwan Le Ray (2):
  dt-bindings: serial: add generic DT binding for announcing RTS/CTS
lines
  serial: stm32: Use generic DT binding for announcing RTS/CTS lines

 Documentation/devicetree/bindings/serial/st,stm32-uart.yaml | 4 +++-
 drivers/tty/serial/stm32-usart.c| 5 +++--
 2 files changed, 6 insertions(+), 3 deletions(-)

-- 
2.17.1



[PATCH 2/2] serial: stm32: Use generic DT binding for announcing RTS/CTS lines

2020-05-20 Thread Erwan Le Ray
Add support of generic DT binding for annoucing RTS/CTS lines. The initial
binding 'st,hw-flow-control' is not needed anymore since generic binding
is available, but is kept for backward compatibility.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 17c2f3276888..9cfcf355567a 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1033,8 +1033,9 @@ static struct stm32_port *stm32_of_get_stm32_port(struct 
platform_device *pdev)
if (WARN_ON(id >= STM32_MAX_PORTS))
return NULL;
 
-   stm32_ports[id].hw_flow_control = of_property_read_bool(np,
-   "st,hw-flow-ctrl");
+   stm32_ports[id].hw_flow_control =
+   of_property_read_bool (np, "st,hw-flow-ctrl") /*deprecated*/ ||
+   of_property_read_bool (np, "uart-has-rtscts");
stm32_ports[id].port.line = id;
stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
stm32_ports[id].cr3_irq = 0;
-- 
2.17.1



[PATCH 1/1] serial: stm32: add no_console_suspend support

2020-05-19 Thread Erwan Le Ray
In order to display console messages in low power mode, console pins
must be kept active after suspend call.

---
Initial patch "serial: stm32: add support for no_console_suspend" was part
of "STM32 usart power improvement" series, but as dependancy to
console_suspend pinctl state has been removed to fit with Rob comment [1],
this patch has no more dependancy with any other patch of this series.

[1] https://lkml.org/lkml/2019/7/9/451

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 9cfcf355567a..5afd29162f6c 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1425,7 +1425,18 @@ static int __maybe_unused stm32_serial_suspend(struct 
device *dev)
else
stm32_serial_enable_wakeup(port, false);
 
-   pinctrl_pm_select_sleep_state(dev);
+   /*
+* When "no_console_suspend" is enabled, keep the pinctrl default state
+* and rely on bootloader stage to restore this state upon resume.
+* Otherwise, apply the idle or sleep states depending on wakeup
+* capabilities.
+*/
+   if (console_suspend_enabled || !uart_console(port)) {
+   if (device_may_wakeup(dev))
+   pinctrl_pm_select_idle_state(dev);
+   else
+   pinctrl_pm_select_sleep_state(dev);
+   }
 
return 0;
 }
-- 
2.17.1



Re: [Linux-stm32] [PATCH v3 1/2] dt-bindings: serial: Document CTS/RTS gpios in STM32 UART

2020-05-18 Thread Erwan LE RAY
Hi Geert,


On 5/18/20 9:04 AM, Geert Uytterhoeven wrote:
> Hi Mani,
>
> On Mon, Apr 20, 2020 at 7:02 PM  wrote:
>> From: Manivannan Sadhasivam 
>>
>> Document the use of CTS/RTS gpios for flow control in STM32 UART
>> controller. These properties can be used instead of 'st,hw-flow-ctrl'
>> for making use of any gpio pins for flow control instead of dedicated
>> pins. It should be noted that both CTS/RTS and 'st,hw-flow-ctrl'
>> properties cannot co-exist in a design.
>>
>> Reviewed-by: Andy Shevchenko 
>> Signed-off-by: Manivannan Sadhasivam 
>> --- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
>> +++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
>> @@ -55,6 +61,14 @@ properties:
>> linux,rs485-enabled-at-boot-time: true
>> rs485-rx-during-tx: true
>>
>> +if:
>> +  required:
>> +- st,hw-flow-ctrl
> Perhaps "st,hw-flow-ctrl" should be deprecated, in favor of the standard
> "uart-has-rtscts" property?
> Of course the driver needs to gain support for the latter first.

You're fully right, the patch to deprecate "st, hw-flow-ctrl" and 
introduce generic "uart-has-rtscts" property in the driver is ready and 
will be sent this week on top of Mani patch.


>
>> +then:
>> +  properties:
>> +cts-gpios: false
>> +rts-gpios: false
>> +
>>   required:
>> - compatible
>> - reg
> Gr{oetje,eeting}s,
>
>  Geert
>

[PATCH] ARM: dts: stm32: fix -Wall W=1 compilation warnings for can1_sleep pinctrl

2019-07-01 Thread Erwan Le Ray
Fix compilations warnings detected by -Wall W=1 compilation option:
- node has a unit name, but no reg property

Signed-off-by: Erwan Le Ray 

diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 140a983..ce98fd8 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -427,7 +427,7 @@
};
};
 
-   m_can1_sleep_pins_a: m_can1-sleep@0 {
+   m_can1_sleep_pins_a: m_can1-sleep-0 {
pins {
pinmux = , /* CAN1_TX */
 ; /* CAN1_RX */
-- 
1.9.1



[PATCH 1/5] serial: stm32: add support of timeout interrupt for RX

2019-06-18 Thread Erwan Le Ray
Add support of RX timeout interrupts to limit the number of interrupts.
RX timeout is a number of bits (baud clock cycles) without
transmission seen in the receiver. One character  is used as an arbitrary
RX timeout value.
If parity is enabled, the number of bits has to include parity bit.

Signed-off-by: Gerald Baeza 
Signed-off-by: Fabrice Gasnier 
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 9c2b04e..e1cfb1e 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -437,6 +437,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
 
sr = readl_relaxed(port->membase + ofs->isr);
 
+   if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
+   writel_relaxed(USART_ICR_RTOCF,
+  port->membase + ofs->icr);
+
if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG))
writel_relaxed(USART_ICR_WUCF,
   port->membase + ofs->icr);
@@ -523,7 +527,7 @@ static void stm32_throttle(struct uart_port *port)
unsigned long flags;
 
spin_lock_irqsave(>lock, flags);
-   stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+   stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
spin_unlock_irqrestore(>lock, flags);
 }
 
@@ -535,7 +539,7 @@ static void stm32_unthrottle(struct uart_port *port)
unsigned long flags;
 
spin_lock_irqsave(>lock, flags);
-   stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+   stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq);
spin_unlock_irqrestore(>lock, flags);
 }
 
@@ -545,7 +549,7 @@ static void stm32_stop_rx(struct uart_port *port)
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
 
-   stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+   stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
 }
 
 /* Handle breaks - ignored by us */
@@ -567,7 +571,7 @@ static int stm32_startup(struct uart_port *port)
if (ret)
return ret;
 
-   val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+   val = stm32_port->cr1_irq | USART_CR1_TE | USART_CR1_RE;
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
stm32_set_bits(port, ofs->cr1, val);
@@ -583,7 +587,8 @@ static void stm32_shutdown(struct uart_port *port)
u32 val, isr;
int ret;
 
-   val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+   val = USART_CR1_TXEIE | USART_CR1_TE;
+   val |= stm32_port->cr1_irq | USART_CR1_RE;
val |= BIT(cfg->uart_enable_bit);
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
@@ -653,7 +658,7 @@ static void stm32_set_termios(struct uart_port *port, 
struct ktermios *termios,
/* Stop serial port and reset value */
writel_relaxed(0, port->membase + ofs->cr1);
 
-   cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
+   cr1 = USART_CR1_TE | USART_CR1_RE;
 
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
@@ -686,6 +691,19 @@ static void stm32_set_termios(struct uart_port *port, 
struct ktermios *termios,
dev_dbg(port->dev, "Unsupported data bits config: %u bits\n"
, bits);
 
+   if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch ||
+  stm32_port->fifoen)) {
+   if (cflag & CSTOPB)
+   bits = bits + 3; /* 1 start bit + 2 stop bits */
+   else
+   bits = bits + 2; /* 1 start bit + 1 stop bit */
+
+   /* RX timeout irq to occur after last stop bit + bits */
+   stm32_port->cr1_irq = USART_CR1_RTOIE;
+   writel_relaxed(bits, port->membase + ofs->rtor);
+   cr2 |= USART_CR2_RTOEN;
+   }
+
if (cflag & PARODD)
cr1 |= USART_CR1_PS;
 
@@ -925,6 +943,7 @@ static struct stm32_port *stm32_of_get_stm32_port(struct 
platform_device *pdev)
stm32_ports[id].hw_flow_control = of_property_read_bool(np,
"st,hw-flow-ctrl");
stm32_ports[id].port.line = id;
+   stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
stm32_ports[id].last_res = RX_BUF_L;
return _ports[id];
 }
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index 30d2433..fcd01fe 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -249,6 +249,7 @@ struct stm32_port {
struct dma_chan *tx_ch;  /* dma tx channel*/
dma_addr_t tx_dma_buf;   /* dma tx buffer bus address */
unsigned char 

[PATCH 0/5] STM32 usart FIFO handling

2019-06-18 Thread Erwan Le Ray
This series delivers RX and TX FIFO features to improve system 
performances during data transfer.

Erwan Le Ray (5):
  serial: stm32: add support of timeout interrupt for RX
  serial: stm32: update PIO transmission
  serial: stm32: add support of TX FIFO threshold
  serial: stm32: add support of RX FIFO threshold
  serial: stm32: add RX and TX FIFO flush

 drivers/tty/serial/stm32-usart.c | 132 +++
 drivers/tty/serial/stm32-usart.h |  19 ++
 2 files changed, 124 insertions(+), 27 deletions(-)

-- 
1.9.1



[PATCH 3/5] serial: stm32: add support of TX FIFO threshold

2019-06-18 Thread Erwan Le Ray
Adds the support of TX FIFO threshold in order to improve the TX FIFO
management:
- TX FIFO threshold irq enabling (instead of relying on tx empty / fifo
  not full irq that generates one irq/char)
- TXCFG is set to half fifo size (e.g. 16/2 = 8 data for a 16 data depth
  FIFO)
- irq rate may be reduced by up to 1/TXCFG,  e.g. 1 over 8 with current
  TXCFG setting.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 8316e19..397d86d 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -298,6 +298,32 @@ static void stm32_tx_dma_complete(void *arg)
stm32_transmit_chars(port);
 }
 
+static void stm32_tx_interrupt_enable(struct uart_port *port)
+{
+   struct stm32_port *stm32_port = to_stm32_port(port);
+   struct stm32_usart_offsets *ofs = _port->info->ofs;
+
+   /*
+* Enables TX FIFO threashold irq when FIFO is enabled,
+* or TX empty irq when FIFO is disabled
+*/
+   if (stm32_port->fifoen)
+   stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE);
+   else
+   stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+}
+
+static void stm32_tx_interrupt_disable(struct uart_port *port)
+{
+   struct stm32_port *stm32_port = to_stm32_port(port);
+   struct stm32_usart_offsets *ofs = _port->info->ofs;
+
+   if (stm32_port->fifoen)
+   stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE);
+   else
+   stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+}
+
 static void stm32_transmit_chars_pio(struct uart_port *port)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
@@ -320,9 +346,9 @@ static void stm32_transmit_chars_pio(struct uart_port *port)
 
/* rely on TXE irq (mask or unmask) for sending remaining data */
if (uart_circ_empty(xmit))
-   stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+   stm32_tx_interrupt_disable(port);
else
-   stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+   stm32_tx_interrupt_enable(port);
 }
 
 static void stm32_transmit_chars_dma(struct uart_port *port)
@@ -404,7 +430,7 @@ static void stm32_transmit_chars(struct uart_port *port)
}
 
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-   stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+   stm32_tx_interrupt_disable(port);
return;
}
 
@@ -422,7 +448,7 @@ static void stm32_transmit_chars(struct uart_port *port)
uart_write_wakeup(port);
 
if (uart_circ_empty(xmit))
-   stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+   stm32_tx_interrupt_disable(port);
 }
 
 static irqreturn_t stm32_interrupt(int irq, void *ptr)
@@ -501,10 +527,7 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
 /* Transmit stop */
 static void stm32_stop_tx(struct uart_port *port)
 {
-   struct stm32_port *stm32_port = to_stm32_port(port);
-   struct stm32_usart_offsets *ofs = _port->info->ofs;
-
-   stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+   stm32_tx_interrupt_disable(port);
 }
 
 /* There are probably characters waiting to be transmitted. */
@@ -575,6 +598,13 @@ static int stm32_startup(struct uart_port *port)
val |= USART_CR1_FIFOEN;
stm32_set_bits(port, ofs->cr1, val);
 
+   if (stm32_port->fifoen) {
+   val = readl_relaxed(port->membase + ofs->cr3);
+   val &= ~USART_CR3_TXFTCFG_MASK;
+   val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
+   writel_relaxed(val, port->membase + ofs->cr3);
+   }
+
return 0;
 }
 
@@ -662,7 +692,9 @@ static void stm32_set_termios(struct uart_port *port, 
struct ktermios *termios,
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
cr2 = 0;
-   cr3 = 0;
+   cr3 = readl_relaxed(port->membase + ofs->cr3);
+   cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG | USART_CR3_RXFTIE
+   | USART_CR3_TXFTCFG_MASK;
 
if (cflag & CSTOPB)
cr2 |= USART_CR2_STOP_2B;
@@ -869,6 +901,7 @@ static int stm32_init_port(struct stm32_port *stm32port,
port->flags = UPF_BOOT_AUTOCONF;
port->ops   = _uart_ops;
port->dev   = >dev;
+   port->fifosize  = stm32port->info->cfg.fifosize;
 
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index fcd01fe..a598446 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -27,6 +27,7 @@ struct stm32_usart_config {
bool has_7bits_data;
bool has_wakeup;
bool has_fifo;
+   int fifosize;
 };
 
 struct stm32_usart_

[PATCH 2/5] serial: stm32: update PIO transmission

2019-06-18 Thread Erwan Le Ray
Improves PIO transmission:
- Replaces the FIFO filling per character by a filling per blocks of
  characters, which provides better performances
- Replaces the active waiting loop by TX empty interrupt dynamic handling.
  TXE interrupt is now enabled when data has to be sent (ie when
  uart_circ is not empty), and inhibited when there is no more data to
  send (ie when uart_circ is empty).

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index e1cfb1e..8316e19 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -303,27 +303,26 @@ static void stm32_transmit_chars_pio(struct uart_port 
*port)
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
struct circ_buf *xmit = >state->xmit;
-   unsigned int isr;
-   int ret;
 
if (stm32_port->tx_dma_busy) {
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32_port->tx_dma_busy = false;
}
 
-   ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
-   isr,
-   (isr & USART_SR_TXE),
-   10, 10);
-
-   if (ret)
-   dev_err(port->dev, "tx empty not set\n");
-
-   stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+   while (!uart_circ_empty(xmit)) {
+   /* Check that TDR is empty before filling FIFO */
+   if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
+   break;
+   writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
+   xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+   port->icount.tx++;
+   }
 
-   writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
-   xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-   port->icount.tx++;
+   /* rely on TXE irq (mask or unmask) for sending remaining data */
+   if (uart_circ_empty(xmit))
+   stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+   else
+   stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
 }
 
 static void stm32_transmit_chars_dma(struct uart_port *port)
-- 
1.9.1



[PATCH 4/5] serial: stm32: add support of RX FIFO threshold

2019-06-18 Thread Erwan Le Ray
Adds the support of RX FIFO threshold in order to improve the RX FIFO
management.
This is done by enabling fifo threshold interrupt, instead of relying
on rx empty/fifo not full irq. That basically generates one irq/char
currently. With this patch:
- RXCFG is set to half fifo size (e.g. 16/2 = 8 data for a 16 data depth
  FIFO)
- irq rate may be reduced by up to 1/RXCFG,  e.g. 1 over 8 with current
  RXCFG setting.
- Receiver timeout is used to gather chars when FIFO threshold isn't
  reached.

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 397d86d..4083145 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -550,6 +550,9 @@ static void stm32_throttle(struct uart_port *port)
 
spin_lock_irqsave(>lock, flags);
stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
+   if (stm32_port->cr3_irq)
+   stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
spin_unlock_irqrestore(>lock, flags);
 }
 
@@ -562,6 +565,9 @@ static void stm32_unthrottle(struct uart_port *port)
 
spin_lock_irqsave(>lock, flags);
stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq);
+   if (stm32_port->cr3_irq)
+   stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
spin_unlock_irqrestore(>lock, flags);
 }
 
@@ -572,6 +578,9 @@ static void stm32_stop_rx(struct uart_port *port)
struct stm32_usart_offsets *ofs = _port->info->ofs;
 
stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
+   if (stm32_port->cr3_irq)
+   stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
 }
 
 /* Handle breaks - ignored by us */
@@ -600,8 +609,9 @@ static int stm32_startup(struct uart_port *port)
 
if (stm32_port->fifoen) {
val = readl_relaxed(port->membase + ofs->cr3);
-   val &= ~USART_CR3_TXFTCFG_MASK;
+   val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
+   val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
writel_relaxed(val, port->membase + ofs->cr3);
}
 
@@ -693,7 +703,7 @@ static void stm32_set_termios(struct uart_port *port, 
struct ktermios *termios,
cr1 |= USART_CR1_FIFOEN;
cr2 = 0;
cr3 = readl_relaxed(port->membase + ofs->cr3);
-   cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG | USART_CR3_RXFTIE
+   cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE
| USART_CR3_TXFTCFG_MASK;
 
if (cflag & CSTOPB)
@@ -733,8 +743,14 @@ static void stm32_set_termios(struct uart_port *port, 
struct ktermios *termios,
stm32_port->cr1_irq = USART_CR1_RTOIE;
writel_relaxed(bits, port->membase + ofs->rtor);
cr2 |= USART_CR2_RTOEN;
+   /* Not using dma, enable fifo threshold irq */
+   if (!stm32_port->rx_ch)
+   stm32_port->cr3_irq =  USART_CR3_RXFTIE;
}
 
+   cr1 |= stm32_port->cr1_irq;
+   cr3 |= stm32_port->cr3_irq;
+
if (cflag & PARODD)
cr1 |= USART_CR1_PS;
 
@@ -976,6 +992,7 @@ static struct stm32_port *stm32_of_get_stm32_port(struct 
platform_device *pdev)
"st,hw-flow-ctrl");
stm32_ports[id].port.line = id;
stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
+   stm32_ports[id].cr3_irq = 0;
stm32_ports[id].last_res = RX_BUF_L;
return _ports[id];
 }
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index a598446..a175c10 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -210,7 +210,8 @@ struct stm32_usart_info stm32h7_info = {
 #define USART_CR3_WUFIEBIT(22) /* H7 */
 #define USART_CR3_TXFTIE   BIT(23) /* H7 */
 #define USART_CR3_TCBGTIE  BIT(24) /* H7 */
-#define USART_CR3_RXFTCFG  GENMASK(27, 25) /* H7 */
+#define USART_CR3_RXFTCFG_MASK GENMASK(27, 25) /* H7 */
+#define USART_CR3_RXFTCFG_SHIFT25  /* H7 */
 #define USART_CR3_RXFTIE   BIT(28) /* H7 */
 #define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */
 #define USART_CR3_TXFTCFG_SHIFT29  /* H7 */
@@ -218,6 +219,9 @@ struct stm32_usart_info stm32h7_info = {
 /* TX FIFO threashold set to half of its depth */
 #define USART_CR3_TXFTCFG_HALF 0x2
 
+/* RX FIFO threashold set to half of its depth */
+#define USART_CR3_RXFTCFG_HALF 0x2
+
 /* USART_GTPR */
 #define USART_GTPR_PSC_MASKGENMASK(7, 0)
 #define USART_GTPR_GT_MASK GENMASK(15, 8)
@@ -263,6 +267,7 @@ struct stm32_port {
dma_addr_t tx_dma_buf; 

[PATCH 5/5] serial: stm32: add RX and TX FIFO flush

2019-06-18 Thread Erwan Le Ray
Adds a flush of RX and TX FIFOs, and fixes some errors:
- adds RX FIFO flush in startup fonction
- removes the useless transmitter enabling in startup fonction
  (e.g. receiver only, see Documentation/serial/driver)
- configures FIFO threshold before enabling it, rather than after
- flushes both TX and RX in set_termios function

Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 4083145..21dc380 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -602,11 +602,11 @@ static int stm32_startup(struct uart_port *port)
if (ret)
return ret;
 
-   val = stm32_port->cr1_irq | USART_CR1_TE | USART_CR1_RE;
-   if (stm32_port->fifoen)
-   val |= USART_CR1_FIFOEN;
-   stm32_set_bits(port, ofs->cr1, val);
+   /* RX FIFO Flush */
+   if (ofs->rqr != UNDEF_REG)
+   stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
 
+   /* Tx and RX FIFO configuration */
if (stm32_port->fifoen) {
val = readl_relaxed(port->membase + ofs->cr3);
val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
@@ -615,6 +615,12 @@ static int stm32_startup(struct uart_port *port)
writel_relaxed(val, port->membase + ofs->cr3);
}
 
+   /* RX FIFO enabling */
+   val = stm32_port->cr1_irq | USART_CR1_RE;
+   if (stm32_port->fifoen)
+   val |= USART_CR1_FIFOEN;
+   stm32_set_bits(port, ofs->cr1, val);
+
return 0;
 }
 
@@ -697,8 +703,12 @@ static void stm32_set_termios(struct uart_port *port, 
struct ktermios *termios,
/* Stop serial port and reset value */
writel_relaxed(0, port->membase + ofs->cr1);
 
-   cr1 = USART_CR1_TE | USART_CR1_RE;
+   /* flush RX & TX FIFO */
+   if (ofs->rqr != UNDEF_REG)
+   stm32_set_bits(port, ofs->rqr,
+  USART_RQR_TXFRQ | USART_RQR_RXFRQ);
 
+   cr1 = USART_CR1_TE | USART_CR1_RE;
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
cr2 = 0;
-- 
1.9.1



[PATCH v3 05/10] serial: stm32: Use __maybe_unused instead of #if CONFIG_PM_SLEEP

2019-06-13 Thread Erwan Le Ray
Use __maybe_unused for power management related functionsinstead of

fixes: 270e5a74fe4c ("serial: stm32: add wakeup mechanism")
Signed-off-by: Erwan Le Ray 

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 41898c4..b0fb420 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1276,8 +1276,8 @@ static int stm32_console_setup(struct console *co, char 
*options)
.cons   = STM32_SERIAL_CONSOLE,
 };
 
-#ifdef CONFIG_PM_SLEEP
-static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable)
+static void __maybe_unused stm32_serial_enable_wakeup(struct uart_port *port,
+ bool enable)
 {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = _port->info->ofs;
@@ -1301,7 +1301,7 @@ static void stm32_serial_enable_wakeup(struct uart_port 
*port, bool enable)
}
 }
 
-static int stm32_serial_suspend(struct device *dev)
+static int __maybe_unused stm32_serial_suspend(struct device *dev)
 {
struct uart_port *port = dev_get_drvdata(dev);
 
@@ -1317,7 +1317,7 @@ static int stm32_serial_suspend(struct device *dev)
return 0;
 }
 
-static int stm32_serial_resume(struct device *dev)
+static int __maybe_unused stm32_serial_resume(struct device *dev)
 {
struct uart_port *port = dev_get_drvdata(dev);
 
@@ -1328,7 +1328,6 @@ static int stm32_serial_resume(struct device *dev)
 
return uart_resume_port(_usart_driver, port);
 }
-#endif /* CONFIG_PM_SLEEP */
 
 static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev)
 {
-- 
1.9.1



[PATCH v3 06/10] serial: stm32: add support for no_console_suspend

2019-06-13 Thread Erwan Le Ray
In order to display console messages in low power mode, console pins
must be kept active after suspend call.

Signed-off-by: Bich Hemon 
Signed-off-by: Erwan Le Ray 

Conflicts:
drivers/tty/serial/stm32-usart.c

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index b0fb420..00e4d7a 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -847,6 +848,7 @@ static int stm32_init_port(struct stm32_port *stm32port,
 {
struct uart_port *port = >port;
struct resource *res;
+   struct pinctrl *uart_pinctrl;
int ret;
 
port->iotype= UPIO_MEM;
@@ -880,6 +882,24 @@ static int stm32_init_port(struct stm32_port *stm32port,
 
stm32port->fifoen = stm32port->info->cfg.has_fifo;
 
+   uart_pinctrl = devm_pinctrl_get(>dev);
+   if (IS_ERR(uart_pinctrl)) {
+   ret = PTR_ERR(uart_pinctrl);
+   if (ret != -ENODEV) {
+   dev_err(>dev, "Can't get pinctrl, error %d\n",
+   ret);
+   return ret;
+   }
+   stm32port->console_pins = ERR_PTR(-ENODEV);
+   } else {
+   stm32port->console_pins = pinctrl_lookup_state
+   (uart_pinctrl, "no_console_suspend");
+   }
+
+   if (IS_ERR(stm32port->console_pins) && PTR_ERR(stm32port->console_pins)
+   != -ENODEV)
+   return PTR_ERR(stm32port->console_pins);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
port->membase = devm_ioremap_resource(>dev, res);
if (IS_ERR(port->membase))
@@ -1304,6 +1324,7 @@ static void __maybe_unused 
stm32_serial_enable_wakeup(struct uart_port *port,
 static int __maybe_unused stm32_serial_suspend(struct device *dev)
 {
struct uart_port *port = dev_get_drvdata(dev);
+   struct stm32_port *stm32_port = to_stm32_port(port);
 
uart_suspend_port(_usart_driver, port);
 
@@ -1312,7 +1333,19 @@ static int __maybe_unused stm32_serial_suspend(struct 
device *dev)
else
stm32_serial_enable_wakeup(port, false);
 
-   pinctrl_pm_select_sleep_state(dev);
+   if (uart_console(port) && !console_suspend_enabled) {
+   if (IS_ERR(stm32_port->console_pins)) {
+   dev_err(dev, "no_console_suspend pinctrl not found\n");
+   return PTR_ERR(stm32_port->console_pins);
+   }
+
+   pinctrl_select_state(dev->pins->p, stm32_port->console_pins);
+   } else {
+   if (device_may_wakeup(dev))
+   pinctrl_pm_select_idle_state(dev);
+   else
+   pinctrl_pm_select_sleep_state(dev);
+   }
 
return 0;
 }
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index 30d2433..050fe04 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -255,6 +255,7 @@ struct stm32_port {
bool fifoen;
int wakeirq;
int rdr_mask;   /* receive data register mask */
+   struct pinctrl_state *console_pins;
 };
 
 static struct stm32_port stm32_ports[STM32_MAX_PORTS];
-- 
1.9.1



[PATCH v3 00/10] STM32 usart power improvements

2019-06-13 Thread Erwan Le Ray
This series delivers power improvements for stm32-usart driver.

Changes in v3:
Move pinctrl/consumer.h include from "add support for no_console_suspend"
patch to "select pinctrl state" patch in order to solve a compilation 
issue.

Bich Hemon (3):
  dt-bindings: serial: add optional pinctrl states
  ARM: dts: stm32: Update pin states for uart4 on stm32mp157c-ed1
  ARM: dts: stm32: Update UART4 pin states on stm32mp157a-dk1

Erwan Le Ray (7):
  dt-bindings: serial: stm32: add wakeup option
  serial: stm32: select pinctrl state in each suspend/resume function
  serial: stm32: add pm_runtime support
  serial: stm32: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
  serial: stm32: add support for no_console_suspend
  ARM: dts: stm32: update uart4 pin configurations for low power
  ARM: dts: stm32: add wakeup capability on each usart/uart on
stm32mp157c

 .../devicetree/bindings/serial/st,stm32-usart.txt  | 19 -
 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi  | 17 +
 arch/arm/boot/dts/stm32mp157a-dk1.dts  |  5 +-
 arch/arm/boot/dts/stm32mp157c-ed1.dts  |  5 +-
 arch/arm/boot/dts/stm32mp157c.dtsi | 40 --
 drivers/tty/serial/stm32-usart.c   | 88 --
 drivers/tty/serial/stm32-usart.h   |  1 +
 7 files changed, 155 insertions(+), 20 deletions(-)

-- 
1.9.1



  1   2   >