mbox series

[v2,0/7] tty: serial: meson: support ttyS devname

Message ID 20230705181833.16137-1-ddrokosov@sberdevices.ru
Headers show
Series tty: serial: meson: support ttyS devname | expand

Message

Dmitry Rokosov July 5, 2023, 6:18 p.m. UTC
During a IRC discussion with Neil, as reported in reference [1], an idea
emerged to provide support for a standard devname 'ttyS' in new SoCs
such as A1, S4, T7, C3 and others. The current devname 'ttyAML' is not
widely known and has caused several issues with both low and high-level
software, without any apparent justification for its implementation.
Consequently, it has been deemed necessary to introduce the 'ttyS'
devname for all new 'compatible' entries, while still retaining backward
compatibility with the old 'ttyAML' devname by supporting it in parallel
with the new approach. This patch series therefore aims to implement
these changes.

Changes v2 since v1 at [2]:
    - as suggested by Conor, relocate modifications with the new
      uart_data structures of S4 and A1 SoC from the main meson_uart
      patchset to a separate patchsets
    - ensure that the uart_driver is not unregistered if there is at
      least one active port
    - per Neil's suggestion declare separate uart_driver and console
      objects for both tty devnames (ttyAML and ttyS) to enable the use
      of multiple uart objects with different compatibility strings

Links:
    [1]: https://libera.irclog.whitequark.org/linux-amlogic/2023-07-03
    [2]: https://lore.kernel.org/linux-amlogic/20230704135936.14697-1-ddrokosov@sberdevices.ru/

Dmitry Rokosov (7):
  tty: serial: meson: use dev_err_probe
  tty: serial: meson: redesign the module to platform_driver
  tty: serial: meson: apply ttyS devname instead of ttyAML for new SoCs
  tty: serial: meson: introduce separate uart_data for S4 SoC family
  tty: serial: meson: add independent uart_data for A1 SoC family
  dt-bindings: serial: amlogic,meson-uart: support Amlogic A1
  arm64: dts: meson: a1: change uart compatible string

 .../bindings/serial/amlogic,meson-uart.yaml   |   2 +
 arch/arm64/boot/dts/amlogic/meson-a1.dtsi     |   4 +-
 drivers/tty/serial/meson_uart.c               | 145 ++++++++++--------
 3 files changed, 88 insertions(+), 63 deletions(-)

Comments

Conor Dooley July 5, 2023, 9:10 p.m. UTC | #1
On Wed, Jul 05, 2023 at 09:18:32PM +0300, Dmitry Rokosov wrote:
> Introduce meson uart serial bindings for A1 SoC family.
> 
> Signed-off-by: Dmitry Rokosov <ddrokosov@sberdevices.ru>

Looks like there's a missing Ack here from Rob:
https://lore.kernel.org/all/168858360022.1592604.9922710628917242811.robh@kernel.org/

Cheers,
Conor.

