kernel_samsung_a34x-permissive/drivers/devfreq/helio-dvfsrc-v3/helio-dvfsrc-ip-v2.c
2024-04-28 15:51:13 +02:00

976 lines
21 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/fb.h>
#include <linux/notifier.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/sched/clock.h>
#include <linux/regulator/consumer.h>
#ifdef CONFIG_MTK_WATCHDOG_COMMON
#include <ext_wd_drv.h>
#endif
#include <helio-dvfsrc-opp.h>
#include <helio-dvfsrc-ip-v2.h>
#include <spm/mtk_vcore_dvfs.h>
#include <linux/mutex.h>
#include <mt-plat/aee.h>
#if defined(CONFIG_MTK_QOS_V2)
#include <mtk_qos_sram.h>
#endif
#if IS_ENABLED(CONFIG_MMPROFILE)
#include <mmprofile.h>
struct dvfsrc_mmp_events_t {
mmp_event dvfs_event;
mmp_event level_change;
};
static struct dvfsrc_mmp_events_t dvfsrc_mmp_events;
#endif
static struct regulator *vcore_reg_id;
#define TIME_STAMP_SIZE 40
static DEFINE_SPINLOCK(force_req_lock);
static char timeout_stamp[TIME_STAMP_SIZE];
static char force_start_stamp[TIME_STAMP_SIZE];
static char force_end_stamp[TIME_STAMP_SIZE];
static char sys_stamp[TIME_STAMP_SIZE];
static char opp_forced;
#define dvfsrc_rmw(offset, val, mask, shift) \
dvfsrc_write(offset, (dvfsrc_read(offset) & ~(mask << shift)) \
| (val << shift))
int __weak mtk_rgu_cfg_dvfsrc(int enable)
{
return 0;
}
struct regulator *__weak dvfsrc_vcore_requlator(struct device *dev)
{
return NULL;
}
static void dvfsrc_set_sw_req(int data, int mask, int shift)
{
dvfsrc_rmw(DVFSRC_SW_REQ3, data, mask, shift);
}
static void dvfsrc_set_sw_req2(int data, int mask, int shift)
{
dvfsrc_rmw(DVFSRC_SW_REQ2, data, mask, shift);
}
static void dvfsrc_set_vcore_request(int data, int mask, int shift)
{
dvfsrc_rmw(DVFSRC_VCORE_REQUEST, data, mask, shift);
}
static void dvfsrc_get_timestamp(char *p)
{
int ret = 0;
u64 sec = local_clock();
u64 usec = do_div(sec, 1000000000);
do_div(usec, 1000);
ret = snprintf(p, TIME_STAMP_SIZE, "%llu.%06llu",
sec, usec);
if (ret < 0)
pr_info("dvfsrc snprintf fail\n");
}
static int is_dvfsrc_forced(void)
{
return opp_forced;
}
int is_dvfsrc_opp_fixed(void)
{
int ret;
unsigned long flags;
if (!is_dvfsrc_enabled())
return 1;
if (!(dvfsrc_read(DVFSRC_BASIC_CONTROL) & 0x100))
return 1;
if (helio_dvfsrc_flag_get() != 0)
return 1;
spin_lock_irqsave(&force_req_lock, flags);
ret = is_dvfsrc_forced();
spin_unlock_irqrestore(&force_req_lock, flags);
return ret;
}
static void dvfsrc_set_force_start(int data)
{
opp_forced = 1;
dvfsrc_get_timestamp(force_start_stamp);
dvfsrc_write(DVFSRC_TARGET_FORCE, data);
dvfsrc_rmw(DVFSRC_BASIC_CONTROL, 1,
FORCE_EN_TAR_MASK, FORCE_EN_TAR_SHIFT);
}
static void dvfsrc_set_force_end(void)
{
dvfsrc_write(DVFSRC_TARGET_FORCE, 0);
}
static void dvfsrc_release_force(void)
{
dvfsrc_rmw(DVFSRC_BASIC_CONTROL, 0,
FORCE_EN_TAR_MASK, FORCE_EN_TAR_SHIFT);
dvfsrc_write(DVFSRC_TARGET_FORCE, 0);
dvfsrc_get_timestamp(force_end_stamp);
opp_forced = 0;
}
static void dvfsrc_set_sw_bw(int type, int data)
{
data = data / 100;
if (data > 0xFF)
data = 0xFF;
switch (type) {
case DVFSRC_QOS_APU_MEMORY_BANDWIDTH:
dvfsrc_write(DVFSRC_SW_BW_0, data);
break;
case DVFSRC_QOS_CPU_MEMORY_BANDWIDTH:
dvfsrc_write(DVFSRC_SW_BW_1, data);
break;
case DVFSRC_QOS_GPU_MEMORY_BANDWIDTH:
dvfsrc_write(DVFSRC_SW_BW_2, data);
break;
case DVFSRC_QOS_MM_MEMORY_BANDWIDTH:
dvfsrc_write(DVFSRC_SW_BW_3, data);
break;
case DVFSRC_QOS_OTHER_MEMORY_BANDWIDTH:
dvfsrc_write(DVFSRC_SW_BW_4, data);
break;
default:
break;
}
}
void dvfsrc_enable_level_intr(int en)
{
if (en == 1)
dvfsrc_write(DVFSRC_INT_EN,
dvfsrc_read(DVFSRC_INT_EN) | (0x4));
else
dvfsrc_write(DVFSRC_INT_EN,
dvfsrc_read(DVFSRC_INT_EN) & ~(0x4));
}
int helio_dvfsrc_level_mask_get(void)
{
return dvfsrc_read(DVFSRC_LEVEL_MASK);
}
int helio_dvfsrc_level_mask_set(bool en, int level)
{
if (en)
dvfsrc_rmw(DVFSRC_LEVEL_MASK, 1, 1, level);
else
dvfsrc_rmw(DVFSRC_LEVEL_MASK, 0, 1, level);
return 0;
}
int get_cur_vcore_dvfs_opp(void)
{
int val = __builtin_ffs(dvfsrc_read(DVFSRC_CURRENT_LEVEL));
if (val == 0)
return VCORE_DVFS_OPP_NUM;
else
return val - 1;
}
int commit_data(int type, int data, int check_spmfw)
{
int ret = 0;
int level = 16, opp = 16;
unsigned long flags;
int opp_uv;
int vcore_uv;
if (!is_dvfsrc_enabled())
return ret;
if (check_spmfw)
mtk_spmfw_init(1, 0);
switch (type) {
case DVFSRC_QOS_APU_MEMORY_BANDWIDTH:
case DVFSRC_QOS_CPU_MEMORY_BANDWIDTH:
case DVFSRC_QOS_GPU_MEMORY_BANDWIDTH:
case DVFSRC_QOS_OTHER_MEMORY_BANDWIDTH:
case DVFSRC_QOS_MM_MEMORY_BANDWIDTH:
if (data < 0)
data = 0;
dvfsrc_set_sw_bw(type, data);
break;
case DVFSRC_QOS_DDR_OPP:
spin_lock_irqsave(&force_req_lock, flags);
if (data >= DDR_OPP_NUM || data < 0)
data = DDR_OPP_NUM - 1;
opp = data;
level = DDR_OPP_NUM - data - 1;
dvfsrc_set_sw_req(level, DDR_SW_AP_MASK, DDR_SW_AP_SHIFT);
if (!is_dvfsrc_forced() && check_spmfw) {
udelay(1);
dvfsrc_wait_for_completion(
dvfsrc_read(DVFSRC_TARGET_LEVEL) == 0,
DVFSRC_TIMEOUT);
udelay(1);
ret = dvfsrc_wait_for_completion(
get_cur_ddr_opp() <= opp,
DVFSRC_TIMEOUT);
}
spin_unlock_irqrestore(&force_req_lock, flags);
break;
case DVFSRC_QOS_VCORE_OPP:
spin_lock_irqsave(&force_req_lock, flags);
if (data >= VCORE_OPP_NUM)
data = VCORE_OPP_NUM - 1;
if (data < 0) {
pr_info("VCORE OPP = %d\n", data);
data = 0;
}
opp = data;
level = VCORE_OPP_NUM - data - 1;
dvfsrc_set_sw_req(level, VCORE_SW_AP_MASK, VCORE_SW_AP_SHIFT);
if (!is_dvfsrc_forced() && check_spmfw) {
udelay(1);
dvfsrc_wait_for_completion(
dvfsrc_read(DVFSRC_TARGET_LEVEL) == 0,
DVFSRC_TIMEOUT);
udelay(1);
ret = dvfsrc_wait_for_completion(
get_cur_vcore_opp() <= opp,
DVFSRC_TIMEOUT);
}
spin_unlock_irqrestore(&force_req_lock, flags);
if (!is_dvfsrc_forced() && check_spmfw) {
if (vcore_reg_id) {
vcore_uv = regulator_get_voltage(vcore_reg_id);
opp_uv = get_vcore_uv_table(opp);
if (vcore_uv < opp_uv) {
pr_info("DVFS FAIL= %d %d 0x%08x 0x%08x %08x\n",
vcore_uv, opp_uv,
dvfsrc_read(DVFSRC_CURRENT_LEVEL),
dvfsrc_read(DVFSRC_TARGET_LEVEL),
get_cur_vcore_dvfs_opp()); /* TODO */
aee_kernel_warning("DVFSRC",
"VCORE failed.",
__func__);
}
}
}
break;
case DVFSRC_QOS_SCP_VCORE_REQUEST:
spin_lock_irqsave(&force_req_lock, flags);
if (data >= VCORE_OPP_NUM || data < 0)
data = 0;
opp = VCORE_OPP_NUM - data - 1;
level = data;
dvfsrc_set_vcore_request(level,
VCORE_SCP_GEAR_MASK, VCORE_SCP_GEAR_SHIFT);
if (!is_dvfsrc_forced() && check_spmfw) {
udelay(1);
dvfsrc_wait_for_completion(
dvfsrc_read(DVFSRC_TARGET_LEVEL) == 0,
DVFSRC_TIMEOUT);
udelay(1);
ret = dvfsrc_wait_for_completion(
get_cur_vcore_opp() <= opp,
DVFSRC_TIMEOUT);
}
spin_unlock_irqrestore(&force_req_lock, flags);
break;
case DVFSRC_QOS_POWER_MODEL_DDR_REQUEST:
if (data >= DDR_OPP_NUM || data < 0)
data = 0;
opp = DDR_OPP_NUM - data - 1;
level = data;
dvfsrc_set_sw_req2(level,
DDR_SW_AP_MASK, DDR_SW_AP_SHIFT);
break;
case DVFSRC_QOS_POWER_MODEL_VCORE_REQUEST:
if (data >= VCORE_OPP_NUM || data < 0)
data = 0;
opp = VCORE_OPP_NUM - data - 1;
level = data;
dvfsrc_set_sw_req2(level,
VCORE_SW_AP_MASK, VCORE_SW_AP_SHIFT);
break;
case DVFSRC_QOS_VCORE_DVFS_FORCE_OPP:
spin_lock_irqsave(&force_req_lock, flags);
if (data >= VCORE_DVFS_OPP_NUM || data < 0)
data = VCORE_DVFS_OPP_NUM;
opp = data;
if (opp == VCORE_DVFS_OPP_NUM) {
dvfsrc_release_force();
spin_unlock_irqrestore(&force_req_lock, flags);
break;
}
level = opp;
dvfsrc_set_force_start(1 << level);
if (check_spmfw) {
ret = dvfsrc_wait_for_completion(
get_cur_vcore_dvfs_opp() == opp,
DVFSRC_TIMEOUT);
}
dvfsrc_set_force_end();
spin_unlock_irqrestore(&force_req_lock, flags);
break;
case DVFSRC_QOS_ISP_HRT_BANDWIDTH:
spin_lock_irqsave(&force_req_lock, flags);
if (data < 0)
data = 0;
dvfsrc_set_isp_hrt_bw(data);
opp = dvfsrc_calc_isp_hrt_opp(data);
if (!is_dvfsrc_forced() && check_spmfw) {
udelay(1);
dvfsrc_wait_for_completion(
dvfsrc_read(DVFSRC_TARGET_LEVEL) == 0,
DVFSRC_TIMEOUT);
ret = dvfsrc_wait_for_completion(
get_cur_ddr_opp() <= opp,
DVFSRC_TIMEOUT);
}
spin_unlock_irqrestore(&force_req_lock, flags);
break;
default:
break;
}
if (!(dvfsrc_read(DVFSRC_BASIC_CONTROL) & 0x100)) {
pr_info("DVFSRC OUT Disable\n");
return ret;
}
if (ret < 0) {
pr_info("%s: type: 0x%x, data: 0x%x, opp: %d, level: %d\n",
__func__, type, data, opp, level);
dvfsrc_dump_reg(NULL, 0);
aee_kernel_warning("DVFSRC", "%s: failed.", __func__);
}
return ret;
}
static void dvfsrc_level_change_dump(void)
{
#if IS_ENABLED(CONFIG_MMPROFILE)
mmprofile_log_ex(dvfsrc_mmp_events.level_change,
MMPROFILE_FLAG_PULSE, dvfsrc_read(DVFSRC_CURRENT_LEVEL),
dvfsrc_read(DVFSRC_TARGET_LEVEL));
#endif
}
static irqreturn_t helio_dvfsrc_interrupt(int irq, void *dev_id)
{
u32 val;
val = dvfsrc_read(DVFSRC_INT);
dvfsrc_write(DVFSRC_INT_CLR, val);
dvfsrc_write(DVFSRC_INT_CLR, 0x0);
if (val & 0x2) {
dvfsrc_write(DVFSRC_INT_EN,
dvfsrc_read(DVFSRC_INT_EN) & ~(0x2));
dvfsrc_get_timestamp(timeout_stamp);
}
if (val & 0x4)
dvfsrc_level_change_dump();
return IRQ_HANDLED;
}
static int dvfsrc_resume(struct helio_dvfsrc *dvfsrc)
{
#ifdef DVFSRC_SUSPEND_SUPPORT
dvfsrc_resume_cb(dvfsrc);
#endif
return 0;
}
static int dvfsrc_suspend(struct helio_dvfsrc *dvfsrc)
{
#ifdef DVFSRC_SUSPEND_SUPPORT
dvfsrc_suspend_cb(dvfsrc);
#endif
return 0;
}
int get_sw_req_vcore_opp(void)
{
int opp = -1;
int sw_req = -1;
int scp_req = VCORE_OPP_NUM - 1;
/* return opp 0, if dvfsrc not enable */
if (!is_dvfsrc_enabled())
return 0;
/* return opp 0, if dvfsrc pmqos not ready */
if (!is_dvfsrc_qos_enabled())
return 0;
/* 1st get sw req opp no lock protect is ok*/
if (!is_dvfsrc_forced()) {
sw_req = (dvfsrc_read(DVFSRC_SW_REQ3) >> VCORE_SW_AP_SHIFT);
sw_req = sw_req & VCORE_SW_AP_MASK;
sw_req = VCORE_OPP_NUM - sw_req - 1;
if (vcorefs_get_scp_req_status()) {
scp_req = ((dvfsrc_read(DVFSRC_VCORE_REQUEST)
>> VCORE_SCP_GEAR_SHIFT) & VCORE_SCP_GEAR_MASK);
scp_req = VCORE_OPP_NUM - scp_req - 1;
}
/* return sw_request, as vcore floor level*/
return (sw_req > scp_req) ? scp_req : sw_req;
}
opp = get_cur_vcore_opp();
return opp; /* return opp , as vcore fixed level*/
}
int helio_dvfsrc_config(struct helio_dvfsrc *dvfsrc)
{
struct platform_device *pdev = to_platform_device(dvfsrc->dev);
int ret;
vcore_reg_id = dvfsrc_vcore_requlator(&pdev->dev);
if (!vcore_reg_id)
pr_info("[DVFSRC] No Vcore regulator\n");
#if defined(CONFIG_MTK_WATCHDOG_COMMON) || defined(CONFIG_MTK_DBGTOP)
dvfsrc_latch_register(1);
#endif
helio_dvfsrc_enable(1);
helio_dvfsrc_platform_init(dvfsrc);
helio_dvfsrc_qos_init_done();
#if IS_ENABLED(CONFIG_MMPROFILE)
mmprofile_enable(1);
if (dvfsrc_mmp_events.dvfs_event == 0) {
dvfsrc_mmp_events.dvfs_event = mmprofile_register_event(
MMP_ROOT_EVENT, "VCORE_DVFS");
dvfsrc_mmp_events.level_change = mmprofile_register_event(
dvfsrc_mmp_events.dvfs_event, "level_change");
mmprofile_enable_event_recursive(
dvfsrc_mmp_events.dvfs_event, 1);
}
mmprofile_start(1);
#endif
dvfsrc->irq = platform_get_irq(pdev, 0);
ret = request_irq(dvfsrc->irq, helio_dvfsrc_interrupt
, IRQF_TRIGGER_NONE, "dvfsrc", dvfsrc);
if (ret)
pr_info("dvfsrc interrupt no use\n");
dvfsrc->resume = dvfsrc_resume;
dvfsrc->suspend = dvfsrc_suspend;
return 0;
}
/* FOR DEBUGGUNG */
u32 vcorefs_get_md_scenario(void)
{
return dvfsrc_read(DVFSRC_DEBUG_STA_0);
}
EXPORT_SYMBOL(vcorefs_get_md_scenario);
u32 vcorefs_get_total_emi_status(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_2);
val = (val >> DEBUG_STA2_EMI_TOTAL_SHIFT) & DEBUG_STA2_EMI_TOTAL_MASK;
return val;
}
u32 vcorefs_get_scp_req_status(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_2);
val = (val >> DEBUG_STA2_SCP_SHIFT) & DEBUG_STA2_SCP_MASK;
return val;
}
u32 vcorefs_get_md_emi_latency_status(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_2);
val = (val >> DEBUG_STA2_MD_EMI_LATENCY_SHIFT)
& DEBUG_STA2_MD_EMI_LATENCY_MASK;
return val;
}
u32 vcorefs_get_hifi_scenario(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_2);
val = (val >> DEBUG_STA2_HIFI_SCENARIO_SHIFT)
& DEBUG_STA2_HIFI_SCENARIO_MASK;
return val;
}
u32 vcorefs_get_hifi_vcore_status(void)
{
u32 hifi_scen;
hifi_scen = __builtin_ffs(vcorefs_get_hifi_scenario());
if (hifi_scen)
return (dvfsrc_read(DVFSRC_VCORE_REQUEST4) >>
((hifi_scen - 1) * 4)) & 0xF;
else
return 0;
}
u32 vcorefs_get_hifi_ddr_status(void)
{
u32 hifi_scen;
hifi_scen = __builtin_ffs(vcorefs_get_hifi_scenario());
if (hifi_scen)
return (dvfsrc_read(DVFSRC_DDR_REQUEST6) >>
((hifi_scen - 1) * 4)) & 0xF;
else
return 0;
}
#if defined(DVFSRC_IP_V2_1) || defined(DVFSRC_IP_V2_2)
u32 dvfsrc_get_md_bw(void)
{
#if defined(DVFSRC_IP_V2_1)
u32 last = dvfsrc_read(DVFSRC_LAST);
#endif
u32 is_turbo, is_urgent, md_scen;
u32 val;
#if defined(DVFSRC_IP_V2_1)
val = dvfsrc_read(DVFSRC_RECORD_0_6 + RECORD_SHIFT * last);
is_turbo =
(val >> MD_TURBO_SWITCH_SHIFT) & MD_TURBO_SWITCH_MASK;
#else
val = dvfsrc_read(DVFSRC_DEBUG_STA_0);
is_turbo =
(val >> DEBUG_MDTURBO_SHIFT) & DEBUG_MDTURBO_MASK;
#endif
val = dvfsrc_read(DVFSRC_DEBUG_STA_0);
is_urgent =
(val >> MD_EMI_URG_DEBUG_SHIFT) & MD_EMI_URG_DEBUG_MASK;
md_scen =
(val >> MD_EMI_VAL_DEBUG_SHIFT) & MD_EMI_VAL_DEBUG_MASK;
if (is_urgent) {
val = dvfsrc_read(DVSFRC_HRT_REQ_MD_URG);
if (is_turbo) {
val = (val >> MD_HRT_BW_URG1_SHIFT)
& MD_HRT_BW_URG1_MASK;
} else {
val = (val >> MD_HRT_BW_URG_SHIFT)
& MD_HRT_BW_URG_MASK;
}
} else {
u32 index, shift;
index = md_scen / 3;
shift = (md_scen % 3) * 10;
if (index > 10)
return 0;
if (index < 8) {
if (is_turbo)
val = dvfsrc_read(DVFSRC_HRT1_REQ_MD_BW_0
+ index * 4);
else
val = dvfsrc_read(DVFSRC_HRT_REQ_MD_BW_0
+ index * 4);
} else {
if (is_turbo)
val = dvfsrc_read(DVFSRC_HRT1_REQ_MD_BW_8
+ (index - 8) * 4);
else
val = dvfsrc_read(DVFSRC_HRT_REQ_MD_BW_8
+ (index - 8) * 4);
}
val = (val >> shift) & MD_HRT_BW_MASK;
}
return val;
}
#else
u32 dvfsrc_get_md_bw(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_3);
val = (val >> DEBUG_STA3_MD_HRT_BW_SHIFT)
& DEBUG_STA3_MD_HRT_BW_MASK;
return val;
}
#endif
#if defined(DVFSRC_IP_V2_1)
u32 vcorefs_get_hrt_bw_ddr(void)
{
u32 last, val;
last = dvfsrc_read(DVFSRC_LAST);
val = dvfsrc_read(DVFSRC_RECORD_0_6 + RECORD_SHIFT * last);
val = (val >> RECORD_HRT_BW_REQ_SHIFT) & RECORD_HRT_BW_REQ_MASK;
return val;
}
#elif defined(DVFSRC_IP_V2_2)
u32 vcorefs_get_hrt_bw_ddr(void)
{
u32 last, val;
last = dvfsrc_read(DVFSRC_LAST);
val = dvfsrc_read(DVFSRC_RECORD_0_5 + RECORD_SHIFT * last);
val = (val >> RECORD_HRT_BW_REQ_SHIFT) & RECORD_HRT_BW_REQ_MASK;
return val;
}
#else
u32 vcorefs_get_hrt_bw_ddr(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_4);
val = (val >> DEBUG_STA4_HRT_BW_REQ_SHIFT)
& DEBUG_STA4_HRT_BW_REQ_MASK;
return val;
}
u32 vcorefs_get_md_imp_ddr(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_4);
val = (val >> MD_EMI_MD_IMP_SHIFT)
& MD_EMI_MD_IMP_MASK;
return val;
}
#endif
#if defined(DVFSRC_IP_V2_1)
u32 vcorefs_get_md_rising_ddr(void)
{
u32 last, val;
last = dvfsrc_read(DVFSRC_LAST);
val = dvfsrc_read(DVFSRC_RECORD_0_6 + RECORD_SHIFT * last);
val = (val >> RECORD_MD_DDR_LATENCY_REQ) &
RECORD_MD_DDR_LATENCY_MASK;
return val;
}
u32 vcorefs_get_hifi_rising_ddr(void)
{
u32 last, val;
last = dvfsrc_read(DVFSRC_LAST);
val = dvfsrc_read(DVFSRC_RECORD_0_6 + RECORD_SHIFT * last);
val = (val >> RECORD_HIFI_DDR_LATENCY_REQ) &
RECORD_HIFI_DDR_LATENCY_MASK;
return val;
}
#else
u32 vcorefs_get_md_rising_ddr(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_0);
val = (val >> DEBUG_MD_RIS_DDR_SHIFT)
& DEBUG_MD_RIS_DDR_MASK;
return val;
}
u32 vcorefs_get_hifi_rising_ddr(void)
{
u32 val;
val = dvfsrc_read(DVFSRC_DEBUG_STA_0);
val = (val >> DEBUG_HIFI_RIS_DDR_SHIFT) &
DEBUG_HIFI_RIS_DDR_MASK;
return val;
}
u32 vcorefs_get_md_scenario_ddr(void)
{
u32 is_turbo, is_urgent, md_scen;
u32 sta0;
u32 val;
is_turbo =
(dvfsrc_read(DVFSRC_MD_TURBO) == 0) ? 1 : 0;
sta0 = dvfsrc_read(DVFSRC_DEBUG_STA_0);
is_urgent =
(sta0 >> MD_EMI_URG_DEBUG_SHIFT) & MD_EMI_URG_DEBUG_MASK;
md_scen =
(sta0 >> MD_EMI_VAL_DEBUG_SHIFT) & MD_EMI_VAL_DEBUG_MASK;
if (is_urgent)
val = is_turbo ? dvfsrc_read(DVFSRC_95MD_SCEN_BW4) : 0;
else {
u32 index, shift;
index = md_scen / 8;
shift = (md_scen % 8) * 4;
if (md_scen > 31)
return 0;
if (is_turbo)
val = dvfsrc_read(DVFSRC_95MD_SCEN_BW0_T
+ index * 4);
else
val = dvfsrc_read(DVFSRC_95MD_SCEN_BW0
+ index * 4);
val = (val >> shift) & DDR_SW_AP_MASK;
}
return val;
}
#endif
void get_dvfsrc_reg(char *p)
{
char timestamp[TIME_STAMP_SIZE];
dvfsrc_get_timestamp(timestamp);
p += sprintf(p, "%-16s: 0x%08x\n",
"BASIC_CONTROL",
dvfsrc_read(DVFSRC_BASIC_CONTROL));
p += sprintf(p,
"%-16s: %08x, %08x, %08x, %08x\n",
"SW_REQ 1~4",
dvfsrc_read(DVFSRC_SW_REQ1),
dvfsrc_read(DVFSRC_SW_REQ2),
dvfsrc_read(DVFSRC_SW_REQ3),
dvfsrc_read(DVFSRC_SW_REQ4));
p += sprintf(p,
"%-16s: %08x, %08x, %08x, %08x\n",
"SW_REQ 5~8",
dvfsrc_read(DVFSRC_SW_REQ5),
dvfsrc_read(DVFSRC_SW_REQ6),
dvfsrc_read(DVFSRC_SW_REQ7),
dvfsrc_read(DVFSRC_SW_REQ8));
p += sprintf(p, "%-16s: %d, %d, %d, %d, %d\n",
"SW_BW_0~4",
dvfsrc_read(DVFSRC_SW_BW_0),
dvfsrc_read(DVFSRC_SW_BW_1),
dvfsrc_read(DVFSRC_SW_BW_2),
dvfsrc_read(DVFSRC_SW_BW_3),
dvfsrc_read(DVFSRC_SW_BW_4));
#if !defined(DVFSRC_IP_V2_1) && !defined(DVFSRC_IP_V2_2)
p += sprintf(p, "%-16s: %d, %d\n",
"SW_BW_5~6",
dvfsrc_read(DVFSRC_SW_BW_5),
dvfsrc_read(DVFSRC_SW_BW_6));
#endif
p += sprintf(p, "%-16s: 0x%08x\n",
"ISP_HRT",
dvfsrc_read(DVFSRC_ISP_HRT));
p += sprintf(p, "%-16s: 0x%08x, 0x%08x, 0x%08x\n",
"DEBUG_STA",
dvfsrc_read(DVFSRC_DEBUG_STA_0),
dvfsrc_read(DVFSRC_DEBUG_STA_1),
dvfsrc_read(DVFSRC_DEBUG_STA_2));
p += sprintf(p, "%-16s: 0x%08x\n",
"DVFSRC_INT",
dvfsrc_read(DVFSRC_INT));
p += sprintf(p, "%-16s: 0x%08x\n",
"DVFSRC_INT_EN",
dvfsrc_read(DVFSRC_INT_EN));
p += sprintf(p, "%-16s: 0x%02x\n",
"TOTAL_EMI_REQ",
vcorefs_get_total_emi_status());
p += sprintf(p, "%-16s: %d\n",
"DDR_QOS_REQ",
dvfsrc_get_ddr_qos());
p += sprintf(p, "%-16s: %d\n",
"HIFI_VCORE_REQ",
vcorefs_get_hifi_vcore_status());
p += sprintf(p, "%-16s: %d\n",
"HIFI_DDR_REQ",
vcorefs_get_hifi_ddr_status());
p += sprintf(p, "%-16s: 0x%08x\n",
"MD_HRT_BW",
dvfsrc_get_md_bw());
p += sprintf(p, "%-16s: %d\n",
"HIFI_RISINGREQ",
vcorefs_get_hifi_rising_ddr());
p += sprintf(p, "%-16s: %d\n",
"MD_RISING_REQ",
vcorefs_get_md_rising_ddr());
#if !defined(DVFSRC_IP_V2_1) && !defined(DVFSRC_IP_V2_2)
p += sprintf(p, "%-16s: %d\n",
"HRT_BW_REQ",
vcorefs_get_hrt_bw_ddr());
#endif
#if !defined(DVFSRC_IP_V2_1)
p += sprintf(p, "%-16s: %d\n",
"MD_SCEN_DDR",
vcorefs_get_md_scenario_ddr());
#endif
p += sprintf(p, "%-16s: %d , 0x%08x\n",
"SCP_VCORE_REQ",
vcorefs_get_scp_req_status(),
dvfsrc_read(DVFSRC_VCORE_REQUEST));
p += sprintf(p, "%-16s: 0x%08x\n",
"CURRENT_LEVEL",
dvfsrc_read(DVFSRC_CURRENT_LEVEL));
p += sprintf(p, "%-16s: 0x%08x\n",
"TARGET_LEVEL",
dvfsrc_read(DVFSRC_TARGET_LEVEL));
p += sprintf(p, "%-16s: %.40s\n",
"Current Tstamp", timestamp);
p += sprintf(p, "%-16s: %.40s\n",
"ForceS Tstamp", force_start_stamp);
p += sprintf(p, "%-16s: %.40s\n",
"ForceE Tstamp", force_end_stamp);
p += sprintf(p, "%-16s: %.40s\n",
"Timeout Tstamp", timeout_stamp);
p += sprintf(p, "%-16s: %.40s\n",
"Sys Tstamp", sys_stamp);
}
void get_dvfsrc_record(char *p)
{
int i, debug_reg;
p += sprintf(p, "%-17s: 0x%08x\n",
"DVFSRC_LAST",
dvfsrc_read(DVFSRC_LAST));
for (i = 0; i < 8; i++) {
debug_reg = DVFSRC_RECORD_0_0 + (i * RECORD_SHIFT);
p += sprintf(p, "[%d]%-14s: %08x,%08x,%08x,%08x\n",
i,
"DVFSRC_REC 0~3",
dvfsrc_read(debug_reg),
dvfsrc_read(debug_reg + 0x4),
dvfsrc_read(debug_reg + 0x8),
dvfsrc_read(debug_reg + 0xC));
#if defined(DVFSRC_IP_V2_1)
p += sprintf(p, "[%d]%-14s: %08x,%08x,%08x\n",
i,
"DVFSRC_REC 4~6",
dvfsrc_read(debug_reg + 0x10),
dvfsrc_read(debug_reg + 0x14),
dvfsrc_read(debug_reg + 0x18));
#else
p += sprintf(p, "[%d]%-14s: %08x,%08x,%08x,%08x\n",
i,
"DVFSRC_REC 4~7",
dvfsrc_read(debug_reg + 0x10),
dvfsrc_read(debug_reg + 0x14),
dvfsrc_read(debug_reg + 0x18),
dvfsrc_read(debug_reg + 0x1C));
#endif
}
}
/* met profile function */
/* met profile table */
static unsigned int met_vcorefs_info[INFO_MAX];
static char *met_info_name[INFO_MAX] = {
"OPP",
"FREQ",
"VCORE",
"x__SPM_LEVEL",
};
int vcorefs_get_num_opp(void)
{
return VCORE_DVFS_OPP_NUM;
}
EXPORT_SYMBOL(vcorefs_get_num_opp);
int vcorefs_get_opp_info_num(void)
{
return INFO_MAX;
}
EXPORT_SYMBOL(vcorefs_get_opp_info_num);
char **vcorefs_get_opp_info_name(void)
{
return met_info_name;
}
EXPORT_SYMBOL(vcorefs_get_opp_info_name);
unsigned int *vcorefs_get_opp_info(void)
{
met_vcorefs_info[INFO_OPP_IDX] = get_cur_vcore_dvfs_opp();
met_vcorefs_info[INFO_FREQ_IDX] = get_cur_ddr_khz();
met_vcorefs_info[INFO_VCORE_IDX] = get_cur_vcore_uv();
met_vcorefs_info[INFO_SPM_LEVEL_IDX] = get_cur_vcore_dvfs_opp();
return met_vcorefs_info;
}
EXPORT_SYMBOL(vcorefs_get_opp_info);