/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #include #include #include #include #include #include #include #include #ifdef CONFIG_MTK_WATCHDOG_COMMON #include #endif #include #include #include #include #include #if defined(CONFIG_MTK_QOS_V2) #include #endif #if IS_ENABLED(CONFIG_MMPROFILE) #include 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);