intel_scu_mip: update intel mip driver
authorShijie Zhang <shijie.zhang@intel.com>
Wed, 28 Mar 2012 22:39:51 +0000 (06:39 +0800)
committerbuildbot <buildbot@intel.com>
Sun, 1 Apr 2012 10:24:05 +0000 (03:24 -0700)
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 <shijie.zhang@intel.com>
Reviewed-on: http://android.intel.com:8080/41379
Reviewed-by: Du, Alek <alek.du@intel.com>
Tested-by: Wang, Zhifeng <zhifeng.wang@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
arch/x86/include/asm/intel_scu_ipc.h
arch/x86/platform/intel-mid/intel-mid.c
drivers/platform/x86/Makefile
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/intel_scu_mip.c [new file with mode: 0644]

index de1bf0a..abdde5d 100644 (file)
 #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);
 
index 4d36817..04b623a 100644 (file)
@@ -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,
index 23f37dc..d942eef 100644 (file)
@@ -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
index 3f2e9b3..195a82a 100644 (file)
 #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 (file)
index 0000000..58aa881
--- /dev/null
@@ -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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/ipc_device.h>
+#include <asm/intel_scu_ipc.h>
+
+#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 <shijie.zhang@intel.com>");
+MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>");
+MODULE_DESCRIPTION("Intel SCU MIP driver");
+MODULE_LICENSE("GPL v2");