[PATCH 6/6] serial: add amba-pl011-pci

Alessandro Rubini rubini at gnudd.com
Fri May 25 11:48:57 EDT 2012


This is a simple PCI driver that registers an amba device
in its probe function. It successfully drives the 4 serial
ports of the sta2x11 I/O Hub.

Signed-off-by: Alessandro Rubini <rubini at gnudd.com>
Acked-by: Giancarlo Asnaghi <giancarlo.asnaghi at st.com>
Cc: Russell King <linux at arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
 drivers/tty/serial/Kconfig          |   10 +++-
 drivers/tty/serial/Makefile         |    1 +
 drivers/tty/serial/amba-pl011-pci.c |  101 +++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+), 1 deletions(-)
 create mode 100644 drivers/tty/serial/amba-pl011-pci.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 070b442..e5e5ef6 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -39,14 +39,22 @@ config SERIAL_AMBA_PL010_CONSOLE
 config SERIAL_AMBA_PL011
 	tristate "ARM AMBA PL011 serial port support"
 	depends on ARM_AMBA
+	default y if STA2X11
 	select SERIAL_CORE
 	help
 	  This selects the ARM(R) AMBA(R) PrimeCell PL011 UART.  If you have
 	  an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
-	  here.
+	  here. This is also needed to use the sta2x11 I/O Hub for Atom.
 
 	  If unsure, say N.
 
+config SERIAL_AMBA_PL011_PCI
+	tristate "ARM AMBA PL011 behind a PCI-to-AMBA bridge"
+	depends on SERIAL_AMBA_PL011 && PCI
+	default y if STA2X11
+	help
+	  Say Y if your AMBA bus is behind a PCI bridge (e.g.: sta2x11)
+
 config SERIAL_AMBA_PL011_CONSOLE
 	bool "Support for console on AMBA serial port"
 	depends on SERIAL_AMBA_PL011=y
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 7257c5d..b8cd14b 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250/
 
 obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
 obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
+obj-$(CONFIG_SERIAL_AMBA_PL011_PCI) += amba-pl011-pci.o
 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
 obj-$(CONFIG_SERIAL_PXA) += pxa.o
 obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
diff --git a/drivers/tty/serial/amba-pl011-pci.c b/drivers/tty/serial/amba-pl011-pci.c
new file mode 100644
index 0000000..b3aa0f1
--- /dev/null
+++ b/drivers/tty/serial/amba-pl011-pci.c
@@ -0,0 +1,101 @@
+/*
+ * Support for AMBA pl011 uart behind a PCI bridge
+ * Copyright 2012 ST Microelectronics (Alessandro Rubini)
+ * GNU GPL version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/amba/bus.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/sizes.h>
+#include <linux/amba/serial.h>
+
+/* This is a template, copied every time a new pci device appears */
+static AMBA_APB_DEVICE(pl011_pci_template, "pl011-pci", 0,
+		       0 /* base */, {0} /* irqs */, NULL /* data */);
+
+static int __devinit pl011_pci_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *id)
+{
+	struct amba_device *adev;
+	struct amba_pl011_data *data;
+	int ret;
+
+	/* Simply build an amba device and register it */
+	adev = kmemdup(&pl011_pci_template_device,
+			 sizeof(pl011_pci_template_device), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!adev || !data) {
+		kfree(adev);
+		kfree(data);
+		return -ENOMEM;
+	}
+	pci_set_master(pdev);
+	pci_enable_msi(pdev);
+	adev->irq[0] = pdev->irq;
+	if (pdev->vendor == PCI_VENDOR_ID_STMICRO) {
+		/* Under sta2x11, DMA is there but limited to 512M */
+		adev->dma_mask = SZ_512M - 1;
+		adev->dev.coherent_dma_mask = SZ_512M - 1;
+	}
+
+	/* Link the pci to amba and the amba to pci */
+	adev->dev.platform_data = data;
+	//data->pdev = pdev;
+	pci_set_drvdata(pdev, adev);
+
+	/* Create a new resource, to be registered as child of the PCI one */
+	adev->res.flags = pdev->resource[0].flags;
+	adev->res.start = pdev->resource[0].start;
+	adev->res.end = adev->res.start + SZ_4K - 1;
+
+	/* change name */
+	adev->dev.init_name = kasprintf(GFP_ATOMIC, "pl011-pci-%02x:%04x",
+				       pdev->bus->number, pdev->devfn);
+
+	printk(KERN_INFO "%s %i\n", __func__, __LINE__);
+	if ((ret = amba_device_register(adev, &pdev->resource[0])) < 0) {
+		kfree(adev);
+		return ret;
+	}
+	return 0;
+};
+
+static void __devexit pl011_pci_remove(struct pci_dev *pdev)
+{
+	struct amba_device *adev = pci_get_drvdata(pdev);
+	amba_device_unregister(adev);
+	kfree(adev->dev.platform_data);
+	kfree(adev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pl011_pci_table) = {
+	{PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_UART_HWFC)},
+	{PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_UART_NO_HWFC)},
+	{0,}
+};
+
+static struct pci_driver pl011_pci_driver = {
+	.name		= "pl011-pci",
+	.id_table	= pl011_pci_table,
+	.probe		= pl011_pci_probe,
+	.remove		= __devexit_p(pl011_pci_remove),
+};
+
+static int __init pl011_pci_init(void)
+{
+	return pci_register_driver(&pl011_pci_driver);
+}
+
+static void __exit pl011_pci_exit(void)
+{
+	pci_unregister_driver(&pl011_pci_driver);
+}
+
+module_init(pl011_pci_init);
+module_exit(pl011_pci_exit);
+
-- 
1.7.7.2



More information about the linux-arm-kernel mailing list