| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Rockchip ISP1 Driver - Params subdevice |
| * |
| * Copyright (C) 2017 Rockchip Electronics Co., Ltd. |
| */ |
| |
| #include <media/v4l2-common.h> |
| #include <media/v4l2-event.h> |
| #include <media/v4l2-ioctl.h> |
| #include <media/videobuf2-core.h> |
| #include <media/videobuf2-vmalloc.h> /* for ISP params */ |
| |
| #include "rkisp1-common.h" |
| |
| #define RKISP1_PARAMS_DEV_NAME RKISP1_DRIVER_NAME "_params" |
| |
| #define RKISP1_ISP_PARAMS_REQ_BUFS_MIN 2 |
| #define RKISP1_ISP_PARAMS_REQ_BUFS_MAX 8 |
| |
| #define RKISP1_ISP_DPCC_LINE_THRESH(n) \ |
| (RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 + 0x14 * (n)) |
| #define RKISP1_ISP_DPCC_LINE_MAD_FAC(n) \ |
| (RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 + 0x14 * (n)) |
| #define RKISP1_ISP_DPCC_PG_FAC(n) \ |
| (RKISP1_CIF_ISP_DPCC_PG_FAC_1 + 0x14 * (n)) |
| #define RKISP1_ISP_DPCC_RND_THRESH(n) \ |
| (RKISP1_CIF_ISP_DPCC_RND_THRESH_1 + 0x14 * (n)) |
| #define RKISP1_ISP_DPCC_RG_FAC(n) \ |
| (RKISP1_CIF_ISP_DPCC_RG_FAC_1 + 0x14 * (n)) |
| #define RKISP1_ISP_CC_COEFF(n) \ |
| (RKISP1_CIF_ISP_CC_COEFF_0 + (n) * 4) |
| |
| static inline void |
| rkisp1_param_set_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) |
| { |
| u32 val; |
| |
| val = rkisp1_read(params->rkisp1, reg); |
| rkisp1_write(params->rkisp1, val | bit_mask, reg); |
| } |
| |
| static inline void |
| rkisp1_param_clear_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) |
| { |
| u32 val; |
| |
| val = rkisp1_read(params->rkisp1, reg); |
| rkisp1_write(params->rkisp1, val & ~bit_mask, reg); |
| } |
| |
| /* ISP BP interface function */ |
| static void rkisp1_dpcc_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_dpcc_config *arg) |
| { |
| unsigned int i; |
| u32 mode; |
| |
| /* avoid to override the old enable value */ |
| mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); |
| mode &= RKISP1_CIF_ISP_DPCC_ENA; |
| mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; |
| rkisp1_write(params->rkisp1, mode, RKISP1_CIF_ISP_DPCC_MODE); |
| rkisp1_write(params->rkisp1, arg->output_mode, |
| RKISP1_CIF_ISP_DPCC_OUTPUT_MODE); |
| rkisp1_write(params->rkisp1, arg->set_use, |
| RKISP1_CIF_ISP_DPCC_SET_USE); |
| |
| rkisp1_write(params->rkisp1, arg->methods[0].method, |
| RKISP1_CIF_ISP_DPCC_METHODS_SET_1); |
| rkisp1_write(params->rkisp1, arg->methods[1].method, |
| RKISP1_CIF_ISP_DPCC_METHODS_SET_2); |
| rkisp1_write(params->rkisp1, arg->methods[2].method, |
| RKISP1_CIF_ISP_DPCC_METHODS_SET_3); |
| for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { |
| rkisp1_write(params->rkisp1, arg->methods[i].line_thresh, |
| RKISP1_ISP_DPCC_LINE_THRESH(i)); |
| rkisp1_write(params->rkisp1, arg->methods[i].line_mad_fac, |
| RKISP1_ISP_DPCC_LINE_MAD_FAC(i)); |
| rkisp1_write(params->rkisp1, arg->methods[i].pg_fac, |
| RKISP1_ISP_DPCC_PG_FAC(i)); |
| rkisp1_write(params->rkisp1, arg->methods[i].rnd_thresh, |
| RKISP1_ISP_DPCC_RND_THRESH(i)); |
| rkisp1_write(params->rkisp1, arg->methods[i].rg_fac, |
| RKISP1_ISP_DPCC_RG_FAC(i)); |
| } |
| |
| rkisp1_write(params->rkisp1, arg->rnd_offs, |
| RKISP1_CIF_ISP_DPCC_RND_OFFS); |
| rkisp1_write(params->rkisp1, arg->ro_limits, |
| RKISP1_CIF_ISP_DPCC_RO_LIMITS); |
| } |
| |
| /* ISP black level subtraction interface function */ |
| static void rkisp1_bls_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_bls_config *arg) |
| { |
| /* avoid to override the old enable value */ |
| u32 new_control; |
| |
| new_control = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL); |
| new_control &= RKISP1_CIF_ISP_BLS_ENA; |
| /* fixed subtraction values */ |
| if (!arg->enable_auto) { |
| const struct rkisp1_cif_isp_bls_fixed_val *pval = |
| &arg->fixed_val; |
| |
| switch (params->raw_type) { |
| case RKISP1_RAW_BGGR: |
| rkisp1_write(params->rkisp1, |
| pval->r, RKISP1_CIF_ISP_BLS_D_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gr, RKISP1_CIF_ISP_BLS_C_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gb, RKISP1_CIF_ISP_BLS_B_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->b, RKISP1_CIF_ISP_BLS_A_FIXED); |
| break; |
| case RKISP1_RAW_GBRG: |
| rkisp1_write(params->rkisp1, |
| pval->r, RKISP1_CIF_ISP_BLS_C_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gr, RKISP1_CIF_ISP_BLS_D_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gb, RKISP1_CIF_ISP_BLS_A_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->b, RKISP1_CIF_ISP_BLS_B_FIXED); |
| break; |
| case RKISP1_RAW_GRBG: |
| rkisp1_write(params->rkisp1, |
| pval->r, RKISP1_CIF_ISP_BLS_B_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gr, RKISP1_CIF_ISP_BLS_A_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gb, RKISP1_CIF_ISP_BLS_D_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->b, RKISP1_CIF_ISP_BLS_C_FIXED); |
| break; |
| case RKISP1_RAW_RGGB: |
| rkisp1_write(params->rkisp1, |
| pval->r, RKISP1_CIF_ISP_BLS_A_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gr, RKISP1_CIF_ISP_BLS_B_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->gb, RKISP1_CIF_ISP_BLS_C_FIXED); |
| rkisp1_write(params->rkisp1, |
| pval->b, RKISP1_CIF_ISP_BLS_D_FIXED); |
| break; |
| default: |
| break; |
| } |
| |
| } else { |
| if (arg->en_windows & BIT(1)) { |
| rkisp1_write(params->rkisp1, arg->bls_window2.h_offs, |
| RKISP1_CIF_ISP_BLS_H2_START); |
| rkisp1_write(params->rkisp1, arg->bls_window2.h_size, |
| RKISP1_CIF_ISP_BLS_H2_STOP); |
| rkisp1_write(params->rkisp1, arg->bls_window2.v_offs, |
| RKISP1_CIF_ISP_BLS_V2_START); |
| rkisp1_write(params->rkisp1, arg->bls_window2.v_size, |
| RKISP1_CIF_ISP_BLS_V2_STOP); |
| new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2; |
| } |
| |
| if (arg->en_windows & BIT(0)) { |
| rkisp1_write(params->rkisp1, arg->bls_window1.h_offs, |
| RKISP1_CIF_ISP_BLS_H1_START); |
| rkisp1_write(params->rkisp1, arg->bls_window1.h_size, |
| RKISP1_CIF_ISP_BLS_H1_STOP); |
| rkisp1_write(params->rkisp1, arg->bls_window1.v_offs, |
| RKISP1_CIF_ISP_BLS_V1_START); |
| rkisp1_write(params->rkisp1, arg->bls_window1.v_size, |
| RKISP1_CIF_ISP_BLS_V1_STOP); |
| new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1; |
| } |
| |
| rkisp1_write(params->rkisp1, arg->bls_samples, |
| RKISP1_CIF_ISP_BLS_SAMPLES); |
| |
| new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED; |
| } |
| rkisp1_write(params->rkisp1, new_control, RKISP1_CIF_ISP_BLS_CTRL); |
| } |
| |
| /* ISP LS correction interface function */ |
| static void |
| rkisp1_lsc_correct_matrix_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_lsc_config *pconfig) |
| { |
| unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; |
| |
| isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); |
| |
| /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ |
| sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? |
| RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : |
| RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; |
| rkisp1_write(params->rkisp1, sram_addr, |
| RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); |
| rkisp1_write(params->rkisp1, sram_addr, |
| RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); |
| rkisp1_write(params->rkisp1, sram_addr, |
| RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); |
| rkisp1_write(params->rkisp1, sram_addr, |
| RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); |
| |
| /* program data tables (table size is 9 * 17 = 153) */ |
| for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { |
| /* |
| * 17 sectors with 2 values in one DWORD = 9 |
| * DWORDs (2nd value of last DWORD unused) |
| */ |
| for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], |
| pconfig->r_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_R_TABLE_DATA); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], |
| pconfig->gr_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], |
| pconfig->gb_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], |
| pconfig->b_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_B_TABLE_DATA); |
| } |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_R_TABLE_DATA); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_B_TABLE_DATA); |
| } |
| isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? |
| RKISP1_CIF_ISP_LSC_TABLE_0 : |
| RKISP1_CIF_ISP_LSC_TABLE_1; |
| rkisp1_write(params->rkisp1, isp_lsc_table_sel, |
| RKISP1_CIF_ISP_LSC_TABLE_SEL); |
| } |
| |
| static void rkisp1_lsc_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_lsc_config *arg) |
| { |
| unsigned int i, data; |
| u32 lsc_ctrl; |
| |
| /* To config must be off , store the current status firstly */ |
| lsc_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_CTRL); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, |
| RKISP1_CIF_ISP_LSC_CTRL_ENA); |
| rkisp1_lsc_correct_matrix_config(params, arg); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE / 2; i++) { |
| /* program x size tables */ |
| data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], |
| arg->x_size_tbl[i * 2 + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4); |
| |
| /* program x grad tables */ |
| data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], |
| arg->x_grad_tbl[i * 2 + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4); |
| |
| /* program y size tables */ |
| data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], |
| arg->y_size_tbl[i * 2 + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4); |
| |
| /* program y grad tables */ |
| data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], |
| arg->y_grad_tbl[i * 2 + 1]); |
| rkisp1_write(params->rkisp1, data, |
| RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4); |
| } |
| |
| /* restore the lsc ctrl status */ |
| if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) { |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_LSC_CTRL, |
| RKISP1_CIF_ISP_LSC_CTRL_ENA); |
| } else { |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_LSC_CTRL, |
| RKISP1_CIF_ISP_LSC_CTRL_ENA); |
| } |
| } |
| |
| /* ISP Filtering function */ |
| static void rkisp1_flt_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_flt_config *arg) |
| { |
| u32 filt_mode; |
| |
| rkisp1_write(params->rkisp1, |
| arg->thresh_bl0, RKISP1_CIF_ISP_FILT_THRESH_BL0); |
| rkisp1_write(params->rkisp1, |
| arg->thresh_bl1, RKISP1_CIF_ISP_FILT_THRESH_BL1); |
| rkisp1_write(params->rkisp1, |
| arg->thresh_sh0, RKISP1_CIF_ISP_FILT_THRESH_SH0); |
| rkisp1_write(params->rkisp1, |
| arg->thresh_sh1, RKISP1_CIF_ISP_FILT_THRESH_SH1); |
| rkisp1_write(params->rkisp1, arg->fac_bl0, RKISP1_CIF_ISP_FILT_FAC_BL0); |
| rkisp1_write(params->rkisp1, arg->fac_bl1, RKISP1_CIF_ISP_FILT_FAC_BL1); |
| rkisp1_write(params->rkisp1, arg->fac_mid, RKISP1_CIF_ISP_FILT_FAC_MID); |
| rkisp1_write(params->rkisp1, arg->fac_sh0, RKISP1_CIF_ISP_FILT_FAC_SH0); |
| rkisp1_write(params->rkisp1, arg->fac_sh1, RKISP1_CIF_ISP_FILT_FAC_SH1); |
| rkisp1_write(params->rkisp1, |
| arg->lum_weight, RKISP1_CIF_ISP_FILT_LUM_WEIGHT); |
| |
| rkisp1_write(params->rkisp1, |
| (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) | |
| RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | |
| RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | |
| RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1), |
| RKISP1_CIF_ISP_FILT_MODE); |
| |
| /* avoid to override the old enable value */ |
| filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE); |
| filt_mode &= RKISP1_CIF_ISP_FLT_ENA; |
| if (arg->mode) |
| filt_mode |= RKISP1_CIF_ISP_FLT_MODE_DNR; |
| filt_mode |= RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | |
| RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | |
| RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1); |
| rkisp1_write(params->rkisp1, filt_mode, RKISP1_CIF_ISP_FILT_MODE); |
| } |
| |
| /* ISP demosaic interface function */ |
| static int rkisp1_bdm_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_bdm_config *arg) |
| { |
| u32 bdm_th; |
| |
| /* avoid to override the old enable value */ |
| bdm_th = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DEMOSAIC); |
| bdm_th &= RKISP1_CIF_ISP_DEMOSAIC_BYPASS; |
| bdm_th |= arg->demosaic_th & ~RKISP1_CIF_ISP_DEMOSAIC_BYPASS; |
| /* set demosaic threshold */ |
| rkisp1_write(params->rkisp1, bdm_th, RKISP1_CIF_ISP_DEMOSAIC); |
| return 0; |
| } |
| |
| /* ISP GAMMA correction interface function */ |
| static void rkisp1_sdg_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_sdg_config *arg) |
| { |
| unsigned int i; |
| |
| rkisp1_write(params->rkisp1, |
| arg->xa_pnts.gamma_dx0, RKISP1_CIF_ISP_GAMMA_DX_LO); |
| rkisp1_write(params->rkisp1, |
| arg->xa_pnts.gamma_dx1, RKISP1_CIF_ISP_GAMMA_DX_HI); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) { |
| rkisp1_write(params->rkisp1, arg->curve_r.gamma_y[i], |
| RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4); |
| rkisp1_write(params->rkisp1, arg->curve_g.gamma_y[i], |
| RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4); |
| rkisp1_write(params->rkisp1, arg->curve_b.gamma_y[i], |
| RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4); |
| } |
| } |
| |
| /* ISP GAMMA correction interface function */ |
| static void rkisp1_goc_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_goc_config *arg) |
| { |
| unsigned int i; |
| |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); |
| rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; i++) |
| rkisp1_write(params->rkisp1, arg->gamma_y[i], |
| RKISP1_CIF_ISP_GAMMA_OUT_Y_0 + i * 4); |
| } |
| |
| /* ISP Cross Talk */ |
| static void rkisp1_ctk_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_ctk_config *arg) |
| { |
| unsigned int i, j, k = 0; |
| |
| for (i = 0; i < 3; i++) |
| for (j = 0; j < 3; j++) |
| rkisp1_write(params->rkisp1, arg->coeff[i][j], |
| RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++); |
| for (i = 0; i < 3; i++) |
| rkisp1_write(params->rkisp1, arg->ct_offset[i], |
| RKISP1_CIF_ISP_CT_OFFSET_R + i * 4); |
| } |
| |
| static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) |
| { |
| if (en) |
| return; |
| |
| /* Write back the default values. */ |
| rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_0); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_1); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_2); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_3); |
| rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_4); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_5); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_6); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_7); |
| rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_8); |
| |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_R); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_G); |
| rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_B); |
| } |
| |
| /* ISP White Balance Mode */ |
| static void rkisp1_awb_meas_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_awb_meas_config *arg) |
| { |
| u32 reg_val = 0; |
| /* based on the mode,configure the awb module */ |
| if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { |
| /* Reference Cb and Cr */ |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | |
| arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF); |
| /* Yc Threshold */ |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | |
| RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | |
| RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | |
| arg->min_c, RKISP1_CIF_ISP_AWB_THRESH); |
| } |
| |
| reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); |
| if (arg->enable_ymax_cmp) |
| reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; |
| else |
| reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; |
| rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); |
| |
| /* window offset */ |
| rkisp1_write(params->rkisp1, |
| arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS); |
| rkisp1_write(params->rkisp1, |
| arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS); |
| /* AWB window size */ |
| rkisp1_write(params->rkisp1, |
| arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE); |
| rkisp1_write(params->rkisp1, |
| arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE); |
| /* Number of frames */ |
| rkisp1_write(params->rkisp1, |
| arg->frames, RKISP1_CIF_ISP_AWB_FRAMES); |
| } |
| |
| static void |
| rkisp1_awb_meas_enable(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_awb_meas_config *arg, |
| bool en) |
| { |
| u32 reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); |
| |
| /* switch off */ |
| reg_val &= RKISP1_CIF_ISP_AWB_MODE_MASK_NONE; |
| |
| if (en) { |
| if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_RGB) |
| reg_val |= RKISP1_CIF_ISP_AWB_MODE_RGB_EN; |
| else |
| reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; |
| |
| rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); |
| |
| /* Measurements require AWB block be active. */ |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); |
| } else { |
| rkisp1_write(params->rkisp1, |
| reg_val, RKISP1_CIF_ISP_AWB_PROP); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); |
| } |
| } |
| |
| static void |
| rkisp1_awb_gain_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_awb_gain_config *arg) |
| { |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | |
| arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G); |
| |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | |
| arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB); |
| } |
| |
| static void rkisp1_aec_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_aec_config *arg) |
| { |
| unsigned int block_hsize, block_vsize; |
| u32 exp_ctrl; |
| |
| /* avoid to override the old enable value */ |
| exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL); |
| exp_ctrl &= RKISP1_CIF_ISP_EXP_ENA; |
| if (arg->autostop) |
| exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP; |
| if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) |
| exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; |
| rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); |
| |
| rkisp1_write(params->rkisp1, |
| arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET); |
| rkisp1_write(params->rkisp1, |
| arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET); |
| |
| block_hsize = arg->meas_window.h_size / |
| RKISP1_CIF_ISP_EXP_COLUMN_NUM - 1; |
| block_vsize = arg->meas_window.v_size / |
| RKISP1_CIF_ISP_EXP_ROW_NUM - 1; |
| |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_EXP_H_SIZE_SET(block_hsize), |
| RKISP1_CIF_ISP_EXP_H_SIZE); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_EXP_V_SIZE_SET(block_vsize), |
| RKISP1_CIF_ISP_EXP_V_SIZE); |
| } |
| |
| static void rkisp1_cproc_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_cproc_config *arg) |
| { |
| struct rkisp1_cif_isp_isp_other_cfg *cur_other_cfg = |
| container_of(arg, struct rkisp1_cif_isp_isp_other_cfg, cproc_config); |
| struct rkisp1_cif_isp_ie_config *cur_ie_config = |
| &cur_other_cfg->ie_config; |
| u32 effect = cur_ie_config->effect; |
| u32 quantization = params->quantization; |
| |
| rkisp1_write(params->rkisp1, arg->contrast, RKISP1_CIF_C_PROC_CONTRAST); |
| rkisp1_write(params->rkisp1, arg->hue, RKISP1_CIF_C_PROC_HUE); |
| rkisp1_write(params->rkisp1, arg->sat, RKISP1_CIF_C_PROC_SATURATION); |
| rkisp1_write(params->rkisp1, arg->brightness, |
| RKISP1_CIF_C_PROC_BRIGHTNESS); |
| |
| if (quantization != V4L2_QUANTIZATION_FULL_RANGE || |
| effect != V4L2_COLORFX_NONE) { |
| rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, |
| RKISP1_CIF_C_PROC_YOUT_FULL | |
| RKISP1_CIF_C_PROC_YIN_FULL | |
| RKISP1_CIF_C_PROC_COUT_FULL); |
| } else { |
| rkisp1_param_set_bits(params, RKISP1_CIF_C_PROC_CTRL, |
| RKISP1_CIF_C_PROC_YOUT_FULL | |
| RKISP1_CIF_C_PROC_YIN_FULL | |
| RKISP1_CIF_C_PROC_COUT_FULL); |
| } |
| } |
| |
| static void rkisp1_hst_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_hst_config *arg) |
| { |
| unsigned int block_hsize, block_vsize; |
| static const u32 hist_weight_regs[] = { |
| RKISP1_CIF_ISP_HIST_WEIGHT_00TO30, |
| RKISP1_CIF_ISP_HIST_WEIGHT_40TO21, |
| RKISP1_CIF_ISP_HIST_WEIGHT_31TO12, |
| RKISP1_CIF_ISP_HIST_WEIGHT_22TO03, |
| RKISP1_CIF_ISP_HIST_WEIGHT_13TO43, |
| RKISP1_CIF_ISP_HIST_WEIGHT_04TO34, |
| }; |
| const u8 *weight; |
| unsigned int i; |
| u32 hist_prop; |
| |
| /* avoid to override the old enable value */ |
| hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP); |
| hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; |
| hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET(arg->histogram_predivider); |
| rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP); |
| rkisp1_write(params->rkisp1, |
| arg->meas_window.h_offs, |
| RKISP1_CIF_ISP_HIST_H_OFFS); |
| rkisp1_write(params->rkisp1, |
| arg->meas_window.v_offs, |
| RKISP1_CIF_ISP_HIST_V_OFFS); |
| |
| block_hsize = arg->meas_window.h_size / |
| RKISP1_CIF_ISP_HIST_COLUMN_NUM - 1; |
| block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM - 1; |
| |
| rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE); |
| rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE); |
| |
| weight = arg->hist_weight; |
| for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_HIST_WEIGHT_SET(weight[0], |
| weight[1], |
| weight[2], |
| weight[3]), |
| hist_weight_regs[i]); |
| |
| rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44); |
| } |
| |
| static void |
| rkisp1_hst_enable(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_hst_config *arg, bool en) |
| { |
| if (en) { |
| u32 hist_prop = rkisp1_read(params->rkisp1, |
| RKISP1_CIF_ISP_HIST_PROP); |
| |
| hist_prop &= ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; |
| hist_prop |= arg->mode; |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, |
| hist_prop); |
| } else { |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_PROP, |
| RKISP1_CIF_ISP_HIST_PROP_MODE_MASK); |
| } |
| } |
| |
| static void rkisp1_afm_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_afc_config *arg) |
| { |
| size_t num_of_win = min_t(size_t, ARRAY_SIZE(arg->afm_win), |
| arg->num_afm_win); |
| u32 afm_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL); |
| unsigned int i; |
| |
| /* Switch off to configure. */ |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, |
| RKISP1_CIF_ISP_AFM_ENA); |
| |
| for (i = 0; i < num_of_win; i++) { |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | |
| RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), |
| RKISP1_CIF_ISP_AFM_LT_A + i * 8); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + |
| arg->afm_win[i].h_offs) | |
| RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + |
| arg->afm_win[i].v_offs), |
| RKISP1_CIF_ISP_AFM_RB_A + i * 8); |
| } |
| rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); |
| rkisp1_write(params->rkisp1, arg->var_shift, |
| RKISP1_CIF_ISP_AFM_VAR_SHIFT); |
| /* restore afm status */ |
| rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); |
| } |
| |
| static void rkisp1_ie_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_ie_config *arg) |
| { |
| u32 eff_ctrl; |
| |
| eff_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL); |
| eff_ctrl &= ~RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK; |
| |
| if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL; |
| |
| switch (arg->effect) { |
| case V4L2_COLORFX_SEPIA: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; |
| break; |
| case V4L2_COLORFX_SET_CBCR: |
| rkisp1_write(params->rkisp1, arg->eff_tint, |
| RKISP1_CIF_IMG_EFF_TINT); |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; |
| break; |
| /* |
| * Color selection is similar to water color(AQUA): |
| * grayscale + selected color w threshold |
| */ |
| case V4L2_COLORFX_AQUA: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL; |
| rkisp1_write(params->rkisp1, arg->color_sel, |
| RKISP1_CIF_IMG_EFF_COLOR_SEL); |
| break; |
| case V4L2_COLORFX_EMBOSS: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS; |
| rkisp1_write(params->rkisp1, arg->eff_mat_1, |
| RKISP1_CIF_IMG_EFF_MAT_1); |
| rkisp1_write(params->rkisp1, arg->eff_mat_2, |
| RKISP1_CIF_IMG_EFF_MAT_2); |
| rkisp1_write(params->rkisp1, arg->eff_mat_3, |
| RKISP1_CIF_IMG_EFF_MAT_3); |
| break; |
| case V4L2_COLORFX_SKETCH: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH; |
| rkisp1_write(params->rkisp1, arg->eff_mat_3, |
| RKISP1_CIF_IMG_EFF_MAT_3); |
| rkisp1_write(params->rkisp1, arg->eff_mat_4, |
| RKISP1_CIF_IMG_EFF_MAT_4); |
| rkisp1_write(params->rkisp1, arg->eff_mat_5, |
| RKISP1_CIF_IMG_EFF_MAT_5); |
| break; |
| case V4L2_COLORFX_BW: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE; |
| break; |
| case V4L2_COLORFX_NEGATIVE: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE; |
| break; |
| default: |
| break; |
| } |
| |
| rkisp1_write(params->rkisp1, eff_ctrl, RKISP1_CIF_IMG_EFF_CTRL); |
| } |
| |
| static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) |
| { |
| if (en) { |
| rkisp1_param_set_bits(params, RKISP1_CIF_ICCL, |
| RKISP1_CIF_ICCL_IE_CLK); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL_ENABLE, |
| RKISP1_CIF_IMG_EFF_CTRL); |
| rkisp1_param_set_bits(params, RKISP1_CIF_IMG_EFF_CTRL, |
| RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD); |
| } else { |
| rkisp1_param_clear_bits(params, RKISP1_CIF_IMG_EFF_CTRL, |
| RKISP1_CIF_IMG_EFF_CTRL_ENABLE); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ICCL, |
| RKISP1_CIF_ICCL_IE_CLK); |
| } |
| } |
| |
| static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) |
| { |
| static const u16 full_range_coeff[] = { |
| 0x0026, 0x004b, 0x000f, |
| 0x01ea, 0x01d6, 0x0040, |
| 0x0040, 0x01ca, 0x01f6 |
| }; |
| static const u16 limited_range_coeff[] = { |
| 0x0021, 0x0040, 0x000d, |
| 0x01ed, 0x01db, 0x0038, |
| 0x0038, 0x01d1, 0x01f7, |
| }; |
| unsigned int i; |
| |
| if (full_range) { |
| for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) |
| rkisp1_write(params->rkisp1, full_range_coeff[i], |
| RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); |
| |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | |
| RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); |
| } else { |
| for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) |
| rkisp1_write(params->rkisp1, limited_range_coeff[i], |
| RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); |
| |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | |
| RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); |
| } |
| } |
| |
| /* ISP De-noise Pre-Filter(DPF) function */ |
| static void rkisp1_dpf_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_dpf_config *arg) |
| { |
| unsigned int isp_dpf_mode, spatial_coeff, i; |
| |
| switch (arg->gain.mode) { |
| case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: |
| isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | |
| RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; |
| break; |
| case RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: |
| isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; |
| break; |
| case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: |
| isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | |
| RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP | |
| RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; |
| break; |
| case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: |
| isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; |
| break; |
| case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: |
| isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP | |
| RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; |
| break; |
| case RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: |
| default: |
| isp_dpf_mode = 0; |
| break; |
| } |
| |
| if (arg->nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) |
| isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION; |
| if (arg->rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9) |
| isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9; |
| if (!arg->rb_flt.r_enable) |
| isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS; |
| if (!arg->rb_flt.b_enable) |
| isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS; |
| if (!arg->g_flt.gb_enable) |
| isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS; |
| if (!arg->g_flt.gr_enable) |
| isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS; |
| |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE, |
| isp_dpf_mode); |
| rkisp1_write(params->rkisp1, arg->gain.nf_b_gain, |
| RKISP1_CIF_ISP_DPF_NF_GAIN_B); |
| rkisp1_write(params->rkisp1, arg->gain.nf_r_gain, |
| RKISP1_CIF_ISP_DPF_NF_GAIN_R); |
| rkisp1_write(params->rkisp1, arg->gain.nf_gb_gain, |
| RKISP1_CIF_ISP_DPF_NF_GAIN_GB); |
| rkisp1_write(params->rkisp1, arg->gain.nf_gr_gain, |
| RKISP1_CIF_ISP_DPF_NF_GAIN_GR); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { |
| rkisp1_write(params->rkisp1, arg->nll.coeff[i], |
| RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4); |
| } |
| |
| spatial_coeff = arg->g_flt.spatial_coeff[0] | |
| (arg->g_flt.spatial_coeff[1] << 8) | |
| (arg->g_flt.spatial_coeff[2] << 16) | |
| (arg->g_flt.spatial_coeff[3] << 24); |
| rkisp1_write(params->rkisp1, spatial_coeff, |
| RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4); |
| |
| spatial_coeff = arg->g_flt.spatial_coeff[4] | |
| (arg->g_flt.spatial_coeff[5] << 8); |
| rkisp1_write(params->rkisp1, spatial_coeff, |
| RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6); |
| |
| spatial_coeff = arg->rb_flt.spatial_coeff[0] | |
| (arg->rb_flt.spatial_coeff[1] << 8) | |
| (arg->rb_flt.spatial_coeff[2] << 16) | |
| (arg->rb_flt.spatial_coeff[3] << 24); |
| rkisp1_write(params->rkisp1, spatial_coeff, |
| RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4); |
| |
| spatial_coeff = arg->rb_flt.spatial_coeff[4] | |
| (arg->rb_flt.spatial_coeff[5] << 8); |
| rkisp1_write(params->rkisp1, spatial_coeff, |
| RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6); |
| } |
| |
| static void |
| rkisp1_dpf_strength_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_dpf_strength_config *arg) |
| { |
| rkisp1_write(params->rkisp1, arg->b, RKISP1_CIF_ISP_DPF_STRENGTH_B); |
| rkisp1_write(params->rkisp1, arg->g, RKISP1_CIF_ISP_DPF_STRENGTH_G); |
| rkisp1_write(params->rkisp1, arg->r, RKISP1_CIF_ISP_DPF_STRENGTH_R); |
| } |
| |
| static void |
| rkisp1_isp_isr_other_config(struct rkisp1_params *params, |
| const struct rkisp1_params_cfg *new_params) |
| { |
| unsigned int module_en_update, module_cfg_update, module_ens; |
| |
| module_en_update = new_params->module_en_update; |
| module_cfg_update = new_params->module_cfg_update; |
| module_ens = new_params->module_ens; |
| |
| /* update dpc config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC) |
| rkisp1_dpcc_config(params, |
| &new_params->others.dpcc_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_DPCC_MODE, |
| RKISP1_CIF_ISP_DPCC_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_DPCC_MODE, |
| RKISP1_CIF_ISP_DPCC_ENA); |
| } |
| |
| /* update bls config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS) |
| rkisp1_bls_config(params, |
| &new_params->others.bls_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_BLS) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_BLS) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_BLS_CTRL, |
| RKISP1_CIF_ISP_BLS_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_BLS_CTRL, |
| RKISP1_CIF_ISP_BLS_ENA); |
| } |
| |
| /* update sdg config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG) |
| rkisp1_sdg_config(params, |
| &new_params->others.sdg_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_SDG) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_SDG) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); |
| } |
| |
| /* update lsc config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) |
| rkisp1_lsc_config(params, |
| &new_params->others.lsc_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_LSC_CTRL, |
| RKISP1_CIF_ISP_LSC_CTRL_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_LSC_CTRL, |
| RKISP1_CIF_ISP_LSC_CTRL_ENA); |
| } |
| |
| /* update awb gains */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) |
| rkisp1_awb_gain_config(params, &new_params->others.awb_gain_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); |
| } |
| |
| /* update bdm config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM) |
| rkisp1_bdm_config(params, |
| &new_params->others.bdm_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_BDM) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_BDM) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_DEMOSAIC, |
| RKISP1_CIF_ISP_DEMOSAIC_BYPASS); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_DEMOSAIC, |
| RKISP1_CIF_ISP_DEMOSAIC_BYPASS); |
| } |
| |
| /* update filter config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT) |
| rkisp1_flt_config(params, |
| &new_params->others.flt_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_FLT) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_FLT) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_FILT_MODE, |
| RKISP1_CIF_ISP_FLT_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_FILT_MODE, |
| RKISP1_CIF_ISP_FLT_ENA); |
| } |
| |
| /* update ctk config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK) |
| rkisp1_ctk_config(params, |
| &new_params->others.ctk_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_CTK) |
| rkisp1_ctk_enable(params, !!(module_ens & RKISP1_CIF_ISP_MODULE_CTK)); |
| |
| /* update goc config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC) |
| rkisp1_goc_config(params, |
| &new_params->others.goc_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_GOC) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); |
| } |
| |
| /* update cproc config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC) |
| rkisp1_cproc_config(params, |
| &new_params->others.cproc_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_CPROC) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_C_PROC_CTRL, |
| RKISP1_CIF_C_PROC_CTR_ENABLE); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_C_PROC_CTRL, |
| RKISP1_CIF_C_PROC_CTR_ENABLE); |
| } |
| |
| /* update ie config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE) |
| rkisp1_ie_config(params, &new_params->others.ie_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_IE) |
| rkisp1_ie_enable(params, !!(module_ens & RKISP1_CIF_ISP_MODULE_IE)); |
| |
| /* update dpf config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF) |
| rkisp1_dpf_config(params, &new_params->others.dpf_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_DPF) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_DPF) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_DPF_MODE, |
| RKISP1_CIF_ISP_DPF_MODE_EN); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_DPF_MODE, |
| RKISP1_CIF_ISP_DPF_MODE_EN); |
| } |
| |
| if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH) || |
| (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH)) { |
| /* update dpf strength config */ |
| rkisp1_dpf_strength_config(params, |
| &new_params->others.dpf_strength_config); |
| } |
| } |
| |
| static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, |
| struct rkisp1_params_cfg *new_params) |
| { |
| unsigned int module_en_update, module_cfg_update, module_ens; |
| |
| module_en_update = new_params->module_en_update; |
| module_cfg_update = new_params->module_cfg_update; |
| module_ens = new_params->module_ens; |
| |
| /* update awb config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB) |
| rkisp1_awb_meas_config(params, &new_params->meas.awb_meas_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) |
| rkisp1_awb_meas_enable(params, |
| &new_params->meas.awb_meas_config, |
| !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); |
| |
| /* update afc config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC) |
| rkisp1_afm_config(params, |
| &new_params->meas.afc_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_AFC) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_AFM_CTRL, |
| RKISP1_CIF_ISP_AFM_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_AFM_CTRL, |
| RKISP1_CIF_ISP_AFM_ENA); |
| } |
| |
| /* update hst config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST) |
| rkisp1_hst_config(params, |
| &new_params->meas.hst_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) |
| rkisp1_hst_enable(params, |
| &new_params->meas.hst_config, |
| !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); |
| |
| /* update aec config */ |
| if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC) |
| rkisp1_aec_config(params, |
| &new_params->meas.aec_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { |
| if (module_ens & RKISP1_CIF_ISP_MODULE_AEC) |
| rkisp1_param_set_bits(params, |
| RKISP1_CIF_ISP_EXP_CTRL, |
| RKISP1_CIF_ISP_EXP_ENA); |
| else |
| rkisp1_param_clear_bits(params, |
| RKISP1_CIF_ISP_EXP_CTRL, |
| RKISP1_CIF_ISP_EXP_ENA); |
| } |
| } |
| |
| static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params, |
| unsigned int frame_sequence) |
| { |
| struct rkisp1_params_cfg *new_params; |
| struct rkisp1_buffer *cur_buf = NULL; |
| |
| if (list_empty(¶ms->params)) |
| return; |
| |
| cur_buf = list_first_entry(¶ms->params, |
| struct rkisp1_buffer, queue); |
| |
| new_params = (struct rkisp1_params_cfg *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); |
| |
| rkisp1_isp_isr_other_config(params, new_params); |
| rkisp1_isp_isr_meas_config(params, new_params); |
| |
| /* update shadow register immediately */ |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); |
| |
| list_del(&cur_buf->queue); |
| |
| cur_buf->vb.sequence = frame_sequence; |
| vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); |
| } |
| |
| void rkisp1_params_isr(struct rkisp1_device *rkisp1) |
| { |
| /* |
| * This isr is called when the ISR finishes processing a frame (RKISP1_CIF_ISP_FRAME). |
| * Configurations performed here will be applied on the next frame. |
| * Since frame_sequence is updated on the vertical sync signal, we should use |
| * frame_sequence + 1 here to indicate to userspace on which frame these parameters |
| * are being applied. |
| */ |
| unsigned int frame_sequence = rkisp1->isp.frame_sequence + 1; |
| struct rkisp1_params *params = &rkisp1->params; |
| |
| spin_lock(¶ms->config_lock); |
| rkisp1_params_apply_params_cfg(params, frame_sequence); |
| |
| spin_unlock(¶ms->config_lock); |
| } |
| |
| static const struct rkisp1_cif_isp_awb_meas_config rkisp1_awb_params_default_config = { |
| { |
| 0, 0, RKISP1_DEFAULT_WIDTH, RKISP1_DEFAULT_HEIGHT |
| }, |
| RKISP1_CIF_ISP_AWB_MODE_YCBCR, 200, 30, 20, 20, 0, 128, 128 |
| }; |
| |
| static const struct rkisp1_cif_isp_aec_config rkisp1_aec_params_default_config = { |
| RKISP1_CIF_ISP_EXP_MEASURING_MODE_0, |
| RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0, |
| { |
| RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, |
| RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 |
| } |
| }; |
| |
| static const struct rkisp1_cif_isp_hst_config rkisp1_hst_params_default_config = { |
| RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED, |
| 3, |
| { |
| RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, |
| RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 |
| }, |
| { |
| 0, /* To be filled in with 0x01 at runtime. */ |
| } |
| }; |
| |
| static const struct rkisp1_cif_isp_afc_config rkisp1_afc_params_default_config = { |
| 1, |
| { |
| { |
| 300, 225, 200, 150 |
| } |
| }, |
| 4, |
| 14 |
| }; |
| |
| static void rkisp1_params_config_parameter(struct rkisp1_params *params) |
| { |
| struct rkisp1_cif_isp_hst_config hst = rkisp1_hst_params_default_config; |
| |
| rkisp1_awb_meas_config(params, &rkisp1_awb_params_default_config); |
| rkisp1_awb_meas_enable(params, &rkisp1_awb_params_default_config, |
| true); |
| |
| rkisp1_aec_config(params, &rkisp1_aec_params_default_config); |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_EXP_CTRL, |
| RKISP1_CIF_ISP_EXP_ENA); |
| |
| rkisp1_afm_config(params, &rkisp1_afc_params_default_config); |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_AFM_CTRL, |
| RKISP1_CIF_ISP_AFM_ENA); |
| |
| memset(hst.hist_weight, 0x01, sizeof(hst.hist_weight)); |
| rkisp1_hst_config(params, &hst); |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, |
| rkisp1_hst_params_default_config.mode); |
| |
| /* set the range */ |
| if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) |
| rkisp1_csm_config(params, true); |
| else |
| rkisp1_csm_config(params, false); |
| |
| spin_lock_irq(¶ms->config_lock); |
| |
| /* apply the first buffer if there is one already */ |
| rkisp1_params_apply_params_cfg(params, 0); |
| |
| spin_unlock_irq(¶ms->config_lock); |
| } |
| |
| void rkisp1_params_configure(struct rkisp1_params *params, |
| enum rkisp1_fmt_raw_pat_type bayer_pat, |
| enum v4l2_quantization quantization) |
| { |
| params->quantization = quantization; |
| params->raw_type = bayer_pat; |
| rkisp1_params_config_parameter(params); |
| } |
| |
| /* |
| * Not called when the camera is active, therefore there is no need to acquire |
| * a lock. |
| */ |
| void rkisp1_params_disable(struct rkisp1_params *params) |
| { |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, |
| RKISP1_CIF_ISP_DPCC_ENA); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, |
| RKISP1_CIF_ISP_LSC_CTRL_ENA); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_BLS_CTRL, |
| RKISP1_CIF_ISP_BLS_ENA); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DEMOSAIC, |
| RKISP1_CIF_ISP_DEMOSAIC_BYPASS); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_FILT_MODE, |
| RKISP1_CIF_ISP_FLT_ENA); |
| rkisp1_awb_meas_enable(params, NULL, false); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_EXP_CTRL, |
| RKISP1_CIF_ISP_EXP_ENA); |
| rkisp1_ctk_enable(params, false); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, |
| RKISP1_CIF_C_PROC_CTR_ENABLE); |
| rkisp1_hst_enable(params, NULL, false); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, |
| RKISP1_CIF_ISP_AFM_ENA); |
| rkisp1_ie_enable(params, false); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPF_MODE, |
| RKISP1_CIF_ISP_DPF_MODE_EN); |
| } |
| |
| static int rkisp1_params_enum_fmt_meta_out(struct file *file, void *priv, |
| struct v4l2_fmtdesc *f) |
| { |
| struct video_device *video = video_devdata(file); |
| struct rkisp1_params *params = video_get_drvdata(video); |
| |
| if (f->index > 0 || f->type != video->queue->type) |
| return -EINVAL; |
| |
| f->pixelformat = params->vdev_fmt.fmt.meta.dataformat; |
| |
| return 0; |
| } |
| |
| static int rkisp1_params_g_fmt_meta_out(struct file *file, void *fh, |
| struct v4l2_format *f) |
| { |
| struct video_device *video = video_devdata(file); |
| struct rkisp1_params *params = video_get_drvdata(video); |
| struct v4l2_meta_format *meta = &f->fmt.meta; |
| |
| if (f->type != video->queue->type) |
| return -EINVAL; |
| |
| memset(meta, 0, sizeof(*meta)); |
| meta->dataformat = params->vdev_fmt.fmt.meta.dataformat; |
| meta->buffersize = params->vdev_fmt.fmt.meta.buffersize; |
| |
| return 0; |
| } |
| |
| static int rkisp1_params_querycap(struct file *file, |
| void *priv, struct v4l2_capability *cap) |
| { |
| struct video_device *vdev = video_devdata(file); |
| |
| strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); |
| strscpy(cap->card, vdev->name, sizeof(cap->card)); |
| strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); |
| |
| return 0; |
| } |
| |
| /* ISP params video device IOCTLs */ |
| static const struct v4l2_ioctl_ops rkisp1_params_ioctl = { |
| .vidioc_reqbufs = vb2_ioctl_reqbufs, |
| .vidioc_querybuf = vb2_ioctl_querybuf, |
| .vidioc_create_bufs = vb2_ioctl_create_bufs, |
| .vidioc_qbuf = vb2_ioctl_qbuf, |
| .vidioc_dqbuf = vb2_ioctl_dqbuf, |
| .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
| .vidioc_expbuf = vb2_ioctl_expbuf, |
| .vidioc_streamon = vb2_ioctl_streamon, |
| .vidioc_streamoff = vb2_ioctl_streamoff, |
| .vidioc_enum_fmt_meta_out = rkisp1_params_enum_fmt_meta_out, |
| .vidioc_g_fmt_meta_out = rkisp1_params_g_fmt_meta_out, |
| .vidioc_s_fmt_meta_out = rkisp1_params_g_fmt_meta_out, |
| .vidioc_try_fmt_meta_out = rkisp1_params_g_fmt_meta_out, |
| .vidioc_querycap = rkisp1_params_querycap, |
| .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
| .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
| }; |
| |
| static int rkisp1_params_vb2_queue_setup(struct vb2_queue *vq, |
| unsigned int *num_buffers, |
| unsigned int *num_planes, |
| unsigned int sizes[], |
| struct device *alloc_devs[]) |
| { |
| *num_buffers = clamp_t(u32, *num_buffers, |
| RKISP1_ISP_PARAMS_REQ_BUFS_MIN, |
| RKISP1_ISP_PARAMS_REQ_BUFS_MAX); |
| |
| *num_planes = 1; |
| |
| sizes[0] = sizeof(struct rkisp1_params_cfg); |
| |
| return 0; |
| } |
| |
| static void rkisp1_params_vb2_buf_queue(struct vb2_buffer *vb) |
| { |
| struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
| struct rkisp1_buffer *params_buf = |
| container_of(vbuf, struct rkisp1_buffer, vb); |
| struct vb2_queue *vq = vb->vb2_queue; |
| struct rkisp1_params *params = vq->drv_priv; |
| |
| spin_lock_irq(¶ms->config_lock); |
| list_add_tail(¶ms_buf->queue, ¶ms->params); |
| spin_unlock_irq(¶ms->config_lock); |
| } |
| |
| static int rkisp1_params_vb2_buf_prepare(struct vb2_buffer *vb) |
| { |
| if (vb2_plane_size(vb, 0) < sizeof(struct rkisp1_params_cfg)) |
| return -EINVAL; |
| |
| vb2_set_plane_payload(vb, 0, sizeof(struct rkisp1_params_cfg)); |
| |
| return 0; |
| } |
| |
| static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) |
| { |
| struct rkisp1_params *params = vq->drv_priv; |
| struct rkisp1_buffer *buf; |
| LIST_HEAD(tmp_list); |
| |
| /* |
| * we first move the buffers into a local list 'tmp_list' |
| * and then we can iterate it and call vb2_buffer_done |
| * without holding the lock |
| */ |
| spin_lock_irq(¶ms->config_lock); |
| list_splice_init(¶ms->params, &tmp_list); |
| spin_unlock_irq(¶ms->config_lock); |
| |
| list_for_each_entry(buf, &tmp_list, queue) |
| vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); |
| } |
| |
| static const struct vb2_ops rkisp1_params_vb2_ops = { |
| .queue_setup = rkisp1_params_vb2_queue_setup, |
| .wait_prepare = vb2_ops_wait_prepare, |
| .wait_finish = vb2_ops_wait_finish, |
| .buf_queue = rkisp1_params_vb2_buf_queue, |
| .buf_prepare = rkisp1_params_vb2_buf_prepare, |
| .stop_streaming = rkisp1_params_vb2_stop_streaming, |
| |
| }; |
| |
| static const struct v4l2_file_operations rkisp1_params_fops = { |
| .mmap = vb2_fop_mmap, |
| .unlocked_ioctl = video_ioctl2, |
| .poll = vb2_fop_poll, |
| .open = v4l2_fh_open, |
| .release = vb2_fop_release |
| }; |
| |
| static int rkisp1_params_init_vb2_queue(struct vb2_queue *q, |
| struct rkisp1_params *params) |
| { |
| struct rkisp1_vdev_node *node; |
| |
| node = container_of(q, struct rkisp1_vdev_node, buf_queue); |
| |
| q->type = V4L2_BUF_TYPE_META_OUTPUT; |
| q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; |
| q->drv_priv = params; |
| q->ops = &rkisp1_params_vb2_ops; |
| q->mem_ops = &vb2_vmalloc_memops; |
| q->buf_struct_size = sizeof(struct rkisp1_buffer); |
| q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| q->lock = &node->vlock; |
| |
| return vb2_queue_init(q); |
| } |
| |
| static void rkisp1_init_params(struct rkisp1_params *params) |
| { |
| params->vdev_fmt.fmt.meta.dataformat = |
| V4L2_META_FMT_RK_ISP1_PARAMS; |
| params->vdev_fmt.fmt.meta.buffersize = |
| sizeof(struct rkisp1_params_cfg); |
| } |
| |
| int rkisp1_params_register(struct rkisp1_device *rkisp1) |
| { |
| struct rkisp1_params *params = &rkisp1->params; |
| struct rkisp1_vdev_node *node = ¶ms->vnode; |
| struct video_device *vdev = &node->vdev; |
| int ret; |
| |
| params->rkisp1 = rkisp1; |
| mutex_init(&node->vlock); |
| INIT_LIST_HEAD(¶ms->params); |
| spin_lock_init(¶ms->config_lock); |
| |
| strscpy(vdev->name, RKISP1_PARAMS_DEV_NAME, sizeof(vdev->name)); |
| |
| video_set_drvdata(vdev, params); |
| vdev->ioctl_ops = &rkisp1_params_ioctl; |
| vdev->fops = &rkisp1_params_fops; |
| vdev->release = video_device_release_empty; |
| /* |
| * Provide a mutex to v4l2 core. It will be used |
| * to protect all fops and v4l2 ioctls. |
| */ |
| vdev->lock = &node->vlock; |
| vdev->v4l2_dev = &rkisp1->v4l2_dev; |
| vdev->queue = &node->buf_queue; |
| vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT; |
| vdev->vfl_dir = VFL_DIR_TX; |
| rkisp1_params_init_vb2_queue(vdev->queue, params); |
| rkisp1_init_params(params); |
| video_set_drvdata(vdev, params); |
| |
| node->pad.flags = MEDIA_PAD_FL_SOURCE; |
| ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); |
| if (ret) |
| return ret; |
| ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); |
| if (ret) { |
| dev_err(rkisp1->dev, |
| "failed to register %s, ret=%d\n", vdev->name, ret); |
| goto err_cleanup_media_entity; |
| } |
| return 0; |
| err_cleanup_media_entity: |
| media_entity_cleanup(&vdev->entity); |
| return ret; |
| } |
| |
| void rkisp1_params_unregister(struct rkisp1_device *rkisp1) |
| { |
| struct rkisp1_params *params = &rkisp1->params; |
| struct rkisp1_vdev_node *node = ¶ms->vnode; |
| struct video_device *vdev = &node->vdev; |
| |
| vb2_video_unregister_device(vdev); |
| media_entity_cleanup(&vdev->entity); |
| } |