[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/devtools/met-driver/4.9/common/sspm/ondiemet_sspm.c b/src/devtools/met-driver/4.9/common/sspm/ondiemet_sspm.c
new file mode 100644
index 0000000..8c5711b
--- /dev/null
+++ b/src/devtools/met-driver/4.9/common/sspm/ondiemet_sspm.c
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/delay.h>
+#include <linux/module.h> /* symbol_get */
+
+#define MET_USER_EVENT_SUPPORT
+#include "met_drv.h"
+
+#if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(ONDIEMET_SUPPORT)
+#include "ondiemet_sspm.h"
+
+#if defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) || defined(CONFIG_MTK_MET_MEM_ALLOC)
+#ifdef CONFIG_MET_ARM_32BIT
+#include <asm/dma-mapping.h> /* arm_coherent_dma_ops */
+#else /* CONFIG_MET_ARM_32BIT */
+#include <linux/dma-mapping.h>
+#endif /* CONFIG_MET_ARM_32BIT */
+#else /* CONFIG_MTK_GMO_RAM_OPTIMIZE */
+#include "sspm_reservedmem.h"
+#include "sspm_reservedmem_define.h"
+#endif /* CONFIG_MTK_GMO_RAM_OPTIMIZE */
+
+dma_addr_t ondiemet_sspm_log_phy_addr;
+void *ondiemet_sspm_log_virt_addr;
+uint32_t ondiemet_sspm_log_size = 0x400000;
+
+/* SSPM_LOG_FILE 0 */
+/* SSPM_LOG_SRAM 1 */
+/* SSPM_LOG_DRAM 2 */
+int sspm_log_mode;
+/* SSPM_RUN_NORMAL mode 0 */
+/* SSPM_RUN_CONTINUOUS mode 1 */
+int sspm_run_mode;
+int met_sspm_log_discard = -1;
+int sspm_log_size = 500;
+
+int sspm_buffer_size;
+int sspm_buf_available;
+EXPORT_SYMBOL(sspm_buf_available);
+int sspm_buf_mapped = -1; /* get buffer by MET itself */
+
+static ssize_t sspm_buffer_size_show(struct device *dev, struct device_attribute *attr, char *buf);
+static DEVICE_ATTR(sspm_buffer_size, 0444, sspm_buffer_size_show, NULL);
+
+static ssize_t sspm_available_show(struct device *dev, struct device_attribute *attr, char *buf);
+static DEVICE_ATTR(sspm_available, 0444, sspm_available_show, NULL);
+
+static ssize_t sspm_log_discard_show(struct device *dev, struct device_attribute *attr, char *buf);
+static DEVICE_ATTR(sspm_log_discard, 0444, sspm_log_discard_show, NULL);
+
+static ssize_t sspm_log_mode_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t sspm_log_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static DEVICE_ATTR(sspm_log_mode, 0664, sspm_log_mode_show, sspm_log_mode_store);
+
+static ssize_t sspm_log_size_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t sspm_log_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static DEVICE_ATTR(sspm_log_size, 0664, sspm_log_size_show, sspm_log_size_store);
+
+
+static ssize_t sspm_run_mode_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t sspm_run_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static DEVICE_ATTR(sspm_run_mode, 0664, sspm_run_mode_show, sspm_run_mode_store);
+
+static ssize_t sspm_modules_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t sspm_modules_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static DEVICE_ATTR(sspm_modules, 0664, sspm_modules_show, sspm_modules_store);
+
+static ssize_t sspm_op_ctrl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static DEVICE_ATTR(sspm_op_ctrl, 0220, NULL, sspm_op_ctrl_store);
+
+static ssize_t sspm_buffer_size_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i;
+
+	mutex_lock(&dev->mutex);
+	i = snprintf(buf, PAGE_SIZE, "%d\n", sspm_buffer_size);
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+static ssize_t sspm_available_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i;
+
+	mutex_lock(&dev->mutex);
+	i = snprintf(buf, PAGE_SIZE, "%d\n", 1);
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+static ssize_t sspm_log_discard_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i;
+
+	mutex_lock(&dev->mutex);
+	i = snprintf(buf, PAGE_SIZE, "%d\n", met_sspm_log_discard);
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+static ssize_t sspm_log_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i;
+
+	mutex_lock(&dev->mutex);
+	i = snprintf(buf, PAGE_SIZE, "%d\n", sspm_log_mode);
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+static ssize_t sspm_log_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int value;
+
+	if (kstrtoint(buf, 0, &value) != 0)
+		return -EINVAL;
+	mutex_lock(&dev->mutex);
+	sspm_log_mode = value;
+	mutex_unlock(&dev->mutex);
+	return count;
+}
+
+
+static ssize_t sspm_log_size_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i;
+
+	mutex_lock(&dev->mutex);
+	i = snprintf(buf, PAGE_SIZE, "%d\n", sspm_log_size);
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+static ssize_t sspm_log_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int value;
+
+	if (kstrtoint(buf, 0, &value) != 0)
+		return -EINVAL;
+	mutex_lock(&dev->mutex);
+	sspm_log_size = value;
+	mutex_unlock(&dev->mutex);
+	return count;
+}
+
+
+static ssize_t sspm_run_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i;
+
+	mutex_lock(&dev->mutex);
+	i = snprintf(buf, PAGE_SIZE, "%d\n", sspm_run_mode);
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+static ssize_t sspm_run_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int value;
+
+	if (kstrtoint(buf, 0, &value) != 0)
+		return -EINVAL;
+	mutex_lock(&dev->mutex);
+	sspm_run_mode = value;
+	mutex_unlock(&dev->mutex);
+	return count;
+}
+
+static ssize_t sspm_op_ctrl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int value;
+
+	if (kstrtoint(buf, 0, &value) != 0)
+		return -EINVAL;
+	mutex_lock(&dev->mutex);
+	if (value == 1)
+		sspm_start();
+	else if (value == 2)
+		sspm_stop();
+	else if (value == 3)
+		sspm_extract();
+	else if (value == 4)
+		sspm_flush();
+	mutex_unlock(&dev->mutex);
+	return count;
+}
+
+static ssize_t sspm_modules_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i;
+
+	mutex_lock(&dev->mutex);
+	i = snprintf(buf, PAGE_SIZE, "%x\n", ondiemet_module[ONDIEMET_SSPM]);
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+static ssize_t sspm_modules_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	uint32_t value;
+
+	if (kstrtouint(buf, 0, &value) != 0)
+		return -EINVAL;
+	mutex_lock(&dev->mutex);
+	ondiemet_module[ONDIEMET_SSPM] = value;
+	mutex_unlock(&dev->mutex);
+	return count;
+}
+
+int sspm_attr_init(struct device *dev)
+{
+	int ret;
+
+#if defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) || defined(CONFIG_MTK_MET_MEM_ALLOC)
+#ifdef CONFIG_MET_ARM_32BIT
+	struct dma_map_ops *ops = (struct dma_map_ops *)symbol_get(arm_coherent_dma_ops);
+
+	if (ops && ops->alloc) {
+		dev->coherent_dma_mask = DMA_BIT_MASK(32);
+		ondiemet_sspm_log_virt_addr = ops->alloc(dev,
+						ondiemet_sspm_log_size,
+						&ondiemet_sspm_log_phy_addr,
+						GFP_KERNEL,
+						0);
+	}
+#else /* CONFIG_MET_ARM_32BIT */
+	/* dma_alloc */
+	ondiemet_sspm_log_virt_addr = dma_alloc_coherent(dev,
+			ondiemet_sspm_log_size,
+			&ondiemet_sspm_log_phy_addr,
+			GFP_KERNEL);
+#endif /* CONFIG_MET_ARM_32BIT */
+#else /* CONFIG_MTK_GMO_RAM_OPTIMIZE */
+
+	phys_addr_t (*sspm_reserve_mem_get_phys_sym)(unsigned int id) = NULL;
+	phys_addr_t (*sspm_reserve_mem_get_virt_sym)(unsigned int id) = NULL;
+	phys_addr_t (*sspm_reserve_mem_get_size_sym)(unsigned int id) = NULL;
+
+	sspm_reserve_mem_get_phys_sym = (phys_addr_t (*)(unsigned int id))symbol_get(sspm_reserve_mem_get_virt);
+	sspm_reserve_mem_get_virt_sym = (phys_addr_t (*)(unsigned int id))symbol_get(sspm_reserve_mem_get_phys);
+	sspm_reserve_mem_get_size_sym = (phys_addr_t (*)(unsigned int id))symbol_get(sspm_reserve_mem_get_size);
+	if (sspm_reserve_mem_get_phys_sym)
+		ondiemet_sspm_log_virt_addr = (void*)sspm_reserve_mem_get_virt(MET_MEM_ID);
+	if (sspm_reserve_mem_get_virt_sym)
+		ondiemet_sspm_log_phy_addr = sspm_reserve_mem_get_phys(MET_MEM_ID);
+	if (sspm_reserve_mem_get_size_sym)
+		ondiemet_sspm_log_size = sspm_reserve_mem_get_size(MET_MEM_ID);
+#endif /* CONFIG_MTK_GMO_RAM_OPTIMIZE */
+
+	ret = device_create_file(dev, &dev_attr_sspm_buffer_size);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_buffer_size\n");
+		return ret;
+	}
+
+	ret = device_create_file(dev, &dev_attr_sspm_available);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_available\n");
+		return ret;
+	}
+
+	ret = device_create_file(dev, &dev_attr_sspm_log_discard);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_log_discard\n");
+		return ret;
+	}
+	ret = device_create_file(dev, &dev_attr_sspm_log_mode);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_log_mode\n");
+		return ret;
+	}
+	ret = device_create_file(dev, &dev_attr_sspm_log_size);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_log_size\n");
+		return ret;
+	}
+	ret = device_create_file(dev, &dev_attr_sspm_run_mode);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_run_mode\n");
+		return ret;
+	}
+	ret = device_create_file(dev, &dev_attr_sspm_op_ctrl);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_op_ctrl\n");
+		return ret;
+	}
+	ret = device_create_file(dev, &dev_attr_sspm_modules);
+	if (ret != 0) {
+		pr_debug("can not create device file: sspm_modules\n");
+		return ret;
+	}
+
+	if (ondiemet_sspm_log_virt_addr != NULL) {
+		start_sspm_ipi_recv_thread();
+		sspm_buf_available = 1;
+		sspm_buffer_size = ondiemet_sspm_log_size;
+	} else {
+		sspm_buf_available = 0;
+		sspm_buffer_size = -1;
+	}
+
+	return 0;
+}
+
+int sspm_attr_uninit(struct device *dev)
+{
+	/* dma_free */
+	if (ondiemet_sspm_log_virt_addr != NULL) {
+#if defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) || defined(CONFIG_MTK_MET_MEM_ALLOC)
+#ifdef CONFIG_MET_ARM_32BIT
+		struct dma_map_ops *ops = (struct dma_map_ops *)symbol_get(arm_coherent_dma_ops);
+
+		if (ops && ops->free) {
+			ops->free(dev,
+				ondiemet_sspm_log_size,
+				ondiemet_sspm_log_virt_addr,
+				ondiemet_sspm_log_phy_addr,
+				0);
+		}
+#else /* CONFIG_MET_ARM_32BIT */
+		dma_free_coherent(dev,
+			ondiemet_sspm_log_size,
+			ondiemet_sspm_log_virt_addr,
+			ondiemet_sspm_log_phy_addr);
+#endif /* CONFIG_MET_ARM_32BIT */
+#endif /* CONFIG_MTK_GMO_RAM_OPTIMIZE */
+		ondiemet_sspm_log_virt_addr = NULL;
+		stop_sspm_ipi_recv_thread();
+	}
+
+	device_remove_file(dev, &dev_attr_sspm_buffer_size);
+	device_remove_file(dev, &dev_attr_sspm_available);
+	device_remove_file(dev, &dev_attr_sspm_log_discard);
+	device_remove_file(dev, &dev_attr_sspm_log_mode);
+	device_remove_file(dev, &dev_attr_sspm_log_size);
+	device_remove_file(dev, &dev_attr_sspm_run_mode);
+	device_remove_file(dev, &dev_attr_sspm_op_ctrl);
+	device_remove_file(dev, &dev_attr_sspm_modules);
+
+	return 0;
+}
+
+#if 0 /* move to sspm_attr_init() */
+void sspm_get_buffer_info(void)
+{
+	if (ondiemet_sspm_log_virt_addr != NULL) {
+		sspm_buf_available = 1;
+		sspm_buffer_size = ondiemet_sspm_log_size;
+	} else {
+		sspm_buf_available = 0;
+		sspm_buffer_size = -1;
+	}
+}
+#endif
+
+extern const char *met_get_platform_name(void);
+void sspm_start(void)
+{
+	int32_t ret = 0;
+	uint32_t rdata;
+	uint32_t ipi_buf[4];
+	const char* platform_name = NULL;
+	unsigned int platform_id = 0;
+	met_sspm_log_discard = -1;
+
+	/* clear DRAM buffer */
+	if (ondiemet_sspm_log_virt_addr != NULL)
+		memset_io((void *)ondiemet_sspm_log_virt_addr, 0, ondiemet_sspm_log_size);
+	else
+		return;
+
+	platform_name = met_get_platform_name();
+	if (platform_name) {
+		char buf[5];
+
+		memset(buf, 0x0, 5);
+		memcpy(buf, &platform_name[2], 4);
+		ret = kstrtouint(buf, 10, &platform_id);
+	}
+
+	/* send DRAM physical address */
+	ipi_buf[0] = MET_MAIN_ID | MET_BUFFER_INFO;
+	ipi_buf[1] = (unsigned int)ondiemet_sspm_log_phy_addr; /* address */
+	if (ret == 0)
+		ipi_buf[2] = platform_id;
+	else
+		ipi_buf[2] = 0;
+	ipi_buf[3] = 0;
+	ret = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);
+
+	/* start ondiemet now */
+	ipi_buf[0] = MET_MAIN_ID | MET_OP | MET_OP_START;
+	ipi_buf[1] = ondiemet_module[ONDIEMET_SSPM];
+	ipi_buf[2] = sspm_log_mode;
+	ipi_buf[3] = sspm_run_mode;
+	ret = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);
+}
+
+void sspm_stop(void)
+{
+	int32_t ret;
+	uint32_t rdata;
+	uint32_t ipi_buf[4];
+
+	if (sspm_buf_available == 1) {
+		ipi_buf[0] = MET_MAIN_ID|MET_OP|MET_OP_STOP;
+		ipi_buf[1] = 0;
+		ipi_buf[2] = 0;
+		ipi_buf[3] = 0;
+		ret = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);
+	}
+}
+
+void sspm_extract(void)
+{
+	int32_t ret;
+	uint32_t rdata;
+	uint32_t ipi_buf[4];
+	int32_t count;
+
+	count = 20;
+	if (sspm_buf_available == 1) {
+		while ((sspm_buffer_dumping == 1) && (count != 0)) {
+			msleep(50);
+			count--;
+		}
+		ipi_buf[0] = MET_MAIN_ID|MET_OP|MET_OP_EXTRACT;
+		ipi_buf[1] = 0;
+		ipi_buf[2] = 0;
+		ipi_buf[3] = 0;
+		ret = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);
+	}
+
+	if (sspm_run_mode == SSPM_RUN_NORMAL)
+		ondiemet_module[ONDIEMET_SSPM] = 0;
+}
+
+void sspm_flush(void)
+{
+	int32_t ret;
+	uint32_t rdata;
+	uint32_t ipi_buf[4];
+
+	if (sspm_buf_available == 1) {
+		ipi_buf[0] = MET_MAIN_ID|MET_OP|MET_OP_FLUSH;
+		ipi_buf[1] = 0;
+		ipi_buf[2] = 0;
+		ipi_buf[3] = 0;
+		ret = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);
+	}
+
+	if (sspm_run_mode == SSPM_RUN_NORMAL)
+		ondiemet_module[ONDIEMET_SSPM] = 0;
+}
+#else /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && ONDIEMET_SUPPORT */
+int sspm_buffer_size = -1;
+
+int sspm_attr_init(struct device *dev)
+{
+	return 0;
+}
+
+int sspm_attr_uninit(struct device *dev)
+{
+	return 0;
+}
+
+void sspm_start(void)
+{
+}
+
+void sspm_stop(void)
+{
+}
+
+void sspm_extract(void)
+{
+}
+
+void sspm_flush(void)
+{
+}
+
+#endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && ONDIEMET_SUPPORT */
diff --git a/src/devtools/met-driver/4.9/common/sspm/ondiemet_sspm.h b/src/devtools/met-driver/4.9/common/sspm/ondiemet_sspm.h
new file mode 100644
index 0000000..d1baadd
--- /dev/null
+++ b/src/devtools/met-driver/4.9/common/sspm/ondiemet_sspm.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ONDIEMET_SSPM_H
+#define __ONDIEMET_SSPM_H
+
+#if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(ONDIEMET_SUPPORT)
+#include "ondiemet.h"
+#include "sspm_ipi.h"
+#include <linux/dma-mapping.h>
+
+/* we may use IPI_ID_PLATFORM for mt6759 to reduce SRAM */
+#ifndef IPI_ID_MET
+/* #define IPI_ID_MET IPI_ID_TST1 */
+#define IPI_ID_MET IPI_ID_PLATFORM
+#endif
+
+/* MET IPI command definition: mbox 0 */
+/* main func ID: bit[31-24]; sub func ID: bit[23-18]; argu 0: bit[17-0] */
+#define MET_MAIN_ID_MASK        0xff000000 /* bit 31 - 24 */
+#define MET_SUB_ID_MASK         0x00fc0000 /* bit 23 - 18 */
+#define MET_ARGU0_MASK          0x0003ffff /* bit 17 - 0 */
+#define FUNC_BIT_SHIFT          18
+#define MID_BIT_SHIFT           9
+#define MET_MAIN_ID             0x06000000
+/* handle argument and attribute */
+#define PROCESS_ARGU            0x01
+#define PROCESS_ATTR            0x02
+#define MODULE_ID_MASK          0x3fe00 /* bit 9 - 17 */
+#define ARGUMENT_MASK           0x01ff  /* bit 0 - 8 */
+
+/* the following command is used for AP to MD32 */
+#define MET_OP            (1 << FUNC_BIT_SHIFT)
+/* argu 0: start: 0x01; stop: 0x02; extract: 0x03 */
+#define MET_OP_START        0x00000001
+#define MET_OP_STOP         0x00000002
+#define MET_OP_EXTRACT      0x00000003
+#define MET_OP_FLUSH        0x00000004
+#define MET_SR            (2 << FUNC_BIT_SHIFT) /* sample rate */
+#define MET_MODULE        (3 << FUNC_BIT_SHIFT) /* module enable/disable */
+#define MET_ARGU          (4 << FUNC_BIT_SHIFT) /* argument passing */
+#define MET_ATTR          (5 << FUNC_BIT_SHIFT) /* attribute passing */
+/* system memory information for on-die-met log data */
+#define MET_BUFFER_INFO   (6 << FUNC_BIT_SHIFT)
+#define MET_TIMESTAMP     (7 << FUNC_BIT_SHIFT) /* timestamp info */
+#define MET_GPT           (8 << FUNC_BIT_SHIFT) /* GPT counter reading */
+#define MET_REQ_AP2MD     (9 << FUNC_BIT_SHIFT) /* user defined command */
+#define MET_RESP_AP2MD    (10 << FUNC_BIT_SHIFT) /* may no need */
+/* mode: bit 15 - 0: */
+/*  Bit 0: MD32 SRAM mode; Bit 1: System DRAM mode */
+/*  value: 0: output to next level of storage; 1: loop in its own storage */
+#define MET_DATA_MODE     (11 << FUNC_BIT_SHIFT) /* log output mode */
+/* start/stop read data into MD32 SRAM buffer; both DMA and met_printf() */
+#define MET_DATA_OP       (12 << FUNC_BIT_SHIFT) /* data read operation */
+/* the following command is used for MD32 to AP */
+#define MET_DUMP_BUFFER   (13 << FUNC_BIT_SHIFT)
+#define MET_REQ_MD2AP     (14 << FUNC_BIT_SHIFT) /* user defined command */
+#define MET_CLOSE_FILE    (15 << FUNC_BIT_SHIFT) /* Inform to close the SD file */
+#define MET_RESP_MD2AP    (16 << FUNC_BIT_SHIFT)
+#define MET_RUN_MODE      (17 << FUNC_BIT_SHIFT)
+
+/* Note: the module ID and its bit pattern should be fixed as below */
+/* DMA based module first */
+enum {
+	MID_PMQOS = 0,
+	MID_VCORE_DVFS,
+	MID_EMI,
+	MID_THERMAL_CPU,
+	MID_WALL_TIME,
+	MID_CPU_DVFS,
+	MID_GPU_DVFS,
+	MID_PTPOD,
+	MID_SPM,
+	MID_PROFILE,
+	MID_MET_TAG,
+	MID_TS,
+	MID_TS_ISR,
+	MID_TS_LAST,
+	MID_TS_ISR_LAST,
+	MID_SRAM_INFO,
+	MID_MET_STOP,
+	MID_IOP_MON,
+	MID_CPU_INFO_MAPPING,
+
+	MID_COMMON = 0x1F
+};
+
+#define ID_PMQOS       (1 << MID_PMQOS)
+#define ID_SMI         (1 << MID_SMI)
+#define ID_EMI         (1 << MID_EMI)
+#define ID_THERMAL_CPU (1 << MID_THERMAL_CPU)
+#define ID_WALL_TIME   (1 << MID_WALL_TIME)
+#define ID_CPU_DVFS    (1 << MID_CPU_DVFS)
+#define ID_GPU_DVFS    (1 << MID_GPU_DVFS)
+#define ID_VCORE_DVFS  (1 << MID_VCORE_DVFS)
+#define ID_PTPOD       (1 << MID_PTPOD)
+#define ID_SPM         (1 << MID_SPM)
+#define ID_PROFILE     (1 << MID_PROFILE)
+#define ID_COMMON      (1 << MID_COMMON)
+#define ID_CPU_INFO_MAPPING      (1 << MID_CPU_INFO_MAPPING)
+
+extern void ondiemet_extract(void);
+extern void ondiemet_stop(void);
+extern void ondiemet_start(void);
+
+extern void start_sspm_ipi_recv_thread(void);
+extern void stop_sspm_ipi_recv_thread(void);
+
+extern unsigned int ondiemet_ipi_buf[];
+
+/* extern phys_addr_t ondiemet_sspm_log_phy_addr, ondiemet_sspm_log_virt_addr; */
+extern dma_addr_t ondiemet_sspm_log_phy_addr;
+
+extern void *ondiemet_sspm_log_virt_addr;
+extern uint32_t ondiemet_sspm_log_size;
+
+extern int ondiemet_attr_init(struct device *dev);
+extern int ondiemet_attr_uninit(struct device *dev);
+extern int met_sspm_log_discard;
+
+#define SSPM_LOG_FILE 0
+#define SSPM_LOG_SRAM 1
+#define SSPM_LOG_DRAM 2
+extern int sspm_log_mode;
+#define SSPM_RUN_NORMAL 0
+#define SSPM_RUN_CONTINUOUS 1
+extern int sspm_run_mode;
+
+/* extern void sspm_get_buffer_info(void); */
+extern int sspm_buf_available;
+extern int sspm_buffer_dumping;
+
+void sspm_flush(void);
+
+#endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && ONDIEMET_SUPPORT */
+#endif /* __ONDIEMET_SSPM_H */
diff --git a/src/devtools/met-driver/4.9/common/sspm/sspm_common.c b/src/devtools/met-driver/4.9/common/sspm/sspm_common.c
new file mode 100644
index 0000000..b3e1066
--- /dev/null
+++ b/src/devtools/met-driver/4.9/common/sspm/sspm_common.c
@@ -0,0 +1,266 @@
+#include <linux/string.h>

