/**************************************************************************** * * The MIT License (MIT) * * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * ***************************************************************************** * * The GPL License (GPL) * * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; * ***************************************************************************** * * Note: This software is released under dual MIT and GPL licenses. A * recipient may use this file under the terms of either the MIT license or * GPL License. If you wish to use only one license not the other, you can * indicate your decision by deleting one of the above license notices in your * version of this file. * *****************************************************************************/ #ifdef __KERNEL__ #include #include #endif #include "isp_ioctl.h" #include "mrv_all_bits.h" #include "isp_types.h" #ifdef ISP_3DNR extern MrvAllRegister_t *all_regs; static void dnr3_hw_init(struct isp_ic_dev *dev) { struct isp_3dnr_context *dnr3 = &dev->dnr3; u32 regVal = 0; int i, pos; /* spacial */ u32 update_spacial = 900; u32 strength_curve_spacial = 64; u32 thr_edge_v_inv = 1024; u32 thr_edge_h_inv = 1024; u32 thr_range_s_inv = 1024; /* temperal */ u32 update_temperal = 1020; u32 strength_curve_temperal = 64; u32 range_t_h = 2; u32 range_t_v = 2; u32 thr_range_t_inv = 41943; u32 thr_motion_inv = 1024; u32 range_d = 1; u32 thr_delta_h_inv = 1023; u32 thr_delta_v_inv = 1023; u32 thr_delta_t_inv = 1023; u32 strength = dnr3->strength; strength = MIN(MAX(strength, 0), 128); if (dnr3->init) { //for 3dnr init u32 isp_denoise3d_ctrl = isp_read_reg(dev, REG_ADDR(isp_denoise3d_ctrl)); REG_SET_SLICE(isp_denoise3d_ctrl, DENOISE3D_HORIZONTAL_EN, dnr3->enable_h); REG_SET_SLICE(isp_denoise3d_ctrl, DENOISE3D_VERTICAL_EN, dnr3->enable_v); REG_SET_SLICE(isp_denoise3d_ctrl, DENOISE3D_TEMPERAL_EN, dnr3->enable_temperal); REG_SET_SLICE(isp_denoise3d_ctrl, DENOISE3D_DILATE_EN, dnr3->enable_dilate); REG_SET_SLICE(isp_denoise3d_ctrl, DENOISE3D_ENABLE, dnr3->enable); isp_write_reg(dev, REG_ADDR(isp_denoise3d_ctrl), isp_denoise3d_ctrl); } regVal = 0; REG_SET_SLICE(regVal, DENOISE3D_STRENGTH_CURVE_SPACIAL, strength_curve_spacial); REG_SET_SLICE(regVal, DENOISE3D_THR_EDGE_H_INV, thr_edge_h_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_edge_h), regVal); regVal = 0; REG_SET_SLICE(regVal, DENOISE3D_STRENGTH_CURVE_TEMPERAL, strength_curve_temperal); REG_SET_SLICE(regVal, DENOISE3D_THR_EDGE_V_INV, thr_edge_v_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_edge_v), regVal); regVal = 0; REG_SET_SLICE(regVal, DENOISE3D_RANGE_S_INV, thr_range_s_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_range_s), regVal); regVal = 0; REG_SET_SLICE(regVal, DENOISE3D_RANGE_T_H, range_t_h); REG_SET_SLICE(regVal, DENOISE3D_RANGE_T_V, range_t_v); REG_SET_SLICE(regVal, DENOISE3D_RANGE_T_INV, thr_range_t_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_range_t), regVal); regVal = 0; REG_SET_SLICE(regVal, DENOISE3D_RANGE_D, range_d); REG_SET_SLICE(regVal, DENOISE3D_MOTION_INV, thr_motion_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_motion), regVal); regVal = 0; REG_SET_SLICE(regVal, DENOISE3D_DELTA_H_INV, thr_delta_h_inv); REG_SET_SLICE(regVal, DENOISE3D_DELTA_V_INV, thr_delta_v_inv); REG_SET_SLICE(regVal, DENOISE3D_DELTA_T_INV, thr_delta_t_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_delta_inv), regVal); /* spacial */ for (i = 0; i < 6; i++) { regVal = 0; pos = i * 3; if (i < 5) { REG_SET_SLICE(regVal, DENOISE3D_SPACIAL_CURVE0, dnr3->spacial_curve[pos + 0]); REG_SET_SLICE(regVal, DENOISE3D_SPACIAL_CURVE1, dnr3->spacial_curve[pos + 1]); REG_SET_SLICE(regVal, DENOISE3D_SPACIAL_CURVE2, dnr3->spacial_curve[pos + 2]); } else { REG_SET_SLICE(regVal, DENOISE3D_SPACIAL_CURVE1, dnr3->spacial_curve[pos + 0]); REG_SET_SLICE(regVal, DENOISE3D_SPACIAL_CURVE2, dnr3->spacial_curve[pos + 1]); } isp_write_reg(dev, REG_ADDR(isp_denoise3d_curve_s[i]), regVal); regVal = 0; if (i < 5) { REG_SET_SLICE(regVal, DENOISE3D_TEMPERAL_CURVE0, dnr3->temperal_curve[pos + 0]); REG_SET_SLICE(regVal, DENOISE3D_TEMPERAL_CURVE1, dnr3->temperal_curve[pos + 1]); REG_SET_SLICE(regVal, DENOISE3D_TEMPERAL_CURVE2, dnr3->temperal_curve[pos + 2]); } else { REG_SET_SLICE(regVal, DENOISE3D_TEMPERAL_CURVE1, dnr3->temperal_curve[pos + 0]); REG_SET_SLICE(regVal, DENOISE3D_TEMPERAL_CURVE2, dnr3->temperal_curve[pos + 1]); } isp_write_reg(dev, REG_ADDR(isp_denoise3d_curve_t[i]), regVal); } regVal = 0; REG_SET_SLICE(regVal, DENOISE3D_UPDATE_SPACIAL, update_spacial); REG_SET_SLICE(regVal, DENOISE3D_UPDATE_TEMPERAL, update_temperal); isp_write_reg(dev, REG_ADDR(isp_denoise3d_strength), regVal); isp_write_reg(dev, REG_ADDR(isp_denoise3d_dummy_hblank), 0x80); } int isp_u_3dnr_strength(struct isp_ic_dev *dev) { #ifndef ISP_3DNR //pr_err("Not supported 3dnr\n"); return -1; #else struct isp_3dnr_context *dnr3 = &dev->dnr3; u32 isp_ctrl; u32 isp_denoise3d_strength; isp_denoise3d_strength = isp_read_reg(dev, REG_ADDR(isp_denoise3d_strength)); REG_SET_SLICE(isp_denoise3d_strength, DENOISE3D_STRENGTH, dnr3->strength); isp_write_reg(dev, REG_ADDR(isp_denoise3d_strength), isp_denoise3d_strength); isp_ctrl = isp_read_reg(dev, REG_ADDR(isp_ctrl)); REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, 1); isp_write_reg(dev, REG_ADDR(isp_ctrl), isp_ctrl); return 0; #endif } int isp_s_3dnr(struct isp_ic_dev *dev) { #ifndef ISP_3DNR //pr_err("Not supported 3dnr\n"); return -1; #else u32 isp_denoise3d_ctrl; struct isp_3dnr_context *dnr3 = &dev->dnr3; u32 isp_denoise3d_strength, isp_denoise3d_motion, isp_denoise3d_delta_inv; isp_info("enter %s\n", __func__); if (dnr3->update_bin) { dnr3_hw_init(dev); } isp_denoise3d_motion = isp_read_reg(dev, REG_ADDR(isp_denoise3d_motion)); REG_SET_SLICE(isp_denoise3d_motion, DENOISE3D_MOTION_INV, dnr3->motion_factor); isp_write_reg(dev, REG_ADDR(isp_denoise3d_motion), isp_denoise3d_motion); isp_denoise3d_delta_inv = isp_read_reg(dev, REG_ADDR(isp_denoise3d_delta_inv)); REG_SET_SLICE(isp_denoise3d_delta_inv, DENOISE3D_DELTA_T_INV, dnr3->delta_factor); isp_write_reg(dev, REG_ADDR(isp_denoise3d_delta_inv), isp_denoise3d_delta_inv); isp_denoise3d_strength = isp_read_reg(dev, REG_ADDR(isp_denoise3d_strength)); #ifndef NR200 if (!dnr3->enable) { REG_SET_SLICE(isp_denoise3d_strength, DENOISE3D_STRENGTH, 0); } else { REG_SET_SLICE(isp_denoise3d_strength, DENOISE3D_STRENGTH, dnr3->strength); isp_denoise3d_ctrl = isp_read_reg(dev, REG_ADDR(isp_denoise3d_ctrl)); REG_SET_SLICE(isp_denoise3d_ctrl, DENOISE3D_ENABLE, dnr3->enable); isp_write_reg(dev, REG_ADDR(isp_denoise3d_ctrl), isp_denoise3d_ctrl); } isp_write_reg(dev, REG_ADDR(isp_denoise3d_strength), isp_denoise3d_strength); #else isp_denoise3d_ctrl = isp_read_reg(dev, REG_ADDR(isp_denoise3d_ctrl)); REG_SET_SLICE(isp_denoise3d_ctrl, DENOISE3D_ENABLE, dnr3->enable); isp_write_reg(dev, REG_ADDR(isp_denoise3d_ctrl), isp_denoise3d_ctrl); u32 isp_ctrl = isp_read_reg(dev, REG_ADDR(isp_ctrl)); REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, 1); isp_write_reg(dev, REG_ADDR(isp_ctrl), isp_ctrl); #endif return 0; #endif } int isp_s_3dnr_motion(struct isp_ic_dev *dev) { #ifndef ISP_3DNR pr_err("Not supported 3dnr\n"); return -1; #else struct isp_3dnr_context *dnr3 = &dev->dnr3; u32 isp_denoise3d_motion; u32 isp_ctrl; isp_denoise3d_motion = isp_read_reg(dev, REG_ADDR(isp_denoise3d_motion)); REG_SET_SLICE(isp_denoise3d_motion, DENOISE3D_MOTION_INV, dnr3->motion_factor); isp_write_reg(dev, REG_ADDR(isp_denoise3d_motion), isp_denoise3d_motion); isp_ctrl = isp_read_reg(dev, REG_ADDR(isp_ctrl)); REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, 1); isp_write_reg(dev, REG_ADDR(isp_ctrl), isp_ctrl); #endif return 0; } int isp_s_3dnr_delta(struct isp_ic_dev *dev) { #ifndef ISP_3DNR pr_err("Not supported 3dnr\n"); return -1; #else struct isp_3dnr_context *dnr3 = &dev->dnr3; u32 isp_denoise3d_delta_inv; u32 isp_ctrl; isp_denoise3d_delta_inv = isp_read_reg(dev, REG_ADDR(isp_denoise3d_delta_inv)); REG_SET_SLICE(isp_denoise3d_delta_inv, DENOISE3D_DELTA_T_INV, dnr3->delta_factor); isp_write_reg(dev, REG_ADDR(isp_denoise3d_delta_inv), isp_denoise3d_delta_inv); isp_ctrl = isp_read_reg(dev, REG_ADDR(isp_ctrl)); REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, 1); isp_write_reg(dev, REG_ADDR(isp_ctrl), isp_ctrl); #endif return 0; } int isp_u_3dnr(struct isp_ic_dev *dev, struct isp_3dnr_update *dnr3_update) { #ifndef ISP_3DNR pr_err("unsupported function: %s", __func__); return -EINVAL; #else u32 regVal = 0; isp_info("enter %s\n", __func__); regVal = isp_read_reg(dev, REG_ADDR(isp_denoise3d_strength)); REG_SET_SLICE(regVal, DENOISE3D_STRENGTH, dev->dnr3.strength); isp_write_reg(dev, REG_ADDR(isp_denoise3d_strength), regVal); regVal = 0; regVal = isp_read_reg(dev, REG_ADDR(isp_denoise3d_edge_h)); REG_SET_SLICE(regVal, DENOISE3D_THR_EDGE_H_INV, dnr3_update->thr_edge_h_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_edge_h), regVal); regVal = 0; regVal = isp_read_reg(dev, REG_ADDR(isp_denoise3d_edge_v)); REG_SET_SLICE(regVal, DENOISE3D_THR_EDGE_V_INV, dnr3_update->thr_edge_v_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_edge_v), regVal); regVal = 0; regVal = isp_read_reg(dev, REG_ADDR(isp_denoise3d_range_s)); REG_SET_SLICE(regVal, DENOISE3D_RANGE_S_INV, dnr3_update->thr_range_s_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_range_s), regVal); regVal = 0; regVal = isp_read_reg(dev, REG_ADDR(isp_denoise3d_range_t)); REG_SET_SLICE(regVal, DENOISE3D_RANGE_T_H, dnr3_update->range_t_h); REG_SET_SLICE(regVal, DENOISE3D_RANGE_T_V, dnr3_update->range_t_v); REG_SET_SLICE(regVal, DENOISE3D_RANGE_T_INV, dnr3_update->thr_range_t_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_range_t), regVal); regVal = 0; regVal = isp_read_reg(dev, REG_ADDR(isp_denoise3d_motion)); REG_SET_SLICE(regVal, DENOISE3D_RANGE_D, dnr3_update->range_d); REG_SET_SLICE(regVal, DENOISE3D_MOTION_INV, dnr3_update->thr_motion_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_motion), regVal); regVal = 0; regVal = isp_read_reg(dev, REG_ADDR(isp_denoise3d_delta_inv)); REG_SET_SLICE(regVal, DENOISE3D_DELTA_H_INV, dnr3_update->thr_delta_h_inv); REG_SET_SLICE(regVal, DENOISE3D_DELTA_V_INV, dnr3_update->thr_delta_v_inv); REG_SET_SLICE(regVal, DENOISE3D_DELTA_T_INV, dnr3_update->thr_delta_t_inv); isp_write_reg(dev, REG_ADDR(isp_denoise3d_delta_inv), regVal); #ifdef NR200 u32 isp_ctrl = isp_read_reg(dev, REG_ADDR(isp_ctrl)); REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, 1); isp_write_reg(dev, REG_ADDR(isp_ctrl), isp_ctrl); #endif return 0; #endif } int isp_g_3dnr(struct isp_ic_dev *dev, u32 * avg) { if (!dev || !avg) { return -EINVAL; } *avg = isp_read_reg(dev, REG_ADDR(isp_denoise3d_average)); return 0; } int isp_r_3dnr(struct isp_ic_dev *dev) { #ifndef ISP_3DNR return -1; #else u32 in_width, in_height; u32 size, lval; u32 miv2_sp2_bus_id; u32 miv2_sp2_fmt; u32 miv2_ctrl = isp_read_reg(dev, REG_ADDR(miv2_ctrl)); u32 miv2_imsc = isp_read_reg(dev, REG_ADDR(miv2_imsc)); u32 miv2_sp2_ctrl = isp_read_reg(dev, REG_ADDR(miv2_sp2_ctrl)); //SP2_RAW_PATH_ENABLE is shadow bit, need set SP2_MI_CFG_UPD to update to shadow. //So here config before set SP2_MI_CFG_UPD REG_SET_SLICE(miv2_ctrl, SP2_RAW_RDMA_PATH_ENABLE, 1); REG_SET_SLICE(miv2_ctrl, SP2_RAW_PATH_ENABLE, 1); isp_write_reg(dev, REG_ADDR(miv2_ctrl), miv2_ctrl); #ifndef NR200 in_width = isp_read_reg(dev, REG_ADDR(isp_acq_h_size)); in_height = isp_read_reg(dev, REG_ADDR(isp_acq_v_size)); #else in_width = isp_read_reg(dev, REG_ADDR(isp_out_h_size)); in_height = isp_read_reg(dev, REG_ADDR(isp_out_v_size)); #endif lval = (in_width * 12 + 127)/ 128; lval <<= 4; size = in_height * lval; //raw12 unaligned //write reference frame config isp_write_reg(dev, REG_ADDR(miv2_sp2_raw_base_ad_init), dev->dnr3.pa); isp_write_reg(dev, REG_ADDR(miv2_sp2_raw_size_init), size); isp_write_reg(dev, REG_ADDR(miv2_sp2_raw_offs_cnt_init), 0); isp_write_reg(dev, REG_ADDR(miv2_sp2_raw_llength), lval); isp_write_reg(dev, REG_ADDR(miv2_sp2_raw_pic_width), in_width); isp_write_reg(dev, REG_ADDR(miv2_sp2_raw_pic_height), in_height); isp_write_reg(dev, REG_ADDR(miv2_sp2_raw_pic_size), size); miv2_sp2_bus_id = isp_read_reg(dev, REG_ADDR(miv2_sp2_bus_id)); REG_SET_SLICE(miv2_sp2_bus_id, SP2_WR_ID_EN, 1); REG_SET_SLICE(miv2_sp2_bus_id, SP2_RD_ID_EN, 1); REG_SET_SLICE(miv2_sp2_bus_id, SP2_RD_BURST_LEN, 2); //sp2 rd burst lenghth 16 REG_SET_SLICE(miv2_sp2_bus_id, SP2_BUS_SW_EN, 1); isp_write_reg(dev, REG_ADDR(miv2_sp2_bus_id), miv2_sp2_bus_id); miv2_sp2_fmt = isp_read_reg(dev, REG_ADDR(miv2_sp2_fmt)); REG_SET_SLICE(miv2_sp2_fmt, SP2_WR_RAW_BIT, 2); //raw12 REG_SET_SLICE(miv2_sp2_fmt, SP2_WR_RAW_ALIGNED, 0); //unaligned REG_SET_SLICE(miv2_sp2_fmt, SP2_RD_RAW_BIT, 2); //raw12 REG_SET_SLICE(miv2_sp2_fmt, SP2_RD_RAW_ALIGNED, 0); //unaligned isp_write_reg(dev, REG_ADDR(miv2_sp2_fmt), miv2_sp2_fmt); //read reference frame config isp_write_reg(dev, REG_ADDR(miv2_sp2_dma_raw_pic_start_ad), dev->dnr3.pa); isp_write_reg(dev, REG_ADDR(miv2_sp2_dma_raw_pic_width), in_width); isp_write_reg(dev, REG_ADDR(miv2_sp2_dma_raw_pic_llength), lval); isp_write_reg(dev, REG_ADDR(miv2_sp2_dma_raw_pic_lval), lval); isp_write_reg(dev, REG_ADDR(miv2_sp2_dma_raw_pic_size), size); REG_SET_SLICE(miv2_sp2_ctrl, SP2_RD_RAW_CFG_UPDATE, 1); REG_SET_SLICE(miv2_sp2_ctrl, SP2_RD_RAW_AUTO_UPDATE, 1); REG_SET_SLICE(miv2_sp2_ctrl, SP2_MI_CFG_UPD, 1); /* we successfully programmed a buffer to marvin, so we need * to enable updateing of base and offset registers */ miv2_sp2_ctrl |= (SP2_INIT_BASE_EN_MASK | SP2_INIT_OFFSET_EN_MASK); isp_write_reg(dev, REG_ADDR(miv2_sp2_ctrl), miv2_sp2_ctrl); miv2_imsc |= SP2_DMA_RAW_READY_MASK; isp_write_reg(dev, REG_ADDR(miv2_imsc), miv2_imsc); return 0; #endif } #endif