// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 MediaTek Inc. */ /** * @file gpufreq_debug.c * @brief Debug mechanism for GPU-DVFS */ /** * =============================================== * Include * =============================================== */ #include #include #include #include #include #include #include #include #include #include #include /** * =============================================== * Local Variable Definition * =============================================== */ static unsigned int g_dual_buck; static unsigned int g_gpueb_support; static unsigned int g_debug_power_state; static unsigned int g_debug_margin_mode; static int g_fixed_oppidx; static unsigned int g_fixed_freq; static unsigned int g_fixed_volt; static const struct gpufreq_shared_status *g_shared_status; static DEFINE_MUTEX(gpufreq_debug_lock); /** * =============================================== * Function Definition * =============================================== */ #if defined(CONFIG_PROC_FS) static int gpufreq_status_proc_show(struct seq_file *m, void *v) { unsigned long long power_time = 0; mutex_lock(&gpufreq_debug_lock); gpufreq_update_debug_opp_info(); seq_printf(m, "[GPUFREQ-DEBUG] Current Status of GPUFREQ\n"); seq_printf(m, "%-16s Index: %2d, Freq: %7d, Volt: %6d, Vsram: %6d\n", "[GPU OPP]", g_shared_status->cur_oppidx_gpu, g_shared_status->cur_fgpu, g_shared_status->cur_vgpu, g_shared_status->cur_vsram_gpu); if (g_dual_buck) seq_printf(m, "%-16s Index: %2d, Freq: %7d, Volt: %6d, Vsram: %6d\n", "[STACK OPP]", g_shared_status->cur_oppidx_stack, g_shared_status->cur_fstack, g_shared_status->cur_vstack, g_shared_status->cur_vsram_stack); seq_printf(m, "%-16s FmeterFreq: %7d, Con1Freq: %7d, ReguVolt: %6d, ReguVsram: %6d\n", "[GPU REALOPP]", g_shared_status->cur_fmeter_fgpu, g_shared_status->cur_con1_fgpu, g_shared_status->cur_regulator_vgpu, g_shared_status->cur_regulator_vsram_gpu); if (g_dual_buck) seq_printf(m, "%-16s FmeterFreq: %7d, Con1Freq: %7d, ReguVolt: %6d, ReguVsram: %6d\n", "[STACK REALOPP]", g_shared_status->cur_fmeter_fstack, g_shared_status->cur_con1_fstack, g_shared_status->cur_regulator_vstack, g_shared_status->cur_regulator_vsram_stack); seq_printf(m, "%-16s SegmentID: %d, WorkingOPPNum: %2d, SignedOPPNum: %2d\n", "[GPU Segment]", g_shared_status->segment_id, g_shared_status->opp_num_gpu, g_shared_status->signed_opp_num_gpu); if (g_dual_buck) seq_printf(m, "%-16s SegmentID: %d, WorkingOPPNum: %2d, SignedOPPNum: %2d\n", "[STACK Segment]", g_shared_status->segment_id, g_shared_status->opp_num_stack, g_shared_status->signed_opp_num_stack); seq_printf(m, "%-16s LimitIndex: %2d, Limiter: %2d, Priority: %2d\n", "[PPM Ceiling]", g_shared_status->cur_ceiling, g_shared_status->cur_c_limiter, g_shared_status->cur_c_priority); seq_printf(m, "%-16s LimitIndex: %2d, Limiter: %2d, Priority: %2d\n", "[PPM Floor]", g_shared_status->cur_floor, g_shared_status->cur_f_limiter, g_shared_status->cur_f_priority); power_time = g_shared_status->power_time_h; power_time = (power_time << 32) | g_shared_status->power_time_l; seq_printf(m, "%-16s PowerCount: %d, Active: %d, CG: %d, MTCMOS: %d, BUCK: %d\n", "[Power State]", g_shared_status->power_count, g_shared_status->active_count, g_shared_status->cg_count, g_shared_status->mtcmos_count, g_shared_status->buck_count); seq_printf(m, "%-16s Timestamp: %lld, DVFSState: 0x%04x\n", "[Power State]", power_time, g_shared_status->dvfs_state); seq_printf(m, "%-16s PowerStatus: 0x%08x, ShaderPresent: 0x%08x\n", "[Power State]", g_shared_status->mfg_pwr_status, g_shared_status->shader_present); seq_printf(m, "%-16s DualBuck: %s, GPUEBSupport: %s, RandomOPP: %s\n", "[MFGSYS Config]", g_dual_buck ? "True" : "False", g_gpueb_support ? "On" : "Off", g_shared_status->stress_test ? "On" : "Off"); seq_printf(m, "%-16s AgingMargin: %s, AVSMargin: %s, GPM1.0: %s, GPM3.0: %s, PTP3: %s\n", "[MFGSYS Config]", g_shared_status->aging_margin ? "On" : "Off", g_shared_status->avs_margin ? "On" : "Off", g_shared_status->gpm1_mode ? "On" : "Off", g_shared_status->gpm3_mode ? "On" : "Off", g_shared_status->ptp3_mode ? "On" : "Off"); seq_printf(m, "%-16s Temperature: %d'C, GPUTemperComp: %d/%d, STACKTemperComp: %d/%d\n", "[MFGSYS Config]", g_shared_status->temperature, g_shared_status->temper_comp_norm_gpu, g_shared_status->temper_comp_high_gpu, g_shared_status->temper_comp_norm_stack, g_shared_status->temper_comp_high_stack); seq_printf(m, "%-16s DBGVer: 0x%08x, PTPVer: 0x%04x, SBVer: 0x%04x\n", "[MFGSYS Config]", g_shared_status->dbg_version, g_shared_status->ptp_version, g_shared_status->sb_version); mutex_unlock(&gpufreq_debug_lock); return GPUFREQ_SUCCESS; } static int gpu_working_opp_table_proc_show(struct seq_file *m, void *v) { const struct gpufreq_opp_info *opp_table = NULL; int ret = GPUFREQ_SUCCESS; int opp_num = 0, i = 0; mutex_lock(&gpufreq_debug_lock); opp_num = g_shared_status->opp_num_gpu; opp_table = g_shared_status->working_table_gpu; if (!opp_table) { GPUFREQ_LOGE("fail to get GPU working OPP table (ENOENT)"); ret = GPUFREQ_ENOENT; goto done; } for (i = 0; i < opp_num; i++) { seq_printf(m, "[%02d] freq: %d, volt: %d, vsram: %d, posdiv: %d, margin: %d, power: %d\n", i, opp_table[i].freq, opp_table[i].volt, opp_table[i].vsram, opp_table[i].posdiv, opp_table[i].margin, opp_table[i].power); } done: mutex_unlock(&gpufreq_debug_lock); return ret; } static int stack_working_opp_table_proc_show(struct seq_file *m, void *v) { const struct gpufreq_opp_info *opp_table = NULL; int ret = GPUFREQ_SUCCESS; int opp_num = 0, i = 0; mutex_lock(&gpufreq_debug_lock); opp_num = g_shared_status->opp_num_stack; opp_table = g_shared_status->working_table_stack; if (!opp_table) { GPUFREQ_LOGE("fail to get STACK working OPP table (ENOENT)"); ret = GPUFREQ_ENOENT; goto done; } for (i = 0; i < opp_num; i++) { seq_printf(m, "[%02d] freq: %d, volt: %d, vsram: %d, posdiv: %d, margin: %d, power: %d\n", i, opp_table[i].freq, opp_table[i].volt, opp_table[i].vsram, opp_table[i].posdiv, opp_table[i].margin, opp_table[i].power); } done: mutex_unlock(&gpufreq_debug_lock); return ret; } static int gpu_signed_opp_table_proc_show(struct seq_file *m, void *v) { const struct gpufreq_opp_info *opp_table = NULL; int ret = GPUFREQ_SUCCESS; int opp_num = 0, i = 0; mutex_lock(&gpufreq_debug_lock); if (g_shared_status->test_mode) { opp_num = g_shared_status->signed_opp_num_gpu; opp_table = g_shared_status->signed_table_gpu; } else { opp_num = g_shared_status->opp_num_gpu; opp_table = g_shared_status->working_table_gpu; } if (!opp_table) { GPUFREQ_LOGE("fail to get GPU signed OPP table (ENOENT)"); ret = GPUFREQ_ENOENT; goto done; } for (i = 0; i < opp_num; i++) { seq_printf(m, "[%02d*] freq: %d, volt: %d, vsram: %d, posdiv: %d, margin: %d, power: %d\n", i, opp_table[i].freq, opp_table[i].volt, opp_table[i].vsram, opp_table[i].posdiv, opp_table[i].margin, opp_table[i].power); } done: mutex_unlock(&gpufreq_debug_lock); return ret; } static int stack_signed_opp_table_proc_show(struct seq_file *m, void *v) { const struct gpufreq_opp_info *opp_table = NULL; int ret = GPUFREQ_SUCCESS; int opp_num = 0, i = 0; mutex_lock(&gpufreq_debug_lock); if (g_shared_status->test_mode) { opp_num = g_shared_status->signed_opp_num_stack; opp_table = g_shared_status->signed_table_stack; } else { opp_num = g_shared_status->opp_num_stack; opp_table = g_shared_status->working_table_stack; } if (!opp_table) { GPUFREQ_LOGE("fail to get STACK signed OPP table (ENOENT)"); ret = GPUFREQ_ENOENT; goto done; } for (i = 0; i < opp_num; i++) { seq_printf(m, "[%02d*] freq: %d, volt: %d, vsram: %d, posdiv: %d, margin: %d, power: %d\n", i, opp_table[i].freq, opp_table[i].volt, opp_table[i].vsram, opp_table[i].posdiv, opp_table[i].margin, opp_table[i].power); } done: mutex_unlock(&gpufreq_debug_lock); return ret; } static int limit_table_proc_show(struct seq_file *m, void *v) { const struct gpuppm_limit_info *limit_table = NULL; int ret = GPUFREQ_SUCCESS; int i = 0; mutex_lock(&gpufreq_debug_lock); limit_table = g_shared_status->limit_table; if (!limit_table) { GPUFREQ_LOGE("fail to get limit table (ENOENT)"); ret = GPUFREQ_ENOENT; goto done; } seq_printf(m, "%4s %15s %11s %10s %8s %11s %11s\n", "[id]", "[name]", "[priority]", "[ceiling]", "[floor]", "[c_enable]", "[f_enable]"); for (i = 0; i < LIMIT_NUM; i++) { seq_printf(m, "%4d %15s %11d %10d %8d %11d %11d\n", i, limit_table[i].name, limit_table[i].priority, limit_table[i].ceiling, limit_table[i].floor, limit_table[i].c_enable, limit_table[i].f_enable); } done: mutex_unlock(&gpufreq_debug_lock); return ret; } static ssize_t limit_table_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { int ret = GPUFREQ_SUCCESS; char buf[64], cmd[64]; unsigned int len = 0; int limiter = 0, ceiling = 0, floor = 0; len = (count < (sizeof(buf) - 1)) ? count : (sizeof(buf) - 1); if (copy_from_user(buf, buffer, len)) { ret = GPUFREQ_EINVAL; goto done; } buf[len] = '\0'; mutex_lock(&gpufreq_debug_lock); if (sscanf(buf, "%6s %2d %2d %2d", cmd, &limiter, &ceiling, &floor) == 4) { if (sysfs_streq(cmd, "set")) { ret = gpufreq_set_limit(TARGET_DEFAULT, limiter, ceiling, floor); if (ret) GPUFREQ_LOGE("fail to set debug limit index (%d)", ret); } else if (sysfs_streq(cmd, "switch")) { ret = gpufreq_switch_limit(TARGET_DEFAULT, limiter, ceiling, floor); if (ret) GPUFREQ_LOGE("fail to switch debug limit option (%d)", ret); } } mutex_unlock(&gpufreq_debug_lock); done: return (ret < 0) ? ret : count; } /* PROCFS: show current state of kept OPP index */ static int fix_target_opp_index_proc_show(struct seq_file *m, void *v) { unsigned int dvfs_state = DVFS_FREE; int cur_oppidx = -1; mutex_lock(&gpufreq_debug_lock); dvfs_state = g_shared_status->dvfs_state; if (g_dual_buck) cur_oppidx = g_shared_status->cur_oppidx_stack; else cur_oppidx = g_shared_status->cur_oppidx_gpu; if ((dvfs_state & DVFS_FIX_OPP) && (cur_oppidx == g_fixed_oppidx)) seq_printf(m, "[GPUFREQ-DEBUG] fix OPP index: %d\n", cur_oppidx); else seq_puts(m, "[GPUFREQ-DEBUG] fix OPP index is disabled\n"); mutex_unlock(&gpufreq_debug_lock); return GPUFREQ_SUCCESS; } /* * PROCFS: keep OPP index * -1: free run * others: OPP index to be kept */ static ssize_t fix_target_opp_index_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { int ret = GPUFREQ_SUCCESS; char buf[64]; unsigned int len = 0; int value = 0, opp_num = -1; len = (count < (sizeof(buf) - 1)) ? count : (sizeof(buf) - 1); if (copy_from_user(buf, buffer, len)) { ret = GPUFREQ_EINVAL; goto done; } buf[len] = '\0'; mutex_lock(&gpufreq_debug_lock); if (sysfs_streq(buf, "min")) { if (g_dual_buck) opp_num = g_shared_status->opp_num_stack; else opp_num = g_shared_status->opp_num_gpu; if (opp_num > 0) { value = opp_num - 1; ret = gpufreq_fix_target_oppidx(TARGET_DEFAULT, value); if (ret) GPUFREQ_LOGE("fail to fix OPP index (%d)", ret); else g_fixed_oppidx = value; } } else if (sscanf(buf, "%2d", &value) == 1) { ret = gpufreq_fix_target_oppidx(TARGET_DEFAULT, value); if (ret) GPUFREQ_LOGE("fail to fix OPP index (%d)", ret); else g_fixed_oppidx = value; } mutex_unlock(&gpufreq_debug_lock); done: return (ret < 0) ? ret : count; } /* PROCFS: show current state of kept freq and volt */ static int fix_custom_freq_volt_proc_show(struct seq_file *m, void *v) { unsigned int dvfs_state = DVFS_FREE; unsigned int cur_freq = 0, cur_volt = 0; mutex_lock(&gpufreq_debug_lock); dvfs_state = g_shared_status->dvfs_state; if (g_dual_buck) { cur_freq = g_shared_status->cur_fstack; cur_volt = g_shared_status->cur_vstack; } else { cur_freq = g_shared_status->cur_fgpu; cur_volt = g_shared_status->cur_vgpu; } if ((dvfs_state & DVFS_FIX_FREQ_VOLT) && (cur_freq == g_fixed_freq) && (cur_volt == g_fixed_volt)) seq_printf(m, "[GPUFREQ-DEBUG] fix freq: %d and volt: %d\n", cur_freq, cur_volt); else seq_puts(m, "[GPUFREQ-DEBUG] fix freq and volt is disabled\n"); mutex_unlock(&gpufreq_debug_lock); return GPUFREQ_SUCCESS; } /* * PROCFS: keep freq and volt * 0 0: free run * others others: freq and volt to be kept */ static ssize_t fix_custom_freq_volt_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { int ret = GPUFREQ_SUCCESS; char buf[64]; unsigned int len = 0; unsigned int fixed_freq = 0, fixed_volt = 0; len = (count < (sizeof(buf) - 1)) ? count : (sizeof(buf) - 1); if (copy_from_user(buf, buffer, len)) { ret = GPUFREQ_EINVAL; goto done; } buf[len] = '\0'; mutex_lock(&gpufreq_debug_lock); if (sscanf(buf, "%7d %6d", &fixed_freq, &fixed_volt) == 2) { ret = gpufreq_fix_custom_freq_volt(TARGET_DEFAULT, fixed_freq, fixed_volt); if (ret) GPUFREQ_LOGE("fail to fix freq and volt (%d)", ret); else { g_fixed_freq = fixed_freq; g_fixed_volt = fixed_volt; } } mutex_unlock(&gpufreq_debug_lock); done: return (ret < 0) ? ret : count; } /* PROCFS: show current power state */ static int mfgsys_power_control_proc_show(struct seq_file *m, void *v) { mutex_lock(&gpufreq_debug_lock); if (g_debug_power_state) seq_puts(m, "[GPUFREQ-DEBUG] MFGSYS is DBG_POWER_ON\n"); else seq_puts(m, "[GPUFREQ-DEBUG] MFGSYS is DBG_POWER_OFF\n"); mutex_unlock(&gpufreq_debug_lock); return GPUFREQ_SUCCESS; } /* * PROCFS: additionally control power of MFGSYS once to achieve AO state * power_on: power on once * power_off: power off once */ static ssize_t mfgsys_power_control_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { int ret = GPUFREQ_SUCCESS; char buf[64]; unsigned int len = 0; len = (count < (sizeof(buf) - 1)) ? count : (sizeof(buf) - 1); if (copy_from_user(buf, buffer, len)) { ret = GPUFREQ_EINVAL; goto done; } buf[len] = '\0'; mutex_lock(&gpufreq_debug_lock); if (sysfs_streq(buf, "power_on") && g_debug_power_state == POWER_OFF) { ret = gpufreq_power_control(POWER_ON, GPUPPM_DEFAULT_IDX); if (ret < 0) GPUFREQ_LOGE("fail to power on MFGSYS (%d)", ret); else g_debug_power_state = POWER_ON; } else if (sysfs_streq(buf, "power_off") && g_debug_power_state == POWER_ON) { ret = gpufreq_power_control(POWER_OFF, GPUPPM_DEFAULT_IDX); if (ret < 0) GPUFREQ_LOGE("fail to power off MFGSYS (%d)", ret); else g_debug_power_state = POWER_OFF; } mutex_unlock(&gpufreq_debug_lock); done: return (ret < 0) ? ret : count; } /* PROCFS: show current info of aging*/ static int asensor_info_proc_show(struct seq_file *m, void *v) { struct gpufreq_asensor_info asensor_info = {}; mutex_lock(&gpufreq_debug_lock); asensor_info = g_shared_status->asensor_info; seq_printf(m, "Aging table index: %d, MOST_AGRRESIVE_AGING_TABLE_ID: %d\n", asensor_info.aging_table_idx, asensor_info.aging_table_idx_agrresive); seq_printf(m, "efuse1(0x%08x): 0x%08x, efuse2(0x%08x): 0x%08x\n", asensor_info.efuse1_addr, asensor_info.efuse1, asensor_info.efuse2_addr, asensor_info.efuse2); seq_printf(m, "efuse3(0x%08x): 0x%08x, efuse4(0x%08x): 0x%08x\n", asensor_info.efuse3_addr, asensor_info.efuse3, asensor_info.efuse4_addr, asensor_info.efuse4); seq_printf(m, "a_t0_efuse1: %d, a_t0_efuse2: %d, a_t0_efuse3: %d, a_t0_efuse4: %d\n", asensor_info.a_t0_efuse1, asensor_info.a_t0_efuse2, asensor_info.a_t0_efuse3, asensor_info.a_t0_efuse4); seq_printf(m, "a_tn_sensor1: %d, a_tn_sensor2: %d, a_tn_sensor3: %d, a_tn_sensor4: %d\n", asensor_info.a_tn_sensor1, asensor_info.a_tn_sensor2, asensor_info.a_tn_sensor3, asensor_info.a_tn_sensor4); seq_printf(m, "a_diff1: %d, a_diff2: %d, a_diff3: %d, a_diff4: %d\n", asensor_info.a_diff1, asensor_info.a_diff2, asensor_info.a_diff3, asensor_info.a_diff4); seq_printf(m, "tj_max: %d, lvts5_0_y_temperature: %d, leakage_power: %d\n", asensor_info.tj_max, asensor_info.lvts5_0_y_temperature, asensor_info.leakage_power); mutex_unlock(&gpufreq_debug_lock); return GPUFREQ_SUCCESS; } static int mfgsys_config_proc_show(struct seq_file *m, void *v) { const struct gpufreq_adj_info *aging_table_gpu = NULL; const struct gpufreq_adj_info *aging_table_stack = NULL; const struct gpufreq_adj_info *avs_table_gpu = NULL; const struct gpufreq_adj_info *avs_table_stack = NULL; const struct gpufreq_gpm3_info *gpm3_table = NULL; int i = 0; int adj_num = GPUFREQ_MAX_ADJ_NUM; int gpm3_num = GPUFREQ_MAX_GPM3_NUM; mutex_lock(&gpufreq_debug_lock); aging_table_gpu = g_shared_status->aging_table_gpu; aging_table_stack = g_shared_status->aging_table_stack; avs_table_gpu = g_shared_status->avs_table_gpu; avs_table_stack = g_shared_status->avs_table_stack; gpm3_table = g_shared_status->gpm3_table; seq_printf(m, "%-8s AgingSensor: %s, AgingLoad: %s, AgingMargin: %s\n", "[AGING]", g_shared_status->asensor_enable ? "On" : "Off", g_shared_status->aging_load ? "On" : "Off", g_shared_status->aging_margin ? "On" : "Off"); seq_printf(m, "%-8s AVS: %s, AVSMargin: %s\n", "[AVS]", g_shared_status->avs_enable ? "On" : "Off", g_shared_status->avs_margin ? "On" : "Off"); seq_printf(m, "%-8s GPM1.0: %s, GPM3.0: %s\n", "[GPM]", g_shared_status->gpm1_mode ? "On" : "Off", g_shared_status->gpm3_mode ? "On" : "Off"); seq_printf(m, "%-8s TemperComp: %s, HTTemperComp: %s\n", "[TEMPER]", g_shared_status->temper_comp_mode ? "On" : "Off", g_shared_status->ht_temper_comp_mode ? "On" : "Off"); seq_printf(m, "%-8s IPS: %s, Vmin: %d (0x%x)\n", "[IPS]", g_shared_status->ips_mode ? "On" : "Off", g_shared_status->ips_info.vmin_val, g_shared_status->ips_info.vmin_reg_val); seq_printf(m, "%-8s AutoKResult: %s (Trim: 0x%x, 0x%x, 0x%x)\n", "[IPS]", g_shared_status->ips_info.autok_result ? "Pass" : "Fail", g_shared_status->ips_info.autok_trim0, g_shared_status->ips_info.autok_trim1, g_shared_status->ips_info.autok_trim2); seq_printf(m, "%-8s RandomOPP: %s, TestMode: %s\n", "[Misc]", g_shared_status->stress_test ? "On" : "Off", g_shared_status->test_mode ? "On" : "Off"); seq_puts(m, "\n[##*] [TOP Vaging] [##*] [TOP Vavs] [##*] [STK Vaging] [##*] [STK Vavs]\n"); for (i = 0; i < adj_num; i++) { seq_printf(m, "[%02d*] %12d [%02d*] %10d [%02d*] %12d [%02d*] %10d\n", aging_table_gpu[i].oppidx, aging_table_gpu[i].volt, avs_table_gpu[i].oppidx, avs_table_gpu[i].volt, aging_table_stack[i].oppidx, aging_table_stack[i].volt, avs_table_stack[i].oppidx, avs_table_stack[i].volt); } seq_puts(m, "\n[Temper] [Ceiling] [I_STACK] [I_SRAM] [P_STACK]\n"); for (i = 0; i < gpm3_num; i++) { seq_printf(m, "[%6d] %9d %9d %8d %9d\n", gpm3_table[i].temper, gpm3_table[i].ceiling, gpm3_table[i].i_stack, gpm3_table[i].i_sram, gpm3_table[i].p_stack); } mutex_unlock(&gpufreq_debug_lock); return GPUFREQ_SUCCESS; } static ssize_t mfgsys_config_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { int ret = GPUFREQ_SUCCESS; char buf[64], input_target[32], input_val[32]; unsigned int len = 0; enum gpufreq_config_target target = CONFIG_TARGET_INVALID; enum gpufreq_config_value val = CONFIG_VAL_INVALID; len = (count < (sizeof(buf) - 1)) ? count : (sizeof(buf) - 1); if (copy_from_user(buf, buffer, len)) { ret = GPUFREQ_EINVAL; goto done; } buf[len] = '\0'; mutex_lock(&gpufreq_debug_lock); if (sscanf(buf, "%14s %10s", input_target, input_val) == 2) { /* parsing */ if (sysfs_streq(input_target, "test_mode")) { target = CONFIG_TEST_MODE; ret = kstrtouint(input_val, 16, &val); if (ret) val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "stress_test")) { target = CONFIG_STRESS_TEST; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; } else if (sysfs_streq(input_target, "margin")) { target = CONFIG_MARGIN; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; /* only allow enable/disable once */ if (g_debug_margin_mode ^ val) g_debug_margin_mode = val; else val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "gpm1")) { target = CONFIG_GPM1; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; } else if (sysfs_streq(input_target, "gpm3")) { target = CONFIG_GPM3; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; } else if (sysfs_streq(input_target, "dfd")) { target = CONFIG_DFD; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; else if (sysfs_streq(input_val, "force_dump")) val = DFD_FORCE_DUMP; } else if (sysfs_streq(input_target, "imax_stack")) { target = CONFIG_IMAX_STACK; ret = kstrtouint(input_val, 10, &val); if (ret) val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "imax_sram")) { target = CONFIG_IMAX_SRAM; ret = kstrtouint(input_val, 10, &val); if (ret) val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "pmax_stack")) { target = CONFIG_PMAX_STACK; ret = kstrtouint(input_val, 10, &val); if (ret) val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "dyn_stack")) { target = CONFIG_DYN_STACK; ret = kstrtouint(input_val, 10, &val); if (ret) val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "dyn_sram_gpu")) { target = CONFIG_DYN_SRAM_GPU; ret = kstrtouint(input_val, 10, &val); if (ret) val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "dyn_sram_stack")) { target = CONFIG_DYN_SRAM_STACK; ret = kstrtouint(input_val, 10, &val); if (ret) val = CONFIG_VAL_INVALID; } else if (sysfs_streq(input_target, "ips")) { target = CONFIG_IPS; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; else if (sysfs_streq(input_val, "get")) val = IPS_VMIN_GET; } else if (sysfs_streq(input_target, "mcuetm_clk")) { target = CONFIG_MCUETM_CLK; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; } else if (sysfs_streq(input_target, "ptp3")) { target = CONFIG_PTP3; if (sysfs_streq(input_val, "enable")) val = FEAT_ENABLE; else if (sysfs_streq(input_val, "disable")) val = FEAT_DISABLE; } /* set to mfgsys if valid */ if (target != CONFIG_TARGET_INVALID && val != CONFIG_VAL_INVALID) gpufreq_set_mfgsys_config(target, val); } mutex_unlock(&gpufreq_debug_lock); done: return (ret < 0) ? ret : count; } #if GPUFREQ_MSSV_TEST_MODE static int mssv_test_proc_show(struct seq_file *m, void *v) { mutex_lock(&gpufreq_debug_lock); seq_printf(m, "%-8s DVFSState: 0x%04x\n", "[Common]", g_shared_status->dvfs_state); seq_printf(m, "%-8s Freq: %7d, Volt: %7d, Vsram: %7d\n", "[GPU]", g_shared_status->cur_fgpu, g_shared_status->cur_vgpu, g_shared_status->cur_vsram_gpu); seq_printf(m, "%-8s Freq: %7d, Volt: %7d, Vsram: %7d\n", "[STACK]", g_shared_status->cur_fstack, g_shared_status->cur_vstack, g_shared_status->cur_vsram_stack); seq_printf(m, "%-8s STACK_SEL(0x%08x[31]): %d, DEL_SEL(0x%08x[0]): %d\n", "[SEL]", g_shared_status->reg_stack_sel.addr, (g_shared_status->reg_stack_sel.val & BIT(31)) ? 1 : 0, g_shared_status->reg_del_sel.addr, (g_shared_status->reg_del_sel.val & BIT(0)) ? 1 : 0); mutex_unlock(&gpufreq_debug_lock); return GPUFREQ_SUCCESS; } static ssize_t mssv_test_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { int ret = GPUFREQ_SUCCESS; char buf[64], cmd[32]; unsigned int len = 0, val = 0; unsigned int target = TARGET_MSSV_INVALID; len = (count < (sizeof(buf) - 1)) ? count : (sizeof(buf) - 1); if (copy_from_user(buf, buffer, len)) { ret = GPUFREQ_EINVAL; goto done; } buf[len] = '\0'; mutex_lock(&gpufreq_debug_lock); if (sscanf(buf, "%8s %7d", cmd, &val) == 2) { if (sysfs_streq(cmd, "fgpu")) target = TARGET_MSSV_FGPU; else if (sysfs_streq(cmd, "vgpu")) target = TARGET_MSSV_VGPU; else if (sysfs_streq(cmd, "fstack")) target = TARGET_MSSV_FSTACK; else if (sysfs_streq(cmd, "vstack")) target = TARGET_MSSV_VSTACK; else if (sysfs_streq(cmd, "vsram")) target = TARGET_MSSV_VSRAM; else if (sysfs_streq(cmd, "stacksel")) target = TARGET_MSSV_STACK_SEL; else if (sysfs_streq(cmd, "delsel")) target = TARGET_MSSV_DEL_SEL; else { GPUFREQ_LOGE("invalid MSSV cmd: %s", cmd); ret = GPUFREQ_EINVAL; goto done_unlock; } ret = gpufreq_mssv_commit(target, val); if (ret) GPUFREQ_LOGE("fail to commit: %s, val: %d (%d)", cmd, val, ret); } done_unlock: mutex_unlock(&gpufreq_debug_lock); done: return (ret < 0) ? ret : count; } #endif /* GPUFREQ_MSSV_TEST_MODE */ /* PROCFS : initialization */ PROC_FOPS_RO(gpufreq_status); PROC_FOPS_RO(gpu_working_opp_table); PROC_FOPS_RO(gpu_signed_opp_table); PROC_FOPS_RO(stack_working_opp_table); PROC_FOPS_RO(stack_signed_opp_table); PROC_FOPS_RO(asensor_info); PROC_FOPS_RW(limit_table); PROC_FOPS_RW(fix_target_opp_index); PROC_FOPS_RW(fix_custom_freq_volt); PROC_FOPS_RW(mfgsys_power_control); PROC_FOPS_RW(mfgsys_config); #if GPUFREQ_MSSV_TEST_MODE PROC_FOPS_RW(mssv_test); #endif /* GPUFREQ_MSSV_TEST_MODE */ static int gpufreq_create_procfs(void) { struct proc_dir_entry *dir = NULL; int i = 0; struct procfs_entry { const char *name; const struct proc_ops *fops; }; const struct procfs_entry default_entries[] = { PROC_ENTRY(gpufreq_status), PROC_ENTRY(gpu_working_opp_table), PROC_ENTRY(gpu_signed_opp_table), PROC_ENTRY(asensor_info), PROC_ENTRY(limit_table), PROC_ENTRY(fix_target_opp_index), PROC_ENTRY(fix_custom_freq_volt), PROC_ENTRY(mfgsys_power_control), PROC_ENTRY(mfgsys_config), #if GPUFREQ_MSSV_TEST_MODE PROC_ENTRY(mssv_test), #endif /* GPUFREQ_MSSV_TEST_MODE */ }; const struct procfs_entry dualbuck_entries[] = { PROC_ENTRY(stack_working_opp_table), PROC_ENTRY(stack_signed_opp_table), }; dir = proc_mkdir(GPUFREQ_DIR_NAME, NULL); if (!dir) { GPUFREQ_LOGE("fail to create /proc/%s (ENOMEM)", GPUFREQ_DIR_NAME); return GPUFREQ_ENOMEM; } for (i = 0; i < ARRAY_SIZE(default_entries); i++) { if (!proc_create(default_entries[i].name, 0660, dir, default_entries[i].fops)) GPUFREQ_LOGE("fail to create /proc/%s/%s", GPUFREQ_DIR_NAME, default_entries[i].name); } if (g_dual_buck){ for (i = 0; i < ARRAY_SIZE(dualbuck_entries); i++) { if (!proc_create(dualbuck_entries[i].name, 0660, dir, dualbuck_entries[i].fops)) GPUFREQ_LOGE("fail to create /proc/gpufreqv2/%s", dualbuck_entries[i].name); } } return GPUFREQ_SUCCESS; } #endif /* CONFIG_PROC_FS */ #if defined(CONFIG_DEBUG_FS) static int history_debug_show(struct seq_file *m, void *v) { int ret = GPUFREQ_SUCCESS; int i = 0; const unsigned int *history_log = NULL; mutex_lock(&gpufreq_debug_lock); history_log = gpufreq_history_get_log(); if (!history_log) { GPUFREQ_LOGE("fail to get history log (ENOENT)"); ret = GPUFREQ_ENOENT; goto done; } for (i = 0; i < GPUFREQ_HISTORY_SIZE; i++) seq_printf(m, "%08x", history_log[i]); done: mutex_unlock(&gpufreq_debug_lock); return ret; } /* DEBUGFS : initialization */ DEBUG_FOPS_RO(history); static int gpufreq_create_debugfs(void) { struct dentry *dir = NULL; int i = 0; struct debugfs_entry { const char *name; const struct file_operations *fops; }; const struct debugfs_entry default_entries[] = { DEBUG_ENTRY(history), }; dir = debugfs_create_dir(GPUFREQ_DIR_NAME, NULL); if (!dir) { GPUFREQ_LOGE("fail to create /sys/kernel/debug/%s", GPUFREQ_DIR_NAME); return GPUFREQ_ENOMEM; } for (i = 0; i < ARRAY_SIZE(default_entries); i++) { if (!debugfs_create_file(default_entries[i].name, 0444, dir, NULL, default_entries[i].fops)) GPUFREQ_LOGE("fail to create /sys/kernel/debug/%s/%s", GPUFREQ_DIR_NAME, default_entries[i].name); } return GPUFREQ_SUCCESS; } #endif /* CONFIG_DEBUG_FS */ void gpufreq_debug_init(unsigned int dual_buck, unsigned int gpueb_support, const struct gpufreq_shared_status *shared_status) { int ret = GPUFREQ_SUCCESS; g_dual_buck = dual_buck; g_gpueb_support = gpueb_support; g_debug_power_state = POWER_OFF; g_debug_margin_mode = FEAT_ENABLE; /* take every info of mfgsys from shared status */ if (shared_status) g_shared_status = shared_status; else { GPUFREQ_LOGE("null gpufreq shared status: 0x%llx", shared_status); BUG_ON(1); } ret = gpufreq_history_init(); if (ret) GPUFREQ_LOGE("fail to init gpufreq history"); #if defined(CONFIG_PROC_FS) ret = gpufreq_create_procfs(); if (ret) GPUFREQ_LOGE("fail to create procfs (%d)", ret); #endif /* CONFIG_PROC_FS */ #if defined(CONFIG_DEBUG_FS) ret = gpufreq_create_debugfs(); if (ret) GPUFREQ_LOGE("fail to create debugfs (%d)", ret); #endif /* CONFIG_DEBUG_FS */ }