+#include <linux/slab.h>

+#include <linux/kernel.h>

+

+#include "met_drv.h"

+#include "ondiemet_sspm.h"

+

+

+struct sspm_met_evnet_header {

+	unsigned int rts_event_id;

+	char *rts_event_name;

+	char *chart_line_name;

+	char *key_list;

+};

+

+

+enum {

+	#ifdef MET_SSPM_RTS_EVNET

+	#undef MET_SSPM_RTS_EVNET

+	#endif

+	#define MET_SSPM_RTS_EVNET(rts_event_id, key_list) rts_event_id,

+	#include "met_sspm_rts_event.h"

+

+	/**********************/

+	CUR_MET_RTS_EVENT_NUM,

+	MAX_MET_RTS_EVENT_NUM = 128

+};

+

+

+struct sspm_met_evnet_header met_evnet_header[MAX_MET_RTS_EVENT_NUM] = {

+	#ifdef MET_SSPM_RTS_EVNET

+	#undef MET_SSPM_RTS_EVNET

+	#endif

+	#define MET_SSPM_RTS_EVNET(rts_event_id, key_list) {rts_event_id, #rts_event_id, #rts_event_id, key_list},

+	#include "met_sspm_rts_event.h"

+};

+

+

+static void ondiemet_sspm_start(void);

