diff options
Diffstat (limited to 'meta-amdfalconx86/recipes-kernel/linux/files/0001-yocto-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch')
-rw-r--r-- | meta-amdfalconx86/recipes-kernel/linux/files/0001-yocto-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/meta-amdfalconx86/recipes-kernel/linux/files/0001-yocto-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch b/meta-amdfalconx86/recipes-kernel/linux/files/0001-yocto-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch new file mode 100644 index 00000000..3d806215 --- /dev/null +++ b/meta-amdfalconx86/recipes-kernel/linux/files/0001-yocto-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch @@ -0,0 +1,415 @@ +The patch essentially adds support for two functions: +amd_imc_enter_scratch_ram() and amd_imc_exit_scratch_ram(). These +functions instruct IMC to stop and start fetching code from BIOS +ROM respectively. These functions are needed where IMC is trying +to fetch code on a shared bus when some other transaction is already +occuring. To prevent IMC to fetch incorrect data from ROM while it +is still being updated, we instruct IMC to temporarily stop fetching +code from BIOS, and then start fetching again when it is safe to do +so. + +upstream status: None + +Signed-off-by: Arindam Nath <arindam.nath@amd.com> +Signed-off-by: Sanjay Mehta <sanju.mehta@amd.com> +diff -Naur a/drivers/staging/amd_imc/amd_imc.c b/drivers/staging/amd_imc/amd_imc.c +--- a/drivers/staging/amd_imc/amd_imc.c 1970-01-01 05:30:00.000000000 +0530 ++++ b/drivers/staging/amd_imc/amd_imc.c 2014-11-17 15:29:04.300072303 +0530 +@@ -0,0 +1,286 @@ ++/***************************************************************************** ++* ++* Copyright (c) 2014, Advanced Micro Devices, Inc. ++* All rights reserved. ++* ++* Redistribution and use in source and binary forms, with or without ++* modification, are permitted provided that the following conditions are met: ++* * Redistributions of source code must retain the above copyright ++* notice, this list of conditions and the following disclaimer. ++* * Redistributions in binary form must reproduce the above copyright ++* notice, this list of conditions and the following disclaimer in the ++* documentation and/or other materials provided with the distribution. ++* * Neither the name of Advanced Micro Devices, Inc. nor the names of ++* its contributors may be used to endorse or promote products derived ++* from this software without specific prior written permission. ++* ++* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ++* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY ++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++* ++* ++***************************************************************************/ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/ioport.h> ++#include <linux/platform_device.h> ++#include <linux/uaccess.h> ++#include <linux/io.h> ++#include <linux/delay.h> ++#include <linux/amd_imc.h> ++ ++static int imc_enabled; ++static u16 imc_port_addr; ++static u8 msg_reg_base_hi; ++static u8 msg_reg_base_lo; ++static u16 msg_reg_base; ++ ++static struct pci_dev *amd_imc_pci; ++static struct platform_device *amd_imc_platform_device; ++ ++static DEFINE_PCI_DEVICE_TABLE(amd_lpc_pci_tbl) = { ++ {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LPC_BRIDGE, PCI_ANY_ID, ++ PCI_ANY_ID,}, ++ {} ++}; ++ ++void amd_imc_enter_scratch_ram(void) ++{ ++ u8 byte; ++ ++ if (!imc_enabled) ++ return; ++ ++ /* Instruct IMC to enter scratch RAM */ ++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ outb(0, msg_reg_base + AMD_MSG_DATA_REG_OFFSET); ++ ++ outb(AMD_MSG_REG1, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ outb(AMD_IMC_ENTER_SCRATCH_RAM, msg_reg_base + AMD_MSG_DATA_REG_OFFSET); ++ ++ outb(AMD_MSG_SYS_TO_IMC, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ outb(AMD_IMC_ROM_OWNERSHIP_SEM, msg_reg_base + ++ AMD_MSG_DATA_REG_OFFSET); ++ ++ /* As per the spec, the firmware may take up to 50ms */ ++ msleep(50); ++ ++ /* read message registger 0 to confirm function completion */ ++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ byte = inb(msg_reg_base + AMD_MSG_DATA_REG_OFFSET); ++ ++ if (byte == AMD_IMC_FUNC_NOT_SUPP) ++ pr_info("amd_imc: %s not supported\n", __func__); ++ else if (byte == AMD_IMC_FUNC_COMPLETED) ++ pr_info("amd_imc: %s completed\n", __func__); ++} ++EXPORT_SYMBOL_GPL(amd_imc_enter_scratch_ram); ++ ++void amd_imc_exit_scratch_ram(void) ++{ ++ u8 byte; ++ ++ if (!imc_enabled) ++ return; ++ ++ /* Instruct IMC to exit scratch RAM */ ++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ outb(0, msg_reg_base + AMD_MSG_DATA_REG_OFFSET); ++ ++ outb(AMD_MSG_REG1, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ outb(AMD_IMC_ENTER_SCRATCH_RAM, msg_reg_base + AMD_MSG_DATA_REG_OFFSET); ++ ++ outb(AMD_MSG_SYS_TO_IMC, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ outb(AMD_IMC_ROM_OWNERSHIP_SEM, msg_reg_base + ++ AMD_MSG_DATA_REG_OFFSET); ++ ++ /* As per the spec, the firmware may take up to 50ms */ ++ msleep(50); ++ ++ /* read message registger 0 to confirm function completion */ ++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET); ++ byte = inb(msg_reg_base + AMD_MSG_DATA_REG_OFFSET); ++ ++ if (byte == AMD_IMC_FUNC_NOT_SUPP) ++ pr_info("amd_imc: %s not supported\n", __func__); ++ else if (byte == AMD_IMC_FUNC_COMPLETED) ++ pr_info("amd_imc: %s completed\n", __func__); ++} ++EXPORT_SYMBOL_GPL(amd_imc_exit_scratch_ram); ++ ++/* ++* The PCI Device ID table below is used to identify the platform ++* the driver is supposed to work for. Since this is a platform ++* driver, we need a way for us to be able to find the correct ++* platform when the driver gets loaded, otherwise we should ++* bail out. ++*/ ++static DEFINE_PCI_DEVICE_TABLE(amd_imc_pci_tbl) = { ++ { PCI_VENDOR_ID_AMD, 0x790B, PCI_ANY_ID, ++ PCI_ANY_ID, }, ++ { 0, }, ++}; ++ ++static int amd_imc_init(struct platform_device *pdev) ++{ ++ struct pci_dev *dev = NULL; ++ static u32 imc_strap_status_phys; ++ void __iomem *imcstrapstatus; ++ u32 val; ++ ++ /* Match the PCI device */ ++ for_each_pci_dev(dev) { ++ if (pci_match_id(amd_imc_pci_tbl, dev) != NULL) { ++ amd_imc_pci = dev; ++ break; ++ } ++ } ++ ++ if (!amd_imc_pci) ++ return -ENODEV; ++ ++ ++ /* ACPI MMIO Base Address */ ++ val = AMD_GPIO_ACPIMMIO_BASE; ++ ++ /* IMCStrapStatus is located at ACPI MMIO Base Address + 0xE80 */ ++ if (!request_mem_region_exclusive(val + AMD_IMC_STRAP_STATUS_OFFSET, ++ AMD_IMC_STRAP_STATUS_SIZE, "IMC Strap Status")) { ++ pr_err("amd_imc: MMIO address 0x%04x already in use\n", ++ val + AMD_IMC_STRAP_STATUS_OFFSET); ++ goto exit; ++ } ++ ++ imc_strap_status_phys = val + AMD_IMC_STRAP_STATUS_OFFSET; ++ ++ imcstrapstatus = ioremap(imc_strap_status_phys, ++ AMD_IMC_STRAP_STATUS_SIZE); ++ if (!imcstrapstatus) { ++ pr_err("amd_imc: failed to get IMC Strap Status address\n"); ++ goto unreg_imc_region; ++ } ++ ++ /* Check if IMC is enabled */ ++ val = ioread32(imcstrapstatus); ++ if ((val & AMD_IMC_ENABLED) == AMD_IMC_ENABLED) { ++ struct pci_dev *pdev = NULL; ++ ++ pr_info("amd_imc: IMC is enabled\n"); ++ imc_enabled = 1; ++ ++ /* ++ * In case IMC is enabled, we need to find the IMC port address ++ * which will be used to send messages to the IMC. The IMC port ++ * address is stored in bits 1:15 of PCI device 20, function 3, ++ * offset 0xA4. PCI device 20, function 3 is actually the LPC ++ * ISA bridge. ++ */ ++ for_each_pci_dev(pdev) { ++ if (pci_match_id(amd_lpc_pci_tbl, pdev) != NULL) ++ break; ++ } ++ ++ /* Match found. Get the IMC port address */ ++ if (pdev) { ++ pci_read_config_word(pdev, AMD_PCI_IMC_PORT_ADDR_REG, ++ &imc_port_addr); ++ ++ /* The actual IMC port address has bit 0 masked out */ ++ imc_port_addr &= ~AMD_IMC_PORT_ACTIVE; ++ } ++ ++ /* Put device into configuration state */ ++ outb(AMD_DEVICE_ENTER_CONFIG_STATE, imc_port_addr + ++ AMD_IMC_INDEX_REG_OFFSET); ++ ++ /* Select logical device number 9 */ ++ outb(AMD_SET_LOGICAL_DEVICE, imc_port_addr + ++ AMD_IMC_INDEX_REG_OFFSET); ++ outb(AMD_SET_DEVICE_9, imc_port_addr + ++ AMD_IMC_DATA_REG_OFFSET); ++ ++ /* read high byte of message register base address */ ++ outb(AMD_MSG_REG_HIGH, imc_port_addr + ++ AMD_IMC_INDEX_REG_OFFSET); ++ msg_reg_base_hi = inb(imc_port_addr + AMD_IMC_DATA_REG_OFFSET); ++ ++ /* read low byte of message register base address */ ++ outb(AMD_MSG_REG_LOW, imc_port_addr + ++ AMD_IMC_INDEX_REG_OFFSET); ++ msg_reg_base_lo = inb(imc_port_addr + AMD_IMC_DATA_REG_OFFSET); ++ ++ msg_reg_base = msg_reg_base_lo | (msg_reg_base_hi << 8); ++ ++ /* Get device out of configuration state */ ++ outb(AMD_DEVICE_EXIT_CONFIG_STATE, imc_port_addr + ++ AMD_IMC_INDEX_REG_OFFSET); ++ } else { ++ pr_info("amd_imc: IMC is disabled\n"); ++ imc_enabled = 0; ++ } ++ ++ /* Release the region occupied by IMC Strap Status register */ ++ iounmap(imcstrapstatus); ++ release_mem_region(imc_strap_status_phys, AMD_IMC_STRAP_STATUS_SIZE); ++ ++ return 0; ++ ++unreg_imc_region: ++ release_mem_region(imc_strap_status_phys, AMD_IMC_STRAP_STATUS_SIZE); ++exit: ++ return -ENODEV; ++} ++ ++static struct platform_driver amd_imc_driver = { ++ .probe = amd_imc_init, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = IMC_MODULE_NAME, ++ }, ++}; ++ ++static int __init amd_imc_init_module(void) ++{ ++ int err; ++ ++ pr_info("AMD IMC Driver v%s\n", IMC_VERSION); ++ ++ err = platform_driver_register(&amd_imc_driver); ++ if (err) ++ return err; ++ ++ amd_imc_platform_device = platform_device_register_simple( ++ IMC_MODULE_NAME, -1, NULL, 0); ++ if (IS_ERR(amd_imc_platform_device)) { ++ err = PTR_ERR(amd_imc_platform_device); ++ goto unreg_platform_driver; ++ } ++ ++ return 0; ++ ++unreg_platform_driver: ++ platform_driver_unregister(&amd_imc_driver); ++ return err; ++} ++ ++static void __exit amd_imc_cleanup_module(void) ++{ ++ platform_device_unregister(amd_imc_platform_device); ++ platform_driver_unregister(&amd_imc_driver); ++ pr_info("AMD IMC Module Unloaded\n"); ++} ++ ++module_init(amd_imc_init_module); ++module_exit(amd_imc_cleanup_module); ++ ++MODULE_AUTHOR("Arindam Nath <arindam.nath@amd.com>"); ++MODULE_DESCRIPTION("AMD IMC driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff -Naur a/drivers/staging/amd_imc/Kconfig b/drivers/staging/amd_imc/Kconfig +--- a/drivers/staging/amd_imc/Kconfig 1970-01-01 05:30:00.000000000 +0530 ++++ b/drivers/staging/amd_imc/Kconfig 2014-11-17 15:26:04.496065060 +0530 +@@ -0,0 +1,9 @@ ++config AMD_IMC ++ bool "AMD Intergrated Micro Controller support" ++ depends on PCI && X86_64 ++ default y ++ ---help--- ++ This driver supports AMD Intergrated Micro Controller. ++ ++ To compile this driver as a module, choose M here. The module ++ will be called amd_imc. +diff -Naur a/drivers/staging/amd_imc/Makefile b/drivers/staging/amd_imc/Makefile +--- a/drivers/staging/amd_imc/Makefile 1970-01-01 05:30:00.000000000 +0530 ++++ b/drivers/staging/amd_imc/Makefile 2014-11-17 15:26:04.496065060 +0530 +@@ -0,0 +1 @@ ++obj-$(CONFIG_AMD_IMC) += amd_imc.o +diff -Naur a/drivers/staging/Kconfig b/drivers/staging/Kconfig +--- a/drivers/staging/Kconfig 2014-03-31 09:10:15.000000000 +0530 ++++ b/drivers/staging/Kconfig 2014-11-17 15:26:04.496065060 +0530 +@@ -146,4 +146,8 @@ + + source "drivers/staging/dgap/Kconfig" + ++source "drivers/staging/amd_imc/Kconfig" ++ ++source "drivers/staging/amd_imc/Kconfig" ++ + endif # STAGING +diff -Naur a/drivers/staging/Makefile b/drivers/staging/Makefile +--- a/drivers/staging/Makefile 2014-03-31 09:10:15.000000000 +0530 ++++ b/drivers/staging/Makefile 2014-11-17 15:26:04.496065060 +0530 +@@ -65,3 +65,4 @@ + obj-$(CONFIG_DGNC) += dgnc/ + obj-$(CONFIG_DGAP) += dgap/ + obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ ++obj-$(CONFIG_AMD_IMC) += amd_imc/ +diff -Naur a/include/linux/amd_imc.h b/include/linux/amd_imc.h +--- a/include/linux/amd_imc.h 1970-01-01 05:30:00.000000000 +0530 ++++ b/include/linux/amd_imc.h 2014-11-17 15:27:54.132069476 +0530 +@@ -0,0 +1,69 @@ ++#ifndef _AMD_IMC_H_ ++#define _AMD_IMC_H_ ++ ++/* Module and version information */ ++#define IMC_VERSION "0.1" ++#define IMC_MODULE_NAME "AMD IMC" ++#define IMC_DRIVER_NAME IMC_MODULE_NAME ", v" IMC_VERSION ++ ++#define DRV_NAME "amd_imc" ++ ++/* IO port address for indirect access using the ACPI PM registers */ ++#define AMD_IO_PM_INDEX_REG 0xCD6 ++#define AMD_IO_PM_DATA_REG 0xCD7 ++ ++#define AMD_GPIO_ACPIMMIO_BASE 0xFED80000 ++#define AMD_PM_ACPI_MMIO_BASE0 0x24 ++#define AMD_PM_ACPI_MMIO_BASE1 0x25 ++#define AMD_PM_ACPI_MMIO_BASE2 0x26 ++#define AMD_PM_ACPI_MMIO_BASE3 0x27 ++ ++#define AMD_ACPI_MMIO_ADDR_MASK ~0x1FFF ++ ++/* Offset of IMC Strap Status register in the ACPI MMIO region */ ++#define AMD_IMC_STRAP_STATUS_OFFSET 0xE80 ++ #define AMD_IMC_ENABLED 0x4 ++#define AMD_IMC_STRAP_STATUS_SIZE 4 ++ ++#define PCI_DEVICE_ID_AMD_LPC_BRIDGE 0x790E ++ #define AMD_PCI_IMC_PORT_ADDR_REG 0xA4 ++ #define AMD_IMC_PORT_ACTIVE 0x0001 ++ ++/* Device configuration state fields */ ++#define AMD_DEVICE_ENTER_CONFIG_STATE 0x5A ++#define AMD_DEVICE_EXIT_CONFIG_STATE 0xA5 ++ ++/* Global configuration registers */ ++#define AMD_SET_LOGICAL_DEVICE 0x07 ++ #define AMD_SET_DEVICE_9 0x09 ++#define AMD_MSG_REG_HIGH 0x60 ++#define AMD_MSG_REG_LOW 0x61 ++ ++/* IMC index and data port offsets for indirect access */ ++#define AMD_IMC_INDEX_REG_OFFSET 0x00 ++#define AMD_IMC_DATA_REG_OFFSET 0x01 ++ ++/* Message register index and data port offsets for indirect access */ ++#define AMD_MSG_INDEX_REG_OFFSET 0x00 ++#define AMD_MSG_DATA_REG_OFFSET 0x01 ++ ++/* IMC message registers */ ++#define AMD_MSG_SYS_TO_IMC 0x80 ++ #define AMD_IMC_ROM_OWNERSHIP_SEM 0x96 ++#define AMD_MSG_REG0 0x82 ++ #define AMD_IMC_FUNC_NOT_SUPP 0x00 ++ #define AMD_IMC_FUNC_COMPLETED 0xFA ++#define AMD_MSG_REG1 0x83 ++ #define AMD_IMC_ENTER_SCRATCH_RAM 0xB4 ++ #define AMD_IMC_EXIT_SCRATCH_RAM 0xB5 ++ ++/* Extern functions */ ++#ifdef CONFIG_AMD_IMC ++extern void amd_imc_enter_scratch_ram(void); ++extern void amd_imc_exit_scratch_ram(void); ++#else ++void amd_imc_enter_scratch_ram(void) {} ++void amd_imc_exit_scratch_ram(void) {} ++#endif ++ ++#endif /* _AMD_IMC_H_ */ |