[linux-yocto] [PATCH 09/11] x86: Rework Apollo Lake GPIO pinctrl non-ACPI mode driver

Yong, Jonathan jonathan.yong at intel.com
Mon Jun 27 18:28:24 PDT 2016


The previous driver depends on a PCI device that is normally
hidden by the BIOS, which means it can never bind correctly.

This driver uses the P2SB hide/unhide mechanism cooperatively
to pass the PCI BAR address to the gpio platform driver.

Original work by Tan, Jui Nee <jui.nee.tan at intel.com>
Signed-off-by: Yong, Jonathan <jonathan.yong at intel.com>
---
 MAINTAINERS                             |   5 +
 drivers/mfd/Makefile                    |   2 +-
 drivers/mfd/lpc_ich-apl.c               |  46 ++++++++
 drivers/mfd/lpc_ich-core.c              |  82 ++++++++++++-
 drivers/pinctrl/intel/Makefile          |   1 -
 drivers/pinctrl/intel/pinctrl-apl-dev.c | 201 --------------------------------
 include/linux/pinctrl/pinctrl-apl.h     |  33 +++++-
 7 files changed, 160 insertions(+), 210 deletions(-)
 create mode 100644 drivers/mfd/lpc_ich-apl.c
 delete mode 100644 drivers/pinctrl/intel/pinctrl-apl-dev.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 5e13b56..66fc822 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2300,6 +2300,11 @@ S:	Supported
 F:	drivers/pinctrl/intel/pinctrl-apl-dev.c
 F:	include/linux/pinctrl/pinctrl-apl.h
 
+BROXTON PLATFORM TESTING
+M:	Yu, Ong Hock <ong.hock.yu at intel.com>
+S:	Supported
+F:	arch/x86/platform/bxt/*
+
 BSG (block layer generic sg v4 driver)
 M:	FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
 L:	linux-scsi at vger.kernel.org
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 39e09eb..5c63c8b 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -144,7 +144,7 @@ obj-$(CONFIG_MFD_KEMPLD)	+= kempld-core.o
 obj-$(CONFIG_MFD_INTEL_QUARK_I2C_GPIO)	+= intel_quark_i2c_gpio.o
 obj-$(CONFIG_LPC_SCH)		+= lpc_sch.o
 obj-$(CONFIG_LPC_ICH)		+= lpc_ich.o
-lpc_ich-y			:= lpc_ich-core.o
+lpc_ich-y			:= lpc_ich-core.o lpc_ich-apl.o
 obj-$(CONFIG_MFD_RDC321X)	+= rdc321x-southbridge.o
 obj-$(CONFIG_MFD_JANZ_CMODIO)	+= janz-cmodio.o
 obj-$(CONFIG_MFD_JZ4740_ADC)	+= jz4740-adc.o
diff --git a/drivers/mfd/lpc_ich-apl.c b/drivers/mfd/lpc_ich-apl.c
new file mode 100644
index 0000000..7e4afff
--- /dev/null
+++ b/drivers/mfd/lpc_ich-apl.c
@@ -0,0 +1,46 @@
+/*  Copyright (c) 2015 Intel Corporation. All rights reserved.
+ *  Author: Yong, Jonathan <jonathan.yong at intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 2 as published
+ *  by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pinctrl/pinctrl-apl.h>
+/* Offset data for Apollo Lake GPIO communities */
+
+const struct apl_gpio_io_res apl_gpio_io_res_off[apl_pinctrl_max] = {
+	[apl_pinctrl_n] = {
+		.start = APL_GPIO_NORTH_OFFSET << 16,
+		.end = (APL_GPIO_NORTH_OFFSET << 16)
+			+ APL_GPIO_NORTH_END,
+		.id = "1",
+	},
+	[apl_pinctrl_nw] = {
+		.start = APL_GPIO_NORTHWEST_OFFSET << 16,
+		.end = (APL_GPIO_NORTHWEST_OFFSET << 16)
+			+ APL_GPIO_NORTHWEST_END,
+		.id = "2",
+	},
+	[apl_pinctrl_w] = {
+		.start = APL_GPIO_WEST_OFFSET << 16,
+		.end = (APL_GPIO_WEST_OFFSET << 16)
+			+ APL_GPIO_WEST_END,
+		.id = "3",
+	},
+	[apl_pinctrl_sw] = {
+		.start = APL_GPIO_SOUTHWEST_OFFSET << 16,
+		.end = (APL_GPIO_SOUTHWEST_OFFSET << 16)
+			+ APL_GPIO_SOUTHWEST_END,
+		.id = "4",
+	},
+};
diff --git a/drivers/mfd/lpc_ich-core.c b/drivers/mfd/lpc_ich-core.c
index 20a176b..15b2ac5 100644
--- a/drivers/mfd/lpc_ich-core.c
+++ b/drivers/mfd/lpc_ich-core.c
@@ -69,6 +69,7 @@
 #include <linux/mfd/lpc_ich.h>
 #include <linux/platform_data/itco_wdt.h>
 #include <linux/platform_data/sbi_apl.h>