> ---
>  .../devicetree/bindings/serial/amlogic,meson-uart.yaml          | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml
> index 01ec45b3b406..f1ae8c4934d9 100644
> --- a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml
> +++ b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml
> @@ -33,6 +33,7 @@ properties:
>                - amlogic,meson8b-uart
>                - amlogic,meson-gx-uart
>                - amlogic,meson-s4-uart
> +              - amlogic,meson-a1-uart
>            - const: amlogic,meson-ao-uart
>        - description: Always-on power domain UART controller on G12A SoCs
>          items:
> @@ -46,6 +47,7 @@ properties:
>            - amlogic,meson8b-uart
>            - amlogic,meson-gx-uart
>            - amlogic,meson-s4-uart
> +          - amlogic,meson-a1-uart
>        - description: Everything-Else power domain UART controller on G12A SoCs
>          items:
>            - const: amlogic,meson-g12a-uart
> -- 
> 2.36.0
>
Neil Armstrong July 6, 2023, 6:59 a.m. UTC | #2
On 05/07/2023 20:18, Dmitry Rokosov wrote:
> Actually, the meson_uart module is already a platform_driver, but it is
> currently registered manually and the uart core registration is run
> outside the probe() scope, which results in some restrictions. For
> instance, it is not possible to communicate with the OF subsystem
> because it requires an initialized device object.
> 
> To address this issue, apply module_platform_driver() instead of direct
> module init/exit routines. Additionally, move uart_register_driver() to
> the driver probe(), and destroy manual console registration because it's
> already run in the uart_register_driver() flow.
> 
> Signed-off-by: Dmitry Rokosov <ddrokosov@sberdevices.ru>
> ---
>   drivers/tty/serial/meson_uart.c | 51 ++++++++++-----------------------
>   1 file changed, 15 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
> index bca54f3d92a1..dcf994a11a21 100644
> --- a/drivers/tty/serial/meson_uart.c
> +++ b/drivers/tty/serial/meson_uart.c
> @@ -621,12 +621,6 @@ static struct console meson_serial_console = {
>   	.data		= &meson_uart_driver,
>   };
>   
> -static int __init meson_serial_console_init(void)
> -{
> -	register_console(&meson_serial_console);
> -	return 0;
> -}
> -
>   static void meson_serial_early_console_write(struct console *co,
>   					     const char *s,
>   					     u_int count)
> @@ -652,9 +646,6 @@ OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart",
>   
>   #define MESON_SERIAL_CONSOLE	(&meson_serial_console)
>   #else
> -static int __init meson_serial_console_init(void) {
> -	return 0;
> -}
>   #define MESON_SERIAL_CONSOLE	NULL
>   #endif
>   
> @@ -738,6 +729,13 @@ static int meson_uart_probe(struct platform_device *pdev)
>   	if (ret)
>   		return ret;
>   
> +	if (!meson_uart_driver.state) {
> +		ret = uart_register_driver(&meson_uart_driver);
> +		if (ret)
> +			return dev_err_probe(&pdev->dev, ret,
> +					     "can't register uart driver\n");
> +	}
> +
>   	port->iotype = UPIO_MEM;
>   	port->mapbase = res_mem->start;
>   	port->mapsize = resource_size(res_mem);
> @@ -776,6 +774,13 @@ static int meson_uart_remove(struct platform_device *pdev)
>   	uart_remove_one_port(&meson_uart_driver, port);
>   	meson_ports[pdev->id] = NULL;
>   
> +	for (int id = 0; id < AML_UART_PORT_NUM; id++)
> +		if (meson_ports[id])
> +			return 0;
> +
> +	/* No more available uart ports, unregister uart driver */
> +	uart_unregister_driver(&meson_uart_driver);
> +
>   	return 0;
>   }
>   
> @@ -809,33 +814,7 @@ static  struct platform_driver meson_uart_platform_driver = {
>   	},
>   };
>   
> -static int __init meson_uart_init(void)
> -{
> -	int ret;
> -
> -	ret = meson_serial_console_init();
> -	if (ret)
> -		return ret;
> -	
> -	ret = uart_register_driver(&meson_uart_driver);
> -	if (ret)
> -		return ret;
> -
> -	ret = platform_driver_register(&meson_uart_platform_driver);
> -	if (ret)
> -		uart_unregister_driver(&meson_uart_driver);
> -
> -	return ret;
> -}
> -
> -static void __exit meson_uart_exit(void)
> -{
> -	platform_driver_unregister(&meson_uart_platform_driver);
> -	uart_unregister_driver(&meson_uart_driver);
> -}
> -
> -module_init(meson_uart_init);
> -module_exit(meson_uart_exit);
> +module_platform_driver(meson_uart_platform_driver);
>   
>   MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
>   MODULE_DESCRIPTION("Amlogic Meson serial port driver");

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Neil Armstrong July 6, 2023, 7:08 a.m. UTC | #3
Hi,

On 05/07/2023 20:18, Dmitry Rokosov wrote:
> It is worth noting that the devname ttyS is a widely recognized tty name
> and is commonly used by many uart device drivers. Given the established
> usage and compatibility concerns, it may not be feasible to change the
> devname for older SoCs. However, for new definitions, it is acceptable
> and even recommended to use a new devname to help ensure clarity and
> avoid any potential conflicts on lower or upper software levels.
> 
> For more information please refer to IRC discussion at [1].
> 
> Links:
>      [1]: https://libera.irclog.whitequark.org/linux-amlogic/2023-07-03
> 
> Signed-off-by: Dmitry Rokosov <ddrokosov@sberdevices.ru>
> ---
>   drivers/tty/serial/meson_uart.c | 82 ++++++++++++++++++++++-----------
>   1 file changed, 56 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
> index dcf994a11a21..ad0748a10db7 100644
> --- a/drivers/tty/serial/meson_uart.c
> +++ b/drivers/tty/serial/meson_uart.c
> @@ -72,16 +72,22 @@
>   
>   #define AML_UART_PORT_NUM		12
>   #define AML_UART_PORT_OFFSET		6
> -#define AML_UART_DEV_NAME		"ttyAML"
>   
>   #define AML_UART_POLL_USEC		5
>   #define AML_UART_TIMEOUT_USEC		10000
>   
> -static struct uart_driver meson_uart_driver;
> +#define MESON_UART_DRIVER(_devname) meson_uart_driver_##_devname
> +
> +#define MESON_UART_DRIVER_DECLARE(_devname) \
> +	static struct uart_driver MESON_UART_DRIVER(_devname)
> +
> +MESON_UART_DRIVER_DECLARE(ttyAML);
> +MESON_UART_DRIVER_DECLARE(ttyS);

