serial: add drivers for the ESP32xx serial devices
Subsystems (2)
v2 cover serial: add drivers for the ESP32xx serial devices
Hello,
this series adds drivers for the UART and ACM controllers found in the Espressif ESP32 and ESP32S3 SoCs.
Changes v1->v2:
- address review comments, listed in each patch
- add cleanup for the uart_get_baud_rate function
Max Filippov (5):
serial: core: tidy invalid baudrate handling in uart_get_baud_rate
dt-bindings: serial: document esp32-uart drivers/tty/serial: add driver for the ESP32 UART
dt-bindings: serial: document esp32s3-acm drivers/tty/serial: add ESP32S3 ACM device driver
.../bindings/serial/esp,esp32-acm.yaml | 39 + .../bindings/serial/esp,esp32-uart.yaml | 48 ++ drivers/tty/serial/Kconfig | 27 + drivers/tty/serial/Makefile | 2 + drivers/tty/serial/esp32_acm.c | 458 +++++++++++ drivers/tty/serial/esp32_uart.c | 749 ++++++++++++++++++ drivers/tty/serial/serial_core.c | 5 +- include/uapi/linux/serial_core.h | 6 + 8 files changed, 1331 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/serial/esp,esp32-acm.yaml create mode 100644 Documentation/devicetree/bindings/serial/esp,esp32-uart.yaml create mode 100644 drivers/tty/serial/esp32_acm.c create mode 100644 drivers/tty/serial/esp32_uart.c
Signature · 1 line
2.30.2
PATCH v2 1/5 serial: core: tidy invalid baudrate handling in uart_get_baud_rate
uart_get_baud_rate has input parameters 'min' and 'max' limiting the range of acceptable baud rates from the caller's perspective. If neither current or old termios structures have acceptable baud rate setting and 9600 is not in the min/max range either the function returns 0 and issues a warning.
However for a UART that does not support speed of 9600 baud this is expected behavior.
Clarify that 0 can be (and always could be) returned from the uart_get_baud_rate. Don't issue a warning in that case.
Move the warinng to the uart_get_divisor instead, which is often called with the uart_get_baud_rate return value.
--- drivers/tty/serial/serial_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/tty/serial/serial_core.c +2 -3
@@ -431,7 +431,7 @@ EXPORT_SYMBOL(uart_update_timeout);* baud. * * If the new baud rate is invalid, try the @old termios setting. If it's still -* invalid, we try 9600 baud. +* invalid, we try 9600 baud. If that is also invalid 0 is returned. * * The @termios structure is updated to reflect the baud rate we're actually * going to be using. Don't do this for the case where B0 is requested ("hang
@@ -515,8 +515,6 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, max - 1, max - 1); } } -/* Should never happen */ -WARN_ON (1 );return 0 ; }EXPORT_SYMBOL (uart_get_baud_rate);
@@ -539,6 +537,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) {unsigned int quot; +WARN_ON (baud ==0 );/* * Old custom speed handling. */
Signature · 1 line
2.30.2
Greg Kroah-Hartman
maintainerRe: [PATCH v2 1/5] serial: core: tidy invalid baudrate handling in uart_get_baud_rate
Quoted 31 lines · Max Filippov
uart_get_baud_ratehas input parameters 'min' and 'max' limiting the range of acceptable baud rates from the caller's perspective. If neither current or old termios structures have acceptable baud rate setting and 9600 is not in the min/max range either the function returns 0 and issues a warning.
However for a UART that does not support speed of 9600 baud this is expected behavior.
Clarify that 0 can be (and always could be) returned from theuart_get_baud_rate. Don't issue a warning in that case.
Move the warinng to theuart_get_divisorinstead, which is often called with theuart_get_baud_ratereturn value.Signed-off-by Max Filippov <[email protected]>--- drivers/tty/serial/serial_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)drivers/tty/serial/serial_core.c +1
-1@@ -431,7 +431,7 @@ EXPORT_SYMBOL(uart_update_timeout);* baud. * * If the new baud rate is invalid, try the @old termios setting. If it's still -* invalid, we try 9600 baud. +* invalid, we try 9600 baud. If that is also invalid 0 is returned. * * The @termios structure is updated to reflect the baud rate we're actually * going to be using. Don't do this for the case where B0 is requested ("hang
drivers/tty/serial/serial_core.c uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, · line 519
Quoted 5 lines
drivers/tty/serial/serial_core.c +0
-2@@ -515,8 +515,6 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, max - 1, max - 1); } } -/* Should never happen */ -WARN_ON (1 );
I'm ok with this removal, but:
drivers/tty/serial/serial_core.c uart_get_divisor(struct uart_port *port, unsigned int baud) · line 540
Quoted 8 lines
drivers/tty/serial/serial_core.c +1
-0return 0 ; }EXPORT_SYMBOL (uart_get_baud_rate);@@ -539,6 +537,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) {unsigned int quot; +WARN_ON (baud ==0 );
Why is this needed? If this isn't happening today, then there's no need to check for this here. Or if it can happen, we should return an error, not cause a possible reboot of the system if panic-on-warn is enabled.
thanks,
greg k-h
Re: [PATCH v2 1/5] serial: core: tidy invalid baudrate handling in uart_get_baud_rate
Quoted 9 lines · Greg Kroah-Hartman
drivers/tty/serial/serial_core.c uart_get_divisor(struct uart_port *port, unsigned int baud) · line 540
Quoted 5 lines · Max Filippov
drivers/tty/serial/serial_core.c +1
-0@@ -539,6 +537,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) {unsigned int quot; +WARN_ON (baud ==0 );Why is this needed? If this isn't happening today, then there's no need to check for this here.
I'll drop it then.
Signature · 2 lines
Thanks. -- Max
PATCH v2 2/5 dt-bindings: serial: document esp32-uart
In reply to Max FilippovAdd documentation for the ESP32xx UART controllers.
---
Changes v1->v2:
- drop '|' from description
- change 'compatible' property type to enum
- drop label from the example node
- fix example indentation
.../bindings/serial/esp,esp32-uart.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/esp,esp32-uart.yaml
Documentation/devicetree/bindings/serial/esp,esp32-uart.yaml new file +48 -0
@@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/esp,esp32-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ESP32xx UART controllers + +maintainers: + - Max Filippov <[email protected]> + +description: + ESP32 UART controller is a part of the ESP32 SoC. + ESP32S3 UART controller is a part of the ESP32S3 SoC. + Both SoCs are produced by Espressif Systems Co. Ltd. + +properties: + compatible: + enum: + - esp,esp32-uart + - esp,esp32s3-uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + serial@60000000 { + compatible = "esp,esp32s3-uart"; + reg = <0x60000000 0x80>; + interrupts = <27 1 0>; + clocks = <&serial_clk>; + };
Signature · 1 line
2.30.2
Re: [PATCH v2 2/5] dt-bindings: serial: document esp32-uart
Quoted 4 lines · Max Filippov
Add documentation for the ESP32xx UART controllers.
Signed-off-by Max Filippov <[email protected]>
Thanks for the changes.
Quoted 10 lines
Documentation/devicetree/bindings/serial/esp,esp32-uart.yaml new file +10
-0+properties: + compatible: + enum: + - esp,esp32-uart + - esp,esp32s3-uart + + reg: + maxItems: 1 + + interrupts:
Documentation/devicetree/bindings/serial/esp,esp32-uart.yaml line 37
Quoted 10 lines
Documentation/devicetree/bindings/serial/esp,esp32-uart.yaml new file +10
-0+ maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks
You need allOf with $ref to serial.yaml# (local serial, not absolute path). I apologize, I missed this in my previous review.
Best regards,
Krzysztof
PATCH v2 3/5 drivers/tty/serial: add driver for the ESP32 UART
In reply to Max FilippovAdd driver for the UART controllers of the Espressif ESP32 and ESP32S3 SoCs. Hardware specification is available at the following URLs:
https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
(Chapter 13 UART Controller)
https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf
(Chapter 26 UART Controller)
---
Changes v1->v2:
- redefine register fields using BIT and GENMASK
- drop _MASK suffix from register field definitions
- drop *_SHIFT definitions where possible
- drop unused rxfifo_full_thrhd_mask and txfifo_empty_thrhd_mask
- split register reads/writes and bitwise operations into multiple lines
- use u8 instead of unsigned char in internal functions
- add timeout to esp32_uart_put_char_sync
- use uart_port_tx_limited in esp32_uart_transmit_buffer
- use IRQ_RETVAL in esp32_uart_int
- disable clock in esp32_uart_startup in case devm_request_irq fails
- rearrange devm_request_irq with enabling IRQs in the UART registers
- drop empty esp32_uart_release_port and esp32_uart_request_port
- simplify esp32_uart_tx_empty
- mask out unsupported CMSPAR flag in termios->c_cflag in esp32_uart_set_termios
- invoke uart_update_timeout in esp32_uart_set_termios
- drop MODULE_DESCRIPTION
- rearrange esp32_uart_set_baud: return bool indicating whether baud rate was set or not, use it in the esp32_uart_set_termios to set the default 115200
- turn 'locked' into bool in esp32_uart_console_write
- turn num_read into unsigned int in esp32_uart_earlycon_read
drivers/tty/serial/Kconfig | 13 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/esp32_uart.c | 749 +++++++++++++++++++++++++++++++ include/uapi/linux/serial_core.h | 3 + 4 files changed, 766 insertions(+) create mode 100644 drivers/tty/serial/esp32_uart.c
drivers/tty/serial/Kconfig +13 -0
@@ -1578,6 +1578,19 @@ config SERIAL_NUVOTON_MA35D1_CONSOLE but you can alter that using a kernel command line option such as "console=ttyNVTx". +config SERIAL_ESP32 + tristate "Espressif ESP32 UART support" + depends on XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF) + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Driver for the UART controllers of the Espressif ESP32xx SoCs. + When earlycon option is enabled the following kernel command line + snippets may be used: + earlycon=esp32s3uart,mmio32,0x60000000,115200n8,40000000 + earlycon=esp32uart,mmio32,0x3ff40000,115200n8 + endmenu config SERIAL_MCTRL_GPIO
drivers/tty/serial/Makefile +1 -0
@@ -88,6 +88,7 @@ obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o +obj-$(CONFIG_SERIAL_ESP32) += esp32_uart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
drivers/tty/serial/esp32_uart.c new file +749 -0
749 lines not on this page · raw message
include/uapi/linux/serial_core.h +3 -0
@@ -245,4 +245,7 @@/* Sunplus UART */ #define PORT_SUNPLUS 123 +/* Espressif ESP32 UART */ +#define PORT_ESP32UART 124 +#endif /* _UAPILINUX_SERIAL_CORE_H */
Signature · 1 line
2.30.2
Jiri Slaby
maintainerRe: [PATCH v2 3/5] drivers/tty/serial: add driver for the ESP32 UART
Quoted 2 lines · Max Filippov
Add driver for the UART controllers of the Espressif ESP32 and ESP32S3 SoCs. Hardware specification is available at the following URLs:
...
Quoted 7 lines
drivers/tty/serial/esp32_uart.c new file +7
-0+static void esp32_uart_rxint (struct uart_port *port) +{ +struct tty_port *tty_port = &port->state->port; +u32 rx_fifo_cnt =esp32_uart_rx_fifo_cnt (port); +unsigned long flags; +u32 i; +
drivers/tty/serial/esp32_uart.c line 207
Quoted 10 lines
drivers/tty/serial/esp32_uart.c new file +10
-0+if (!rx_fifo_cnt) +return ; + +spin_lock_irqsave (&port->lock, flags); + +for (i =0 ; i < rx_fifo_cnt; ++i) { +u32 rx =esp32_uart_read (port,UART_FIFO_REG ); +u32 brk =0 ; + + ++port->icount.rx;
Should yuou increment this only in case of insert_flip_char()?
drivers/tty/serial/esp32_uart.c line 221
Quoted 13 lines
drivers/tty/serial/esp32_uart.c new file +13
-0+if (!rx) { + brk =esp32_uart_read (port,UART_INT_ST_REG ) & +UART_BRK_DET_INT ; + } +if (brk) { +esp32_uart_write (port,UART_INT_CLR_REG , brk); + ++port->icount.brk; +uart_handle_break (port); + }else { +if (uart_handle_sysrq_char (port, (unsigned char )rx)) +continue ; +tty_insert_flip_char (tty_port, rx,TTY_NORMAL ); + }
This is heavy. Is it equivalent to:
if (!rx && esp32_uart_read(port, UART_INT_ST_REG) &
UART_BRK_DET_INT) { esp32_uart_write(port, UART_INT_CLR_REG, brk);
++port->icount.brk;
uart_handle_break(port);
continue;
}
if (uart_handle_sysrq_char(port, (unsigned char)rx))
continue;
tty_insert_flip_char(tty_port, rx, TTY_NORMAL);
?
Quoted 5 lines
drivers/tty/serial/esp32_uart.c new file +5
-0+ } +spin_unlock_irqrestore (&port->lock, flags); + +tty_flip_buffer_push (tty_port); +}
...
drivers/tty/serial/esp32_uart.c line 237
Quoted 5 lines
drivers/tty/serial/esp32_uart.c new file +5
-0+static void esp32_uart_put_char_sync (struct uart_port *port,u8 c) +{ +unsigned long timeout; + + timeout = jiffies +msecs_to_jiffies (1000 );
I.e. plus HZ?
Quoted 5 lines
drivers/tty/serial/esp32_uart.c new file +5
-0+while (esp32_uart_tx_fifo_cnt (port) >=ESP32_UART_TX_FIFO_SIZE ) { +if (time_after (jiffies, timeout)) { +dev_warn (port->dev,"timeout waiting for TX FIFO\n" ); +return ; + }
drivers/tty/serial/esp32_uart.c line 252
Quoted 10 lines
drivers/tty/serial/esp32_uart.c new file +10
-0+cpu_relax (); + } +esp32_uart_put_char (port, c); +} + +static void esp32_uart_transmit_buffer (struct uart_port *port) +{ +u32 tx_fifo_used =esp32_uart_tx_fifo_cnt (port); + +if (tx_fifo_used <ESP32_UART_TX_FIFO_SIZE ) {
Invert the condition and return here?
Quoted 21 lines
drivers/tty/serial/esp32_uart.c new file +19
-0+unsigned int pending; +u8 ch; + + pending =uart_port_tx_limited (port, ch, +ESP32_UART_TX_FIFO_SIZE - tx_fifo_used, + true,esp32_uart_put_char (port, ch), + ({})); +if (pending) { +u32 int_ena; + + int_ena =esp32_uart_read (port,UART_INT_ENA_REG ); + int_ena |=UART_TXFIFO_EMPTY_INT ; +esp32_uart_write (port,UART_INT_ENA_REG , int_ena); + } + } +} +static irqreturn_t esp32_uart_int (int irq,void *dev_id) +{ +struct uart_port *port = dev_id;
drivers/tty/serial/esp32_uart.c line 287
Quoted 10 lines
drivers/tty/serial/esp32_uart.c new file +10
-0+u32 status; + + status =esp32_uart_read (port,UART_INT_ST_REG ); + +if (status & (UART_RXFIFO_FULL_INT |UART_BRK_DET_INT )) +esp32_uart_rxint (port); +if (status &UART_TXFIFO_EMPTY_INT ) +esp32_uart_txint (port); + +esp32_uart_write (port,UART_INT_CLR_REG , status);
\n here please.
Quoted 13 lines
drivers/tty/serial/esp32_uart.c new file +12
-0+return IRQ_RETVAL (status); +} +static int esp32_uart_startup (struct uart_port *port) +{ +int ret =0 ; +unsigned long flags; + struct esp32_port *sport = container_of(port, struct esp32_port, port); + + ret =clk_prepare_enable (sport->clk); +if (ret) +return ret; +
drivers/tty/serial/esp32_uart.c line 324
Quoted 10 lines
drivers/tty/serial/esp32_uart.c new file +10
-0+ ret =devm_request_irq (port->dev, port->irq, esp32_uart_int,0 , +DRIVER_NAME , port); +if (ret) { +clk_disable_unprepare (sport->clk); +return ret; + } + +spin_lock_irqsave (&port->lock, flags); + esp32_uart_write(port, UART_CONF1_REG, + (1 << UART_RXFIFO_FULL_THRHD_SHIFT) |
BIT() ?
drivers/tty/serial/esp32_uart.c line 325
Quoted 1 line
drivers/tty/serial/esp32_uart.c new file +1
-0+ (1 << port_variant(port)->txfifo_empty_thrhd_shift));
And here?
drivers/tty/serial/esp32_uart.c line 334
Quoted 9 lines
drivers/tty/serial/esp32_uart.c new file +9
-0+esp32_uart_write (port,UART_INT_CLR_REG ,UART_RXFIFO_FULL_INT |UART_BRK_DET_INT ); +esp32_uart_write (port,UART_INT_ENA_REG ,UART_RXFIFO_FULL_INT |UART_BRK_DET_INT ); +spin_unlock_irqrestore (&port->lock, flags); + +pr_debug ("%s, conf1 = %08x, int_st = %08x, status = %08x\n" , + __func__, +esp32_uart_read (port,UART_CONF1_REG ), +esp32_uart_read (port,UART_INT_ST_REG ), +esp32_uart_read (port,UART_STATUS_REG ));
\n here. Is this debug printout somehow useful?
drivers/tty/serial/esp32_uart.c line 343
Quoted 9 lines
drivers/tty/serial/esp32_uart.c new file +9
-0+return ret; +} + +static void esp32_uart_shutdown (struct uart_port *port) +{ + struct esp32_port *sport = container_of(port, struct esp32_port, port); + +esp32_uart_write (port,UART_INT_ENA_REG ,0 ); +devm_free_irq (port->dev, port->irq, port);
I wonder why to use devm_ after all?
drivers/tty/serial/esp32_uart.c line 356
Quoted 13 lines
drivers/tty/serial/esp32_uart.c new file +13
-0+clk_disable_unprepare (sport->clk); +} + +static bool esp32_uart_set_baud (struct uart_port *port,u32 baud) +{ +u32 div = port->uartclk / baud; +u32 frag = (port->uartclk *16 ) / baud - div *16 ; + +if (div <=port_variant (port)->clkdiv_mask) { +esp32_uart_write (port,UART_CLKDIV_REG , + div |FIELD_PREP (UART_CLKDIV_FRAG , frag)); +return true; + }
\n
Quoted 2 lines
(quoted diff) +2
-0+ return false; +}
...
drivers/tty/serial/esp32_uart.c line 628
Quoted 4 lines
drivers/tty/serial/esp32_uart.c new file +4
-0+static int __init esp32s3_uart_early_console_setup (struct earlycon_device *device, +const char *options) +{ + device->port.private_data = (void *)&esp32s3_variant;
No need to cast, right?
\n
Quoted 2 lines
(quoted diff) +2
-0+ return esp32xx_uart_early_console_setup(device, options); +}
...
Quoted 44 lines
drivers/tty/serial/esp32_uart.c new file +44
-0+static int esp32_uart_probe (struct platform_device *pdev) +{ +struct device_node *np = pdev->dev.of_node; +static const struct of_device_id *match; +struct uart_port *port; +struct esp32_port *sport; +struct resource *res; +int ret; + + match =of_match_device (esp32_uart_dt_ids, &pdev->dev); +if (!match) +return -ENODEV ; + + sport =devm_kzalloc (&pdev->dev,sizeof (*sport),GFP_KERNEL ); +if (!sport) +return -ENOMEM ; + + port = &sport->port; + + ret =of_alias_get_id (np,"serial" ); +if (ret <0 ) { +dev_err (&pdev->dev,"failed to get alias id, errno %d\n" , ret); +return ret; + } +if (ret >=UART_NR ) { +dev_err (&pdev->dev,"driver limited to %d serial ports\n" ,UART_NR ); +return -ENOMEM ; + } + + port->line = ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -ENODEV ; + + port->mapbase = res->start; + port->membase =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (port->membase)) +return PTR_ERR (port->membase); + + sport->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (sport->clk)) +return PTR_ERR (sport->clk); +
drivers/tty/serial/esp32_uart.c line 696
Quoted 10 lines
drivers/tty/serial/esp32_uart.c new file +10
-0+ port->uartclk =clk_get_rate (sport->clk); + port->dev = &pdev->dev; + port->type =PORT_ESP32UART ; + port->iotype =UPIO_MEM ; + port->irq =platform_get_irq (pdev,0 ); + port->ops = &esp32_uart_pops; + port->flags =UPF_BOOT_AUTOCONF ; + port->has_sysrq =1 ; + port->fifosize =ESP32_UART_TX_FIFO_SIZE ; + port->private_data = (void *)match->data;
No need to cast.
drivers/tty/serial/esp32_uart.c line 703
Quoted 7 lines
drivers/tty/serial/esp32_uart.c new file +7
-0+ + esp32_uart_ports[port->line] = sport; + +platform_set_drvdata (pdev, port); + +return uart_add_one_port (&esp32_uart_reg, port); +}
regards,
Signature · 2 lines
js suse labs
Re: [PATCH v2 3/5] drivers/tty/serial: add driver for the ESP32 UART
Quoted 16 lines · Jiri Slaby
Quoted 2 lines · Max Filippov
Add driver for the UART controllers of the Espressif ESP32 and ESP32S3 SoCs. Hardware specification is available at the following URLs:
...
Quoted 11 lines
drivers/tty/serial/esp32_uart.c new file +11
-0+static void esp32_uart_rxint (struct uart_port *port) +{ +struct tty_port *tty_port = &port->state->port; +u32 rx_fifo_cnt =esp32_uart_rx_fifo_cnt (port); +unsigned long flags; +u32 i; + +if (!rx_fifo_cnt) +return ; + +spin_lock_irqsave (&port->lock, flags);
Quoted 8 lines
drivers/tty/serial/esp32_uart.c line 207
Quoted 6 lines
drivers/tty/serial/esp32_uart.c new file +6
-0+ +for (i =0 ; i < rx_fifo_cnt; ++i) { +u32 rx =esp32_uart_read (port,UART_FIFO_REG ); +u32 brk =0 ; + + ++port->icount.rx;Should yuou increment this only in case of
insert_flip_char()?
I don't know. Does port->icount.rx have clearly defined semantics? I've looked through multiple other serial drivers and there's a lot of examples of similar pattern.
Quoted 23 lines
drivers/tty/serial/esp32_uart.c line 221
Quoted 13 lines
drivers/tty/serial/esp32_uart.c new file +13
-0+if (!rx) { + brk =esp32_uart_read (port,UART_INT_ST_REG ) & +UART_BRK_DET_INT ; + } +if (brk) { +esp32_uart_write (port,UART_INT_CLR_REG , brk); + ++port->icount.brk; +uart_handle_break (port); + }else { +if (uart_handle_sysrq_char (port, (unsigned char )rx)) +continue ; +tty_insert_flip_char (tty_port, rx,TTY_NORMAL ); + }This is heavy. Is it equivalent to:
if (!rx &&esp32_uart_read(port, UART_INT_ST_REG)&UART_BRK_DET_INT) { esp32_uart_write(port, UART_INT_CLR_REG, brk); ++port->icount.brk; uart_handle_break(port); continue; }
Quoted 6 lines
if (
uart_handle_sysrq_char(port, (unsigned char)rx))
continue;
tty_insert_flip_char(tty_port, rx, TTY_NORMAL);?
It is equivalent, but I find the version that I used somewhat easier to read. Maybe this:
if (!rx &&
(esp32_uart_read(port, UART_INT_ST_REG) &
UART_BRK_DET_INT)) {
esp32_uart_write(port, UART_INT_CLR_REG, brk);
++port->icount.brk;
uart_handle_break(port);
} else {
if (uart_handle_sysrq_char(port, (unsigned char)rx))
continue;
tty_insert_flip_char(tty_port, rx, TTY_NORMAL);
}?
Quoted 6 lines
Quoted 5 lines
drivers/tty/serial/esp32_uart.c new file +5
-0+ } +spin_unlock_irqrestore (&port->lock, flags); + +tty_flip_buffer_push (tty_port); +}...
Quoted 7 lines
drivers/tty/serial/esp32_uart.c line 237
Quoted 5 lines
drivers/tty/serial/esp32_uart.c new file +5
-0+static void esp32_uart_put_char_sync (struct uart_port *port,u8 c) +{ +unsigned long timeout; + + timeout = jiffies +msecs_to_jiffies (1000 );I.e. plus HZ?
Yes, ok.
Quoted 9 lines
Quoted 9 lines
drivers/tty/serial/esp32_uart.c new file +9
-0+while (esp32_uart_tx_fifo_cnt (port) >=ESP32_UART_TX_FIFO_SIZE ) { +if (time_after (jiffies, timeout)) { +dev_warn (port->dev,"timeout waiting for TX FIFO\n" ); +return ; + } +cpu_relax (); + } +esp32_uart_put_char (port, c); +}
Quoted 8 lines
drivers/tty/serial/esp32_uart.c line 252
Quoted 6 lines
drivers/tty/serial/esp32_uart.c new file +6
-0+ +static void esp32_uart_transmit_buffer (struct uart_port *port) +{ +u32 tx_fifo_used =esp32_uart_tx_fifo_cnt (port); + +if (tx_fifo_used <ESP32_UART_TX_FIFO_SIZE ) {Invert the condition and return here?
Ok.
Quoted 18 lines
Quoted 16 lines
drivers/tty/serial/esp32_uart.c new file +16
-0+unsigned int pending; +u8 ch; + + pending =uart_port_tx_limited (port, ch, +ESP32_UART_TX_FIFO_SIZE - tx_fifo_used, + true,esp32_uart_put_char (port, ch), + ({})); +if (pending) { +u32 int_ena; + + int_ena =esp32_uart_read (port,UART_INT_ENA_REG ); + int_ena |=UART_TXFIFO_EMPTY_INT ; +esp32_uart_write (port,UART_INT_ENA_REG , int_ena); + } + } +}
Quoted 15 lines
drivers/tty/serial/esp32_uart.c line 287
Quoted 13 lines
drivers/tty/serial/esp32_uart.c new file +13
-0+static irqreturn_t esp32_uart_int (int irq,void *dev_id) +{ +struct uart_port *port = dev_id; +u32 status; + + status =esp32_uart_read (port,UART_INT_ST_REG ); + +if (status & (UART_RXFIFO_FULL_INT |UART_BRK_DET_INT )) +esp32_uart_rxint (port); +if (status &UART_TXFIFO_EMPTY_INT ) +esp32_uart_txint (port); + +esp32_uart_write (port,UART_INT_CLR_REG , status);\n here please.
Ok
Quoted 26 lines
Quoted 13 lines
drivers/tty/serial/esp32_uart.c new file +12
-0+return IRQ_RETVAL (status); +} +static int esp32_uart_startup (struct uart_port *port) +{ +int ret =0 ; +unsigned long flags; + struct esp32_port *sport = container_of(port, struct esp32_port, port); + + ret =clk_prepare_enable (sport->clk); +if (ret) +return ret; +drivers/tty/serial/esp32_uart.c line 324
Quoted 10 lines
drivers/tty/serial/esp32_uart.c new file +10
-0+ ret =devm_request_irq (port->dev, port->irq, esp32_uart_int,0 , +DRIVER_NAME , port); +if (ret) { +clk_disable_unprepare (sport->clk); +return ret; + } + +spin_lock_irqsave (&port->lock, flags); + esp32_uart_write(port, UART_CONF1_REG, + (1 << UART_RXFIFO_FULL_THRHD_SHIFT) |
BIT()?
Quoted 3 lines
Quoted 1 line
+ (1 << port_variant(port)->txfifo_empty_thrhd_shift));
And here?
These are not logically bits, in both cases I put value 1 into multiple-bit fields.
Quoted 11 lines
drivers/tty/serial/esp32_uart.c line 334
Quoted 9 lines
drivers/tty/serial/esp32_uart.c new file +9
-0+esp32_uart_write (port,UART_INT_CLR_REG ,UART_RXFIFO_FULL_INT |UART_BRK_DET_INT ); +esp32_uart_write (port,UART_INT_ENA_REG ,UART_RXFIFO_FULL_INT |UART_BRK_DET_INT ); +spin_unlock_irqrestore (&port->lock, flags); + +pr_debug ("%s, conf1 = %08x, int_st = %08x, status = %08x\n" , + __func__, +esp32_uart_read (port,UART_CONF1_REG ), +esp32_uart_read (port,UART_INT_ST_REG ), +esp32_uart_read (port,UART_STATUS_REG ));\n here. Is this debug printout somehow useful?
I'll drop it.
Quoted 11 lines
drivers/tty/serial/esp32_uart.c line 343
Quoted 9 lines
drivers/tty/serial/esp32_uart.c new file +9
-0+return ret; +} + +static void esp32_uart_shutdown (struct uart_port *port) +{ + struct esp32_port *sport = container_of(port, struct esp32_port, port); + +esp32_uart_write (port,UART_INT_ENA_REG ,0 ); +devm_free_irq (port->dev, port->irq, port);I wonder why to use
devm_after all?
I'll switch to non-devm_ version.
Quoted 7 lines
Quoted 7 lines
drivers/tty/serial/esp32_uart.c new file +7
-0+clk_disable_unprepare (sport->clk); +} + +static bool esp32_uart_set_baud (struct uart_port *port,u32 baud) +{ +u32 div = port->uartclk / baud; +u32 frag = (port->uartclk *16 ) / baud - div *16 ;
Quoted 8 lines
drivers/tty/serial/esp32_uart.c line 356
Quoted 6 lines
drivers/tty/serial/esp32_uart.c new file +6
-0+ +if (div <=port_variant (port)->clkdiv_mask) { +esp32_uart_write (port,UART_CLKDIV_REG , + div |FIELD_PREP (UART_CLKDIV_FRAG , frag)); +return true; + }\n
Ok.
Quoted 9 lines
Quoted 2 lines
(quoted diff) +2
-0+ return false; +}...
drivers/tty/serial/esp32_uart.c line 628
Quoted 4 lines
drivers/tty/serial/esp32_uart.c new file +4
-0+static int __init esp32s3_uart_early_console_setup (struct earlycon_device *device, +const char *options) +{ + device->port.private_data = (void *)&esp32s3_variant;No need to cast, right?
private_data is void *, esp32s3_variant is a constant.
Quoted 1 line
\n
Ok.
Quoted 51 lines
Quoted 2 lines
(quoted diff) +2
-0+ return esp32xx_uart_early_console_setup(device, options); +}...
Quoted 48 lines
drivers/tty/serial/esp32_uart.c new file +48
-0+static int esp32_uart_probe (struct platform_device *pdev) +{ +struct device_node *np = pdev->dev.of_node; +static const struct of_device_id *match; +struct uart_port *port; +struct esp32_port *sport; +struct resource *res; +int ret; + + match =of_match_device (esp32_uart_dt_ids, &pdev->dev); +if (!match) +return -ENODEV ; + + sport =devm_kzalloc (&pdev->dev,sizeof (*sport),GFP_KERNEL ); +if (!sport) +return -ENOMEM ; + + port = &sport->port; + + ret =of_alias_get_id (np,"serial" ); +if (ret <0 ) { +dev_err (&pdev->dev,"failed to get alias id, errno %d\n" , ret); +return ret; + } +if (ret >=UART_NR ) { +dev_err (&pdev->dev,"driver limited to %d serial ports\n" ,UART_NR ); +return -ENOMEM ; + } + + port->line = ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -ENODEV ; + + port->mapbase = res->start; + port->membase =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (port->membase)) +return PTR_ERR (port->membase); + + sport->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (sport->clk)) +return PTR_ERR (sport->clk); + + port->uartclk =clk_get_rate (sport->clk); + port->dev = &pdev->dev; + port->type =PORT_ESP32UART ; + port->iotype =UPIO_MEM ;
Quoted 8 lines
drivers/tty/serial/esp32_uart.c line 696
Quoted 6 lines
drivers/tty/serial/esp32_uart.c new file +6
-0+ port->irq =platform_get_irq (pdev,0 ); + port->ops = &esp32_uart_pops; + port->flags =UPF_BOOT_AUTOCONF ; + port->has_sysrq =1 ; + port->fifosize =ESP32_UART_TX_FIFO_SIZE ; + port->private_data = (void *)match->data;No need to cast.
This is again a const cast.
Quoted 13 lines
drivers/tty/serial/esp32_uart.c line 703
Quoted 7 lines
drivers/tty/serial/esp32_uart.c new file +7
-0+ + esp32_uart_ports[port->line] = sport; + +platform_set_drvdata (pdev, port); + +return uart_add_one_port (&esp32_uart_reg, port); +}regards,
--
js
suse labs
Signature · 2 lines
Thanks. -- Max
PATCH v2 4/5 dt-bindings: serial: document esp32s3-acm
In reply to Max FilippovAdd documentation for the ESP32S3 USB CDC-ACM controller.
---
Changes v1->v2:
- fix description
- rename node in the example
- fix example indentation
.../bindings/serial/esp,esp32-acm.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/esp,esp32-acm.yaml
Documentation/devicetree/bindings/serial/esp,esp32-acm.yaml new file +39 -0
@@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/esp,esp32-acm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ESP32S3 ACM controller + +maintainers: + - Max Filippov <[email protected]> + +description: + Fixed function USB CDC-ACM device controller of the Espressif ESP32S3 SoC. + +properties: + compatible: + const: esp,esp32s3-acm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + serial@60038000 { + compatible = "esp,esp32s3-acm"; + reg = <0x60038000 0x1000>; + interrupts = <96 3 0>; + };
Signature · 1 line
2.30.2
Re: [PATCH v2 4/5] dt-bindings: serial: document esp32s3-acm
Documentation/devicetree/bindings/serial/esp,esp32-acm.yaml line 30
Quoted 11 lines · Max Filippov
Documentation/devicetree/bindings/serial/esp,esp32-acm.yaml new file +11
-0+ reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts +
Same comment here - missing $ref to serial.yaml. Sorry for no bringing it up earlier.
Best regards,
Krzysztof
PATCH v2 5/5 drivers/tty/serial: add ESP32S3 ACM device driver
In reply to Max FilippovAdd driver for the ACM controller of the Espressif ESP32S3 Soc. Hardware specification is available at the following URL:
https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf
(Chapter 33 USB Serial/JTAG Controller)
---
Changes v1->v2:
- redefine register fields using BIT and GENMASK
- drop _MASK suffix from register field definitions
- drop *_SHIFT definitions where possible
- split register reads/writes and bitwise operations into multiple lines
- use u8 instead of unsigned char in internal functions
- add timeout to esp32_acm_put_char_sync
- use uart_port_tx_limited in esp32_acm_transmit_buffer
- use IRQ_RETVAL in esp32_acm_int
- drop esp32s3_acm_console_putchar and esp32s3_acm_earlycon_putchar
- turn num_read into unsigned int in esp32_acm_earlycon_read
- drop MODULE_DESCRIPTION
drivers/tty/serial/Kconfig | 14 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/esp32_acm.c | 458 +++++++++++++++++++++++++++++++ include/uapi/linux/serial_core.h | 3 + 4 files changed, 476 insertions(+) create mode 100644 drivers/tty/serial/esp32_acm.c
drivers/tty/serial/Kconfig +14 -0
@@ -1591,6 +1591,20 @@ config SERIAL_ESP32 earlycon=esp32s3uart,mmio32,0x60000000,115200n8,40000000 earlycon=esp32uart,mmio32,0x3ff40000,115200n8 +config SERIAL_ESP32_ACM + tristate "Espressif ESP32 USB ACM support" + depends on XTENSA_PLATFORM_ESP32 || (COMPILE_TEST && OF) + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Driver for the CDC ACM controllers of the Espressif ESP32S3 SoCs + that share separate USB controller with the JTAG adapter. + The device name used for this controller is ttyACM. + When earlycon option is enabled the following kernel command line + snippet may be used: + earlycon=esp32s3acm,mmio32,0x60038000 + endmenu config SERIAL_MCTRL_GPIO
drivers/tty/serial/Makefile +1 -0
@@ -89,6 +89,7 @@ obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o obj-$(CONFIG_SERIAL_ESP32) += esp32_uart.o +obj-$(CONFIG_SERIAL_ESP32_ACM) += esp32_acm.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
drivers/tty/serial/esp32_acm.c new file +458 -0
458 lines not on this page · raw message
include/uapi/linux/serial_core.h +3 -0
@@ -248,4 +248,7 @@/* Espressif ESP32 UART */ #define PORT_ESP32UART 124 +/* Espressif ESP32 ACM */ +#define PORT_ESP32ACM 125 +#endif /* _UAPILINUX_SERIAL_CORE_H */
Signature · 1 line
2.30.2