/* * Samsung Exynos5 SoC series FIMC-IS driver * * exynos5 fimc-is core functions * * Copyright (c) 2011 Samsung Electronics Co., Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #ifdef CONFIG_SCHED_EMS #include #endif #include "fimc-is-core.h" #include "fimc-is-dvfs.h" #include "fimc-is-hw-dvfs.h" #include #ifdef CONFIG_PM_DEVFREQ #if defined(QOS_INTCAM) extern struct pm_qos_request exynos_isp_qos_int_cam; #endif extern struct pm_qos_request exynos_isp_qos_int; extern struct pm_qos_request exynos_isp_qos_mem; extern struct pm_qos_request exynos_isp_qos_cam; extern struct pm_qos_request exynos_isp_qos_hpg; #ifdef CONFIG_SCHED_EMS extern struct gb_qos_request gb_req; #endif static inline int fimc_is_get_start_sensor_cnt(struct fimc_is_core *core) { int i, sensor_cnt = 0; for (i = 0; i < FIMC_IS_SENSOR_COUNT; i++) if (test_bit(FIMC_IS_SENSOR_OPEN, &(core->sensor[i].state))) sensor_cnt++; return sensor_cnt; } #ifdef BDS_DVFS static int fimc_is_get_bds_size(struct fimc_is_device_ischain *device) { int resol = 0; struct fimc_is_group *group; group = &device->group_3aa; if (!test_bit(FIMC_IS_GROUP_INIT, &group->state)) return resol; resol = device->txp.output.width * device->txp.output.height; return resol; } #else static int fimc_is_get_target_resol(struct fimc_is_device_ischain *device) { int resol = 0; #ifdef SOC_MCS int i = 0; struct fimc_is_group *group; group = &device->group_mcs; if (!test_bit(FIMC_IS_GROUP_INIT, &group->state)) return resol; for (i = ENTRY_M0P; i <= ENTRY_M4P; i++) if (group->subdev[i] && test_bit(FIMC_IS_SUBDEV_START, &(group->subdev[i]->state))) resol = max_t(int, resol, group->subdev[i]->output.width * group->subdev[i]->output.height); #else resol = device->scp.output.width * device->scp.output.height; #endif return resol; } #endif int fimc_is_dvfs_init(struct fimc_is_resourcemgr *resourcemgr) { int ret = 0; struct fimc_is_dvfs_ctrl *dvfs_ctrl; FIMC_BUG(!resourcemgr); dvfs_ctrl = &resourcemgr->dvfs_ctrl; #if defined(QOS_INTCAM) dvfs_ctrl->cur_int_cam_qos = 0; #endif dvfs_ctrl->cur_int_qos = 0; dvfs_ctrl->cur_mif_qos = 0; dvfs_ctrl->cur_cam_qos = 0; dvfs_ctrl->cur_i2c_qos = 0; dvfs_ctrl->cur_disp_qos = 0; dvfs_ctrl->cur_hpg_qos = 0; dvfs_ctrl->cur_hmp_bst = 0; /* init spin_lock for clock gating */ mutex_init(&dvfs_ctrl->lock); if (!(dvfs_ctrl->static_ctrl)) dvfs_ctrl->static_ctrl = kzalloc(sizeof(struct fimc_is_dvfs_scenario_ctrl), GFP_KERNEL); if (!(dvfs_ctrl->dynamic_ctrl)) dvfs_ctrl->dynamic_ctrl = kzalloc(sizeof(struct fimc_is_dvfs_scenario_ctrl), GFP_KERNEL); if (!(dvfs_ctrl->external_ctrl)) dvfs_ctrl->external_ctrl = kzalloc(sizeof(struct fimc_is_dvfs_scenario_ctrl), GFP_KERNEL); if (!dvfs_ctrl->static_ctrl || !dvfs_ctrl->dynamic_ctrl || !dvfs_ctrl->external_ctrl) { err("dvfs_ctrl alloc is failed!!\n"); return -ENOMEM; } /* assign static / dynamic scenario check logic data */ ret = fimc_is_hw_dvfs_init((void *)dvfs_ctrl); if (ret) { err("fimc_is_hw_dvfs_init is failed(%d)\n", ret); return -EINVAL; } /* default value is 0 */ dvfs_ctrl->dvfs_table_idx = 0; clear_bit(FIMC_IS_DVFS_SEL_TABLE, &dvfs_ctrl->state); return 0; } int fimc_is_dvfs_sel_table(struct fimc_is_resourcemgr *resourcemgr) { int ret = 0; struct fimc_is_dvfs_ctrl *dvfs_ctrl; u32 dvfs_table_idx = 0; FIMC_BUG(!resourcemgr); dvfs_ctrl = &resourcemgr->dvfs_ctrl; if (test_bit(FIMC_IS_DVFS_SEL_TABLE, &dvfs_ctrl->state)) return 0; #if defined(EXPANSION_DVFS_TABLE) switch(resourcemgr->hal_version) { case IS_HAL_VER_1_0: dvfs_table_idx = 0; break; case IS_HAL_VER_3_2: dvfs_table_idx = 1; break; default: err("hal version is unknown"); dvfs_table_idx = 0; ret = -EINVAL; break; } #endif if (dvfs_table_idx >= dvfs_ctrl->dvfs_table_max) { err("dvfs index(%d) is invalid", dvfs_table_idx); ret = -EINVAL; goto p_err; } resourcemgr->dvfs_ctrl.dvfs_table_idx = dvfs_table_idx; set_bit(FIMC_IS_DVFS_SEL_TABLE, &dvfs_ctrl->state); p_err: info("[RSC] %s(%d):%d\n", __func__, dvfs_table_idx, ret); return ret; } int fimc_is_dvfs_sel_static(struct fimc_is_device_ischain *device) { struct fimc_is_core *core; struct fimc_is_dvfs_ctrl *dvfs_ctrl; struct fimc_is_dvfs_scenario_ctrl *static_ctrl; struct fimc_is_dvfs_scenario *scenarios; struct fimc_is_resourcemgr *resourcemgr; struct fimc_is_dual_info *dual_info; int i, scenario_id, scenario_cnt; int position, resol, fps, stream_cnt; unsigned long sensor_map; FIMC_BUG(!device); FIMC_BUG(!device->interface); core = (struct fimc_is_core *)device->interface->core; resourcemgr = device->resourcemgr; dvfs_ctrl = &(resourcemgr->dvfs_ctrl); static_ctrl = dvfs_ctrl->static_ctrl; if (!test_bit(FIMC_IS_DVFS_SEL_TABLE, &dvfs_ctrl->state)) { err("dvfs table is NOT selected"); return -EINVAL; } /* static scenario */ if (!static_ctrl) { err("static_dvfs_ctrl is NULL"); return -EINVAL; } if (static_ctrl->scenario_cnt == 0) { pr_debug("static_scenario's count is zero"); return -EINVAL; } scenarios = static_ctrl->scenarios; scenario_cnt = static_ctrl->scenario_cnt; position = fimc_is_sensor_g_position(device->sensor); #ifdef BDS_DVFS resol = fimc_is_get_bds_size(device); #else resol = fimc_is_get_target_resol(device); #endif fps = fimc_is_sensor_g_framerate(device->sensor); stream_cnt = fimc_is_get_start_sensor_cnt(core); sensor_map = core->sensor_map; dual_info = &core->dual_info; for (i = 0; i < scenario_cnt; i++) { if (!scenarios[i].check_func) { warn("check_func[%d] is NULL\n", i); continue; } if ((scenarios[i].check_func(device, NULL, position, resol, fps, stream_cnt, sensor_map, dual_info)) > 0) { scenario_id = scenarios[i].scenario_id; static_ctrl->cur_scenario_id = scenario_id; static_ctrl->cur_scenario_idx = i; static_ctrl->cur_frame_tick = scenarios[i].keep_frame_tick; return scenario_id; } } warn("couldn't find static dvfs scenario [sensor:(%d/%d)/fps:%d/setfile:%d/resol:(%d)]\n", fimc_is_get_start_sensor_cnt(core), device->sensor->pdev->id, fps, (device->setfile & FIMC_IS_SETFILE_MASK), resol); static_ctrl->cur_scenario_id = FIMC_IS_SN_DEFAULT; static_ctrl->cur_scenario_idx = -1; static_ctrl->cur_frame_tick = -1; return FIMC_IS_SN_DEFAULT; } int fimc_is_dvfs_sel_dynamic(struct fimc_is_device_ischain *device, struct fimc_is_group *group) { int ret; struct fimc_is_core *core; struct fimc_is_dvfs_ctrl *dvfs_ctrl; struct fimc_is_dvfs_scenario_ctrl *dynamic_ctrl; struct fimc_is_dvfs_scenario *scenarios; struct fimc_is_resourcemgr *resourcemgr; struct fimc_is_dual_info *dual_info; int i, scenario_id, scenario_cnt; int position, resol, fps; unsigned long sensor_map; FIMC_BUG(!device); core = (struct fimc_is_core *)device->interface->core; resourcemgr = device->resourcemgr; dvfs_ctrl = &(resourcemgr->dvfs_ctrl); dynamic_ctrl = dvfs_ctrl->dynamic_ctrl; if (!test_bit(FIMC_IS_DVFS_SEL_TABLE, &dvfs_ctrl->state)) { err("dvfs table is NOT selected"); return -EINVAL; } /* dynamic scenario */ if (!dynamic_ctrl) { err("dynamic_dvfs_ctrl is NULL"); return -EINVAL; } if (dynamic_ctrl->scenario_cnt == 0) { pr_debug("dynamic_scenario's count is zero"); return -EINVAL; } scenarios = dynamic_ctrl->scenarios; scenario_cnt = dynamic_ctrl->scenario_cnt; if (dynamic_ctrl->cur_frame_tick >= 0) { (dynamic_ctrl->cur_frame_tick)--; /* * when cur_frame_tick is lower than 0, clear current scenario. * This means that current frame tick to keep dynamic scenario * was expired. */ if (dynamic_ctrl->cur_frame_tick < 0) { dynamic_ctrl->cur_scenario_id = -1; dynamic_ctrl->cur_scenario_idx = -1; } } if (!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state) || group->id == GROUP_ID_VRA0) return -EAGAIN; position = fimc_is_sensor_g_position(device->sensor); #ifdef BDS_DVFS resol = fimc_is_get_bds_size(device); #else resol = fimc_is_get_target_resol(device); #endif fps = fimc_is_sensor_g_framerate(device->sensor); sensor_map = core->sensor_map; dual_info = &core->dual_info; for (i = 0; i < scenario_cnt; i++) { if (!scenarios[i].check_func) { warn("check_func[%d] is NULL\n", i); continue; } ret = scenarios[i].check_func(device, group, position, resol, fps, 0, sensor_map, dual_info); switch (ret) { case DVFS_MATCHED: scenario_id = scenarios[i].scenario_id; dynamic_ctrl->cur_scenario_id = scenario_id; dynamic_ctrl->cur_scenario_idx = i; dynamic_ctrl->cur_frame_tick = scenarios[i].keep_frame_tick; return scenario_id; case DVFS_SKIP: goto p_again; case DVFS_NOT_MATCHED: default: continue; } } p_again: return -EAGAIN; } int fimc_is_dvfs_sel_external(struct fimc_is_device_sensor *device) { struct fimc_is_core *core; struct fimc_is_dvfs_ctrl *dvfs_ctrl; struct fimc_is_dvfs_scenario_ctrl *external_ctrl; struct fimc_is_dvfs_scenario *scenarios; struct fimc_is_resourcemgr *resourcemgr; struct fimc_is_dual_info *dual_info; int i, scenario_id, scenario_cnt; int position, resol, fps, stream_cnt; unsigned long sensor_map; FIMC_BUG(!device); core = device->private_data; resourcemgr = device->resourcemgr; dvfs_ctrl = &(resourcemgr->dvfs_ctrl); external_ctrl = dvfs_ctrl->external_ctrl; if (!test_bit(FIMC_IS_DVFS_SEL_TABLE, &dvfs_ctrl->state)) { err("dvfs table is NOT selected"); return -EINVAL; } /* external scenario */ if (!external_ctrl) { warn("external_dvfs_ctrl is NULL, default max dvfs lv"); return FIMC_IS_SN_MAX; } scenarios = external_ctrl->scenarios; scenario_cnt = external_ctrl->scenario_cnt; position = fimc_is_sensor_g_position(device); resol = fimc_is_sensor_g_width(device) * fimc_is_sensor_g_height(device); fps = fimc_is_sensor_g_framerate(device); stream_cnt = fimc_is_get_start_sensor_cnt(core); sensor_map = core->sensor_map; dual_info = &core->dual_info; for (i = 0; i < scenario_cnt; i++) { if (!scenarios[i].ext_check_func) { warn("check_func[%d] is NULL\n", i); continue; } if ((scenarios[i].ext_check_func(device, position, resol, fps, stream_cnt, sensor_map, dual_info)) > 0) { scenario_id = scenarios[i].scenario_id; external_ctrl->cur_scenario_id = scenario_id; external_ctrl->cur_scenario_idx = i; external_ctrl->cur_frame_tick = scenarios[i].keep_frame_tick; return scenario_id; } } warn("couldn't find external dvfs scenario [sensor:(%d/%d)/fps:%d/resol:(%d)]\n", stream_cnt, position, fps, resol); external_ctrl->cur_scenario_id = FIMC_IS_SN_MAX; external_ctrl->cur_scenario_idx = -1; external_ctrl->cur_frame_tick = -1; return FIMC_IS_SN_MAX; } int fimc_is_get_qos(struct fimc_is_core *core, u32 type, u32 scenario_id) { struct exynos_platform_fimc_is *pdata = NULL; int qos = 0; u32 dvfs_idx = core->resourcemgr.dvfs_ctrl.dvfs_table_idx; pdata = core->pdata; if (pdata == NULL) { err("pdata is NULL\n"); return -EINVAL; } if (type >= FIMC_IS_DVFS_END) { err("Cannot find DVFS value"); return -EINVAL; } if (dvfs_idx >= FIMC_IS_DVFS_TABLE_IDX_MAX) { err("invalid dvfs index(%d)", dvfs_idx); dvfs_idx = 0; } qos = pdata->dvfs_data[dvfs_idx][scenario_id][type]; return qos; } int fimc_is_set_dvfs(struct fimc_is_core *core, struct fimc_is_device_ischain *device, u32 scenario_id) { int ret = 0; #if defined(QOS_INTCAM) int int_cam_qos, int_qos, mif_qos, i2c_qos, cam_qos, disp_qos, hpg_qos; #else int int_qos, mif_qos, i2c_qos, cam_qos, disp_qos, hpg_qos; #endif struct fimc_is_resourcemgr *resourcemgr; struct fimc_is_dvfs_ctrl *dvfs_ctrl; if (core == NULL) { err("core is NULL\n"); return -EINVAL; } resourcemgr = &core->resourcemgr; dvfs_ctrl = &(resourcemgr->dvfs_ctrl); #if defined(QOS_INTCAM) int_cam_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_INT_CAM, scenario_id); #endif int_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_INT, scenario_id); mif_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_MIF, scenario_id); i2c_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_I2C, scenario_id); cam_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CAM, scenario_id); disp_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_DISP, scenario_id); hpg_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_HPG, scenario_id); #if defined(QOS_INTCAM) if ((int_cam_qos < 0) || (int_qos < 0) || (mif_qos < 0) || (i2c_qos < 0) || (cam_qos < 0) || (disp_qos < 0)) { err("getting qos value is failed!!\n"); return -EINVAL; } #else if ((int_qos < 0) || (mif_qos < 0) || (i2c_qos < 0) || (cam_qos < 0) || (disp_qos < 0)) { err("getting qos value is failed!!\n"); return -EINVAL; } #endif #if defined(QOS_INTCAM) /* check current qos */ if (int_cam_qos && dvfs_ctrl->cur_int_cam_qos != int_cam_qos) { if (i2c_qos && device) { ret = fimc_is_itf_i2c_lock(device, i2c_qos, true); if (ret) { err("fimc_is_itf_i2_clock fail\n"); goto exit; } } pm_qos_update_request(&exynos_isp_qos_int_cam, int_cam_qos); dvfs_ctrl->cur_int_cam_qos = int_cam_qos; if (i2c_qos && device) { /* i2c unlock */ ret = fimc_is_itf_i2c_lock(device, i2c_qos, false); if (ret) { err("fimc_is_itf_i2c_unlock fail\n"); goto exit; } } } if (int_qos && dvfs_ctrl->cur_int_qos != int_qos) { pm_qos_update_request(&exynos_isp_qos_int, int_qos); dvfs_ctrl->cur_int_qos = int_qos; } #else /* check current qos */ if (int_qos && dvfs_ctrl->cur_int_qos != int_qos) { if (i2c_qos && device) { ret = fimc_is_itf_i2c_lock(device, i2c_qos, true); if (ret) { err("fimc_is_itf_i2_clock fail\n"); goto exit; } } pm_qos_update_request(&exynos_isp_qos_int, int_qos); dvfs_ctrl->cur_int_qos = int_qos; if (i2c_qos && device) { /* i2c unlock */ ret = fimc_is_itf_i2c_lock(device, i2c_qos, false); if (ret) { err("fimc_is_itf_i2c_unlock fail\n"); goto exit; } } } #endif if (mif_qos && dvfs_ctrl->cur_mif_qos != mif_qos) { pm_qos_update_request(&exynos_isp_qos_mem, mif_qos); dvfs_ctrl->cur_mif_qos = mif_qos; } if (cam_qos && dvfs_ctrl->cur_cam_qos != cam_qos) { pm_qos_update_request(&exynos_isp_qos_cam, cam_qos); dvfs_ctrl->cur_cam_qos = cam_qos; } #if defined(ENABLE_HMP_BOOST) /* hpg_qos : number of minimum online CPU */ if (hpg_qos && dvfs_ctrl->cur_hpg_qos != hpg_qos) { pm_qos_update_request(&exynos_isp_qos_hpg, hpg_qos); dvfs_ctrl->cur_hpg_qos = hpg_qos; #if defined(CONFIG_HMP_VARIABLE_SCALE) /* for migration to big core */ if (hpg_qos > 4) { if (!dvfs_ctrl->cur_hmp_bst) { set_hmp_boost(1); dvfs_ctrl->cur_hmp_bst = 1; } } else { if (dvfs_ctrl->cur_hmp_bst) { set_hmp_boost(0); dvfs_ctrl->cur_hmp_bst = 0; } } #elif defined(CONFIG_SCHED_EMS) /* for migration to big core */ if (hpg_qos > 4) { if (!dvfs_ctrl->cur_hmp_bst) { gb_qos_update_request(&gb_req, 100); dvfs_ctrl->cur_hmp_bst = 1; } } else { if (dvfs_ctrl->cur_hmp_bst) { gb_qos_update_request(&gb_req, 0); dvfs_ctrl->cur_hmp_bst = 0; } } #endif } #endif #if defined(QOS_INTCAM) info("[RSC:%d]: New QoS [INT_CAM(%d), INT(%d), MIF(%d), CAM(%d), DISP(%d), I2C(%d), HPG(%d, %d)]\n", device ? device->instance : 0, int_cam_qos, int_qos, mif_qos, cam_qos, disp_qos, i2c_qos, hpg_qos, dvfs_ctrl->cur_hmp_bst); #else info("[RSC:%d]: New QoS [INT(%d), MIF(%d), CAM(%d), DISP(%d), I2C(%d), HPG(%d, %d)]\n", device ? device->instance : 0, int_qos, mif_qos, cam_qos, disp_qos, i2c_qos, hpg_qos, dvfs_ctrl->cur_hmp_bst); #endif exit: return ret; } void fimc_is_dual_mode_update(struct fimc_is_device_ischain *device, struct fimc_is_group *group, struct fimc_is_frame *frame) { struct fimc_is_core *core = NULL; struct fimc_is_device_sensor *sensor = NULL; struct fimc_is_resourcemgr *resourcemgr = NULL; struct fimc_is_dual_info *dual_info = NULL; core = (struct fimc_is_core *)device->interface->core; sensor = device->sensor; resourcemgr = device->resourcemgr; dual_info = &core->dual_info; /* Continue if wide and tele complete fimc_is_sensor_s_input(). */ if (!(test_bit(SENSOR_POSITION_REAR, &core->sensor_map) && test_bit(SENSOR_POSITION_REAR2, &core->sensor_map))) return; if (group->head->device_type != FIMC_IS_DEVICE_SENSOR) return; /* Update max fps of dual sensor device with reference to shot meta. */ switch (sensor->position) { case SENSOR_POSITION_REAR: dual_info->max_fps_master = frame->shot->ctl.aa.aeTargetFpsRange[1]; break; case SENSOR_POSITION_REAR2: dual_info->max_fps_slave = frame->shot->ctl.aa.aeTargetFpsRange[1]; break; default: err("invalid dual sensor position\n"); return; } /* * bypass - master_max_fps : 30fps, slave_max_fps : 0fps (sensor standby) * sync - master_max_fps : 30fps, slave_max_fps : 30fps (fusion) * switch - master_max_fps : 5ps, slave_max_fps : 30fps (post standby) * nothing - invalid mode */ if (dual_info->max_fps_master >= 24 && dual_info->max_fps_slave == 0) dual_info->mode = FIMC_IS_DUAL_MODE_BYPASS; else if (dual_info->max_fps_master >= 24 && dual_info->max_fps_slave >= 24) dual_info->mode = FIMC_IS_DUAL_MODE_SYNC; else if (dual_info->max_fps_master <= 5 && dual_info->max_fps_slave >= 24) dual_info->mode = FIMC_IS_DUAL_MODE_SWITCH; else dual_info->mode = FIMC_IS_DUAL_MODE_NOTHING; } void fimc_is_dual_dvfs_update(struct fimc_is_device_ischain *device, struct fimc_is_group *group, struct fimc_is_frame *frame) { struct fimc_is_core *core = NULL; struct fimc_is_device_sensor *sensor = NULL; struct fimc_is_resourcemgr *resourcemgr = NULL; struct fimc_is_dvfs_scenario_ctrl *static_ctrl = NULL; struct fimc_is_dual_info *dual_info = NULL; int scenario_id, pre_scenario_id; core = (struct fimc_is_core *)device->interface->core; sensor = device->sensor; resourcemgr = device->resourcemgr; static_ctrl = resourcemgr->dvfs_ctrl.static_ctrl; dual_info = &core->dual_info; /* Continue if wide and tele complete fimc_is_sensor_s_input(). */ if (!(test_bit(SENSOR_POSITION_REAR, &core->sensor_map) && test_bit(SENSOR_POSITION_REAR2, &core->sensor_map))) return; if (group->head->device_type != FIMC_IS_DEVICE_SENSOR) return; /* * tick_count : Add dvfs update margin for dvfs update when mode is changed * from fusion(sync) to standby(bypass, switch) because H/W does not apply * immediately even if mode is dropped from hal. * tick_count == 0 : dvfs update * tick_count > 0 : tick count decrease * tick count < 0 : ignore */ if (dual_info->tick_count >= 0) dual_info->tick_count--; /* If pre_mode and mode are different, tick_count setup. */ if (dual_info->pre_mode != dual_info->mode) { /* If current state is FIMC_IS_DUAL_NOTHING, do not do DVFS update. */ if (dual_info->mode == FIMC_IS_DUAL_MODE_NOTHING) dual_info->tick_count = -1; switch (dual_info->pre_mode) { case FIMC_IS_DUAL_MODE_BYPASS: case FIMC_IS_DUAL_MODE_SWITCH: case FIMC_IS_DUAL_MODE_NOTHING: dual_info->tick_count = 0; break; case FIMC_IS_DUAL_MODE_SYNC: dual_info->tick_count = FIMC_IS_DVFS_DUAL_TICK; break; default: err("invalid dual mode %d -> %d\n", dual_info->pre_mode, dual_info->mode); dual_info->tick_count = -1; dual_info->pre_mode = FIMC_IS_DUAL_MODE_NOTHING; dual_info->mode = FIMC_IS_DUAL_MODE_NOTHING; break; } } /* Only if tick_count is 0 dvfs update. */ if (dual_info->tick_count == 0) { pre_scenario_id = static_ctrl->cur_scenario_id; scenario_id = fimc_is_dvfs_sel_static(device); if (scenario_id >= 0 && scenario_id != pre_scenario_id) { struct fimc_is_dvfs_scenario_ctrl *static_ctrl = resourcemgr->dvfs_ctrl.static_ctrl; mgrinfo("tbl[%d] dual static scenario(%d)-[%s]\n", device, group, frame, resourcemgr->dvfs_ctrl.dvfs_table_idx, static_ctrl->cur_scenario_id, static_ctrl->scenarios[static_ctrl->cur_scenario_idx].scenario_nm); fimc_is_set_dvfs((struct fimc_is_core *)device->interface->core, device, scenario_id); } else { mgrinfo("tbl[%d] dual DVFS update skip %d -> %d\n", device, group, frame, resourcemgr->dvfs_ctrl.dvfs_table_idx, pre_scenario_id, scenario_id); } } /* Update current mode to pre_mode. */ dual_info->pre_mode = dual_info->mode; } #endif