linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: mlangsdo@redhat.com (Mark Langsdorf)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 10/11] drivers: PL011: add support for the ARM SBSA generic UART
Date: Wed, 13 May 2015 09:32:54 -0500	[thread overview]
Message-ID: <55536096.4020008@redhat.com> (raw)
In-Reply-To: <1431440095-5146-11-git-send-email-andre.przywara@arm.com>

On 05/12/2015 09:14 AM, Andre Przywara wrote:
> The ARM Server Base System Architecture[1] document describes a
> generic UART which is a subset of the PL011 UART.
> It lacks DMA support, baud rate control and modem status line
> control, among other things.
> The idea is to move the UART initialization and setup into the
> firmware (which does this job today already) and let the kernel just
> use the UART for sending and receiving characters.
>
> We use the recent refactoring to build a new struct uart_ops
> variable which points to some new functions avoiding access to the
> missing registers. We reuse as much existing PL011 code as possible.
>
> In contrast to the PL011 the SBSA UART does not define any AMBA or
> PrimeCell relations, so we go with a pretty generic probe function
> which only uses platform device functions.
> A DT binding is provided with this patch, ACPI support is added in a
> separate one.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>   .../devicetree/bindings/serial/arm_sbsa_uart.txt   |  10 ++
>   drivers/tty/serial/amba-pl011.c                    | 168 +++++++++++++++++++++
>   2 files changed, 178 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
>
> diff --git a/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt b/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
> new file mode 100644
> index 0000000..4163e7e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
> @@ -0,0 +1,10 @@
> +* ARM SBSA defined generic UART
> +This UART uses a subset of the PL011 registers and consequently lives
> +in the PL011 driver. It's baudrate and other communication parameters
> +cannot be adjusted at runtime, so it lacks a clock specifier here.
> +
> +Required properties:
> +- compatible: must be "arm,sbsa-uart"
> +- reg: exactly one register range
> +- interrupts: exactly one interrupt specifier
> +- current-speed: the (fixed) baud rate set by the firmware
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index 70e2958..cca93d9 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -101,6 +101,14 @@ static struct vendor_data vendor_arm = {
>   	.get_fifosize		= get_fifosize_arm,
>   };
>
> +static struct vendor_data vendor_sbsa = {
> +	.oversampling		= false,
> +	.dma_threshold		= false,
> +	.cts_event_workaround	= false,
> +	.always_enabled		= true,
> +	.fixed_options		= true,
> +};
> +
>   static unsigned int get_fifosize_st(struct amba_device *dev)
>   {
>   	return 64;
> @@ -1641,6 +1649,28 @@ static int pl011_startup(struct uart_port *port)
>   	return retval;
>   }
>
> +static int sbsa_uart_startup(struct uart_port *port)
> +{
> +	struct uart_amba_port *uap =
> +		container_of(port, struct uart_amba_port, port);
> +	int retval;
> +
> +	retval = pl011_hwinit(port);
> +	if (retval)
> +		return retval;
> +
> +	retval = pl011_allocate_irq(uap);
> +	if (retval)
> +		return retval;
> +
> +	/* The SBSA UART does not support any modem status lines. */
> +	uap->old_status = 0;
> +
> +	pl011_enable_interrupts(uap);
> +
> +	return 0;
> +}
> +
>   static void pl011_shutdown_channel(struct uart_amba_port *uap,
>   					unsigned int lcrh)
>   {
> @@ -1721,6 +1751,19 @@ static void pl011_shutdown(struct uart_port *port)
>   		uap->port.ops->flush_buffer(port);
>   }
>
> +static void sbsa_uart_shutdown(struct uart_port *port)
> +{
> +	struct uart_amba_port *uap =
> +		container_of(port, struct uart_amba_port, port);
> +
> +	pl011_disable_interrupts(uap);
> +
> +	free_irq(uap->port.irq, uap);
> +
> +	if (uap->port.ops->flush_buffer)
> +		uap->port.ops->flush_buffer(port);
> +}
> +
>   static void
>   pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios)
>   {
> @@ -1872,6 +1915,24 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
>   	spin_unlock_irqrestore(&port->lock, flags);
>   }
>
> +static void
> +sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
> +		      struct ktermios *old)
> +{
> +	struct uart_amba_port *uap =
> +	    container_of(port, struct uart_amba_port, port);
> +	unsigned long flags;
> +
> +	if (old)
> +		tty_termios_copy_hw(termios, old);

This code prevented login via the serial console on our test hardware.

Mark Salter suggested the following patch:

-       if (old)
+       /*
+        * The first call to set_termios() comes when the console is
+        * registered via uart_add_one_port(). The serial core will
+        * pass in a dummy old termios rather than NULL. Check to make
+        * sure the old termios has reasonable info before copying from
+        * it.
+        */
+       if (old && old->c_cflag)
                 tty_termios_copy_hw(termios, old);

which fixed the issue.

> +	tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +	uart_update_timeout(port, CS8, uap->fixed_baud);
> +	pl011_setup_status_masks(port, termios);
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
>   static const char *pl011_type(struct uart_port *port)
>   {
>   	struct uart_amba_port *uap =
> @@ -1947,6 +2008,37 @@ static struct uart_ops amba_pl011_pops = {
>   #endif
>   };
>
> +static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +}
> +
> +static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
> +{
> +	return 0;
> +}
> +
> +static const struct uart_ops sbsa_uart_pops = {
> +	.tx_empty	= pl011_tx_empty,
> +	.set_mctrl	= sbsa_uart_set_mctrl,
> +	.get_mctrl	= sbsa_uart_get_mctrl,
> +	.stop_tx	= pl011_stop_tx,
> +	.start_tx	= pl011_start_tx,
> +	.stop_rx	= pl011_stop_rx,
> +	.startup	= sbsa_uart_startup,
> +	.shutdown	= sbsa_uart_shutdown,
> +	.set_termios	= sbsa_uart_set_termios,
> +	.type		= pl011_type,
> +	.release_port	= pl011_release_port,
> +	.request_port	= pl011_request_port,
> +	.config_port	= pl011_config_port,
> +	.verify_port	= pl011_verify_port,
> +#ifdef CONFIG_CONSOLE_POLL
> +	.poll_init     = pl011_hwinit,
> +	.poll_get_char = pl011_get_poll_char,
> +	.poll_put_char = pl011_put_poll_char,
> +#endif
> +};
> +
>   static struct uart_amba_port *amba_ports[UART_NR];
>
>   #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
> @@ -2327,6 +2419,79 @@ static int pl011_resume(struct device *dev)
>
>   static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
>
> +static int sbsa_uart_probe(struct platform_device *pdev)
> +{
> +	struct uart_amba_port *uap;
> +	struct resource *r;
> +	int portnr, ret;
> +	int baudrate;
> +
> +	/*
> +	 * Check the mandatory baud rate parameter in the DT node early
> +	 * so that we can easily exit with the error.
> +	 */
> +	if (pdev->dev.of_node) {
> +		struct device_node *np = pdev->dev.of_node;
> +
> +		ret = of_property_read_u32(np, "current-speed", &baudrate);
> +		if (ret)
> +			return ret;
> +	} else {
> +		baudrate = 115200;
> +	}
> +
> +	portnr = pl011_find_free_port();
> +	if (portnr < 0)
> +		return portnr;
> +
> +	uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
> +			   GFP_KERNEL);
> +	if (uap == NULL)
> +		return -ENOMEM;
> +
> +	uap->vendor	= &vendor_sbsa;
> +	uap->fifosize	= 32;
> +	uap->port.irq	= platform_get_irq(pdev, 0);
> +	uap->port.ops	= &sbsa_uart_pops;
> +	uap->fixed_baud = baudrate;
> +
> +	snprintf(uap->type, sizeof(uap->type), "SBSA");
> +
> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> +	ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, uap);
> +
> +	return pl011_register_port(uap);
> +}
> +
> +static int sbsa_uart_remove(struct platform_device *pdev)
> +{
> +	struct uart_amba_port *uap = platform_get_drvdata(pdev);
> +
> +	uart_remove_one_port(&amba_reg, &uap->port);
> +	pl011_unregister_port(uap);
> +	return 0;
> +}
> +
> +static const struct of_device_id sbsa_uart_of_match[] = {
> +	{ .compatible = "arm,sbsa-uart", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
> +
> +static struct platform_driver arm_sbsa_uart_platform_driver = {
> +	.probe		= sbsa_uart_probe,
> +	.remove		= sbsa_uart_remove,
> +	.driver	= {
> +		.name	= "sbsa-uart",
> +		.of_match_table = of_match_ptr(sbsa_uart_of_match),
> +	},
> +};
> +
>   static struct amba_id pl011_ids[] = {
>   	{
>   		.id	= 0x00041011,
> @@ -2357,11 +2522,14 @@ static int __init pl011_init(void)
>   {
>   	printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
>
> +	if (platform_driver_register(&arm_sbsa_uart_platform_driver))
> +		pr_warn("could not register SBSA UART platform driver\n");
>   	return amba_driver_register(&pl011_driver);
>   }
>
>   static void __exit pl011_exit(void)
>   {
> +	platform_driver_unregister(&arm_sbsa_uart_platform_driver);
>   	amba_driver_unregister(&pl011_driver);
>   }

--Mark Langsdorf

  reply	other threads:[~2015-05-13 14:32 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-12 14:14 [PATCH v4 00/11] drivers: PL011: add ARM SBSA Generic UART support Andre Przywara
2015-05-12 14:14 ` [PATCH v4 01/11] drivers: PL011: avoid potential unregister_driver call Andre Przywara
2015-05-12 14:14 ` [PATCH v4 02/11] drivers: PL011: refactor pl011_startup() Andre Przywara
2015-05-12 14:14 ` [PATCH v4 03/11] drivers: PL011: refactor pl011_shutdown() Andre Przywara
2015-05-12 14:14 ` [PATCH v4 04/11] drivers: PL011: refactor pl011_set_termios() Andre Przywara
2015-05-12 14:14 ` [PATCH v4 05/11] drivers: PL011: refactor pl011_probe() Andre Przywara
2015-05-12 14:14 ` [PATCH v4 06/11] drivers: PL011: replace UART_MIS reading with _RIS & _IMSC Andre Przywara
2015-05-12 14:14 ` [PATCH v4 07/11] drivers: PL011: move cts_event workaround into separate function Andre Przywara
2015-05-12 14:14 ` [PATCH v4 08/11] drivers: PL011: allow avoiding UART enabling/disabling Andre Przywara
2015-05-12 14:14 ` [PATCH v4 09/11] drivers: PL011: allow to supply fixed option string Andre Przywara
2015-05-12 14:14 ` [PATCH v4 10/11] drivers: PL011: add support for the ARM SBSA generic UART Andre Przywara
2015-05-13 14:32   ` Mark Langsdorf [this message]
2015-05-13 15:03     ` Graeme Gregory
2015-05-21 11:13     ` Andre Przywara
2015-05-21 12:49       ` Naresh Bhat
2015-05-21 15:12       ` Mark Langsdorf
2015-05-12 14:14 ` [PATCH v4 11/11] drivers: PL011: add ACPI probing for SBSA UART Andre Przywara
2015-05-13  1:09   ` Hanjun Guo
2015-05-12 15:18 ` [PATCH v4 00/11] drivers: PL011: add ARM SBSA Generic UART support Jakub Kiciński
2015-05-12 16:42 ` Robert Richter
2015-05-13  9:17 ` Lorenzo Pieralisi
2015-05-15  3:31 ` Hanjun Guo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55536096.4020008@redhat.com \
    --to=mlangsdo@redhat.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).