+static void ondiemet_sspm_stop(void);

+static int ondiemet_sspm_print_help(char *buf, int len);

+static int ondiemet_sspm_process_argument(const char *arg, int len);

+static int ondiemet_sspm_print_header(char *buf, int len);

+

+

+static unsigned int event_id_flag0;

+static unsigned int event_id_flag1;

+static unsigned int event_id_flag2;

+static unsigned int event_id_flag3;

+static char *update_rts_event_tbl[MAX_MET_RTS_EVENT_NUM];

+static char sspm_help[] = "  --sspm_common=rts_event_name\n";

+static char header[] = 	"met-info [000] 0.0: sspm_common_header: ";

+

+struct metdevice met_sspm_common = {

+	.name = "sspm_common",

+	.owner = THIS_MODULE,

+	.type = MET_TYPE_BUS,

+	.cpu_related = 0,

+	.ondiemet_mode = 1,

+	.ondiemet_start = ondiemet_sspm_start,

+	.ondiemet_stop = ondiemet_sspm_stop,

+	.ondiemet_process_argument = ondiemet_sspm_process_argument,

+	.ondiemet_print_help = ondiemet_sspm_print_help,

+	.ondiemet_print_header = ondiemet_sspm_print_header,

+};

+

+

+static int ondiemet_sspm_print_help(char *buf, int len)

