#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ipc_device.h>
+#include <linux/fs.h>
#include <asm/intel_scu_ipc.h>
#define IPC_MIP_BASE 0xFFFD8000 /* sram base address for mip accessing*/
}
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;
}
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");