* [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
[parent not found: <CAHYSBa8rpRS8suDdE-mfem_Gi3HYVXRydTm3PESnkzFVq2LXrA@mail.gmail.com>]
* 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).