unplugged-kernel/drivers/misc/mediatek/emi_bwl/mt6739/emi_mbw.c

239 lines
5.3 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <mt-plat/sync_write.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/sched/clock.h>
#include <asm/div64.h>
#include <mtk_dramc.h>
#include "emi_mbw.h"
#include "emi_bwl.h"
#include "emi_elm.h"
static bool dump_latency_status;
unsigned long long last_time_ns;
long long LastWordAllCount;
void dump_last_bm(char *buf, unsigned int leng)
{
#if ENABLE_ELM
elm_dump(buf, leng);
#else
snprintf(buf, leng, "[EMI] no ELM and runtime BM support\n");
#endif
}
/***********************************************
* register / unregister g_pGetMemBW CB
***********************************************/
static getmembw_func g_pGetMemBW; /* not initialise statics to 0 or NULL */
void mt_getmembw_registerCB(getmembw_func pCB)
{
if (pCB == NULL) {
/* reset last time & word all count */
last_time_ns = sched_clock();
LastWordAllCount = 0;
pr_info("[get_mem_bw] register CB is a null function\n");
} else {
pr_info("[get_mem_bw] register CB successful\n");
}
g_pGetMemBW = pCB;
}
EXPORT_SYMBOL(mt_getmembw_registerCB);
unsigned long long get_mem_bw(void)
{
unsigned long long throughput;
long long WordAllCount;
unsigned long long current_time_ns, time_period_ns;
int count;
long long value;
int emi_dcm_status;
#if DISABLE_FLIPPER_FUNC
return 0;
#endif
if (g_pGetMemBW)
return g_pGetMemBW();
emi_dcm_status = BM_GetEmiDcm();
/* pr_info("[get_mem_bw]emi_dcm_status = %d\n", emi_dcm_status); */
current_time_ns = sched_clock();
time_period_ns = current_time_ns - last_time_ns;
/* pr_info("[get_mem_bw]last_time=%llu, current_time=%llu,
* period=%llu\n", last_time_ns, current_time_ns, time_period_ns);
*/
/* disable_infra_dcm(); */
BM_SetEmiDcm(0xff); /* disable EMI dcm */
BM_Pause();
WordAllCount = BM_GetWordAllCount();
if (WordAllCount == 0) {
LastWordAllCount = 0;
} else if (WordAllCount == BM_ERR_OVERRUN) {
pr_debug("[get_mem_bw] BM_ERR_OVERRUN\n");
WordAllCount = 0;
LastWordAllCount = 0;
BM_Enable(0); /* stop EMI monitors will reset all counters */
BM_Enable(1); /* start EMI monitor counting */
}
WordAllCount -= LastWordAllCount;
throughput = (WordAllCount * 8 * 1000);
if (time_period_ns >= 0xFFFFFFFF) { /* uint32_t overflow */
do_div(time_period_ns, 10000000);
do_div(throughput, 10000000);
pr_debug("[get_mem_bw] time_period_ns overflow lst\n");
/* pr_info("[get_mem_bw] time_period_ns overflow 1st\n"); */
if (time_period_ns >= 0xFFFFFFFF) { /* uint32_t overflow */
do_div(time_period_ns, 1000);
do_div(throughput, 1000);
pr_debug("[get_mem_bw] time_period_ns overflow 2nd\n");
/* pr_info("[get_mem_bw] time_period overflow 2nd\n"); */
}
}
do_div(throughput, time_period_ns);
/* pr_info("[get_mem_bw]Total MEMORY THROUGHPUT =%llu(MB/s),
* WordAllCount_delta = 0x%llx, LastWordAllCount = 0x%llx\n",
* throughput, WordAllCount, LastWordAllCount);
*/
/* stopping EMI monitors will reset all counters */
BM_Enable(0);
value = BM_GetWordAllCount();
count = 100;
if ((value != 0) && (value > 0xB0000000)) {
do {
value = BM_GetWordAllCount();
if (value != 0) {
count--;
BM_Enable(1);
BM_Enable(0);
} else
break;
} while (count > 0);
}
LastWordAllCount = value;
/* pr_info("[get_mem_bw]loop count = %d, last_word_all_count = 0x%llx\n", count, LastWordAllCount); */
/* start EMI monitor counting */
BM_Enable(1);
last_time_ns = sched_clock();
/* restore_infra_dcm();*/
BM_SetEmiDcm(emi_dcm_status);
/*pr_info("[get_mem_bw]throughput = %llx\n", throughput);*/
return throughput;
}
static int mem_bw_suspend_callback(struct device *dev)
{
/*pr_info("[get_mem_bw]mem_bw_suspend_callback\n");*/
LastWordAllCount = 0;
BM_Pause();
return 0;
}
static int mem_bw_resume_callback(struct device *dev)
{
/* pr_info("[get_mem_bw]mem_bw_resume_callback\n"); */
BM_Continue();
return 0;
}
const struct dev_pm_ops mt_mem_bw_pm_ops = {
.suspend = mem_bw_suspend_callback,
.resume = mem_bw_resume_callback,
.restore_early = NULL,
};
struct platform_device mt_mem_bw_pdev = {
.name = "mt-mem_bw",
.id = -1,
};
static struct platform_driver mt_mem_bw_pdrv = {
.probe = NULL,
.remove = NULL,
.driver = {
.name = "mt-mem_bw",
.pm = &mt_mem_bw_pm_ops,
.owner = THIS_MODULE,
},
};
int mbw_init(void)
{
int ret = 0;
BM_Init();
/* register platform device/driver */
ret = platform_device_register(&mt_mem_bw_pdev);
if (ret) {
pr_info("fail to register mem_bw device @ %s()\n", __func__);
goto out;
}
ret = platform_driver_register(&mt_mem_bw_pdrv);
if (ret) {
pr_info("fail to register mem_bw driver @ %s()\n", __func__);
platform_device_unregister(&mt_mem_bw_pdev);
}
enable_dump_latency();
out:
return ret;
}
void enable_dump_latency(void)
{
dump_latency_status = true;
}
void disable_dump_latency(void)
{
dump_latency_status = false;
}
static int __init dvfs_bwct_init(void)
{
return 0;
}
late_initcall(dvfs_bwct_init);
#ifdef ENABLE_RUNTIME_BM
static int __init runtime_bm_init(void)
{
setup_deferrable_timer_on_stack(&bm_timer, bm_timer_callback, 0);
if (mod_timer(&bm_timer, jiffies + msecs_to_jiffies(RUNTIME_PERIOD)))
pr_debug("[EMI MBW] Error in BM mod_timer\n");
return 0;
}
late_initcall(runtime_bm_init);
#endif