static void mmdvfs_dump_info(void) { MMDVFSMSG("CMD %d %d %d\n", g_mmdvfs_cmd.sensor_size, g_mmdvfs_cmd.sensor_fps, g_mmdvfs_cmd.camera_mode); MMDVFSMSG("INFO VR %d %d\n", g_mmdvfs_info->video_record_size[0], g_mmdvfs_info->video_record_size[1]); }
int mmdvfs_set_step(MTK_SMI_BWC_SCEN scenario, mmdvfs_voltage_enum step) { int i, scen_index; mmdvfs_voltage_enum final_step = mmdvfs_get_default_step(); #if !MMDVFS_ENABLE return 0; #endif #if defined(SMI_D1) /* D1 FHD always HPM. do not have to trigger vcore dvfs. */ if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_FHD) return 0; #endif MMDVFSMSG("MMDVFS set voltage scen %d step %d\n", scenario, step); if ((scenario >= MMDVFS_SCEN_COUNT) || (scenario < SMI_BWC_SCEN_NORMAL)) { MMDVFSERR("invalid scenario\n"); return -1; } /* dump information */ mmdvfs_dump_info(); /* go through all scenarios to decide the final step */ scen_index = (int)scenario; spin_lock(&g_mmdvfs_mgr->scen_lock); g_mmdvfs_scenario_voltage[scen_index] = step; /* one high = final high */ for (i = 0; i < MMDVFS_SCEN_COUNT; i++) { if (g_mmdvfs_scenario_voltage[i] == MMDVFS_VOLTAGE_HIGH) { final_step = MMDVFS_VOLTAGE_HIGH; break; } } g_mmdvfs_current_step = final_step; spin_unlock(&g_mmdvfs_mgr->scen_lock); MMDVFSMSG("MMDVFS set voltage scen %d step %d final %d\n", scenario, step, final_step); #if MMDVFS_ENABLE /* call vcore dvfs API */ if (final_step == MMDVFS_VOLTAGE_HIGH) vcorefs_request_dvfs_opp(KIR_MM, OPPI_PERF); else vcorefs_request_dvfs_opp(KIR_MM, OPPI_UNREQ); #endif return 0; }
void mmdvfs_handle_cmd(MTK_MMDVFS_CMD *cmd) { #if !MMDVFS_ENABLE return; #endif MMDVFSMSG("MMDVFS cmd %u %d\n", cmd->type, cmd->scen); switch (cmd->type) { case MTK_MMDVFS_CMD_TYPE_SET: /* save cmd */ mmdvfs_update_cmd(cmd); cmd->ret = mmdvfs_set_step(cmd->scen, mmdvfs_query(cmd->scen, cmd)); break; case MTK_MMDVFS_CMD_TYPE_QUERY: { /* query with some parameters */ if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_FHD) { /* QUERY ALWAYS HIGH for FHD */ cmd->ret = (unsigned int)MMDVFS_STEP_HIGH2HIGH; } else { /* FHD */ mmdvfs_voltage_enum query_voltage = mmdvfs_query(cmd->scen, cmd); mmdvfs_voltage_enum current_voltage = mmdvfs_get_current_step(); if (current_voltage < query_voltage) { cmd->ret = (unsigned int)MMDVFS_STEP_LOW2HIGH; } else if (current_voltage > query_voltage) { cmd->ret = (unsigned int)MMDVFS_STEP_HIGH2LOW; } else { cmd->ret = (unsigned int)(query_voltage == MMDVFS_VOLTAGE_HIGH ? MMDVFS_STEP_HIGH2HIGH : MMDVFS_STEP_LOW2LOW); } } MMDVFSMSG("query %d\n", cmd->ret); /* cmd->ret = (unsigned int)query_voltage; */ break; } default: MMDVFSMSG("invalid mmdvfs cmd\n"); BUG(); break; } }
void mmdvfs_notify_scenario_concurrency(unsigned int u4Concurrency) { /* raise EMI monitor BW threshold in VP, VR, VR SLOW motion cases to make sure vcore stay MMDVFS level as long as possible */ if (u4Concurrency & ((1 << SMI_BWC_SCEN_VP) | (1 << SMI_BWC_SCEN_VR) | (1 << SMI_BWC_SCEN_VR_SLOW))) { #if MMDVFS_ENABLE MMDVFSMSG("fliper high\n"); fliper_set_bw(BW_THRESHOLD_HIGH); #endif } else { #if MMDVFS_ENABLE MMDVFSMSG("fliper normal\n"); fliper_restore_bw(); #endif } }
void mmdvfs_notify_scenario_enter(MTK_SMI_BWC_SCEN scen) { #if !MMDVFS_ENABLE return; #endif MMDVFSMSG("enter %d\n", scen); /* ISP ON = high */ switch (scen) { #if defined(SMI_D2) /* d2 sensor > 6M */ case SMI_BWC_SCEN_VR: mmdvfs_set_step(scen, mmdvfs_query(scen, NULL)); break; case SMI_BWC_SCEN_VR_SLOW: #elif defined(SMI_D1) /* default VR high */ case SMI_BWC_SCEN_VR: case SMI_BWC_SCEN_VR_SLOW: #else /* D3 */ case SMI_BWC_SCEN_WFD: case SMI_BWC_SCEN_VSS: #endif /* Fall through */ case SMI_BWC_SCEN_ICFP: /* Fall through */ case SMI_BWC_SCEN_FORCE_MMDVFS: mmdvfs_set_step(scen, MMDVFS_VOLTAGE_HIGH); break; default: break; } }
void mmdvfs_notify_scenario_enter(MTK_SMI_BWC_SCEN scen) { #if !MMDVFS_ENABLE return; #endif MMDVFSMSG("enter %d\n", scen); if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_WQHD) { #if MMDVFS_ENABLE_WQHD if (scen == SMI_BWC_SCEN_VP) { mmdvfs_start_gpu_monitor(&g_mmdvfs_mgr->gpu_monitor); } #endif /* MMDVFS_ENABLE_WQHD */ } else { /* FHD */ switch (scen) { case SMI_BWC_SCEN_ICFP: mmdvfs_set_step(scen, MMDVFS_VOLTAGE_HIGH); break; case SMI_BWC_SCEN_VR: case SMI_BWC_SCEN_VR_SLOW: mmdvfs_set_step(scen, mmdvfs_query(scen, NULL)); /* workaround for ICFP...its mmdvfs_set() will come after leaving ICFP */ mmdvfs_set_step(SMI_BWC_SCEN_ICFP, mmdvfs_get_default_step()); break; default: break; } } }
static void mmdvfs_start_cam_monitor(void) { mmdvfs_stop_cam_monitor(); MMDVFSMSG("CAM start %d\n", jiffies_to_msecs(jiffies)); mmdvfs_set_step(MMDVFS_CAM_MON_SCEN, MMDVFS_VOLTAGE_HIGH); /* 4 seconds for PIP switch preview aspect delays... */ schedule_delayed_work(&g_mmdvfs_cam_work, MMDVFS_CAM_MON_DELAY); }
static void mmdvfs_update_cmd(MTK_MMDVFS_CMD *cmd) { if (cmd == NULL) return; if (cmd->sensor_size) g_mmdvfs_cmd.sensor_size = cmd->sensor_size; if (cmd->sensor_fps) g_mmdvfs_cmd.sensor_fps = cmd->sensor_fps; MMDVFSMSG("update cm %d %d\n", cmd->camera_mode, cmd->sensor_size); g_mmdvfs_cmd.camera_mode = cmd->camera_mode; }
void mmdvfs_notify_scenario_exit(MTK_SMI_BWC_SCEN scen) { #if !MMDVFS_ENABLE return; #endif MMDVFSMSG("leave %d\n", scen); if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_WQHD) { #if MMDVFS_ENABLE_WQHD if (scen == SMI_BWC_SCEN_VP) { mmdvfs_stop_gpu_monitor(&g_mmdvfs_mgr->gpu_monitor); } #endif /* MMDVFS_ENABLE_WQHD */ } /* reset scenario voltage to default when it exits */ mmdvfs_set_step(scen, mmdvfs_get_default_step()); }
static void mmdvfs_update_cmd(MTK_MMDVFS_CMD *cmd) { if (cmd == NULL) { return; } if (cmd->sensor_size) { g_mmdvfs_cmd.sensor_size = cmd->sensor_size; } if (cmd->sensor_fps) { g_mmdvfs_cmd.sensor_fps = cmd->sensor_fps; } MMDVFSMSG("update cm %d\n", cmd->camera_mode); // if (cmd->camera_mode != MMDVFS_CAMERA_MODE_FLAG_DEFAULT) { g_mmdvfs_cmd.camera_mode = cmd->camera_mode; // } }
static void mmdvfs_timer_callback(unsigned long data) { mmdvfs_gpu_monitor_struct *gpu_monitor = (mmdvfs_gpu_monitor_struct *)data; unsigned int gpu_loading = 0; if (mtk_get_gpu_loading(&gpu_loading)) { // MMDVFSMSG("gpuload %d %ld\n", gpu_loading, jiffies_to_msecs(jiffies)); } /* store gpu loading into the array */ gpu_monitor->gpu_loadings[gpu_monitor->gpu_loading_index++] = gpu_loading; /* fire another timer until the end */ if (gpu_monitor->gpu_loading_index < MMDVFS_GPU_LOADING_NUM - 1) { mod_timer(&gpu_monitor->timer, jiffies + msecs_to_jiffies(MMDVFS_GPU_LOADING_SAMPLE_DURATION_IN_MS)); } else { /* the final timer */ int i; int avg_loading; unsigned int sum = 0; for (i = MMDVFS_GPU_LOADING_START_INDEX; i < MMDVFS_GPU_LOADING_NUM; i++) { sum += gpu_monitor->gpu_loadings[i]; } avg_loading = sum / MMDVFS_GPU_LOADING_NUM; MMDVFSMSG("gpuload %d AVG %d\n", jiffies_to_msecs(jiffies), avg_loading); /* drops to low step if the gpu loading is low */ if (avg_loading <= MMDVFS_GPU_LOADING_THRESHOLD) { queue_work(gpu_monitor->work_queue, &gpu_monitor->work); } } }
void mmdvfs_notify_scenario_exit(MTK_SMI_BWC_SCEN scen) { #if !MMDVFS_ENABLE return; #endif MMDVFSMSG("leave %d\n", scen); #if !defined(SMI_D3) /* d3 does not need this workaround because the MMCLK is always the highest */ /* * keep HPM for 4 seconds after exiting camera scenarios to get rid of * cam framework will let us go to normal scenario for a short time * (ex: STOP PREVIEW --> NORMAL --> START PREVIEW) * where the LPM mode (low MMCLK) may cause ISP failures */ if ((scen == SMI_BWC_SCEN_VR) || (scen == SMI_BWC_SCEN_VR_SLOW) || (scen == SMI_BWC_SCEN_ICFP)) { mmdvfs_start_cam_monitor(); } #endif /* !defined(SMI_D3) */ /* reset scenario voltage to default when it exits */ mmdvfs_set_step(scen, mmdvfs_get_default_step()); }
static void mmdvfs_cam_work_handler(struct work_struct *work) { MMDVFSMSG("CAM handler %d\n", jiffies_to_msecs(jiffies)); mmdvfs_set_step(MMDVFS_CAM_MON_SCEN, mmdvfs_get_default_step()); }
int mmdvfs_set_step(MTK_SMI_BWC_SCEN scenario, mmdvfs_voltage_enum step) { int i, scen_index; mmdvfs_voltage_enum final_step = mmdvfs_get_default_step(); #if !MMDVFS_ENABLE return 0; #endif #if !MMDVFS_ENABLE_WQHD /* do nothing if disable MMDVFS in WQHD */ if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_WQHD) { return 0; } #endif /* MMDVFS_ENABLE_WQHD */ MMDVFSMSG("MMDVFS set voltage scen %d step %d\n", scenario, step); if (scenario >= SMI_BWC_SCEN_CNT || (scenario < SMI_BWC_SCEN_NORMAL)) { MMDVFSERR("invalid scenario\n"); return -1; } /* dump information */ mmdvfs_dump_info(); /* go through all scenarios to decide the final step */ scen_index = (int)scenario; spin_lock(&g_mmdvfs_mgr->scen_lock); g_mmdvfs_scenario_voltage[scen_index] = step; /* one high = final high */ for (i = 0; i < SMI_BWC_SCEN_CNT; i++) { if (g_mmdvfs_scenario_voltage[i] == MMDVFS_VOLTAGE_HIGH) { final_step = MMDVFS_VOLTAGE_HIGH; break; } } g_mmdvfs_current_step = final_step; spin_unlock(&g_mmdvfs_mgr->scen_lock); MMDVFSMSG("MMDVFS set voltage scen %d step %d final %d\n", scenario, step, final_step); #if MMDVFS_ENABLE /* call vcore dvfs API */ if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_WQHD) { /* WQHD */ // TODO: use final_step and retry vcore dvfs MMDVFSMSG("HIGH to %d\n", step); if (step == MMDVFS_VOLTAGE_LOW) { vcorefs_request_dvfs_opp(KR_MM_SCEN, OPPI_LOW_PWR); } else { vcorefs_request_dvfs_opp(KR_MM_SCEN, OPPI_UNREQ); } } else { /* FHD */ MMDVFSMSG("FHD %d\n", final_step); if (final_step == MMDVFS_VOLTAGE_HIGH) { vcorefs_request_dvfs_opp(KR_MM_SCEN, OPPI_PERF); } else { vcorefs_request_dvfs_opp(KR_MM_SCEN, OPPI_UNREQ); } } #endif return 0; }
static void mmdvfs_gpu_monitor_work(struct work_struct *work) { MMDVFSMSG("WQ %d\n", jiffies_to_msecs(jiffies)); }