From d1cb33fced45f46855fb4496e5bbb4841c8f1f01 Mon Sep 17 00:00:00 2001 From: Shijie Zhang Date: Tue, 10 Apr 2012 22:19:34 +0800 Subject: [PATCH] intel_scu_mip: Add mip sysfs interface BZ: 30963 This patch adds sysfs interface for intel_scu_mip driver, which can be used for debugging and testing of mip read/write. Change-Id: Iae052d7773f5a056feaecaabc3cfff4e47a301a6 Signed-off-by: Shijie Zhang Reviewed-on: http://android.intel.com:8080/42863 Reviewed-by: Du, Alek Reviewed-by: Yang, Bin Tested-by: Wang, Zhifeng Reviewed-by: buildbot Tested-by: buildbot --- drivers/platform/x86/intel_scu_mip.c | 235 ++++++++++++++++++++++++++++++++++- 1 file changed, 233 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel_scu_mip.c b/drivers/platform/x86/intel_scu_mip.c index 336a3c9..d9dc9be 100644 --- a/drivers/platform/x86/intel_scu_mip.c +++ b/drivers/platform/x86/intel_scu_mip.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define IPC_MIP_BASE 0xFFFD8000 /* sram base address for mip accessing*/ @@ -116,18 +117,249 @@ fail: } EXPORT_SYMBOL(intel_scu_ipc_write_umip); + +#define MAX_DATA_NR 8 +#define MIP_CMD_LEN 11 + +enum { + MIP_DBG_DATA, + MIP_DBG_LEN, + MIP_DBG_OFFSET, + MIP_DBG_ISSIGNED, + MIP_DBG_ERROR, +}; + +static u8 mip_data[MAX_DATA_NR]; +static int valid_data_nr; +static int mip_len; +static int mip_offset; +static int mip_issigned; +static int mip_dbg_error; +static char mip_cmd[MIP_CMD_LEN]; + +static char *mip_msg_format[] = { + "data[%d]: %#x\n", + "len: %d\n", + "offset: %#x\n", + "issigned: %d\n", + "error: %d\n", +}; + +static int mip_generic_show(char *buf, int type, int *data) +{ + int i, buf_size; + int ret = 0; + + switch (type) { + case MIP_DBG_DATA: + for (i = 0; i < valid_data_nr; i++) { + buf_size = PAGE_SIZE - ret; + ret += snprintf(buf + ret, buf_size, + mip_msg_format[type], + i, mip_data[i]); + } + break; + case MIP_DBG_LEN: + case MIP_DBG_OFFSET: + case MIP_DBG_ISSIGNED: + case MIP_DBG_ERROR: + ret = snprintf(buf, PAGE_SIZE, mip_msg_format[type], *data); + break; + default: + break; + } + + return ret; +} + +static void mip_generic_store(const char *buf, int type, int *data) +{ + int i, ret; + + if (type == MIP_DBG_DATA) { + u32 t[MAX_DATA_NR]; + + valid_data_nr = 0; + memset(mip_data, 0, sizeof(mip_data)); + + ret = sscanf(buf, "%x %x %x %x %x %x %x %x", &t[0], &t[1], + &t[2], &t[3], &t[4], &t[5], &t[6], &t[7]); + if (ret == 0 || ret > MAX_DATA_NR) { + mip_dbg_error = -EINVAL; + return; + } else { + for (i = 0; i < ret; i++) + mip_data[i] = (u8)t[i]; + valid_data_nr = ret; + } + } else { + *data = 0; + switch (type) { + case MIP_DBG_OFFSET: + ret = sscanf(buf, "%x", data); + break; + case MIP_DBG_LEN: + case MIP_DBG_ISSIGNED: + ret = sscanf(buf, "%d", data); + break; + default: + ret = -1; + break; + } + } + + if (ret) + mip_dbg_error = 0; + else + mip_dbg_error = -EINVAL; + + return; +} + +static ssize_t mip_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mip_generic_show(buf, MIP_DBG_DATA, NULL); +} + +static ssize_t mip_data_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + mip_generic_store(buf, MIP_DBG_DATA, NULL); + return size; +} + +static ssize_t mip_len_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mip_generic_show(buf, MIP_DBG_LEN, &mip_len); +} + +static ssize_t mip_len_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + mip_generic_store(buf, MIP_DBG_LEN, &mip_len); + return size; +} + +static ssize_t mip_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mip_generic_show(buf, MIP_DBG_OFFSET, &mip_offset); +} + +static ssize_t mip_offset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + mip_generic_store(buf, MIP_DBG_OFFSET, &mip_offset); + return size; +} + +static ssize_t mip_issigned_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mip_generic_show(buf, MIP_DBG_ISSIGNED, &mip_issigned); +} + +static ssize_t mip_issigned_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + mip_generic_store(buf, MIP_DBG_ISSIGNED, &mip_issigned); + return size; +} + +static ssize_t mip_error_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mip_generic_show(buf, MIP_DBG_ERROR, &mip_dbg_error); +} + +static ssize_t mip_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + + int ret; + + memset(mip_cmd, 0, sizeof(mip_cmd)); + + ret = sscanf(buf, "%10s", mip_cmd); + if (ret == 0) { + mip_dbg_error = -EINVAL; + goto end; + } + + if (!strncmp("read_mip", mip_cmd, MIP_CMD_LEN)) { + memset(mip_data, 0, sizeof(mip_data)); + ret = intel_scu_ipc_read_mip(mip_data, mip_len, mip_offset, + mip_issigned); + if (!ret) + valid_data_nr = mip_len; + + } else if (!strncmp("write_umip", mip_cmd, MIP_CMD_LEN)) { + if (mip_len == valid_data_nr) { + ret = intel_scu_ipc_write_umip(mip_data, mip_len, + mip_offset); + } else + goto error; + } else + goto error; + + if (ret) + goto error; + else + goto end; + +error: + mip_dbg_error = -EINVAL; + +end: + return size; +} + +static DEVICE_ATTR(data, S_IRUGO|S_IWUSR, mip_data_show, mip_data_store); +static DEVICE_ATTR(len, S_IRUGO|S_IWUSR, mip_len_show, mip_len_store); +static DEVICE_ATTR(offset, S_IRUGO|S_IWUSR, mip_offset_show, mip_offset_store); +static DEVICE_ATTR(issigned, S_IRUGO|S_IWUSR, mip_issigned_show, + mip_issigned_store); +static DEVICE_ATTR(cmd, S_IWUSR, NULL, mip_cmd_store); +static DEVICE_ATTR(error, S_IRUGO, mip_error_show, NULL); + +static struct attribute *mip_attrs[] = { + &dev_attr_data.attr, + &dev_attr_len.attr, + &dev_attr_offset.attr, + &dev_attr_issigned.attr, + &dev_attr_cmd.attr, + &dev_attr_error.attr, + NULL, +}; + +static struct attribute_group mip_attr_group = { + .name = "mip_debug", + .attrs = mip_attrs, +}; + static int __devinit intel_mip_probe(struct ipc_device *ipcdev) { + int ret; + intel_mip_base = ioremap_nocache(IPC_MIP_BASE, IPC_MIP_MAX_ADDR); if (!intel_mip_base) return -ENOMEM; - return 0; + ret = sysfs_create_group(&ipcdev->dev.kobj, &mip_attr_group); + if (ret) { + dev_err(&ipcdev->dev, "Failed to create mip sysfs interface\n"); + iounmap(intel_mip_base); + } + + return ret; } static int __devexit intel_mip_remove(struct ipc_device *ipcdev) { iounmap(intel_mip_base); + sysfs_remove_group(&ipcdev->dev.kobj, &mip_attr_group); return 0; } @@ -157,6 +389,5 @@ 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