+{

+	return snprintf(buf, PAGE_SIZE, sspm_help);

+}

+

+

+static int ondiemet_sspm_print_header(char *buf, int len)

+{

+	int i;

+	int write_len;

+	int flag = 0;

+	static int is_dump_header = 0;

+	static int read_idx = 0;

+

+	len = 0;

+	met_sspm_common.header_read_again = 0;

+	if (is_dump_header == 0) {

+		len = snprintf(buf, PAGE_SIZE, "%s", header);

+		is_dump_header = 1;

+	}

+

+	for (i=read_idx; i<MAX_MET_RTS_EVENT_NUM; i++) {

+		if (met_evnet_header[i].chart_line_name) {

+			if (i <32) {

+				flag = 1<<i;

+				flag = event_id_flag0 & flag;

+			} else if (i >=32 && i < 64) {

+				flag = 1<<(i-32);

+				flag = event_id_flag1 & flag;

+			} else if (i >=64 && i < 96) {

+				flag = 1<<(i-64);

+				flag = event_id_flag2 & flag;

+			} else if (i >=96 && i < 128) {

+				flag = 1<<(i-96);

+				flag = event_id_flag3 & flag;

+			}

+			if (flag == 0)

+				continue;

+

+			write_len = strlen(met_evnet_header[i].chart_line_name) + strlen(met_evnet_header[i].key_list) + 3;

+			if ((len+write_len) < PAGE_SIZE) {

+				len += snprintf(buf+len, PAGE_SIZE-len, "%u,%s,%s;",

+					met_evnet_header[i].rts_event_id,

+					met_evnet_header[i].chart_line_name,

+					met_evnet_header[i].key_list);

+			} else {

+				met_sspm_common.header_read_again = 1;

+				read_idx = i;

+				return len;

+			}

+		}

+	}

+

+	if (i == MAX_MET_RTS_EVENT_NUM) {

+		is_dump_header = 0;

+		read_idx = 0;

+		buf[len-1] = '\n';

+		for (i=0; i<MAX_MET_RTS_EVENT_NUM; i++) {

+			if (update_rts_event_tbl[i]) {

+				kfree(update_rts_event_tbl[i]);

+				update_rts_event_tbl[i] = NULL;

+			}

+		}

+		met_sspm_common.mode = 0;

+		event_id_flag0 = 0;

+		event_id_flag1 = 0;

+		event_id_flag2 = 0;

+		event_id_flag3 = 0;

+	}

+

+	return len;

+}

