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