linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller
@ 2018-10-27 15:09 Elie Morisse
  2018-10-30 20:56 ` Bjorn Helgaas
  0 siblings, 1 reply; 6+ messages in thread
From: Elie Morisse @ 2018-10-27 15:09 UTC (permalink / raw)
  To: linux-i2c, Wolfram Sang, helgaas, Nehal-bakulchandra.Shah,
	Shyam-sundar.S-k, sandeep.singh, linux-kernel

This contains two drivers:
 * i2c-amd-plat-mp2: platform driver managing an i2c adapter (one of
the two busses of the MP2) and routing any i2c read/write command to
the PCI driver.
 * i2c-amd-pci-mp2: PCI driver communicating through the C2P/P2C
mailbox registers, or through DMA for more than 32 bytes transfers.

This is major rework of the patch submitted by Nehal-bakulchandra Shah
from AMD (https://patchwork.kernel.org/patch/10597369/).

Most of the event handling of v2/v3 was rewritten since it couldn't work
if more than one bus was enabled, and contains many more fixes listed
in the patch changelog.

With those changes both the touchpad and the touchscreen of the
Ryzen-based Lenovo Yoga 530 which lie in separate busses work beautifully.

Signed-off-by: Elie Morisse <syniurge@gmail.com>
---
Changes since v1:(https://www.spinics.net/lists/linux-i2c/msg34650.html)
-> Add fix for IOMMU
-> Add depedency of ACPI
-> Add locks to avoid the crash

Changes since v2:(https://patchwork.ozlabs.org/patch/961270/)

-> fix for review comments
-> fix for more than 32 bytes write issue

Changes since v3 (https://patchwork.kernel.org/patch/10597369/) by Elie M.:

-> support more than one bus/adapter
-> support more than one slave per bus
-> use the bus speed specified by the slaves declared in the DSDT instead of
   assuming speed == 400kbits/s
-> instead of kzalloc'ing a buffer for every less than 32 bytes reads, simply
   use i2c_msg.buf
-> fix buffer overreads/overflows when (<=32 bytes) message lengths aren't a
   multiple of 4 by using memcpy_fromio and memcpy_toio
-> use streaming DMA mappings instead of allocating a coherent DMA buffer for
   every >32 bytes read/write
-> properly check for timeouts during i2c_amd_xfer and increase it from 50
   jiffies to 250 msecs (which is more in line with other drivers)
-> complete amd_i2c_dev.msg even if the device doesn't return a xxx_success
   event, instead of stalling i2c_amd_xfer
-> removed the spinlock and mdelay during i2c_amd_pci_configure, I didn't see
   the point since it's already waiting for a i2c_busenable_complete event
-> add an adapter-specific mutex lock for i2c_amd_xfer, since we don't want
   parallel calls writing to AMD_C2P_MSG0 (or AMD_C2P_MSG1)
-> add a global mutex lock for registers AMD_C2P_MSG2 to AMD_C2P_MSG9,  which
   are shared across the two busses/adapters
-> add MODULE_DEVICE_TABLE to automatically load i2c-amd-platdrv if the DSDT
   enumerates devices with the "AMDI0011" HID
-> set maximum length of reads/writes to 4095 (event's length field is 12 bits)
-> basic PM support
-> style corrections to match the kernel code style, and tried to reduce code
   duplication whenever possible

Changes since v4 (https://marc.info/?l=linux-kernel&m=154031133019835) by Elie M.:

-> fix missing typecast warning
-> removed the duplicated entry in Kconfig

Changes since v5 by Elie M.:

-> move DMA mapping from the platform driver to the PCI driver
-> attempt to find the platform device's PCI parent through the _DEP ACPI method
   (if not found take the first MP2 device registred in the i2c-amd-pci-mp2
   driver, like before)
-> do not assume anymore that the PCI device is owned by the i2c-amd-pci-mp2
   driver
-> address other review comments by Bjorn Helgaas (meant for v3)

Changes since v6 by Elie M.:

-> remove unnecessary memcpy from the DMA buffer during i2c_amd_read_completion

 MAINTAINERS                           |   6 +
 drivers/i2c/busses/Kconfig            |  15 +
 drivers/i2c/busses/Makefile           |   2 +
 drivers/i2c/busses/i2c-amd-pci-mp2.c  | 706 ++++++++++++++++++++++++++
 drivers/i2c/busses/i2c-amd-pci-mp2.h  | 224 ++++++++
 drivers/i2c/busses/i2c-amd-plat-mp2.c | 373 ++++++++++++++
 6 files changed, 1326 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-amd-pci-mp2.c
 create mode 100644 drivers/i2c/busses/i2c-amd-pci-mp2.h
 create mode 100644 drivers/i2c/busses/i2c-amd-plat-mp2.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6ac000cc006d..8ff2bddc1ac2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -791,6 +791,12 @@ F:	drivers/gpu/drm/amd/include/vi_structs.h
 F:	drivers/gpu/drm/amd/include/v9_structs.h
 F:	include/uapi/linux/kfd_ioctl.h
 
+AMD MP2 I2C DRIVER
+M:	Elie Morisse <syniurge@gmail.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+F:	drivers/i2c/busses/i2c-amd-*-mp2*
+
 AMD POWERPLAY
 M:	Rex Zhu <rex.zhu@amd.com>
 M:	Evan Quan <evan.quan@amd.com>
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae50e66..e20f2d1ce381 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -77,6 +77,21 @@ config I2C_AMD8111
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-amd8111.
 
+config I2C_AMD_MP2_PCI
+	tristate
+	depends on PCI
+
+config I2C_AMD_MP2_PLATFORM
+	tristate "AMD MP2 Platform"
+	select I2C_AMD_MP2_PCI
+	depends on ACPI
+	help
+	  If you say yes to this option, support will be included for the AMD MP2
+	  PCI I2C adapter.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-amd-plat-mp2.
+
 config I2C_HIX5HD2
 	tristate "Hix5hd2 high-speed I2C driver"
 	depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af82b1c..16ef646d7ef5 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -32,6 +32,8 @@ obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
 
 # Embedded system I2C/SMBus host controller drivers
 obj-$(CONFIG_I2C_ALTERA)	+= i2c-altera.o
+obj-$(CONFIG_I2C_AMD_MP2_PCI)	+= i2c-amd-pci-mp2.o
+obj-$(CONFIG_I2C_AMD_MP2_PLATFORM)	+= i2c-amd-plat-mp2.o
 obj-$(CONFIG_I2C_ASPEED)	+= i2c-aspeed.o
 obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.c b/drivers/i2c/busses/i2c-amd-pci-mp2.c
new file mode 100644
index 000000000000..eb54825f3f69
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd-pci-mp2.c
@@ -0,0 +1,706 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * AMD PCIe MP2 Communication Driver
+ *
+ * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ *          Elie Morisse <syniurge@gmail.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "i2c-amd-pci-mp2.h"
+
+#define DRIVER_NAME	"pcie_mp2_amd"
+#define DRIVER_DESC	"AMD(R) PCI-E MP2 Communication Driver"
+#define DRIVER_VER	"1.0"
+
+static const struct file_operations amd_mp2_debugfs_info;
+static struct dentry *debugfs_dir;
+
+#define write64 _write64
+static inline void _write64(u64 val, void __iomem *mmio)
+{
+	writel(val, mmio);
+	writel(val >> 32, mmio + sizeof(u32));
+}
+
+#define read64 _read64
+static inline u64 _read64(void __iomem *mmio)
+{
+	u64 low, high;
+
+	low = readl(mmio);
+	high = readl(mmio + sizeof(u32));
+	return low | (high << 32);
+}
+
+static int amd_mp2_cmd(struct amd_mp2_dev *privdata,
+		       union i2c_cmd_base i2c_cmd_base)
+{
+	void __iomem *reg;
+
+	if (i2c_cmd_base.s.bus_id > 1) {
+		dev_err(ndev_dev(privdata), "%s Invalid bus id\n", __func__);
+		return -EINVAL;
+	}
+
+	reg = privdata->mmio + ((i2c_cmd_base.s.bus_id == 1) ?
+				AMD_C2P_MSG1 : AMD_C2P_MSG0);
+	writel(i2c_cmd_base.ul, reg);
+
+	return 0;
+}
+
+int amd_mp2_connect(struct amd_i2c_common *i2c_common, bool enable)
+{
+	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
+	union i2c_cmd_base i2c_cmd_base;
+
+	dev_dbg(ndev_dev(privdata), "%s id: %d\n", __func__,
+		i2c_common->bus_id);
+
+	i2c_common->reqcmd = enable ? i2c_enable : i2c_disable;
+
+	i2c_cmd_base.ul = 0;
+	i2c_cmd_base.s.i2c_cmd = i2c_common->reqcmd;
+	i2c_cmd_base.s.bus_id = i2c_common->bus_id;
+	i2c_cmd_base.s.i2c_speed = i2c_common->i2c_speed;
+
+	return amd_mp2_cmd(privdata, i2c_cmd_base);
+}
+EXPORT_SYMBOL_GPL(amd_mp2_connect);
+
+static void amd_mp2_cmd_rw_fill(struct amd_i2c_common *i2c_common,
+				union i2c_cmd_base *i2c_cmd_base,
+				enum i2c_cmd reqcmd)
+{
+	i2c_common->reqcmd = reqcmd;
+
+	i2c_cmd_base->s.i2c_cmd = reqcmd;
+	i2c_cmd_base->s.bus_id = i2c_common->bus_id;
+	i2c_cmd_base->s.i2c_speed = i2c_common->i2c_speed;
+	i2c_cmd_base->s.slave_addr = i2c_common->rw_cfg.slave_addr;
+	i2c_cmd_base->s.length = i2c_common->rw_cfg.length;
+}
+
+static int amd_mp2_dma_map(struct amd_mp2_dev *privdata,
+			   struct amd_i2c_common *i2c_common,
+			   bool is_write)
+{
+	enum dma_data_direction dma_direction = is_write ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+	i2c_common->rw_cfg.dma_addr = dma_map_single(&privdata->pci_dev->dev,
+						     i2c_common->rw_cfg.buf,
+						     i2c_common->rw_cfg.length,
+						     dma_direction);
+	i2c_common->rw_cfg.dma_direction = dma_direction;
+
+	if (dma_mapping_error(&privdata->pci_dev->dev,
+			      i2c_common->rw_cfg.dma_addr)) {
+		dev_err(ndev_dev(privdata),
+			"Error while mapping dma buffer %p\n",
+			i2c_common->rw_cfg.buf);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void amd_mp2_dma_unmap(struct amd_mp2_dev *privdata,
+			      struct amd_i2c_common *i2c_common)
+{
+	dma_unmap_single(&privdata->pci_dev->dev,
+			 i2c_common->rw_cfg.dma_addr,
+			 i2c_common->rw_cfg.length,
+			 i2c_common->rw_cfg.dma_direction);
+}
+
+int amd_mp2_read(struct amd_i2c_common *i2c_common)
+{
+	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
+	union i2c_cmd_base i2c_cmd_base;
+
+	dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__,
+		i2c_common->rw_cfg.slave_addr, i2c_common->bus_id);
+
+	amd_mp2_cmd_rw_fill(i2c_common, &i2c_cmd_base, i2c_read);
+
+	/* there is only one data mailbox for two i2c adapters */
+	mutex_lock(&privdata->c2p_lock);
+
+	if (!i2c_common->rw_cfg.buf) {
+		dev_err(ndev_dev(privdata), "%s no mem for buf received\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	if (i2c_common->rw_cfg.length <= 32) {
+		i2c_cmd_base.s.mem_type = use_c2pmsg;
+	} else {
+		i2c_cmd_base.s.mem_type = use_dram;
+		if (amd_mp2_dma_map(privdata, i2c_common, false))
+			return -EIO;
+		write64((u64)i2c_common->rw_cfg.dma_addr,
+			privdata->mmio + AMD_C2P_MSG2);
+	}
+
+	return amd_mp2_cmd(privdata, i2c_cmd_base);
+}
+EXPORT_SYMBOL_GPL(amd_mp2_read);
+
+int amd_mp2_write(struct amd_i2c_common *i2c_common)
+{
+	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
+	union i2c_cmd_base i2c_cmd_base;
+
+	dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__,
+		i2c_common->rw_cfg.slave_addr, i2c_common->bus_id);
+
+	amd_mp2_cmd_rw_fill(i2c_common, &i2c_cmd_base, i2c_write);
+
+	/* there is only one data mailbox for two i2c adapters */
+	mutex_lock(&privdata->c2p_lock);
+
+	if (i2c_common->rw_cfg.length <= 32) {
+		i2c_cmd_base.s.mem_type = use_c2pmsg;
+		memcpy_toio(privdata->mmio + AMD_C2P_MSG2,
+			    i2c_common->rw_cfg.buf,
+			    i2c_common->rw_cfg.length);
+	} else {
+		i2c_cmd_base.s.mem_type = use_dram;
+		if (amd_mp2_dma_map(privdata, i2c_common, true))
+			return -EIO;
+		write64((u64)i2c_common->rw_cfg.dma_addr,
+			privdata->mmio + AMD_C2P_MSG2);
+	}
+
+	return amd_mp2_cmd(privdata, i2c_cmd_base);
+}
+EXPORT_SYMBOL_GPL(amd_mp2_write);
+
+static void amd_mp2_pci_do_work(struct work_struct *work)
+{
+	struct amd_i2c_common *i2c_common = work_amd_i2c_common(work);
+	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
+	int sts = i2c_common->eventval.r.status;
+	int res = i2c_common->eventval.r.response;
+	int len = i2c_common->eventval.r.length;
+	u32 slave_addr = i2c_common->eventval.r.slave_addr;
+
+	if (len != i2c_common->rw_cfg.length)
+		dev_err(ndev_dev(privdata),
+			"length %d in event doesn't match buffer length %d!\n",
+			len, i2c_common->rw_cfg.length);
+	if (slave_addr != i2c_common->rw_cfg.slave_addr)
+		dev_err(ndev_dev(privdata),
+			"unexpected slave address %x (expected: %x)!\n",
+			slave_addr, i2c_common->rw_cfg.slave_addr);
+
+	if (res != command_success) {
+		if (res == command_failed)
+			dev_err(ndev_dev(privdata), "i2c command failed!\n");
+		else
+			dev_err(ndev_dev(privdata), "invalid response to i2c command!\n");
+		return;
+	}
+
+	switch (i2c_common->reqcmd) {
+	case i2c_read:
+		if (sts == i2c_readcomplete_event) {
+			if (len <= 32)
+				memcpy_fromio(i2c_common->rw_cfg.buf,
+					      privdata->mmio + AMD_C2P_MSG2,
+					      i2c_common->rw_cfg.length);
+		} else if (sts == i2c_readfail_event) {
+			dev_err(ndev_dev(privdata), "i2c read failed!\n");
+		} else {
+			dev_err(ndev_dev(privdata), "invalid i2c status after read!\n");
+		}
+
+		i2c_common->ops->read_complete(&i2c_common->eventval);
+		break;
+	case i2c_write:
+		if (sts == i2c_writefail_event)
+			dev_err(ndev_dev(privdata), "i2c write failed!\n");
+		else if (sts != i2c_writecomplete_event)
+			dev_err(ndev_dev(privdata), "invalid i2c status after write!\n");
+
+		i2c_common->ops->write_complete(&i2c_common->eventval);
+		break;
+	case i2c_enable:
+		if (sts == i2c_busdisable_failed)
+			dev_err(ndev_dev(privdata), "i2c bus enable failed!\n");
+		else if (sts != i2c_busenable_complete)
+			dev_err(ndev_dev(privdata), "invalid i2c status after bus enable!\n");
+
+		i2c_common->ops->connect_complete(&i2c_common->eventval);
+		break;
+	default:
+		break;
+	}
+
+	if ((i2c_common->reqcmd == i2c_read ||
+	     i2c_common->reqcmd == i2c_write) &&
+	    i2c_common->rw_cfg.length > 32)
+		amd_mp2_dma_unmap(privdata, i2c_common);
+}
+
+static void amd_mp2_pci_work(struct work_struct *work)
+{
+	struct amd_i2c_common *i2c_common = work_amd_i2c_common(work);
+	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
+	enum i2c_cmd cmd = i2c_common->reqcmd;
+
+	amd_mp2_pci_do_work(work);
+
+	i2c_common->reqcmd = i2c_none;
+
+	if (cmd == i2c_read || cmd == i2c_write)
+		mutex_unlock(&privdata->c2p_lock);
+}
+
+static irqreturn_t amd_mp2_irq_isr(int irq, void *dev)
+{
+	struct amd_mp2_dev *privdata = dev;
+	struct amd_i2c_common *i2c_common;
+	u32 val;
+	unsigned int bus_id;
+	void __iomem *reg;
+	unsigned long flags;
+	enum irqreturn ret = IRQ_NONE;
+
+	raw_spin_lock_irqsave(&privdata->lock, flags);
+
+	for (bus_id = 0; bus_id < 2; bus_id++) {
+		reg = privdata->mmio + ((bus_id == 0) ?
+					AMD_P2C_MSG1 : AMD_P2C_MSG2);
+		val = readl(reg);
+		if (val != 0) {
+			i2c_common = privdata->plat_common[bus_id];
+			if (!i2c_common)
+				continue;
+			i2c_common->eventval.ul = val;
+
+			writel(0, reg);
+			writel(0, privdata->mmio + AMD_P2C_MSG_INTEN);
+
+			if (i2c_common->reqcmd != i2c_none)
+				schedule_delayed_work(&i2c_common->work, 0);
+
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	raw_spin_unlock_irqrestore(&privdata->lock, flags);
+	return ret;
+}
+
+int amd_i2c_register_cb(struct amd_mp2_dev *privdata,
+			struct amd_i2c_common *i2c_common)
+{
+	if (i2c_common->bus_id > 1)
+		return -EINVAL;
+	privdata->plat_common[i2c_common->bus_id] = i2c_common;
+
+	INIT_DELAYED_WORK(&i2c_common->work, amd_mp2_pci_work);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(amd_i2c_register_cb);
+
+int amd_i2c_unregister_cb(struct amd_mp2_dev *privdata,
+			  struct amd_i2c_common *i2c_common)
+{
+	cancel_delayed_work_sync(&i2c_common->work);
+	privdata->plat_common[i2c_common->bus_id] = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(amd_i2c_unregister_cb);
+
+static ssize_t amd_mp2_debugfs_read(struct file *filp, char __user *ubuf,
+				    size_t count, loff_t *offp)
+{
+	struct amd_mp2_dev *privdata;
+	void __iomem *mmio;
+	u8 *buf;
+	size_t buf_size;
+	ssize_t ret, off;
+	u32 v32;
+
+	privdata = filp->private_data;
+	mmio = privdata->mmio;
+	buf_size = min_t(size_t, count, 0x800);
+	buf = kmalloc(buf_size, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	off = 0;
+	off += scnprintf(buf + off, buf_size - off,
+			"Mp2 Device Information:\n");
+
+	off += scnprintf(buf + off, buf_size - off,
+			"========================\n");
+	off += scnprintf(buf + off, buf_size - off,
+			"\tMP2 C2P Message Register Dump:\n\n");
+	v32 = readl(privdata->mmio + AMD_C2P_MSG0);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG0 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG1);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG1 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG2);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG2 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG3);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG3 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG4);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG4 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG5);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG5 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG6);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG6 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG7);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG7 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG8);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG8 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_C2P_MSG9);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_C2P_MSG9 -\t\t\t%#06x\n", v32);
+
+	off += scnprintf(buf + off, buf_size - off,
+			"\n\tMP2 P2C Message Register Dump:\n\n");
+
+	v32 = readl(privdata->mmio + AMD_P2C_MSG1);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_P2C_MSG1 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_P2C_MSG2);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_P2C_MSG2 -\t\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_P2C_MSG_INTEN);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_P2C_MSG_INTEN -\t\t%#06x\n", v32);
+
+	v32 = readl(privdata->mmio + AMD_P2C_MSG_INTSTS);
+	off += scnprintf(buf + off, buf_size - off,
+			"AMD_P2C_MSG_INTSTS -\t\t%#06x\n", v32);
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
+	kfree(buf);
+	return ret;
+}
+
+static void amd_mp2_init_debugfs(struct amd_mp2_dev *privdata)
+{
+	if (!debugfs_dir) {
+		privdata->debugfs_dir = NULL;
+		privdata->debugfs_info = NULL;
+		return;
+	}
+
+	privdata->debugfs_dir = debugfs_create_dir(ndev_name(privdata),
+						   debugfs_dir);
+	if (!privdata->debugfs_dir) {
+		privdata->debugfs_info = NULL;
+	} else {
+		privdata->debugfs_info = debugfs_create_file
+			("info", 0400, privdata->debugfs_dir,
+			 privdata, &amd_mp2_debugfs_info);
+	}
+}
+
+static void amd_mp2_deinit_debugfs(struct amd_mp2_dev *privdata)
+{
+	debugfs_remove_recursive(privdata->debugfs_dir);
+}
+
+static void amd_mp2_clear_reg(struct amd_mp2_dev *privdata)
+{
+	int reg;
+
+	for (reg = AMD_C2P_MSG0; reg <= AMD_C2P_MSG9; reg += 4)
+		writel(0, privdata->mmio + reg);
+
+	for (reg = AMD_P2C_MSG0; reg <= AMD_P2C_MSG2; reg += 4)
+		writel(0, privdata->mmio + reg);
+}
+
+static int amd_mp2_pci_init(struct amd_mp2_dev *privdata,
+			    struct pci_dev *pci_dev)
+{
+	int rc;
+	resource_size_t size, base;
+
+	pci_set_drvdata(pci_dev, privdata);
+
+	rc = pci_enable_device(pci_dev);
+	if (rc)
+		goto err_pci_enable;
+
+	rc = pci_request_regions(pci_dev, DRIVER_NAME);
+	if (rc)
+		goto err_pci_regions;
+
+	pci_set_master(pci_dev);
+
+	rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err_dma_mask;
+		dev_warn(ndev_dev(privdata), "Cannot DMA highmem\n");
+	}
+
+	rc = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err_dma_mask;
+		dev_warn(ndev_dev(privdata), "Cannot DMA consistent highmem\n");
+	}
+
+	base = pci_resource_start(pci_dev, 2);
+	size = pci_resource_len(pci_dev, 2);
+	dev_dbg(ndev_dev(privdata), "Base addr:%zx size:%zx\n",
+		(size_t)base, (size_t)size);
+
+	mutex_init(&privdata->c2p_lock);
+	privdata->mmio = ioremap(base, size);
+	if (!privdata->mmio) {
+		rc = -EIO;
+		goto err_dma_mask;
+	}
+
+	/* Try to set up intx irq */
+	raw_spin_lock_init(&privdata->lock);
+	pci_intx(pci_dev, 1);
+	rc = request_irq(pci_dev->irq, amd_mp2_irq_isr, IRQF_SHARED,
+			 "mp2_irq_isr", privdata);
+	if (rc)
+		goto err_intx_request;
+
+	return 0;
+
+err_intx_request:
+	return rc;
+err_dma_mask:
+	pci_clear_master(pci_dev);
+	pci_release_regions(pci_dev);
+err_pci_regions:
+	pci_disable_device(pci_dev);
+err_pci_enable:
+	pci_set_drvdata(pci_dev, NULL);
+	return rc;
+}
+
+static void amd_mp2_pci_deinit(struct amd_mp2_dev *privdata)
+{
+	struct pci_dev *pci_dev = ndev_pdev(privdata);
+
+	pci_iounmap(pci_dev, privdata->mmio);
+
+	pci_clear_master(pci_dev);
+	pci_release_regions(pci_dev);
+	pci_disable_device(pci_dev);
+	pci_set_drvdata(pci_dev, NULL);
+}
+
+static int amd_mp2_pci_probe(struct pci_dev *pci_dev,
+			     const struct pci_device_id *id)
+{
+	struct amd_mp2_dev *privdata;
+	int rc;
+	static bool first_probe = true;
+
+	if (first_probe) {
+		pr_info("%s: %s Version: %s\n", DRIVER_NAME,
+			DRIVER_DESC, DRIVER_VER);
+		first_probe = false;
+	}
+
+	dev_info(&pci_dev->dev, "MP2 device found [%04x:%04x] (rev %x)\n",
+		 (int)pci_dev->vendor, (int)pci_dev->device,
+		 (int)pci_dev->revision);
+
+	privdata = kzalloc(sizeof(*privdata), GFP_KERNEL);
+	if (!privdata) {
+		rc = -ENOMEM;
+		goto err_dev;
+	}
+
+	privdata->pci_dev = pci_dev;
+
+	rc = amd_mp2_pci_init(privdata, pci_dev);
+	if (rc)
+		goto err_pci_init;
+	dev_dbg(&pci_dev->dev, "pci init done.\n");
+
+	amd_mp2_init_debugfs(privdata);
+	dev_info(&pci_dev->dev, "MP2 device registered.\n");
+	return 0;
+
+err_pci_init:
+	kfree(privdata);
+err_dev:
+	dev_err(&pci_dev->dev, "Memory Allocation Failed\n");
+	return rc;
+}
+
+static void amd_mp2_pci_remove(struct pci_dev *pci_dev)
+{
+	struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
+	unsigned int bus_id;
+
+	for (bus_id = 0; bus_id < 2; bus_id++)
+		if (privdata->plat_common[bus_id])
+			amd_i2c_unregister_cb(privdata,
+					      privdata->plat_common[bus_id]);
+
+	amd_mp2_deinit_debugfs(privdata);
+	amd_mp2_clear_reg(privdata);
+	free_irq(pci_dev->irq, privdata);
+	pci_intx(pci_dev, 0);
+	amd_mp2_pci_deinit(privdata);
+	kfree(privdata);
+}
+
+static const struct file_operations amd_mp2_debugfs_info = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = amd_mp2_debugfs_read,
+};
+
+static const struct pci_device_id amd_mp2_pci_tbl[] = {
+	{PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
+
+#ifdef CONFIG_PM_SLEEP
+static int amd_mp2_pci_device_suspend(struct pci_dev *pci_dev,
+				      pm_message_t mesg)
+{
+	int ret;
+	struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
+
+	if (!privdata)
+		return -EINVAL;
+
+	ret = pci_save_state(pci_dev);
+	if (ret) {
+		dev_err(ndev_dev(privdata),
+			"pci_save_state failed = %d\n", ret);
+		return ret;
+	}
+
+	pci_enable_wake(pci_dev, PCI_D3hot, 0);
+	pci_disable_device(pci_dev);
+	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, mesg));
+
+	return 0;
+}
+
+static int amd_mp2_pci_device_resume(struct pci_dev *pci_dev)
+{
+	struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
+
+	if (!privdata)
+		return -EINVAL;
+
+	pci_set_power_state(pci_dev, PCI_D0);
+	pci_restore_state(pci_dev);
+
+	if (pci_enable_device(pci_dev) < 0) {
+		dev_err(ndev_dev(privdata), "pci_enable_device failed\n");
+		return -EIO;
+	}
+
+	pci_enable_wake(pci_dev, PCI_D3hot, 0);
+
+	return 0;
+}
+#endif
+
+static struct pci_driver amd_mp2_pci_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= amd_mp2_pci_tbl,
+	.probe		= amd_mp2_pci_probe,
+	.remove		= amd_mp2_pci_remove,
+#ifdef CONFIG_PM_SLEEP
+	.suspend		= amd_mp2_pci_device_suspend,
+	.resume			= amd_mp2_pci_device_resume,
+#endif
+};
+
+static int amd_mp2_device_match(struct device *dev, void *data)
+{
+	struct pci_dev *candidate = data;
+
+	if (!candidate)
+		return 1;
+	return (to_pci_dev(dev) == candidate) ? 1 : 0;
+}
+
+struct amd_mp2_dev *amd_mp2_find_device(struct pci_dev *candidate)
+{
+	struct device *dev;
+	struct pci_dev *pci_dev;
+
+	dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, candidate,
+				 amd_mp2_device_match);
+	if (!dev && candidate)
+		dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, NULL,
+					 amd_mp2_device_match);
+	if (!dev)
+		return NULL;
+
+	pci_dev = to_pci_dev(dev);
+	return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev);
+}
+EXPORT_SYMBOL_GPL(amd_mp2_find_device);
+
+static int __init amd_mp2_pci_driver_init(void)
+{
+	if (debugfs_initialized())
+		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	return pci_register_driver(&amd_mp2_pci_driver);
+}
+module_init(amd_mp2_pci_driver_init);
+
+static void __exit amd_mp2_pci_driver_exit(void)
+{
+	pci_unregister_driver(&amd_mp2_pci_driver);
+	debugfs_remove_recursive(debugfs_dir);
+}
+module_exit(amd_mp2_pci_driver_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VER);
+MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
+MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.h b/drivers/i2c/busses/i2c-amd-pci-mp2.h
new file mode 100644
index 000000000000..65601b6ba3b3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd-pci-mp2.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * AMD PCIe MP2 Communication Driver
+ *
+ * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ *          Elie Morisse <syniurge@gmail.com>
+ */
+
+#ifndef I2C_AMD_PCI_MP2_H
+#define I2C_AMD_PCI_MP2_H
+
+#include <linux/pci.h>
+
+#define PCI_DEVICE_ID_AMD_MP2	0x15E6
+
+struct amd_i2c_common;
+struct amd_mp2_dev;
+
+enum {
+	/* MP2 C2P Message Registers */
+	AMD_C2P_MSG0 = 0x10500,			/* MP2 Message for I2C0 */
+	AMD_C2P_MSG1 = 0x10504,			/* MP2 Message for I2C1 */
+	AMD_C2P_MSG2 = 0x10508,			/* DRAM Address Lo / Data 0 */
+	AMD_C2P_MSG3 = 0x1050c,			/* DRAM Address HI / Data 1 */
+	AMD_C2P_MSG4 = 0x10510,			/* Data 2 */
+	AMD_C2P_MSG5 = 0x10514,			/* Data 3 */
+	AMD_C2P_MSG6 = 0x10518,			/* Data 4 */
+	AMD_C2P_MSG7 = 0x1051c,			/* Data 5 */
+	AMD_C2P_MSG8 = 0x10520,			/* Data 6 */
+	AMD_C2P_MSG9 = 0x10524,			/* Data 7 */
+
+	/* MP2 P2C Message Registers */
+	AMD_P2C_MSG0 = 0x10680,			/* Do not use */
+	AMD_P2C_MSG1 = 0x10684,			/* I2C0 interrupt register */
+	AMD_P2C_MSG2 = 0x10688,			/* I2C1 interrupt register */
+	AMD_P2C_MSG3 = 0x1068C,			/* MP2 debug info */
+	AMD_P2C_MSG_INTEN = 0x10690,	/* MP2 interrupt gen register */
+	AMD_P2C_MSG_INTSTS = 0x10694,	/* Interrupt status */
+};
+
+/* Command register data structures */
+
+#define i2c_none (-1)
+enum i2c_cmd {
+	i2c_read = 0,
+	i2c_write,
+	i2c_enable,
+	i2c_disable,
+	number_of_sensor_discovered,
+	is_mp2_active,
+	invalid_cmd = 0xF,
+};
+
+enum speed_enum {
+	speed100k = 0,
+	speed400k = 1,
+	speed1000k = 2,
+	speed1400k = 3,
+	speed3400k = 4
+};
+
+enum mem_type {
+	use_dram = 0,
+	use_c2pmsg = 1,
+};
+
+/**
+ * union i2c_cmd_base : bit access of C2P commands
+ * @i2c_cmd: bit 0..3 i2c R/W command
+ * @bus_id: bit 4..7 i2c bus index
+ * @slave_addr: bit 8..15 slave address
+ * @length: bit 16..27 read/write length
+ * @i2c_speed: bit 28..30 bus speed
+ * @mem_type: bit 31 0-DRAM; 1-C2P msg o/p
+ */
+union i2c_cmd_base {
+	u32 ul;
+	struct {
+		enum i2c_cmd i2c_cmd : 4;
+		u8 bus_id : 4;
+		u32 slave_addr : 8;
+		u32 length : 12;
+		enum speed_enum i2c_speed : 3;
+		enum mem_type mem_type : 1;
+	} s;
+};
+
+/* Response - Response of SFI */
+enum response_type {
+	invalid_response = 0,
+	command_success = 1,
+	command_failed = 2,
+};
+
+/* Status - Command ID to indicate a command */
+enum status_type {
+	i2c_readcomplete_event = 0,
+	i2c_readfail_event = 1,
+	i2c_writecomplete_event = 2,
+	i2c_writefail_event = 3,
+	i2c_busenable_complete = 4,
+	i2c_busenable_failed = 5,
+	i2c_busdisable_complete = 6,
+	i2c_busdisable_failed = 7,
+	invalid_data_length = 8,
+	invalid_slave_address = 9,
+	invalid_i2cbus_id = 10,
+	invalid_dram_addr = 11,
+	invalid_command = 12,
+	mp2_active = 13,
+	numberof_sensors_discovered_resp = 14,
+	i2c_bus_notinitialized
+};
+
+/**
+ * union i2c_event : bit access of P2C events
+ * @response: bit 0..1 i2c response type
+ * @status: bit 2..6 status_type
+ * @mem_type: bit 7 0-DRAM; 1-C2P msg o/p
+ * @bus_id: bit 8..11 i2c bus id
+ * @length: bit 12..23 message length
+ * @slave_addr: bit 24-31 slave address
+ */
+union i2c_event {
+	u32 ul;
+	struct {
+		enum response_type response : 2;
+		enum status_type status : 5;
+		enum mem_type mem_type : 1;
+		u8 bus_id : 4;
+		u32 length : 12;
+		u32 slave_addr : 8;
+	} r;
+};
+
+/**
+ * struct i2c_rw_config - i2c read/write settings
+ * @slave_addr: slave address
+ * @length: message length
+ * @buf: buffer address
+ * @dma_addr: if length > 32, holds the DMA buffer address
+ * @dma_direction: if length > 32, is either FROM or TO device
+ */
+struct i2c_rw_config {
+	u16 slave_addr;
+	u32 length;
+	u32 *buf;
+	dma_addr_t dma_addr;
+	enum dma_data_direction dma_direction;
+};
+
+/**
+ * struct amd_i2c_pci_ops - platdrv hooks
+ */
+struct amd_i2c_pci_ops {
+	int (*read_complete)(union i2c_event *event);
+	int (*write_complete)(union i2c_event *event);
+	int (*connect_complete)(union i2c_event *event);
+};
+
+/**
+ * struct amd_i2c_common - per bus/i2c adapter context, shared
+ *		between the pci and the platform driver
+ * @eventval: MP2 event value set by the IRQ handler to be processed
+ *		by the worker
+ * @ops: platdrv hooks
+ * @rw_cfg: settings for reads/writes
+ * @work: delayed worker struct
+ * @reqcmd: i2c command type requested by platdrv
+ * @requested: true if the interrupt answered a request from platdrv
+ * @bus_id: bus index
+ * @i2c_speed: i2c bus speed determined by the slowest slave
+ */
+struct amd_i2c_common {
+	union i2c_event eventval;
+	const struct amd_i2c_pci_ops *ops;
+	struct amd_mp2_dev *mp2_dev;
+	struct i2c_rw_config rw_cfg;
+	struct delayed_work work;
+	enum i2c_cmd reqcmd;
+	u8 bus_id;
+	enum speed_enum i2c_speed;
+};
+
+/**
+ * struct amd_mp2_dev - per PCI device context
+ * @pci_dev: PCI driver node
+ * @plat_common: MP2 devices may have up to two busses,
+ *		each bus corresponding to an i2c adapter
+ * @mmio: iommapped registers
+ * @lock: interrupt spinlock
+ * @c2p_lock: controls access to the C2P mailbox shared between
+ *		the two adapters
+ */
+struct amd_mp2_dev {
+	struct pci_dev *pci_dev;
+	struct amd_i2c_common *plat_common[2];
+	void __iomem *mmio;
+	raw_spinlock_t lock;
+	struct mutex c2p_lock;
+	struct dentry *debugfs_dir;
+	struct dentry *debugfs_info;
+};
+
+int amd_mp2_read(struct amd_i2c_common *i2c_common);
+int amd_mp2_write(struct amd_i2c_common *i2c_common);
+int amd_mp2_connect(struct amd_i2c_common *i2c_common, bool enable);
+
+int amd_i2c_register_cb(struct amd_mp2_dev *mp2_dev,
+			struct amd_i2c_common *i2c_common);
+int amd_i2c_unregister_cb(struct amd_mp2_dev *mp2_dev,
+			  struct amd_i2c_common *i2c_common);
+
+struct amd_mp2_dev *amd_mp2_find_device(struct pci_dev *candidate);
+
+#define ndev_pdev(ndev) ((ndev)->pci_dev)
+#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
+#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
+#define work_amd_i2c_common(__work) \
+	container_of(__work, struct amd_i2c_common, work.work)
+#define event_amd_i2c_common(__event) \
+	container_of(__event, struct amd_i2c_common, eventval)
+
+#endif
diff --git a/drivers/i2c/busses/i2c-amd-plat-mp2.c b/drivers/i2c/busses/i2c-amd-plat-mp2.c
new file mode 100644
index 000000000000..a10bd08fe1db
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd-plat-mp2.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * AMD MP2 I2C Platform Driver
+ *
+ * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
+ *          Elie Morisse <syniurge@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+
+#include "i2c-amd-pci-mp2.h"
+#define DRIVER_NAME "i2c-amd-plat-mp2"
+
+#define AMD_MP2_I2C_MAX_RW_LENGTH ((1 << 12) - 1)
+#define AMD_I2C_TIMEOUT (msecs_to_jiffies(250))
+
+/**
+ * struct amd_i2c_dev - MP2 bus/i2c adapter context
+ * @i2c_common: shared context with the MP2 pci driver
+ * @pdev: platform driver node
+ * @adapter: i2c adapter
+ * @xfer_lock: xfer lock
+ * @completion: xfer completion object
+ */
+struct amd_i2c_dev {
+	struct amd_i2c_common i2c_common;
+	struct platform_device *pdev;
+	struct i2c_adapter adapter;
+	struct mutex xfer_lock;
+	struct completion msg_complete;
+	struct i2c_msg *msg_buf;
+	bool is_configured;
+};
+
+static const struct i2c_adapter_quirks amd_i2c_dev_quirks = {
+	.max_read_len = AMD_MP2_I2C_MAX_RW_LENGTH,
+	.max_write_len = AMD_MP2_I2C_MAX_RW_LENGTH,
+};
+
+#define amd_i2c_dev_common(__common) \
+	container_of(__common, struct amd_i2c_dev, i2c_common)
+
+static int i2c_amd_read_completion(union i2c_event *event)
+{
+	struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
+	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
+
+	if (event->r.status == i2c_readcomplete_event)
+		dev_dbg(&i2c_dev->pdev->dev, "%s readdata:%*ph\n",
+			__func__, event->r.length,
+			i2c_common->rw_cfg.buf);
+
+	complete(&i2c_dev->msg_complete);
+
+	return 0;
+}
+
+static int i2c_amd_write_completion(union i2c_event *event)
+{
+	struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
+	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
+
+	complete(&i2c_dev->msg_complete);
+
+	return 0;
+}
+
+static int i2c_amd_connect_completion(union i2c_event *event)
+{
+	struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
+	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
+
+	complete(&i2c_dev->msg_complete);
+
+	return 0;
+}
+
+static const struct amd_i2c_pci_ops data_handler = {
+		.read_complete = i2c_amd_read_completion,
+		.write_complete = i2c_amd_write_completion,
+		.connect_complete = i2c_amd_connect_completion,
+};
+
+static int i2c_amd_pci_configure(struct amd_i2c_dev *i2c_dev)
+{
+	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
+
+	amd_i2c_register_cb(i2c_common->mp2_dev, i2c_common);
+	i2c_common->ops = &data_handler;
+
+	return 0;
+}
+
+static int i2c_amd_pci_xconnect(struct amd_i2c_dev *i2c_dev, bool enable)
+{
+	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
+	unsigned long timeout;
+
+	reinit_completion(&i2c_dev->msg_complete);
+	amd_mp2_connect(i2c_common, enable);
+	timeout = wait_for_completion_timeout(&i2c_dev->msg_complete,
+					      AMD_I2C_TIMEOUT);
+	if (timeout == 0) {
+		dev_err(&i2c_dev->pdev->dev,
+			"i2c connection timed out\n");
+		mutex_unlock(&i2c_dev->xfer_lock);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int i2c_amd_xfer_msg(struct amd_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+{
+	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
+	unsigned long timeout;
+	bool is_read = pmsg->flags & I2C_M_RD;
+
+	reinit_completion(&i2c_dev->msg_complete);
+
+	i2c_common->rw_cfg.slave_addr = pmsg->addr;
+	i2c_common->rw_cfg.buf = (u32 *)pmsg->buf;
+	i2c_common->rw_cfg.length = pmsg->len;
+	i2c_dev->msg_buf = pmsg;
+
+	if (is_read)
+		amd_mp2_read(i2c_common);
+	else
+		amd_mp2_write(i2c_common);
+
+	timeout = wait_for_completion_timeout
+		(&i2c_dev->msg_complete, AMD_I2C_TIMEOUT);
+	if (timeout == 0) {
+		dev_err(&i2c_dev->pdev->dev,
+			"i2c %s timed out\n",
+			is_read ? "read" : "write");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int i2c_amd_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct amd_i2c_dev *dev = i2c_get_adapdata(adap);
+	int i;
+	struct i2c_msg *pmsg;
+	int err;
+
+	mutex_lock(&dev->xfer_lock);
+
+	if (dev->is_configured == 0) {
+		i2c_amd_pci_configure(dev);
+		i2c_amd_pci_xconnect(dev, true);
+		dev->is_configured = 1;
+	}
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		err = i2c_amd_xfer_msg(dev, pmsg);
+		if (err)
+			break;
+	}
+
+	mutex_unlock(&dev->xfer_lock);
+
+	if (err)
+		return err;
+	return num;
+}
+
+static u32 i2c_amd_func(struct i2c_adapter *a)
+{
+	return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm i2c_amd_algorithm = {
+	.master_xfer = i2c_amd_xfer,
+	.functionality = i2c_amd_func,
+};
+
+static enum speed_enum i2c_amd_get_bus_speed(struct platform_device *pdev)
+{
+	u32 acpi_speed;
+	int i;
+	static const u32 supported_speeds[] = {
+		0, 100000, 400000, 1000000, 1400000, 3400000
+	};
+
+	acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
+	/* round down to the lowest standard speed */
+	for (i = 1; i < ARRAY_SIZE(supported_speeds); i++) {
+		if (acpi_speed < supported_speeds[i])
+			break;
+	}
+	acpi_speed = supported_speeds[i - 1];
+
+	switch (acpi_speed) {
+	case 100000:
+		return speed100k;
+	case 400000:
+		return speed400k;
+	case 1000000:
+		return speed1000k;
+	case 1400000:
+		return speed1400k;
+	case 3400000:
+		return speed3400k;
+	default:
+		return speed400k;
+	}
+}
+
+static struct device *i2c_amd_acpi_get_first_phys_node(struct acpi_device *adev)
+{
+	const struct acpi_device_physical_node *node;
+
+	if (list_empty(&adev->physical_node_list))
+		return NULL;
+
+	node = list_first_entry(&adev->physical_node_list,
+				struct acpi_device_physical_node, node);
+	return node->dev;
+}
+
+/*
+ * Assume that the first device listed by the _DEP method is the parent
+ * MP2 device
+ */
+static struct pci_dev *i2c_amd_find_pci_parent(struct acpi_device *adev)
+{
+	struct acpi_device *parent_adev;
+	struct device *phys_dev;
+	struct acpi_handle_list dep_devices;
+	acpi_status status;
+
+	if (!acpi_has_method(adev->handle, "_DEP"))
+		return NULL;
+
+	status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+					 &dep_devices);
+	if (ACPI_FAILURE(status) || !dep_devices.count)
+		return NULL;
+
+	if (acpi_bus_get_device(dep_devices.handles[0], &parent_adev))
+		return NULL;
+	phys_dev = i2c_amd_acpi_get_first_phys_node(parent_adev);
+
+	if (!dev_is_pci(phys_dev))
+		return NULL;
+	return to_pci_dev(phys_dev);
+}
+
+static int i2c_amd_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct amd_i2c_dev *i2c_dev;
+	struct device *dev = &pdev->dev;
+	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+	struct acpi_device *adev;
+	struct pci_dev *parent_candidate = NULL;
+
+	i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->pdev = pdev;
+
+	if (!acpi_bus_get_device(handle, &adev)) {
+		const char *uid = adev->pnp.unique_id;
+
+		if (!uid) {
+			dev_err(&pdev->dev, "missing UID/bus id!\n");
+			return -EINVAL;
+		}
+
+		if (strcmp(uid, "0") == 0) {
+			i2c_dev->i2c_common.bus_id = 0;
+		} else if (strcmp(uid, "1") == 0) {
+			i2c_dev->i2c_common.bus_id = 1;
+		} else {
+			dev_err(&pdev->dev,
+				"incorrect UID/bus id \"%s\"!\n", uid);
+			return -EINVAL;
+		}
+
+		dev_dbg(&pdev->dev, "bus id is %u\n",
+			i2c_dev->i2c_common.bus_id);
+
+		i2c_dev->i2c_common.i2c_speed = i2c_amd_get_bus_speed(pdev);
+	} else {
+		i2c_dev->i2c_common.i2c_speed = speed400k;
+	}
+
+	/* setup i2c adapter description */
+	i2c_dev->adapter.owner = THIS_MODULE;
+	i2c_dev->adapter.algo = &i2c_amd_algorithm;
+	i2c_dev->adapter.quirks = &amd_i2c_dev_quirks;
+	i2c_dev->adapter.dev.parent = dev;
+	i2c_dev->adapter.algo_data = i2c_dev;
+	ACPI_COMPANION_SET(&i2c_dev->adapter.dev, ACPI_COMPANION(&pdev->dev));
+	i2c_dev->adapter.dev.of_node = dev->of_node;
+	snprintf(i2c_dev->adapter.name, sizeof(i2c_dev->adapter.name), "%s-%s",
+		 "i2c_dev-i2c", dev_name(pdev->dev.parent));
+
+	if (adev)
+		parent_candidate = i2c_amd_find_pci_parent(adev);
+	i2c_dev->i2c_common.mp2_dev = amd_mp2_find_device(parent_candidate);
+	if (!i2c_dev->i2c_common.mp2_dev) {
+		dev_err(&pdev->dev,
+			"%s Could not find MP2 PCI device for i2c adapter\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, i2c_dev);
+
+	i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
+
+	init_completion(&i2c_dev->msg_complete);
+	mutex_init(&i2c_dev->xfer_lock);
+
+	/* and finally attach to i2c layer */
+	ret = i2c_add_adapter(&i2c_dev->adapter);
+
+	if (ret < 0)
+		dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
+
+	return ret;
+}
+
+static int i2c_amd_remove(struct platform_device *pdev)
+{
+	struct amd_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
+
+	i2c_amd_pci_xconnect(i2c_dev, false);
+
+	amd_i2c_unregister_cb(i2c_common->mp2_dev, i2c_common);
+	i2c_del_adapter(&i2c_dev->adapter);
+
+	return 0;
+}
+
+static const struct acpi_device_id i2c_amd_acpi_match[] = {
+		{ "AMDI0011" },
+		{ },
+};
+MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match);
+
+static struct platform_driver amd_i2c_plat_driver = {
+		.probe = i2c_amd_probe,
+		.remove = i2c_amd_remove,
+		.driver = {
+				.name = "i2c_amd_plat_mp2",
+				.acpi_match_table = ACPI_PTR
+						(i2c_amd_acpi_match),
+		},
+};
+
+module_platform_driver(amd_i2c_plat_driver);
+
+MODULE_DESCRIPTION("AMD MP2 I2C Platform Driver");
+MODULE_AUTHOR("Nehal Shah <nehal-bakulchandra.shah@amd.com>");
+MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
+MODULE_LICENSE("Dual BSD/GPL");
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller
  2018-10-27 15:09 [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller Elie Morisse
@ 2018-10-30 20:56 ` Bjorn Helgaas
  2018-10-30 21:47   ` Tobias Thomer
                     ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Bjorn Helgaas @ 2018-10-30 20:56 UTC (permalink / raw)
  To: Elie Morisse
  Cc: linux-i2c, Wolfram Sang, Nehal-bakulchandra.Shah,
	Shyam-sundar.S-k, sandeep.singh, linux-kernel, Rafael J. Wysocki,
	Len Brown, linux-acpi

[+cc Rafael, Len, linux-acpi]

On Sat, Oct 27, 2018 at 12:09:10PM -0300, Elie Morisse wrote:
> This contains two drivers:
>  * i2c-amd-plat-mp2: platform driver managing an i2c adapter (one of
> the two busses of the MP2) and routing any i2c read/write command to
> the PCI driver.
>  * i2c-amd-pci-mp2: PCI driver communicating through the C2P/P2C
> mailbox registers, or through DMA for more than 32 bytes transfers.

I'm dubious about this two-driver structure.  If I understand
correctly (and it's very possible that I don't), the PCI driver
(amd_mp2_pci_probe()) is the real owner of the i2c adapter: it
claims the PCI device, claims its BARs, and requests an IRQ.

The i2c_amd_probe() code *looks* like a platform driver that claims
AMDI0011 devices from the ACPI namespace, but I don't think it's
really a driver.  It looks like it exists mainly to extract some
information (bus speed and maybe a bus number?) from the namespace,
then to call i2c_add_adapter().

It looks like i2c_amd_probe() must run *after* amd_mp2_pci_probe(),
but there's no way to really enforce that ordering.

And i2c-amd-plat-mp2 contains the i2c_amd_algorithm functions, which 
operate on the PCI device, which requires exported interfaces
(amd_mp2_read(), amd_mp2_write()) that are implemented in the PCI
driver but called from the platform part.

It seems like there should be a way to put the ACPI lookups into
i2c-amd-pci-mp2 so there's only one driver.

I only have a couple trivial comments below but I'm not trimming my
response so the ACPI folks can see the whole context.

> This is major rework of the patch submitted by Nehal-bakulchandra Shah
> from AMD (https://patchwork.kernel.org/patch/10597369/).
> 
> Most of the event handling of v2/v3 was rewritten since it couldn't work
> if more than one bus was enabled, and contains many more fixes listed
> in the patch changelog.
> 
> With those changes both the touchpad and the touchscreen of the
> Ryzen-based Lenovo Yoga 530 which lie in separate busses work beautifully.
> 
> Signed-off-by: Elie Morisse <syniurge@gmail.com>
> ---
> Changes since v1:(https://www.spinics.net/lists/linux-i2c/msg34650.html)
> -> Add fix for IOMMU
> -> Add depedency of ACPI
> -> Add locks to avoid the crash
> 
> Changes since v2:(https://patchwork.ozlabs.org/patch/961270/)
> 
> -> fix for review comments
> -> fix for more than 32 bytes write issue
> 
> Changes since v3 (https://patchwork.kernel.org/patch/10597369/) by Elie M.:
> 
> -> support more than one bus/adapter
> -> support more than one slave per bus
> -> use the bus speed specified by the slaves declared in the DSDT instead of
>    assuming speed == 400kbits/s
> -> instead of kzalloc'ing a buffer for every less than 32 bytes reads, simply
>    use i2c_msg.buf
> -> fix buffer overreads/overflows when (<=32 bytes) message lengths aren't a
>    multiple of 4 by using memcpy_fromio and memcpy_toio
> -> use streaming DMA mappings instead of allocating a coherent DMA buffer for
>    every >32 bytes read/write
> -> properly check for timeouts during i2c_amd_xfer and increase it from 50
>    jiffies to 250 msecs (which is more in line with other drivers)
> -> complete amd_i2c_dev.msg even if the device doesn't return a xxx_success
>    event, instead of stalling i2c_amd_xfer
> -> removed the spinlock and mdelay during i2c_amd_pci_configure, I didn't see
>    the point since it's already waiting for a i2c_busenable_complete event
> -> add an adapter-specific mutex lock for i2c_amd_xfer, since we don't want
>    parallel calls writing to AMD_C2P_MSG0 (or AMD_C2P_MSG1)
> -> add a global mutex lock for registers AMD_C2P_MSG2 to AMD_C2P_MSG9,  which
>    are shared across the two busses/adapters
> -> add MODULE_DEVICE_TABLE to automatically load i2c-amd-platdrv if the DSDT
>    enumerates devices with the "AMDI0011" HID
> -> set maximum length of reads/writes to 4095 (event's length field is 12 bits)
> -> basic PM support
> -> style corrections to match the kernel code style, and tried to reduce code
>    duplication whenever possible
> 
> Changes since v4 (https://marc.info/?l=linux-kernel&m=154031133019835) by Elie M.:
> 
> -> fix missing typecast warning
> -> removed the duplicated entry in Kconfig
> 
> Changes since v5 by Elie M.:
> 
> -> move DMA mapping from the platform driver to the PCI driver
> -> attempt to find the platform device's PCI parent through the _DEP ACPI method
>    (if not found take the first MP2 device registred in the i2c-amd-pci-mp2
>    driver, like before)
> -> do not assume anymore that the PCI device is owned by the i2c-amd-pci-mp2
>    driver
> -> address other review comments by Bjorn Helgaas (meant for v3)
> 
> Changes since v6 by Elie M.:
> 
> -> remove unnecessary memcpy from the DMA buffer during i2c_amd_read_completion
> 
>  MAINTAINERS                           |   6 +
>  drivers/i2c/busses/Kconfig            |  15 +
>  drivers/i2c/busses/Makefile           |   2 +
>  drivers/i2c/busses/i2c-amd-pci-mp2.c  | 706 ++++++++++++++++++++++++++
>  drivers/i2c/busses/i2c-amd-pci-mp2.h  | 224 ++++++++
>  drivers/i2c/busses/i2c-amd-plat-mp2.c | 373 ++++++++++++++
>  6 files changed, 1326 insertions(+)
>  create mode 100644 drivers/i2c/busses/i2c-amd-pci-mp2.c
>  create mode 100644 drivers/i2c/busses/i2c-amd-pci-mp2.h
>  create mode 100644 drivers/i2c/busses/i2c-amd-plat-mp2.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6ac000cc006d..8ff2bddc1ac2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -791,6 +791,12 @@ F:	drivers/gpu/drm/amd/include/vi_structs.h
>  F:	drivers/gpu/drm/amd/include/v9_structs.h
>  F:	include/uapi/linux/kfd_ioctl.h
>  
> +AMD MP2 I2C DRIVER
> +M:	Elie Morisse <syniurge@gmail.com>
> +L:	linux-i2c@vger.kernel.org
> +S:	Maintained
> +F:	drivers/i2c/busses/i2c-amd-*-mp2*
> +
>  AMD POWERPLAY
>  M:	Rex Zhu <rex.zhu@amd.com>
>  M:	Evan Quan <evan.quan@amd.com>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 451d4ae50e66..e20f2d1ce381 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -77,6 +77,21 @@ config I2C_AMD8111
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called i2c-amd8111.
>  
> +config I2C_AMD_MP2_PCI
> +	tristate
> +	depends on PCI
> +
> +config I2C_AMD_MP2_PLATFORM
> +	tristate "AMD MP2 Platform"
> +	select I2C_AMD_MP2_PCI
> +	depends on ACPI
> +	help
> +	  If you say yes to this option, support will be included for the AMD MP2
> +	  PCI I2C adapter.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called i2c-amd-plat-mp2.
> +
>  config I2C_HIX5HD2
>  	tristate "Hix5hd2 high-speed I2C driver"
>  	depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 18b26af82b1c..16ef646d7ef5 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -32,6 +32,8 @@ obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
>  
>  # Embedded system I2C/SMBus host controller drivers
>  obj-$(CONFIG_I2C_ALTERA)	+= i2c-altera.o
> +obj-$(CONFIG_I2C_AMD_MP2_PCI)	+= i2c-amd-pci-mp2.o
> +obj-$(CONFIG_I2C_AMD_MP2_PLATFORM)	+= i2c-amd-plat-mp2.o
>  obj-$(CONFIG_I2C_ASPEED)	+= i2c-aspeed.o
>  obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
>  obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
> diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.c b/drivers/i2c/busses/i2c-amd-pci-mp2.c
> new file mode 100644
> index 000000000000..eb54825f3f69
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-amd-pci-mp2.c
> @@ -0,0 +1,706 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/*
> + * AMD PCIe MP2 Communication Driver
> + *
> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> + *          Elie Morisse <syniurge@gmail.com>
> + */
> +
> +#include <linux/debugfs.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +
> +#include "i2c-amd-pci-mp2.h"
> +
> +#define DRIVER_NAME	"pcie_mp2_amd"
> +#define DRIVER_DESC	"AMD(R) PCI-E MP2 Communication Driver"
> +#define DRIVER_VER	"1.0"
> +
> +static const struct file_operations amd_mp2_debugfs_info;
> +static struct dentry *debugfs_dir;
> +
> +#define write64 _write64
> +static inline void _write64(u64 val, void __iomem *mmio)
> +{
> +	writel(val, mmio);
> +	writel(val >> 32, mmio + sizeof(u32));
> +}
> +
> +#define read64 _read64
> +static inline u64 _read64(void __iomem *mmio)
> +{
> +	u64 low, high;
> +
> +	low = readl(mmio);
> +	high = readl(mmio + sizeof(u32));
> +	return low | (high << 32);
> +}
> +
> +static int amd_mp2_cmd(struct amd_mp2_dev *privdata,
> +		       union i2c_cmd_base i2c_cmd_base)
> +{
> +	void __iomem *reg;
> +
> +	if (i2c_cmd_base.s.bus_id > 1) {
> +		dev_err(ndev_dev(privdata), "%s Invalid bus id\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	reg = privdata->mmio + ((i2c_cmd_base.s.bus_id == 1) ?
> +				AMD_C2P_MSG1 : AMD_C2P_MSG0);
> +	writel(i2c_cmd_base.ul, reg);
> +
> +	return 0;
> +}
> +
> +int amd_mp2_connect(struct amd_i2c_common *i2c_common, bool enable)
> +{
> +	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> +	union i2c_cmd_base i2c_cmd_base;
> +
> +	dev_dbg(ndev_dev(privdata), "%s id: %d\n", __func__,
> +		i2c_common->bus_id);
> +
> +	i2c_common->reqcmd = enable ? i2c_enable : i2c_disable;
> +
> +	i2c_cmd_base.ul = 0;
> +	i2c_cmd_base.s.i2c_cmd = i2c_common->reqcmd;
> +	i2c_cmd_base.s.bus_id = i2c_common->bus_id;
> +	i2c_cmd_base.s.i2c_speed = i2c_common->i2c_speed;
> +
> +	return amd_mp2_cmd(privdata, i2c_cmd_base);
> +}
> +EXPORT_SYMBOL_GPL(amd_mp2_connect);
> +
> +static void amd_mp2_cmd_rw_fill(struct amd_i2c_common *i2c_common,
> +				union i2c_cmd_base *i2c_cmd_base,
> +				enum i2c_cmd reqcmd)
> +{
> +	i2c_common->reqcmd = reqcmd;
> +
> +	i2c_cmd_base->s.i2c_cmd = reqcmd;
> +	i2c_cmd_base->s.bus_id = i2c_common->bus_id;
> +	i2c_cmd_base->s.i2c_speed = i2c_common->i2c_speed;
> +	i2c_cmd_base->s.slave_addr = i2c_common->rw_cfg.slave_addr;
> +	i2c_cmd_base->s.length = i2c_common->rw_cfg.length;
> +}
> +
> +static int amd_mp2_dma_map(struct amd_mp2_dev *privdata,
> +			   struct amd_i2c_common *i2c_common,
> +			   bool is_write)
> +{
> +	enum dma_data_direction dma_direction = is_write ?
> +			DMA_TO_DEVICE : DMA_FROM_DEVICE;
> +
> +	i2c_common->rw_cfg.dma_addr = dma_map_single(&privdata->pci_dev->dev,
> +						     i2c_common->rw_cfg.buf,
> +						     i2c_common->rw_cfg.length,
> +						     dma_direction);
> +	i2c_common->rw_cfg.dma_direction = dma_direction;
> +
> +	if (dma_mapping_error(&privdata->pci_dev->dev,
> +			      i2c_common->rw_cfg.dma_addr)) {
> +		dev_err(ndev_dev(privdata),
> +			"Error while mapping dma buffer %p\n",
> +			i2c_common->rw_cfg.buf);
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static void amd_mp2_dma_unmap(struct amd_mp2_dev *privdata,
> +			      struct amd_i2c_common *i2c_common)
> +{
> +	dma_unmap_single(&privdata->pci_dev->dev,
> +			 i2c_common->rw_cfg.dma_addr,
> +			 i2c_common->rw_cfg.length,
> +			 i2c_common->rw_cfg.dma_direction);
> +}
> +
> +int amd_mp2_read(struct amd_i2c_common *i2c_common)
> +{
> +	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> +	union i2c_cmd_base i2c_cmd_base;
> +
> +	dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__,
> +		i2c_common->rw_cfg.slave_addr, i2c_common->bus_id);
> +
> +	amd_mp2_cmd_rw_fill(i2c_common, &i2c_cmd_base, i2c_read);
> +
> +	/* there is only one data mailbox for two i2c adapters */
> +	mutex_lock(&privdata->c2p_lock);
> +
> +	if (!i2c_common->rw_cfg.buf) {
> +		dev_err(ndev_dev(privdata), "%s no mem for buf received\n",
> +			__func__);
> +		return -ENOMEM;
> +	}
> +
> +	if (i2c_common->rw_cfg.length <= 32) {
> +		i2c_cmd_base.s.mem_type = use_c2pmsg;
> +	} else {
> +		i2c_cmd_base.s.mem_type = use_dram;
> +		if (amd_mp2_dma_map(privdata, i2c_common, false))
> +			return -EIO;
> +		write64((u64)i2c_common->rw_cfg.dma_addr,
> +			privdata->mmio + AMD_C2P_MSG2);
> +	}
> +
> +	return amd_mp2_cmd(privdata, i2c_cmd_base);
> +}
> +EXPORT_SYMBOL_GPL(amd_mp2_read);
> +
> +int amd_mp2_write(struct amd_i2c_common *i2c_common)
> +{
> +	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> +	union i2c_cmd_base i2c_cmd_base;
> +
> +	dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__,
> +		i2c_common->rw_cfg.slave_addr, i2c_common->bus_id);
> +
> +	amd_mp2_cmd_rw_fill(i2c_common, &i2c_cmd_base, i2c_write);
> +
> +	/* there is only one data mailbox for two i2c adapters */
> +	mutex_lock(&privdata->c2p_lock);
> +
> +	if (i2c_common->rw_cfg.length <= 32) {
> +		i2c_cmd_base.s.mem_type = use_c2pmsg;
> +		memcpy_toio(privdata->mmio + AMD_C2P_MSG2,
> +			    i2c_common->rw_cfg.buf,
> +			    i2c_common->rw_cfg.length);
> +	} else {
> +		i2c_cmd_base.s.mem_type = use_dram;
> +		if (amd_mp2_dma_map(privdata, i2c_common, true))
> +			return -EIO;
> +		write64((u64)i2c_common->rw_cfg.dma_addr,
> +			privdata->mmio + AMD_C2P_MSG2);
> +	}
> +
> +	return amd_mp2_cmd(privdata, i2c_cmd_base);
> +}
> +EXPORT_SYMBOL_GPL(amd_mp2_write);
> +
> +static void amd_mp2_pci_do_work(struct work_struct *work)
> +{
> +	struct amd_i2c_common *i2c_common = work_amd_i2c_common(work);
> +	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> +	int sts = i2c_common->eventval.r.status;
> +	int res = i2c_common->eventval.r.response;
> +	int len = i2c_common->eventval.r.length;
> +	u32 slave_addr = i2c_common->eventval.r.slave_addr;
> +
> +	if (len != i2c_common->rw_cfg.length)
> +		dev_err(ndev_dev(privdata),
> +			"length %d in event doesn't match buffer length %d!\n",
> +			len, i2c_common->rw_cfg.length);
> +	if (slave_addr != i2c_common->rw_cfg.slave_addr)
> +		dev_err(ndev_dev(privdata),
> +			"unexpected slave address %x (expected: %x)!\n",
> +			slave_addr, i2c_common->rw_cfg.slave_addr);
> +
> +	if (res != command_success) {
> +		if (res == command_failed)
> +			dev_err(ndev_dev(privdata), "i2c command failed!\n");
> +		else
> +			dev_err(ndev_dev(privdata), "invalid response to i2c command!\n");
> +		return;
> +	}
> +
> +	switch (i2c_common->reqcmd) {
> +	case i2c_read:
> +		if (sts == i2c_readcomplete_event) {
> +			if (len <= 32)
> +				memcpy_fromio(i2c_common->rw_cfg.buf,
> +					      privdata->mmio + AMD_C2P_MSG2,
> +					      i2c_common->rw_cfg.length);
> +		} else if (sts == i2c_readfail_event) {
> +			dev_err(ndev_dev(privdata), "i2c read failed!\n");
> +		} else {
> +			dev_err(ndev_dev(privdata), "invalid i2c status after read!\n");
> +		}
> +
> +		i2c_common->ops->read_complete(&i2c_common->eventval);
> +		break;
> +	case i2c_write:
> +		if (sts == i2c_writefail_event)
> +			dev_err(ndev_dev(privdata), "i2c write failed!\n");
> +		else if (sts != i2c_writecomplete_event)
> +			dev_err(ndev_dev(privdata), "invalid i2c status after write!\n");
> +
> +		i2c_common->ops->write_complete(&i2c_common->eventval);
> +		break;
> +	case i2c_enable:
> +		if (sts == i2c_busdisable_failed)
> +			dev_err(ndev_dev(privdata), "i2c bus enable failed!\n");
> +		else if (sts != i2c_busenable_complete)
> +			dev_err(ndev_dev(privdata), "invalid i2c status after bus enable!\n");
> +
> +		i2c_common->ops->connect_complete(&i2c_common->eventval);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if ((i2c_common->reqcmd == i2c_read ||
> +	     i2c_common->reqcmd == i2c_write) &&
> +	    i2c_common->rw_cfg.length > 32)
> +		amd_mp2_dma_unmap(privdata, i2c_common);
> +}
> +
> +static void amd_mp2_pci_work(struct work_struct *work)
> +{
> +	struct amd_i2c_common *i2c_common = work_amd_i2c_common(work);
> +	struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> +	enum i2c_cmd cmd = i2c_common->reqcmd;
> +
> +	amd_mp2_pci_do_work(work);
> +
> +	i2c_common->reqcmd = i2c_none;
> +
> +	if (cmd == i2c_read || cmd == i2c_write)
> +		mutex_unlock(&privdata->c2p_lock);
> +}
> +
> +static irqreturn_t amd_mp2_irq_isr(int irq, void *dev)
> +{
> +	struct amd_mp2_dev *privdata = dev;
> +	struct amd_i2c_common *i2c_common;
> +	u32 val;
> +	unsigned int bus_id;
> +	void __iomem *reg;
> +	unsigned long flags;
> +	enum irqreturn ret = IRQ_NONE;
> +
> +	raw_spin_lock_irqsave(&privdata->lock, flags);
> +
> +	for (bus_id = 0; bus_id < 2; bus_id++) {
> +		reg = privdata->mmio + ((bus_id == 0) ?
> +					AMD_P2C_MSG1 : AMD_P2C_MSG2);
> +		val = readl(reg);
> +		if (val != 0) {
> +			i2c_common = privdata->plat_common[bus_id];
> +			if (!i2c_common)
> +				continue;
> +			i2c_common->eventval.ul = val;
> +
> +			writel(0, reg);
> +			writel(0, privdata->mmio + AMD_P2C_MSG_INTEN);
> +
> +			if (i2c_common->reqcmd != i2c_none)
> +				schedule_delayed_work(&i2c_common->work, 0);
> +
> +			ret = IRQ_HANDLED;
> +		}
> +	}
> +
> +	raw_spin_unlock_irqrestore(&privdata->lock, flags);
> +	return ret;
> +}
> +
> +int amd_i2c_register_cb(struct amd_mp2_dev *privdata,
> +			struct amd_i2c_common *i2c_common)
> +{
> +	if (i2c_common->bus_id > 1)
> +		return -EINVAL;
> +	privdata->plat_common[i2c_common->bus_id] = i2c_common;
> +
> +	INIT_DELAYED_WORK(&i2c_common->work, amd_mp2_pci_work);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(amd_i2c_register_cb);
> +
> +int amd_i2c_unregister_cb(struct amd_mp2_dev *privdata,
> +			  struct amd_i2c_common *i2c_common)
> +{
> +	cancel_delayed_work_sync(&i2c_common->work);
> +	privdata->plat_common[i2c_common->bus_id] = NULL;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(amd_i2c_unregister_cb);
> +
> +static ssize_t amd_mp2_debugfs_read(struct file *filp, char __user *ubuf,
> +				    size_t count, loff_t *offp)
> +{
> +	struct amd_mp2_dev *privdata;
> +	void __iomem *mmio;
> +	u8 *buf;
> +	size_t buf_size;
> +	ssize_t ret, off;
> +	u32 v32;
> +
> +	privdata = filp->private_data;
> +	mmio = privdata->mmio;
> +	buf_size = min_t(size_t, count, 0x800);
> +	buf = kmalloc(buf_size, GFP_KERNEL);
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	off = 0;
> +	off += scnprintf(buf + off, buf_size - off,
> +			"Mp2 Device Information:\n");
> +
> +	off += scnprintf(buf + off, buf_size - off,
> +			"========================\n");
> +	off += scnprintf(buf + off, buf_size - off,
> +			"\tMP2 C2P Message Register Dump:\n\n");
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG0);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG0 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG1);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG1 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG2);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG2 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG3);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG3 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG4);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG4 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG5);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG5 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG6);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG6 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG7);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG7 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG8);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG8 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_C2P_MSG9);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_C2P_MSG9 -\t\t\t%#06x\n", v32);
> +
> +	off += scnprintf(buf + off, buf_size - off,
> +			"\n\tMP2 P2C Message Register Dump:\n\n");
> +
> +	v32 = readl(privdata->mmio + AMD_P2C_MSG1);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_P2C_MSG1 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_P2C_MSG2);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_P2C_MSG2 -\t\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_P2C_MSG_INTEN);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_P2C_MSG_INTEN -\t\t%#06x\n", v32);
> +
> +	v32 = readl(privdata->mmio + AMD_P2C_MSG_INTSTS);
> +	off += scnprintf(buf + off, buf_size - off,
> +			"AMD_P2C_MSG_INTSTS -\t\t%#06x\n", v32);
> +
> +	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static void amd_mp2_init_debugfs(struct amd_mp2_dev *privdata)
> +{
> +	if (!debugfs_dir) {
> +		privdata->debugfs_dir = NULL;
> +		privdata->debugfs_info = NULL;
> +		return;
> +	}
> +
> +	privdata->debugfs_dir = debugfs_create_dir(ndev_name(privdata),
> +						   debugfs_dir);
> +	if (!privdata->debugfs_dir) {
> +		privdata->debugfs_info = NULL;
> +	} else {
> +		privdata->debugfs_info = debugfs_create_file
> +			("info", 0400, privdata->debugfs_dir,
> +			 privdata, &amd_mp2_debugfs_info);
> +	}
> +}
> +
> +static void amd_mp2_deinit_debugfs(struct amd_mp2_dev *privdata)
> +{
> +	debugfs_remove_recursive(privdata->debugfs_dir);
> +}
> +
> +static void amd_mp2_clear_reg(struct amd_mp2_dev *privdata)
> +{
> +	int reg;
> +
> +	for (reg = AMD_C2P_MSG0; reg <= AMD_C2P_MSG9; reg += 4)
> +		writel(0, privdata->mmio + reg);
> +
> +	for (reg = AMD_P2C_MSG0; reg <= AMD_P2C_MSG2; reg += 4)
> +		writel(0, privdata->mmio + reg);
> +}
> +
> +static int amd_mp2_pci_init(struct amd_mp2_dev *privdata,
> +			    struct pci_dev *pci_dev)
> +{
> +	int rc;
> +	resource_size_t size, base;
> +
> +	pci_set_drvdata(pci_dev, privdata);
> +
> +	rc = pci_enable_device(pci_dev);
> +	if (rc)
> +		goto err_pci_enable;
> +
> +	rc = pci_request_regions(pci_dev, DRIVER_NAME);
> +	if (rc)
> +		goto err_pci_regions;
> +
> +	pci_set_master(pci_dev);
> +
> +	rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64));
> +	if (rc) {
> +		rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
> +		if (rc)
> +			goto err_dma_mask;
> +		dev_warn(ndev_dev(privdata), "Cannot DMA highmem\n");
> +	}
> +
> +	rc = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(64));
> +	if (rc) {
> +		rc = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(32));
> +		if (rc)
> +			goto err_dma_mask;
> +		dev_warn(ndev_dev(privdata), "Cannot DMA consistent highmem\n");
> +	}
> +
> +	base = pci_resource_start(pci_dev, 2);
> +	size = pci_resource_len(pci_dev, 2);
> +	dev_dbg(ndev_dev(privdata), "Base addr:%zx size:%zx\n",
> +		(size_t)base, (size_t)size);

You can use %pR on pci_dev->resource[2].  That uses the conventional
format (same as used by the PCI core).

> +
> +	mutex_init(&privdata->c2p_lock);
> +	privdata->mmio = ioremap(base, size);
> +	if (!privdata->mmio) {
> +		rc = -EIO;
> +		goto err_dma_mask;
> +	}
> +
> +	/* Try to set up intx irq */
> +	raw_spin_lock_init(&privdata->lock);
> +	pci_intx(pci_dev, 1);
> +	rc = request_irq(pci_dev->irq, amd_mp2_irq_isr, IRQF_SHARED,
> +			 "mp2_irq_isr", privdata);
> +	if (rc)
> +		goto err_intx_request;
> +
> +	return 0;
> +
> +err_intx_request:
> +	return rc;
> +err_dma_mask:
> +	pci_clear_master(pci_dev);
> +	pci_release_regions(pci_dev);
> +err_pci_regions:
> +	pci_disable_device(pci_dev);
> +err_pci_enable:
> +	pci_set_drvdata(pci_dev, NULL);
> +	return rc;
> +}
> +
> +static void amd_mp2_pci_deinit(struct amd_mp2_dev *privdata)
> +{
> +	struct pci_dev *pci_dev = ndev_pdev(privdata);
> +
> +	pci_iounmap(pci_dev, privdata->mmio);
> +
> +	pci_clear_master(pci_dev);
> +	pci_release_regions(pci_dev);
> +	pci_disable_device(pci_dev);
> +	pci_set_drvdata(pci_dev, NULL);
> +}
> +
> +static int amd_mp2_pci_probe(struct pci_dev *pci_dev,
> +			     const struct pci_device_id *id)
> +{
> +	struct amd_mp2_dev *privdata;
> +	int rc;
> +	static bool first_probe = true;
> +
> +	if (first_probe) {
> +		pr_info("%s: %s Version: %s\n", DRIVER_NAME,
> +			DRIVER_DESC, DRIVER_VER);
> +		first_probe = false;
> +	}
> +
> +	dev_info(&pci_dev->dev, "MP2 device found [%04x:%04x] (rev %x)\n",
> +		 (int)pci_dev->vendor, (int)pci_dev->device,
> +		 (int)pci_dev->revision);
> +
> +	privdata = kzalloc(sizeof(*privdata), GFP_KERNEL);
> +	if (!privdata) {
> +		rc = -ENOMEM;
> +		goto err_dev;

There's nothing to clean up at this point, so just emit the message
and return directly:

  if (!privdata) {
    dev_err(&pci_dev->dev, "Memory Allocation Failed\n");
    return -ENOMEM;
  }

> +	}
> +
> +	privdata->pci_dev = pci_dev;
> +
> +	rc = amd_mp2_pci_init(privdata, pci_dev);
> +	if (rc)
> +		goto err_pci_init;
> +	dev_dbg(&pci_dev->dev, "pci init done.\n");
> +
> +	amd_mp2_init_debugfs(privdata);
> +	dev_info(&pci_dev->dev, "MP2 device registered.\n");
> +	return 0;
> +
> +err_pci_init:
> +	kfree(privdata);
> +err_dev:
> +	dev_err(&pci_dev->dev, "Memory Allocation Failed\n");
> +	return rc;
> +}
> +
> +static void amd_mp2_pci_remove(struct pci_dev *pci_dev)
> +{
> +	struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
> +	unsigned int bus_id;
> +
> +	for (bus_id = 0; bus_id < 2; bus_id++)
> +		if (privdata->plat_common[bus_id])
> +			amd_i2c_unregister_cb(privdata,
> +					      privdata->plat_common[bus_id]);
> +
> +	amd_mp2_deinit_debugfs(privdata);
> +	amd_mp2_clear_reg(privdata);
> +	free_irq(pci_dev->irq, privdata);
> +	pci_intx(pci_dev, 0);
> +	amd_mp2_pci_deinit(privdata);
> +	kfree(privdata);
> +}
> +
> +static const struct file_operations amd_mp2_debugfs_info = {
> +	.owner = THIS_MODULE,
> +	.open = simple_open,
> +	.read = amd_mp2_debugfs_read,
> +};
> +
> +static const struct pci_device_id amd_mp2_pci_tbl[] = {
> +	{PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
> +	{0}
> +};
> +MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int amd_mp2_pci_device_suspend(struct pci_dev *pci_dev,
> +				      pm_message_t mesg)
> +{
> +	int ret;
> +	struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
> +
> +	if (!privdata)
> +		return -EINVAL;
> +
> +	ret = pci_save_state(pci_dev);
> +	if (ret) {
> +		dev_err(ndev_dev(privdata),
> +			"pci_save_state failed = %d\n", ret);
> +		return ret;
> +	}
> +
> +	pci_enable_wake(pci_dev, PCI_D3hot, 0);
> +	pci_disable_device(pci_dev);
> +	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, mesg));
> +
> +	return 0;
> +}
> +
> +static int amd_mp2_pci_device_resume(struct pci_dev *pci_dev)
> +{
> +	struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
> +
> +	if (!privdata)
> +		return -EINVAL;
> +
> +	pci_set_power_state(pci_dev, PCI_D0);
> +	pci_restore_state(pci_dev);
> +
> +	if (pci_enable_device(pci_dev) < 0) {
> +		dev_err(ndev_dev(privdata), "pci_enable_device failed\n");
> +		return -EIO;
> +	}
> +
> +	pci_enable_wake(pci_dev, PCI_D3hot, 0);
> +
> +	return 0;
> +}
> +#endif
> +
> +static struct pci_driver amd_mp2_pci_driver = {
> +	.name		= DRIVER_NAME,
> +	.id_table	= amd_mp2_pci_tbl,
> +	.probe		= amd_mp2_pci_probe,
> +	.remove		= amd_mp2_pci_remove,
> +#ifdef CONFIG_PM_SLEEP
> +	.suspend		= amd_mp2_pci_device_suspend,
> +	.resume			= amd_mp2_pci_device_resume,
> +#endif
> +};
> +
> +static int amd_mp2_device_match(struct device *dev, void *data)
> +{
> +	struct pci_dev *candidate = data;
> +
> +	if (!candidate)
> +		return 1;
> +	return (to_pci_dev(dev) == candidate) ? 1 : 0;
> +}
> +
> +struct amd_mp2_dev *amd_mp2_find_device(struct pci_dev *candidate)
> +{
> +	struct device *dev;
> +	struct pci_dev *pci_dev;
> +
> +	dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, candidate,
> +				 amd_mp2_device_match);
> +	if (!dev && candidate)
> +		dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, NULL,
> +					 amd_mp2_device_match);
> +	if (!dev)
> +		return NULL;
> +
> +	pci_dev = to_pci_dev(dev);
> +	return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev);
> +}
> +EXPORT_SYMBOL_GPL(amd_mp2_find_device);
> +
> +static int __init amd_mp2_pci_driver_init(void)
> +{
> +	if (debugfs_initialized())
> +		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
> +
> +	return pci_register_driver(&amd_mp2_pci_driver);
> +}
> +module_init(amd_mp2_pci_driver_init);
> +
> +static void __exit amd_mp2_pci_driver_exit(void)
> +{
> +	pci_unregister_driver(&amd_mp2_pci_driver);
> +	debugfs_remove_recursive(debugfs_dir);
> +}
> +module_exit(amd_mp2_pci_driver_exit);
> +
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_VERSION(DRIVER_VER);
> +MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
> +MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.h b/drivers/i2c/busses/i2c-amd-pci-mp2.h
> new file mode 100644
> index 000000000000..65601b6ba3b3
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-amd-pci-mp2.h
> @@ -0,0 +1,224 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
> +/*
> + * AMD PCIe MP2 Communication Driver
> + *
> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> + *          Elie Morisse <syniurge@gmail.com>
> + */
> +
> +#ifndef I2C_AMD_PCI_MP2_H
> +#define I2C_AMD_PCI_MP2_H
> +
> +#include <linux/pci.h>
> +
> +#define PCI_DEVICE_ID_AMD_MP2	0x15E6
> +
> +struct amd_i2c_common;
> +struct amd_mp2_dev;
> +
> +enum {
> +	/* MP2 C2P Message Registers */
> +	AMD_C2P_MSG0 = 0x10500,			/* MP2 Message for I2C0 */
> +	AMD_C2P_MSG1 = 0x10504,			/* MP2 Message for I2C1 */
> +	AMD_C2P_MSG2 = 0x10508,			/* DRAM Address Lo / Data 0 */
> +	AMD_C2P_MSG3 = 0x1050c,			/* DRAM Address HI / Data 1 */
> +	AMD_C2P_MSG4 = 0x10510,			/* Data 2 */
> +	AMD_C2P_MSG5 = 0x10514,			/* Data 3 */
> +	AMD_C2P_MSG6 = 0x10518,			/* Data 4 */
> +	AMD_C2P_MSG7 = 0x1051c,			/* Data 5 */
> +	AMD_C2P_MSG8 = 0x10520,			/* Data 6 */
> +	AMD_C2P_MSG9 = 0x10524,			/* Data 7 */
> +
> +	/* MP2 P2C Message Registers */
> +	AMD_P2C_MSG0 = 0x10680,			/* Do not use */
> +	AMD_P2C_MSG1 = 0x10684,			/* I2C0 interrupt register */
> +	AMD_P2C_MSG2 = 0x10688,			/* I2C1 interrupt register */
> +	AMD_P2C_MSG3 = 0x1068C,			/* MP2 debug info */
> +	AMD_P2C_MSG_INTEN = 0x10690,	/* MP2 interrupt gen register */
> +	AMD_P2C_MSG_INTSTS = 0x10694,	/* Interrupt status */
> +};
> +
> +/* Command register data structures */
> +
> +#define i2c_none (-1)
> +enum i2c_cmd {
> +	i2c_read = 0,
> +	i2c_write,
> +	i2c_enable,
> +	i2c_disable,
> +	number_of_sensor_discovered,
> +	is_mp2_active,
> +	invalid_cmd = 0xF,
> +};
> +
> +enum speed_enum {
> +	speed100k = 0,
> +	speed400k = 1,
> +	speed1000k = 2,
> +	speed1400k = 3,
> +	speed3400k = 4
> +};
> +
> +enum mem_type {
> +	use_dram = 0,
> +	use_c2pmsg = 1,
> +};
> +
> +/**
> + * union i2c_cmd_base : bit access of C2P commands
> + * @i2c_cmd: bit 0..3 i2c R/W command
> + * @bus_id: bit 4..7 i2c bus index
> + * @slave_addr: bit 8..15 slave address
> + * @length: bit 16..27 read/write length
> + * @i2c_speed: bit 28..30 bus speed
> + * @mem_type: bit 31 0-DRAM; 1-C2P msg o/p
> + */
> +union i2c_cmd_base {
> +	u32 ul;
> +	struct {
> +		enum i2c_cmd i2c_cmd : 4;
> +		u8 bus_id : 4;
> +		u32 slave_addr : 8;
> +		u32 length : 12;
> +		enum speed_enum i2c_speed : 3;
> +		enum mem_type mem_type : 1;
> +	} s;
> +};
> +
> +/* Response - Response of SFI */
> +enum response_type {
> +	invalid_response = 0,
> +	command_success = 1,
> +	command_failed = 2,
> +};
> +
> +/* Status - Command ID to indicate a command */
> +enum status_type {
> +	i2c_readcomplete_event = 0,
> +	i2c_readfail_event = 1,
> +	i2c_writecomplete_event = 2,
> +	i2c_writefail_event = 3,
> +	i2c_busenable_complete = 4,
> +	i2c_busenable_failed = 5,
> +	i2c_busdisable_complete = 6,
> +	i2c_busdisable_failed = 7,
> +	invalid_data_length = 8,
> +	invalid_slave_address = 9,
> +	invalid_i2cbus_id = 10,
> +	invalid_dram_addr = 11,
> +	invalid_command = 12,
> +	mp2_active = 13,
> +	numberof_sensors_discovered_resp = 14,
> +	i2c_bus_notinitialized
> +};
> +
> +/**
> + * union i2c_event : bit access of P2C events
> + * @response: bit 0..1 i2c response type
> + * @status: bit 2..6 status_type
> + * @mem_type: bit 7 0-DRAM; 1-C2P msg o/p
> + * @bus_id: bit 8..11 i2c bus id
> + * @length: bit 12..23 message length
> + * @slave_addr: bit 24-31 slave address
> + */
> +union i2c_event {
> +	u32 ul;
> +	struct {
> +		enum response_type response : 2;
> +		enum status_type status : 5;
> +		enum mem_type mem_type : 1;
> +		u8 bus_id : 4;
> +		u32 length : 12;
> +		u32 slave_addr : 8;
> +	} r;
> +};
> +
> +/**
> + * struct i2c_rw_config - i2c read/write settings
> + * @slave_addr: slave address
> + * @length: message length
> + * @buf: buffer address
> + * @dma_addr: if length > 32, holds the DMA buffer address
> + * @dma_direction: if length > 32, is either FROM or TO device
> + */
> +struct i2c_rw_config {
> +	u16 slave_addr;
> +	u32 length;
> +	u32 *buf;
> +	dma_addr_t dma_addr;
> +	enum dma_data_direction dma_direction;
> +};
> +
> +/**
> + * struct amd_i2c_pci_ops - platdrv hooks
> + */
> +struct amd_i2c_pci_ops {
> +	int (*read_complete)(union i2c_event *event);
> +	int (*write_complete)(union i2c_event *event);
> +	int (*connect_complete)(union i2c_event *event);
> +};
> +
> +/**
> + * struct amd_i2c_common - per bus/i2c adapter context, shared
> + *		between the pci and the platform driver
> + * @eventval: MP2 event value set by the IRQ handler to be processed
> + *		by the worker
> + * @ops: platdrv hooks
> + * @rw_cfg: settings for reads/writes
> + * @work: delayed worker struct
> + * @reqcmd: i2c command type requested by platdrv
> + * @requested: true if the interrupt answered a request from platdrv
> + * @bus_id: bus index
> + * @i2c_speed: i2c bus speed determined by the slowest slave
> + */
> +struct amd_i2c_common {
> +	union i2c_event eventval;
> +	const struct amd_i2c_pci_ops *ops;
> +	struct amd_mp2_dev *mp2_dev;
> +	struct i2c_rw_config rw_cfg;
> +	struct delayed_work work;
> +	enum i2c_cmd reqcmd;
> +	u8 bus_id;
> +	enum speed_enum i2c_speed;
> +};
> +
> +/**
> + * struct amd_mp2_dev - per PCI device context
> + * @pci_dev: PCI driver node
> + * @plat_common: MP2 devices may have up to two busses,
> + *		each bus corresponding to an i2c adapter
> + * @mmio: iommapped registers
> + * @lock: interrupt spinlock
> + * @c2p_lock: controls access to the C2P mailbox shared between
> + *		the two adapters
> + */
> +struct amd_mp2_dev {
> +	struct pci_dev *pci_dev;
> +	struct amd_i2c_common *plat_common[2];
> +	void __iomem *mmio;
> +	raw_spinlock_t lock;
> +	struct mutex c2p_lock;
> +	struct dentry *debugfs_dir;
> +	struct dentry *debugfs_info;
> +};
> +
> +int amd_mp2_read(struct amd_i2c_common *i2c_common);
> +int amd_mp2_write(struct amd_i2c_common *i2c_common);
> +int amd_mp2_connect(struct amd_i2c_common *i2c_common, bool enable);
> +
> +int amd_i2c_register_cb(struct amd_mp2_dev *mp2_dev,
> +			struct amd_i2c_common *i2c_common);
> +int amd_i2c_unregister_cb(struct amd_mp2_dev *mp2_dev,
> +			  struct amd_i2c_common *i2c_common);
> +
> +struct amd_mp2_dev *amd_mp2_find_device(struct pci_dev *candidate);
> +
> +#define ndev_pdev(ndev) ((ndev)->pci_dev)
> +#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
> +#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
> +#define work_amd_i2c_common(__work) \
> +	container_of(__work, struct amd_i2c_common, work.work)
> +#define event_amd_i2c_common(__event) \
> +	container_of(__event, struct amd_i2c_common, eventval)
> +
> +#endif
> diff --git a/drivers/i2c/busses/i2c-amd-plat-mp2.c b/drivers/i2c/busses/i2c-amd-plat-mp2.c
> new file mode 100644
> index 000000000000..a10bd08fe1db
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-amd-plat-mp2.c
> @@ -0,0 +1,373 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/*
> + * AMD MP2 I2C Platform Driver
> + *
> + * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
> + *          Elie Morisse <syniurge@gmail.com>
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/platform_device.h>
> +#include <linux/acpi.h>
> +#include <linux/delay.h>
> +
> +#include "i2c-amd-pci-mp2.h"
> +#define DRIVER_NAME "i2c-amd-plat-mp2"
> +
> +#define AMD_MP2_I2C_MAX_RW_LENGTH ((1 << 12) - 1)
> +#define AMD_I2C_TIMEOUT (msecs_to_jiffies(250))
> +
> +/**
> + * struct amd_i2c_dev - MP2 bus/i2c adapter context
> + * @i2c_common: shared context with the MP2 pci driver
> + * @pdev: platform driver node
> + * @adapter: i2c adapter
> + * @xfer_lock: xfer lock
> + * @completion: xfer completion object
> + */
> +struct amd_i2c_dev {
> +	struct amd_i2c_common i2c_common;
> +	struct platform_device *pdev;
> +	struct i2c_adapter adapter;
> +	struct mutex xfer_lock;
> +	struct completion msg_complete;
> +	struct i2c_msg *msg_buf;
> +	bool is_configured;
> +};
> +
> +static const struct i2c_adapter_quirks amd_i2c_dev_quirks = {
> +	.max_read_len = AMD_MP2_I2C_MAX_RW_LENGTH,
> +	.max_write_len = AMD_MP2_I2C_MAX_RW_LENGTH,
> +};
> +
> +#define amd_i2c_dev_common(__common) \
> +	container_of(__common, struct amd_i2c_dev, i2c_common)
> +
> +static int i2c_amd_read_completion(union i2c_event *event)
> +{
> +	struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
> +	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
> +
> +	if (event->r.status == i2c_readcomplete_event)
> +		dev_dbg(&i2c_dev->pdev->dev, "%s readdata:%*ph\n",
> +			__func__, event->r.length,
> +			i2c_common->rw_cfg.buf);
> +
> +	complete(&i2c_dev->msg_complete);
> +
> +	return 0;
> +}
> +
> +static int i2c_amd_write_completion(union i2c_event *event)
> +{
> +	struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
> +	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
> +
> +	complete(&i2c_dev->msg_complete);
> +
> +	return 0;
> +}
> +
> +static int i2c_amd_connect_completion(union i2c_event *event)
> +{
> +	struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
> +	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
> +
> +	complete(&i2c_dev->msg_complete);
> +
> +	return 0;
> +}
> +
> +static const struct amd_i2c_pci_ops data_handler = {
> +		.read_complete = i2c_amd_read_completion,
> +		.write_complete = i2c_amd_write_completion,
> +		.connect_complete = i2c_amd_connect_completion,
> +};
> +
> +static int i2c_amd_pci_configure(struct amd_i2c_dev *i2c_dev)
> +{
> +	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> +
> +	amd_i2c_register_cb(i2c_common->mp2_dev, i2c_common);
> +	i2c_common->ops = &data_handler;
> +
> +	return 0;
> +}
> +
> +static int i2c_amd_pci_xconnect(struct amd_i2c_dev *i2c_dev, bool enable)
> +{
> +	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> +	unsigned long timeout;
> +
> +	reinit_completion(&i2c_dev->msg_complete);
> +	amd_mp2_connect(i2c_common, enable);
> +	timeout = wait_for_completion_timeout(&i2c_dev->msg_complete,
> +					      AMD_I2C_TIMEOUT);
> +	if (timeout == 0) {
> +		dev_err(&i2c_dev->pdev->dev,
> +			"i2c connection timed out\n");
> +		mutex_unlock(&i2c_dev->xfer_lock);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +static int i2c_amd_xfer_msg(struct amd_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
> +{
> +	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> +	unsigned long timeout;
> +	bool is_read = pmsg->flags & I2C_M_RD;
> +
> +	reinit_completion(&i2c_dev->msg_complete);
> +
> +	i2c_common->rw_cfg.slave_addr = pmsg->addr;
> +	i2c_common->rw_cfg.buf = (u32 *)pmsg->buf;
> +	i2c_common->rw_cfg.length = pmsg->len;
> +	i2c_dev->msg_buf = pmsg;
> +
> +	if (is_read)
> +		amd_mp2_read(i2c_common);
> +	else
> +		amd_mp2_write(i2c_common);
> +
> +	timeout = wait_for_completion_timeout
> +		(&i2c_dev->msg_complete, AMD_I2C_TIMEOUT);
> +	if (timeout == 0) {
> +		dev_err(&i2c_dev->pdev->dev,
> +			"i2c %s timed out\n",
> +			is_read ? "read" : "write");
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +static int i2c_amd_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> +{
> +	struct amd_i2c_dev *dev = i2c_get_adapdata(adap);
> +	int i;
> +	struct i2c_msg *pmsg;
> +	int err;
> +
> +	mutex_lock(&dev->xfer_lock);
> +
> +	if (dev->is_configured == 0) {
> +		i2c_amd_pci_configure(dev);
> +		i2c_amd_pci_xconnect(dev, true);
> +		dev->is_configured = 1;
> +	}
> +
> +	for (i = 0; i < num; i++) {
> +		pmsg = &msgs[i];
> +		err = i2c_amd_xfer_msg(dev, pmsg);
> +		if (err)
> +			break;
> +	}
> +
> +	mutex_unlock(&dev->xfer_lock);
> +
> +	if (err)
> +		return err;
> +	return num;
> +}
> +
> +static u32 i2c_amd_func(struct i2c_adapter *a)
> +{
> +	return I2C_FUNC_I2C;
> +}
> +
> +static const struct i2c_algorithm i2c_amd_algorithm = {
> +	.master_xfer = i2c_amd_xfer,
> +	.functionality = i2c_amd_func,
> +};
> +
> +static enum speed_enum i2c_amd_get_bus_speed(struct platform_device *pdev)
> +{
> +	u32 acpi_speed;
> +	int i;
> +	static const u32 supported_speeds[] = {
> +		0, 100000, 400000, 1000000, 1400000, 3400000
> +	};
> +
> +	acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
> +	/* round down to the lowest standard speed */
> +	for (i = 1; i < ARRAY_SIZE(supported_speeds); i++) {
> +		if (acpi_speed < supported_speeds[i])
> +			break;
> +	}
> +	acpi_speed = supported_speeds[i - 1];
> +
> +	switch (acpi_speed) {
> +	case 100000:
> +		return speed100k;
> +	case 400000:
> +		return speed400k;
> +	case 1000000:
> +		return speed1000k;
> +	case 1400000:
> +		return speed1400k;
> +	case 3400000:
> +		return speed3400k;
> +	default:
> +		return speed400k;
> +	}
> +}
> +
> +static struct device *i2c_amd_acpi_get_first_phys_node(struct acpi_device *adev)
> +{
> +	const struct acpi_device_physical_node *node;
> +
> +	if (list_empty(&adev->physical_node_list))
> +		return NULL;
> +
> +	node = list_first_entry(&adev->physical_node_list,
> +				struct acpi_device_physical_node, node);
> +	return node->dev;
> +}
> +
> +/*
> + * Assume that the first device listed by the _DEP method is the parent
> + * MP2 device
> + */
> +static struct pci_dev *i2c_amd_find_pci_parent(struct acpi_device *adev)
> +{
> +	struct acpi_device *parent_adev;
> +	struct device *phys_dev;
> +	struct acpi_handle_list dep_devices;
> +	acpi_status status;
> +
> +	if (!acpi_has_method(adev->handle, "_DEP"))
> +		return NULL;
> +
> +	status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
> +					 &dep_devices);

Several other callers of acpi_evaluate_reference() do call
acpi_has_method() first, but I'm pretty sure that's not necessary.  If
_DEP doesn't exist, acpi_evaluate_reference() should return an error
itself.

_DEP is for operation region dependencies.  I don't know enough about
ACPI to know why you're using it to find the PCI device related to an
ACPI device.  That doesn't really seem like an op region thing.

> +	if (ACPI_FAILURE(status) || !dep_devices.count)
> +		return NULL;
> +
> +	if (acpi_bus_get_device(dep_devices.handles[0], &parent_adev))
> +		return NULL;
> +	phys_dev = i2c_amd_acpi_get_first_phys_node(parent_adev);
> +
> +	if (!dev_is_pci(phys_dev))
> +		return NULL;
> +	return to_pci_dev(phys_dev);
> +}
> +
> +static int i2c_amd_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct amd_i2c_dev *i2c_dev;
> +	struct device *dev = &pdev->dev;
> +	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
> +	struct acpi_device *adev;
> +	struct pci_dev *parent_candidate = NULL;
> +
> +	i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL);
> +	if (!i2c_dev)
> +		return -ENOMEM;
> +
> +	i2c_dev->pdev = pdev;
> +
> +	if (!acpi_bus_get_device(handle, &adev)) {
> +		const char *uid = adev->pnp.unique_id;
> +
> +		if (!uid) {
> +			dev_err(&pdev->dev, "missing UID/bus id!\n");
> +			return -EINVAL;
> +		}
> +
> +		if (strcmp(uid, "0") == 0) {
> +			i2c_dev->i2c_common.bus_id = 0;
> +		} else if (strcmp(uid, "1") == 0) {
> +			i2c_dev->i2c_common.bus_id = 1;
> +		} else {
> +			dev_err(&pdev->dev,
> +				"incorrect UID/bus id \"%s\"!\n", uid);
> +			return -EINVAL;
> +		}
> +
> +		dev_dbg(&pdev->dev, "bus id is %u\n",
> +			i2c_dev->i2c_common.bus_id);
> +
> +		i2c_dev->i2c_common.i2c_speed = i2c_amd_get_bus_speed(pdev);
> +	} else {
> +		i2c_dev->i2c_common.i2c_speed = speed400k;
> +	}
> +
> +	/* setup i2c adapter description */
> +	i2c_dev->adapter.owner = THIS_MODULE;
> +	i2c_dev->adapter.algo = &i2c_amd_algorithm;
> +	i2c_dev->adapter.quirks = &amd_i2c_dev_quirks;
> +	i2c_dev->adapter.dev.parent = dev;
> +	i2c_dev->adapter.algo_data = i2c_dev;
> +	ACPI_COMPANION_SET(&i2c_dev->adapter.dev, ACPI_COMPANION(&pdev->dev));
> +	i2c_dev->adapter.dev.of_node = dev->of_node;
> +	snprintf(i2c_dev->adapter.name, sizeof(i2c_dev->adapter.name), "%s-%s",
> +		 "i2c_dev-i2c", dev_name(pdev->dev.parent));
> +
> +	if (adev)
> +		parent_candidate = i2c_amd_find_pci_parent(adev);
> +	i2c_dev->i2c_common.mp2_dev = amd_mp2_find_device(parent_candidate);
> +	if (!i2c_dev->i2c_common.mp2_dev) {
> +		dev_err(&pdev->dev,
> +			"%s Could not find MP2 PCI device for i2c adapter\n",
> +		       __func__);
> +		return -EINVAL;
> +	}
> +
> +	platform_set_drvdata(pdev, i2c_dev);
> +
> +	i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
> +
> +	init_completion(&i2c_dev->msg_complete);
> +	mutex_init(&i2c_dev->xfer_lock);
> +
> +	/* and finally attach to i2c layer */
> +	ret = i2c_add_adapter(&i2c_dev->adapter);
> +
> +	if (ret < 0)
> +		dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int i2c_amd_remove(struct platform_device *pdev)
> +{
> +	struct amd_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
> +	struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> +
> +	i2c_amd_pci_xconnect(i2c_dev, false);
> +
> +	amd_i2c_unregister_cb(i2c_common->mp2_dev, i2c_common);
> +	i2c_del_adapter(&i2c_dev->adapter);
> +
> +	return 0;
> +}
> +
> +static const struct acpi_device_id i2c_amd_acpi_match[] = {
> +		{ "AMDI0011" },
> +		{ },
> +};
> +MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match);
> +
> +static struct platform_driver amd_i2c_plat_driver = {
> +		.probe = i2c_amd_probe,
> +		.remove = i2c_amd_remove,
> +		.driver = {
> +				.name = "i2c_amd_plat_mp2",
> +				.acpi_match_table = ACPI_PTR
> +						(i2c_amd_acpi_match),
> +		},
> +};
> +
> +module_platform_driver(amd_i2c_plat_driver);
> +
> +MODULE_DESCRIPTION("AMD MP2 I2C Platform Driver");
> +MODULE_AUTHOR("Nehal Shah <nehal-bakulchandra.shah@amd.com>");
> +MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
> +MODULE_LICENSE("Dual BSD/GPL");
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller
  2018-10-30 20:56 ` Bjorn Helgaas
@ 2018-10-30 21:47   ` Tobias Thomer
       [not found]   ` <CAHYSBa8rpRS8suDdE-mfem_Gi3HYVXRydTm3PESnkzFVq2LXrA@mail.gmail.com>
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Tobias Thomer @ 2018-10-30 21:47 UTC (permalink / raw)
  To: helgaas
  Cc: syniurge, linux-i2c, wsa, Nehal-bakulchandra.Shah,
	Shyam-sundar.S-k, sandeep.singh, linux-kernel, rjw, lenb,
	linux-acpi

I've tested v7 on a Yoga 530 and it seems to work (sometimes for
hours) but it randomly dies with a i2c read timeout

[ 9562.237020] i2c_amd_plat_mp2 AMDI0011:00: i2c read timed out

and reloading/removing of the module results in this:

[ 9703.591021] pcie_mp2_amd 0000:03:00.7: length 0 in event doesn't
match buffer length 64!
[ 9703.591030] pcie_mp2_amd 0000:03:00.7: unexpected slave address 0
(expected: 2c)!
[ 9703.863740] i2c_amd_plat_mp2 AMDI0011:01: i2c connection timed out
[ 9707.596826] INFO: task irq/67-WCOM517E:340 blocked for more than 120 seconds.
[ 9707.596838]       Tainted: G           OE     4.19.0-v7 #1
[ 9707.596841] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs"
disables this message.
[ 9707.596845] irq/67-WCOM517E D    0   340      2 0x80000080
[ 9707.596851] Call Trace:
[ 9707.596868]  ? __schedule+0x29b/0x8b0
[ 9707.596873]  schedule+0x32/0x90
[ 9707.596875]  schedule_preempt_disabled+0x14/0x20
[ 9707.596879]  __mutex_lock.isra.0+0x217/0x520
[ 9707.596884]  ? __switch_to_asm+0x40/0x70
[ 9707.596887]  ? __switch_to_asm+0x34/0x70
[ 9707.596890]  ? __switch_to_asm+0x34/0x70
[ 9707.596898]  amd_mp2_read+0x4f/0x17b [i2c_amd_pci_mp2]
[ 9707.596912]  i2c_amd_xfer+0x61/0x150 [i2c_amd_plat_mp2]
[ 9707.596919]  __i2c_transfer+0x142/0x480
[ 9707.596922]  ? _raw_spin_unlock_irq+0x1d/0x30
[ 9707.596926]  ? irq_forced_thread_fn+0x70/0x70
[ 9707.596929]  i2c_transfer+0x51/0xc0
[ 9707.596932]  i2c_transfer_buffer_flags+0x4c/0x70
[ 9707.596937]  i2c_hid_irq+0x3c/0x130 [i2c_hid]
[ 9707.596941]  irq_thread_fn+0x1f/0x50
[ 9707.596944]  irq_thread+0xf7/0x1a0
[ 9707.596946]  ? irq_thread_check_affinity.part.3+0xa0/0xa0
[ 9707.596949]  ? irq_thread_dtor+0xb0/0xb0
[ 9707.596953]  kthread+0x112/0x130
[ 9707.596956]  ? kthread_park+0x80/0x80
[ 9707.596959]  ret_from_fork+0x22/0x40

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller
       [not found]   ` <CAHYSBa8rpRS8suDdE-mfem_Gi3HYVXRydTm3PESnkzFVq2LXrA@mail.gmail.com>
@ 2018-11-04 16:41     ` Elie Morisse
  0 siblings, 0 replies; 6+ messages in thread
From: Elie Morisse @ 2018-11-04 16:41 UTC (permalink / raw)
  To: Tobias Thomer
  Cc: helgaas, linux-i2c, Wolfram Sang, Nehal-bakulchandra.Shah,
	Shyam-sundar.S-k, sandeep.singh, linux-kernel, rjw, lenb,
	linux-acpi

The errors on module exit and the hang after a read/write timeout should be
fixed in v8, someone else reported the same issue here:
https://github.com/Syniurge/i2c-amd-mp2/issues/1

Weird that despite a lot of trying by doing random stuff with my touchpad and
touchscreen neither never ever timed out on my Yoga 530.

Le mar. 30 oct. 2018 à 18:41, Tobias Thomer <thomer.tobias@gmail.com> a écrit :
>
> I've tested this patch on a Yoga 530 and it seems to work (sometimes for hours) but it randomly dies with a i2c read timeout
>
> [ 9562.237020] i2c_amd_plat_mp2 AMDI0011:00: i2c read timed out
>
> and reloading/removing of the module results in this:
>
> [ 9703.591021] pcie_mp2_amd 0000:03:00.7: length 0 in event doesn't match buffer length 64!
> [ 9703.591030] pcie_mp2_amd 0000:03:00.7: unexpected slave address 0 (expected: 2c)!
> [ 9703.863740] i2c_amd_plat_mp2 AMDI0011:01: i2c connection timed out
> [ 9707.596826] INFO: task irq/67-WCOM517E:340 blocked for more than 120 seconds.
> [ 9707.596838]       Tainted: G           OE     4.19.0-v7 #1
> [ 9707.596841] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> [ 9707.596845] irq/67-WCOM517E D    0   340      2 0x80000080
> [ 9707.596851] Call Trace:
> [ 9707.596868]  ? __schedule+0x29b/0x8b0
> [ 9707.596873]  schedule+0x32/0x90
> [ 9707.596875]  schedule_preempt_disabled+0x14/0x20
> [ 9707.596879]  __mutex_lock.isra.0+0x217/0x520
> [ 9707.596884]  ? __switch_to_asm+0x40/0x70
> [ 9707.596887]  ? __switch_to_asm+0x34/0x70
> [ 9707.596890]  ? __switch_to_asm+0x34/0x70
> [ 9707.596898]  amd_mp2_read+0x4f/0x17b [i2c_amd_pci_mp2]
> [ 9707.596912]  i2c_amd_xfer+0x61/0x150 [i2c_amd_plat_mp2]
> [ 9707.596919]  __i2c_transfer+0x142/0x480
> [ 9707.596922]  ? _raw_spin_unlock_irq+0x1d/0x30
> [ 9707.596926]  ? irq_forced_thread_fn+0x70/0x70
> [ 9707.596929]  i2c_transfer+0x51/0xc0
> [ 9707.596932]  i2c_transfer_buffer_flags+0x4c/0x70
> [ 9707.596937]  i2c_hid_irq+0x3c/0x130 [i2c_hid]
> [ 9707.596941]  irq_thread_fn+0x1f/0x50
> [ 9707.596944]  irq_thread+0xf7/0x1a0
> [ 9707.596946]  ? irq_thread_check_affinity.part.3+0xa0/0xa0
> [ 9707.596949]  ? irq_thread_dtor+0xb0/0xb0
> [ 9707.596953]  kthread+0x112/0x130
> [ 9707.596956]  ? kthread_park+0x80/0x80
> [ 9707.596959]  ret_from_fork+0x22/0x40

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller
  2018-10-30 20:56 ` Bjorn Helgaas
  2018-10-30 21:47   ` Tobias Thomer
       [not found]   ` <CAHYSBa8rpRS8suDdE-mfem_Gi3HYVXRydTm3PESnkzFVq2LXrA@mail.gmail.com>
@ 2018-11-04 16:43   ` Elie Morisse
  2018-11-11 17:36   ` Elie Morisse
  3 siblings, 0 replies; 6+ messages in thread
From: Elie Morisse @ 2018-11-04 16:43 UTC (permalink / raw)
  To: helgaas
  Cc: linux-i2c, Wolfram Sang, Nehal-bakulchandra.Shah,
	Shyam-sundar.S-k, sandeep.singh, linux-kernel, rjw, lenb,
	linux-acpi

[-- Attachment #1: Type: text/plain, Size: 4025 bytes --]

Le mar. 30 oct. 2018 à 17:56, Bjorn Helgaas <helgaas@kernel.org> a écrit :
> I'm dubious about this two-driver structure.  If I understand
> correctly (and it's very possible that I don't), the PCI driver
> (amd_mp2_pci_probe()) is the real owner of the i2c adapter: it
> claims the PCI device, claims its BARs, and requests an IRQ.
>
> The i2c_amd_probe() code *looks* like a platform driver that claims
> AMDI0011 devices from the ACPI namespace, but I don't think it's
> really a driver.  It looks like it exists mainly to extract some
> information (bus speed and maybe a bus number?) from the namespace,
> then to call i2c_add_adapter().
>
> It looks like i2c_amd_probe() must run *after* amd_mp2_pci_probe(),
> but there's no way to really enforce that ordering.
>
> And i2c-amd-plat-mp2 contains the i2c_amd_algorithm functions, which
> operate on the PCI device, which requires exported interfaces
> (amd_mp2_read(), amd_mp2_write()) that are implemented in the PCI
> driver but called from the platform part.

> It seems like there should be a way to put the ACPI lookups into
> i2c-amd-pci-mp2 so there's only one driver.

I merged the two drivers into one module in v8 I just submitted, but this
doesn't enforce that the platform probe occur after the PCI probe.

(and from looking at the drivers/acpi/ code _DEP doesn't seem to help)

> _DEP is for operation region dependencies.  I don't know enough about
> ACPI to know why you're using it to find the PCI device related to an
> ACPI device.  That doesn't really seem like an op region thing.

For the Yoga 530 that seems to be the only available hint at which MP2
device those ACPI devices are related to.

I attached the DSDT of the Yoga 530-14ARR
(also pasted here: https://paste.kde.org/pjobniftq)

Relevant parts are:

    Scope (_SB)
    {
        Device (PCI0)
        {
// ....
            Device (GP17)
            {
// ...
                Device (MP2C)
                {
                    Name (_ADR, 0x07)  // _ADR: Address
                }
// ...
            }
        }
    }

    Scope (_SB)
    {
        Device (I2CA)
        {
            Name (_HID, "AMDI0011")  // _HID: Hardware ID
            Name (_UID, Zero)  // _UID: Unique ID
            Name (_ADR, Zero)  // _ADR: Address
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                IRQ (Edge, ActiveHigh, Exclusive, )
                    {10}
                Memory32Fixed (ReadWrite,
                    0xFEDC2000,         // Address Base
                    0x00001000,         // Address Length
                    )
            })
            Name (_DEP, Package (0x01)  // _DEP: Dependencies
            {
                ^PCI0.GP17.MP2C
            })
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Method (RSET, 0, NotSerialized)
            {
                SRAD (0x05, 0xC8)
            }
        }

        Device (I2CB)
        {
            Name (_HID, "AMDI0011")  // _HID: Hardware ID
            Name (_UID, One)  // _UID: Unique ID
            Name (_ADR, One)  // _ADR: Address
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                IRQ (Edge, ActiveHigh, Exclusive, )
                    {11}
                Memory32Fixed (ReadWrite,
                    0xFEDC3000,         // Address Base
                    0x00001000,         // Address Length
                    )
            })
            Name (_DEP, Package (0x01)  // _DEP: Dependencies
            {
                ^PCI0.GP17.MP2C
            })
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Method (RSET, 0, NotSerialized)
            {
                SRAD (0x06, 0xC8)
            }
        }
    }

[-- Attachment #2: dsdt.dsl --]
[-- Type: text/x-dsl, Size: 268997 bytes --]

/*
 * Intel ACPI Component Architecture
 * AML/ASL+ Disassembler version 20180105 (64-bit version)
 * Copyright (c) 2000 - 2018 Intel Corporation
 * 
 * Disassembling to symbolic ASL+ operators
 *
 * Disassembly of dsdt.dat, Thu Sep  6 13:46:21 2018
 *
 * Original Table Header:
 *     Signature        "DSDT"
 *     Length           0x000063BC (25532)
 *     Revision         0x01 **** 32-bit table (V1), no 64-bit math support
 *     Checksum         0x9F
 *     OEM ID           "LENOVO"
 *     OEM Table ID     "CB-01   "
 *     OEM Revision     0x00000001 (1)
 *     Compiler ID      "ACPI"
 *     Compiler Version 0x00040000 (262144)
 */
DefinitionBlock ("", "DSDT", 1, "LENOVO", "CB-01   ", 0x00000001)
{
    /*
     * iASL Warning: There were 8 external control methods found during
     * disassembly, but only 0 were resolved (8 unresolved). Additional
     * ACPI tables may be required to properly disassemble the code. This
     * resulting disassembler output file may not compile because the
     * disassembler did not know how many arguments to assign to the
     * unresolved methods. Note: SSDTs can be dynamically loaded at
     * runtime and may or may not be available via the host OS.
     *
     * To specify the tables needed to resolve external control method
     * references, the -e option can be used to specify the filenames.
     * Example iASL invocations:
     *     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml
     *     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml
     *     iasl -e ssdt*.aml -d dsdt.aml
     *
     * In addition, the -fe option can be used to specify a file containing
     * control method external declarations with the associated method
     * argument counts. Each line of the file must be of the form:
     *     External (<method pathname>, MethodObj, <argument count>)
     * Invocation:
     *     iasl -fe refs.txt -d dsdt.aml
     *
     * The following methods were unresolved and many not compile properly
     * because the disassembler had to guess at the number of arguments
     * required for each:
     */
    External (_SB_.APTS, MethodObj)    // Warning: Unknown method, guessing 3 arguments
    External (_SB_.AWAK, MethodObj)    // Warning: Unknown method, guessing 1 arguments
    External (_SB_.TPM2.PTS_, MethodObj)    // Warning: Unknown method, guessing 1 arguments
    External (AFN4, MethodObj)    // Warning: Unknown method, guessing 1 arguments
    External (AFN7, MethodObj)    // Warning: Unknown method, guessing 1 arguments
    External (ALIB, MethodObj)    // Warning: Unknown method, guessing 2 arguments
    External (MPTS, MethodObj)    // Warning: Unknown method, guessing 1 arguments
    External (MWAK, MethodObj)    // Warning: Unknown method, guessing 1 arguments

    OperationRegion (DBG0, SystemIO, 0x80, One)
    Field (DBG0, ByteAcc, NoLock, Preserve)
    {
        IO80,   8
    }

    OperationRegion (DBG1, SystemIO, 0x80, 0x02)
    Field (DBG1, WordAcc, NoLock, Preserve)
    {
        P80H,   16
    }

    OperationRegion (ACMS, SystemIO, 0x72, 0x02)
    Field (ACMS, ByteAcc, NoLock, Preserve)
    {
        ACMX,   8, 
        ACMA,   8
    }

    IndexField (ACMX, ACMA, ByteAcc, NoLock, Preserve)
    {
        Offset (0xB9), 
        IMEN,   8
    }

    OperationRegion (PSMI, SystemIO, 0xB0, 0x02)
    Field (PSMI, ByteAcc, NoLock, Preserve)
    {
        APMC,   8, 
        APMD,   8
    }

    OperationRegion (PMRG, SystemIO, 0x0CD6, 0x02)
    Field (PMRG, ByteAcc, NoLock, Preserve)
    {
        PMRI,   8, 
        PMRD,   8
    }

    IndexField (PMRI, PMRD, ByteAcc, NoLock, Preserve)
    {
            ,   6, 
        HPEN,   1, 
        Offset (0x60), 
        P1EB,   16, 
        Offset (0xF0), 
            ,   3, 
        RSTU,   1
    }

    OperationRegion (GSMM, SystemMemory, 0xFED80000, 0x1000)
    Field (GSMM, AnyAcc, NoLock, Preserve)
    {
        Offset (0x288), 
            ,   1, 
        CLPS,   1, 
        Offset (0x2B0), 
            ,   2, 
        SLPS,   2, 
        Offset (0x3BB), 
            ,   6, 
        PWDE,   1, 
        Offset (0x3E4), 
        BLNK,   2
    }

    OperationRegion (P1E0, SystemIO, P1EB, 0x04)
    Field (P1E0, ByteAcc, NoLock, Preserve)
    {
            ,   14, 
        PEWS,   1, 
        WSTA,   1, 
            ,   14, 
        PEWD,   1
    }

    OperationRegion (IOCC, SystemIO, 0x0400, 0x80)
    Field (IOCC, ByteAcc, NoLock, Preserve)
    {
        Offset (0x01), 
            ,   2, 
        RTCS,   1
    }

    Name (PRWP, Package (0x02)
    {
        Zero, 
        Zero
    })
    Method (GPRW, 2, NotSerialized)
    {
        PRWP [Zero] = Arg0
        PRWP [One] = Arg1
        If ((DAS3 == Zero))
        {
            If ((Arg1 <= 0x03))
            {
                PRWP [One] = Zero
            }
        }

        Return (PRWP) /* \PRWP */
    }

    Method (SPTS, 1, NotSerialized)
    {
        If ((Arg0 == 0x03))
        {
            BLNK = One
        }

        If (((Arg0 == 0x04) || (Arg0 == 0x05)))
        {
            BLNK = Zero
        }

        If ((Arg0 == 0x03))
        {
            RSTU = Zero
        }

        CLPS = One
        SLPS = One
        PEWS = PEWS /* \PEWS */
    }

    Method (SWAK, 1, NotSerialized)
    {
        BLNK = 0x03
        If ((Arg0 == 0x03))
        {
            RSTU = One
        }

        PEWS = PEWS /* \PEWS */
        PWDE = One
        PEWD = Zero
    }

    OperationRegion (GNVS, SystemMemory, 0xBF7BBA98, 0x00000186)
    Field (GNVS, AnyAcc, NoLock, Preserve)
    {
        SMIF,   8, 
        PRM0,   8, 
        PRM1,   8, 
        BRTL,   8, 
        TLST,   8, 
        IGDS,   8, 
        LCDA,   16, 
        CSTE,   16, 
        NSTE,   16, 
        CADL,   16, 
        PADL,   16, 
        LIDS,   8, 
        PWRS,   8, 
        BVAL,   32, 
        ADDL,   16, 
        BCMD,   8, 
        SBFN,   8, 
        DID,    32, 
        INFO,   2048, 
        TOML,   8, 
        TOMH,   8, 
        CEBP,   8, 
        C0LS,   8, 
        C1LS,   8, 
        C0HS,   8, 
        C1HS,   8, 
        ROMS,   32, 
        MUXF,   8, 
        PDDN,   8, 
        CNSB,   8, 
        RDHW,   8, 
        DAS3,   8, 
        TNBH,   8, 
        TCP0,   8, 
        TCP1,   8, 
        ATNB,   8, 
        PCP0,   8, 
        PCP1,   8, 
        PWMN,   8, 
        LPTY,   8, 
        M92D,   8, 
        WKPM,   8, 
        ALST,   8, 
        AFUC,   8, 
        EXUS,   8, 
        GV0E,   8, 
        WLSH,   8, 
        TSSS,   8, 
        AOZP,   8, 
        TZFG,   8, 
        BPS0,   8, 
        NAPC,   8, 
        PCBA,   32, 
        PCBL,   32, 
        WLAN,   8, 
        BLTH,   8, 
        GPSS,   8, 
        NFCS,   8, 
        SBTY,   8, 
        BDID,   16, 
        MWTT,   8, 
        ACPM,   8, 
        KBCS,   8, 
        ACEC,   8, 
        MM64,   8, 
        HMB1,   64, 
        HMB2,   64, 
        HMM1,   64, 
        HMM2,   64, 
        HML1,   64, 
        HML2,   64
    }

    OperationRegion (OGNS, SystemMemory, 0xBF7A0E98, 0x0000000B)
    Field (OGNS, AnyAcc, Lock, Preserve)
    {
        EGPO,   8, 
        BTBE,   8, 
        M2WL,   8, 
        THPN,   8, 
        PBAR,   8, 
        THPD,   8, 
        OG06,   8, 
        OG07,   8, 
        OG08,   8, 
        OG09,   8, 
        OG10,   8
    }

    Method (SCMP, 2, NotSerialized)
    {
        Name (STG1, Buffer (0x50){})
        Name (STG2, Buffer (0x50){})
        STG1 = Arg0
        STG2 = Arg1
        If ((SizeOf (Arg0) != SizeOf (Arg1)))
        {
            Return (Zero)
        }

        Local0 = Zero
        While ((Local0 < SizeOf (Arg0)))
        {
            If ((DerefOf (STG1 [Local0]) != DerefOf (STG2 [Local0]
                )))
            {
                Return (Zero)
            }

            Local0++
        }

        Return (One)
    }

    Name (WNOS, Zero)
    Name (MYOS, Zero)
    Name (HTTS, Zero)
    Name (OSTB, Ones)
    Name (TPOS, Zero)
    Name (LINX, Zero)
    Name (OSSP, Zero)
    Method (SEQL, 2, Serialized)
    {
        Local0 = SizeOf (Arg0)
        Local1 = SizeOf (Arg1)
        If ((Local0 != Local1))
        {
            Return (Zero)
        }

        Name (BUF0, Buffer (Local0){})
        BUF0 = Arg0
        Name (BUF1, Buffer (Local0){})
        BUF1 = Arg1
        Local2 = Zero
        While ((Local2 < Local0))
        {
            Local3 = DerefOf (BUF0 [Local2])
            Local4 = DerefOf (BUF1 [Local2])
            If ((Local3 != Local4))
            {
                Return (Zero)
            }

            Local2++
        }

        Return (One)
    }

    Method (OSTP, 0, NotSerialized)
    {
        If ((OSTB == Ones))
        {
            If (CondRefOf (\_OSI, Local0))
            {
                OSTB = Zero
                TPOS = Zero
                If (_OSI ("Windows 2001"))
                {
                    OSTB = 0x08
                    TPOS = 0x08
                }

                If (_OSI ("Windows 2001.1"))
                {
                    OSTB = 0x20
                    TPOS = 0x20
                }

                If (_OSI ("Windows 2001 SP1"))
                {
                    OSTB = 0x10
                    TPOS = 0x10
                }

                If (_OSI ("Windows 2001 SP2"))
                {
                    OSTB = 0x11
                    TPOS = 0x11
                }

                If (_OSI ("Windows 2001 SP3"))
                {
                    OSTB = 0x12
                    TPOS = 0x12
                }

                If (_OSI ("Windows 2006"))
                {
                    OSTB = 0x40
                    TPOS = 0x40
                }

                If (_OSI ("Windows 2006 SP1"))
                {
                    OSTB = 0x41
                    TPOS = 0x41
                    OSSP = One
                }

                If (_OSI ("Windows 2009"))
                {
                    OSSP = One
                    OSTB = 0x50
                    TPOS = 0x50
                }

                If (_OSI ("Windows 2012"))
                {
                    OSSP = One
                    OSTB = 0x60
                    TPOS = 0x60
                }

                If (_OSI ("Windows 2013"))
                {
                    OSSP = One
                    OSTB = 0x61
                    TPOS = 0x61
                }

                If (_OSI ("Windows 2015"))
                {
                    OSSP = One
                    OSTB = 0x70
                    TPOS = 0x70
                }

                If (_OSI ("Linux"))
                {
                    LINX = One
                    OSTB = 0x80
                    TPOS = 0x80
                }
            }
            ElseIf (CondRefOf (\_OS, Local0))
            {
                If (SEQL (_OS, "Microsoft Windows"))
                {
                    OSTB = One
                    TPOS = One
                }
                ElseIf (SEQL (_OS, "Microsoft WindowsME: Millennium Edition"))
                {
                    OSTB = 0x02
                    TPOS = 0x02
                }
                ElseIf (SEQL (_OS, "Microsoft Windows NT"))
                {
                    OSTB = 0x04
                    TPOS = 0x04
                }
                Else
                {
                    OSTB = Zero
                    TPOS = Zero
                }
            }
            Else
            {
                OSTB = Zero
                TPOS = Zero
            }
        }

        Return (OSTB) /* \OSTB */
    }

    Name (BUFN, Zero)
    Name (MBUF, Buffer (0x1000){})
    OperationRegion (MDBG, SystemMemory, 0xBF399018, 0x00001004)
    Field (MDBG, AnyAcc, Lock, Preserve)
    {
        MDG0,   32768
    }

    Method (DB2H, 1, Serialized)
    {
        SHOW (Arg0)
        MDGC (0x20)
        MDG0 = MBUF /* \MBUF */
    }

    Method (DW2H, 1, Serialized)
    {
        Local0 = Arg0
        Local1 = (Arg0 >> 0x08)
        Local0 &= 0xFF
        Local1 &= 0xFF
        DB2H (Local1)
        BUFN--
        DB2H (Local0)
    }

    Method (DD2H, 1, Serialized)
    {
        Local0 = Arg0
        Local1 = (Arg0 >> 0x10)
        Local0 &= 0xFFFF
        Local1 &= 0xFFFF
        DW2H (Local1)
        BUFN--
        DW2H (Local0)
    }

    Method (MBGS, 1, Serialized)
    {
        Local0 = SizeOf (Arg0)
        Name (BUFS, Buffer (Local0){})
        BUFS = Arg0
        MDGC (0x20)
        While (Local0)
        {
            MDGC (DerefOf (BUFS [(SizeOf (Arg0) - Local0)]))
            Local0--
        }

        MDG0 = MBUF /* \MBUF */
    }

    Method (SHOW, 1, Serialized)
    {
        MDGC (NTOC ((Arg0 >> 0x04)))
        MDGC (NTOC (Arg0))
    }

    Method (LINE, 0, Serialized)
    {
        Local0 = BUFN /* \BUFN */
        Local0 &= 0x0F
        While (Local0)
        {
            MDGC (Zero)
            Local0++
            Local0 &= 0x0F
        }
    }

    Method (MDGC, 1, Serialized)
    {
        MBUF [BUFN] = Arg0
        BUFN += One
        If ((BUFN > 0x0FFF))
        {
            BUFN &= 0x0FFF
            UP_L (One)
        }
    }

    Method (UP_L, 1, Serialized)
    {
        Local2 = Arg0
        Local2 <<= 0x04
        MOVE (Local2)
        Local3 = (0x1000 - Local2)
        While (Local2)
        {
            MBUF [Local3] = Zero
            Local3++
            Local2--
        }
    }

    Method (MOVE, 1, Serialized)
    {
        Local4 = Arg0
        BUFN = Zero
        Local5 = (0x1000 - Local4)
        While (Local5)
        {
            Local5--
            MBUF [BUFN] = DerefOf (MBUF [Local4])
            BUFN++
            Local4++
        }
    }

    Method (NTOC, 1, Serialized)
    {
        Local0 = (Arg0 & 0x0F)
        If ((Local0 < 0x0A))
        {
            Local0 += 0x30
        }
        Else
        {
            Local0 += 0x37
        }

        Return (Local0)
    }

    Scope (_PR)
    {
        Processor (C000, 0x00, 0x00000410, 0x06){}
        Processor (C001, 0x01, 0x00000410, 0x06){}
        Processor (C002, 0x02, 0x00000410, 0x06){}
        Processor (C003, 0x03, 0x00000410, 0x06){}
        Processor (C004, 0x04, 0x00000410, 0x06){}
        Processor (C005, 0x05, 0x00000410, 0x06){}
        Processor (C006, 0x06, 0x00000410, 0x06){}
        Processor (C007, 0x07, 0x00000410, 0x06){}
    }

    Name (_S0, Package (0x04)  // _S0_: S0 System State
    {
        Zero, 
        Zero, 
        Zero, 
        Zero
    })
    If ((DAS3 == One))
    {
        Name (_S3, Package (0x04)  // _S3_: S3 System State
        {
            0x03, 
            0x03, 
            Zero, 
            Zero
        })
    }

    Name (_S4, Package (0x04)  // _S4_: S4 System State
    {
        0x04, 
        0x04, 
        Zero, 
        Zero
    })
    Name (_S5, Package (0x04)  // _S5_: S5 System State
    {
        0x05, 
        0x05, 
        Zero, 
        Zero
    })
    Scope (_GPE)
    {
        Method (_L08, 0, NotSerialized)  // _Lxx: Level-Triggered GPE
        {
            Notify (\_SB.PCI0.GPP0, 0x02) // Device Wake
            Notify (\_SB.PCI0.GPP1, 0x02) // Device Wake
            Notify (\_SB.PCI0.GPP2, 0x02) // Device Wake
            Notify (\_SB.PCI0.GPP3, 0x02) // Device Wake
            Notify (\_SB.PCI0.GPP4, 0x02) // Device Wake
            Notify (\_SB.PCI0.GPP5, 0x02) // Device Wake
            Notify (\_SB.PCI0.GPP6, 0x02) // Device Wake
            Notify (\_SB.PCI0.GP17, 0x02) // Device Wake
            Notify (\_SB.PCI0.GP18, 0x02) // Device Wake
        }

        Method (_L19, 0, NotSerialized)  // _Lxx: Level-Triggered GPE
        {
            Notify (\_SB.PCI0.GP17.XHC0, 0x02) // Device Wake
            Notify (\_SB.PCI0.GP17.XHC1, 0x02) // Device Wake
        }
    }

    Name (PICM, Zero)
    Name (GPIC, Zero)
    Method (_PIC, 1, NotSerialized)  // _PIC: Interrupt Model
    {
        PICM = Arg0
        GPIC = Arg0
        If (PICM)
        {
            \_SB.DSPI ()
            If (NAPC)
            {
                \_SB.PCI0.NAPE ()
            }
        }
    }

    Method (_PTS, 1, NotSerialized)  // _PTS: Prepare To Sleep
    {
        SPTS (Arg0)
        If ((Arg0 == One))
        {
            \_SB.S80H (0x51)
        }

        If ((Arg0 == 0x03))
        {
            \_SB.S80H (0x53)
            SLPS = One
        }

        If ((Arg0 == 0x04))
        {
            \_SB.S80H (0x54)
            SLPS = One
            RSTU = One
        }

        If ((Arg0 == 0x05))
        {
            \_SB.S80H (0x55)
            BCMD = 0x90
            \_SB.BSMI (Zero)
            \_SB.GSMI (0x03)
        }

        If (CondRefOf (\_SB.TPM2.PTS))
        {
            \_SB.TPM2.PTS (Arg0)
        }

        \_SB.APTS (Arg0, MPTS (Arg0))
    }

    OperationRegion (XMOS, SystemIO, 0x72, 0x02)
    Field (XMOS, ByteAcc, Lock, Preserve)
    {
        XIDX,   8, 
        XDAT,   8
    }

    IndexField (XIDX, XDAT, ByteAcc, Lock, Preserve)
    {
        Offset (0x74), 
        WKSR,   8, 
        Offset (0xD0), 
        WLNS,   1, 
        BTNS,   1
    }

    Method (_WAK, 1, NotSerialized)  // _WAK: Wake
    {
        SWAK (Arg0)
        \_SB.AWAK (Arg0)
        If (((Arg0 == 0x03) || (Arg0 == 0x04)))
        {
            If ((GPIC != Zero))
            {
                \_SB.DSPI ()
                If (NAPC)
                {
                    \_SB.PCI0.NAPE ()
                }
            }
        }

        If ((Arg0 == 0x03))
        {
            \_SB.S80H (0xE3)
            If (((WKSR == 0x06) || (WKSR == 0x07)))
            {
                Notify (\_SB.GPIO, Zero) // Bus Check
                Notify (\_SB.I2CA, Zero) // Bus Check
                Notify (\_SB.I2CB, Zero) // Bus Check
                Notify (\_SB.I2CD, Zero) // Bus Check
            }
            Else
            {
                Notify (\_SB.PWRB, 0x02) // Device Wake
                Notify (_SB, Zero) // Bus Check
            }
        }

        If ((Arg0 == 0x04))
        {
            \_SB.S80H (0xE4)
            Notify (\_SB.PWRB, 0x02) // Device Wake
            Notify (_SB, Zero) // Bus Check
        }

        If ((TPOS == 0x40))
        {
            Local0 = One
        }

        If ((TPOS == 0x80))
        {
            Local0 = 0x02
        }

        If ((TPOS == 0x50))
        {
            Local0 = 0x03
        }

        If ((TPOS == 0x60))
        {
            Local0 = 0x04
        }

        If ((TPOS == 0x61))
        {
            Local0 = 0x05
        }

        If ((TPOS == 0x70))
        {
            Local0 = 0x06
        }

        \_SB.PCI0.LPC0.EC0.OSTY = Local0
        MWAK (Arg0)
        Return (Zero)
    }

    Scope (_SB)
    {
        Device (PCI0)
        {
            Name (_HID, EisaId ("PNP0A08") /* PCI Express Bus */)  // _HID: Hardware ID
            Name (_CID, EisaId ("PNP0A03") /* PCI Bus */)  // _CID: Compatible ID
            Name (_UID, One)  // _UID: Unique ID
            Name (_BBN, Zero)  // _BBN: BIOS Bus Number
            Name (_ADR, Zero)  // _ADR: Address
            Method (_INI, 0, NotSerialized)  // _INI: Initialize
            {
                If ((GPIC != Zero))
                {
                    DSPI ()
                    If (\NAPC)
                    {
                        NAPE ()
                    }
                }

                OSTP ()
            }

            Name (SUPP, Zero)
            Name (CTRL, Zero)
            Method (_OSC, 4, NotSerialized)  // _OSC: Operating System Capabilities
            {
                CreateDWordField (Arg3, Zero, CDW1)
                CreateDWordField (Arg3, 0x04, CDW2)
                CreateDWordField (Arg3, 0x08, CDW3)
                If ((Arg0 == ToUUID ("33db4d5b-1ff7-401c-9657-7441c03dd766") /* PCI Host Bridge Device */))
                {
                    SUPP = CDW2 /* \_SB_.PCI0._OSC.CDW2 */
                    CTRL = CDW3 /* \_SB_.PCI0._OSC.CDW3 */
                    If (((SUPP & 0x16) != 0x16))
                    {
                        CTRL &= 0x1E
                    }

                    CTRL &= 0x1D
                    If (~(CDW1 & One))
                    {
                        If ((CTRL & One)){}
                        If ((CTRL & 0x04)){}
                        If ((CTRL & 0x10)){}
                    }

                    If ((Arg1 != One))
                    {
                        CDW1 |= 0x08
                    }

                    If ((CDW3 != CTRL))
                    {
                        CDW1 |= 0x10
                    }

                    CDW3 = CTRL /* \_SB_.PCI0.CTRL */
                    Return (Arg3)
                }
                Else
                {
                    CDW1 |= 0x04
                    Return (Arg3)
                }
            }

            Method (TOM, 0, NotSerialized)
            {
                Local0 = (TOML * 0x00010000)
                Local1 = (TOMH * 0x01000000)
                Local0 += Local1
                Return (Local0)
            }

            Name (CRES, ResourceTemplate ()
            {
                WordBusNumber (ResourceProducer, MinFixed, MaxFixed, SubDecode,
                    0x0000,             // Granularity
                    0x0000,             // Range Minimum
                    0x00FF,             // Range Maximum
                    0x0000,             // Translation Offset
                    0x0100,             // Length
                    0x00,, )
                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
                    0x0000,             // Granularity
                    0x0000,             // Range Minimum
                    0x0CF7,             // Range Maximum
                    0x0000,             // Translation Offset
                    0x0CF8,             // Length
                    0x00,, , TypeStatic, DenseTranslation)
                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
                    0x0000,             // Granularity
                    0x0D00,             // Range Minimum
                    0xFFFF,             // Range Maximum
                    0x0000,             // Translation Offset
                    0xF300,             // Length
                    ,, , TypeStatic, DenseTranslation)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000A0000,         // Range Minimum
                    0x000BFFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00020000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, Cacheable, ReadOnly,
                    0x00000000,         // Granularity
                    0x000C0000,         // Range Minimum
                    0x000C3FFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, Cacheable, ReadOnly,
                    0x00000000,         // Granularity
                    0x000C4000,         // Range Minimum
                    0x000C7FFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadOnly,
                    0x00000000,         // Granularity
                    0x000C8000,         // Range Minimum
                    0x000CBFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadOnly,
                    0x00000000,         // Granularity
                    0x000CC000,         // Range Minimum
                    0x000CFFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000D0000,         // Range Minimum
                    0x000D3FFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000D4000,         // Range Minimum
                    0x000D7FFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000D8000,         // Range Minimum
                    0x000DBFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000DC000,         // Range Minimum
                    0x000DFFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000E0000,         // Range Minimum
                    0x000E3FFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000E4000,         // Range Minimum
                    0x000E7FFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000E8000,         // Range Minimum
                    0x000EBFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x000EC000,         // Range Minimum
                    0x000EFFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x00004000,         // Length
                    0x00,, , AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0x80000000,         // Range Minimum
                    0xF7FFFFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x78000000,         // Length
                    0x00,, _Y00, AddressRangeMemory, TypeStatic)
                DWordMemory (ResourceProducer, SubDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0xFC000000,         // Range Minimum
                    0xFED3FFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x02D40000,         // Length
                    0x00,, _Y01, AddressRangeMemory, TypeStatic)
                IO (Decode16,
                    0x0CF8,             // Range Minimum
                    0x0CF8,             // Range Maximum
                    0x01,               // Alignment
                    0x08,               // Length
                    )
                QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x0000000000000000, // Granularity
                    0x0000000000000000, // Range Minimum
                    0x0000000000000000, // Range Maximum
                    0x0000000000000000, // Translation Offset
                    0x0000000000000000, // Length
                    ,, _Y02, AddressRangeMemory, TypeStatic)
                QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x0000000000000000, // Granularity
                    0x0000000000000000, // Range Minimum
                    0x0000000000000000, // Range Maximum
                    0x0000000000000000, // Translation Offset
                    0x0000000000000000, // Length
                    ,, _Y03, AddressRangeMemory, TypeStatic)
            })
            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateDWordField (CRES, \_SB.PCI0._Y00._MIN, BTMN)  // _MIN: Minimum Base Address
                CreateDWordField (CRES, \_SB.PCI0._Y00._MAX, BTMX)  // _MAX: Maximum Base Address
                CreateDWordField (CRES, \_SB.PCI0._Y00._LEN, BTLN)  // _LEN: Length
                CreateDWordField (CRES, \_SB.PCI0._Y01._MIN, BTN1)  // _MIN: Minimum Base Address
                CreateDWordField (CRES, \_SB.PCI0._Y01._MAX, BTX1)  // _MAX: Maximum Base Address
                CreateDWordField (CRES, \_SB.PCI0._Y01._LEN, BTL1)  // _LEN: Length
                BTMN = TOM ()
                BTMX = (PCBA - One)
                BTLN = (PCBA - BTMN) /* \_SB_.PCI0._CRS.BTMN */
                BTN1 = (PCBL + One)
                BTL1 = (BTX1 - BTN1) /* \_SB_.PCI0._CRS.BTN1 */
                BTL1 += One
                If ((MM64 == One))
                {
                    CreateQWordField (CRES, \_SB.PCI0._Y02._MIN, M1MN)  // _MIN: Minimum Base Address
                    CreateQWordField (CRES, \_SB.PCI0._Y02._MAX, M1MX)  // _MAX: Maximum Base Address
                    CreateQWordField (CRES, \_SB.PCI0._Y02._LEN, M1LN)  // _LEN: Length
                    M1MN = HMB1 /* \HMB1 */
                    M1MX = HMM1 /* \HMM1 */
                    M1LN = HML1 /* \HML1 */
                    CreateQWordField (CRES, \_SB.PCI0._Y03._MIN, M2MN)  // _MIN: Minimum Base Address
                    CreateQWordField (CRES, \_SB.PCI0._Y03._MAX, M2MX)  // _MAX: Maximum Base Address
                    CreateQWordField (CRES, \_SB.PCI0._Y03._LEN, M2LN)  // _LEN: Length
                    M2MN = HMB2 /* \HMB2 */
                    M2MX = HMM2 /* \HMM2 */
                    M2LN = HML2 /* \HML2 */
                }

                Return (CRES) /* \_SB_.PCI0.CRES */
            }

            Device (MEMR)
            {
                Name (_HID, EisaId ("PNP0C02") /* PNP Motherboard Resources */)  // _HID: Hardware ID
                Name (BAR3, 0xFDA00000)
                Name (MEM1, ResourceTemplate ()
                {
                    Memory32Fixed (ReadWrite,
                        0x00000000,         // Address Base
                        0x00000000,         // Address Length
                        _Y04)
                    Memory32Fixed (ReadWrite,
                        0x00000000,         // Address Base
                        0x00000000,         // Address Length
                        _Y05)
                    Memory32Fixed (ReadWrite,
                        0x00000000,         // Address Base
                        0x00000000,         // Address Length
                        _Y06)
                })
                Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
                {
                    CreateDWordField (MEM1, \_SB.PCI0.MEMR._Y04._BAS, MB01)  // _BAS: Base Address
                    CreateDWordField (MEM1, \_SB.PCI0.MEMR._Y04._LEN, ML01)  // _LEN: Length
                    CreateDWordField (MEM1, \_SB.PCI0.MEMR._Y05._BAS, MB02)  // _BAS: Base Address
                    CreateDWordField (MEM1, \_SB.PCI0.MEMR._Y05._LEN, ML02)  // _LEN: Length
                    CreateDWordField (MEM1, \_SB.PCI0.MEMR._Y06._BAS, MB03)  // _BAS: Base Address
                    CreateDWordField (MEM1, \_SB.PCI0.MEMR._Y06._LEN, ML03)  // _LEN: Length
                    If (GPIC)
                    {
                        MB01 = 0xFEC00000
                        MB02 = 0xFEE00000
                        ML01 = 0x1000
                        If (\NAPC)
                        {
                            ML01 += 0x1000
                        }

                        ML02 = 0x1000
                    }

                    If ((BAR3 != 0xFFF00000))
                    {
                        MB03 = BAR3 /* \_SB_.PCI0.MEMR.BAR3 */
                        ML03 = 0x00100000
                    }

                    Return (MEM1) /* \_SB_.PCI0.MEMR.MEM1 */
                }
            }

            OperationRegion (NAPC, PCI_Config, 0xB8, 0x08)
            Field (NAPC, DWordAcc, NoLock, Preserve)
            {
                NAPX,   32, 
                NAPD,   32
            }

            Mutex (NAPM, 0x00)
            Method (NAPE, 0, NotSerialized)
            {
                Acquire (NAPM, 0xFFFF)
                NAPX = 0x14300000
                Local0 = NAPD /* \_SB_.PCI0.NAPD */
                Local0 &= 0xFFFFFFEF
                NAPD = Local0
                Release (NAPM)
            }

            Name (PR00, Package (0x0A)
            {
                Package (0x04)
                {
                    0x0001FFFF, 
                    Zero, 
                    LNKA, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    One, 
                    LNKB, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    0x02, 
                    LNKC, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    0x03, 
                    LNKD, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0008FFFF, 
                    Zero, 
                    LNKD, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0008FFFF, 
                    One, 
                    LNKE, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    Zero, 
                    LNKA, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    One, 
                    LNKB, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    0x02, 
                    LNKC, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    0x03, 
                    LNKD, 
                    Zero
                }
            })
            Name (AR00, Package (0x0A)
            {
                Package (0x04)
                {
                    0x0001FFFF, 
                    Zero, 
                    Zero, 
                    0x10
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    One, 
                    Zero, 
                    0x11
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    0x02, 
                    Zero, 
                    0x12
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    0x03, 
                    Zero, 
                    0x13
                }, 

                Package (0x04)
                {
                    0x0008FFFF, 
                    Zero, 
                    Zero, 
                    0x13
                }, 

                Package (0x04)
                {
                    0x0008FFFF, 
                    One, 
                    Zero, 
                    0x14
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    Zero, 
                    Zero, 
                    0x10
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    One, 
                    Zero, 
                    0x11
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    0x02, 
                    Zero, 
                    0x12
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    0x03, 
                    Zero, 
                    0x13
                }
            })
            Name (NR00, Package (0x0A)
            {
                Package (0x04)
                {
                    0x0001FFFF, 
                    Zero, 
                    Zero, 
                    0x28
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    One, 
                    Zero, 
                    0x29
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    0x02, 
                    Zero, 
                    0x2A
                }, 

                Package (0x04)
                {
                    0x0001FFFF, 
                    0x03, 
                    Zero, 
                    0x2B
                }, 

                Package (0x04)
                {
                    0x0008FFFF, 
                    Zero, 
                    Zero, 
                    0x2B
                }, 

                Package (0x04)
                {
                    0x0008FFFF, 
                    One, 
                    Zero, 
                    0x24
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    Zero, 
                    Zero, 
                    0x10
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    One, 
                    Zero, 
                    0x11
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    0x02, 
                    Zero, 
                    0x12
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    0x03, 
                    Zero, 
                    0x13
                }
            })
            Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
            {
                If (PICM)
                {
                    If (\NAPC)
                    {
                        Return (NR00) /* \_SB_.PCI0.NR00 */
                    }
                    Else
                    {
                        Return (AR00) /* \_SB_.PCI0.AR00 */
                    }
                }
                Else
                {
                    Return (PR00) /* \_SB_.PCI0.PR00 */
                }
            }

            Device (GPP0)
            {
                Name (_ADR, 0x00010001)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR01, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKA, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKB, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKC, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKD, 
                        Zero
                    }
                })
                Name (AR01, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x10
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x11
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x12
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x13
                    }
                })
                Name (NR01, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x18
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x19
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x1A
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x1B
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR01) /* \_SB_.PCI0.GPP0.NR01 */
                        }
                        Else
                        {
                            Return (AR01) /* \_SB_.PCI0.GPP0.AR01 */
                        }
                    }
                    Else
                    {
                        Return (PR01) /* \_SB_.PCI0.GPP0.PR01 */
                    }
                }

                Device (VGA)
                {
                    Name (_ADR, Zero)  // _ADR: Address
                    Name (DOSA, Zero)
                    Method (_DOS, 1, NotSerialized)  // _DOS: Disable Output Switching
                    {
                        DOSA = Arg0
                    }

                    Method (_DOD, 0, NotSerialized)  // _DOD: Display Output Devices
                    {
                        Return (Package (0x05)
                        {
                            0x00010110, 
                            0x00010210, 
                            0x00010220, 
                            0x00010230, 
                            0x00010240
                        })
                    }

                    Device (LCD)
                    {
                        Name (_ADR, 0x0110)  // _ADR: Address
                        Name (BCLB, Package (0x34)
                        {
                            0x5A, 
                            0x3C, 
                            0x02, 
                            0x04, 
                            0x06, 
                            0x08, 
                            0x0A, 
                            0x0C, 
                            0x0E, 
                            0x10, 
                            0x12, 
                            0x14, 
                            0x16, 
                            0x18, 
                            0x1A, 
                            0x1C, 
                            0x1E, 
                            0x20, 
                            0x22, 
                            0x24, 
                            0x26, 
                            0x28, 
                            0x2A, 
                            0x2C, 
                            0x2E, 
                            0x30, 
                            0x32, 
                            0x34, 
                            0x36, 
                            0x38, 
                            0x3A, 
                            0x3C, 
                            0x3E, 
                            0x40, 
                            0x42, 
                            0x44, 
                            0x46, 
                            0x48, 
                            0x4A, 
                            0x4C, 
                            0x4E, 
                            0x50, 
                            0x52, 
                            0x54, 
                            0x56, 
                            0x58, 
                            0x5A, 
                            0x5C, 
                            0x5E, 
                            0x60, 
                            0x62, 
                            0x64
                        })
                        Method (_BCL, 0, NotSerialized)  // _BCL: Brightness Control Levels
                        {
                            Return (BCLB) /* \_SB_.PCI0.GPP0.VGA_.LCD_.BCLB */
                        }

                        Method (_BCM, 1, NotSerialized)  // _BCM: Brightness Control Method
                        {
                            Divide ((Arg0 * 0xFF), 0x64, Local1, Local0)
                            AFN7 (Local0)
                            BRTL = Arg0
                        }
                    }

                    Method (_RMV, 0, NotSerialized)  // _RMV: Removal Status
                    {
                        Return (Zero)
                    }
                }

                Device (HDAU)
                {
                    Name (_ADR, One)  // _ADR: Address
                    Method (_RMV, 0, NotSerialized)  // _RMV: Removal Status
                    {
                        Return (Zero)
                    }
                }
            }

            Device (GPP1)
            {
                Name (_ADR, 0x00010002)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR02, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKE, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKF, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKG, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKH, 
                        Zero
                    }
                })
                Name (AR02, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x14
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x15
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x16
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x17
                    }
                })
                Name (NR02, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x1C
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x1D
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x1E
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x1F
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR02) /* \_SB_.PCI0.GPP1.NR02 */
                        }
                        Else
                        {
                            Return (AR02) /* \_SB_.PCI0.GPP1.AR02 */
                        }
                    }
                    Else
                    {
                        Return (PR02) /* \_SB_.PCI0.GPP1.PR02 */
                    }
                }

                Device (VGA)
                {
                    Name (_ADR, Zero)  // _ADR: Address
                    Name (DOSA, Zero)
                    Method (_DOS, 1, NotSerialized)  // _DOS: Disable Output Switching
                    {
                        DOSA = Arg0
                    }

                    Method (_DOD, 0, NotSerialized)  // _DOD: Display Output Devices
                    {
                        Return (Package (0x05)
                        {
                            0x00010110, 
                            0x00010210, 
                            0x00010220, 
                            0x00010230, 
                            0x00010240
                        })
                    }

                    Device (LCD)
                    {
                        Name (_ADR, 0x0110)  // _ADR: Address
                        Name (BCLB, Package (0x34)
                        {
                            0x5A, 
                            0x3C, 
                            0x02, 
                            0x04, 
                            0x06, 
                            0x08, 
                            0x0A, 
                            0x0C, 
                            0x0E, 
                            0x10, 
                            0x12, 
                            0x14, 
                            0x16, 
                            0x18, 
                            0x1A, 
                            0x1C, 
                            0x1E, 
                            0x20, 
                            0x22, 
                            0x24, 
                            0x26, 
                            0x28, 
                            0x2A, 
                            0x2C, 
                            0x2E, 
                            0x30, 
                            0x32, 
                            0x34, 
                            0x36, 
                            0x38, 
                            0x3A, 
                            0x3C, 
                            0x3E, 
                            0x40, 
                            0x42, 
                            0x44, 
                            0x46, 
                            0x48, 
                            0x4A, 
                            0x4C, 
                            0x4E, 
                            0x50, 
                            0x52, 
                            0x54, 
                            0x56, 
                            0x58, 
                            0x5A, 
                            0x5C, 
                            0x5E, 
                            0x60, 
                            0x62, 
                            0x64
                        })
                        Method (_BCL, 0, NotSerialized)  // _BCL: Brightness Control Levels
                        {
                            Return (BCLB) /* \_SB_.PCI0.GPP1.VGA_.LCD_.BCLB */
                        }

                        Method (_BCM, 1, NotSerialized)  // _BCM: Brightness Control Method
                        {
                            Divide ((Arg0 * 0xFF), 0x64, Local1, Local0)
                            AFN7 (Local0)
                            BRTL = Arg0
                        }
                    }

                    Method (_RMV, 0, NotSerialized)  // _RMV: Removal Status
                    {
                        Return (Zero)
                    }
                }

                Device (HDAU)
                {
                    Name (_ADR, One)  // _ADR: Address
                    Method (_RMV, 0, NotSerialized)  // _RMV: Removal Status
                    {
                        Return (Zero)
                    }
                }
            }

            Device (GPP2)
            {
                Name (_ADR, 0x00010003)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR03, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKA, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKB, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKC, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKD, 
                        Zero
                    }
                })
                Name (AR03, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x10
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x11
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x12
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x13
                    }
                })
                Name (NR03, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x20
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x21
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x22
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x23
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR03) /* \_SB_.PCI0.GPP2.NR03 */
                        }
                        Else
                        {
                            Return (AR03) /* \_SB_.PCI0.GPP2.AR03 */
                        }
                    }
                    Else
                    {
                        Return (PR03) /* \_SB_.PCI0.GPP2.PR03 */
                    }
                }
            }

            Device (GPP3)
            {
                Name (_ADR, 0x00010004)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR04, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKE, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKF, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKG, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKH, 
                        Zero
                    }
                })
                Name (AR04, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x14
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x15
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x16
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x17
                    }
                })
                Name (NR04, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x24
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x25
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x26
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x27
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR04) /* \_SB_.PCI0.GPP3.NR04 */
                        }
                        Else
                        {
                            Return (AR04) /* \_SB_.PCI0.GPP3.AR04 */
                        }
                    }
                    Else
                    {
                        Return (PR04) /* \_SB_.PCI0.GPP3.PR04 */
                    }
                }
            }

            Device (GPP4)
            {
                Name (_ADR, 0x00010005)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR05, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKA, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKB, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKC, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKD, 
                        Zero
                    }
                })
                Name (AR05, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x10
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x11
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x12
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x13
                    }
                })
                Name (NR05, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x28
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x29
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x2A
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x2B
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR05) /* \_SB_.PCI0.GPP4.NR05 */
                        }
                        Else
                        {
                            Return (AR05) /* \_SB_.PCI0.GPP4.AR05 */
                        }
                    }
                    Else
                    {
                        Return (PR05) /* \_SB_.PCI0.GPP4.PR05 */
                    }
                }
            }

            Device (GPP5)
            {
                Name (_ADR, 0x00010006)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR06, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKE, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKF, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKG, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKH, 
                        Zero
                    }
                })
                Name (AR06, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x14
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x15
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x16
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x17
                    }
                })
                Name (NR06, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x2C
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x2D
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x2E
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x2F
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR06) /* \_SB_.PCI0.GPP5.NR06 */
                        }
                        Else
                        {
                            Return (AR06) /* \_SB_.PCI0.GPP5.AR06 */
                        }
                    }
                    Else
                    {
                        Return (PR06) /* \_SB_.PCI0.GPP5.PR06 */
                    }
                }
            }

            Device (GPP6)
            {
                Name (_ADR, 0x00010007)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR07, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKA, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKB, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKC, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKD, 
                        Zero
                    }
                })
                Name (AR07, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x10
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x11
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x12
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x13
                    }
                })
                Name (NR07, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x30
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x31
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x32
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x33
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR07) /* \_SB_.PCI0.GPP6.NR07 */
                        }
                        Else
                        {
                            Return (AR07) /* \_SB_.PCI0.GPP6.AR07 */
                        }
                    }
                    Else
                    {
                        Return (PR07) /* \_SB_.PCI0.GPP6.PR07 */
                    }
                }
            }

            Device (GP17)
            {
                Name (_ADR, 0x00080001)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x19, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x19, Zero))
                    }
                }

                Name (PR17, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKE, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKF, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKG, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKH, 
                        Zero
                    }
                })
                Name (AR17, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x14
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x15
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x16
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x17
                    }
                })
                Name (NR17, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x34
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x35
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x36
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x37
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR17) /* \_SB_.PCI0.GP17.NR17 */
                        }
                        Else
                        {
                            Return (AR17) /* \_SB_.PCI0.GP17.AR17 */
                        }
                    }
                    Else
                    {
                        Return (PR17) /* \_SB_.PCI0.GP17.PR17 */
                    }
                }

                Device (VGA)
                {
                    Name (_ADR, Zero)  // _ADR: Address
                    Method (_STA, 0, NotSerialized)  // _STA: Status
                    {
                        Return (0x0F)
                    }

                    Name (DOSA, Zero)
                    Method (_DOS, 1, NotSerialized)  // _DOS: Disable Output Switching
                    {
                        DOSA = Arg0
                    }

                    Method (_DOD, 0, NotSerialized)  // _DOD: Display Output Devices
                    {
                        Return (Package (0x07)
                        {
                            0x00010110, 
                            0x00010210, 
                            0x00010220, 
                            0x00010230, 
                            0x00010240, 
                            0x00031000, 
                            0x00032000
                        })
                    }

                    Device (LCD)
                    {
                        Name (_ADR, 0x0110)  // _ADR: Address
                        Name (BCLB, Package (0x34)
                        {
                            0x5A, 
                            0x3C, 
                            0x02, 
                            0x04, 
                            0x06, 
                            0x08, 
                            0x0A, 
                            0x0C, 
                            0x0E, 
                            0x10, 
                            0x12, 
                            0x14, 
                            0x16, 
                            0x18, 
                            0x1A, 
                            0x1C, 
                            0x1E, 
                            0x20, 
                            0x22, 
                            0x24, 
                            0x26, 
                            0x28, 
                            0x2A, 
                            0x2C, 
                            0x2E, 
                            0x30, 
                            0x32, 
                            0x34, 
                            0x36, 
                            0x38, 
                            0x3A, 
                            0x3C, 
                            0x3E, 
                            0x40, 
                            0x42, 
                            0x44, 
                            0x46, 
                            0x48, 
                            0x4A, 
                            0x4C, 
                            0x4E, 
                            0x50, 
                            0x52, 
                            0x54, 
                            0x56, 
                            0x58, 
                            0x5A, 
                            0x5C, 
                            0x5E, 
                            0x60, 
                            0x62, 
                            0x64
                        })
                        Method (_BCL, 0, NotSerialized)  // _BCL: Brightness Control Levels
                        {
                            Return (BCLB) /* \_SB_.PCI0.GP17.VGA_.LCD_.BCLB */
                        }

                        Method (_BCM, 1, NotSerialized)  // _BCM: Brightness Control Method
                        {
                            Divide ((Arg0 * 0xFF), 0x64, Local1, Local0)
                            AFN7 (Local0)
                            BRTL = Arg0
                        }
                    }

                    OperationRegion (GPUM, PCI_Config, 0x24, 0x04)
                    Field (GPUM, ByteAcc, NoLock, Preserve)
                    {
                        GPUB,   32
                    }

                    Method (GBSA, 0, Serialized)
                    {
                        Local0 = GPUB /* \_SB_.PCI0.GP17.VGA_.GPUB */
                        Local0 &= 0xFFFFFF00
                        Local0 += 0x0138
                        Return (Local0)
                    }

                    OperationRegion (SCRA, SystemMemory, GBSA (), 0x04)
                    Field (SCRA, ByteAcc, NoLock, Preserve)
                    {
                        Offset (0x01), 
                        BRIL,   8
                    }
                }

                Device (PSP)
                {
                    Name (_ADR, 0x02)  // _ADR: Address
                }

                Device (ACP)
                {
                    Name (_ADR, 0x05)  // _ADR: Address
                }

                Device (AZAL)
                {
                    Name (_ADR, 0x06)  // _ADR: Address
                }

                Device (MP2C)
                {
                    Name (_ADR, 0x07)  // _ADR: Address
                }

                Device (XHC0)
                {
                    Name (_ADR, 0x03)  // _ADR: Address
                    Method (_S0W, 0, NotSerialized)  // _S0W: S0 Device Wake State
                    {
                        Return (Zero)
                    }

                    Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                    {
                        Return (GPRW (0x19, 0x03))
                    }

                    Device (HUBN)
                    {
                        Name (_ADR, Zero)  // _ADR: Address
                        Name (UPC0, Package (0x04)
                        {
                            Zero, 
                            0xFF, 
                            Zero, 
                            Zero
                        })
                        Name (UPCN, Package (0x04)
                        {
                            Zero, 
                            Zero, 
                            Zero, 
                            Zero
                        })
                        Name (UPCC, Package (0x04)
                        {
                            0xFF, 
                            0x09, 
                            Zero, 
                            Zero
                        })
                        Name (UPC3, Package (0x04)
                        {
                            0xFF, 
                            0x03, 
                            Zero, 
                            Zero
                        })
                        Name (UPC2, Package (0x04)
                        {
                            0xFF, 
                            Zero, 
                            Zero, 
                            Zero
                        })
                        Name (UPCP, Package (0x04)
                        {
                            0xFF, 
                            0xFF, 
                            Zero, 
                            Zero
                        })
                        Name (PLDN, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                                /* 0008 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // ........
                            }
                        })
                        Name (PLD1, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x01, 0xC6, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,  // ..r.....
                                /* 0008 */  0x69, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00   // i.......
                            }
                        })
                        Name (PLD2, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x01, 0xC6, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,  // ..r.....
                                /* 0008 */  0x71, 0x0C, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00   // q.......
                            }
                        })
                        Name (PLD3, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x01, 0xC6, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,  // ..r.....
                                /* 0008 */  0x69, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00   // i.......
                            }
                        })
                        Name (PLDB, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                                /* 0008 */  0xE0, 0x1E, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00   // ........
                            }
                        })
                        Device (HS01)
                        {
                            Name (_ADR, One)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPC2) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPC2 */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLD1) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLD1 */
                            }
                        }

                        Device (HS02)
                        {
                            Name (_ADR, 0x02)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPC2) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPC2 */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLD2) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLD2 */
                            }
                        }

                        Device (HS03)
                        {
                            Name (_ADR, 0x03)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPCC) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPCC */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLD3) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLD3 */
                            }
                        }

                        Device (HS04)
                        {
                            Name (_ADR, 0x04)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPCP) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPCP */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLDB) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLDB */
                            }

                            Device (BLTH)
                            {
                                Name (_ADR, One)  // _ADR: Address
                                Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                                {
                                    Return (PLDB) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLDB */
                                }

                                Method (_STA, 0, NotSerialized)  // _STA: Status
                                {
                                    Return (0x0F)
                                }
                            }
                        }

                        Device (SS01)
                        {
                            Name (_ADR, 0x05)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPC3) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPC3 */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLD1) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLD1 */
                            }
                        }

                        Device (SS02)
                        {
                            Name (_ADR, 0x06)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPC3) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPC3 */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLD2) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLD2 */
                            }
                        }

                        Device (SS03)
                        {
                            Name (_ADR, 0x07)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPCC) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPCC */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLD3) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLD3 */
                            }
                        }

                        Device (SS04)
                        {
                            Name (_ADR, 0x08)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPC0) /* \_SB_.PCI0.GP17.XHC0.HUBN.UPC0 */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLDN) /* \_SB_.PCI0.GP17.XHC0.HUBN.PLDN */
                            }
                        }
                    }
                }

                Device (XHC1)
                {
                    Name (_ADR, 0x04)  // _ADR: Address
                    Method (_S0W, 0, NotSerialized)  // _S0W: S0 Device Wake State
                    {
                        Return (Zero)
                    }

                    Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                    {
                        Return (GPRW (0x19, 0x03))
                    }

                    Device (HUBN)
                    {
                        Name (_ADR, Zero)  // _ADR: Address
                        Name (UPCN, Package (0x04)
                        {
                            Zero, 
                            Zero, 
                            Zero, 
                            Zero
                        })
                        Name (UPCP, Package (0x04)
                        {
                            0xFF, 
                            0xFF, 
                            Zero, 
                            Zero
                        })
                        Name (PLDN, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                                /* 0008 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // ........
                            }
                        })
                        Name (PLDR, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                                /* 0008 */  0xB0, 0x1E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00   // ........
                            }
                        })
                        Name (PLDH, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                                /* 0008 */  0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00   // ........
                            }
                        })
                        Name (PLDC, Package (0x01)
                        {
                            Buffer (0x14)
                            {
                                /* 0000 */  0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                                /* 0008 */  0x24, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,  // $.......
                                /* 0010 */  0x88, 0xFF, 0xB8, 0xFF                           // ....
                            }
                        })
                        Name (PLDF, Package (0x01)
                        {
                            Buffer (0x10)
                            {
                                /* 0000 */  0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                                /* 0008 */  0xE0, 0x1E, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00   // ........
                            }
                        })
                        Device (HS01)
                        {
                            Name (_ADR, One)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPCP) /* \_SB_.PCI0.GP17.XHC1.HUBN.UPCP */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLDR) /* \_SB_.PCI0.GP17.XHC1.HUBN.PLDR */
                            }

                            Device (CARD)
                            {
                                Name (_ADR, One)  // _ADR: Address
                                Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                                {
                                    Return (UPCP) /* \_SB_.PCI0.GP17.XHC1.HUBN.UPCP */
                                }

                                Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                                {
                                    Return (PLDR) /* \_SB_.PCI0.GP17.XHC1.HUBN.PLDR */
                                }

                                Method (_STA, 0, NotSerialized)  // _STA: Status
                                {
                                    Return (0x0F)
                                }
                            }
                        }

                        Name (XUPC, Package (0x04)
                        {
                            0xFF, 
                            0xFF, 
                            Zero, 
                            Zero
                        })
                        Name (XPLD, Buffer (0x10)
                        {
                            /* 0000 */  0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // ........
                            /* 0008 */  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // 0.......
                        })
                        Device (HS02)
                        {
                            OperationRegion (BOID, SystemMemory, 0xFED81614, 0x04)
                            Field (BOID, ByteAcc, NoLock, Preserve)
                            {
                                Offset (0x02), 
                                ID3V,   1
                            }

                            Name (_ADR, 0x02)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPCP) /* \_SB_.PCI0.GP17.XHC1.HUBN.UPCP */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLDH) /* \_SB_.PCI0.GP17.XHC1.HUBN.PLDH */
                            }

                            Device (GHUB)
                            {
                                Name (_ADR, One)  // _ADR: Address
                                Method (_UPC, 0, Serialized)  // _UPC: USB Port Capabilities
                                {
                                    Return (XUPC) /* \_SB_.PCI0.GP17.XHC1.HUBN.XUPC */
                                }

                                Method (_PLD, 0, Serialized)  // _PLD: Physical Location of Device
                                {
                                    Return (XPLD) /* \_SB_.PCI0.GP17.XHC1.HUBN.XPLD */
                                }

                                Device (CAMA)
                                {
                                    Name (_ADR, One)  // _ADR: Address
                                    Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                                    {
                                        Return (PLDC) /* \_SB_.PCI0.GP17.XHC1.HUBN.PLDC */
                                    }

                                    Method (_STA, 0, NotSerialized)  // _STA: Status
                                    {
                                        Return (0x0F)
                                    }
                                }

                                Device (FGPT)
                                {
                                    Name (_ADR, 0x02)  // _ADR: Address
                                    Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                                    {
                                        Return (PLDF) /* \_SB_.PCI0.GP17.XHC1.HUBN.PLDF */
                                    }

                                    Method (_STA, 0, NotSerialized)  // _STA: Status
                                    {
                                        If ((ID3V == Zero))
                                        {
                                            Return (Zero)
                                        }

                                        Return (0x0F)
                                    }
                                }

                                Method (_STA, 0, NotSerialized)  // _STA: Status
                                {
                                    If ((ID3V == Zero))
                                    {
                                        Return (Zero)
                                    }

                                    Return (0x0F)
                                }
                            }

                            Device (CAMB)
                            {
                                Name (_ADR, 0x02)  // _ADR: Address
                                Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                                {
                                    Return (PLDC) /* \_SB_.PCI0.GP17.XHC1.HUBN.PLDC */
                                }

                                Method (_STA, 0, NotSerialized)  // _STA: Status
                                {
                                    If ((ID3V == Zero))
                                    {
                                        Return (0x0F)
                                    }

                                    Return (Zero)
                                }
                            }
                        }

                        Device (SS01)
                        {
                            Name (_ADR, 0x03)  // _ADR: Address
                            Method (_UPC, 0, NotSerialized)  // _UPC: USB Port Capabilities
                            {
                                Return (UPCN) /* \_SB_.PCI0.GP17.XHC1.HUBN.UPCN */
                            }

                            Method (_PLD, 0, NotSerialized)  // _PLD: Physical Location of Device
                            {
                                Return (PLDN) /* \_SB_.PCI0.GP17.XHC1.HUBN.PLDN */
                            }
                        }
                    }
                }
            }

            Device (GP18)
            {
                Name (_ADR, 0x00080002)  // _ADR: Address
                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    If ((WKPM == One))
                    {
                        Return (GPRW (0x08, 0x03))
                    }
                    Else
                    {
                        Return (GPRW (0x08, Zero))
                    }
                }

                Name (PR18, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        LNKG, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        LNKH, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        LNKE, 
                        Zero
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        LNKF, 
                        Zero
                    }
                })
                Name (AR18, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x16
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x17
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x14
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x15
                    }
                })
                Name (NR18, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        Zero, 
                        Zero, 
                        0x36
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        One, 
                        Zero, 
                        0x37
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        Zero, 
                        0x34
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        Zero, 
                        0x35
                    }
                })
                Method (_PRT, 0, NotSerialized)  // _PRT: PCI Routing Table
                {
                    If (PICM)
                    {
                        If (\NAPC)
                        {
                            Return (NR18) /* \_SB_.PCI0.GP18.NR18 */
                        }
                        Else
                        {
                            Return (AR18) /* \_SB_.PCI0.GP18.AR18 */
                        }
                    }
                    Else
                    {
                        Return (PR18) /* \_SB_.PCI0.GP18.PR18 */
                    }
                }

                Device (SATA)
                {
                    Name (_ADR, Zero)  // _ADR: Address
                }
            }

            Device (HPET)
            {
                Name (_HID, EisaId ("PNP0103") /* HPET System Timer */)  // _HID: Hardware ID
                Method (_STA, 0, NotSerialized)  // _STA: Status
                {
                    If ((HPEN == One))
                    {
                        If ((OSTB >= 0x40))
                        {
                            Return (0x0F)
                        }

                        HPEN = Zero
                        Return (One)
                    }

                    Return (One)
                }

                Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
                {
                    Name (BUF0, ResourceTemplate ()
                    {
                        IRQNoFlags ()
                            {0}
                        IRQNoFlags ()
                            {8}
                        Memory32Fixed (ReadOnly,
                            0xFED00000,         // Address Base
                            0x00000400,         // Address Length
                            _Y07)
                    })
                    CreateDWordField (BUF0, \_SB.PCI0.HPET._CRS._Y07._BAS, HPEB)  // _BAS: Base Address
                    Local0 = 0xFED00000
                    HPEB = (Local0 & 0xFFFFFC00)
                    Return (BUF0) /* \_SB_.PCI0.HPET._CRS.BUF0 */
                }
            }

            Device (SMBS)
            {
                Name (_ADR, 0x00140000)  // _ADR: Address
            }

            Device (LPC0)
            {
                Name (_ADR, 0x00140003)  // _ADR: Address
                Device (DMAC)
                {
                    Name (_HID, EisaId ("PNP0200") /* PC-class DMA Controller */)  // _HID: Hardware ID
                    Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
                    {
                        IO (Decode16,
                            0x0000,             // Range Minimum
                            0x0000,             // Range Maximum
                            0x01,               // Alignment
                            0x10,               // Length
                            )
                        IO (Decode16,
                            0x0081,             // Range Minimum
                            0x0081,             // Range Maximum
                            0x01,               // Alignment
                            0x0F,               // Length
                            )
                        IO (Decode16,
                            0x00C0,             // Range Minimum
                            0x00C0,             // Range Maximum
                            0x01,               // Alignment
                            0x20,               // Length
                            )
                        DMA (Compatibility, NotBusMaster, Transfer8_16, )
                            {4}
                    })
                }

                Device (COPR)
                {
                    Name (_HID, EisaId ("PNP0C04") /* x87-compatible Floating Point Processing Unit */)  // _HID: Hardware ID
                    Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
                    {
                        IO (Decode16,
                            0x00F0,             // Range Minimum
                            0x00F0,             // Range Maximum
                            0x01,               // Alignment
                            0x0F,               // Length
                            )
                        IRQNoFlags ()
                            {13}
                    })
                }

                Device (PIC)
                {
                    Name (_HID, EisaId ("PNP0000") /* 8259-compatible Programmable Interrupt Controller */)  // _HID: Hardware ID
                    Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
                    {
                        IO (Decode16,
                            0x0020,             // Range Minimum
                            0x0020,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                        IO (Decode16,
                            0x00A0,             // Range Minimum
                            0x00A0,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                        IRQNoFlags ()
                            {2}
                    })
                }

                Device (RTC)
                {
                    Name (_HID, EisaId ("PNP0B00") /* AT Real-Time Clock */)  // _HID: Hardware ID
                    Name (BUF0, ResourceTemplate ()
                    {
                        IO (Decode16,
                            0x0070,             // Range Minimum
                            0x0070,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                    })
                    Name (BUF1, ResourceTemplate ()
                    {
                        IO (Decode16,
                            0x0070,             // Range Minimum
                            0x0070,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                        IRQNoFlags ()
                            {8}
                    })
                    Method (_CRS, 0, Serialized)  // _CRS: Current Resource Settings
                    {
                        If ((HPEN == One))
                        {
                            Return (BUF0) /* \_SB_.PCI0.LPC0.RTC_.BUF0 */
                        }

                        Return (BUF1) /* \_SB_.PCI0.LPC0.RTC_.BUF1 */
                    }
                }

                Device (SPKR)
                {
                    Name (_HID, EisaId ("PNP0800") /* Microsoft Sound System Compatible Device */)  // _HID: Hardware ID
                    Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
                    {
                        IO (Decode16,
                            0x0061,             // Range Minimum
                            0x0061,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                    })
                }

                Device (TMR)
                {
                    Name (_HID, EisaId ("PNP0100") /* PC-class System Timer */)  // _HID: Hardware ID
                    Name (BUF0, ResourceTemplate ()
                    {
                        IO (Decode16,
                            0x0040,             // Range Minimum
                            0x0040,             // Range Maximum
                            0x01,               // Alignment
                            0x04,               // Length
                            )
                    })
                    Name (BUF1, ResourceTemplate ()
                    {
                        IO (Decode16,
                            0x0040,             // Range Minimum
                            0x0040,             // Range Maximum
                            0x01,               // Alignment
                            0x04,               // Length
                            )
                        IRQNoFlags ()
                            {0}
                    })
                    Method (_CRS, 0, Serialized)  // _CRS: Current Resource Settings
                    {
                        If ((HPEN == One))
                        {
                            Return (BUF0) /* \_SB_.PCI0.LPC0.TMR_.BUF0 */
                        }

                        Return (BUF1) /* \_SB_.PCI0.LPC0.TMR_.BUF1 */
                    }
                }

                Device (KBC0)
                {
                    Name (_HID, EisaId ("FUJ7401"))  // _HID: Hardware ID
                    Name (_CID, EisaId ("PNP0303") /* IBM Enhanced Keyboard (101/102-key, PS/2 Mouse) */)  // _CID: Compatible ID
                    Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
                    {
                        IO (Decode16,
                            0x0060,             // Range Minimum
                            0x0060,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x0064,             // Range Minimum
                            0x0064,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IRQNoFlags ()
                            {1}
                    })
                }

                Device (SYSR)
                {
                    Name (_HID, EisaId ("PNP0C02") /* PNP Motherboard Resources */)  // _HID: Hardware ID
                    Name (_UID, One)  // _UID: Unique ID
                    Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
                    {
                        IO (Decode16,
                            0x0010,             // Range Minimum
                            0x0010,             // Range Maximum
                            0x01,               // Alignment
                            0x10,               // Length
                            )
                        IO (Decode16,
                            0x0072,             // Range Minimum
                            0x0072,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                        IO (Decode16,
                            0x0080,             // Range Minimum
                            0x0080,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x00B0,             // Range Minimum
                            0x00B0,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                        IO (Decode16,
                            0x0092,             // Range Minimum
                            0x0092,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x0400,             // Range Minimum
                            0x0400,             // Range Maximum
                            0x01,               // Alignment
                            0xD0,               // Length
                            )
                        IO (Decode16,
                            0x04D0,             // Range Minimum
                            0x04D0,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                        IO (Decode16,
                            0x04D6,             // Range Minimum
                            0x04D6,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x0C00,             // Range Minimum
                            0x0C00,             // Range Maximum
                            0x01,               // Alignment
                            0x02,               // Length
                            )
                        IO (Decode16,
                            0x0C14,             // Range Minimum
                            0x0C14,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x0C50,             // Range Minimum
                            0x0C50,             // Range Maximum
                            0x01,               // Alignment
                            0x03,               // Length
                            )
                        IO (Decode16,
                            0x0C6C,             // Range Minimum
                            0x0C6C,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x0C6F,             // Range Minimum
                            0x0C6F,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x0CD0,             // Range Minimum
                            0x0CD0,             // Range Maximum
                            0x01,               // Alignment
                            0x0C,               // Length
                            )
                    })
                }

                Device (MEM)
                {
                    Name (_HID, EisaId ("PNP0C01") /* System Board */)  // _HID: Hardware ID
                    Name (MSRC, ResourceTemplate ()
                    {
                        Memory32Fixed (ReadOnly,
                            0x000E0000,         // Address Base
                            0x00020000,         // Address Length
                            )
                        Memory32Fixed (ReadWrite,
                            0xFFF00000,         // Address Base
                            0x00100000,         // Address Length
                            _Y08)
                    })
                    Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
                    {
                        CreateDWordField (MSRC, \_SB.PCI0.LPC0.MEM._Y08._LEN, PSIZ)  // _LEN: Length
                        CreateDWordField (MSRC, \_SB.PCI0.LPC0.MEM._Y08._BAS, PBAS)  // _BAS: Base Address
                        PSIZ = ROMS /* \ROMS */
                        Local0 = (ROMS - One)
                        PBAS = (Ones - Local0)
                        Return (MSRC) /* \_SB_.PCI0.LPC0.MEM_.MSRC */
                    }
                }

                Scope (\)
                {
                    Name (ECON, One)
                }

                Device (EC0)
                {
                    Name (_HID, EisaId ("PNP0C09") /* Embedded Controller Device */)  // _HID: Hardware ID
                    Name (_UID, One)  // _UID: Unique ID
                    Name (ECAV, Zero)
                    Name (XX11, Buffer (0x07){})
                    Mutex (LFCM, 0x00)
                    Mutex (ECMT, 0x00)
                    Name (_GPE, 0x03)  // _GPE: General Purpose Events
                    Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
                    {
                        Name (BFFR, ResourceTemplate ()
                        {
                            IO (Decode16,
                                0x0062,             // Range Minimum
                                0x0062,             // Range Maximum
                                0x00,               // Alignment
                                0x01,               // Length
                                )
                            IO (Decode16,
                                0x0066,             // Range Minimum
                                0x0066,             // Range Maximum
                                0x00,               // Alignment
                                0x01,               // Length
                                )
                        })
                        Return (BFFR) /* \_SB_.PCI0.LPC0.EC0_._CRS.BFFR */
                    }

                    Method (_STA, 0, NotSerialized)  // _STA: Status
                    {
                        Return (0x0F)
                    }

                    OperationRegion (ERAM, EmbeddedControl, Zero, 0xFF)
                    Field (ERAM, ByteAcc, Lock, Preserve)
                    {
                        VCMD,   8, 
                        Offset (0x60), 
                        SMPR,   8
                    }

                    OperationRegion (ERAX, SystemMemory, 0xFF00D400, 0xFF)
                    Field (ERAX, ByteAcc, Lock, Preserve)
                    {
                        Offset (0x01), 
                        VDAT,   8, 
                        VSTA,   8, 
                        Offset (0x06), 
                        FANS,   8, 
                        BUSG,   1, 
                        BLEG,   1, 
                        BATF,   1, 
                        BNSM,   1, 
                        BTST,   1, 
                        BBAD,   1, 
                        AUTO,   1, 
                        FCHG,   1, 
                        ABTL,   8, 
                        DBTL,   8, 
                        EDCC,   1, 
                        ALSC,   1, 
                        CDMB,   1, 
                        CCSB,   1, 
                        BTSM,   1, 
                        BTCM,   1, 
                        LBTM,   1, 
                        CSBM,   1, 
                        SGST,   1, 
                        HDMI,   1, 
                        HYBD,   1, 
                        SWST,   1, 
                        EVNT,   1, 
                        DCRF,   1, 
                        COLR,   1, 
                        SGCN,   1, 
                        ODPO,   1, 
                        EODD,   1, 
                        ODPK,   1, 
                        CMEX,   1, 
                        CMON,   1, 
                        SODD,   1, 
                        ODFB,   1, 
                        EODS,   1, 
                        RTMP,   8, 
                        VTMP,   8, 
                        AFCC,   8, 
                        PINF,   3, 
                        SUPR,   1, 
                        GTMP,   1, 
                        QUIT,   1, 
                        LS35,   1, 
                        Offset (0x11), 
                        RMBT,   1, 
                        RSBT,   1, 
                        VTYP,   2, 
                        Offset (0x12), 
                        FUSL,   8, 
                        FUSH,   8, 
                        FWBT,   64, 
                        Offset (0x1D), 
                        QUIE,   8, 
                        Offset (0x31), 
                        GIRT,   8, 
                        PIRT,   8, 
                        KIRT,   8, 
                        IRTI,   8, 
                        Offset (0x36), 
                        DGPU,   8, 
                        GUST,   8, 
                        GDST,   8, 
                        Offset (0x43), 
                        ECTP,   8, 
                        Offset (0x4A), 
                        ESMC,   1, 
                        Offset (0x4B), 
                        EMOD,   8, 
                        BFUD,   16, 
                        Offset (0x5D), 
                        EXSI,   8, 
                        EXSB,   8, 
                        EXND,   8, 
                        Offset (0x61), 
                        SMST,   8, 
                        SMAD,   8, 
                        SMCM,   8, 
                        SMDA,   256, 
                        BCNT,   8, 
                        SMAA,   8, 
                        SAD0,   8, 
                        SAD1,   8, 
                            ,   1, 
                            ,   1, 
                            ,   1, 
                            ,   1, 
                            ,   1, 
                        FBFG,   1, 
                        Offset (0x8A), 
                        KBLO,   1, 
                        UCHE,   1, 
                        KLCH,   1, 
                            ,   1, 
                        KLFS,   1, 
                        KLOR,   1, 
                        UCHR,   1, 
                        UCER,   1, 
                        TPDV,   3, 
                        Offset (0x8C), 
                        QCHO,   1, 
                        BKLT,   1, 
                        Offset (0x8F), 
                        BMN0,   72, 
                        BDN0,   64, 
                        IBTL,   1, 
                        IBCL,   1, 
                        ISS0,   1, 
                        IRTC,   1, 
                        ISUP,   1, 
                        ISC2,   1, 
                        IWAK,   1, 
                        Offset (0xA1), 
                            ,   1, 
                        VOUT,   1, 
                        TPAD,   1, 
                        HKDB,   1, 
                        Offset (0xA2), 
                        Offset (0xA3), 
                        OSTY,   3, 
                            ,   1, 
                        ADPI,   2, 
                            ,   1, 
                        ADPT,   1, 
                        PMEW,   1, 
                        MODW,   1, 
                        LANW,   1, 
                        RTCW,   1, 
                        WLAW,   1, 
                        USBW,   1, 
                        KEYW,   1, 
                        TPWK,   1, 
                        CHCR,   1, 
                        ADPP,   1, 
                        LERN,   1, 
                        ACMD,   1, 
                        BOVP,   1, 
                        LEAK,   1, 
                        AIRP,   1, 
                        ACOF,   1, 
                        S3EN,   1, 
                        S3RS,   1, 
                        S4EN,   1, 
                        S4RS,   1, 
                        S5EN,   1, 
                        S5RS,   1, 
                        Offset (0xA7), 
                        OSTT,   8, 
                        OSST,   8, 
                        THRT,   8, 
                        TCOT,   8, 
                        MODE,   1, 
                            ,   2, 
                        INIT,   1, 
                        FAN1,   1, 
                        FAN2,   1, 
                        FAOK,   1, 
                        SKIN,   1, 
                        SDTE,   8, 
                        SPDN,   4, 
                        FNUM,   4, 
                        TLVL,   4, 
                            ,   2, 
                        THSW,   1, 
                        TPIN,   1, 
                        TSTH,   1, 
                        TSCP,   1, 
                            ,   2, 
                        PLVL,   4, 
                        CPUT,   8, 
                        CPTL,   8, 
                        Offset (0xB7), 
                            ,   1, 
                        PWDB,   1, 
                        DIGT,   1, 
                        CDLK,   1, 
                        Offset (0xB8), 
                            ,   1, 
                        LSTE,   1, 
                        PMEE,   1, 
                        PWBE,   1, 
                        RNGE,   1, 
                        BTWE,   1, 
                        Offset (0xB9), 
                        LCBV,   8, 
                        DGDF,   8, 
                        WLAN,   1, 
                        BLUE,   1, 
                        WEXT,   1, 
                        BEXT,   1, 
                        KILL,   1, 
                        WLOK,   1, 
                        EN3G,   1, 
                        EX3G,   1, 
                        KPID,   8, 
                        CTYP,   3, 
                        CORE,   3, 
                        GATY,   2, 
                        BA1P,   1, 
                        BA2P,   1, 
                            ,   2, 
                        B1CH,   1, 
                        B2CH,   1, 
                        Offset (0xBF), 
                        PBY1,   1, 
                        PBY2,   1, 
                            ,   2, 
                        SMB1,   1, 
                        SMB2,   1, 
                        Offset (0xC0), 
                        B1TY,   1, 
                        B1MD,   1, 
                        B1LW,   1, 
                            ,   1, 
                        B1MF,   3, 
                        Offset (0xC1), 
                        B1ST,   8, 
                        B1RC,   16, 
                        B1SN,   16, 
                        B1FV,   16, 
                        B1DV,   16, 
                        B1DC,   16, 
                        B1FC,   16, 
                        B1GS,   8, 
                        B1CT,   8, 
                        B1CR,   16, 
                        B1AC,   16, 
                        B1PC,   8, 
                        B1VL,   8, 
                        B1TM,   8, 
                        B1AT,   8, 
                        B1CC,   16, 
                        B1TC,   8, 
                        B1CI,   8, 
                        B1CU,   8, 
                        B1CA,   8, 
                        B1SM,   16, 
                        B1VC,   8, 
                        B1FA,   8, 
                        B1VA,   8, 
                        B1C1,   16, 
                        B1C2,   16, 
                        B1C3,   16, 
                        B1C4,   16, 
                        Offset (0xF0), 
                        B1EX,   1, 
                        B1FL,   1, 
                        B1EP,   1, 
                        B1FI,   1, 
                            ,   2, 
                        B1RE,   1, 
                        Offset (0xF1), 
                        B1LL,   1, 
                        B1CE,   1, 
                        B1SE,   1, 
                        B1S5,   1, 
                        B1SR,   1, 
                        B1SC,   1, 
                        Offset (0xF2), 
                        B1TO,   1, 
                        B1BC,   1, 
                        B1CF,   1, 
                        B1CS,   1, 
                        B1SG,   1, 
                        B1SU,   1, 
                        B1OV,   1, 
                        B1OT,   1, 
                        B1TT,   1, 
                        B1SA,   1, 
                        B1SS,   1, 
                            ,   1, 
                        B1SF,   1, 
                        B1WN,   1, 
                        Offset (0xF4), 
                        B1DA,   16, 
                        Offset (0xF8), 
                        B1CN,   8, 
                        Offset (0xFB), 
                        Offset (0xFE), 
                        FA2S,   8
                    }

                    OperationRegion (ECMS, SystemIO, 0x72, 0x02)
                    Field (ECMS, ByteAcc, Lock, Preserve)
                    {
                        INDX,   8, 
                        DATA,   8
                    }

                    Method (RECM, 1, Serialized)
                    {
                        INDX = Arg0
                        Return (DATA) /* \_SB_.PCI0.LPC0.EC0_.DATA */
                    }

                    Method (WECM, 2, Serialized)
                    {
                        INDX = Arg0
                        DATA = Arg1
                    }

                    OperationRegion (CMDE, SystemIO, 0x62, 0x0B)
                    Field (CMDE, ByteAcc, Lock, Preserve)
                    {
                        EC62,   8, 
                        Offset (0x02), 
                        Offset (0x03), 
                        Offset (0x04), 
                        EC66,   8, 
                        Offset (0x06), 
                        EC68,   8, 
                        Offset (0x08), 
                        Offset (0x09), 
                        Offset (0x0A), 
                        EC6C,   8
                    }

                    Method (WIBE, 1, Serialized)
                    {
                        Local0 = 0x00010000
                        While (Local0)
                        {
                            If ((Arg0 == One))
                            {
                                Local1 = EC66 /* \_SB_.PCI0.LPC0.EC0_.EC66 */
                            }
                            ElseIf ((Arg0 == 0x02))
                            {
                                Local1 = EC6C /* \_SB_.PCI0.LPC0.EC0_.EC6C */
                            }
                            Else
                            {
                                Return (0x02)
                            }

                            If (((Local1 & 0x02) == Zero))
                            {
                                Return (Zero)
                            }

                            Stall (0x0A)
                            Local0--
                        }

                        Return (One)
                    }

                    Method (WOBF, 1, Serialized)
                    {
                        Local0 = 0x00010000
                        While (Local0)
                        {
                            If ((Arg0 == One))
                            {
                                Local1 = EC66 /* \_SB_.PCI0.LPC0.EC0_.EC66 */
                            }
                            ElseIf ((Arg0 == 0x02))
                            {
                                Local1 = EC6C /* \_SB_.PCI0.LPC0.EC0_.EC6C */
                            }
                            Else
                            {
                                Return (0x02)
                            }

                            If (((Local1 & One) == One))
                            {
                                Return (Zero)
                            }

                            Stall (0x0A)
                            Local0--
                        }

                        Return (One)
                    }

                    Method (WOBE, 1, Serialized)
                    {
                        Local0 = 0x00010000
                        While (Local0)
                        {
                            If ((Arg0 == One))
                            {
                                Local1 = EC66 /* \_SB_.PCI0.LPC0.EC0_.EC66 */
                            }
                            ElseIf ((Arg0 == 0x02))
                            {
                                Local1 = EC6C /* \_SB_.PCI0.LPC0.EC0_.EC6C */
                            }
                            Else
                            {
                                Return (0x02)
                            }

                            If (((Local1 & One) == One))
                            {
                                If ((Arg0 == One))
                                {
                                    Local2 = EC62 /* \_SB_.PCI0.LPC0.EC0_.EC62 */
                                }
                                ElseIf ((Arg0 == 0x02))
                                {
                                    Local2 = EC68 /* \_SB_.PCI0.LPC0.EC0_.EC68 */
                                }
                                Else
                                {
                                    Return (0x02)
                                }
                            }
                            Else
                            {
                                Return (Zero)
                            }

                            Stall (0x0A)
                            Local0--
                        }

                        Return (One)
                    }

                    Method (LCMD, 2, Serialized)
                    {
                        Name (LBUF, Buffer (0x1E)
                        {
                             0x00                                             // .
                        })
                        If ((WIBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        If ((WOBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        EC6C = Arg0
                        If ((WIBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        If (((Arg1 != Zero) && (Arg1 != 0xFF)))
                        {
                            EC68 = Arg1
                            If ((WIBE (0x02) != Zero))
                            {
                                Return (One)
                            }
                        }

                        If ((WOBF (0x02) != Zero))
                        {
                            Return (One)
                        }

                        Local0 = EC68 /* \_SB_.PCI0.LPC0.EC0_.EC68 */
                        Local1 = Zero
                        While (Local0)
                        {
                            If ((WOBF (0x02) != Zero))
                            {
                                Return (One)
                            }

                            LBUF [Local1] = EC68 /* \_SB_.PCI0.LPC0.EC0_.EC68 */
                            Local1++
                            Local0--
                        }

                        Return (LBUF) /* \_SB_.PCI0.LPC0.EC0_.LCMD.LBUF */
                    }

                    Method (SCMD, 2, Serialized)
                    {
                        Name (LBUF, Buffer (0x1E)
                        {
                             0x00                                             // .
                        })
                        If ((WIBE (One) != Zero))
                        {
                            Return (One)
                        }

                        If ((WOBE (One) != Zero))
                        {
                            Return (One)
                        }

                        EC66 = Arg0
                        If ((WIBE (One) != Zero))
                        {
                            Return (One)
                        }

                        If (((Arg1 != Zero) && (Arg1 != 0xFF)))
                        {
                            EC62 = Arg1
                            If ((WIBE (One) != Zero))
                            {
                                Return (One)
                            }
                        }

                        If ((WOBF (One) != Zero))
                        {
                            Return (One)
                        }

                        Local0 = EC62 /* \_SB_.PCI0.LPC0.EC0_.EC62 */
                        Local1 = Zero
                        While (Local0)
                        {
                            If ((WOBF (One) != Zero))
                            {
                                Return (One)
                            }

                            LBUF [Local1] = EC62 /* \_SB_.PCI0.LPC0.EC0_.EC62 */
                            Local1++
                            Local0--
                        }

                        Return (LBUF) /* \_SB_.PCI0.LPC0.EC0_.SCMD.LBUF */
                    }

                    Method (LRAM, 2, Serialized)
                    {
                        If ((WIBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        If ((WOBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        EC6C = 0x7E
                        If ((WIBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        EC68 = Arg0
                        If ((WIBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        EC68 = Arg1
                        If ((WIBE (0x02) != Zero))
                        {
                            Return (One)
                        }

                        If ((WOBF (0x02) != Zero))
                        {
                            Return (One)
                        }

                        Return (EC68) /* \_SB_.PCI0.LPC0.EC0_.EC68 */
                    }

                    Method (SRAM, 2, Serialized)
                    {
                        If ((WIBE (One) != Zero))
                        {
                            Return (One)
                        }

                        If ((WOBE (One) != Zero))
                        {
                            Return (One)
                        }

                        EC66 = 0x7E
                        If ((WIBE (One) != Zero))
                        {
                            Return (One)
                        }

                        EC62 = Arg0
                        If ((WIBE (One) != Zero))
                        {
                            Return (One)
                        }

                        EC62 = Arg1
                        If ((WIBE (One) != Zero))
                        {
                            Return (One)
                        }

                        If ((WOBF (One) != Zero))
                        {
                            Return (One)
                        }

                        Return (EC62) /* \_SB_.PCI0.LPC0.EC0_.EC62 */
                    }

                    Scope (\)
                    {
                        OperationRegion (LFCN, SystemMemory, 0xBF7BBD18, 0x00EE)
                        Field (LFCN, AnyAcc, Lock, Preserve)
                        {
                            PS2V,   8, 
                            KBID,   8, 
                            MCSZ,   8, 
                            OKRB,   8, 
                            EDID,   1024, 
                            TPTY,   8, 
                            TPNV,   16, 
                            TPNP,   16, 
                            YG53,   8, 
                            LFCO,   800
                        }

                        OperationRegion (SMIO, SystemIO, 0xB0, 0x02)
                        Field (SMIO, ByteAcc, NoLock, Preserve)
                        {
                            SMBA,   8, 
                            SMBB,   8
                        }
                    }

                    Device (BAT0)
                    {
                        Name (_HID, EisaId ("PNP0C0A") /* Control Method Battery */)  // _HID: Hardware ID
                        Name (_UID, One)  // _UID: Unique ID
                        Name (_PCL, Package (0x01)  // _PCL: Power Consumer List
                        {
                            _SB
                        })
                        Name (PBIF, Package (0x0D)
                        {
                            Zero, 
                            Ones, 
                            Ones, 
                            One, 
                            Ones, 
                            Zero, 
                            Zero, 
                            0x64, 
                            Zero, 
                            "LCFC", 
                            "BAT20101001", 
                            "LiP", 
                            "LENOVO"
                        })
                        Name (PBST, Package (0x04)
                        {
                            One, 
                            0x0A90, 
                            0x1000, 
                            0x2A30
                        })
                        Method (_STA, 0, NotSerialized)  // _STA: Status
                        {
                            If ((ECON == One))
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        Local0 = BA1P /* \_SB_.PCI0.LPC0.EC0_.BA1P */
                                        Release (LFCM)
                                    }
                                }

                                If ((Local0 & One))
                                {
                                    Return (0x1F)
                                }
                                Else
                                {
                                    Return (0x0F)
                                }
                            }
                            Else
                            {
                                Return (Zero)
                            }
                        }

                        Method (_BIF, 0, NotSerialized)  // _BIF: Battery Information
                        {
                            If ((ECAV == One))
                            {
                                If ((Acquire (LFCM, 0xA000) == Zero))
                                {
                                    Local0 = B1DC /* \_SB_.PCI0.LPC0.EC0_.B1DC */
                                    Local0 *= 0x0A
                                    PBIF [One] = Local0
                                    Local0 = B1FC /* \_SB_.PCI0.LPC0.EC0_.B1FC */
                                    Local0 *= 0x0A
                                    PBIF [0x02] = Local0
                                    PBIF [0x04] = B1DV /* \_SB_.PCI0.LPC0.EC0_.B1DV */
                                    If (B1FC)
                                    {
                                        PBIF [0x05] = ((B1FC * 0x0A) / 0x0A)
                                        PBIF [0x06] = ((B1FC * 0x0A) / 0x19)
                                        PBIF [0x07] = ((B1DC * 0x0A) / 0x64)
                                    }

                                    PBIF [0x09] = ""
                                    PBIF [0x0A] = ""
                                    PBIF [0x0B] = ""
                                    PBIF [0x0C] = ""
                                    Name (BDNT, Buffer (0x09)
                                    {
                                         0x00                                             // .
                                    })
                                    BDNT = BDN0 /* \_SB_.PCI0.LPC0.EC0_.BDN0 */
                                    PBIF [0x09] = ToString (BDNT, Ones)
                                    Local0 = B1SN /* \_SB_.PCI0.LPC0.EC0_.B1SN */
                                    Name (SERN, Buffer (0x06)
                                    {
                                        "     "
                                    })
                                    Local2 = 0x04
                                    While (Local0)
                                    {
                                        Divide (Local0, 0x0A, Local1, Local0)
                                        SERN [Local2] = (Local1 + 0x30)
                                        Local2--
                                    }

                                    PBIF [0x0A] = SERN /* \_SB_.PCI0.LPC0.EC0_.BAT0._BIF.SERN */
                                    Name (DCH0, Buffer (0x0A)
                                    {
                                         0x00                                             // .
                                    })
                                    Name (DCH1, "LION")
                                    Name (DCH2, "LiP")
                                    If ((B1TY == One))
                                    {
                                        DCH0 = DCH1 /* \_SB_.PCI0.LPC0.EC0_.BAT0._BIF.DCH1 */
                                        PBIF [0x0B] = ToString (DCH0, Ones)
                                    }
                                    Else
                                    {
                                        DCH0 = DCH2 /* \_SB_.PCI0.LPC0.EC0_.BAT0._BIF.DCH2 */
                                        PBIF [0x0B] = ToString (DCH0, Ones)
                                    }

                                    Name (BMNT, Buffer (0x0A)
                                    {
                                         0x00                                             // .
                                    })
                                    BMNT = BMN0 /* \_SB_.PCI0.LPC0.EC0_.BMN0 */
                                    PBIF [0x0C] = ToString (BMNT, Ones)
                                    Release (LFCM)
                                }
                            }

                            Return (PBIF) /* \_SB_.PCI0.LPC0.EC0_.BAT0.PBIF */
                        }

                        Name (OBST, Zero)
                        Name (OBAC, Zero)
                        Name (OBPR, Zero)
                        Name (OBRC, Zero)
                        Name (OBPV, Zero)
                        Method (_BST, 0, Serialized)  // _BST: Battery Status
                        {
                            If ((ECAV == One))
                            {
                                If ((Acquire (LFCM, 0xA000) == Zero))
                                {
                                    Sleep (0x10)
                                    Local0 = B1ST /* \_SB_.PCI0.LPC0.EC0_.B1ST */
                                    Local1 = DerefOf (PBST [Zero])
                                    Switch ((Local0 & 0x07))
                                    {
                                        Case (Zero)
                                        {
                                            OBST = (Local1 & 0xF8)
                                        }
                                        Case (One)
                                        {
                                            OBST = (One | (Local1 & 0xF8))
                                        }
                                        Case (0x02)
                                        {
                                            OBST = (0x02 | (Local1 & 0xF8))
                                        }
                                        Case (0x04)
                                        {
                                            OBST = (0x04 | (Local1 & 0xF8))
                                        }

                                    }

                                    Sleep (0x10)
                                    OBAC = B1AC /* \_SB_.PCI0.LPC0.EC0_.B1AC */
                                    If ((OBST & One))
                                    {
                                        If ((OBAC != Zero))
                                        {
                                            OBAC = (~OBAC & 0x7FFF)
                                        }
                                    }
                                    ElseIf ((FBFG != One))
                                    {
                                        If ((OBAC == Zero))
                                        {
                                            OBAC = 0xFF
                                        }
                                    }

                                    Sleep (0x10)
                                    OBRC = B1RC /* \_SB_.PCI0.LPC0.EC0_.B1RC */
                                    Sleep (0x10)
                                    OBPV = B1FV /* \_SB_.PCI0.LPC0.EC0_.B1FV */
                                    OBRC *= 0x0A
                                    OBPR = ((OBAC * OBPV) / 0x03E8)
                                    PBST [Zero] = OBST /* \_SB_.PCI0.LPC0.EC0_.BAT0.OBST */
                                    PBST [One] = OBPR /* \_SB_.PCI0.LPC0.EC0_.BAT0.OBPR */
                                    PBST [0x02] = OBRC /* \_SB_.PCI0.LPC0.EC0_.BAT0.OBRC */
                                    PBST [0x03] = OBPV /* \_SB_.PCI0.LPC0.EC0_.BAT0.OBPV */
                                    Release (LFCM)
                                }
                            }

                            Return (PBST) /* \_SB_.PCI0.LPC0.EC0_.BAT0.PBST */
                        }
                    }

                    Scope (\_SB.PCI0.LPC0.EC0)
                    {
                        Device (VPC0)
                        {
                            OperationRegion (BOID, SystemMemory, 0xFED8150C, 0x04)
                            Field (BOID, ByteAcc, NoLock, Preserve)
                            {
                                Offset (0x02), 
                                ID2V,   1
                            }

                            Name (_HID, "VPC2004")  // _HID: Hardware ID
                            Name (_UID, Zero)  // _UID: Unique ID
                            Name (_VPC, 0x400DE114)
                            Name (VPCD, Zero)
                            Method (_HRV, 0, NotSerialized)  // _HRV: Hardware Revision
                            {
                                Return (One)
                            }

                            Method (_STA, 0, NotSerialized)  // _STA: Status
                            {
                                If ((YG53 == Zero))
                                {
                                    _VPC = 0xFC0DF010
                                }

                                If ((YG53 == One))
                                {
                                    _VPC = 0xF40DF018
                                }

                                If ((YG53 == 0x02))
                                {
                                    _VPC = 0xF40DF008
                                }

                                Return (0x0F)
                            }

                            Method (_CFG, 0, NotSerialized)
                            {
                                Return (_VPC) /* \_SB_.PCI0.LPC0.EC0_.VPC0._VPC */
                            }

                            Method (VPCR, 1, Serialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If ((Arg0 == One))
                                        {
                                            VPCD = VCMD /* \_SB_.PCI0.LPC0.EC0_.VCMD */
                                        }
                                        Else
                                        {
                                            VPCD = VDAT /* \_SB_.PCI0.LPC0.EC0_.VDAT */
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (VPCD) /* \_SB_.PCI0.LPC0.EC0_.VPC0.VPCD */
                            }

                            Method (VPCW, 2, Serialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If ((Arg0 == One))
                                        {
                                            VCMD = Arg1
                                        }
                                        Else
                                        {
                                            VDAT = Arg1
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (Zero)
                            }

                            Method (SVCR, 1, Serialized)
                            {
                            }

                            Method (HALS, 0, NotSerialized)
                            {
                                Local0 = Zero
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If (((YG53 == One) && (ID2V == Zero)))
                                        {
                                            Local0 |= 0x10
                                        }

                                        If (((YG53 == One) && (ID2V == Zero)))
                                        {
                                            If ((One == KBLO))
                                            {
                                                Local0 |= 0x20
                                            }
                                        }

                                        Local0 |= 0x40
                                        If ((One == UCHE))
                                        {
                                            Local0 |= 0x80
                                        }

                                        Local0 |= 0x0200
                                        If (HKDB)
                                        {
                                            Local0 |= 0x0400
                                        }

                                        Local0 |= 0x0800
                                        If ((QUIE == One))
                                        {
                                            Local0 |= 0x2000
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (Local0)
                            }

                            Method (SALS, 1, Serialized)
                            {
                                Local0 = ToInteger (Arg0)
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If ((Local0 == 0x08))
                                        {
                                            KBLO = One
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Local0 == 0x09))
                                        {
                                            KBLO = Zero
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Local0 == 0x0A))
                                        {
                                            UCHE = One
                                            SMBB = 0x32
                                            SMBA = 0xCA
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Local0 == 0x0B))
                                        {
                                            UCHE = Zero
                                            SMBB = 0x33
                                            SMBA = 0xCA
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Local0 == 0x0E))
                                        {
                                            HKDB = One
                                            SMBB = 0x31
                                            SMBA = 0xCA
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Local0 == 0x0F))
                                        {
                                            HKDB = Zero
                                            SMBB = 0x30
                                            SMBA = 0xCA
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (Zero)
                            }

                            Method (GBMD, 0, NotSerialized)
                            {
                                Local0 = 0x10000000
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If ((One == CDMB))
                                        {
                                            Local0 |= One
                                        }

                                        If ((One == QCHO))
                                        {
                                            Local0 |= 0x04
                                        }

                                        If ((One == BBAD))
                                        {
                                            Local0 |= 0x08
                                        }

                                        If ((One == BTSM))
                                        {
                                            Local0 |= 0x20
                                        }

                                        If ((One == BLEG))
                                        {
                                            Local0 |= 0x80
                                        }

                                        If ((One == BATF))
                                        {
                                            Local0 |= 0x0100
                                        }

                                        If ((Zero == BTSM))
                                        {
                                            Local0 |= 0x0200
                                        }

                                        If ((One == BUSG))
                                        {
                                            Local0 |= 0x0800
                                        }

                                        If ((Zero == ADPI))
                                        {
                                            Local0 &= 0xFFFE7FFF
                                        }

                                        If ((One == ADPI))
                                        {
                                            Local0 |= 0x8000
                                        }

                                        If ((0x02 == ADPI))
                                        {
                                            Local0 |= 0x00010000
                                        }

                                        Local0 |= 0x00020000
                                        Local0 |= 0x00040000
                                        If ((One == ESMC))
                                        {
                                            Local0 |= 0x00400000
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (Local0)
                            }

                            Name (VBST, Zero)
                            Name (VBAC, Zero)
                            Name (VBPR, Zero)
                            Name (VBRC, Zero)
                            Name (VBPV, Zero)
                            Name (VBFC, Zero)
                            Name (VBCT, Zero)
                            Method (SMTF, 1, NotSerialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If ((Arg0 == Zero))
                                        {
                                            If ((B1FV == Zero))
                                            {
                                                Release (LFCM)
                                                Return (0xFFFF)
                                            }

                                            If ((B1AC == Zero))
                                            {
                                                Release (LFCM)
                                                Return (0xFFFF)
                                            }

                                            Local0 = B1FC /* \_SB_.PCI0.LPC0.EC0_.B1FC */
                                            Local0 *= 0x0A
                                            VBFC = Local0
                                            Local1 = B1RC /* \_SB_.PCI0.LPC0.EC0_.B1RC */
                                            Local1 *= 0x0A
                                            VBRC = Local1
                                            If ((VBFC > VBRC))
                                            {
                                                VBPV = B1FV /* \_SB_.PCI0.LPC0.EC0_.B1FV */
                                                VBAC = B1AC /* \_SB_.PCI0.LPC0.EC0_.B1AC */
                                                Local0 -= Local1
                                                Local1 = (VBAC * VBPV)
                                                Local3 = (Local0 * 0x03E8)
                                                Local3 = (Local3 * 0x3C)
                                                VBCT = (Local3 / Local1)
                                                Release (LFCM)
                                                Return (VBCT) /* \_SB_.PCI0.LPC0.EC0_.VPC0.VBCT */
                                            }
                                            Else
                                            {
                                                Release (LFCM)
                                                Return (0xFFFF)
                                            }
                                        }

                                        If ((Arg0 == One))
                                        {
                                            Release (LFCM)
                                            Return (0xFFFF)
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (0xFFFF)
                            }

                            Name (QBST, Zero)
                            Name (QBAC, Zero)
                            Name (QBPR, Zero)
                            Name (QBRC, Zero)
                            Name (QBPV, Zero)
                            Name (QBFC, Zero)
                            Name (QBCT, Zero)
                            Method (SMTE, 1, NotSerialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If ((Arg0 == Zero))
                                        {
                                            If ((B1FV == Zero))
                                            {
                                                Release (LFCM)
                                                Return (0xFFFF)
                                            }

                                            If ((B1AC == Zero))
                                            {
                                                Release (LFCM)
                                                Return (0xFFFF)
                                            }

                                            Local0 = B1RC /* \_SB_.PCI0.LPC0.EC0_.B1RC */
                                            Local0 *= 0x0A
                                            QBRC = Local0
                                            Local1 = B1FC /* \_SB_.PCI0.LPC0.EC0_.B1FC */
                                            Local1 *= 0x0A
                                            QBFC = Local1
                                            If ((QBFC > QBRC))
                                            {
                                                QBPV = B1FV /* \_SB_.PCI0.LPC0.EC0_.B1FV */
                                                If (((B1AC & 0x8000) == Zero))
                                                {
                                                    QBAC = B1AC /* \_SB_.PCI0.LPC0.EC0_.B1AC */
                                                }
                                                Else
                                                {
                                                    QBAC = (0xFFFF - B1AC)
                                                }

                                                Local1 = (QBAC * QBPV)
                                                Local3 = (Local0 * 0x03E8)
                                                Local3 = (Local3 * 0x3C)
                                                QBCT = (Local3 / Local1)
                                                Release (LFCM)
                                                Return (QBCT) /* \_SB_.PCI0.LPC0.EC0_.VPC0.QBCT */
                                            }
                                            Else
                                            {
                                                Release (LFCM)
                                                Return (0xFFFF)
                                            }
                                        }

                                        If ((Arg0 == One))
                                        {
                                            Release (LFCM)
                                            Return (0xFFFF)
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (0xFFFF)
                            }

                            Method (SBMC, 1, NotSerialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        If ((Arg0 == Zero))
                                        {
                                            CDMB = Zero
                                            EDCC = One
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Arg0 == One))
                                        {
                                            CDMB = One
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Arg0 == 0x03))
                                        {
                                            BTSM = One
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Arg0 == 0x05))
                                        {
                                            BTSM = Zero
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Arg0 == 0x07))
                                        {
                                            QCHO = One
                                            BTSM = Zero
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Arg0 == 0x08))
                                        {
                                            QCHO = Zero
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Arg0 == 0x09))
                                        {
                                            ESMC = One
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        If ((Arg0 == 0x10))
                                        {
                                            ESMC = Zero
                                            Release (LFCM)
                                            Return (Zero)
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (Zero)
                            }

                            Method (MHCF, 1, NotSerialized)
                            {
                                P80H = 0x78
                                Local0 = Arg0
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        Local0 &= 0x20
                                        Local0 >>= 0x05
                                        RMBT = Local0
                                        Sleep (0x14)
                                        Release (LFCM)
                                    }
                                }

                                Return (Local0)
                            }

                            Method (MHPF, 1, NotSerialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        Name (BFWB, Buffer (0x25){})
                                        CreateByteField (BFWB, Zero, FB0)
                                        CreateByteField (BFWB, One, FB1)
                                        CreateByteField (BFWB, 0x02, FB2)
                                        CreateByteField (BFWB, 0x03, FB3)
                                        CreateField (BFWB, 0x20, 0x0100, FB4)
                                        CreateByteField (BFWB, 0x24, FB5)
                                        If ((SizeOf (Arg0) <= 0x25))
                                        {
                                            If ((SMPR != Zero))
                                            {
                                                FB1 = SMST /* \_SB_.PCI0.LPC0.EC0_.SMST */
                                            }
                                            Else
                                            {
                                                BFWB = Arg0
                                                SMAD = FB2 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.FB2_ */
                                                SMCM = FB3 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.FB3_ */
                                                BCNT = FB5 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.FB5_ */
                                                Local0 = FB0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.FB0_ */
                                                If (((Local0 & One) == Zero))
                                                {
                                                    SMDA = FB4 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.FB4_ */
                                                }

                                                SMST = Zero
                                                SMPR = FB0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.FB0_ */
                                                Local1 = 0x03E8
                                                While (Local1)
                                                {
                                                    Sleep (One)
                                                    Local1--
                                                    If (((SMST && 0x80) || (SMPR == Zero)))
                                                    {
                                                        Break
                                                    }
                                                }

                                                Local0 = FB0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.FB0_ */
                                                If (((Local0 & One) != Zero))
                                                {
                                                    FB4 = SMDA /* \_SB_.PCI0.LPC0.EC0_.SMDA */
                                                }

                                                FB1 = SMST /* \_SB_.PCI0.LPC0.EC0_.SMST */
                                                If (((Local1 == Zero) || !(SMST && 0x80)))
                                                {
                                                    SMPR = Zero
                                                    FB1 = 0x92
                                                }
                                            }

                                            Release (LFCM)
                                            Return (BFWB) /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHPF.BFWB */
                                        }

                                        Release (LFCM)
                                    }
                                }
                            }

                            Method (MHIF, 1, NotSerialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        P80H = 0x50
                                        If ((Arg0 == Zero))
                                        {
                                            Name (RETB, Buffer (0x0A){})
                                            Name (BUF1, Buffer (0x08){})
                                            BUF1 = FWBT /* \_SB_.PCI0.LPC0.EC0_.FWBT */
                                            CreateByteField (BUF1, Zero, FW0)
                                            CreateByteField (BUF1, One, FW1)
                                            CreateByteField (BUF1, 0x02, FW2)
                                            CreateByteField (BUF1, 0x03, FW3)
                                            CreateByteField (BUF1, 0x04, FW4)
                                            CreateByteField (BUF1, 0x05, FW5)
                                            CreateByteField (BUF1, 0x06, FW6)
                                            CreateByteField (BUF1, 0x07, FW7)
                                            RETB [Zero] = FUSL /* \_SB_.PCI0.LPC0.EC0_.FUSL */
                                            RETB [One] = FUSH /* \_SB_.PCI0.LPC0.EC0_.FUSH */
                                            RETB [0x02] = FW0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW0_ */
                                            RETB [0x03] = FW1 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW1_ */
                                            RETB [0x04] = FW2 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW2_ */
                                            RETB [0x05] = FW3 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW3_ */
                                            RETB [0x06] = FW4 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW4_ */
                                            RETB [0x07] = FW5 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW5_ */
                                            RETB [0x08] = FW6 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW6_ */
                                            RETB [0x09] = FW7 /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.FW7_ */
                                            Release (LFCM)
                                            Return (RETB) /* \_SB_.PCI0.LPC0.EC0_.VPC0.MHIF.RETB */
                                        }

                                        Release (LFCM)
                                    }
                                }
                            }

                            Method (GSBI, 1, NotSerialized)
                            {
                                Name (BIFB, Buffer (0x53)
                                {
                                    /* 0000 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0008 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0010 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0018 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0020 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0028 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0030 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0038 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0040 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0048 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // ........
                                    /* 0050 */  0xFF, 0xFF, 0xFF                                 // ...
                                })
                                CreateWordField (BIFB, Zero, DCAP)
                                CreateWordField (BIFB, 0x02, FCAP)
                                CreateWordField (BIFB, 0x04, RCAP)
                                CreateWordField (BIFB, 0x06, ATTE)
                                CreateWordField (BIFB, 0x08, ATTF)
                                CreateWordField (BIFB, 0x0A, BTVT)
                                CreateWordField (BIFB, 0x0C, BTCT)
                                CreateWordField (BIFB, 0x0E, BTMP)
                                CreateWordField (BIFB, 0x10, MDAT)
                                CreateWordField (BIFB, 0x12, FUDT)
                                CreateWordField (BIFB, 0x14, DVLT)
                                CreateField (BIFB, 0xB0, 0x50, DCHE)
                                CreateField (BIFB, 0x0100, 0x40, DNAM)
                                CreateField (BIFB, 0x0140, 0x60, MNAM)
                                CreateField (BIFB, 0x01A0, 0xB8, BRNB)
                                CreateQWordField (BIFB, 0x4B, BFW0)
                                If (((Arg0 == Zero) || (Arg0 == One)))
                                {
                                    If (ECAV)
                                    {
                                        If ((Acquire (LFCM, 0xA000) == Zero))
                                        {
                                            Local0 = B1DC /* \_SB_.PCI0.LPC0.EC0_.B1DC */
                                            Local0 *= 0x0A
                                            DCAP = Local0
                                            Local0 = B1FC /* \_SB_.PCI0.LPC0.EC0_.B1FC */
                                            Local0 *= 0x0A
                                            FCAP = Local0
                                            Local0 = B1RC /* \_SB_.PCI0.LPC0.EC0_.B1RC */
                                            Local0 *= 0x0A
                                            RCAP = Local0
                                            ATTE = SMTE (Zero)
                                            ATTF = SMTF (Zero)
                                            BTVT = B1FV /* \_SB_.PCI0.LPC0.EC0_.B1FV */
                                            BTCT = B1AC /* \_SB_.PCI0.LPC0.EC0_.B1AC */
                                            Local0 = B1AT /* \_SB_.PCI0.LPC0.EC0_.B1AT */
                                            Local0 += 0x0111
                                            Local0 *= 0x0A
                                            BTMP = Local0
                                            MDAT = B1DA /* \_SB_.PCI0.LPC0.EC0_.B1DA */
                                            If ((BFUD != Zero))
                                            {
                                                FUDT = BFUD /* \_SB_.PCI0.LPC0.EC0_.BFUD */
                                            }

                                            DVLT = B1DV /* \_SB_.PCI0.LPC0.EC0_.B1DV */
                                            Name (DCH0, Buffer (0x0A)
                                            {
                                                 0x00                                             // .
                                            })
                                            Name (DCH1, "LION")
                                            Name (DCH2, "LiP")
                                            If ((B1TY == One))
                                            {
                                                DCH0 = DCH1 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.DCH1 */
                                                DCHE = DCH0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.DCH0 */
                                            }
                                            Else
                                            {
                                                DCH0 = DCH2 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.DCH2 */
                                                DCHE = DCH0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.DCH0 */
                                            }

                                            Name (BDNT, Buffer (0x08)
                                            {
                                                 0x00                                             // .
                                            })
                                            BDNT = BDN0 /* \_SB_.PCI0.LPC0.EC0_.BDN0 */
                                            DNAM = BDNT /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.BDNT */
                                            Name (BMNT, Buffer (0x0C)
                                            {
                                                 0x00                                             // .
                                            })
                                            BMNT = BMN0 /* \_SB_.PCI0.LPC0.EC0_.BMN0 */
                                            MNAM = BMNT /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.BMNT */
                                            Name (BRN0, Buffer (0x17)
                                            {
                                                 0x00                                             // .
                                            })
                                            Local1 = 0x17
                                            Local2 = 0x2E
                                            While (Local1)
                                            {
                                                BRN0 [(0x17 - Local1)] = SRAM (0x02, Local2)
                                                Local2++
                                                Local1--
                                            }

                                            BRNB = BRN0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.BRN0 */
                                            BFW0 = FWBT /* \_SB_.PCI0.LPC0.EC0_.FWBT */
                                            Release (LFCM)
                                        }
                                    }

                                    Return (BIFB) /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.BIFB */
                                }

                                If ((Arg0 == 0x02))
                                {
                                    Return (BIFB) /* \_SB_.PCI0.LPC0.EC0_.VPC0.GSBI.BIFB */
                                }

                                Return (Zero)
                            }

                            Method (HODD, 0, NotSerialized)
                            {
                            }

                            Method (SODD, 1, Serialized)
                            {
                            }

                            Method (GBID, 0, Serialized)
                            {
                                Name (GBUF, Package (0x04)
                                {
                                    Buffer (0x02)
                                    {
                                         0x00, 0x00                                       // ..
                                    }, 

                                    Buffer (0x02)
                                    {
                                         0x00, 0x00                                       // ..
                                    }, 

                                    Buffer (0x08)
                                    {
                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // ........
                                    }, 

                                    Buffer (0x08)
                                    {
                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // ........
                                    }
                                })
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        DerefOf (GBUF [Zero]) [Zero] = B1CT /* \_SB_.PCI0.LPC0.EC0_.B1CT */
                                        DerefOf (GBUF [One]) [Zero] = Zero
                                        Name (BUF1, Buffer (0x08){})
                                        BUF1 = FWBT /* \_SB_.PCI0.LPC0.EC0_.FWBT */
                                        CreateByteField (BUF1, Zero, FW0)
                                        CreateByteField (BUF1, One, FW1)
                                        CreateByteField (BUF1, 0x02, FW2)
                                        CreateByteField (BUF1, 0x03, FW3)
                                        CreateByteField (BUF1, 0x04, FW4)
                                        CreateByteField (BUF1, 0x05, FW5)
                                        CreateByteField (BUF1, 0x06, FW6)
                                        CreateByteField (BUF1, 0x07, FW7)
                                        DerefOf (GBUF [0x02]) [Zero] = FW0 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW0_ */
                                        DerefOf (GBUF [0x02]) [One] = FW1 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW1_ */
                                        DerefOf (GBUF [0x02]) [0x02] = FW2 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW2_ */
                                        DerefOf (GBUF [0x02]) [0x03] = FW3 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW3_ */
                                        DerefOf (GBUF [0x02]) [0x04] = FW4 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW4_ */
                                        DerefOf (GBUF [0x02]) [0x05] = FW5 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW5_ */
                                        DerefOf (GBUF [0x02]) [0x06] = FW6 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW6_ */
                                        DerefOf (GBUF [0x02]) [0x07] = FW7 /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.FW7_ */
                                        DerefOf (GBUF [0x03]) [Zero] = Zero
                                        Release (LFCM)
                                    }
                                }

                                Return (GBUF) /* \_SB_.PCI0.LPC0.EC0_.VPC0.GBID.GBUF */
                            }

                            Name (APDT, Zero)
                            Method (APPC, 1, Serialized)
                            {
                                APDT = Arg0
                                Return (Zero)
                            }

                            Method (DBSL, 0, NotSerialized)
                            {
                                Return (Package (0x10)
                                {
                                    0xC9, 
                                    0xAE, 
                                    0x95, 
                                    0x7E, 
                                    0x69, 
                                    0x56, 
                                    0x45, 
                                    0x36, 
                                    0x29, 
                                    0x1E, 
                                    0x15, 
                                    0x0E, 
                                    0x09, 
                                    0x06, 
                                    0x05, 
                                    Zero
                                })
                            }

                            Method (SBSL, 1, Serialized)
                            {
                                If (ECAV)
                                {
                                    If ((Acquire (LFCM, 0xA000) == Zero))
                                    {
                                        Local0 = Arg0
                                        If ((Local0 == One))
                                        {
                                            LCBV = 0x0E
                                        }

                                        If ((Local0 == 0x02))
                                        {
                                            LCBV = 0x07
                                        }

                                        Release (LFCM)
                                    }
                                }

                                Return (Zero)
                            }

                            Method (STHT, 1, Serialized)
                            {
                                Return (Zero)
                            }
                        }
                    }

                    Device (CIND)
                    {
                        Name (_HID, "CIND0C60")  // _HID: Hardware ID
                        Name (_CID, "PNP0C60" /* Display Sensor Device */)  // _CID: Compatible ID
                        Method (_STA, 0, NotSerialized)  // _STA: Status
                        {
                            If ((YG53 == One))
                            {
                                Return (0x0F)
                            }

                            Return (Zero)
                        }
                    }

                    Method (_REG, 2, NotSerialized)  // _REG: Region Availability
                    {
                        If ((Arg0 == 0x03))
                        {
                            ECAV = Arg1
                        }

                        If (((Arg0 == 0x03) && (Arg1 == One)))
                        {
                            If ((TPOS == 0x40))
                            {
                                Local0 = One
                            }

                            If ((TPOS == 0x80))
                            {
                                Local0 = 0x02
                            }

                            If ((TPOS == 0x50))
                            {
                                Local0 = 0x03
                            }

                            If ((TPOS == 0x60))
                            {
                                Local0 = 0x04
                            }

                            If ((TPOS == 0x61))
                            {
                                Local0 = 0x05
                            }

                            If ((TPOS == 0x70))
                            {
                                Local0 = 0x06
                            }

                            If ((Acquire (LFCM, 0xA000) == Zero))
                            {
                                OSTY = Local0
                                LIDS = LSTE /* \_SB_.PCI0.LPC0.EC0_.LSTE */
                                Release (LFCM)
                            }
                        }
                    }

                    Method (CMFC, 0, Serialized)
                    {
                        Return (EDID) /* \EDID */
                    }

                    Method (LFCI, 2, Serialized)
                    {
                        Return (OKRB) /* \OKRB */
                    }

                    Method (_Q11, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        If (IGDS)
                        {
                            If ((^^^GP17.VGA.BRIL == 0x0C))
                            {
                                BKLT = One
                            }
                        }

                        P80H = 0x11
                        Notify (^^^GP17.VGA.LCD, 0x87) // Device-Specific
                        Notify (VPC0, 0x80) // Status Change
                    }

                    Method (_Q12, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        If (IGDS)
                        {
                            If ((BKLT == One))
                            {
                                BKLT = Zero
                            }
                            Else
                            {
                                P80H = 0x12
                                Notify (^^^GP17.VGA.LCD, 0x86) // Device-Specific
                                Notify (VPC0, 0x80) // Status Change
                            }
                        }
                        Else
                        {
                            P80H = 0x12
                            Notify (^^^GP17.VGA.LCD, 0x86) // Device-Specific
                            Notify (VPC0, 0x80) // Status Change
                        }
                    }

                    Method (_Q13, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        CreateWordField (XX11, Zero, SSZE)
                        CreateByteField (XX11, 0x02, SMUF)
                        CreateDWordField (XX11, 0x03, SMUD)
                        SSZE = 0x07
                        SMUF = 0x05
                        If ((QUIE == 0x02))
                        {
                            SMUD = 0x32C8
                        }
                        Else
                        {
                            SMUD = 0x3A98
                        }

                        ALIB (0x0C, XX11)
                        P80H = 0x13
                        If ((QUIE == 0x02))
                        {
                            SMBB = 0x36
                            SMBA = 0xCA
                        }
                        Else
                        {
                            SMBB = 0x35
                            SMBA = 0xCA
                        }
                    }

                    Method (_Q15, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x15
                        If (ECAV)
                        {
                            If ((Acquire (LFCM, 0xA000) == Zero))
                            {
                                LIDS = LSTE /* \_SB_.PCI0.LPC0.EC0_.LSTE */
                                Release (LFCM)
                            }
                        }

                        Notify (LID, 0x80) // Status Change
                    }

                    Method (_Q16, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x16
                        If (ECAV)
                        {
                            If ((Acquire (LFCM, 0xA000) == Zero))
                            {
                                LIDS = LSTE /* \_SB_.PCI0.LPC0.EC0_.LSTE */
                                Release (LFCM)
                            }
                        }

                        Notify (LID, 0x80) // Status Change
                    }

                    Method (_Q25, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x25
                        Notify (ADP0, 0x80) // Status Change
                        Notify (BAT0, 0x80) // Status Change
                        Notify (BAT0, 0x81) // Information Change
                    }

                    Method (_Q37, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x37
                        Sleep (0xC8)
                        PWRS = One
                        Notify (ADP0, 0x80) // Status Change
                        Notify (BAT0, 0x80) // Status Change
                    }

                    Method (_Q38, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x38
                        Sleep (0xC8)
                        PWRS = Zero
                        Notify (ADP0, 0x80) // Status Change
                        Notify (BAT0, 0x80) // Status Change
                    }

                    Method (_Q32, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x32
                        Notify (PWRB, 0x80) // Status Change
                    }

                    Method (_Q3E, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x3E
                        Notify (^^^^I2CB.TPD0, 0x3E) // Reserved
                    }

                    Method (_Q3F, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x3F
                        Notify (^^^^I2CB.TPD0, 0x3F) // Reserved
                    }

                    Method (_Q44, 0, NotSerialized)  // _Qxx: EC Query
                    {
                        P80H = 0x44
                        Notify (VPC0, 0x80) // Status Change
                    }
                }

                Scope (\_SB)
                {
                    Device (ADP0)
                    {
                        Name (_HID, "ACPI0003" /* Power Source Device */)  // _HID: Hardware ID
                        Name (XX00, Buffer (0x03){})
                        Name (ACDC, 0xFF)
                        Method (_STA, 0, NotSerialized)  // _STA: Status
                        {
                            If ((ECON == One))
                            {
                                Return (0x0F)
                            }

                            Return (Zero)
                        }

                        Method (_PSR, 0, NotSerialized)  // _PSR: Power Source
                        {
                            If (^^PCI0.LPC0.EC0.ECAV)
                            {
                                If ((Acquire (^^PCI0.LPC0.EC0.LFCM, 0xA000) == Zero))
                                {
                                    Local0 = One
                                    Local0 = ^^PCI0.LPC0.EC0.ADPT /* \_SB_.PCI0.LPC0.EC0_.ADPT */
                                    If (((Local0 != ACDC) || (ACDC == 0xFF)))
                                    {
                                        CreateWordField (XX00, Zero, SSZE)
                                        CreateByteField (XX00, 0x02, ACST)
                                        SSZE = 0x03
                                        If (Local0)
                                        {
                                            P80H = 0xAC
                                            AFN4 (One)
                                            ACST = Zero
                                        }
                                        Else
                                        {
                                            P80H = 0xDC
                                            AFN4 (0x02)
                                            ACST = One
                                        }

                                        Sleep (0x64)
                                        ALIB (One, XX00)
                                        ACDC = Local0
                                    }

                                    Release (^^PCI0.LPC0.EC0.LFCM)
                                    Return (Local0)
                                }
                            }
                        }

                        Method (_PCL, 0, NotSerialized)  // _PCL: Power Consumer List
                        {
                            Return (Package (0x01)
                            {
                                _SB
                            })
                        }
                    }

                    Device (LID)
                    {
                        Name (_HID, EisaId ("PNP0C0D") /* Lid Device */)  // _HID: Hardware ID
                        Method (_STA, 0, NotSerialized)  // _STA: Status
                        {
                            If ((ECON == One))
                            {
                                Return (0x0F)
                            }

                            Return (Zero)
                        }

                        Method (_LID, 0, NotSerialized)  // _LID: Lid Status
                        {
                            Local0 = Zero
                            If ((Acquire (^^PCI0.LPC0.EC0.LFCM, 0xA000) == Zero))
                            {
                                Local0 = ^^PCI0.LPC0.EC0.LSTE /* \_SB_.PCI0.LPC0.EC0_.LSTE */
                                Release (^^PCI0.LPC0.EC0.LFCM)
                            }

                            Return (Local0)
                        }
                    }

                    Device (PWRB)
                    {
                        Name (_HID, EisaId ("PNP0C0C") /* Power Button Device */)  // _HID: Hardware ID
                        Method (_STA, 0, NotSerialized)  // _STA: Status
                        {
                            If ((ECON == One))
                            {
                                Return (0x0F)
                            }

                            Return (Zero)
                        }
                    }

                    Device (WMI4)
                    {
                        Name (_HID, EisaId ("PNP0C14") /* Windows Management Instrumentation Device */)  // _HID: Hardware ID
                        Name (_UID, 0x04)  // _UID: Unique ID
                        Mutex (MWMI, 0x00)
                        Name (_WDG, Buffer (0x28)
                        {
                            /* 0000 */  0x76, 0x37, 0xA0, 0xC3, 0xAC, 0x51, 0xAA, 0x49,  // v7...Q.I
                            /* 0008 */  0xAD, 0x0F, 0xF2, 0xF7, 0xD6, 0x2C, 0x3F, 0x3C,  // .....,?<
                            /* 0010 */  0x41, 0x44, 0x03, 0x05, 0x21, 0x12, 0x90, 0x05,  // AD..!...
                            /* 0018 */  0x66, 0xD5, 0xD1, 0x11, 0xB2, 0xF0, 0x00, 0xA0,  // f.......
                            /* 0020 */  0xC9, 0x06, 0x29, 0x10, 0x42, 0x44, 0x01, 0x00   // ..).BD..
                        })
                        Name (ITEM, Package (0x03)
                        {
                            Package (0x03)
                            {
                                Zero, 
                                Zero, 
                                "BAT0 BatMaker"
                            }, 

                            Package (0x03)
                            {
                                Zero, 
                                One, 
                                "BAT0 HwId "
                            }, 

                            Package (0x03)
                            {
                                Zero, 
                                0x02, 
                                "BAT0 MfgDate "
                            }
                        })
                        Method (WQAD, 1, NotSerialized)
                        {
                            If (^^PCI0.LPC0.EC0.ECAV)
                            {
                                If ((Acquire (^^PCI0.LPC0.EC0.LFCM, 0xA000) == Zero))
                                {
                                    Local0 = PSAG (Arg0)
                                    Local1 = DerefOf (ITEM [Local0])
                                    Local2 = DerefOf (Local1 [Zero])
                                    Local3 = DerefOf (Local1 [One])
                                    Local4 = DerefOf (Local1 [0x02])
                                    Local5 = BATD (Local2, Local3)
                                    Concatenate (Local4, ",", Local6)
                                    Concatenate (Local6, Local5, Local7)
                                    Release (^^PCI0.LPC0.EC0.LFCM)
                                }
                            }

                            Return (Local7)
                        }

                        Method (PSAG, 1, NotSerialized)
                        {
                            Return (Arg0)
                        }

                        Method (BATD, 2, NotSerialized)
                        {
                            Name (STRB, Buffer (0x0A)
                            {
                                 0x00                                             // .
                            })
                            Name (BUFR, Buffer (0x08){})
                            BUFR = ^^PCI0.LPC0.EC0.FWBT /* \_SB_.PCI0.LPC0.EC0_.FWBT */
                            CreateWordField (BUFR, Zero, MID0)
                            CreateWordField (BUFR, 0x02, HID0)
                            CreateWordField (BUFR, 0x04, FIR0)
                            CreateWordField (BUFR, 0x06, DAT0)
                            If ((Arg0 == Zero))
                            {
                                If ((Arg1 == Zero))
                                {
                                    STRB = ToHexString (MID0)
                                }

                                If ((Arg1 == One))
                                {
                                    STRB = ToHexString (HID0)
                                }

                                If ((Arg1 == 0x02))
                                {
                                    Local0 = ^^PCI0.LPC0.EC0.B1DA /* \_SB_.PCI0.LPC0.EC0_.B1DA */
                                    Name (DATB, Buffer (0x09)
                                    {
                                        "00000000"
                                    })
                                    Local3 = 0x07
                                    Local1 = (Local0 & 0x1F)
                                    While (Local1)
                                    {
                                        Divide (Local1, 0x0A, Local2, Local1)
                                        DATB [Local3] = (Local2 + 0x30)
                                        Local3--
                                    }

                                    Local3 = 0x05
                                    Local1 = ((Local0 & 0x01E0) >> 0x05)
                                    While (Local1)
                                    {
                                        Divide (Local1, 0x0A, Local2, Local1)
                                        DATB [Local3] = (Local2 + 0x30)
                                        Local3--
                                    }

                                    Local3 = 0x03
                                    Local1 = (((Local0 & 0xFE00) >> 0x09) + 0x07BC)
                                    While (Local1)
                                    {
                                        Divide (Local1, 0x0A, Local2, Local1)
                                        DATB [Local3] = (Local2 + 0x30)
                                        Local3--
                                    }

                                    STRB = DATB /* \_SB_.WMI4.BATD.DATB */
                                }
                            }

                            Return (ToString (STRB, Ones))
                        }

                        Name (WQBD, Buffer (0x0275)
                        {
                            /* 0000 */  0x46, 0x4F, 0x4D, 0x42, 0x01, 0x00, 0x00, 0x00,  // FOMB....
                            /* 0008 */  0x65, 0x02, 0x00, 0x00, 0xF8, 0x05, 0x00, 0x00,  // e.......
                            /* 0010 */  0x44, 0x53, 0x00, 0x01, 0x1A, 0x7D, 0xDA, 0x54,  // DS...}.T
                            /* 0018 */  0x18, 0xD1, 0x82, 0x00, 0x01, 0x06, 0x18, 0x42,  // .......B
                            /* 0020 */  0x10, 0x05, 0x10, 0x8A, 0x0D, 0x21, 0x02, 0x0B,  // .....!..
                            /* 0028 */  0x83, 0x50, 0x50, 0x18, 0x14, 0xA0, 0x45, 0x41,  // .PP...EA
                            /* 0030 */  0xC8, 0x05, 0x14, 0x95, 0x02, 0x21, 0xC3, 0x02,  // .....!..
                            /* 0038 */  0x14, 0x0B, 0x70, 0x2E, 0x40, 0xBA, 0x00, 0xE5,  // ..p.@...
                            /* 0040 */  0x28, 0x72, 0x0C, 0x22, 0x02, 0xF7, 0xEF, 0x0F,  // (r."....
                            /* 0048 */  0x31, 0xD0, 0x18, 0xA8, 0x50, 0x08, 0x89, 0x00,  // 1...P...
                            /* 0050 */  0xA6, 0x42, 0xE0, 0x08, 0x41, 0xBF, 0x02, 0x10,  // .B..A...
                            /* 0058 */  0x3A, 0x14, 0x20, 0x53, 0x80, 0x41, 0x01, 0x4E,  // :. S.A.N
                            /* 0060 */  0x11, 0x44, 0x10, 0xA5, 0x65, 0x01, 0xBA, 0x05,  // .D..e...
                            /* 0068 */  0xF8, 0x16, 0xA0, 0x1D, 0x42, 0x68, 0x91, 0x9A,  // ....Bh..
                            /* 0070 */  0x9F, 0x04, 0x81, 0x6A, 0x5B, 0x80, 0x45, 0x01,  // ...j[.E.
                            /* 0078 */  0xB2, 0x41, 0x08, 0xA0, 0xC7, 0xC1, 0x44, 0x0E,  // .A....D.
                            /* 0080 */  0x02, 0x25, 0x66, 0x10, 0x28, 0x9D, 0x73, 0x90,  // .%f.(.s.
                            /* 0088 */  0x4D, 0x60, 0xE1, 0x9F, 0x4C, 0x94, 0xF3, 0x88,  // M`..L...
                            /* 0090 */  0x92, 0xE0, 0xA8, 0x0E, 0x22, 0x42, 0xF0, 0x72,  // ...."B.r
                            /* 0098 */  0x05, 0x48, 0x9E, 0x80, 0x34, 0x4F, 0x4C, 0xD6,  // .H..4OL.
                            /* 00A0 */  0x07, 0xA1, 0x21, 0xB0, 0x11, 0xF0, 0x88, 0x12,  // ..!.....
                            /* 00A8 */  0x40, 0x58, 0xA0, 0x75, 0x2A, 0x14, 0x0C, 0xCA,  // @X.u*...
                            /* 00B0 */  0x03, 0x88, 0xE4, 0x8C, 0x15, 0x05, 0x6C, 0xAF,  // ......l.
                            /* 00B8 */  0x13, 0x91, 0xC9, 0x81, 0x52, 0x49, 0x70, 0xA8,  // ....RIp.
                            /* 00C0 */  0x61, 0x5A, 0xE2, 0xEC, 0x34, 0xB2, 0x13, 0x39,  // aZ..4..9
                            /* 00C8 */  0xB6, 0xA6, 0x87, 0x2C, 0x48, 0x26, 0x6D, 0x28,  // ...,H&m(
                            /* 00D0 */  0xA8, 0xB1, 0x7B, 0x5A, 0x27, 0xE5, 0x99, 0x46,  // ..{Z'..F
                            /* 00D8 */  0x3C, 0x28, 0xC3, 0x24, 0xF0, 0x28, 0x18, 0x1A,  // <(.$.(..
                            /* 00E0 */  0x27, 0x28, 0x0B, 0x42, 0x0E, 0x06, 0x8A, 0x02,  // '(.B....
                            /* 00E8 */  0x3C, 0x09, 0xCF, 0xB1, 0x78, 0x01, 0xC2, 0x67,  // <...x..g
                            /* 00F0 */  0x4C, 0xA6, 0x1D, 0x23, 0x81, 0xCF, 0x04, 0x1E,  // L..#....
                            /* 00F8 */  0xE6, 0x31, 0x63, 0x47, 0x14, 0x2E, 0xE0, 0xF9,  // .1cG....
                            /* 0100 */  0x1C, 0x43, 0xE4, 0xB8, 0x87, 0x1A, 0xE3, 0x28,  // .C.....(
                            /* 0108 */  0x22, 0x3F, 0x08, 0x60, 0x05, 0x1D, 0x04, 0x90,  // "?.`....
                            /* 0110 */  0x38, 0xFF, 0xFF, 0xE3, 0x89, 0x76, 0xDA, 0xC1,  // 8....v..
                            /* 0118 */  0x42, 0xC7, 0x39, 0xBF, 0xD0, 0x18, 0xD1, 0xE3,  // B.9.....
                            /* 0120 */  0x40, 0xC9, 0x80, 0x90, 0x47, 0x01, 0x56, 0x61,  // @...G.Va
                            /* 0128 */  0x35, 0x91, 0x04, 0xBE, 0x07, 0x74, 0x76, 0x12,  // 5....tv.
                            /* 0130 */  0xD0, 0xA5, 0x21, 0x46, 0x6F, 0x08, 0xD2, 0x26,  // ..!Fo..&
                            /* 0138 */  0xC0, 0x96, 0x00, 0x6B, 0x02, 0x8C, 0xDD, 0x06,  // ...k....
                            /* 0140 */  0x08, 0xCA, 0xD1, 0x36, 0x87, 0x22, 0x84, 0x28,  // ...6.".(
                            /* 0148 */  0x21, 0xE2, 0x86, 0xAC, 0x11, 0x45, 0x10, 0x95,  // !....E..
                            /* 0150 */  0x41, 0x08, 0x35, 0x50, 0xD8, 0x28, 0xF1, 0x8D,  // A.5P.(..
                            /* 0158 */  0x13, 0x22, 0x48, 0x02, 0x8F, 0x1C, 0x77, 0x04,  // ."H...w.
                            /* 0160 */  0xF0, 0xD8, 0x0E, 0xE8, 0x04, 0x4F, 0xE9, 0x71,  // .....O.q
                            /* 0168 */  0xC1, 0x04, 0x9E, 0xF7, 0xC1, 0x1D, 0xEA, 0x21,  // .......!
                            /* 0170 */  0x1C, 0x70, 0xD4, 0x18, 0xC7, 0xF1, 0x4C, 0x40,  // .p....L@
                            /* 0178 */  0x16, 0x2E, 0x0D, 0x20, 0x8A, 0x04, 0x8F, 0x3A,  // ... ...:
                            /* 0180 */  0x32, 0xF8, 0x70, 0xE0, 0x41, 0x7A, 0x9E, 0x9E,  // 2.p.Az..
                            /* 0188 */  0x40, 0x90, 0x43, 0x38, 0x82, 0xC7, 0x86, 0xA7,  // @.C8....
                            /* 0190 */  0x02, 0x8F, 0x81, 0x5D, 0x17, 0x7C, 0x0E, 0xF0,  // ...].|..
                            /* 0198 */  0x31, 0x01, 0xEF, 0x1A, 0x50, 0xA3, 0x7E, 0x3A,  // 1...P.~:
                            /* 01A0 */  0x60, 0x93, 0x0E, 0x87, 0x19, 0xAE, 0x87, 0x1D,  // `.......
                            /* 01A8 */  0xEE, 0x04, 0x1E, 0x0E, 0x1E, 0x33, 0xF8, 0x91,  // .....3..
                            /* 01B0 */  0xC3, 0x83, 0xC3, 0xCD, 0xF0, 0x64, 0x8E, 0xAC,  // .....d..
                            /* 01B8 */  0x54, 0x01, 0x66, 0x4F, 0x08, 0x3A, 0x4D, 0xF8,  // T.fO.:M.
                            /* 01C0 */  0xCC, 0xC1, 0x6E, 0x00, 0xE7, 0xD3, 0x33, 0x24,  // ..n...3$
                            /* 01C8 */  0x91, 0x3F, 0x08, 0xD4, 0xC8, 0x0C, 0xED, 0x69,  // .?.....i
                            /* 01D0 */  0xBF, 0x7A, 0x18, 0xF2, 0xA1, 0xE0, 0xB0, 0x98,  // .z......
                            /* 01D8 */  0xD8, 0xB3, 0x07, 0x1D, 0x0F, 0xF8, 0xAF, 0x24,  // .......$
                            /* 01E0 */  0x0F, 0x1B, 0x9E, 0xBE, 0xE7, 0x6B, 0x82, 0x91,  // .....k..
                            /* 01E8 */  0x07, 0x8E, 0x1E, 0x88, 0xA1, 0x9F, 0x38, 0x0E,  // ......8.
                            /* 01F0 */  0xE3, 0x34, 0x7C, 0x09, 0xF1, 0x39, 0xE0, 0xFF,  // .4|..9..
                            /* 01F8 */  0x1F, 0x24, 0xC6, 0x31, 0x79, 0x70, 0x3C, 0xD8,  // .$.1yp<.
                            /* 0200 */  0xC8, 0xE9, 0x51, 0xC5, 0x47, 0x0A, 0x7E, 0xBE,  // ..Q.G.~.
                            /* 0208 */  0xF0, 0x91, 0x82, 0x5D, 0x10, 0x9E, 0x1C, 0x0C,  // ...]....
                            /* 0210 */  0x71, 0x38, 0x67, 0xE5, 0x13, 0x85, 0x0F, 0x2A,  // q8g....*
                            /* 0218 */  0xB8, 0x13, 0x05, 0x5C, 0x85, 0xE8, 0xE4, 0x36,  // ...\...6
                            /* 0220 */  0x61, 0xB4, 0x67, 0x81, 0xC7, 0x09, 0x98, 0x07,  // a.g.....
                            /* 0228 */  0x01, 0xF0, 0x8D, 0xDF, 0x07, 0x19, 0xB0, 0x4D,  // .......M
                            /* 0230 */  0x09, 0x3B, 0x24, 0x78, 0x47, 0x19, 0xE0, 0x71,  // .;$xG..q
                            /* 0238 */  0x32, 0xC1, 0x1D, 0x27, 0x3C, 0x04, 0x3E, 0x80,  // 2..'<.>.
                            /* 0240 */  0x87, 0x90, 0x93, 0xB4, 0xD2, 0xA9, 0x21, 0xCF,  // ......!.
                            /* 0248 */  0x3C, 0x60, 0x1B, 0x06, 0x57, 0x68, 0xD3, 0xA7,  // <`..Wh..
                            /* 0250 */  0x46, 0xA3, 0x56, 0x0D, 0xCA, 0xD4, 0x28, 0xD3,  // F.V...(.
                            /* 0258 */  0xA0, 0x56, 0x9F, 0x4A, 0x8D, 0x19, 0xFB, 0xE1,  // .V.J....
                            /* 0260 */  0x58, 0xDC, 0xBB, 0x40, 0x07, 0x03, 0x0B, 0x7B,  // X..@...{
                            /* 0268 */  0x21, 0xE8, 0x88, 0xE0, 0x58, 0x20, 0x34, 0x08,  // !...X 4.
                            /* 0270 */  0x9D, 0x40, 0xFC, 0xFF, 0x07                     // .@...
                        })
                    }
                }

                Mutex (PSMX, 0x00)
            }
        }

        OperationRegion (PIRQ, SystemIO, 0x0C00, 0x02)
        Field (PIRQ, ByteAcc, NoLock, Preserve)
        {
            PIDX,   8, 
            PDAT,   8
        }

        IndexField (PIDX, PDAT, ByteAcc, NoLock, Preserve)
        {
            PIRA,   8, 
            PIRB,   8, 
            PIRC,   8, 
            PIRD,   8, 
            PIRE,   8, 
            PIRF,   8, 
            PIRG,   8, 
            PIRH,   8, 
            Offset (0x0C), 
            SIRA,   8, 
            SIRB,   8, 
            SIRC,   8, 
            SIRD,   8, 
            PIRS,   8, 
            Offset (0x13), 
            HDAD,   8, 
            Offset (0x17), 
            SDCL,   8, 
            Offset (0x1A), 
            SDIO,   8, 
            Offset (0x30), 
            USB1,   8, 
            Offset (0x34), 
            USB3,   8, 
            Offset (0x41), 
            SATA,   8, 
            Offset (0x62), 
            GIOC,   8, 
            Offset (0x70), 
            I2C0,   8, 
            I2C1,   8, 
            I2C2,   8, 
            I2C3,   8, 
            URT0,   8, 
            URT1,   8
        }

        OperationRegion (KBDD, SystemIO, 0x64, One)
        Field (KBDD, ByteAcc, NoLock, Preserve)
        {
            PD64,   8
        }

        Method (DSPI, 0, NotSerialized)
        {
            INTA (0x1F)
            INTB (0x1F)
            INTC (0x1F)
            INTD (0x1F)
            Local1 = PD64 /* \_SB_.PD64 */
            PIRE = 0x1F
            PIRF = 0x1F
            PIRG = 0x1F
            PIRH = 0x1F
        }

        Method (INTA, 1, NotSerialized)
        {
            PIRA = Arg0
            If (PICM)
            {
                HDAD = Arg0
                SDCL = Arg0
            }
        }

        Method (INTB, 1, NotSerialized)
        {
            PIRB = Arg0
        }

        Method (INTC, 1, NotSerialized)
        {
            PIRC = Arg0
            If (PICM)
            {
                USB1 = Arg0
                USB3 = Arg0
            }
        }

        Method (INTD, 1, NotSerialized)
        {
            PIRD = Arg0
            If (PICM)
            {
                SATA = Arg0
            }
        }

        Name (PRS1, ResourceTemplate ()
        {
            IRQ (Level, ActiveLow, Shared, )
                {3,5,6,10,11}
        })
        Name (BUFA, ResourceTemplate ()
        {
            IRQ (Level, ActiveLow, Shared, )
                {15}
        })
        Device (LNKA)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, One)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRA && (PIRA != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                INTA (0x1F)
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRA) /* \_SB_.PIRA */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRA = Local0
            }
        }

        Device (LNKB)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, 0x02)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRB && (PIRB != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                INTB (0x1F)
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRB) /* \_SB_.PIRB */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRB = Local0
            }
        }

        Device (LNKC)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, 0x03)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRC && (PIRC != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                INTC (0x1F)
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRC) /* \_SB_.PIRC */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRC = Local0
            }
        }

        Device (LNKD)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, 0x04)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRD && (PIRD != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                INTD (0x1F)
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRD) /* \_SB_.PIRD */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRD = Local0
            }
        }

        Device (LNKE)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, 0x05)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRE && (PIRE != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                PIRE = 0x1F
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRE) /* \_SB_.PIRE */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRE = Local0
            }
        }

        Device (LNKF)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, 0x06)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRF && (PIRF != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                PIRF = 0x1F
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRF) /* \_SB_.PIRF */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRF = Local0
            }
        }

        Device (LNKG)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, 0x07)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRG && (PIRG != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                PIRG = 0x1F
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRG) /* \_SB_.PIRG */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRG = Local0
            }
        }

        Device (LNKH)
        {
            Name (_HID, EisaId ("PNP0C0F") /* PCI Interrupt Link Device */)  // _HID: Hardware ID
            Name (_UID, 0x08)  // _UID: Unique ID
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((PIRH && (PIRH != 0x1F)))
                {
                    Return (0x0B)
                }
                Else
                {
                    Return (0x09)
                }
            }

            Method (_PRS, 0, NotSerialized)  // _PRS: Possible Resource Settings
            {
                Return (PRS1) /* \_SB_.PRS1 */
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
                PIRH = 0x1F
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                CreateWordField (BUFA, One, IRQX)
                IRQX = (One << PIRH) /* \_SB_.PIRH */
                Return (BUFA) /* \_SB_.BUFA */
            }

            Method (_SRS, 1, NotSerialized)  // _SRS: Set Resource Settings
            {
                CreateWordField (Arg0, One, IRA)
                FindSetRightBit (IRA, Local0)
                Local0--
                PIRH = Local0
            }
        }

        Method (GSMI, 1, NotSerialized)
        {
            APMD = Arg0
            APMC = 0xE4
            Sleep (0x02)
        }

        Method (S80H, 1, NotSerialized)
        {
            P80H = Arg0
        }

        Method (BSMI, 1, NotSerialized)
        {
            APMD = Arg0
            APMC = 0xBE
            Sleep (One)
        }
    }

    Name (TSOS, 0x75)
    If (CondRefOf (\_OSI))
    {
        If (_OSI ("Windows 2009"))
        {
            TSOS = 0x50
        }

        If (_OSI ("Windows 2015"))
        {
            TSOS = 0x70
        }

        If (_OSI ("Linux"))
        {
            TSOS = 0x80
        }
    }

    Scope (_SB)
    {
        OperationRegion (SMIC, SystemMemory, 0xFED80000, 0x00800000)
        Field (SMIC, ByteAcc, NoLock, Preserve)
        {
            Offset (0x36A), 
            SMIB,   8
        }

        OperationRegion (SSMI, SystemIO, SMIB, 0x02)
        Field (SSMI, AnyAcc, NoLock, Preserve)
        {
            SMIW,   16
        }

        OperationRegion (ECMC, SystemIO, 0x72, 0x02)
        Field (ECMC, AnyAcc, NoLock, Preserve)
        {
            ECMI,   8, 
            ECMD,   8
        }

        IndexField (ECMI, ECMD, ByteAcc, NoLock, Preserve)
        {
            Offset (0x08), 
            FRTB,   32
        }

        OperationRegion (FRTP, SystemMemory, FRTB, 0x0100)
        Field (FRTP, AnyAcc, NoLock, Preserve)
        {
            PEBA,   32, 
                ,   5, 
            IC0E,   1, 
            IC1E,   1, 
            IC2E,   1, 
            IC3E,   1, 
            IC4E,   1, 
            IC5E,   1, 
            UT0E,   1, 
            UT1E,   1, 
                ,   1, 
                ,   1, 
            ST_E,   1, 
            UT2E,   1, 
                ,   1, 
            EMMD,   2, 
                ,   3, 
            XHCE,   1, 
                ,   1, 
                ,   1, 
            UT3E,   1, 
            ESPI,   1, 
            EMME,   1, 
            Offset (0x08), 
            PCEF,   1, 
                ,   4, 
            IC0D,   1, 
            IC1D,   1, 
            IC2D,   1, 
            IC3D,   1, 
            IC4D,   1, 
            IC5D,   1, 
            UT0D,   1, 
            UT1D,   1, 
                ,   1, 
                ,   1, 
            ST_D,   1, 
            UT2D,   1, 
                ,   1, 
            EHCD,   1, 
                ,   4, 
            XHCD,   1, 
            SD_D,   1, 
                ,   1, 
            UT3D,   1, 
                ,   1, 
            EMD3,   1, 
                ,   2, 
            S03D,   1, 
            FW00,   16, 
            FW01,   32, 
            FW02,   16, 
            FW03,   32, 
            SDS0,   8, 
            SDS1,   8, 
            CZFG,   1, 
            Offset (0x20), 
            SD10,   32, 
            EH10,   32, 
            XH10,   32, 
            STBA,   32
        }

        OperationRegion (FCFG, SystemMemory, PEBA, 0x01000000)
        Field (FCFG, DWordAcc, NoLock, Preserve)
        {
            Offset (0xA3044), 
            IPDE,   32, 
            IMPE,   32, 
            Offset (0xA3078), 
                ,   2, 
            LDQ0,   1, 
            Offset (0xA30CB), 
                ,   7, 
            AUSS,   1, 
            Offset (0xA30D0), 
                ,   13, 
            LCLK,   2
        }

        OperationRegion (IOMX, SystemMemory, 0xFED80D00, 0x0100)
        Field (IOMX, AnyAcc, NoLock, Preserve)
        {
            Offset (0x15), 
            IM15,   8, 
            IM16,   8, 
            Offset (0x1F), 
            IM1F,   8, 
            IM20,   8, 
            Offset (0x44), 
            IM44,   8, 
            Offset (0x46), 
            IM46,   8, 
            Offset (0x4A), 
            IM4A,   8, 
            IM4B,   8, 
            Offset (0x57), 
            IM57,   8, 
            IM58,   8, 
            Offset (0x68), 
            IM68,   8, 
            IM69,   8, 
            IM6A,   8, 
            IM6B,   8, 
            Offset (0x6D), 
            IM6D,   8
        }

        OperationRegion (FMIS, SystemMemory, 0xFED80E00, 0x0100)
        Field (FMIS, AnyAcc, NoLock, Preserve)
        {
            Offset (0x40), 
                ,   13, 
            I24M,   1
        }

        OperationRegion (FGIO, SystemMemory, 0xFED81500, 0x0300)
        Field (FGIO, AnyAcc, NoLock, Preserve)
        {
            Offset (0xA8), 
                ,   22, 
            O042,   1, 
            Offset (0x164), 
                ,   22, 
            O089,   1
        }

        OperationRegion (FACR, SystemMemory, 0xFED81E00, 0x0100)
        Field (FACR, AnyAcc, NoLock, Preserve)
        {
            Offset (0x80), 
                ,   28, 
            RD28,   1, 
                ,   1, 
            RQTY,   1, 
            Offset (0x84), 
                ,   28, 
            SD28,   1, 
                ,   1, 
            Offset (0xA0), 
            PG1A,   1
        }

        OperationRegion (EMMX, SystemMemory, 0xFEDD5800, 0x0130)
        Field (EMMX, AnyAcc, NoLock, Preserve)
        {
            Offset (0xD0), 
                ,   17, 
            FC18,   1, 
            FC33,   1, 
                ,   7, 
            CD_T,   1, 
            WP_T,   1
        }

        OperationRegion (EMMB, SystemMemory, 0xFEDD5800, 0x0130)
        Field (EMMB, AnyAcc, NoLock, Preserve)
        {
            Offset (0xA4), 
            E0A4,   32, 
            E0A8,   32, 
            Offset (0xB0), 
            E0B0,   32, 
            Offset (0xD0), 
            E0D0,   32, 
            Offset (0x116), 
            E116,   32
        }

        Name (SVBF, Buffer (0x0100)
        {
             0x00                                             // .
        })
        CreateDWordField (SVBF, Zero, S0A4)
        CreateDWordField (SVBF, 0x04, S0A8)
        CreateDWordField (SVBF, 0x08, S0B0)
        CreateDWordField (SVBF, 0x0C, S0D0)
        CreateDWordField (SVBF, 0x10, S116)
        Method (SECR, 0, Serialized)
        {
            S116 = E116 /* \_SB_.E116 */
            RQTY = Zero
            RD28 = One
            Local0 = SD28 /* \_SB_.SD28 */
            While (Local0)
            {
                Local0 = SD28 /* \_SB_.SD28 */
            }
        }

        Method (RECR, 0, Serialized)
        {
            E116 = S116 /* \_SB_.S116 */
        }

        OperationRegion (LUIE, SystemMemory, 0xFEDC0020, 0x04)
        Field (LUIE, AnyAcc, NoLock, Preserve)
        {
            IER0,   1, 
            IER1,   1, 
            IER2,   1, 
            IER3,   1, 
            UOL0,   1, 
            UOL1,   1, 
            UOL2,   1, 
            UOL3,   1, 
            WUR0,   2, 
            WUR1,   2, 
            WUR2,   2, 
            WUR3,   2
        }

        Method (FRUI, 1, Serialized)
        {
            If ((Arg0 == Zero))
            {
                Return (IUA0) /* \_SB_.IUA0 */
            }

            If ((Arg0 == One))
            {
                Return (IUA1) /* \_SB_.IUA1 */
            }

            If ((Arg0 == 0x02))
            {
                Return (IUA2) /* \_SB_.IUA2 */
            }

            If ((Arg0 == 0x03))
            {
                Return (IUA3) /* \_SB_.IUA3 */
            }
        }

        Method (SRAD, 2, Serialized)
        {
            Local0 = (Arg0 << One)
            Local0 += 0xFED81E40
            OperationRegion (ADCR, SystemMemory, Local0, 0x02)
            Field (ADCR, ByteAcc, NoLock, Preserve)
            {
                ADTD,   2, 
                ADPS,   1, 
                ADPD,   1, 
                ADSO,   1, 
                ADSC,   1, 
                ADSR,   1, 
                ADIS,   1, 
                ADDS,   3
            }

            ADIS = One
            ADSR = Zero
            Stall (Arg1)
            ADSR = One
            ADIS = Zero
            Stall (Arg1)
        }

        Method (DSAD, 2, Serialized)
        {
            Local0 = (Arg0 << One)
            Local0 += 0xFED81E40
            OperationRegion (ADCR, SystemMemory, Local0, 0x02)
            Field (ADCR, ByteAcc, NoLock, Preserve)
            {
                ADTD,   2, 
                ADPS,   1, 
                ADPD,   1, 
                ADSO,   1, 
                ADSC,   1, 
                ADSR,   1, 
                ADIS,   1, 
                ADDS,   3
            }

            If ((Arg1 != ADTD))
            {
                If ((Arg1 == Zero))
                {
                    ADTD = Zero
                    ADPD = One
                    Local0 = ADDS /* \_SB_.DSAD.ADDS */
                    While ((Local0 != 0x07))
                    {
                        Local0 = ADDS /* \_SB_.DSAD.ADDS */
                    }
                }

                If ((Arg1 == 0x03))
                {
                    ADPD = Zero
                    Local0 = ADDS /* \_SB_.DSAD.ADDS */
                    While ((Local0 != Zero))
                    {
                        Local0 = ADDS /* \_SB_.DSAD.ADDS */
                    }

                    ADTD = 0x03
                }
            }
        }

        Method (HSAD, 2, Serialized)
        {
            Local3 = (One << Arg0)
            Local0 = (Arg0 << One)
            Local0 += 0xFED81E40
            OperationRegion (ADCR, SystemMemory, Local0, 0x02)
            Field (ADCR, ByteAcc, NoLock, Preserve)
            {
                ADTD,   2, 
                ADPS,   1, 
                ADPD,   1, 
                ADSO,   1, 
                ADSC,   1, 
                ADSR,   1, 
                ADIS,   1, 
                ADDS,   3
            }

            If ((Arg1 != ADTD))
            {
                If ((Arg1 == Zero))
                {
                    ADTD = Zero
                    ADPD = One
                    Local0 = ADDS /* \_SB_.HSAD.ADDS */
                    While ((Local0 != 0x07))
                    {
                        Local0 = ADDS /* \_SB_.HSAD.ADDS */
                    }

                    RQTY = One
                    RD28 = One
                    Local0 = SD28 /* \_SB_.SD28 */
                    While (!Local0)
                    {
                        Local0 = SD28 /* \_SB_.SD28 */
                    }
                }

                If ((Arg1 == 0x03))
                {
                    RQTY = Zero
                    RD28 = One
                    Local0 = SD28 /* \_SB_.SD28 */
                    While (Local0)
                    {
                        Local0 = SD28 /* \_SB_.SD28 */
                    }

                    ADPD = Zero
                    Local0 = ADDS /* \_SB_.HSAD.ADDS */
                    While ((Local0 != Zero))
                    {
                        Local0 = ADDS /* \_SB_.HSAD.ADDS */
                    }

                    ADTD = 0x03
                }
            }
        }

        OperationRegion (FPIC, SystemIO, 0x0C00, 0x02)
        Field (FPIC, AnyAcc, NoLock, Preserve)
        {
            FPII,   8, 
            FPID,   8
        }

        IndexField (FPII, FPID, ByteAcc, NoLock, Preserve)
        {
            Offset (0xF4), 
            IUA0,   8, 
            IUA1,   8, 
            Offset (0xF8), 
            IUA2,   8, 
            IUA3,   8
        }

        Device (GPIO)
        {
            Name (_HID, "AMDI0030")  // _HID: Hardware ID
            Name (_CID, "AMDI0030")  // _CID: Compatible ID
            Name (_UID, Zero)  // _UID: Unique ID
            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                Name (RBUF, ResourceTemplate ()
                {
                    Interrupt (ResourceConsumer, Level, ActiveLow, Shared, ,, )
                    {
                        0x00000007,
                    }
                    Memory32Fixed (ReadWrite,
                        0xFED81500,         // Address Base
                        0x00000400,         // Address Length
                        )
                })
                Return (RBUF) /* \_SB_.GPIO._CRS.RBUF */
            }

            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((TSOS >= 0x70))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (Zero)
                }
            }
        }

        Device (I2CA)
        {
            Name (_HID, "AMDI0011")  // _HID: Hardware ID
            Name (_UID, Zero)  // _UID: Unique ID
            Name (_ADR, Zero)  // _ADR: Address
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                IRQ (Edge, ActiveHigh, Exclusive, )
                    {10}
                Memory32Fixed (ReadWrite,
                    0xFEDC2000,         // Address Base
                    0x00001000,         // Address Length
                    )
            })
            Name (_DEP, Package (0x01)  // _DEP: Dependencies
            {
                ^PCI0.GP17.MP2C
            })
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Method (RSET, 0, NotSerialized)
            {
                SRAD (0x05, 0xC8)
            }
        }

        Device (I2CB)
        {
            Name (_HID, "AMDI0011")  // _HID: Hardware ID
            Name (_UID, One)  // _UID: Unique ID
            Name (_ADR, One)  // _ADR: Address
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                IRQ (Edge, ActiveHigh, Exclusive, )
                    {11}
                Memory32Fixed (ReadWrite,
                    0xFEDC3000,         // Address Base
                    0x00001000,         // Address Length
                    )
            })
            Name (_DEP, Package (0x01)  // _DEP: Dependencies
            {
                ^PCI0.GP17.MP2C
            })
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Method (RSET, 0, NotSerialized)
            {
                SRAD (0x06, 0xC8)
            }
        }

        Device (I2CD)
        {
            Name (_HID, "AMDI0010")  // _HID: Hardware ID
            Name (_UID, 0x03)  // _UID: Unique ID
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                IRQ (Edge, ActiveHigh, Exclusive, )
                    {6}
                Memory32Fixed (ReadWrite,
                    0xFEDC5000,         // Address Base
                    0x00001000,         // Address Length
                    )
            })
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Method (RSET, 0, NotSerialized)
            {
                SRAD (0x08, 0xC8)
            }

            Method (_S0W, 0, NotSerialized)  // _S0W: S0 Device Wake State
            {
                If ((IC3D && IC3E))
                {
                    Return (0x04)
                }
                Else
                {
                    Return (Zero)
                }
            }

            Method (_PS0, 0, NotSerialized)  // _PS0: Power State 0
            {
                If ((IC3D && IC3E))
                {
                    DSAD (0x08, Zero)
                }
            }

            Method (_PS3, 0, NotSerialized)  // _PS3: Power State 3
            {
                If ((IC3D && IC3E))
                {
                    DSAD (0x08, 0x03)
                }
            }
        }

        Name (D0ST, One)
        Name (D3ST, One)
        PowerResource (P0ST, 0x00, 0x0000)
        {
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (D0ST) /* \_SB_.D0ST */
            }

            Method (_ON, 0, NotSerialized)  // _ON_: Power On
            {
                D0ST = One
            }

            Method (_OFF, 0, NotSerialized)  // _OFF: Power Off
            {
                D0ST = Zero
            }
        }

        PowerResource (P3ST, 0x00, 0x0000)
        {
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (D3ST) /* \_SB_.D3ST */
            }

            Method (_ON, 0, NotSerialized)  // _ON_: Power On
            {
                D3ST = One
            }

            Method (_OFF, 0, NotSerialized)  // _OFF: Power Off
            {
                D3ST = Zero
            }
        }
    }

    Scope (_SB.PCI0.GP18.SATA)
    {
        Name (_PR0, Package (0x01)  // _PR0: Power Resources for D0
        {
            P0ST
        })
        Name (_PR3, Package (0x01)  // _PR3: Power Resources for D3hot
        {
            P3ST
        })
        Method (_S0W, 0, NotSerialized)  // _S0W: S0 Device Wake State
        {
            If ((ST_D == One))
            {
                Return (0x04)
            }
            Else
            {
                Return (Zero)
            }
        }

        Method (_PS0, 0, NotSerialized)  // _PS0: Power State 0
        {
            If ((ST_D == One))
            {
                IO80 = 0x88
                SMIW = 0xD6
            }
        }

        Method (_PS3, 0, NotSerialized)  // _PS3: Power State 3
        {
            If ((ST_D == One))
            {
                IO80 = 0x77
                SMIW = 0xD5
            }
        }
    }

    Scope (_SB.I2CA)
    {
        Device (TPNL)
        {
            Name (_HID, "MSFT0002")  // _HID: Hardware ID
            Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */)  // _CID: Compatible ID
            Name (_UID, 0x04)  // _UID: Unique ID
            Method (_INI, 0, NotSerialized)  // _INI: Initialize
            {
                If ((TPNP == 0x517A))
                {
                    _HID = "WCOM517A"
                    Return (Zero)
                }

                If ((TPNP == 0x517B))
                {
                    _HID = "WCOM517B"
                    Return (Zero)
                }

                If ((TPNP == 0x517C))
                {
                    _HID = "WCOM517C"
                    Return (Zero)
                }

                If ((TPNP == 0x517D))
                {
                    _HID = "WCOM517D"
                    Return (Zero)
                }

                If ((TPNP == 0x517E))
                {
                    _HID = "WCOM517E"
                    Return (Zero)
                }

                If ((TPNP == 0x517F))
                {
                    _HID = "WCOM517F"
                    Return (Zero)
                }

                Return (Zero)
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                Name (RBUF, ResourceTemplate ()
                {
                    I2cSerialBusV2 (0x000A, ControllerInitiated, 0x00061A80,
                        AddressingMode7Bit, "\\_SB.I2CA",
                        0x00, ResourceConsumer, , Exclusive,
                        )
                    GpioInt (Level, ActiveLow, Shared, PullUp, 0x0000,
                        "\\_SB.GPIO", 0x00, ResourceConsumer, ,
                        )
                        {   // Pin list
                            0x005A
                        }
                })
                Return (RBUF) /* \_SB_.I2CA.TPNL._CRS.RBUF */
            }

            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((TPNV == Zero))
                {
                    Return (Zero)
                }

                Return (0x0F)
            }

            Method (_DSW, 3, NotSerialized)  // _DSW: Device Sleep Wake
            {
                If (Arg0){}
                Else
                {
                }
            }

            Method (_PS0, 0, NotSerialized)  // _PS0: Power State 0
            {
            }

            Method (_PS3, 0, NotSerialized)  // _PS3: Power State 3
            {
            }

            Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
            {
                If ((Arg0 == ToUUID ("3cdff6f7-4267-4555-ad05-b30a3d8938de") /* HID I2C Device */))
                {
                    Switch (ToInteger (Arg2))
                    {
                        Case (Zero)
                        {
                            Switch (ToInteger (Arg1))
                            {
                                Case (One)
                                {
                                    Return (Buffer (One)
                                    {
                                         0x03                                             // .
                                    })
                                }
                                Default
                                {
                                    Return (Buffer (One)
                                    {
                                         0x00                                             // .
                                    })
                                }

                            }
                        }
                        Case (One)
                        {
                            Return (One)
                        }
                        Default
                        {
                            Return (Zero)
                        }

                    }
                }
                Else
                {
                    Return (Buffer (One)
                    {
                         0x00                                             // .
                    })
                }
            }
        }
    }

    Scope (_SB.I2CD)
    {
        Device (ECSS)
        {
            OperationRegion (BOID, SystemMemory, 0xFED81538, 0x04)
            Field (BOID, ByteAcc, NoLock, Preserve)
            {
                Offset (0x02), 
                ID5V,   1
            }

            Name (_HID, EisaId ("ITE8396"))  // _HID: Hardware ID
            Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */)  // _CID: Compatible ID
            Name (_UID, One)  // _UID: Unique ID
            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                Name (RBUF, ResourceTemplate ()
                {
                    I2cSerialBusV2 (0x0050, ControllerInitiated, 0x00061A80,
                        AddressingMode7Bit, "\\_SB.I2CD",
                        0x00, ResourceConsumer, , Exclusive,
                        )
                    GpioInt (Level, ActiveHigh, Shared, PullNone, 0x0000,
                        "\\_SB.GPIO", 0x00, ResourceConsumer, ,
                        )
                        {   // Pin list
                            0x0055
                        }
                })
                Return (RBUF) /* \_SB_.I2CD.ECSS._CRS.RBUF */
            }

            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((ID5V == Zero))
                {
                    Return (Zero)
                }

                Return (0x0F)
            }

            Method (_DSW, 3, NotSerialized)  // _DSW: Device Sleep Wake
            {
                If (Arg0){}
                Else
                {
                }
            }

            Method (_PS0, 0, NotSerialized)  // _PS0: Power State 0
            {
            }

            Method (_PS3, 0, NotSerialized)  // _PS3: Power State 3
            {
            }

            Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
            {
                If ((Arg0 == ToUUID ("3cdff6f7-4267-4555-ad05-b30a3d8938de") /* HID I2C Device */))
                {
                    Switch (ToInteger (Arg2))
                    {
                        Case (Zero)
                        {
                            Switch (ToInteger (Arg1))
                            {
                                Case (One)
                                {
                                    Return (Buffer (One)
                                    {
                                         0x03                                             // .
                                    })
                                }
                                Default
                                {
                                    Return (Buffer (One)
                                    {
                                         0x00                                             // .
                                    })
                                }

                            }
                        }
                        Case (One)
                        {
                            Return (One)
                        }
                        Default
                        {
                            Return (Zero)
                        }

                    }
                }
                Else
                {
                    Return (Buffer (One)
                    {
                         0x00                                             // .
                    })
                }
            }
        }
    }

    Scope (_SB.I2CB)
    {
        Device (TPD0)
        {
            Name (_HID, "MSFT0001")  // _HID: Hardware ID
            Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */)  // _CID: Compatible ID
            Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
            {
                If ((Arg0 == ToUUID ("3cdff6f7-4267-4555-ad05-b30a3d8938de") /* HID I2C Device */))
                {
                    If ((Arg2 == Zero))
                    {
                        If ((Arg1 == One))
                        {
                            Return (Buffer (One)
                            {
                                 0x03                                             // .
                            })
                        }
                    }

                    If ((Arg2 == One))
                    {
                        If ((TPTY == One))
                        {
                            Return (One)
                        }

                        If (((TPTY == 0x02) || (TPTY == 0x03)))
                        {
                            Return (0x20)
                        }
                    }
                }

                Return (Buffer (One)
                {
                     0x00                                             // .
                })
            }

            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                If ((TPTY == Zero))
                {
                    Return (Zero)
                }
                Else
                {
                    Return (0x0F)
                }
            }

            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                If ((TPTY == One))
                {
                    Name (SBFB, ResourceTemplate ()
                    {
                        I2cSerialBusV2 (0x0015, ControllerInitiated, 0x00061A80,
                            AddressingMode7Bit, "\\_SB.I2CB",
                            0x00, ResourceConsumer, , Exclusive,
                            )
                    })
                }

                If ((TPTY == 0x03))
                {
                    Name (SBFA, ResourceTemplate ()
                    {
                        I2cSerialBusV2 (0x002A, ControllerInitiated, 0x00061A80,
                            AddressingMode7Bit, "\\_SB.I2CB",
                            0x00, ResourceConsumer, , Exclusive,
                            )
                    })
                }

                If ((TPTY == 0x02))
                {
                    Name (SBFS, ResourceTemplate ()
                    {
                        I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
                            AddressingMode7Bit, "\\_SB.I2CB",
                            0x00, ResourceConsumer, , Exclusive,
                            )
                    })
                }

                Name (SBFI, ResourceTemplate ()
                {
                    GpioInt (Level, ActiveLow, ExclusiveAndWake, PullUp, 0x0000,
                        "\\_SB.GPIO", 0x00, ResourceConsumer, ,
                        )
                        {   // Pin list
                            0x0059
                        }
                })
                If ((TPTY == One))
                {
                    Return (ConcatenateResTemplate (SBFB, SBFI))
                }

                If ((TPTY == 0x03))
                {
                    Return (ConcatenateResTemplate (SBFA, SBFI))
                }

                If ((TPTY == 0x02))
                {
                    Return (ConcatenateResTemplate (SBFS, SBFI))
                }
            }

            Method (TPRD, 0, Serialized)
            {
                Return (^^^PCI0.LPC0.EC0.ECTP) /* \_SB_.PCI0.LPC0.EC0_.ECTP */
            }

            Method (TPWR, 1, Serialized)
            {
                ^^^PCI0.LPC0.EC0.ECTP = Arg0
            }
        }
    }
}


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller
  2018-10-30 20:56 ` Bjorn Helgaas
                     ` (2 preceding siblings ...)
  2018-11-04 16:43   ` Elie Morisse
@ 2018-11-11 17:36   ` Elie Morisse
  3 siblings, 0 replies; 6+ messages in thread
From: Elie Morisse @ 2018-11-11 17:36 UTC (permalink / raw)
  To: helgaas
  Cc: linux-i2c, Wolfram Sang, Nehal-bakulchandra.Shah,
	Shyam-sundar.S-k, sandeep.singh, linux-kernel, rjw, Len Brown,
	linux-acpi

Hi,

In v9 the platform driver defers probe() if no MP2 devices has been
registered in the PCI driver yet, is this an acceptable fix?

I've found examples of kernel code extracting info from the ACPI
namespace (e.g in i2c-core-acpi.c), but this would require adding more
code to the driver and AMDI0011 ACPI devices getting associated to a
platform device still seem like a minor but nice bonus to me, but that
may be the wrong way of looking at it.

So, to get this patch accepted do I keep things this way or do I
replace the platform driver by an ACPI namespace walker?

Le mar. 30 oct. 2018 à 17:56, Bjorn Helgaas <helgaas@kernel.org> a écrit :
>
> [+cc Rafael, Len, linux-acpi]
>
> On Sat, Oct 27, 2018 at 12:09:10PM -0300, Elie Morisse wrote:
> > This contains two drivers:
> >  * i2c-amd-plat-mp2: platform driver managing an i2c adapter (one of
> > the two busses of the MP2) and routing any i2c read/write command to
> > the PCI driver.
> >  * i2c-amd-pci-mp2: PCI driver communicating through the C2P/P2C
> > mailbox registers, or through DMA for more than 32 bytes transfers.
>
> I'm dubious about this two-driver structure.  If I understand
> correctly (and it's very possible that I don't), the PCI driver
> (amd_mp2_pci_probe()) is the real owner of the i2c adapter: it
> claims the PCI device, claims its BARs, and requests an IRQ.
>
> The i2c_amd_probe() code *looks* like a platform driver that claims
> AMDI0011 devices from the ACPI namespace, but I don't think it's
> really a driver.  It looks like it exists mainly to extract some
> information (bus speed and maybe a bus number?) from the namespace,
> then to call i2c_add_adapter().
>
> It looks like i2c_amd_probe() must run *after* amd_mp2_pci_probe(),
> but there's no way to really enforce that ordering.
>
> And i2c-amd-plat-mp2 contains the i2c_amd_algorithm functions, which
> operate on the PCI device, which requires exported interfaces
> (amd_mp2_read(), amd_mp2_write()) that are implemented in the PCI
> driver but called from the platform part.
>
> It seems like there should be a way to put the ACPI lookups into
> i2c-amd-pci-mp2 so there's only one driver.
>
> I only have a couple trivial comments below but I'm not trimming my
> response so the ACPI folks can see the whole context.
>
> > This is major rework of the patch submitted by Nehal-bakulchandra Shah
> > from AMD (https://patchwork.kernel.org/patch/10597369/).
> >
> > Most of the event handling of v2/v3 was rewritten since it couldn't work
> > if more than one bus was enabled, and contains many more fixes listed
> > in the patch changelog.
> >
> > With those changes both the touchpad and the touchscreen of the
> > Ryzen-based Lenovo Yoga 530 which lie in separate busses work beautifully.
> >
> > Signed-off-by: Elie Morisse <syniurge@gmail.com>
> > ---
> > Changes since v1:(https://www.spinics.net/lists/linux-i2c/msg34650.html)
> > -> Add fix for IOMMU
> > -> Add depedency of ACPI
> > -> Add locks to avoid the crash
> >
> > Changes since v2:(https://patchwork.ozlabs.org/patch/961270/)
> >
> > -> fix for review comments
> > -> fix for more than 32 bytes write issue
> >
> > Changes since v3 (https://patchwork.kernel.org/patch/10597369/) by Elie M.:
> >
> > -> support more than one bus/adapter
> > -> support more than one slave per bus
> > -> use the bus speed specified by the slaves declared in the DSDT instead of
> >    assuming speed == 400kbits/s
> > -> instead of kzalloc'ing a buffer for every less than 32 bytes reads, simply
> >    use i2c_msg.buf
> > -> fix buffer overreads/overflows when (<=32 bytes) message lengths aren't a
> >    multiple of 4 by using memcpy_fromio and memcpy_toio
> > -> use streaming DMA mappings instead of allocating a coherent DMA buffer for
> >    every >32 bytes read/write
> > -> properly check for timeouts during i2c_amd_xfer and increase it from 50
> >    jiffies to 250 msecs (which is more in line with other drivers)
> > -> complete amd_i2c_dev.msg even if the device doesn't return a xxx_success
> >    event, instead of stalling i2c_amd_xfer
> > -> removed the spinlock and mdelay during i2c_amd_pci_configure, I didn't see
> >    the point since it's already waiting for a i2c_busenable_complete event
> > -> add an adapter-specific mutex lock for i2c_amd_xfer, since we don't want
> >    parallel calls writing to AMD_C2P_MSG0 (or AMD_C2P_MSG1)
> > -> add a global mutex lock for registers AMD_C2P_MSG2 to AMD_C2P_MSG9,  which
> >    are shared across the two busses/adapters
> > -> add MODULE_DEVICE_TABLE to automatically load i2c-amd-platdrv if the DSDT
> >    enumerates devices with the "AMDI0011" HID
> > -> set maximum length of reads/writes to 4095 (event's length field is 12 bits)
> > -> basic PM support
> > -> style corrections to match the kernel code style, and tried to reduce code
> >    duplication whenever possible
> >
> > Changes since v4 (https://marc.info/?l=linux-kernel&m=154031133019835) by Elie M.:
> >
> > -> fix missing typecast warning
> > -> removed the duplicated entry in Kconfig
> >
> > Changes since v5 by Elie M.:
> >
> > -> move DMA mapping from the platform driver to the PCI driver
> > -> attempt to find the platform device's PCI parent through the _DEP ACPI method
> >    (if not found take the first MP2 device registred in the i2c-amd-pci-mp2
> >    driver, like before)
> > -> do not assume anymore that the PCI device is owned by the i2c-amd-pci-mp2
> >    driver
> > -> address other review comments by Bjorn Helgaas (meant for v3)
> >
> > Changes since v6 by Elie M.:
> >
> > -> remove unnecessary memcpy from the DMA buffer during i2c_amd_read_completion
> >
> >  MAINTAINERS                           |   6 +
> >  drivers/i2c/busses/Kconfig            |  15 +
> >  drivers/i2c/busses/Makefile           |   2 +
> >  drivers/i2c/busses/i2c-amd-pci-mp2.c  | 706 ++++++++++++++++++++++++++
> >  drivers/i2c/busses/i2c-amd-pci-mp2.h  | 224 ++++++++
> >  drivers/i2c/busses/i2c-amd-plat-mp2.c | 373 ++++++++++++++
> >  6 files changed, 1326 insertions(+)
> >  create mode 100644 drivers/i2c/busses/i2c-amd-pci-mp2.c
> >  create mode 100644 drivers/i2c/busses/i2c-amd-pci-mp2.h
> >  create mode 100644 drivers/i2c/busses/i2c-amd-plat-mp2.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 6ac000cc006d..8ff2bddc1ac2 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -791,6 +791,12 @@ F:       drivers/gpu/drm/amd/include/vi_structs.h
> >  F:   drivers/gpu/drm/amd/include/v9_structs.h
> >  F:   include/uapi/linux/kfd_ioctl.h
> >
> > +AMD MP2 I2C DRIVER
> > +M:   Elie Morisse <syniurge@gmail.com>
> > +L:   linux-i2c@vger.kernel.org
> > +S:   Maintained
> > +F:   drivers/i2c/busses/i2c-amd-*-mp2*
> > +
> >  AMD POWERPLAY
> >  M:   Rex Zhu <rex.zhu@amd.com>
> >  M:   Evan Quan <evan.quan@amd.com>
> > diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> > index 451d4ae50e66..e20f2d1ce381 100644
> > --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -77,6 +77,21 @@ config I2C_AMD8111
> >         This driver can also be built as a module.  If so, the module
> >         will be called i2c-amd8111.
> >
> > +config I2C_AMD_MP2_PCI
> > +     tristate
> > +     depends on PCI
> > +
> > +config I2C_AMD_MP2_PLATFORM
> > +     tristate "AMD MP2 Platform"
> > +     select I2C_AMD_MP2_PCI
> > +     depends on ACPI
> > +     help
> > +       If you say yes to this option, support will be included for the AMD MP2
> > +       PCI I2C adapter.
> > +
> > +       This driver can also be built as a module.  If so, the module
> > +       will be called i2c-amd-plat-mp2.
> > +
> >  config I2C_HIX5HD2
> >       tristate "Hix5hd2 high-speed I2C driver"
> >       depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
> > diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> > index 18b26af82b1c..16ef646d7ef5 100644
> > --- a/drivers/i2c/busses/Makefile
> > +++ b/drivers/i2c/busses/Makefile
> > @@ -32,6 +32,8 @@ obj-$(CONFIG_I2C_POWERMAC)  += i2c-powermac.o
> >
> >  # Embedded system I2C/SMBus host controller drivers
> >  obj-$(CONFIG_I2C_ALTERA)     += i2c-altera.o
> > +obj-$(CONFIG_I2C_AMD_MP2_PCI)        += i2c-amd-pci-mp2.o
> > +obj-$(CONFIG_I2C_AMD_MP2_PLATFORM)   += i2c-amd-plat-mp2.o
> >  obj-$(CONFIG_I2C_ASPEED)     += i2c-aspeed.o
> >  obj-$(CONFIG_I2C_AT91)               += i2c-at91.o
> >  obj-$(CONFIG_I2C_AU1550)     += i2c-au1550.o
> > diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.c b/drivers/i2c/busses/i2c-amd-pci-mp2.c
> > new file mode 100644
> > index 000000000000..eb54825f3f69
> > --- /dev/null
> > +++ b/drivers/i2c/busses/i2c-amd-pci-mp2.c
> > @@ -0,0 +1,706 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> > +/*
> > + * AMD PCIe MP2 Communication Driver
> > + *
> > + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > + *          Elie Morisse <syniurge@gmail.com>
> > + */
> > +
> > +#include <linux/debugfs.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/module.h>
> > +#include <linux/pci.h>
> > +#include <linux/slab.h>
> > +
> > +#include "i2c-amd-pci-mp2.h"
> > +
> > +#define DRIVER_NAME  "pcie_mp2_amd"
> > +#define DRIVER_DESC  "AMD(R) PCI-E MP2 Communication Driver"
> > +#define DRIVER_VER   "1.0"
> > +
> > +static const struct file_operations amd_mp2_debugfs_info;
> > +static struct dentry *debugfs_dir;
> > +
> > +#define write64 _write64
> > +static inline void _write64(u64 val, void __iomem *mmio)
> > +{
> > +     writel(val, mmio);
> > +     writel(val >> 32, mmio + sizeof(u32));
> > +}
> > +
> > +#define read64 _read64
> > +static inline u64 _read64(void __iomem *mmio)
> > +{
> > +     u64 low, high;
> > +
> > +     low = readl(mmio);
> > +     high = readl(mmio + sizeof(u32));
> > +     return low | (high << 32);
> > +}
> > +
> > +static int amd_mp2_cmd(struct amd_mp2_dev *privdata,
> > +                    union i2c_cmd_base i2c_cmd_base)
> > +{
> > +     void __iomem *reg;
> > +
> > +     if (i2c_cmd_base.s.bus_id > 1) {
> > +             dev_err(ndev_dev(privdata), "%s Invalid bus id\n", __func__);
> > +             return -EINVAL;
> > +     }
> > +
> > +     reg = privdata->mmio + ((i2c_cmd_base.s.bus_id == 1) ?
> > +                             AMD_C2P_MSG1 : AMD_C2P_MSG0);
> > +     writel(i2c_cmd_base.ul, reg);
> > +
> > +     return 0;
> > +}
> > +
> > +int amd_mp2_connect(struct amd_i2c_common *i2c_common, bool enable)
> > +{
> > +     struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> > +     union i2c_cmd_base i2c_cmd_base;
> > +
> > +     dev_dbg(ndev_dev(privdata), "%s id: %d\n", __func__,
> > +             i2c_common->bus_id);
> > +
> > +     i2c_common->reqcmd = enable ? i2c_enable : i2c_disable;
> > +
> > +     i2c_cmd_base.ul = 0;
> > +     i2c_cmd_base.s.i2c_cmd = i2c_common->reqcmd;
> > +     i2c_cmd_base.s.bus_id = i2c_common->bus_id;
> > +     i2c_cmd_base.s.i2c_speed = i2c_common->i2c_speed;
> > +
> > +     return amd_mp2_cmd(privdata, i2c_cmd_base);
> > +}
> > +EXPORT_SYMBOL_GPL(amd_mp2_connect);
> > +
> > +static void amd_mp2_cmd_rw_fill(struct amd_i2c_common *i2c_common,
> > +                             union i2c_cmd_base *i2c_cmd_base,
> > +                             enum i2c_cmd reqcmd)
> > +{
> > +     i2c_common->reqcmd = reqcmd;
> > +
> > +     i2c_cmd_base->s.i2c_cmd = reqcmd;
> > +     i2c_cmd_base->s.bus_id = i2c_common->bus_id;
> > +     i2c_cmd_base->s.i2c_speed = i2c_common->i2c_speed;
> > +     i2c_cmd_base->s.slave_addr = i2c_common->rw_cfg.slave_addr;
> > +     i2c_cmd_base->s.length = i2c_common->rw_cfg.length;
> > +}
> > +
> > +static int amd_mp2_dma_map(struct amd_mp2_dev *privdata,
> > +                        struct amd_i2c_common *i2c_common,
> > +                        bool is_write)
> > +{
> > +     enum dma_data_direction dma_direction = is_write ?
> > +                     DMA_TO_DEVICE : DMA_FROM_DEVICE;
> > +
> > +     i2c_common->rw_cfg.dma_addr = dma_map_single(&privdata->pci_dev->dev,
> > +                                                  i2c_common->rw_cfg.buf,
> > +                                                  i2c_common->rw_cfg.length,
> > +                                                  dma_direction);
> > +     i2c_common->rw_cfg.dma_direction = dma_direction;
> > +
> > +     if (dma_mapping_error(&privdata->pci_dev->dev,
> > +                           i2c_common->rw_cfg.dma_addr)) {
> > +             dev_err(ndev_dev(privdata),
> > +                     "Error while mapping dma buffer %p\n",
> > +                     i2c_common->rw_cfg.buf);
> > +             return -EIO;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static void amd_mp2_dma_unmap(struct amd_mp2_dev *privdata,
> > +                           struct amd_i2c_common *i2c_common)
> > +{
> > +     dma_unmap_single(&privdata->pci_dev->dev,
> > +                      i2c_common->rw_cfg.dma_addr,
> > +                      i2c_common->rw_cfg.length,
> > +                      i2c_common->rw_cfg.dma_direction);
> > +}
> > +
> > +int amd_mp2_read(struct amd_i2c_common *i2c_common)
> > +{
> > +     struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> > +     union i2c_cmd_base i2c_cmd_base;
> > +
> > +     dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__,
> > +             i2c_common->rw_cfg.slave_addr, i2c_common->bus_id);
> > +
> > +     amd_mp2_cmd_rw_fill(i2c_common, &i2c_cmd_base, i2c_read);
> > +
> > +     /* there is only one data mailbox for two i2c adapters */
> > +     mutex_lock(&privdata->c2p_lock);
> > +
> > +     if (!i2c_common->rw_cfg.buf) {
> > +             dev_err(ndev_dev(privdata), "%s no mem for buf received\n",
> > +                     __func__);
> > +             return -ENOMEM;
> > +     }
> > +
> > +     if (i2c_common->rw_cfg.length <= 32) {
> > +             i2c_cmd_base.s.mem_type = use_c2pmsg;
> > +     } else {
> > +             i2c_cmd_base.s.mem_type = use_dram;
> > +             if (amd_mp2_dma_map(privdata, i2c_common, false))
> > +                     return -EIO;
> > +             write64((u64)i2c_common->rw_cfg.dma_addr,
> > +                     privdata->mmio + AMD_C2P_MSG2);
> > +     }
> > +
> > +     return amd_mp2_cmd(privdata, i2c_cmd_base);
> > +}
> > +EXPORT_SYMBOL_GPL(amd_mp2_read);
> > +
> > +int amd_mp2_write(struct amd_i2c_common *i2c_common)
> > +{
> > +     struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> > +     union i2c_cmd_base i2c_cmd_base;
> > +
> > +     dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__,
> > +             i2c_common->rw_cfg.slave_addr, i2c_common->bus_id);
> > +
> > +     amd_mp2_cmd_rw_fill(i2c_common, &i2c_cmd_base, i2c_write);
> > +
> > +     /* there is only one data mailbox for two i2c adapters */
> > +     mutex_lock(&privdata->c2p_lock);
> > +
> > +     if (i2c_common->rw_cfg.length <= 32) {
> > +             i2c_cmd_base.s.mem_type = use_c2pmsg;
> > +             memcpy_toio(privdata->mmio + AMD_C2P_MSG2,
> > +                         i2c_common->rw_cfg.buf,
> > +                         i2c_common->rw_cfg.length);
> > +     } else {
> > +             i2c_cmd_base.s.mem_type = use_dram;
> > +             if (amd_mp2_dma_map(privdata, i2c_common, true))
> > +                     return -EIO;
> > +             write64((u64)i2c_common->rw_cfg.dma_addr,
> > +                     privdata->mmio + AMD_C2P_MSG2);
> > +     }
> > +
> > +     return amd_mp2_cmd(privdata, i2c_cmd_base);
> > +}
> > +EXPORT_SYMBOL_GPL(amd_mp2_write);
> > +
> > +static void amd_mp2_pci_do_work(struct work_struct *work)
> > +{
> > +     struct amd_i2c_common *i2c_common = work_amd_i2c_common(work);
> > +     struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> > +     int sts = i2c_common->eventval.r.status;
> > +     int res = i2c_common->eventval.r.response;
> > +     int len = i2c_common->eventval.r.length;
> > +     u32 slave_addr = i2c_common->eventval.r.slave_addr;
> > +
> > +     if (len != i2c_common->rw_cfg.length)
> > +             dev_err(ndev_dev(privdata),
> > +                     "length %d in event doesn't match buffer length %d!\n",
> > +                     len, i2c_common->rw_cfg.length);
> > +     if (slave_addr != i2c_common->rw_cfg.slave_addr)
> > +             dev_err(ndev_dev(privdata),
> > +                     "unexpected slave address %x (expected: %x)!\n",
> > +                     slave_addr, i2c_common->rw_cfg.slave_addr);
> > +
> > +     if (res != command_success) {
> > +             if (res == command_failed)
> > +                     dev_err(ndev_dev(privdata), "i2c command failed!\n");
> > +             else
> > +                     dev_err(ndev_dev(privdata), "invalid response to i2c command!\n");
> > +             return;
> > +     }
> > +
> > +     switch (i2c_common->reqcmd) {
> > +     case i2c_read:
> > +             if (sts == i2c_readcomplete_event) {
> > +                     if (len <= 32)
> > +                             memcpy_fromio(i2c_common->rw_cfg.buf,
> > +                                           privdata->mmio + AMD_C2P_MSG2,
> > +                                           i2c_common->rw_cfg.length);
> > +             } else if (sts == i2c_readfail_event) {
> > +                     dev_err(ndev_dev(privdata), "i2c read failed!\n");
> > +             } else {
> > +                     dev_err(ndev_dev(privdata), "invalid i2c status after read!\n");
> > +             }
> > +
> > +             i2c_common->ops->read_complete(&i2c_common->eventval);
> > +             break;
> > +     case i2c_write:
> > +             if (sts == i2c_writefail_event)
> > +                     dev_err(ndev_dev(privdata), "i2c write failed!\n");
> > +             else if (sts != i2c_writecomplete_event)
> > +                     dev_err(ndev_dev(privdata), "invalid i2c status after write!\n");
> > +
> > +             i2c_common->ops->write_complete(&i2c_common->eventval);
> > +             break;
> > +     case i2c_enable:
> > +             if (sts == i2c_busdisable_failed)
> > +                     dev_err(ndev_dev(privdata), "i2c bus enable failed!\n");
> > +             else if (sts != i2c_busenable_complete)
> > +                     dev_err(ndev_dev(privdata), "invalid i2c status after bus enable!\n");
> > +
> > +             i2c_common->ops->connect_complete(&i2c_common->eventval);
> > +             break;
> > +     default:
> > +             break;
> > +     }
> > +
> > +     if ((i2c_common->reqcmd == i2c_read ||
> > +          i2c_common->reqcmd == i2c_write) &&
> > +         i2c_common->rw_cfg.length > 32)
> > +             amd_mp2_dma_unmap(privdata, i2c_common);
> > +}
> > +
> > +static void amd_mp2_pci_work(struct work_struct *work)
> > +{
> > +     struct amd_i2c_common *i2c_common = work_amd_i2c_common(work);
> > +     struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
> > +     enum i2c_cmd cmd = i2c_common->reqcmd;
> > +
> > +     amd_mp2_pci_do_work(work);
> > +
> > +     i2c_common->reqcmd = i2c_none;
> > +
> > +     if (cmd == i2c_read || cmd == i2c_write)
> > +             mutex_unlock(&privdata->c2p_lock);
> > +}
> > +
> > +static irqreturn_t amd_mp2_irq_isr(int irq, void *dev)
> > +{
> > +     struct amd_mp2_dev *privdata = dev;
> > +     struct amd_i2c_common *i2c_common;
> > +     u32 val;
> > +     unsigned int bus_id;
> > +     void __iomem *reg;
> > +     unsigned long flags;
> > +     enum irqreturn ret = IRQ_NONE;
> > +
> > +     raw_spin_lock_irqsave(&privdata->lock, flags);
> > +
> > +     for (bus_id = 0; bus_id < 2; bus_id++) {
> > +             reg = privdata->mmio + ((bus_id == 0) ?
> > +                                     AMD_P2C_MSG1 : AMD_P2C_MSG2);
> > +             val = readl(reg);
> > +             if (val != 0) {
> > +                     i2c_common = privdata->plat_common[bus_id];
> > +                     if (!i2c_common)
> > +                             continue;
> > +                     i2c_common->eventval.ul = val;
> > +
> > +                     writel(0, reg);
> > +                     writel(0, privdata->mmio + AMD_P2C_MSG_INTEN);
> > +
> > +                     if (i2c_common->reqcmd != i2c_none)
> > +                             schedule_delayed_work(&i2c_common->work, 0);
> > +
> > +                     ret = IRQ_HANDLED;
> > +             }
> > +     }
> > +
> > +     raw_spin_unlock_irqrestore(&privdata->lock, flags);
> > +     return ret;
> > +}
> > +
> > +int amd_i2c_register_cb(struct amd_mp2_dev *privdata,
> > +                     struct amd_i2c_common *i2c_common)
> > +{
> > +     if (i2c_common->bus_id > 1)
> > +             return -EINVAL;
> > +     privdata->plat_common[i2c_common->bus_id] = i2c_common;
> > +
> > +     INIT_DELAYED_WORK(&i2c_common->work, amd_mp2_pci_work);
> > +
> > +     return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(amd_i2c_register_cb);
> > +
> > +int amd_i2c_unregister_cb(struct amd_mp2_dev *privdata,
> > +                       struct amd_i2c_common *i2c_common)
> > +{
> > +     cancel_delayed_work_sync(&i2c_common->work);
> > +     privdata->plat_common[i2c_common->bus_id] = NULL;
> > +
> > +     return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(amd_i2c_unregister_cb);
> > +
> > +static ssize_t amd_mp2_debugfs_read(struct file *filp, char __user *ubuf,
> > +                                 size_t count, loff_t *offp)
> > +{
> > +     struct amd_mp2_dev *privdata;
> > +     void __iomem *mmio;
> > +     u8 *buf;
> > +     size_t buf_size;
> > +     ssize_t ret, off;
> > +     u32 v32;
> > +
> > +     privdata = filp->private_data;
> > +     mmio = privdata->mmio;
> > +     buf_size = min_t(size_t, count, 0x800);
> > +     buf = kmalloc(buf_size, GFP_KERNEL);
> > +
> > +     if (!buf)
> > +             return -ENOMEM;
> > +
> > +     off = 0;
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "Mp2 Device Information:\n");
> > +
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "========================\n");
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "\tMP2 C2P Message Register Dump:\n\n");
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG0);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG0 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG1);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG1 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG2);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG2 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG3);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG3 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG4);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG4 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG5);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG5 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG6);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG6 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG7);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG7 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG8);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG8 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_C2P_MSG9);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_C2P_MSG9 -\t\t\t%#06x\n", v32);
> > +
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "\n\tMP2 P2C Message Register Dump:\n\n");
> > +
> > +     v32 = readl(privdata->mmio + AMD_P2C_MSG1);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_P2C_MSG1 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_P2C_MSG2);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_P2C_MSG2 -\t\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_P2C_MSG_INTEN);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_P2C_MSG_INTEN -\t\t%#06x\n", v32);
> > +
> > +     v32 = readl(privdata->mmio + AMD_P2C_MSG_INTSTS);
> > +     off += scnprintf(buf + off, buf_size - off,
> > +                     "AMD_P2C_MSG_INTSTS -\t\t%#06x\n", v32);
> > +
> > +     ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
> > +     kfree(buf);
> > +     return ret;
> > +}
> > +
> > +static void amd_mp2_init_debugfs(struct amd_mp2_dev *privdata)
> > +{
> > +     if (!debugfs_dir) {
> > +             privdata->debugfs_dir = NULL;
> > +             privdata->debugfs_info = NULL;
> > +             return;
> > +     }
> > +
> > +     privdata->debugfs_dir = debugfs_create_dir(ndev_name(privdata),
> > +                                                debugfs_dir);
> > +     if (!privdata->debugfs_dir) {
> > +             privdata->debugfs_info = NULL;
> > +     } else {
> > +             privdata->debugfs_info = debugfs_create_file
> > +                     ("info", 0400, privdata->debugfs_dir,
> > +                      privdata, &amd_mp2_debugfs_info);
> > +     }
> > +}
> > +
> > +static void amd_mp2_deinit_debugfs(struct amd_mp2_dev *privdata)
> > +{
> > +     debugfs_remove_recursive(privdata->debugfs_dir);
> > +}
> > +
> > +static void amd_mp2_clear_reg(struct amd_mp2_dev *privdata)
> > +{
> > +     int reg;
> > +
> > +     for (reg = AMD_C2P_MSG0; reg <= AMD_C2P_MSG9; reg += 4)
> > +             writel(0, privdata->mmio + reg);
> > +
> > +     for (reg = AMD_P2C_MSG0; reg <= AMD_P2C_MSG2; reg += 4)
> > +             writel(0, privdata->mmio + reg);
> > +}
> > +
> > +static int amd_mp2_pci_init(struct amd_mp2_dev *privdata,
> > +                         struct pci_dev *pci_dev)
> > +{
> > +     int rc;
> > +     resource_size_t size, base;
> > +
> > +     pci_set_drvdata(pci_dev, privdata);
> > +
> > +     rc = pci_enable_device(pci_dev);
> > +     if (rc)
> > +             goto err_pci_enable;
> > +
> > +     rc = pci_request_regions(pci_dev, DRIVER_NAME);
> > +     if (rc)
> > +             goto err_pci_regions;
> > +
> > +     pci_set_master(pci_dev);
> > +
> > +     rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64));
> > +     if (rc) {
> > +             rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
> > +             if (rc)
> > +                     goto err_dma_mask;
> > +             dev_warn(ndev_dev(privdata), "Cannot DMA highmem\n");
> > +     }
> > +
> > +     rc = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(64));
> > +     if (rc) {
> > +             rc = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(32));
> > +             if (rc)
> > +                     goto err_dma_mask;
> > +             dev_warn(ndev_dev(privdata), "Cannot DMA consistent highmem\n");
> > +     }
> > +
> > +     base = pci_resource_start(pci_dev, 2);
> > +     size = pci_resource_len(pci_dev, 2);
> > +     dev_dbg(ndev_dev(privdata), "Base addr:%zx size:%zx\n",
> > +             (size_t)base, (size_t)size);
>
> You can use %pR on pci_dev->resource[2].  That uses the conventional
> format (same as used by the PCI core).
>
> > +
> > +     mutex_init(&privdata->c2p_lock);
> > +     privdata->mmio = ioremap(base, size);
> > +     if (!privdata->mmio) {
> > +             rc = -EIO;
> > +             goto err_dma_mask;
> > +     }
> > +
> > +     /* Try to set up intx irq */
> > +     raw_spin_lock_init(&privdata->lock);
> > +     pci_intx(pci_dev, 1);
> > +     rc = request_irq(pci_dev->irq, amd_mp2_irq_isr, IRQF_SHARED,
> > +                      "mp2_irq_isr", privdata);
> > +     if (rc)
> > +             goto err_intx_request;
> > +
> > +     return 0;
> > +
> > +err_intx_request:
> > +     return rc;
> > +err_dma_mask:
> > +     pci_clear_master(pci_dev);
> > +     pci_release_regions(pci_dev);
> > +err_pci_regions:
> > +     pci_disable_device(pci_dev);
> > +err_pci_enable:
> > +     pci_set_drvdata(pci_dev, NULL);
> > +     return rc;
> > +}
> > +
> > +static void amd_mp2_pci_deinit(struct amd_mp2_dev *privdata)
> > +{
> > +     struct pci_dev *pci_dev = ndev_pdev(privdata);
> > +
> > +     pci_iounmap(pci_dev, privdata->mmio);
> > +
> > +     pci_clear_master(pci_dev);
> > +     pci_release_regions(pci_dev);
> > +     pci_disable_device(pci_dev);
> > +     pci_set_drvdata(pci_dev, NULL);
> > +}
> > +
> > +static int amd_mp2_pci_probe(struct pci_dev *pci_dev,
> > +                          const struct pci_device_id *id)
> > +{
> > +     struct amd_mp2_dev *privdata;
> > +     int rc;
> > +     static bool first_probe = true;
> > +
> > +     if (first_probe) {
> > +             pr_info("%s: %s Version: %s\n", DRIVER_NAME,
> > +                     DRIVER_DESC, DRIVER_VER);
> > +             first_probe = false;
> > +     }
> > +
> > +     dev_info(&pci_dev->dev, "MP2 device found [%04x:%04x] (rev %x)\n",
> > +              (int)pci_dev->vendor, (int)pci_dev->device,
> > +              (int)pci_dev->revision);
> > +
> > +     privdata = kzalloc(sizeof(*privdata), GFP_KERNEL);
> > +     if (!privdata) {
> > +             rc = -ENOMEM;
> > +             goto err_dev;
>
> There's nothing to clean up at this point, so just emit the message
> and return directly:
>
>   if (!privdata) {
>     dev_err(&pci_dev->dev, "Memory Allocation Failed\n");
>     return -ENOMEM;
>   }
>
> > +     }
> > +
> > +     privdata->pci_dev = pci_dev;
> > +
> > +     rc = amd_mp2_pci_init(privdata, pci_dev);
> > +     if (rc)
> > +             goto err_pci_init;
> > +     dev_dbg(&pci_dev->dev, "pci init done.\n");
> > +
> > +     amd_mp2_init_debugfs(privdata);
> > +     dev_info(&pci_dev->dev, "MP2 device registered.\n");
> > +     return 0;
> > +
> > +err_pci_init:
> > +     kfree(privdata);
> > +err_dev:
> > +     dev_err(&pci_dev->dev, "Memory Allocation Failed\n");
> > +     return rc;
> > +}
> > +
> > +static void amd_mp2_pci_remove(struct pci_dev *pci_dev)
> > +{
> > +     struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
> > +     unsigned int bus_id;
> > +
> > +     for (bus_id = 0; bus_id < 2; bus_id++)
> > +             if (privdata->plat_common[bus_id])
> > +                     amd_i2c_unregister_cb(privdata,
> > +                                           privdata->plat_common[bus_id]);
> > +
> > +     amd_mp2_deinit_debugfs(privdata);
> > +     amd_mp2_clear_reg(privdata);
> > +     free_irq(pci_dev->irq, privdata);
> > +     pci_intx(pci_dev, 0);
> > +     amd_mp2_pci_deinit(privdata);
> > +     kfree(privdata);
> > +}
> > +
> > +static const struct file_operations amd_mp2_debugfs_info = {
> > +     .owner = THIS_MODULE,
> > +     .open = simple_open,
> > +     .read = amd_mp2_debugfs_read,
> > +};
> > +
> > +static const struct pci_device_id amd_mp2_pci_tbl[] = {
> > +     {PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
> > +     {0}
> > +};
> > +MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
> > +
> > +#ifdef CONFIG_PM_SLEEP
> > +static int amd_mp2_pci_device_suspend(struct pci_dev *pci_dev,
> > +                                   pm_message_t mesg)
> > +{
> > +     int ret;
> > +     struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
> > +
> > +     if (!privdata)
> > +             return -EINVAL;
> > +
> > +     ret = pci_save_state(pci_dev);
> > +     if (ret) {
> > +             dev_err(ndev_dev(privdata),
> > +                     "pci_save_state failed = %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     pci_enable_wake(pci_dev, PCI_D3hot, 0);
> > +     pci_disable_device(pci_dev);
> > +     pci_set_power_state(pci_dev, pci_choose_state(pci_dev, mesg));
> > +
> > +     return 0;
> > +}
> > +
> > +static int amd_mp2_pci_device_resume(struct pci_dev *pci_dev)
> > +{
> > +     struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
> > +
> > +     if (!privdata)
> > +             return -EINVAL;
> > +
> > +     pci_set_power_state(pci_dev, PCI_D0);
> > +     pci_restore_state(pci_dev);
> > +
> > +     if (pci_enable_device(pci_dev) < 0) {
> > +             dev_err(ndev_dev(privdata), "pci_enable_device failed\n");
> > +             return -EIO;
> > +     }
> > +
> > +     pci_enable_wake(pci_dev, PCI_D3hot, 0);
> > +
> > +     return 0;
> > +}
> > +#endif
> > +
> > +static struct pci_driver amd_mp2_pci_driver = {
> > +     .name           = DRIVER_NAME,
> > +     .id_table       = amd_mp2_pci_tbl,
> > +     .probe          = amd_mp2_pci_probe,
> > +     .remove         = amd_mp2_pci_remove,
> > +#ifdef CONFIG_PM_SLEEP
> > +     .suspend                = amd_mp2_pci_device_suspend,
> > +     .resume                 = amd_mp2_pci_device_resume,
> > +#endif
> > +};
> > +
> > +static int amd_mp2_device_match(struct device *dev, void *data)
> > +{
> > +     struct pci_dev *candidate = data;
> > +
> > +     if (!candidate)
> > +             return 1;
> > +     return (to_pci_dev(dev) == candidate) ? 1 : 0;
> > +}
> > +
> > +struct amd_mp2_dev *amd_mp2_find_device(struct pci_dev *candidate)
> > +{
> > +     struct device *dev;
> > +     struct pci_dev *pci_dev;
> > +
> > +     dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, candidate,
> > +                              amd_mp2_device_match);
> > +     if (!dev && candidate)
> > +             dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, NULL,
> > +                                      amd_mp2_device_match);
> > +     if (!dev)
> > +             return NULL;
> > +
> > +     pci_dev = to_pci_dev(dev);
> > +     return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev);
> > +}
> > +EXPORT_SYMBOL_GPL(amd_mp2_find_device);
> > +
> > +static int __init amd_mp2_pci_driver_init(void)
> > +{
> > +     if (debugfs_initialized())
> > +             debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
> > +
> > +     return pci_register_driver(&amd_mp2_pci_driver);
> > +}
> > +module_init(amd_mp2_pci_driver_init);
> > +
> > +static void __exit amd_mp2_pci_driver_exit(void)
> > +{
> > +     pci_unregister_driver(&amd_mp2_pci_driver);
> > +     debugfs_remove_recursive(debugfs_dir);
> > +}
> > +module_exit(amd_mp2_pci_driver_exit);
> > +
> > +MODULE_DESCRIPTION(DRIVER_DESC);
> > +MODULE_VERSION(DRIVER_VER);
> > +MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
> > +MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
> > +MODULE_LICENSE("Dual BSD/GPL");
> > diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.h b/drivers/i2c/busses/i2c-amd-pci-mp2.h
> > new file mode 100644
> > index 000000000000..65601b6ba3b3
> > --- /dev/null
> > +++ b/drivers/i2c/busses/i2c-amd-pci-mp2.h
> > @@ -0,0 +1,224 @@
> > +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
> > +/*
> > + * AMD PCIe MP2 Communication Driver
> > + *
> > + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > + *          Elie Morisse <syniurge@gmail.com>
> > + */
> > +
> > +#ifndef I2C_AMD_PCI_MP2_H
> > +#define I2C_AMD_PCI_MP2_H
> > +
> > +#include <linux/pci.h>
> > +
> > +#define PCI_DEVICE_ID_AMD_MP2        0x15E6
> > +
> > +struct amd_i2c_common;
> > +struct amd_mp2_dev;
> > +
> > +enum {
> > +     /* MP2 C2P Message Registers */
> > +     AMD_C2P_MSG0 = 0x10500,                 /* MP2 Message for I2C0 */
> > +     AMD_C2P_MSG1 = 0x10504,                 /* MP2 Message for I2C1 */
> > +     AMD_C2P_MSG2 = 0x10508,                 /* DRAM Address Lo / Data 0 */
> > +     AMD_C2P_MSG3 = 0x1050c,                 /* DRAM Address HI / Data 1 */
> > +     AMD_C2P_MSG4 = 0x10510,                 /* Data 2 */
> > +     AMD_C2P_MSG5 = 0x10514,                 /* Data 3 */
> > +     AMD_C2P_MSG6 = 0x10518,                 /* Data 4 */
> > +     AMD_C2P_MSG7 = 0x1051c,                 /* Data 5 */
> > +     AMD_C2P_MSG8 = 0x10520,                 /* Data 6 */
> > +     AMD_C2P_MSG9 = 0x10524,                 /* Data 7 */
> > +
> > +     /* MP2 P2C Message Registers */
> > +     AMD_P2C_MSG0 = 0x10680,                 /* Do not use */
> > +     AMD_P2C_MSG1 = 0x10684,                 /* I2C0 interrupt register */
> > +     AMD_P2C_MSG2 = 0x10688,                 /* I2C1 interrupt register */
> > +     AMD_P2C_MSG3 = 0x1068C,                 /* MP2 debug info */
> > +     AMD_P2C_MSG_INTEN = 0x10690,    /* MP2 interrupt gen register */
> > +     AMD_P2C_MSG_INTSTS = 0x10694,   /* Interrupt status */
> > +};
> > +
> > +/* Command register data structures */
> > +
> > +#define i2c_none (-1)
> > +enum i2c_cmd {
> > +     i2c_read = 0,
> > +     i2c_write,
> > +     i2c_enable,
> > +     i2c_disable,
> > +     number_of_sensor_discovered,
> > +     is_mp2_active,
> > +     invalid_cmd = 0xF,
> > +};
> > +
> > +enum speed_enum {
> > +     speed100k = 0,
> > +     speed400k = 1,
> > +     speed1000k = 2,
> > +     speed1400k = 3,
> > +     speed3400k = 4
> > +};
> > +
> > +enum mem_type {
> > +     use_dram = 0,
> > +     use_c2pmsg = 1,
> > +};
> > +
> > +/**
> > + * union i2c_cmd_base : bit access of C2P commands
> > + * @i2c_cmd: bit 0..3 i2c R/W command
> > + * @bus_id: bit 4..7 i2c bus index
> > + * @slave_addr: bit 8..15 slave address
> > + * @length: bit 16..27 read/write length
> > + * @i2c_speed: bit 28..30 bus speed
> > + * @mem_type: bit 31 0-DRAM; 1-C2P msg o/p
> > + */
> > +union i2c_cmd_base {
> > +     u32 ul;
> > +     struct {
> > +             enum i2c_cmd i2c_cmd : 4;
> > +             u8 bus_id : 4;
> > +             u32 slave_addr : 8;
> > +             u32 length : 12;
> > +             enum speed_enum i2c_speed : 3;
> > +             enum mem_type mem_type : 1;
> > +     } s;
> > +};
> > +
> > +/* Response - Response of SFI */
> > +enum response_type {
> > +     invalid_response = 0,
> > +     command_success = 1,
> > +     command_failed = 2,
> > +};
> > +
> > +/* Status - Command ID to indicate a command */
> > +enum status_type {
> > +     i2c_readcomplete_event = 0,
> > +     i2c_readfail_event = 1,
> > +     i2c_writecomplete_event = 2,
> > +     i2c_writefail_event = 3,
> > +     i2c_busenable_complete = 4,
> > +     i2c_busenable_failed = 5,
> > +     i2c_busdisable_complete = 6,
> > +     i2c_busdisable_failed = 7,
> > +     invalid_data_length = 8,
> > +     invalid_slave_address = 9,
> > +     invalid_i2cbus_id = 10,
> > +     invalid_dram_addr = 11,
> > +     invalid_command = 12,
> > +     mp2_active = 13,
> > +     numberof_sensors_discovered_resp = 14,
> > +     i2c_bus_notinitialized
> > +};
> > +
> > +/**
> > + * union i2c_event : bit access of P2C events
> > + * @response: bit 0..1 i2c response type
> > + * @status: bit 2..6 status_type
> > + * @mem_type: bit 7 0-DRAM; 1-C2P msg o/p
> > + * @bus_id: bit 8..11 i2c bus id
> > + * @length: bit 12..23 message length
> > + * @slave_addr: bit 24-31 slave address
> > + */
> > +union i2c_event {
> > +     u32 ul;
> > +     struct {
> > +             enum response_type response : 2;
> > +             enum status_type status : 5;
> > +             enum mem_type mem_type : 1;
> > +             u8 bus_id : 4;
> > +             u32 length : 12;
> > +             u32 slave_addr : 8;
> > +     } r;
> > +};
> > +
> > +/**
> > + * struct i2c_rw_config - i2c read/write settings
> > + * @slave_addr: slave address
> > + * @length: message length
> > + * @buf: buffer address
> > + * @dma_addr: if length > 32, holds the DMA buffer address
> > + * @dma_direction: if length > 32, is either FROM or TO device
> > + */
> > +struct i2c_rw_config {
> > +     u16 slave_addr;
> > +     u32 length;
> > +     u32 *buf;
> > +     dma_addr_t dma_addr;
> > +     enum dma_data_direction dma_direction;
> > +};
> > +
> > +/**
> > + * struct amd_i2c_pci_ops - platdrv hooks
> > + */
> > +struct amd_i2c_pci_ops {
> > +     int (*read_complete)(union i2c_event *event);
> > +     int (*write_complete)(union i2c_event *event);
> > +     int (*connect_complete)(union i2c_event *event);
> > +};
> > +
> > +/**
> > + * struct amd_i2c_common - per bus/i2c adapter context, shared
> > + *           between the pci and the platform driver
> > + * @eventval: MP2 event value set by the IRQ handler to be processed
> > + *           by the worker
> > + * @ops: platdrv hooks
> > + * @rw_cfg: settings for reads/writes
> > + * @work: delayed worker struct
> > + * @reqcmd: i2c command type requested by platdrv
> > + * @requested: true if the interrupt answered a request from platdrv
> > + * @bus_id: bus index
> > + * @i2c_speed: i2c bus speed determined by the slowest slave
> > + */
> > +struct amd_i2c_common {
> > +     union i2c_event eventval;
> > +     const struct amd_i2c_pci_ops *ops;
> > +     struct amd_mp2_dev *mp2_dev;
> > +     struct i2c_rw_config rw_cfg;
> > +     struct delayed_work work;
> > +     enum i2c_cmd reqcmd;
> > +     u8 bus_id;
> > +     enum speed_enum i2c_speed;
> > +};
> > +
> > +/**
> > + * struct amd_mp2_dev - per PCI device context
> > + * @pci_dev: PCI driver node
> > + * @plat_common: MP2 devices may have up to two busses,
> > + *           each bus corresponding to an i2c adapter
> > + * @mmio: iommapped registers
> > + * @lock: interrupt spinlock
> > + * @c2p_lock: controls access to the C2P mailbox shared between
> > + *           the two adapters
> > + */
> > +struct amd_mp2_dev {
> > +     struct pci_dev *pci_dev;
> > +     struct amd_i2c_common *plat_common[2];
> > +     void __iomem *mmio;
> > +     raw_spinlock_t lock;
> > +     struct mutex c2p_lock;
> > +     struct dentry *debugfs_dir;
> > +     struct dentry *debugfs_info;
> > +};
> > +
> > +int amd_mp2_read(struct amd_i2c_common *i2c_common);
> > +int amd_mp2_write(struct amd_i2c_common *i2c_common);
> > +int amd_mp2_connect(struct amd_i2c_common *i2c_common, bool enable);
> > +
> > +int amd_i2c_register_cb(struct amd_mp2_dev *mp2_dev,
> > +                     struct amd_i2c_common *i2c_common);
> > +int amd_i2c_unregister_cb(struct amd_mp2_dev *mp2_dev,
> > +                       struct amd_i2c_common *i2c_common);
> > +
> > +struct amd_mp2_dev *amd_mp2_find_device(struct pci_dev *candidate);
> > +
> > +#define ndev_pdev(ndev) ((ndev)->pci_dev)
> > +#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
> > +#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
> > +#define work_amd_i2c_common(__work) \
> > +     container_of(__work, struct amd_i2c_common, work.work)
> > +#define event_amd_i2c_common(__event) \
> > +     container_of(__event, struct amd_i2c_common, eventval)
> > +
> > +#endif
> > diff --git a/drivers/i2c/busses/i2c-amd-plat-mp2.c b/drivers/i2c/busses/i2c-amd-plat-mp2.c
> > new file mode 100644
> > index 000000000000..a10bd08fe1db
> > --- /dev/null
> > +++ b/drivers/i2c/busses/i2c-amd-plat-mp2.c
> > @@ -0,0 +1,373 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> > +/*
> > + * AMD MP2 I2C Platform Driver
> > + *
> > + * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
> > + *          Elie Morisse <syniurge@gmail.com>
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/types.h>
> > +#include <linux/slab.h>
> > +#include <linux/i2c.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/acpi.h>
> > +#include <linux/delay.h>
> > +
> > +#include "i2c-amd-pci-mp2.h"
> > +#define DRIVER_NAME "i2c-amd-plat-mp2"
> > +
> > +#define AMD_MP2_I2C_MAX_RW_LENGTH ((1 << 12) - 1)
> > +#define AMD_I2C_TIMEOUT (msecs_to_jiffies(250))
> > +
> > +/**
> > + * struct amd_i2c_dev - MP2 bus/i2c adapter context
> > + * @i2c_common: shared context with the MP2 pci driver
> > + * @pdev: platform driver node
> > + * @adapter: i2c adapter
> > + * @xfer_lock: xfer lock
> > + * @completion: xfer completion object
> > + */
> > +struct amd_i2c_dev {
> > +     struct amd_i2c_common i2c_common;
> > +     struct platform_device *pdev;
> > +     struct i2c_adapter adapter;
> > +     struct mutex xfer_lock;
> > +     struct completion msg_complete;
> > +     struct i2c_msg *msg_buf;
> > +     bool is_configured;
> > +};
> > +
> > +static const struct i2c_adapter_quirks amd_i2c_dev_quirks = {
> > +     .max_read_len = AMD_MP2_I2C_MAX_RW_LENGTH,
> > +     .max_write_len = AMD_MP2_I2C_MAX_RW_LENGTH,
> > +};
> > +
> > +#define amd_i2c_dev_common(__common) \
> > +     container_of(__common, struct amd_i2c_dev, i2c_common)
> > +
> > +static int i2c_amd_read_completion(union i2c_event *event)
> > +{
> > +     struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
> > +     struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
> > +
> > +     if (event->r.status == i2c_readcomplete_event)
> > +             dev_dbg(&i2c_dev->pdev->dev, "%s readdata:%*ph\n",
> > +                     __func__, event->r.length,
> > +                     i2c_common->rw_cfg.buf);
> > +
> > +     complete(&i2c_dev->msg_complete);
> > +
> > +     return 0;
> > +}
> > +
> > +static int i2c_amd_write_completion(union i2c_event *event)
> > +{
> > +     struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
> > +     struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
> > +
> > +     complete(&i2c_dev->msg_complete);
> > +
> > +     return 0;
> > +}
> > +
> > +static int i2c_amd_connect_completion(union i2c_event *event)
> > +{
> > +     struct amd_i2c_common *i2c_common = event_amd_i2c_common(event);
> > +     struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
> > +
> > +     complete(&i2c_dev->msg_complete);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct amd_i2c_pci_ops data_handler = {
> > +             .read_complete = i2c_amd_read_completion,
> > +             .write_complete = i2c_amd_write_completion,
> > +             .connect_complete = i2c_amd_connect_completion,
> > +};
> > +
> > +static int i2c_amd_pci_configure(struct amd_i2c_dev *i2c_dev)
> > +{
> > +     struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> > +
> > +     amd_i2c_register_cb(i2c_common->mp2_dev, i2c_common);
> > +     i2c_common->ops = &data_handler;
> > +
> > +     return 0;
> > +}
> > +
> > +static int i2c_amd_pci_xconnect(struct amd_i2c_dev *i2c_dev, bool enable)
> > +{
> > +     struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> > +     unsigned long timeout;
> > +
> > +     reinit_completion(&i2c_dev->msg_complete);
> > +     amd_mp2_connect(i2c_common, enable);
> > +     timeout = wait_for_completion_timeout(&i2c_dev->msg_complete,
> > +                                           AMD_I2C_TIMEOUT);
> > +     if (timeout == 0) {
> > +             dev_err(&i2c_dev->pdev->dev,
> > +                     "i2c connection timed out\n");
> > +             mutex_unlock(&i2c_dev->xfer_lock);
> > +             return -ETIMEDOUT;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int i2c_amd_xfer_msg(struct amd_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
> > +{
> > +     struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> > +     unsigned long timeout;
> > +     bool is_read = pmsg->flags & I2C_M_RD;
> > +
> > +     reinit_completion(&i2c_dev->msg_complete);
> > +
> > +     i2c_common->rw_cfg.slave_addr = pmsg->addr;
> > +     i2c_common->rw_cfg.buf = (u32 *)pmsg->buf;
> > +     i2c_common->rw_cfg.length = pmsg->len;
> > +     i2c_dev->msg_buf = pmsg;
> > +
> > +     if (is_read)
> > +             amd_mp2_read(i2c_common);
> > +     else
> > +             amd_mp2_write(i2c_common);
> > +
> > +     timeout = wait_for_completion_timeout
> > +             (&i2c_dev->msg_complete, AMD_I2C_TIMEOUT);
> > +     if (timeout == 0) {
> > +             dev_err(&i2c_dev->pdev->dev,
> > +                     "i2c %s timed out\n",
> > +                     is_read ? "read" : "write");
> > +             return -ETIMEDOUT;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int i2c_amd_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
> > +{
> > +     struct amd_i2c_dev *dev = i2c_get_adapdata(adap);
> > +     int i;
> > +     struct i2c_msg *pmsg;
> > +     int err;
> > +
> > +     mutex_lock(&dev->xfer_lock);
> > +
> > +     if (dev->is_configured == 0) {
> > +             i2c_amd_pci_configure(dev);
> > +             i2c_amd_pci_xconnect(dev, true);
> > +             dev->is_configured = 1;
> > +     }
> > +
> > +     for (i = 0; i < num; i++) {
> > +             pmsg = &msgs[i];
> > +             err = i2c_amd_xfer_msg(dev, pmsg);
> > +             if (err)
> > +                     break;
> > +     }
> > +
> > +     mutex_unlock(&dev->xfer_lock);
> > +
> > +     if (err)
> > +             return err;
> > +     return num;
> > +}
> > +
> > +static u32 i2c_amd_func(struct i2c_adapter *a)
> > +{
> > +     return I2C_FUNC_I2C;
> > +}
> > +
> > +static const struct i2c_algorithm i2c_amd_algorithm = {
> > +     .master_xfer = i2c_amd_xfer,
> > +     .functionality = i2c_amd_func,
> > +};
> > +
> > +static enum speed_enum i2c_amd_get_bus_speed(struct platform_device *pdev)
> > +{
> > +     u32 acpi_speed;
> > +     int i;
> > +     static const u32 supported_speeds[] = {
> > +             0, 100000, 400000, 1000000, 1400000, 3400000
> > +     };
> > +
> > +     acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
> > +     /* round down to the lowest standard speed */
> > +     for (i = 1; i < ARRAY_SIZE(supported_speeds); i++) {
> > +             if (acpi_speed < supported_speeds[i])
> > +                     break;
> > +     }
> > +     acpi_speed = supported_speeds[i - 1];
> > +
> > +     switch (acpi_speed) {
> > +     case 100000:
> > +             return speed100k;
> > +     case 400000:
> > +             return speed400k;
> > +     case 1000000:
> > +             return speed1000k;
> > +     case 1400000:
> > +             return speed1400k;
> > +     case 3400000:
> > +             return speed3400k;
> > +     default:
> > +             return speed400k;
> > +     }
> > +}
> > +
> > +static struct device *i2c_amd_acpi_get_first_phys_node(struct acpi_device *adev)
> > +{
> > +     const struct acpi_device_physical_node *node;
> > +
> > +     if (list_empty(&adev->physical_node_list))
> > +             return NULL;
> > +
> > +     node = list_first_entry(&adev->physical_node_list,
> > +                             struct acpi_device_physical_node, node);
> > +     return node->dev;
> > +}
> > +
> > +/*
> > + * Assume that the first device listed by the _DEP method is the parent
> > + * MP2 device
> > + */
> > +static struct pci_dev *i2c_amd_find_pci_parent(struct acpi_device *adev)
> > +{
> > +     struct acpi_device *parent_adev;
> > +     struct device *phys_dev;
> > +     struct acpi_handle_list dep_devices;
> > +     acpi_status status;
> > +
> > +     if (!acpi_has_method(adev->handle, "_DEP"))
> > +             return NULL;
> > +
> > +     status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
> > +                                      &dep_devices);
>
> Several other callers of acpi_evaluate_reference() do call
> acpi_has_method() first, but I'm pretty sure that's not necessary.  If
> _DEP doesn't exist, acpi_evaluate_reference() should return an error
> itself.
>
> _DEP is for operation region dependencies.  I don't know enough about
> ACPI to know why you're using it to find the PCI device related to an
> ACPI device.  That doesn't really seem like an op region thing.
>
> > +     if (ACPI_FAILURE(status) || !dep_devices.count)
> > +             return NULL;
> > +
> > +     if (acpi_bus_get_device(dep_devices.handles[0], &parent_adev))
> > +             return NULL;
> > +     phys_dev = i2c_amd_acpi_get_first_phys_node(parent_adev);
> > +
> > +     if (!dev_is_pci(phys_dev))
> > +             return NULL;
> > +     return to_pci_dev(phys_dev);
> > +}
> > +
> > +static int i2c_amd_probe(struct platform_device *pdev)
> > +{
> > +     int ret;
> > +     struct amd_i2c_dev *i2c_dev;
> > +     struct device *dev = &pdev->dev;
> > +     acpi_handle handle = ACPI_HANDLE(&pdev->dev);
> > +     struct acpi_device *adev;
> > +     struct pci_dev *parent_candidate = NULL;
> > +
> > +     i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL);
> > +     if (!i2c_dev)
> > +             return -ENOMEM;
> > +
> > +     i2c_dev->pdev = pdev;
> > +
> > +     if (!acpi_bus_get_device(handle, &adev)) {
> > +             const char *uid = adev->pnp.unique_id;
> > +
> > +             if (!uid) {
> > +                     dev_err(&pdev->dev, "missing UID/bus id!\n");
> > +                     return -EINVAL;
> > +             }
> > +
> > +             if (strcmp(uid, "0") == 0) {
> > +                     i2c_dev->i2c_common.bus_id = 0;
> > +             } else if (strcmp(uid, "1") == 0) {
> > +                     i2c_dev->i2c_common.bus_id = 1;
> > +             } else {
> > +                     dev_err(&pdev->dev,
> > +                             "incorrect UID/bus id \"%s\"!\n", uid);
> > +                     return -EINVAL;
> > +             }
> > +
> > +             dev_dbg(&pdev->dev, "bus id is %u\n",
> > +                     i2c_dev->i2c_common.bus_id);
> > +
> > +             i2c_dev->i2c_common.i2c_speed = i2c_amd_get_bus_speed(pdev);
> > +     } else {
> > +             i2c_dev->i2c_common.i2c_speed = speed400k;
> > +     }
> > +
> > +     /* setup i2c adapter description */
> > +     i2c_dev->adapter.owner = THIS_MODULE;
> > +     i2c_dev->adapter.algo = &i2c_amd_algorithm;
> > +     i2c_dev->adapter.quirks = &amd_i2c_dev_quirks;
> > +     i2c_dev->adapter.dev.parent = dev;
> > +     i2c_dev->adapter.algo_data = i2c_dev;
> > +     ACPI_COMPANION_SET(&i2c_dev->adapter.dev, ACPI_COMPANION(&pdev->dev));
> > +     i2c_dev->adapter.dev.of_node = dev->of_node;
> > +     snprintf(i2c_dev->adapter.name, sizeof(i2c_dev->adapter.name), "%s-%s",
> > +              "i2c_dev-i2c", dev_name(pdev->dev.parent));
> > +
> > +     if (adev)
> > +             parent_candidate = i2c_amd_find_pci_parent(adev);
> > +     i2c_dev->i2c_common.mp2_dev = amd_mp2_find_device(parent_candidate);
> > +     if (!i2c_dev->i2c_common.mp2_dev) {
> > +             dev_err(&pdev->dev,
> > +                     "%s Could not find MP2 PCI device for i2c adapter\n",
> > +                    __func__);
> > +             return -EINVAL;
> > +     }
> > +
> > +     platform_set_drvdata(pdev, i2c_dev);
> > +
> > +     i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
> > +
> > +     init_completion(&i2c_dev->msg_complete);
> > +     mutex_init(&i2c_dev->xfer_lock);
> > +
> > +     /* and finally attach to i2c layer */
> > +     ret = i2c_add_adapter(&i2c_dev->adapter);
> > +
> > +     if (ret < 0)
> > +             dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
> > +
> > +     return ret;
> > +}
> > +
> > +static int i2c_amd_remove(struct platform_device *pdev)
> > +{
> > +     struct amd_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
> > +     struct amd_i2c_common *i2c_common = &i2c_dev->i2c_common;
> > +
> > +     i2c_amd_pci_xconnect(i2c_dev, false);
> > +
> > +     amd_i2c_unregister_cb(i2c_common->mp2_dev, i2c_common);
> > +     i2c_del_adapter(&i2c_dev->adapter);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct acpi_device_id i2c_amd_acpi_match[] = {
> > +             { "AMDI0011" },
> > +             { },
> > +};
> > +MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match);
> > +
> > +static struct platform_driver amd_i2c_plat_driver = {
> > +             .probe = i2c_amd_probe,
> > +             .remove = i2c_amd_remove,
> > +             .driver = {
> > +                             .name = "i2c_amd_plat_mp2",
> > +                             .acpi_match_table = ACPI_PTR
> > +                                             (i2c_amd_acpi_match),
> > +             },
> > +};
> > +
> > +module_platform_driver(amd_i2c_plat_driver);
> > +
> > +MODULE_DESCRIPTION("AMD MP2 I2C Platform Driver");
> > +MODULE_AUTHOR("Nehal Shah <nehal-bakulchandra.shah@amd.com>");
> > +MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
> > +MODULE_LICENSE("Dual BSD/GPL");
> > --
> > 2.17.1
> >

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-11-11 17:36 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-27 15:09 [PATCH v7] i2c: Add PCI and platform drivers for the AMD MP2 I2C controller Elie Morisse
2018-10-30 20:56 ` Bjorn Helgaas
2018-10-30 21:47   ` Tobias Thomer
     [not found]   ` <CAHYSBa8rpRS8suDdE-mfem_Gi3HYVXRydTm3PESnkzFVq2LXrA@mail.gmail.com>
2018-11-04 16:41     ` Elie Morisse
2018-11-04 16:43   ` Elie Morisse
2018-11-11 17:36   ` Elie Morisse

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).