blob: 8c5711b6e240ac7a2d69313976856d594df6cd18 [file] [log] [blame]
/*
* 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 */