[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);