From 645f2d69560456a4c9dd20c43618f86f7199979b Mon Sep 17 00:00:00 2001 From: Shijie Zhang Date: Thu, 29 Mar 2012 06:39:51 +0800 Subject: [PATCH] intel_scu_mip: update intel mip driver BZ: 28902 Base on current IPC driver framework, it is not suitable to put MIP access code inside IPC bus driver. So we move it to a dedicated mip driver, to make it more clear in logic. Change-Id: I2b2392f586d5c5ef17b3498cdfe6e58e396e7ebf Signed-off-by: Shijie Zhang Reviewed-on: http://android.intel.com:8080/41379 Reviewed-by: Du, Alek Tested-by: Wang, Zhifeng Reviewed-by: buildbot Tested-by: buildbot --- arch/x86/include/asm/intel_scu_ipc.h | 10 +- arch/x86/platform/intel-mid/intel-mid.c | 35 +++--- drivers/platform/x86/Makefile | 2 +- drivers/platform/x86/intel_scu_ipc.c | 183 +++++++++----------------------- drivers/platform/x86/intel_scu_mip.c | 162 ++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 152 deletions(-) create mode 100644 drivers/platform/x86/intel_scu_mip.c diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h index de1bf0a..abdde5d 100644 --- a/arch/x86/include/asm/intel_scu_ipc.h +++ b/arch/x86/include/asm/intel_scu_ipc.h @@ -36,8 +36,13 @@ #define IPC_CMD_VRTC_SYNC_RTC 3 /* Sync MSIC/PMIC RTC to VRTC */ /* Issue commands to the SCU with or without data */ int intel_scu_ipc_simple_command(int cmd, int sub); -int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, - u32 *out, int outlen); +void intel_scu_ipc_lock(void); +void intel_scu_ipc_unlock(void); +int intel_scu_ipc_command(u32 cmd, u32 sub, u32 *in, u32 inlen, + u32 *out, u32 outlen); +int intel_scu_ipc_raw_cmd(u32 cmd, u32 sub, u32 *in, u32 inlen, + u32 *out, u32 outlen, u32 dptr, u32 sptr); + /* I2C control api */ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data); @@ -45,7 +50,6 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data); int intel_scu_ipc_mrstfw_update(u8 *buffer, u32 length); int intel_scu_ipc_medfw_upgrade(void); int intel_scu_ipc_medfw_prepare(void __user *arg); - int intel_scu_ipc_read_mip(u8 *data, int len, int offset, int issigned); int intel_scu_ipc_write_umip(u8 *data, int len, int offset); diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c index 4d36817..04b623a 100644 --- a/arch/x86/platform/intel-mid/intel-mid.c +++ b/arch/x86/platform/intel-mid/intel-mid.c @@ -550,25 +550,32 @@ static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *pentry, } #ifdef CONFIG_INTEL_SCU_IPC -static int __init intel_scu_pmic_init(void) -{ - int ret; - struct ipc_board_info board_info; - - memset(&board_info, 0, sizeof(board_info)); - strncpy(board_info.name, "intel_scu_pmic", 16); - board_info.bus_id = IPC_SCU; +static int __init intel_scu_ipc_subdev_init(void) +{ + int i, ret; + static struct ipc_board_info info[] __initdata = { + [0] = { + .name = "intel_scu_pmic", + .bus_id = IPC_SCU, + }, + + [1] = { + .name = "intel_scu_mip", + .bus_id = IPC_SCU, + }, + }; - ret = ipc_new_device(&board_info); - if (ret) { - pr_err("failed to create ipc device: intel_scu_pmic\n"); - return -EINVAL; + for (i = 0; i < ARRAY_SIZE(info); i++) { + ret = ipc_new_device(&info[i]); + if (ret) { + pr_err("Fail to create ipc device: %s\n", info[i].name); + return -EINVAL; + } } return 0; } -/* Ensure that it's created as the first ipc device in the ipc_device_list */ -postcore_initcall(intel_scu_pmic_init); +postcore_initcall(intel_scu_ipc_subdev_init); #endif static void __init sfi_handle_spi_dev(struct sfi_device_table_entry *pentry, diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 23f37dc..d942eef 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o -obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o intel_scu_pmic.o +obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o intel_scu_pmic.o intel_scu_mip.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 3f2e9b3..195a82a 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -57,12 +57,12 @@ #define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ #define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ -#define IPC_SPTR_ADDR 0x08 /* IPC source pointer regiser*/ -#define IPC_DPTR_ADDR 0x0c /* IPC destination pointer regiser*/ -#define IPC_MIP_BASE 0xFFFD8000 /* sram base address for mip accessing*/ -#define IPC_MIP_MAX_ADDR 0x1000 - -#define IPC_IOC 0x100 +#define IPC_STATUS_ADDR 0X04 +#define IPC_SPTR_ADDR 0x08 +#define IPC_DPTR_ADDR 0x0C +#define IPC_READ_BUFFER 0x90 +#define IPC_WRITE_BUFFER 0x80 +#define IPC_IOC 0x100 static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id); static void ipc_remove(struct pci_dev *pdev); @@ -99,13 +99,6 @@ static char *ipc_err_sources[] = { "unsigned kernel", }; -/* - * IPC Read Buffer (Read Only): - * 16 byte buffer for receiving data from SCU, if IPC command - * processing results in response data - */ -#define IPC_READ_BUFFER 0x90 - #define IPC_I2C_CNTRL_ADDR 0 #define I2C_DATA_ADDR 0x04 @@ -145,7 +138,7 @@ static inline void ipc_command(u32 cmd) /* Send ipc command */ */ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */ { - writel(data, ipcdev.ipc_base + 0x80 + offset); + writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset); } /* @@ -158,7 +151,7 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */ static inline u32 ipc_read_status(void) { - return __raw_readl(ipcdev.ipc_base + 0x04); + return __raw_readl(ipcdev.ipc_base + IPC_STATUS_ADDR); } static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */ @@ -241,30 +234,45 @@ int intel_scu_ipc_simple_command(int cmd, int sub) } EXPORT_SYMBOL(intel_scu_ipc_simple_command); +void intel_scu_ipc_lock(void) +{ + mutex_lock(&ipclock); +} +EXPORT_SYMBOL_GPL(intel_scu_ipc_lock); + +void intel_scu_ipc_unlock(void) +{ + mutex_unlock(&ipclock); +} +EXPORT_SYMBOL_GPL(intel_scu_ipc_unlock); + /** - * intel_scu_ipc_command - command with data - * @cmd: command - * @sub: sub type - * @in: input data - * @inlen: input length in dwords - * @out: output data - * @outlein: output length in dwords + * intel_scu_ipc_raw_cmd - raw ipc command with data + * @cmd: command + * @sub: sub type + * @in: input data + * @inlen: input length in dwords + * @out: output data + * @outlen: output length in dwords + * @sptr: data writing to SPTR register + * @dptr: data writing to DPTR register * - * Issue a command to the SCU which involves data transfers. Do the - * data copies under the lock but leave it for the caller to interpret + * Issue a command to the SCU which involves data transfers. Do the + * data copies under the lock but leave it for the caller to interpret + * Note: This function should be called with the holding of ipclock */ - -int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, - u32 *out, int outlen) +int intel_scu_ipc_raw_cmd(u32 cmd, u32 sub, u32 *in, u32 inlen, u32 *out, + u32 outlen, u32 dptr, u32 sptr) { int i, err; - mutex_lock(&ipclock); if (ipcdev.pdev == NULL) { - mutex_unlock(&ipclock); return -ENODEV; } + writel(dptr, ipcdev.ipc_base + IPC_DPTR_ADDR); + writel(sptr, ipcdev.ipc_base + IPC_SPTR_ADDR); + for (i = 0; i < inlen; i++) ipc_data_writel(*in++, 4 * i); @@ -274,10 +282,20 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, for (i = 0; i < outlen; i++) *out++ = ipc_data_readl(4 * i); - mutex_unlock(&ipclock); return err; } -EXPORT_SYMBOL(intel_scu_ipc_command); +EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_cmd); + +int intel_scu_ipc_command(u32 cmd, u32 sub, u32 *in, u32 inlen, + u32 *out, u32 outlen) +{ + int ret; + mutex_lock(&ipclock); + ret = intel_scu_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0); + mutex_unlock(&ipclock); + return ret; +} +EXPORT_SYMBOL_GPL(intel_scu_ipc_command); /*I2C commands */ #define IPC_I2C_WRITE 1 /* I2C Write command */ @@ -1135,101 +1153,6 @@ out_unlock: } EXPORT_SYMBOL_GPL(intel_scu_ipc_medfw_upgrade); -static int read_mip(u8 *data, int len, int offset, int issigned) -{ - int ret; - u32 cmdid; - u32 data_off; - - if (platform != INTEL_MID_CPU_CHIP_PENWELL) - return -EINVAL; - - if (offset + len > IPC_MIP_MAX_ADDR) - return -EINVAL; - - if (ipcdev.mip_base == NULL) - return -ENODEV; - - do { - writel(offset, ipcdev.ipc_base + IPC_DPTR_ADDR); - writel((len + 3) / 4, ipcdev.ipc_base + IPC_SPTR_ADDR); - - cmdid = issigned ? IPC_CMD_SMIP_RD : IPC_CMD_UMIP_RD; - ipc_command(4 << 16 | cmdid << 12 | IPCMSG_MIP_ACCESS); - ret = ipc_wait_interrupt(); - } while (ret == -EIO); - if (!ret) { - data_off = ipc_data_readl(0); - memcpy(data, ipcdev.mip_base + data_off, len); - } - - return ret; -} - -int intel_scu_ipc_read_mip(u8 *data, int len, int offset, int issigned) -{ - int ret; - - mutex_lock(&ipclock); - if (ipcdev.pdev == NULL) { - mutex_unlock(&ipclock); - return -ENODEV; - } - ret = read_mip(data, len, offset, issigned); - mutex_unlock(&ipclock); - - return ret; -} -EXPORT_SYMBOL(intel_scu_ipc_read_mip); - -int intel_scu_ipc_write_umip(u8 *data, int len, int offset) -{ - int ret; - u8 *buf = NULL; - int offset_align, len_align = 0; - - if (platform != INTEL_MID_CPU_CHIP_PENWELL) - return -EINVAL; - if (offset + len > IPC_MIP_MAX_ADDR) - return -EINVAL; - - mutex_lock(&ipclock); - if (ipcdev.pdev == NULL || ipcdev.mip_base == NULL) { - ret = -ENODEV; - goto fail; - } - offset_align = offset & (~0x3); - len_align = (len + (offset - offset_align) + 3) & (~0x3); - if (len != len_align) { - buf = kzalloc(len_align, GFP_KERNEL); - if (!buf) { - dev_err(&ipcdev.pdev->dev, "Alloc memory failed\n"); - ret = -ENOMEM; - goto fail; - } - ret = read_mip(buf, len_align, offset_align, 0); - if (ret) - goto fail; - memcpy(buf + offset - offset_align, data, len); - } else { - buf = data; - } - do { - writel(offset_align, ipcdev.ipc_base + IPC_DPTR_ADDR); - writel(len_align / 4, ipcdev.ipc_base + IPC_SPTR_ADDR); - memcpy(ipcdev.mip_base, buf, len_align); - ipc_command(IPC_CMD_UMIP_WR << 12 | IPCMSG_MIP_ACCESS); - ret = ipc_wait_interrupt(); - } while (ret == -EIO); -fail: - if (buf && len_align != len) - kfree(buf); - mutex_unlock(&ipclock); - - return ret; -} -EXPORT_SYMBOL(intel_scu_ipc_write_umip); - #define MAX_BIN_BUF_SIZE (4*1024*1024) #define DNX_SIZE_OFFSET 0 #define GP_FLAG_OFFSET 4 @@ -1816,13 +1739,6 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENOMEM; } - ipcdev.mip_base = ioremap_nocache(IPC_MIP_BASE, IPC_MIP_MAX_ADDR); - if (!ipcdev.mip_base) { - iounmap(ipcdev.i2c_base); - iounmap(ipcdev.ipc_base); - return -ENOMEM; - } - intel_scu_devices_create(*bus_id); intel_scu_sysfs_create(dev); @@ -1851,7 +1767,6 @@ static void ipc_remove(struct pci_dev *pdev) pci_dev_put(ipcdev.pdev); iounmap(ipcdev.ipc_base); iounmap(ipcdev.i2c_base); - iounmap(ipcdev.mip_base); ipcdev.pdev = NULL; intel_scu_devices_destroy(*bus_id); kfree(bus_id); diff --git a/drivers/platform/x86/intel_scu_mip.c b/drivers/platform/x86/intel_scu_mip.c new file mode 100644 index 0000000..58aa881 --- /dev/null +++ b/drivers/platform/x86/intel_scu_mip.c @@ -0,0 +1,162 @@ +/* + * intel_scu_mip.c: Driver for the Intel scu mip and umip access + * + * (C) Copyright 2012 Intel Corporation + * Author: Shijie Zhang (shijie.zhang@intel.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define IPC_MIP_BASE 0xFFFD8000 /* sram base address for mip accessing*/ +#define IPC_MIP_MAX_ADDR 0x1000 + +static void __iomem *intel_mip_base; + +static int read_mip(u8 *data, int len, int offset, int issigned) +{ + int ret; + u32 sptr, dptr, cmd, cmdid, data_off; + int retry = 10000; + + if (!intel_mip_base) + return -ENODEV; + + if (offset + len > IPC_MIP_MAX_ADDR) + return -EINVAL; + + dptr = offset; + sptr = (len + 3) / 4; + + cmdid = issigned ? IPC_CMD_SMIP_RD : IPC_CMD_UMIP_RD; + cmd = 4 << 16 | cmdid << 12 | IPCMSG_MIP_ACCESS; + + do { + ret = intel_scu_ipc_raw_cmd(cmd, 0, NULL, 0, &data_off, 1, + dptr, sptr); + } while (ret == -EIO && --retry != 0); + + if (!ret) + memcpy(data, intel_mip_base + data_off, len); + + return ret; +} + +int intel_scu_ipc_read_mip(u8 *data, int len, int offset, int issigned) +{ + int ret; + + intel_scu_ipc_lock(); + ret = read_mip(data, len, offset, issigned); + intel_scu_ipc_unlock(); + + return ret; +} +EXPORT_SYMBOL(intel_scu_ipc_read_mip); + +int intel_scu_ipc_write_umip(u8 *data, int len, int offset) +{ + int ret, offset_align; + int retry = 10000, len_align = 0; + u32 dptr, sptr, cmd; + u8 *buf = NULL; + + if (!intel_mip_base) + return -ENODEV; + + if (offset + len > IPC_MIP_MAX_ADDR) + return -EINVAL; + + intel_scu_ipc_lock(); + + offset_align = offset & (~0x3); + len_align = (len + (offset - offset_align) + 3) & (~0x3); + + if (len != len_align) { + buf = kzalloc(len_align, GFP_KERNEL); + if (!buf) { + pr_err("Alloc memory failed\n"); + ret = -ENOMEM; + goto fail; + } + ret = read_mip(buf, len_align, offset_align, 0); + if (ret) + goto fail; + memcpy(buf + offset - offset_align, data, len); + } else { + buf = data; + } + + dptr = offset_align; + sptr = len_align / 4; + cmd = IPC_CMD_UMIP_WR << 12 | IPCMSG_MIP_ACCESS; + + do { + ret = intel_scu_ipc_raw_cmd(cmd, 0, NULL, 0, NULL, 0, + dptr, sptr); + } while (ret == -EIO && --retry != 0); + +fail: + if (buf && len_align != len) + kfree(buf); + + intel_scu_ipc_unlock(); + + return ret; +} +EXPORT_SYMBOL(intel_scu_ipc_write_umip); + +static int __devinit intel_mip_probe(struct ipc_device *ipcdev) +{ + intel_mip_base = ioremap_nocache(IPC_MIP_BASE, IPC_MIP_MAX_ADDR); + if (!intel_mip_base) + return -ENOMEM; + + return 0; +} + +static int __devexit intel_mip_remove(struct ipc_device *ipcdev) +{ + iounmap(intel_mip_base); + return 0; +} + +static struct ipc_driver mip_driver = { + .driver = { + .name = "intel_scu_mip", + .owner = THIS_MODULE, + }, + .probe = intel_mip_probe, + .remove = __devexit_p(intel_mip_remove), +}; + +static int __init mip_module_init(void) +{ + if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_PENWELL) + return -EINVAL; + + return ipc_driver_register(&mip_driver); +} + +static void __exit mip_module_exit(void) +{ + ipc_driver_unregister(&mip_driver); +} + +module_init(mip_module_init); +module_exit(mip_module_exit); + +MODULE_AUTHOR("Shijie Zhang "); +MODULE_AUTHOR("Sreedhara DS "); +MODULE_DESCRIPTION("Intel SCU MIP driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4