+

+

+static void ondiemet_sspm_start(void)

+{

+	if (sspm_buf_available == 0)

+		return ;

+

+	/* ID_COMMON = 1<<MID_COMMON */

+	ondiemet_module[ONDIEMET_SSPM] |= ID_COMMON;

+}

+

+

+static void ondiemet_sspm_stop(void)

+{

+	if (sspm_buf_available == 0)

+		return ;

+}

+

+

+static void update_event_id_flag(int event_id)

+{

+	unsigned int ipi_buf[4];

+	unsigned int rdata;

+	unsigned int res;

+

+	if (sspm_buf_available == 0)

+		return ;

+

+	/* main func ID: bit[31-24]; sub func ID: bit[23-18]; argu 0: bit[17-0]

+	   #define MET_MAIN_ID_MASK		0xff000000

+	   #define FUNC_BIT_SHIFT		  18

+	   #define MET_ARGU				(4 << FUNC_BIT_SHIFT)

+	   #define MID_BIT_SHIFT		   9

+	*/

+	if (event_id <32) {

+		event_id_flag0 |= 1<<event_id;

+		ipi_buf[0] = MET_MAIN_ID | MET_ARGU | MID_COMMON<<MID_BIT_SHIFT | 1;

+		ipi_buf[1] = 0;

+		ipi_buf[2] = event_id_flag0;

+		ipi_buf[3] = 0;

+		res = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);

+	} else if (event_id >=32 && event_id < 64) {

+		event_id_flag1 |= 1<<(event_id-32);

+		ipi_buf[0] = MET_MAIN_ID | MET_ARGU | MID_COMMON<<MID_BIT_SHIFT | 1;

+		ipi_buf[1] = 1;

+		ipi_buf[2] = event_id_flag1;

+		ipi_buf[3] = 0;

+		res = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);