+#include <linux/pinctrl/pinctrl-apl.h>
 
 #define ACPIBASE		0x40
 #define ACPIBASE_GPE_OFF	0x28
@@ -1148,23 +1149,96 @@ wdt_done:
 	return ret;
 }
 
+#ifdef CONFIG_PINCTRL_APL_DEVICE
+static struct resource apl_gpio_res[] = {
+	{},
+	{
+		.start = 14,
+		.end = 14,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct apl_pinctrl_port apl_pinctrl_pdata;
+
+static const struct mfd_cell apl_gpio_devices = {
+	.name = "apl_gpio",
+	.resources = apl_gpio_res,
+	.num_resources = ARRAY_SIZE(apl_gpio_res),
+	.pdata_size = sizeof(apl_pinctrl_pdata),
+	.platform_data = &apl_pinctrl_pdata,
+	.ignore_resource_conflicts = true,
+};
+#endif
+
 static int lpc_ich_misc(struct pci_dev *dev, enum lpc_chipsets e,
 	struct lpc_ich_priv *priv)
 {
+	int ret = -ENODEV;
+	unsigned int apl_p2sb = PCI_DEVFN(0x0d, 0);
+#ifdef CONFIG_PINCTRL_APL_DEVICE
+	u32 dword;
+	resource_size_t apl_gpio_base = 0;
+#endif
+
 	switch (e) {
 	case LPC_APL:
 		sbi_apl_data.name = lpc_ich_cells[LPC_P2SB_APL].name;
 		sbi_apl_data.version = 1;
 		sbi_apl_data.bus = 0;
-		sbi_apl_data.p2sb = PCI_DEVFN(0x0d, 0);
+		sbi_apl_data.p2sb = apl_p2sb;
 		sbi_apl_data.lock = &priv->lock;
-		return mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO,
+		ret = mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO,
 			 &lpc_ich_cells[LPC_P2SB_APL], 1, NULL, 0, NULL);
-	break;
+		if (ret)
+			dev_warn(&dev->dev,
+				"Failed to add Apollo Lake Sideband\n");
+
+		/* Apollo lake, has not 1, but 4 gpio controllers, handle it
+		   a bit differently */
+#ifdef CONFIG_PINCTRL_APL_DEVICE
+		/* unhide and read apl_gpio_base */
+		mutex_lock(&priv->lock);
+		pci_bus_write_config_byte(dev->bus, apl_p2sb, 0xe1, 0x0);
+
+		/* Check if device present */
+		pci_bus_read_config_dword(dev->bus, apl_p2sb, 0,
+			&dword);
+		if (dword == ~0 || dword == 0) {
+			mutex_unlock(&priv->lock);
+			dev_warn(&dev->dev,
+				"P2SB device access disabled by BIOS?\n");
+			goto out_apl_pinctrl;
+		}
+		/* Get MMIO BAR */
+		apl_gpio_res[0].flags =
+			lpc_ich_res(&apl_gpio_base, dev->bus, apl_p2sb, 0);
+
+		/* rehide p2sb */
+		pci_bus_write_config_byte(dev->bus, apl_p2sb, 0xe1, 0x1);
+		mutex_unlock(&priv->lock);
+
+		for (dword = apl_pinctrl_n; dword < apl_pinctrl_max; dword++) {
+			apl_gpio_res[0].start = apl_gpio_base
+				+ apl_gpio_io_res_off[dword].start;
+			apl_gpio_res[0].end = apl_gpio_base
+				+ apl_gpio_io_res_off[dword].end;
+			apl_pinctrl_pdata.unique_id =
+				apl_gpio_io_res_off[dword].id;
+			ret = mfd_add_devices(&dev->dev, dword,
+				&apl_gpio_devices, 1, NULL, 0, NULL);
+			if (ret)
+				dev_warn(&dev->dev,
+					"Failed to add Apollo Lake GPIO %u\n",
+					dword);
+		}
+out_apl_pinctrl:
+#endif
+	return 0;
 	default:
 	break;
 	}
-	return -ENODEV;
+	return ret;
 }
 
 static int lpc_ich_probe(struct pci_dev *dev,
diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile
index 2df696b..03bc68e 100644
--- a/drivers/pinctrl/intel/Makefile
+++ b/drivers/pinctrl/intel/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_PINCTRL_BAYTRAIL)		+= pinctrl-baytrail.o
 obj-$(CONFIG_PINCTRL_CHERRYVIEW)	+= pinctrl-cherryview.o
 obj-$(CONFIG_PINCTRL_INTEL)		+= pinctrl-intel.o
 obj-$(CONFIG_PINCTRL_BROXTON)		+= pinctrl-broxton.o
-obj-$(CONFIG_PINCTRL_APL_DEVICE)	+= pinctrl-apl-dev.o
 obj-$(CONFIG_PINCTRL_SUNRISEPOINT)	+= pinctrl-sunrisepoint.o
diff --git a/drivers/pinctrl/intel/pinctrl-apl-dev.c b/drivers/pinctrl/intel/pinctrl-apl-dev.c
deleted file mode 100644
index 226ec6a..0000000
--- a/drivers/pinctrl/intel/pinctrl-apl-dev.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * pinctrl-apl-dev.c: APL pinctrl GPIO Platform Device
- *
- * (C) Copyright 2015 Intel Corporation
- * Author: Kean Ho, Chew (kean.ho.chew at intel.com)
- * Modified: Tan, Jui Nee (jui.nee.tan at intel.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/pci.h>
-#include <linux/pinctrl/pinctrl-apl.h>
-
-/* PCI Memory Base Access */
-#define PCI_DEVICE_ID_INTEL_APL_PCU	0x5A92
-#define NO_REGISTER_SETTINGS	(BIT(0) | BIT(1) | BIT(2))
-
-/* Offsets */
-#define NORTH_OFFSET		0xC5
-#define NORTHWEST_OFFSET		0xC4
-#define WEST_OFFSET		0xC7
-#define SOUTHWEST_OFFSET		0xC0
-
-#define NORTH_END		(90 * 0x8)
-#define NORTHWEST_END		(77 * 0x8)
-#define WEST_END		(47 * 0x8)
-#define SOUTHWEST_END		(43 * 0x8)
-
-static struct apl_pinctrl_port apl_gpio_north_platform_data = {
-	.unique_id = "1",
-};
-
-static struct resource apl_gpio_north_resources[] = {
-	{
-		.start	= 0x0,
-		.end	= 0x0,
-		.flags	= IORESOURCE_MEM,
-		.name	= "io-memory",
-	},
-	{
-		.start	= 14,
-		.end	= 14,
-		.flags	= IORESOURCE_IRQ,
-		.name	= "irq",
-	}
-};
-
-static struct apl_pinctrl_port apl_gpio_northwest_platform_data = {
-	.unique_id = "2",
-};
-
-static struct resource apl_gpio_northwest_resources[] = {
-	{
-		.start	= 0x0,
-		.end	= 0x0,
-		.flags	= IORESOURCE_MEM,
-		.name	= "io-memory",
-	},
-	{
-		.start	= 14,
-		.end	= 14,
-		.flags	= IORESOURCE_IRQ,
-		.name	= "irq",
-	}
-};
-
-static struct apl_pinctrl_port apl_gpio_west_platform_data = {
-	.unique_id = "3",
-};
-
-static struct resource apl_gpio_west_resources[] = {
-	{
-		.start	= 0x0,
-		.end	= 0x0,
-		.flags	= IORESOURCE_MEM,
-		.name	= "io-memory",
-	},
-	{
-		.start	= 14,
-		.end	= 14,
-		.flags	= IORESOURCE_IRQ,
-		.name	= "irq",
-	}
-};
-
-static struct apl_pinctrl_port apl_gpio_southwest_platform_data = {
-	.unique_id = "4",
-};
-
-static struct resource apl_gpio_southwest_resources[] = {
-	{
-		.start	= 0x0,
-		.end	= 0x0,
-		.flags	= IORESOURCE_MEM,
-		.name	= "io-memory",
-	},
-	{
-		.start	= 14,
-		.end	= 14,
-		.flags	= IORESOURCE_IRQ,
-		.name	= "irq",
-	}
-};
-
-static struct platform_device apl_gpio_north_device = {
-	.name			= "apl_gpio",
-	.id			= 0,
-	.num_resources		= ARRAY_SIZE(apl_gpio_north_resources),
-	.resource		= apl_gpio_north_resources,
-	.dev			= {
-		.platform_data	= &apl_gpio_north_platform_data,
-	}
-};
-
-static struct platform_device apl_gpio_northwest_device = {
-	.name			= "apl_gpio",
-	.id			= 1,
-	.num_resources		= ARRAY_SIZE(apl_gpio_northwest_resources),
-	.resource		= apl_gpio_northwest_resources,
-	.dev			= {
-		.platform_data	= &apl_gpio_northwest_platform_data,
-	}
-};
-
-static struct platform_device apl_gpio_west_device = {
-	.name			= "apl_gpio",
-	.id			= 2,
-	.num_resources		= ARRAY_SIZE(apl_gpio_west_resources),
-	.resource		= apl_gpio_west_resources,
-	.dev			= {
-		.platform_data	= &apl_gpio_west_platform_data,
-	}
-};
-
-static struct platform_device apl_gpio_southwest_device = {
-	.name			= "apl_gpio",
-	.id			= 3,
-	.num_resources		= ARRAY_SIZE(apl_gpio_southwest_resources),
-	.resource		= apl_gpio_southwest_resources,
-	.dev			= {
-		.platform_data	= &apl_gpio_southwest_platform_data,
-	}
-};
-
-static struct platform_device *devices[] __initdata = {
-	&apl_gpio_north_device,
-	&apl_gpio_northwest_device,
-	&apl_gpio_west_device,
-	&apl_gpio_southwest_device,
-};
-
-static int __init get_pci_memory_init(void)
-{
-	u32 io_base_add;
-	struct pci_dev *pci_dev;
-
-	pci_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_APL_PCU,
-				NULL);
-
-	if (pci_dev == NULL)
-		return -EFAULT;
-
-	pci_read_config_dword(pci_dev, 0x10, &io_base_add);
-	io_base_add &= ~NO_REGISTER_SETTINGS;
-	apl_gpio_north_resources[0].start =
-		io_base_add + (NORTH_OFFSET << 16);
-	apl_gpio_north_resources[0].end =
-		io_base_add + (NORTH_OFFSET << 16) + NORTH_END;
-	apl_gpio_northwest_resources[0].start =
-		io_base_add + (NORTHWEST_OFFSET << 16);
-	apl_gpio_northwest_resources[0].end =
-		io_base_add + (NORTHWEST_OFFSET << 16) + NORTHWEST_END;
-	apl_gpio_west_resources[0].start =
-		io_base_add + (WEST_OFFSET << 16);
-	apl_gpio_west_resources[0].end =
-		io_base_add + (WEST_OFFSET << 16) + WEST_END;
-	apl_gpio_southwest_resources[0].start =
-		io_base_add + (SOUTHWEST_OFFSET << 16);
-	apl_gpio_southwest_resources[0].end =
-		io_base_add + (SOUTHWEST_OFFSET << 16) + SOUTHWEST_END;
-	return 0;
-};
-rootfs_initcall(get_pci_memory_init);
-
-static int __init apl_gpio_device_init(void)
-{
-	return platform_add_devices(devices, ARRAY_SIZE(devices));
-};
-device_initcall(apl_gpio_device_init);
diff --git a/include/linux/pinctrl/pinctrl-apl.h b/include/linux/pinctrl/pinctrl-apl.h
index d414255..3bfec8a 100644
--- a/include/linux/pinctrl/pinctrl-apl.h
+++ b/include/linux/pinctrl/pinctrl-apl.h
@@ -10,9 +10,36 @@
  * as published by the Free Software Foundation.
  */
 
-#ifdef CONFIG_PINCTRL_APL_DEVICE
+#include <linux/types.h>
+
 struct apl_pinctrl_port {
-	char *unique_id;
+	const char *unique_id;
+};
+
+enum apl_pinctrl_resource {
+	apl_pinctrl_n = 0,
+	apl_pinctrl_nw,
+	apl_pinctrl_w,
+	apl_pinctrl_sw,
+	apl_pinctrl_max,
+};
+
+/* Offsets */
+#define APL_GPIO_NORTH_OFFSET		0xC5
+#define APL_GPIO_NORTHWEST_OFFSET	0xC4
+#define APL_GPIO_WEST_OFFSET		0xC7
+#define APL_GPIO_SOUTHWEST_OFFSET	0xC0
+
+#define APL_GPIO_NORTH_END		(90 * 0x8)
+#define APL_GPIO_NORTHWEST_END		(77 * 0x8)
+#define APL_GPIO_WEST_END		(47 * 0x8)
+#define APL_GPIO_SOUTHWEST_END		(43 * 0x8)
+
+struct apl_gpio_io_res {
+	resource_size_t start;
+	resource_size_t end;
+	const char id[2];
 };
-#endif
+
+extern const struct apl_gpio_io_res apl_gpio_io_res_off[apl_pinctrl_max];
 
-- 
2.7.3



More information about the linux-yocto mailing list