| // 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, reg, val | bit_mask); |
| } |
| |
| 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, reg, val & ~bit_mask); |
| } |
| |
| /* 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, RKISP1_CIF_ISP_DPCC_MODE, mode); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_OUTPUT_MODE, |
| arg->output_mode); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_SET_USE, |
| arg->set_use); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_1, |
| arg->methods[0].method); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_2, |
| arg->methods[1].method); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_3, |
| arg->methods[2].method); |
| for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { |
| rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_THRESH(i), |
| arg->methods[i].line_thresh); |
| rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_MAD_FAC(i), |
| arg->methods[i].line_mad_fac); |
| rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_PG_FAC(i), |
| arg->methods[i].pg_fac); |
| rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RND_THRESH(i), |
| arg->methods[i].rnd_thresh); |
| rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RG_FAC(i), |
| arg->methods[i].rg_fac); |
| } |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RND_OFFS, |
| arg->rnd_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RO_LIMITS, |
| arg->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, RKISP1_CIF_ISP_BLS_D_FIXED, |
| pval->r); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, |
| pval->gr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, |
| pval->gb); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, |
| pval->b); |
| break; |
| case RKISP1_RAW_GBRG: |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, |
| pval->r); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, |
| pval->gr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, |
| pval->gb); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, |
| pval->b); |
| break; |
| case RKISP1_RAW_GRBG: |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, |
| pval->r); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, |
| pval->gr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, |
| pval->gb); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, |
| pval->b); |
| break; |
| case RKISP1_RAW_RGGB: |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, |
| pval->r); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, |
| pval->gr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, |
| pval->gb); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, |
| pval->b); |
| break; |
| default: |
| break; |
| } |
| |
| } else { |
| if (arg->en_windows & BIT(1)) { |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_START, |
| arg->bls_window2.h_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_STOP, |
| arg->bls_window2.h_size); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_START, |
| arg->bls_window2.v_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_STOP, |
| arg->bls_window2.v_size); |
| new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2; |
| } |
| |
| if (arg->en_windows & BIT(0)) { |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_START, |
| arg->bls_window1.h_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_STOP, |
| arg->bls_window1.h_size); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_START, |
| arg->bls_window1.v_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_STOP, |
| arg->bls_window1.v_size); |
| new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1; |
| } |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_SAMPLES, |
| arg->bls_samples); |
| |
| new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED; |
| } |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL, new_control); |
| } |
| |
| /* ISP LS correction interface function */ |
| static void |
| rkisp1_lsc_matrix_config_v10(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, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_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_V10(pconfig->r_data_tbl[i][j], |
| pconfig->r_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], |
| pconfig->gr_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], |
| pconfig->gb_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], |
| pconfig->b_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); |
| } |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, |
| data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, |
| data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, |
| data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, |
| 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, RKISP1_CIF_ISP_LSC_TABLE_SEL, |
| isp_lsc_table_sel); |
| } |
| |
| static void |
| rkisp1_lsc_matrix_config_v12(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, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_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_V12( |
| pconfig->r_data_tbl[i][j], |
| pconfig->r_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( |
| pconfig->gr_data_tbl[i][j], |
| pconfig->gr_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( |
| pconfig->gb_data_tbl[i][j], |
| pconfig->gb_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( |
| pconfig->b_data_tbl[i][j], |
| pconfig->b_data_tbl[i][j + 1]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); |
| } |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->r_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, |
| data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gr_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, |
| data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gb_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, |
| data); |
| |
| data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->b_data_tbl[i][j], 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, |
| 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, RKISP1_CIF_ISP_LSC_TABLE_SEL, |
| 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); |
| params->ops->lsc_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, |
| RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data); |
| |
| /* 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, |
| RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data); |
| |
| /* 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, |
| RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data); |
| |
| /* 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, |
| RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data); |
| } |
| |
| /* 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, RKISP1_CIF_ISP_FILT_THRESH_BL0, |
| arg->thresh_bl0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_BL1, |
| arg->thresh_bl1); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH0, |
| arg->thresh_sh0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH1, |
| arg->thresh_sh1); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL0, |
| arg->fac_bl0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL1, |
| arg->fac_bl1); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_MID, |
| arg->fac_mid); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH0, |
| arg->fac_sh0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH1, |
| arg->fac_sh1); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT, |
| arg->lum_weight); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE, |
| (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)); |
| |
| /* 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, RKISP1_CIF_ISP_FILT_MODE, 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, RKISP1_CIF_ISP_DEMOSAIC, bdm_th); |
| 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, RKISP1_CIF_ISP_GAMMA_DX_LO, |
| arg->xa_pnts.gamma_dx0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_DX_HI, |
| arg->xa_pnts.gamma_dx1); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) { |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4, |
| arg->curve_r.gamma_y[i]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4, |
| arg->curve_g.gamma_y[i]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4, |
| arg->curve_b.gamma_y[i]); |
| } |
| } |
| |
| /* ISP GAMMA correction interface function */ |
| static void rkisp1_goc_config_v10(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, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10, |
| arg->mode); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; i++) |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4, |
| arg->gamma_y[i]); |
| } |
| |
| static void rkisp1_goc_config_v12(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_goc_config *arg) |
| { |
| unsigned int i; |
| u32 value; |
| |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12, |
| arg->mode); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12 / 2; i++) { |
| value = RKISP1_CIF_ISP_GAMMA_VALUE_V12( |
| arg->gamma_y[2 * i + 1], |
| arg->gamma_y[2 * i]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4, value); |
| } |
| } |
| |
| /* 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, |
| RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++, |
| arg->coeff[i][j]); |
| for (i = 0; i < 3; i++) |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_CT_OFFSET_R + i * 4, |
| arg->ct_offset[i]); |
| } |
| |
| static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) |
| { |
| if (en) |
| return; |
| |
| /* Write back the default values. */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_0, 0x80); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_1, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_2, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_3, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_4, 0x80); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_5, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_6, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_7, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_8, 0x80); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_R, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_G, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_B, 0); |
| } |
| |
| /* ISP White Balance Mode */ |
| static void rkisp1_awb_meas_config_v10(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_V10, |
| RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | |
| arg->awb_ref_cb); |
| /* Yc Threshold */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V10, |
| 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); |
| } |
| |
| reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10); |
| 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, RKISP1_CIF_ISP_AWB_PROP_V10, reg_val); |
| |
| /* window offset */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10, |
| arg->awb_wnd.v_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10, |
| arg->awb_wnd.h_offs); |
| /* AWB window size */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10, |
| arg->awb_wnd.v_size); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10, |
| arg->awb_wnd.h_size); |
| /* Number of frames */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_FRAMES_V10, |
| arg->frames); |
| } |
| |
| static void rkisp1_awb_meas_config_v12(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_V12, |
| RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | |
| arg->awb_ref_cb); |
| /* Yc Threshold */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V12, |
| 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); |
| } |
| |
| reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12); |
| if (arg->enable_ymax_cmp) |
| reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; |
| else |
| reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; |
| reg_val &= ~RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12; |
| reg_val |= RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(arg->frames); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, reg_val); |
| |
| /* window offset */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_OFFS_V12, |
| arg->awb_wnd.v_offs << 16 | arg->awb_wnd.h_offs); |
| /* AWB window size */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_SIZE_V12, |
| arg->awb_wnd.v_size << 16 | arg->awb_wnd.h_size); |
| } |
| |
| static void |
| rkisp1_awb_meas_enable_v10(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_V10); |
| |
| /* 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, RKISP1_CIF_ISP_AWB_PROP_V10, |
| reg_val); |
| |
| /* 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, RKISP1_CIF_ISP_AWB_PROP_V10, |
| reg_val); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); |
| } |
| } |
| |
| static void |
| rkisp1_awb_meas_enable_v12(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_V12); |
| |
| /* 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, RKISP1_CIF_ISP_AWB_PROP_V12, |
| reg_val); |
| |
| /* 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, RKISP1_CIF_ISP_AWB_PROP_V12, |
| reg_val); |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, |
| RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); |
| } |
| } |
| |
| static void |
| rkisp1_awb_gain_config_v10(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_awb_gain_config *arg) |
| { |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V10, |
| RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | |
| arg->gain_green_b); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V10, |
| RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | |
| arg->gain_blue); |
| } |
| |
| static void |
| rkisp1_awb_gain_config_v12(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_awb_gain_config *arg) |
| { |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V12, |
| RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | |
| arg->gain_green_b); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V12, |
| RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | |
| arg->gain_blue); |
| } |
| |
| static void rkisp1_aec_config_v10(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, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_OFFSET_V10, |
| arg->meas_window.h_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_OFFSET_V10, |
| arg->meas_window.v_offs); |
| |
| block_hsize = arg->meas_window.h_size / |
| RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 - 1; |
| block_vsize = arg->meas_window.v_size / |
| RKISP1_CIF_ISP_EXP_ROW_NUM_V10 - 1; |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_SIZE_V10, |
| RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize)); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_SIZE_V10, |
| RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize)); |
| } |
| |
| static void rkisp1_aec_config_v12(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_aec_config *arg) |
| { |
| u32 exp_ctrl; |
| u32 block_hsize, block_vsize; |
| u32 wnd_num_idx = 1; |
| const u32 ae_wnd_num[] = { 5, 9, 15, 15 }; |
| |
| /* 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; |
| exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_WNDNUM_SET_V12(wnd_num_idx); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_OFFS_V12, |
| RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(arg->meas_window.v_offs) | |
| RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs)); |
| |
| block_hsize = arg->meas_window.h_size / ae_wnd_num[wnd_num_idx] - 1; |
| block_vsize = arg->meas_window.v_size / ae_wnd_num[wnd_num_idx] - 1; |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_SIZE_V12, |
| RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(block_vsize) | |
| RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize)); |
| } |
| |
| 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, RKISP1_CIF_C_PROC_CONTRAST, |
| arg->contrast); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_HUE, arg->hue); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_SATURATION, arg->sat); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_BRIGHTNESS, |
| arg->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_v10(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_V10, |
| RKISP1_CIF_ISP_HIST_WEIGHT_40TO21_V10, |
| RKISP1_CIF_ISP_HIST_WEIGHT_31TO12_V10, |
| RKISP1_CIF_ISP_HIST_WEIGHT_22TO03_V10, |
| RKISP1_CIF_ISP_HIST_WEIGHT_13TO43_V10, |
| RKISP1_CIF_ISP_HIST_WEIGHT_04TO34_V10, |
| }; |
| 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_V10); |
| hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10; |
| hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(arg->histogram_predivider); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10, hist_prop); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_OFFS_V10, |
| arg->meas_window.h_offs); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_OFFS_V10, |
| arg->meas_window.v_offs); |
| |
| block_hsize = arg->meas_window.h_size / |
| RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 - 1; |
| block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM_V10 - 1; |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_SIZE_V10, |
| block_hsize); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_SIZE_V10, |
| block_vsize); |
| |
| weight = arg->hist_weight; |
| for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) |
| rkisp1_write(params->rkisp1, hist_weight_regs[i], |
| RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0], weight[1], |
| weight[2], weight[3])); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10, |
| weight[0] & 0x1F); |
| } |
| |
| static void rkisp1_hst_config_v12(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_hst_config *arg) |
| { |
| unsigned int i, j; |
| u32 block_hsize, block_vsize; |
| u32 wnd_num_idx, hist_weight_num, hist_ctrl, value; |
| u8 weight15x15[RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12]; |
| const u32 hist_wnd_num[] = { 5, 9, 15, 15 }; |
| |
| /* now we just support 9x9 window */ |
| wnd_num_idx = 1; |
| memset(weight15x15, 0x00, sizeof(weight15x15)); |
| /* avoid to override the old enable value */ |
| hist_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_CTRL_V12); |
| hist_ctrl &= RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12 | |
| RKISP1_CIF_ISP_HIST_CTRL_EN_MASK_V12; |
| hist_ctrl = hist_ctrl | |
| RKISP1_CIF_ISP_HIST_CTRL_INTRSEL_SET_V12(1) | |
| RKISP1_CIF_ISP_HIST_CTRL_DATASEL_SET_V12(0) | |
| RKISP1_CIF_ISP_HIST_CTRL_WATERLINE_SET_V12(0) | |
| RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(0) | |
| RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(1) | |
| RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(arg->histogram_predivider); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_CTRL_V12, hist_ctrl); |
| |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_OFFS_V12, |
| RKISP1_CIF_ISP_HIST_OFFS_SET_V12(arg->meas_window.h_offs, |
| arg->meas_window.v_offs)); |
| |
| block_hsize = arg->meas_window.h_size / hist_wnd_num[wnd_num_idx] - 1; |
| block_vsize = arg->meas_window.v_size / hist_wnd_num[wnd_num_idx] - 1; |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_SIZE_V12, |
| RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize)); |
| |
| for (i = 0; i < hist_wnd_num[wnd_num_idx]; i++) { |
| for (j = 0; j < hist_wnd_num[wnd_num_idx]; j++) { |
| weight15x15[i * RKISP1_CIF_ISP_HIST_ROW_NUM_V12 + j] = |
| arg->hist_weight[i * hist_wnd_num[wnd_num_idx] + j]; |
| } |
| } |
| |
| hist_weight_num = RKISP1_CIF_ISP_HIST_WEIGHT_REG_SIZE_V12; |
| for (i = 0; i < (hist_weight_num / 4); i++) { |
| value = RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12( |
| weight15x15[4 * i + 0], |
| weight15x15[4 * i + 1], |
| weight15x15[4 * i + 2], |
| weight15x15[4 * i + 3]); |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i, value); |
| } |
| value = RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(weight15x15[4 * i + 0], 0, 0, 0); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i, |
| value); |
| } |
| |
| static void |
| rkisp1_hst_enable_v10(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_V10); |
| |
| hist_prop &= ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10; |
| hist_prop |= arg->mode; |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, |
| hist_prop); |
| } else { |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, |
| RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10); |
| } |
| } |
| |
| static void |
| rkisp1_hst_enable_v12(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_hst_config *arg, bool en) |
| { |
| if (en) { |
| u32 hist_ctrl = rkisp1_read(params->rkisp1, |
| RKISP1_CIF_ISP_HIST_CTRL_V12); |
| |
| hist_ctrl &= ~RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12; |
| hist_ctrl |= RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(arg->mode); |
| hist_ctrl |= RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(1); |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_CTRL_V12, |
| hist_ctrl); |
| } else { |
| rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_CTRL_V12, |
| RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12 | |
| RKISP1_CIF_ISP_HIST_CTRL_EN_MASK_V12); |
| } |
| } |
| |
| static void rkisp1_afm_config_v10(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_LT_A + i * 8, |
| 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_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8, |
| 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_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT, |
| arg->var_shift); |
| /* restore afm status */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, afm_ctrl); |
| } |
| |
| static void rkisp1_afm_config_v12(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); |
| u32 lum_var_shift, afm_var_shift; |
| 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_LT_A + i * 8, |
| 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_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8, |
| 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_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres); |
| |
| lum_var_shift = RKISP1_CIF_ISP_AFM_GET_LUM_SHIFT_a_V12(arg->var_shift); |
| afm_var_shift = RKISP1_CIF_ISP_AFM_GET_AFM_SHIFT_a_V12(arg->var_shift); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT, |
| RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(lum_var_shift, afm_var_shift) | |
| RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(lum_var_shift, afm_var_shift) | |
| RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift)); |
| |
| /* restore afm status */ |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, 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, RKISP1_CIF_IMG_EFF_TINT, |
| arg->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, RKISP1_CIF_IMG_EFF_COLOR_SEL, |
| arg->color_sel); |
| break; |
| case V4L2_COLORFX_EMBOSS: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS; |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_1, |
| arg->eff_mat_1); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_2, |
| arg->eff_mat_2); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3, |
| arg->eff_mat_3); |
| break; |
| case V4L2_COLORFX_SKETCH: |
| eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH; |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3, |
| arg->eff_mat_3); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_4, |
| arg->eff_mat_4); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_5, |
| arg->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, RKISP1_CIF_IMG_EFF_CTRL, eff_ctrl); |
| } |
| |
| static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) |
| { |
| if (en) { |
| rkisp1_param_set_bits(params, RKISP1_CIF_VI_ICCL, |
| RKISP1_CIF_VI_ICCL_IE_CLK); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL, |
| RKISP1_CIF_IMG_EFF_CTRL_ENABLE); |
| 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_VI_ICCL, |
| RKISP1_CIF_VI_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, |
| RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, |
| full_range_coeff[i]); |
| |
| 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, |
| RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, |
| limited_range_coeff[i]); |
| |
| 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, RKISP1_CIF_ISP_DPF_NF_GAIN_B, |
| arg->gain.nf_b_gain); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_R, |
| arg->gain.nf_r_gain); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GB, |
| arg->gain.nf_gb_gain); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GR, |
| arg->gain.nf_gr_gain); |
| |
| for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { |
| rkisp1_write(params->rkisp1, |
| RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4, |
| arg->nll.coeff[i]); |
| } |
| |
| 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, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4, |
| spatial_coeff); |
| |
| spatial_coeff = arg->g_flt.spatial_coeff[4] | |
| (arg->g_flt.spatial_coeff[5] << 8); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6, |
| spatial_coeff); |
| |
| 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, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4, |
| spatial_coeff); |
| |
| spatial_coeff = arg->rb_flt.spatial_coeff[4] | |
| (arg->rb_flt.spatial_coeff[5] << 8); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6, |
| spatial_coeff); |
| } |
| |
| static void |
| rkisp1_dpf_strength_config(struct rkisp1_params *params, |
| const struct rkisp1_cif_isp_dpf_strength_config *arg) |
| { |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_B, arg->b); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_G, arg->g); |
| rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_R, arg->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) |
| params->ops->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) |
| params->ops->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) |
| params->ops->awb_meas_config(params, &new_params->meas.awb_meas_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) |
| params->ops->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) |
| params->ops->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) |
| params->ops->hst_config(params, |
| &new_params->meas.hst_config); |
| |
| if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) |
| params->ops->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) |
| params->ops->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; |
| |
| params->ops->awb_meas_config(params, &rkisp1_awb_params_default_config); |
| params->ops->awb_meas_enable(params, &rkisp1_awb_params_default_config, |
| true); |
| |
| params->ops->aec_config(params, &rkisp1_aec_params_default_config); |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_EXP_CTRL, |
| RKISP1_CIF_ISP_EXP_ENA); |
| |
| params->ops->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)); |
| params->ops->hst_config(params, &hst); |
| rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, |
| 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); |
| params->ops->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); |
| params->ops->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 const struct rkisp1_params_ops rkisp1_v10_params_ops = { |
| .lsc_matrix_config = rkisp1_lsc_matrix_config_v10, |
| .goc_config = rkisp1_goc_config_v10, |
| .awb_meas_config = rkisp1_awb_meas_config_v10, |
| .awb_meas_enable = rkisp1_awb_meas_enable_v10, |
| .awb_gain_config = rkisp1_awb_gain_config_v10, |
| .aec_config = rkisp1_aec_config_v10, |
| .hst_config = rkisp1_hst_config_v10, |
| .hst_enable = rkisp1_hst_enable_v10, |
| .afm_config = rkisp1_afm_config_v10, |
| }; |
| |
| static struct rkisp1_params_ops rkisp1_v12_params_ops = { |
| .lsc_matrix_config = rkisp1_lsc_matrix_config_v12, |
| .goc_config = rkisp1_goc_config_v12, |
| .awb_meas_config = rkisp1_awb_meas_config_v12, |
| .awb_meas_enable = rkisp1_awb_meas_enable_v12, |
| .awb_gain_config = rkisp1_awb_gain_config_v12, |
| .aec_config = rkisp1_aec_config_v12, |
| .hst_config = rkisp1_hst_config_v12, |
| .hst_enable = rkisp1_hst_enable_v12, |
| .afm_config = rkisp1_afm_config_v12, |
| }; |
| |
| 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); |
| |
| if (params->rkisp1->info->isp_ver == RKISP1_V12) |
| params->ops = &rkisp1_v12_params_ops; |
| else |
| params->ops = &rkisp1_v10_params_ops; |
| } |
| |
| 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) |
| goto error; |
| |
| 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 error; |
| } |
| |
| return 0; |
| |
| error: |
| media_entity_cleanup(&vdev->entity); |
| mutex_destroy(&node->vlock); |
| 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; |
| |
| if (!video_is_registered(vdev)) |
| return; |
| |
| vb2_video_unregister_device(vdev); |
| media_entity_cleanup(&vdev->entity); |
| mutex_destroy(&node->vlock); |
| } |