Not sure those macros are useful:
MESON_UART_DRIVER_DECLARE(ttyAML)
vs
static struct uart_driver meson_uart_driver_ttyAML

I prefer the second...

>   
>   static struct uart_port *meson_ports[AML_UART_PORT_NUM];
>   
>   struct meson_uart_data {
> +	struct uart_driver *uart_driver;
>   	bool has_xtal_div2;
>   };
>   
> @@ -611,15 +617,21 @@ static int meson_serial_console_setup(struct console *co, char *options)
>   	return uart_set_options(port, co, baud, parity, bits, flow);
>   }

I think the uart_driver meson_uart_driver_ttyXXX should be declared here instead or..

>   
> -static struct console meson_serial_console = {
> -	.name		= AML_UART_DEV_NAME,
> -	.write		= meson_serial_console_write,
> -	.device		= uart_console_device,
> -	.setup		= meson_serial_console_setup,
> -	.flags		= CON_PRINTBUFFER,
> -	.index		= -1,
> -	.data		= &meson_uart_driver,
> -};
> +#define MESON_SERIAL_CONSOLE(_devname) meson_serial_console_##_devname
> +
> +#define MESON_SERIAL_CONSOLE_DEFINE(_devname)				\
> +	static struct console MESON_SERIAL_CONSOLE(_devname) = {	\
> +		.name		= __stringify(_devname),		\
> +		.write		= meson_serial_console_write,		\
> +		.device		= uart_console_device,			\
> +		.setup		= meson_serial_console_setup,		\
> +		.flags		= CON_PRINTBUFFER,			\
> +		.index		= -1,					\
> +		.data		= &MESON_UART_DRIVER(_devname),		\
> +	}

... you could even declare the meson_uart_driver_ttyXXX in this macro instead.