+	} else if (event_id >=64 && event_id < 96) {

+		event_id_flag2 |= 1<<(event_id-64);

+		ipi_buf[0] = MET_MAIN_ID | MET_ARGU | MID_COMMON<<MID_BIT_SHIFT | 1;

+		ipi_buf[1] = 2;

+		ipi_buf[2] = event_id_flag2;

+		ipi_buf[3] = 0;

+		res = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);

+	} else if (event_id >=96 && event_id < 128) {

+		event_id_flag3 = 1<<(event_id-96);

+		ipi_buf[0] |= MET_MAIN_ID | MET_ARGU | MID_COMMON<<MID_BIT_SHIFT | 1;

+		ipi_buf[1] = 3;

+		ipi_buf[2] = event_id_flag3;

+		ipi_buf[3] = 0;

+		res = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);

+	}

+	met_sspm_common.mode = 1;

+}

+

+

+static char *strdup(const char *s)

+{

+	char *p = kmalloc(strlen(s) + 1, GFP_KERNEL);

+

+	if (p)

+		strcpy(p, s);

+	return p;

+}

+

+

+static int ondiemet_sspm_process_argument(const char *arg, int len)

+{

+	int i;

+	int rts_event_id = -1;

+	int res;

+	char *line;

+	char *token;

+

+	for (i=0; met_evnet_header[i].rts_event_name && i<MAX_MET_RTS_EVENT_NUM; i++) {

+		if (strcmp(met_evnet_header[i].rts_event_name, arg) == 0) {

+			rts_event_id = i;

+			break;

+		}

+	}

+	if (strstarts(arg, "update_rts_event_tbl")) {

+		char *ptr;

+

+		/* update_rts_event_tbl=rts_event_id;rts_event_name;chart_line_name;key_list*/

+		line = strdup(arg);

+		if (line == NULL)

+			return -1;

+		ptr = line;

+		token = strsep(&line, "=");

+

+		/* rts_event_id, */

+		token = strsep(&line, ";");

+		res = kstrtoint(token, 10, &rts_event_id);

+		met_evnet_header[rts_event_id].rts_event_id = rts_event_id;

+

+		/* rts_event_name */

+		token = strsep(&line, ";");

+		met_evnet_header[rts_event_id].rts_event_name = token;

+

+		/* chart_line_name */

+		token = strsep(&line, ";");

+		met_evnet_header[rts_event_id].chart_line_name = token;

+

+		/* key_list */

+		token = strsep(&line, ";\n");

+		met_evnet_header[rts_event_id].key_list = token;

+

+		update_rts_event_tbl[rts_event_id] = ptr;

+	}

+

+	if (rts_event_id >=0)

+		update_event_id_flag(rts_event_id);

+

+	return 0;

+}

