/* ****************************************************************************** * * isp.c * * Hawkview ISP - isp.c module * * Copyright (c) 2016 by Allwinnertech Co., Ltd. http://www.allwinnertech.com * * Version Author Date Description * * 3.0 Yang Feng 2016/05/27 VIDEO INPUT * ***************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "device/isp_dev.h" #include "isp_dev/tools.h" #include "isp_events/events.h" #include "isp_tuning/isp_tuning_priv.h" #include "isp_tuning.h" #include "isp_manage.h" #include "isp_version.h" #include "isp.h" #include "iniparser/src/iniparser.h" #include "include/isp_cmd_intf.h" #include "include/V4l2Camera/sunxi_camera_v2.h" #define MEDIA_DEVICE "/dev/media0" unsigned int isp_lib_log_param = 0; struct hw_isp_media_dev media_params; struct isp_lib_context isp_ctx[HW_ISP_DEVICE_NUM] = { [0] = { .isp_ini_cfg = { .isp_test_settings = { .ae_en = 1, .awb_en = 1, .wb_en = 1, .hist_en = 1, }, .isp_3a_settings = { .ae_stat_sel = 1, .ae_delay_frame = 0, .exp_delay_frame = 1, .gain_delay_frame = 1, .awb_interval = 2, .awb_speed = 32, .awb_stat_sel = 1, .awb_light_num = 9, .awb_light_info = { 254, 256, 104, 256, 256, 256, 50, 1900, 32, 80, 234, 256, 108, 256, 256, 256, 50, 2500, 32, 85, 217, 256, 114, 256, 256, 256, 50, 2800, 32, 90, 160, 256, 153, 256, 256, 256, 50, 4000, 64, 90, 141, 256, 133, 256, 256, 256, 50, 4100, 64, 100, 142, 256, 174, 256, 256, 256, 50, 5000, 100, 100, 118, 256, 156, 256, 256, 256, 50, 5300, 64, 100, 127, 256, 195, 256, 256, 256, 50, 6500, 64, 90, 115, 256, 215, 256, 256, 256, 50, 8000, 64, 80 }, }, }, }, }; struct isp_tuning *tuning[HW_ISP_DEVICE_NUM]; struct event_list events_arr[HW_ISP_DEVICE_NUM]; static int af_status; static void __ae_done(struct isp_lib_context *lib, ae_result_t *result __attribute__((__unused__))) { #if (HW_ISP_DEVICE_NUM > 1) if(media_params.isp_sync_mode && (lib->isp_id == 0)) { *result = isp_ctx[1].ae_entity_ctx.ae_result; } #endif FUNCTION_LOG; } static void __af_done(struct isp_lib_context *lib, af_result_t *result __attribute__((__unused__))) { #if (HW_ISP_DEVICE_NUM > 1) if(media_params.isp_sync_mode && (lib->isp_id == 0)) { *result = isp_ctx[1].af_entity_ctx.af_result; } #endif FUNCTION_LOG; } static void __awb_done(struct isp_lib_context *lib, awb_result_t *result __attribute__((__unused__))) { #if (HW_ISP_DEVICE_NUM > 1) if(media_params.isp_sync_mode && (lib->isp_id == 0)) { *result = isp_ctx[1].awb_entity_ctx.awb_result; } #endif FUNCTION_LOG; } static void __afs_done(struct isp_lib_context *lib, afs_result_t *result __attribute__((__unused__))) { #if (HW_ISP_DEVICE_NUM > 1) if(media_params.isp_sync_mode && (lib->isp_id == 0)) { *result = isp_ctx[1].afs_entity_ctx.afs_result; } #endif FUNCTION_LOG; } static void __md_done(struct isp_lib_context *lib, md_result_t *result __attribute__((__unused__))) { FUNCTION_LOG; } static void __pltm_done(struct isp_lib_context *lib, pltm_result_t *result __attribute__((__unused__))) { #if (HW_ISP_DEVICE_NUM > 1) if(media_params.isp_sync_mode && (lib->isp_id == 0)) { *result = isp_ctx[1].pltm_entity_ctx.pltm_result; } #endif FUNCTION_LOG; } #if ISP_LIB_USE_FLASH void __isp_flash_open(struct hw_isp_device *isp) { struct isp_lib_context *isp_gen = isp_dev_get_ctx(isp); ae_result_t *ae_result = &isp_gen->ae_entity_ctx.ae_result; isp_gen->ae_settings.take_pic_start_cnt = isp_gen->ae_frame_cnt; ISP_DEV_LOG(ISP_LOG_FLASH, "%s: TORCH_ON, ev_set.ev_idx:%d, take_pic_start_cnt:%d, flash_delay:%d.\n", __FUNCTION__, ae_result->sensor_set.ev_set.ev_idx, isp_gen->ae_settings.take_pic_start_cnt, isp_gen->isp_ini_cfg.isp_tunning_settings.flash_delay_frame); ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_TORCH; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_TORCH); isp_gen->ae_settings.flash_open = 1; } void isp_flash_update_status(struct hw_isp_device *isp) { struct isp_lib_context *isp_gen = isp_dev_get_ctx(isp); isp_ae_entity_context_t *isp_ae_cxt = &isp_gen->ae_entity_ctx; ae_result_t *ae_result = &isp_gen->ae_entity_ctx.ae_result; int flash_gain = isp_gen->isp_ini_cfg.isp_tunning_settings.flash_gain; int flash_delay = isp_gen->isp_ini_cfg.isp_tunning_settings.flash_delay_frame; int ev_idx_flash = 0; switch (isp_gen->ae_settings.flash_mode) { case FLASH_MODE_ON: if (isp_gen->ae_settings.take_picture_flag == V4L2_TAKE_PICTURE_FLASH) { if(isp_gen->ae_settings.flash_open == 0) { isp_gen->ae_settings.flash_switch_flag = true; __isp_flash_open(isp); } } break; case FLASH_MODE_AUTO: if (isp_gen->ae_settings.take_picture_flag == V4L2_TAKE_PICTURE_FLASH) { if(isp_gen->ae_settings.flash_open == 0) { if(ae_result->sensor_set.ev_set.ev_idx > (ae_result->sensor_set.ev_idx_max - 40)) { ISP_DEV_LOG(ISP_LOG_FLASH, "ev_idx is %d, ev_idx_max is %d\n", ae_result->sensor_set.ev_set.ev_idx, ae_result->sensor_set.ev_idx_max); isp_gen->ae_settings.flash_switch_flag = true; __isp_flash_open(isp); } } else { if (isp_gen->ae_frame_cnt == (isp_gen->ae_settings.take_pic_start_cnt + flash_delay)) { ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_NONE; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_NONE); isp_gen->ae_settings.flash_switch_flag = false; isp_gen->ae_settings.exposure_lock = true; if (ae_result->ae_flash_ev_cumul >= 100) { ev_idx_flash = ae_result->sensor_set.ev_idx_expect; } else if (ae_result->ae_flash_ev_cumul < 100 && ae_result->ae_flash_ev_cumul >= flash_gain*100/256) { ev_idx_flash = ae_result->sensor_set.ev_idx_expect; } else if (ae_result->ae_flash_ev_cumul >= -25 && ae_result->ae_flash_ev_cumul < flash_gain*100/256) { ev_idx_flash = ae_result->sensor_set.ev_idx_expect + ae_result->ae_flash_ev_cumul * flash_gain/256; } else { ev_idx_flash = ae_result->sensor_set.ev_idx_expect + ae_result->ae_flash_ev_cumul * flash_gain/256; } ev_idx_flash = clamp(ev_idx_flash, 1, ae_result->sensor_set.ev_idx_max); ISP_DEV_LOG(ISP_LOG_FLASH, "%s: FLASH_OFF, ae_flash_ev_cumul:%d, ev_idx_expect:%d, ev_idx_flash:%d, flash_gain:%d.\n", __FUNCTION__, ae_result->ae_flash_ev_cumul, ae_result->sensor_set.ev_idx_expect, ev_idx_flash, isp_gen->isp_ini_cfg.isp_tunning_settings.flash_gain); isp_ae_cxt->ae_param->ae_pline_index = ev_idx_flash; isp_ae_set_params_helper(isp_ae_cxt, ISP_AE_SET_EXP_IDX); } else if (isp_gen->ae_frame_cnt == (1 + isp_gen->ae_settings.take_pic_start_cnt + flash_delay)) { ISP_DEV_LOG(ISP_LOG_FLASH, "%s: FLASH_ON.\n", __FUNCTION__); isp_gen->ae_settings.flash_switch_flag = true; ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_FLASH; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_FLASH); } else if ((isp_gen->ae_frame_cnt >= (4 + isp_gen->ae_settings.take_pic_start_cnt + flash_delay)) && (isp_gen->ae_frame_cnt <= (6 + isp_gen->ae_settings.take_pic_start_cnt + flash_delay))) { ae_result->ae_flash_ok = 1; isp_gen->image_params.isp_image_params.image_para.bits.flash_ok = ae_result->ae_flash_ok; } else if (isp_gen->ae_frame_cnt == (7 + isp_gen->ae_settings.take_pic_start_cnt + flash_delay)) { ISP_DEV_LOG(ISP_LOG_FLASH, "%s: FLASH_OFF.\n", __FUNCTION__); ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_NONE; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_NONE); isp_gen->ae_settings.flash_switch_flag = false; isp_gen->ae_settings.exposure_lock = false; } } } break; case FLASH_MODE_TORCH: if (isp_gen->ae_settings.take_picture_flag == V4L2_TAKE_PICTURE_FLASH) { if (isp_gen->ae_settings.flash_open == 0) { isp_gen->ae_settings.flash_switch_flag = true; __isp_flash_open(isp); } else { if ((isp_gen->ae_frame_cnt >= (1 + isp_gen->ae_settings.take_pic_start_cnt + flash_delay)) && (isp_gen->ae_frame_cnt <= (3 + isp_gen->ae_settings.take_pic_start_cnt + flash_delay))) { ae_result->ae_flash_ok = 1; isp_gen->image_params.isp_image_params.image_para.bits.flash_ok = ae_result->ae_flash_ok; } if (isp_gen->ae_frame_cnt == (4 + isp_gen->ae_settings.take_pic_start_cnt + flash_delay)) { ISP_DEV_LOG(ISP_LOG_FLASH, "%s: FLASH_OFF.\n", __FUNCTION__); ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_TORCH; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_NONE); isp_gen->ae_settings.flash_switch_flag = false; } } } else { ISP_DEV_LOG(ISP_LOG_FLASH, "%s: TORCH_ON, FLASH_MODE TORCH_ON.\n", __FUNCTION__); isp_gen->ae_settings.flash_switch_flag = true; ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_TORCH; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_TORCH); } break; case FLASH_MODE_OFF: if (isp_gen->ae_settings.flash_switch_flag) { ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_NONE; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_NONE); isp_gen->ae_settings.flash_switch_flag = false; } if (isp_gen->ae_settings.exposure_lock) isp_gen->ae_settings.exposure_lock = false; break; case FLASH_MODE_RED_EYE: case FLASH_MODE_NONE: break; default: ae_result->ae_flash_led = V4L2_FLASH_LED_MODE_NONE; isp_flash_ctrl(isp, V4L2_FLASH_LED_MODE_NONE); break; } } #endif int isp_get_af_status(void) { return af_status; } static void __isp_stats_process(struct hw_isp_device *isp, const void *buffer) { struct isp_lib_context *ctx; struct isp_table_reg_map reg; struct sensor_exp_gain exp_gain; ae_result_t *ae_result = NULL; awb_result_t *awb_result = NULL; af_result_t *af_result = NULL; ctx = isp_dev_get_ctx(isp); if (ctx == NULL) return; ctx->isp_stat_buf = buffer; #if (HW_ISP_DEVICE_NUM > 1) if(media_params.isp_sync_mode) { isp_ctx_stats_prepare_sync(ctx, isp_ctx[0].isp_stat_buf, isp_ctx[1].isp_stat_buf); } else { isp_ctx_stats_prepare(ctx, ctx->isp_stat_buf); } #else isp_ctx_stats_prepare(ctx, ctx->isp_stat_buf); #endif isp_stat_save_run(ctx); FUNCTION_LOG; isp_ctx_algo_run(ctx); FUNCTION_LOG; isp_log_save_run(ctx); af_result = &ctx->af_entity_ctx.af_result; if (ctx->isp_ini_cfg.isp_test_settings.af_en || ctx->isp_ini_cfg.isp_test_settings.isp_test_focus) { if (af_result->last_code_output != af_result->real_code_output) { isp_act_set_pos(isp, af_result->real_code_output); af_result->last_code_output = af_result->real_code_output; } ISP_DEV_LOG(ISP_LOG_ISP, "set sensor pos real_code_output: %d.\n", af_result->real_code_output); af_status = af_result->af_status_output; ALOGD("af_result af_status_output: %d.\n", af_result->af_status_output); } #if ISP_LIB_USE_FLASH isp_flash_update_status(isp); #endif ae_result = &ctx->ae_entity_ctx.ae_result; awb_result = &ctx->awb_entity_ctx.awb_result; exp_gain.exp_val = ae_result->sensor_set.ev_set_curr.ev_sensor_exp_line; //exp_gain.ae_wdr_ratio = ae_result->ae_wdr_ratio.sensor; exp_gain.gain_val = ae_result->sensor_set.ev_set_curr.ev_analog_gain >> 4; exp_gain.r_gain = awb_result->wb_gain_output.r_gain * 256 / awb_result->wb_gain_output.gr_gain; exp_gain.b_gain = awb_result->wb_gain_output.b_gain * 256 / awb_result->wb_gain_output.gb_gain; #if (HW_ISP_DEVICE_NUM > 1) /*isp0 and isp1 are opened and have same head sensor, so we only use isp0 control ae*/ if (isp->id == 1 && media_params.isp_dev[0] != NULL && media_params.isp_dev[1] != NULL && !strcmp(media_params.isp_dev[0]->sensor.info.name, media_params.isp_dev[1]->sensor.info.name)) { ISP_DEV_LOG(ISP_LOG_ISP, "isp0 and isp1 are opened and have same head, so we only use isp0 to do ae!\n"); } else { isp_sensor_set_exp_gain(isp, &exp_gain); } #else isp_sensor_set_exp_gain(isp, &exp_gain); #endif FUNCTION_LOG; #if (ISP_VERSION > 500) reg.addr = ctx->load_reg_base; reg.size = ISP_LOAD_DRAM_SIZE; isp_set_load_reg(isp, ®); #else reg.addr = ctx->load_reg_base; reg.size = 0x400; isp_set_load_reg(isp, ®); reg.addr = ctx->module_cfg.table_mapping1; reg.size = ISP_TABLE_MAPPING1_SIZE; isp_set_table1_map(isp, ®); reg.addr = ctx->module_cfg.table_mapping2; reg.size = ISP_TABLE_MAPPING2_SIZE; isp_set_table2_map(isp, ®); #endif } static void __isp_fsync_process(struct hw_isp_device *isp, struct v4l2_event *event) { struct isp_lib_context *ctx = isp_dev_get_ctx(isp); if(ctx->sensor_info.color_space != event->u.data[1]) { ctx->sensor_info.color_space = event->u.data[1]; ctx->isp_3a_change_flags |= ISP_SET_HUE; } isp_lib_log_param = (event->u.data[3] << 8) | event->u.data[2] | ctx->isp_ini_cfg.isp_test_settings.isp_log_param; isp_dev_log_param = isp_lib_log_param; } void __isp_ctrl_process(struct hw_isp_device *isp, struct v4l2_event *event) { struct isp_lib_context *isp_gen = isp_dev_get_ctx(isp); HW_S32 iso_qmenu[] = { 100, 200, 400, 800, 1600, 3200, 6400}; HW_S32 exp_bias_qmenu[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4, }; #if (ISP_VERSION == 522) if (isp->id && isp_gen->sensor_info.sensor_width > 4000 && isp_gen->sensor_info.sensor_height > 3000) { isp_gen = &isp_ctx[0]; } #endif if (isp_gen == NULL) return; switch(event->id) { case V4L2_CID_BRIGHTNESS: isp_s_brightness(isp_gen, event->u.ctrl.value); break; case V4L2_CID_CONTRAST: isp_s_contrast(isp_gen, event->u.ctrl.value); break; case V4L2_CID_SATURATION: isp_s_saturation(isp_gen, event->u.ctrl.value); break; case V4L2_CID_HUE: isp_s_hue(isp_gen, event->u.ctrl.value); break; case V4L2_CID_AUTO_WHITE_BALANCE: isp_s_auto_white_balance(isp_gen, event->u.ctrl.value); break; case V4L2_CID_EXPOSURE: isp_s_exposure(isp_gen, event->u.ctrl.value); break; case V4L2_CID_AUTOGAIN: isp_s_auto_gain(isp_gen, event->u.ctrl.value); break; case V4L2_CID_GAIN: isp_s_gain(isp_gen, event->u.ctrl.value); break; case V4L2_CID_POWER_LINE_FREQUENCY: isp_s_power_line_frequency(isp_gen, event->u.ctrl.value); break; case V4L2_CID_WHITE_BALANCE_TEMPERATURE: isp_s_white_balance_temperature(isp_gen, event->u.ctrl.value); break; case V4L2_CID_SHARPNESS: isp_s_sharpness(isp_gen, event->u.ctrl.value); break; case V4L2_CID_AUTOBRIGHTNESS: isp_s_auto_brightness(isp_gen, event->u.ctrl.value); break; case V4L2_CID_BAND_STOP_FILTER: isp_s_band_stop_filter(isp_gen, event->u.ctrl.value); break; case V4L2_CID_ILLUMINATORS_1: isp_s_illuminators_1(isp_gen, event->u.ctrl.value); break; case V4L2_CID_ILLUMINATORS_2: isp_s_illuminators_2(isp_gen, event->u.ctrl.value); break; case V4L2_CID_EXPOSURE_AUTO: isp_s_exposure_auto(isp_gen, event->u.ctrl.value); break; case V4L2_CID_EXPOSURE_ABSOLUTE: isp_s_exposure_absolute(isp_gen, event->u.ctrl.value); break; case V4L2_CID_FOCUS_ABSOLUTE: isp_s_focus_absolute(isp_gen, event->u.ctrl.value); break; case V4L2_CID_FOCUS_RELATIVE: isp_s_focus_relative(isp_gen, event->u.ctrl.value); break; case V4L2_CID_FOCUS_AUTO: isp_s_focus_auto(isp_gen, event->u.ctrl.value); break; case V4L2_CID_AUTO_EXPOSURE_BIAS: isp_s_auto_exposure_bias(isp_gen, exp_bias_qmenu[event->u.ctrl.value]); break; case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: isp_s_auto_n_preset_white_balance(isp_gen, event->u.ctrl.value); break; case V4L2_CID_ISO_SENSITIVITY: isp_s_iso_sensitivity(isp_gen, iso_qmenu[event->u.ctrl.value]); break; case V4L2_CID_ISO_SENSITIVITY_AUTO: isp_s_iso_sensitivity_auto(isp_gen, event->u.ctrl.value); break; case V4L2_CID_EXPOSURE_METERING: isp_s_ae_metering_mode(isp_gen, event->u.ctrl.value); break; case V4L2_CID_SCENE_MODE: isp_s_scene_mode(isp_gen, event->u.ctrl.value); break; case V4L2_CID_3A_LOCK: //isp_s_3a_lock(isp_gen, event->u.ctrl.value); break; case V4L2_CID_AUTO_FOCUS_START: isp_s_auto_focus_start(isp_gen, event->u.ctrl.value); break; case V4L2_CID_AUTO_FOCUS_STOP: isp_s_auto_focus_stop(isp_gen, event->u.ctrl.value); break; case V4L2_CID_AUTO_FOCUS_RANGE: isp_s_auto_focus_range(isp_gen, event->u.ctrl.value); break; case V4L2_CID_TAKE_PICTURE: isp_s_take_picture(isp_gen, event->u.ctrl.value); break; case V4L2_CID_FLASH_LED_MODE: isp_s_flash_mode(isp_gen, event->u.ctrl.value); break; default: ISP_ERR("Unknown ctrl.\n"); break; } } static void __isp_stream_off(struct hw_isp_device *isp __attribute__((__unused__))) { if ((isp->id >= HW_ISP_DEVICE_NUM) || (isp->id == -1)) ISP_ERR("ISP ID is invalid, __isp_stream_off failed!\n"); events_stop(&events_arr[isp->id]); } static void __isp_monitor_fd(int id, int fd, enum hw_isp_event_type type, void(*callback)(void *), void *priv) { events_monitor_fd(&events_arr[id], fd, type, callback, priv); } static void __isp_unmonitor_fd(int id, int fd) { events_unmonitor_fd(&events_arr[id], fd); } static struct isp_ctx_operations isp_ctx_ops = { .ae_done = __ae_done, .af_done = __af_done, .awb_done = __awb_done, .afs_done = __afs_done, .md_done = __md_done, .pltm_done = __pltm_done, }; static struct isp_dev_operations isp_dev_ops = { .stats_ready = __isp_stats_process, .fsync = __isp_fsync_process, .stream_off = __isp_stream_off, .ctrl_process = __isp_ctrl_process, .monitor_fd = __isp_monitor_fd, .unmonitor_fd = __isp_unmonitor_fd, }; static void *__isp_thread(void *arg) { int ret = 0; struct hw_isp_device *isp = (struct hw_isp_device *)arg; if ((isp->id >= HW_ISP_DEVICE_NUM) || (isp->id == -1)) ISP_ERR("ISP ID is invalid, isp_run failed!\n"); ret = isp_dev_start(isp); if (ret < 0) goto end; if (events_loop(&events_arr[isp->id])) goto end; end: isp_dev_stop(isp); return NULL; } int isp_set_sync(int mode) { #if (HW_ISP_DEVICE_NUM > 1) if(mode == 0 || mode == 1) media_params.isp_sync_mode = mode; else return -1; #else media_params.isp_sync_mode = 0; #endif return 0; } int media_dev_init(void) { /*must be called before all isp init*/ //memset(&media_params, 0, sizeof(media_params)); isp_version_info(); return 0; } void media_dev_exit(void) { /*must be called after all isp exit*/ #if (HW_ISP_DEVICE_NUM > 1) if ((media_params.isp_use_cnt[0] == 0) && (media_params.isp_use_cnt[1] == 0)) { if (media_params.mdev) { media_close(media_params.mdev); media_params.mdev = NULL; } } #else if (media_params.isp_use_cnt[0] == 0) { if (media_params.mdev) { media_close(media_params.mdev); media_params.mdev = NULL; } } #endif } int isp_reset(int dev_id) { int ret = 0; struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } isp_params_parse(isp, &isp_ctx[dev_id].isp_ini_cfg, media_params.isp_sync_mode); ret = isp_tuning_reset(isp, &isp_ctx[dev_id].isp_ini_cfg); if (ret) { ISP_ERR("error: unable to reset isp tuning\n"); } return ret; } int isp_init(int dev_id) { int ret = 0; struct hw_isp_device *isp = NULL; struct isp_table_reg_map reg; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; if (media_params.isp_use_cnt[dev_id]++ > 0) return 0; /*update media entity and links*/ if (media_params.mdev) { media_close(media_params.mdev); media_params.mdev = NULL; } media_params.mdev = media_open(MEDIA_DEVICE, 0); if (media_params.mdev == NULL) { ISP_ERR("isp%d update media entity and links failed!\n", dev_id); return -1; } ret = isp_dev_open(&media_params, dev_id); if (ret < 0) return ret; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } isp_dev_register(isp, &isp_dev_ops); isp_dev_banding_ctx(isp, &isp_ctx[dev_id]); isp_ctx[dev_id].isp_id = dev_id; isp_sensor_otp_init(isp); isp_config_sensor_info(isp); isp_ctx_save_init(&isp_ctx[dev_id]); isp_stat_save_init(&isp_ctx[dev_id]); isp_log_save_init(&isp_ctx[dev_id]); ret = isp_params_parse(isp, &isp_ctx[dev_id].isp_ini_cfg, media_params.isp_sync_mode); if (ret < 0) { if (dev_id >= 1) isp_ctx[dev_id].isp_ini_cfg = isp_ctx[0].isp_ini_cfg; } FUNCTION_LOG; isp_ctx_algo_init(&isp_ctx[dev_id], &isp_ctx_ops); FUNCTION_LOG; tuning[dev_id] = isp_tuning_init(isp, &isp_ctx[dev_id].isp_ini_cfg); if (tuning[dev_id] == NULL) { ISP_ERR("error: unable to initialize isp tuning\n"); return -1; } FUNCTION_LOG; if (isp_ctx[dev_id].isp_ini_cfg.isp_test_settings.af_en || isp_ctx[dev_id].isp_ini_cfg.isp_test_settings.isp_test_focus) isp_act_init_range(isp, isp_ctx[dev_id].isp_ini_cfg.isp_3a_settings.vcm_min_code, isp_ctx[dev_id].isp_ini_cfg.isp_3a_settings.vcm_max_code); events_arr[dev_id].isp_id = dev_id; events_init(&events_arr[dev_id]); events_star(&events_arr[dev_id]); FUNCTION_LOG; #if (ISP_VERSION > 500) reg.addr = isp_ctx[dev_id].load_reg_base; reg.size = ISP_LOAD_DRAM_SIZE; isp_set_load_reg(isp, ®); #else reg.addr = isp_ctx[dev_id].load_reg_base; reg.size = 0x400; isp_set_load_reg(isp, ®); reg.addr = isp_ctx[dev_id].module_cfg.table_mapping1; reg.size = ISP_TABLE_MAPPING1_SIZE; isp_set_table1_map(isp, ®); reg.addr = isp_ctx[dev_id].module_cfg.table_mapping2; reg.size = ISP_TABLE_MAPPING2_SIZE; isp_set_table2_map(isp, ®); #endif ISP_DEV_LOG(ISP_LOG_ISP, "isp%d init end!!!\n", dev_id); ISP_PRINT("isp%d init end!!!\n", dev_id); return 0; } int isp_update(int dev_id) { int ret = 0; struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } ret = isp_tuning_update(isp); if (ret) { ISP_ERR("error: unable to update isp tuning\n"); } return ret; } int isp_get_imageparams(int dev_id, isp_image_params_t *pParams) { struct hw_isp_device *isp = NULL; struct isp_lib_context *isp_gen = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } isp_gen = isp_dev_get_ctx(isp); memcpy(pParams, &isp_gen->image_params, sizeof(isp_image_params_t)); return 0; } int isp_stop(int dev_id) { if (dev_id >= HW_ISP_DEVICE_NUM) return -1; if (media_params.isp_use_cnt[dev_id] == 1) events_stop(&events_arr[dev_id]); return 0; } int isp_exit(int dev_id) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; if ((media_params.isp_use_cnt[dev_id] == 0) || (--media_params.isp_use_cnt[dev_id] > 0)) return 0; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } /*wait to exit until the thread is finished*/ pthread_join(media_params.isp_tid[dev_id], NULL); isp_log_save_exit(&isp_ctx[dev_id]); isp_stat_save_exit(&isp_ctx[dev_id]); isp_ctx_save_exit(&isp_ctx[dev_id]); isp_tuning_exit(isp); isp_ctx_algo_exit(&isp_ctx[dev_id]); isp_dev_close(&media_params, dev_id); isp_sensor_otp_exit(isp); ISP_DEV_LOG(ISP_LOG_ISP, "isp%d exit end!!!\n", dev_id); return 0; } int isp_run(int dev_id) { int ret = 0; struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; if (media_params.isp_use_cnt[dev_id] > 1) return 0; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } ISP_PRINT("create isp%d server thread!\n", dev_id); ret = pthread_create(&media_params.isp_tid[dev_id], NULL, __isp_thread, isp); if(ret != 0) ISP_ERR("%s: %s\n",__func__, strerror(ret)); return ret; } HW_S32 isp_pthread_join(int dev_id) { #if 0 struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; if (media_params.isp_use_cnt[dev_id] == 1) pthread_join(media_params.isp_tid[dev_id], NULL); #endif return 0; } HW_S32 isp_get_cfg(int dev_id, HW_U8 group_id, HW_U32 cfg_ids, void *cfg_data) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } return isp_tuning_get_cfg(isp, group_id, cfg_ids, cfg_data); } HW_S32 isp_set_cfg(int dev_id, HW_U8 group_id, HW_U32 cfg_ids, void *cfg_data) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } return isp_tuning_set_cfg(isp, group_id, cfg_ids, cfg_data); } HW_S32 isp_stats_req(int dev_id, struct isp_stats_context *stats_ctx) { struct hw_isp_device *isp = NULL; struct isp_lib_context *ctx = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } ctx = isp_dev_get_ctx(isp); if (ctx == NULL) return -1; return isp_ctx_stats_req(ctx, stats_ctx); } HW_S32 isp_set_saved_ctx(int dev_id) { return isp_ctx_save_exit(&isp_ctx[dev_id]); } int isp_set_fps(int dev_id, int s_fps) { struct hw_isp_device *isp = NULL; struct sensor_fps fps; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } fps.fps = s_fps; isp_sensor_set_fps(isp, &fps); if(s_fps > 1) isp_ctx_update_ae_tbl(&isp_ctx[dev_id], s_fps); return 0; } HW_S32 isp_get_sensor_info(int dev_id, struct sensor_config *cfg) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } memset(cfg, 0, sizeof(struct sensor_config)); isp_sensor_get_configs(isp, cfg); return 0; } /*******************isp for video buffer*********************/ HW_S32 isp_get_lv(int dev_id) { struct hw_isp_device *isp; struct isp_lib_context *ctx; isp = media_params.isp_dev[dev_id]; if (!isp) { //ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } ctx = isp_dev_get_ctx(isp); if (ctx == NULL) { //ISP_ERR("isp%d get isp ctx failed!\n", dev_id); return -1; } return ctx->ae_entity_ctx.ae_result.sensor_set.ev_set_curr.ev_lv; } HW_S32 isp_get_attr_cfg(int dev_id, HW_U32 ctrl_id, void *value) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } struct isp_lib_context *isp_gen = isp_dev_get_ctx(isp); if (isp_gen == NULL) return -1; switch(ctrl_id) { case ISP_CTRL_MODULE_EN: break; case ISP_CTRL_DIGITAL_GAIN: *(HW_S32 *)value = isp_gen->ae_entity_ctx.ae_result.sensor_set.ev_set_curr.ev_digital_gain; break; case ISP_CTRL_PLTMWDR_STR: *(HW_S32 *)value = isp_gen->tune.pltmwdr_level; break; case ISP_CTRL_DN_STR: *(HW_S32 *)value = isp_gen->tune.denoise_level; break; case ISP_CTRL_3DN_STR: *(HW_S32 *)value = isp_gen->tune.tdf_level; break; case ISP_CTRL_HIGH_LIGHT: *(HW_S32 *)value = isp_gen->tune.highlight_level; break; case ISP_CTRL_BACK_LIGHT: *(HW_S32 *)value = isp_gen->tune.backlight_level; break; case ISP_CTRL_WB_MGAIN: *(struct isp_wb_gain *)value = isp_gen->awb_entity_ctx.awb_result.wb_gain_output; break; case ISP_CTRL_AGAIN_DGAIN: *(struct gain_cfg *)value = isp_gen->tune.gains; break; case ISP_CTRL_COLOR_EFFECT: *(HW_S32 *)value = isp_gen->tune.effect; break; case ISP_CTRL_AE_ROI: *(struct isp_h3a_coor_win *)value = isp_gen->ae_settings.ae_coor; break; case ISP_CTRL_COLOR_TEMP: *(HW_S32 *)value = isp_gen->awb_entity_ctx.awb_result.color_temp_output; break; case ISP_CTRL_EV_IDX: *(HW_S32 *)value = isp_gen->ae_entity_ctx.ae_result.sensor_set.ev_set.ev_idx; break; case ISP_CTRL_EXPOSURE_TIME: *(HW_S32 *)value = isp_gen->ae_entity_ctx.ae_result.sensor_set.ev_set_curr.ev_exposure_time; break; case ISP_CTRL_AGAIN_ISO: *(HW_S32 *)value = ((isp_gen->ae_entity_ctx.ae_result.sensor_set.ev_set_curr.ev_analog_gain >> 4) < 16) ? 100 : ((isp_gen->ae_entity_ctx.ae_result.sensor_set.ev_set_curr.ev_analog_gain >> 4) / 16 * 100); break; default: ISP_ERR("Unknown ctrl.\n"); break; } return 0; } HW_S32 isp_set_attr_cfg(int dev_id, HW_U32 ctrl_id, void *value) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } struct isp_lib_context *isp_gen = isp_dev_get_ctx(isp); if (isp_gen == NULL) return -1; switch(ctrl_id) { case ISP_CTRL_MODULE_EN: break; case ISP_CTRL_DIGITAL_GAIN: break; case ISP_CTRL_PLTMWDR_STR: isp_gen->tune.pltmwdr_level = *(HW_S32 *)value; break; case ISP_CTRL_DN_STR: isp_gen->tune.denoise_level = *(HW_S32 *)value; break; case ISP_CTRL_3DN_STR: isp_gen->tune.tdf_level = *(HW_S32 *)value; break; case ISP_CTRL_HIGH_LIGHT: isp_gen->tune.highlight_level = *(HW_S32 *)value; break; case ISP_CTRL_BACK_LIGHT: isp_gen->tune.backlight_level = *(HW_S32 *)value; break; case ISP_CTRL_WB_MGAIN: isp_gen->awb_settings.wb_gain_manual = *(struct isp_wb_gain *)value; break; case ISP_CTRL_AGAIN_DGAIN: if (memcmp(&isp_gen->tune.gains, value, sizeof(struct gain_cfg))) { isp_gen->tune.gains = *(struct gain_cfg *)value; isp_gen->isp_3a_change_flags |= ISP_SET_GAIN_STR; } break; case ISP_CTRL_COLOR_EFFECT: if (isp_gen->tune.effect != *(HW_S32 *)value) { isp_gen->tune.effect = *(HW_S32 *)value; isp_gen->isp_3a_change_flags |= ISP_SET_EFFECT; } break; case ISP_CTRL_AE_ROI: isp_s_ae_roi(isp_gen, AE_METERING_MODE_SPOT, value); break; case ISP_CTRL_AF_METERING: isp_s_af_metering_mode(isp_gen, value); break; default: ISP_ERR("Unknown ctrl.\n"); break; } return 0; } HW_S32 isp_get_info_length(HW_S32* i3a_length, HW_S32* debug_length) { HW_S32 data_len = 0; *i3a_length = sizeof(ae_result_t) + sizeof(ae_param_t)+ sizeof(struct isp_ae_stats_s) // ae info + sizeof(awb_result_t)+ sizeof(awb_param_t)+ sizeof(struct isp_awb_stats_s) // awb info + sizeof(af_result_t)+ sizeof(af_param_t)+ sizeof(struct isp_af_stats_s); // af info *debug_length = sizeof(iso_result_t) +sizeof(iso_param_t) // iso info +sizeof(struct isp_module_config) // isp module info +sizeof(int) // otp enable flag +16*16*3*sizeof(unsigned short) // msc tbl +4*2*sizeof(unsigned short); // wb otp data data_len = *i3a_length + *debug_length; ISP_PRINT("i3a_length:%d, debug_length:%d.\n", *i3a_length, *debug_length); ISP_PRINT("af_result_t:%d, af_param_t:%d, isp_af_stats_s:%d.\n", sizeof(ae_result_t), sizeof(ae_param_t), sizeof(struct isp_ae_stats_s)); ISP_PRINT("af_result_t:%d, af_param_t:%d, isp_af_stats_s:%d.\n", sizeof(awb_result_t), sizeof(awb_param_t), sizeof(struct isp_awb_stats_s)); ISP_PRINT("af_result_t:%d, af_param_t:%d, isp_af_stats_s:%d.\n", sizeof(af_result_t), sizeof(af_param_t), sizeof(struct isp_af_stats_s)); return data_len; } HW_S32 isp_get_3a_parameters(int dev_id, void* params) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } struct isp_lib_context *isp_gen = isp_dev_get_ctx(isp); if (isp_gen == NULL) return -1; void * ptr = params; int isp_3a_size = 0; // ae info memcpy(ptr, &(isp_gen->ae_entity_ctx.ae_result), sizeof(ae_result_t)); ptr += sizeof(ae_result_t); memcpy(ptr, isp_gen->ae_entity_ctx.ae_param, sizeof(ae_param_t)); ptr += sizeof(ae_param_t); memcpy(ptr, isp_gen->ae_entity_ctx.ae_stats.ae_stats, sizeof(struct isp_ae_stats_s)); ptr += sizeof(struct isp_ae_stats_s); // awb info memcpy(ptr, &(isp_gen->awb_entity_ctx.awb_result), sizeof(awb_result_t)); ptr += sizeof(awb_result_t); memcpy(ptr, isp_gen->awb_entity_ctx.awb_param, sizeof(awb_param_t)); ptr += sizeof(awb_param_t); memcpy(ptr, isp_gen->awb_entity_ctx.awb_stats.awb_stats, sizeof(struct isp_awb_stats_s)); ptr += sizeof(struct isp_awb_stats_s); // af info memcpy(ptr, &(isp_gen->af_entity_ctx.af_result), sizeof(af_result_t)); ptr += sizeof(af_result_t); memcpy(ptr, isp_gen->af_entity_ctx.af_param, sizeof(af_param_t)); ptr += sizeof(af_param_t); memcpy(ptr, isp_gen->af_entity_ctx.af_stats.af_stats, sizeof(struct isp_af_stats_s)); ptr += sizeof(struct isp_af_stats_s); isp_3a_size = sizeof(ae_result_t) + sizeof(ae_param_t) + sizeof(struct isp_ae_stats_s) + sizeof(awb_result_t) + sizeof(awb_param_t) + sizeof(struct isp_awb_stats_s) + sizeof(af_result_t) + sizeof(af_param_t) + sizeof(struct isp_af_stats_s); ptr = NULL; return isp_3a_size; } HW_S32 isp_get_debug_msg(int dev_id, void* msg) { struct hw_isp_device *isp = NULL; if (dev_id >= HW_ISP_DEVICE_NUM) return -1; isp = media_params.isp_dev[dev_id]; if (!isp) { ISP_ERR("isp%d device is NULL!\n", dev_id); return -1; } struct isp_lib_context *isp_gen = isp_dev_get_ctx(isp); if (isp_gen == NULL) return -1; void * ptr = msg; int isp_debug_msg_size = 0; memcpy(ptr, &(isp_gen->iso_entity_ctx.iso_result), sizeof(iso_result_t)); ptr += sizeof(iso_result_t); memcpy(ptr, isp_gen->iso_entity_ctx.iso_param, sizeof(iso_param_t)); ptr += sizeof(iso_param_t); memcpy(ptr, &isp_gen->module_cfg, sizeof(struct isp_module_config)); ptr += sizeof(struct isp_module_config); memcpy(ptr, &isp_gen->otp_enable, sizeof(int)); ptr += sizeof(int); // shading msc rgb tbl 16x16x3 memcpy(ptr, isp_gen->pmsc_table, 16*16*3*sizeof(unsigned short)); ptr += 16*16*3*sizeof(unsigned short); // wb otp & golden data memcpy(ptr, isp_gen->pwb_table, 4*2*sizeof(unsigned short)); ptr += 4*2*sizeof(unsigned short); isp_debug_msg_size = sizeof(iso_result_t) + sizeof(iso_param_t) + sizeof(struct isp_module_config) + sizeof(int) + 16*16*3*sizeof(unsigned short) + 4*2*sizeof(unsigned short); ptr = NULL; return isp_debug_msg_size; } /*******************get isp version*********************/ HW_S32 isp_get_version(char* version) { sprintf(version, "ISP%d", ISP_VERSION); ISP_PRINT("ISP Version: ISP%d", ISP_VERSION); return 0; }