Re: [PATCH v2] serial: stm32: optimize spin lock usage
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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