+EXPORT_SYMBOL(met_sspm_common);

diff --git a/src/devtools/met-driver/4.9/common/sspm/sspm_ipi_handle.c b/src/devtools/met-driver/4.9/common/sspm/sspm_ipi_handle.c
new file mode 100644
index 0000000..161d752
--- /dev/null
+++ b/src/devtools/met-driver/4.9/common/sspm/sspm_ipi_handle.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
+#include <linux/semaphore.h>
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+/* #include <asm/uaccess.h> */
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+
+#include "ondiemet_sspm.h"
+#include "ondiemet_log.h"
+#include "interface.h"
+
+static struct ipi_action ondiemet_sspm_isr;
+static uint32_t log_size;
+static uint32_t recv_buf[4];
+static struct task_struct *ondiemet_sspm_recv_task;
+static int sspm_ipi_thread_started;
+int sspm_buffer_dumping;
+int sspm_recv_thread_comp;
+
+void log_done_cb(const void *p)
+{
+	uint32_t ret;
+	uint32_t rdata = 0;
+	uint32_t ipi_buf[4];
+	uint32_t opt = (p != NULL);
+
+	if (opt == 0) {
+		ipi_buf[0] = MET_MAIN_ID | MET_RESP_AP2MD;
+		ipi_buf[1] = MET_DUMP_BUFFER;
+		ipi_buf[2] = 0;
+		ipi_buf[3] = 0;
+		ret = sspm_ipi_send_sync(IPI_ID_MET, IPI_OPT_WAIT, (void *)ipi_buf, 0, &rdata, 1);
+	}
+}
+
+int ondiemet_sspm_recv_thread(void *data)
+{
+	uint32_t rdata = 0, cmd, ret;
+	uint32_t ridx, widx, wlen;
+
+	ondiemet_sspm_isr.data = (void *)recv_buf;
+	ret = sspm_ipi_recv_registration(IPI_ID_TST1, &ondiemet_sspm_isr);
+	do {
+		sspm_ipi_recv_wait(IPI_ID_TST1);
+		if (sspm_recv_thread_comp == 1) {
+			while (!kthread_should_stop())
+				;
+			return 0;
+		}
+		cmd = recv_buf[0] & MET_SUB_ID_MASK;
+		switch (cmd) {
+		case MET_DUMP_BUFFER:	/* mbox 1: start index; 2: size */
+			sspm_buffer_dumping = 1;
+			ridx = recv_buf[1];
+			widx = recv_buf[2];
+			log_size = recv_buf[3];
+			sspm_ipi_send_ack(IPI_ID_TST1, &rdata);
+			if (widx < ridx) {	/* wrapping occurs */
+				wlen = log_size - ridx;
+				ondiemet_log_req_enq((char *)(ondiemet_sspm_log_virt_addr) + (ridx << 2),
+				wlen * 4, log_done_cb, (void *)1);
+				ondiemet_log_req_enq((char *)(ondiemet_sspm_log_virt_addr),
+						     widx * 4, log_done_cb, (void *)0);
+			} else {
+				wlen = widx - ridx;
+				ondiemet_log_req_enq((char *)(ondiemet_sspm_log_virt_addr) + (ridx << 2),
+				wlen * 4, log_done_cb, (void *)0);
+			}
+			break;
+		case MET_CLOSE_FILE:	/* no argument */
+			/* do close file */
+			ridx = recv_buf[1];
+			widx = recv_buf[2];
+			met_sspm_log_discard = recv_buf[3];
+			if (widx < ridx) {	/* wrapping occurs */
+				wlen = log_size - ridx;
+				ondiemet_log_req_enq((char *)(ondiemet_sspm_log_virt_addr) + (ridx << 2),
+				wlen * 4, log_done_cb, (void *)1);
+				ondiemet_log_req_enq((char *)(ondiemet_sspm_log_virt_addr),
+						     widx * 4, log_done_cb, (void *)1);
+			} else {
+				wlen = widx - ridx;
+				ondiemet_log_req_enq((char *)(ondiemet_sspm_log_virt_addr) + (ridx << 2),
+				wlen * 4, log_done_cb, (void *)1);
+			}
+			ret = ondiemet_log_manager_stop();
+			/* pr_debug("MET_CLOSE_FILE: ret=%d log_discard=%d\n", ret, met_sspm_log_discard); */
+			sspm_ipi_send_ack(IPI_ID_TST1, &rdata);
+			if (sspm_run_mode == SSPM_RUN_CONTINUOUS) {
+				/* clear the memory */
+				memset_io((void *)ondiemet_sspm_log_virt_addr, 0,
+					  ondiemet_sspm_log_size);
+				/* re-start ondiemet again */
+				sspm_start();
+			}
+			break;
+		case MET_RESP_MD2AP:
+			sspm_ipi_send_ack(IPI_ID_TST1, &rdata);
+			sspm_buffer_dumping = 0;
+			break;
+		default:
+			sspm_ipi_send_ack(IPI_ID_TST1, &rdata);
+			break;
+		}
+	} while (!kthread_should_stop());
+	return 0;
+}
+
+void start_sspm_ipi_recv_thread(void)
+{
+	if (sspm_ipi_thread_started != 1) {
+		sspm_recv_thread_comp = 0;
+		ondiemet_sspm_recv_task =
+		    kthread_run(ondiemet_sspm_recv_thread, NULL, "ondiemet_sspm_recv");
+		if (IS_ERR(ondiemet_sspm_recv_task))
+			pr_debug("MET: Can not create ondiemet_sspm_recv\n");
+		else
+			sspm_ipi_thread_started = 1;
+	}
+}
+
+void stop_sspm_ipi_recv_thread(void)
+{
+	if (ondiemet_sspm_recv_task) {
+		sspm_recv_thread_comp = 1;
+		sspm_ipi_recv_complete(IPI_ID_TST1);
+		kthread_stop(ondiemet_sspm_recv_task);
+		ondiemet_sspm_recv_task = NULL;
+		sspm_ipi_thread_started = 0;
+		sspm_ipi_recv_unregistration(IPI_ID_TST1);
+	}
+}
+
diff --git a/src/devtools/met-driver/4.9/common/sspm/sspm_walltime.c b/src/devtools/met-driver/4.9/common/sspm/sspm_walltime.c
new file mode 100644
index 0000000..cc12b8b
--- /dev/null
+++ b/src/devtools/met-driver/4.9/common/sspm/sspm_walltime.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/fs.h>
+
+#include "met_drv.h"
+#include "trace.h"
+/* #include "plf_init.h" */
+#include "sspm/ondiemet_sspm.h"
+
+static void sspm_walltime_start(void)
+{
+	ondiemet_module[ONDIEMET_SSPM] |= ID_WALL_TIME;
+}
+
+static void sspm_walltime_stop(void)
+{
+}
+
+static const char sspm_walltime_header[] = "met-info [000] 0.0: sspm WCLK: freq\n";
+
+static int sspm_walltime_print_header(char *buf, int len)
+{
+	return snprintf(buf, PAGE_SIZE, sspm_walltime_header);
+}
+
+struct metdevice met_sspm_walltime = {
+	.name = "sspm_wall_time",
+	.owner = THIS_MODULE,
+	.type = MET_TYPE_BUS,
+	.cpu_related = 0,
+	.ondiemet_mode = 0,
+	.print_header = sspm_walltime_print_header,
+	.ondiemet_start = sspm_walltime_start,
+	.ondiemet_stop = sspm_walltime_stop,
+	.ondiemet_print_header = sspm_walltime_print_header,
+};
+EXPORT_SYMBOL(met_sspm_walltime);