> +
> +MESON_SERIAL_CONSOLE_DEFINE(ttyAML);
> +MESON_SERIAL_CONSOLE_DEFINE(ttyS);
>   
>   static void meson_serial_early_console_write(struct console *co,
>   					     const char *s,
> @@ -644,18 +656,22 @@ meson_serial_early_console_setup(struct earlycon_device *device, const char *opt
>   OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart",
>   		    meson_serial_early_console_setup);
>   
> -#define MESON_SERIAL_CONSOLE	(&meson_serial_console)
> +#define MESON_SERIAL_CONSOLE_PTR(_devname) (&MESON_SERIAL_CONSOLE(_devname))
>   #else
> -#define MESON_SERIAL_CONSOLE	NULL
> +#define MESON_SERIAL_CONSOLE_PTR(_devname)	(NULL)
>   #endif
>   
> -static struct uart_driver meson_uart_driver = {
> -	.owner		= THIS_MODULE,
> -	.driver_name	= "meson_uart",
> -	.dev_name	= AML_UART_DEV_NAME,
> -	.nr		= AML_UART_PORT_NUM,
> -	.cons		= MESON_SERIAL_CONSOLE,
> -};
> +#define MESON_UART_DRIVER_DEFINE(_devname)  \
> +	static struct uart_driver MESON_UART_DRIVER(_devname) = {	\
> +		.owner		= THIS_MODULE,				\
> +		.driver_name	= "meson_uart",				\
> +		.dev_name	= __stringify(_devname),		\
> +		.nr		= AML_UART_PORT_NUM,			\
> +		.cons		= MESON_SERIAL_CONSOLE_PTR(_devname),	\
> +	}
> +
> +MESON_UART_DRIVER_DEFINE(ttyAML);
> +MESON_UART_DRIVER_DEFINE(ttyS);

Those macros are fine, but drop the MESON_UART_DRIVER & MESON_SERIAL_CONSOLE macros and drop the _DEFINE in those macros.

>   
>   static int meson_uart_probe_clocks(struct platform_device *pdev,
>   				   struct uart_port *port)
> @@ -681,8 +697,16 @@ static int meson_uart_probe_clocks(struct platform_device *pdev,
>   	return 0;
>   }
>   
> +static struct uart_driver *meson_uart_current(const struct meson_uart_data *pd)
> +{
> +	return (pd && pd->uart_driver) ?
> +		pd->uart_driver : &MESON_UART_DRIVER(ttyAML);

I'll definitely prefer if you use the real variable name everywhere and in the 2 following patches

> +}
> +
>   static int meson_uart_probe(struct platform_device *pdev)
>   {
> +	const struct meson_uart_data *priv_data;
> +	struct uart_driver *uart_driver;
>   	struct resource *res_mem;
>   	struct uart_port *port;
>   	u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */
> @@ -729,8 +753,12 @@ static int meson_uart_probe(struct platform_device *pdev)
>   	if (ret)
>   		return ret;
>   
> -	if (!meson_uart_driver.state) {
> -		ret = uart_register_driver(&meson_uart_driver);
> +	priv_data = device_get_match_data(&pdev->dev);
> +
> +	uart_driver = meson_uart_current(priv_data);
> +
> +	if (!uart_driver->state) {
> +		ret = uart_register_driver(uart_driver);
>   		if (ret)
>   			return dev_err_probe(&pdev->dev, ret,
>   					     "can't register uart driver\n");
> @@ -748,7 +776,7 @@ static int meson_uart_probe(struct platform_device *pdev)
>   	port->x_char = 0;
>   	port->ops = &meson_uart_ops;
>   	port->fifosize = fifosize;
> -	port->private_data = (void *)device_get_match_data(&pdev->dev);
> +	port->private_data = (void *)priv_data;
>   
>   	meson_ports[pdev->id] = port;
>   	platform_set_drvdata(pdev, port);
> @@ -759,7 +787,7 @@ static int meson_uart_probe(struct platform_device *pdev)
>   		meson_uart_release_port(port);
>   	}
>   
> -	ret = uart_add_one_port(&meson_uart_driver, port);
> +	ret = uart_add_one_port(uart_driver, port);
>   	if (ret)
>   		meson_ports[pdev->id] = NULL;
>   
> @@ -768,10 +796,12 @@ static int meson_uart_probe(struct platform_device *pdev)
>   
>   static int meson_uart_remove(struct platform_device *pdev)
>   {
> +	struct uart_driver *uart_driver;
>   	struct uart_port *port;
>   
>   	port = platform_get_drvdata(pdev);
> -	uart_remove_one_port(&meson_uart_driver, port);
> +	uart_driver = meson_uart_current(port->private_data);
> +	uart_remove_one_port(uart_driver, port);
>   	meson_ports[pdev->id] = NULL;
>   
>   	for (int id = 0; id < AML_UART_PORT_NUM; id++)
> @@ -779,7 +809,7 @@ static int meson_uart_remove(struct platform_device *pdev)
>   			return 0;
>   
>   	/* No more available uart ports, unregister uart driver */
> -	uart_unregister_driver(&meson_uart_driver);
> +	uart_unregister_driver(uart_driver);
>   
>   	return 0;
>   }

Anyway this looks much better :-)

Thanks,
Neil
Neil Armstrong July 6, 2023, 7:09 a.m. UTC | #4
On 05/07/2023 20:18, Dmitry Rokosov wrote:
> In order to use the correct devname value for the S4 SoC family, it
> is imperative that we implement separate uart_data. Unlike the legacy
> g12a architecture, the S4 architecture should employ the use of 'ttyS'
> devname.
> 
> Signed-off-by: Dmitry Rokosov <ddrokosov@sberdevices.ru>
> ---
>   drivers/tty/serial/meson_uart.c | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
> index ad0748a10db7..6a63184b8091 100644
> --- a/drivers/tty/serial/meson_uart.c
> +++ b/drivers/tty/serial/meson_uart.c
> @@ -818,6 +818,11 @@ static struct meson_uart_data meson_g12a_uart_data = {
>   	.has_xtal_div2 = true,
>   };
>   
> +static struct meson_uart_data meson_s4_uart_data = {
> +	.uart_driver = &MESON_UART_DRIVER(ttyS),
> +	.has_xtal_div2 = true,
> +};
> +
>   static const struct of_device_id meson_uart_dt_match[] = {
>   	{ .compatible = "amlogic,meson6-uart" },
>   	{ .compatible = "amlogic,meson8-uart" },
> @@ -829,7 +834,7 @@ static const struct of_device_id meson_uart_dt_match[] = {
>   	},
>   	{
>   		.compatible = "amlogic,meson-s4-uart",
> -		.data = (void *)&meson_g12a_uart_data,
> +		.data = (void *)&meson_s4_uart_data,
>   	},
>   	{ /* sentinel */ },
>   };

With the real struct name:

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Rob Herring (Arm) July 6, 2023, 5:57 p.m. UTC | #5
On Wed, 05 Jul 2023 21:18:32 +0300, Dmitry Rokosov wrote:
> Introduce meson uart serial bindings for A1 SoC family.
> 
> Signed-off-by: Dmitry Rokosov <ddrokosov@sberdevices.ru>
> ---
>  .../devicetree/bindings/serial/amlogic,meson-uart.yaml          | 2 ++
>  1 file changed, 2 insertions(+)
> 


Please add Acked-by/Reviewed-by tags when posting new versions. However,
there's no need to repost patches *only* to add the tags. The upstream
maintainer will do that for acks received on the version they apply.

If a tag was not added on purpose, please state why and what changed.

Missing tags:

Acked-by: Rob Herring <robh@kernel.org>