| /* |
| * drivers/amlogic/media/deinterlace/nr_drv.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * 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. |
| * |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/types.h> |
| #include <linux/kernel.h> |
| #include <linux/device.h> |
| #include <linux/vmalloc.h> |
| #include <linux/slab.h> |
| #include <linux/amlogic/iomap.h> |
| #include <linux/amlogic/cpu_version.h> |
| #include "register.h" |
| #include "register_nr4.h" |
| #include "nr_drv.h" |
| #include "deinterlace.h" |
| |
| static DNR_PRM_t dnr_param; |
| static struct NR_PARM_s nr_param; |
| static bool dnr_pr; |
| module_param(dnr_pr, bool, 0644); |
| MODULE_PARM_DESC(dnr_pr, "/n print dnr debug information /n"); |
| |
| static bool dnr_dm_en; |
| module_param(dnr_dm_en, bool, 0644); |
| MODULE_PARM_DESC(dnr_dm_en, "/n dnr dm enable debug /n"); |
| |
| static bool dnr_en = true; |
| module_param_named(dnr_en, dnr_en, bool, 0644); |
| |
| static unsigned int nr2_en = 0x1; |
| module_param_named(nr2_en, nr2_en, uint, 0644); |
| |
| static bool nr_ctrl_reg; |
| |
| int global_bs_calc_sw(int *pGbsVldCnt, |
| int *pGbsVldFlg, |
| int *pGbs, |
| int nGbsStatLR, |
| int nGbsStatLL, |
| int nGbsStatRR, |
| int nGbsStatDif, |
| int nGbsStatCnt, |
| int prm_gbs_vldcntthd, /* prm below */ |
| int prm_gbs_cnt_min, |
| int prm_gbs_ratcalcmod, |
| int prm_gbs_ratthd[3], |
| int prm_gbs_difthd[3], |
| int prm_gbs_bsdifthd, |
| int prm_gbs_calcmod) |
| { |
| int nMax, nMin; |
| int nDif0, nDif1, nDif2; |
| int nDif, nRat; |
| int nCurGbs; |
| |
| nMax = max(max(nGbsStatLR, nGbsStatLL), nGbsStatRR); |
| nMin = min(min(nGbsStatLR, nGbsStatLL), nGbsStatRR); |
| |
| nDif0 = nMax == 0 ? 0 : ((nMax - nMin) << 9)/nMax; |
| nDif0 = min(511, nDif0); |
| |
| nDif1 = nGbsStatLR == 0 ? 0 : |
| (abs(nGbsStatLR - (nGbsStatLL + nGbsStatRR)/2) << 9)/nGbsStatLR; |
| nDif1 = min(511, nDif1); |
| |
| nDif2 = nGbsStatLR == 0 ? 0 : |
| (abs(nGbsStatLR - max(nGbsStatLL, nGbsStatRR)) << 9)/nGbsStatLR; |
| nDif2 = min(511, nDif2); |
| |
| if (prm_gbs_ratcalcmod == 0) |
| nRat = (nGbsStatLR << 4) / max(prm_gbs_cnt_min, nGbsStatCnt); |
| else |
| nRat = (nGbsStatDif << 4) / max(prm_gbs_cnt_min, nGbsStatCnt); |
| |
| nDif = (prm_gbs_calcmod == 0) ? nDif0 : |
| (prm_gbs_calcmod == 1 ? nDif1 : nDif2); |
| |
| if (nGbsStatLR < max(nGbsStatLL, nGbsStatRR)) { |
| if (nGbsStatCnt <= prm_gbs_cnt_min || nRat <= prm_gbs_ratthd[0]) |
| nCurGbs = 0; |
| else if (nRat <= prm_gbs_ratthd[1]) |
| nCurGbs = 1; |
| else if (nRat <= prm_gbs_ratthd[2]) |
| nCurGbs = 2; |
| else |
| nCurGbs = 3; |
| } else { |
| if (nGbsStatCnt <= prm_gbs_cnt_min || nDif <= prm_gbs_difthd[0]) |
| nCurGbs = 0; |
| else if (nDif <= prm_gbs_difthd[1]) |
| nCurGbs = 1; |
| else if (nDif <= prm_gbs_difthd[2]) |
| nCurGbs = 2; |
| else |
| nCurGbs = 3; |
| } |
| |
| /* */ |
| if ((nCurGbs != 0 && 0 == *pGbs) || |
| (nCurGbs != 0 && abs(nCurGbs - *pGbs) <= prm_gbs_bsdifthd)) |
| (*pGbsVldCnt)++; |
| else |
| *pGbsVldCnt = 0; |
| |
| if (*pGbsVldCnt >= prm_gbs_vldcntthd) |
| *pGbsVldFlg = 1; |
| else |
| *pGbsVldFlg = 0; |
| |
| *pGbs = nCurGbs; |
| |
| /* print debug info. */ |
| /* printk("GBS info at Field: LR = %6d, LL = %6d, RR = %6d.\n", |
| * nGbsStatLR, nGbsStatLL, nGbsStatRR; |
| */ |
| |
| return 0; |
| } |
| |
| #ifdef DNR_HV_SHIFT |
| int hor_blk_ofst_calc_sw(int *pHbOfVldCnt, |
| int *pHbOfVldFlg, |
| int *pHbOfst, |
| int nHbOfStatCnt[32], |
| int nXst, |
| int nXed, |
| int prm_hbof_minthd, |
| int prm_hbof_ratthd0, |
| int prm_hbof_ratthd1, |
| int prm_hbof_vldcntthd, |
| int nRow, |
| int nCol) |
| { |
| int i = 0; |
| |
| int nCurHbOfst = 0; |
| int nRat0 = 0, nRat1 = 0; |
| |
| int nMax1 = 0; |
| int nMax2 = 0; |
| int nMaxIdx = 0; |
| |
| /* get 2 maximum, move to RTL part */ |
| nMax1 = nMax2 = 0; |
| for (i = 0; i < 8; i++) { |
| if (nHbOfStatCnt[i] > nMax1) { |
| nMax2 = nMax1; |
| nMax1 = nHbOfStatCnt[i]; |
| nMaxIdx = i; |
| } else if (nHbOfStatCnt[i] > nMax2) { |
| nMax2 = nHbOfStatCnt[i]; |
| } |
| } /* i */ |
| |
| /* decide if offset valid */ |
| nCurHbOfst = -1; |
| nRat0 = 256*nMax1/((nXed - nXst)/8)/nRow; |
| nRat1 = 128*nMax1/max(nMax2, prm_hbof_minthd); |
| if (nRat0 >= prm_hbof_ratthd0 && nRat1 >= prm_hbof_ratthd1) |
| nCurHbOfst = (nMaxIdx+1)%8; |
| |
| if (nCurHbOfst == *pHbOfst) |
| (*pHbOfVldCnt)++; |
| else |
| *pHbOfVldCnt = 0; |
| |
| if (*pHbOfVldCnt >= prm_hbof_vldcntthd) |
| *pHbOfVldFlg = 1; |
| else |
| *pHbOfVldFlg = 0; |
| |
| *pHbOfst = (nCurHbOfst == -1) ? 0 : nCurHbOfst; |
| |
| /* print for debug |
| * printk("Hoff info at Field: "); |
| * for ( i = 0; i < 32; i++ ) { |
| * printk("%5d, ", nHbOfStatCnt[i]); |
| * } |
| */ |
| if (dnr_pr) { |
| pr_dbg("Max1 = %5d, Max2 = %5d, MaxIdx = %5d, Rat0 = %5d,Rat1 = %5d.\n", |
| nMax1, nMax2, nMaxIdx, nRat0, nRat1); |
| pr_dbg("CurHbOfst = %5d, HbOfVldFlg = %d, HbOfVldCnt = %d.\n", |
| nCurHbOfst, *pHbOfVldFlg, *pHbOfVldCnt); |
| } |
| |
| return 0; |
| } |
| int ver_blk_ofst_calc_sw(int *pVbOfVldCnt, |
| int *pVbOfVldFlg, |
| int *pVbOfst, |
| int nVbOfStatCnt[32], |
| int nYst, |
| int nYed, |
| int prm_vbof_minthd, |
| int prm_vbof_ratthd0, |
| int prm_vbof_ratthd1, |
| int prm_vbof_vldcntthd, |
| int nRow, |
| int nCol) |
| { |
| int i = 0; |
| |
| int nCurVbOfst = 0; |
| int nRat0 = 0, nRat1 = 0; |
| |
| int nMax1 = 0; |
| int nMax2 = 0; |
| int nMaxIdx = 0; |
| |
| /* get 2 maximum, move to RTL part */ |
| nMax1 = nMax2 = 0; |
| for (i = 0; i < 8; i++) { |
| if (nVbOfStatCnt[i] > nMax1) { |
| nMax2 = nMax1; |
| nMax1 = nVbOfStatCnt[i]; |
| nMaxIdx = i; |
| } |
| else if (nVbOfStatCnt[i] > nMax2) { |
| nMax2 = nVbOfStatCnt[i]; |
| } |
| } |
| |
| /* decide if offset valid */ |
| nCurVbOfst = -1; |
| nRat0 = 256*nMax1/((nYed - nYst)/8)/nCol; |
| nRat1 = 128*nMax1/max(nMax2, prm_vbof_minthd); |
| if (nRat0 >= prm_vbof_ratthd0 && nRat1 >= prm_vbof_ratthd1) |
| nCurVbOfst = (nMaxIdx+1)%8; |
| |
| if (nCurVbOfst == *pVbOfst) |
| (*pVbOfVldCnt)++; |
| else |
| *pVbOfVldCnt = 0; |
| |
| if (*pVbOfVldCnt >= prm_vbof_vldcntthd) |
| *pVbOfVldFlg = 1; |
| else |
| *pVbOfVldFlg = 0; |
| |
| *pVbOfst = (nCurVbOfst == -1) ? 0 : nCurVbOfst; |
| |
| /* print for debug |
| * printk("Voff info at Field: "); |
| * for ( i = 0; i < 32; i++ ) { |
| * printk("%5d, ", nVbOfStatCnt[i]); |
| * }//i |
| * //printk("Max1 = %5d, Max2 = %5d, MaxIdx = %5d, Rat0 = %5d, |
| * Rat1 = %5d, CurVbOfst = %5d, VbOfVldFlg = %d, VbOfVldCnt = %d.\n" |
| * nMax1, nMax2, nMaxIdx, nRat0, nRat1, nCurVbOfst, *pVbOfVldFlg, |
| * *pVbOfVldCnt); |
| */ |
| return 0; |
| } |
| #endif |
| static void dnr_config(struct DNR_PARM_s *dnr_parm_p, |
| unsigned short width, unsigned short height) |
| { |
| unsigned short border_offset = dnr_parm_p->dnr_stat_coef; |
| |
| DI_Wr(DNR_HVSIZE, width<<16|height); |
| DI_Wr(DNR_STAT_X_START_END, (((border_offset<<3)&0x3fff) << 16) |
| |((width-((border_offset<<3)+1))&0x3fff)); |
| DI_Wr(DNR_STAT_Y_START_END, (((border_offset<<3)&0x3fff) << 16) |
| |((height-((border_offset<<3)+1))&0x3fff)); |
| DI_Wr(DNR_DM_CTRL, Rd(DNR_DM_CTRL)|(1 << 11)); |
| DI_Wr_reg_bits(DNR_CTRL, dnr_en?1:0, 16, 1); |
| /* dm for sd, hd will slower */ |
| if (is_meson_tl1_cpu()) |
| DI_Wr(DNR_CTRL, 0x1df00 | (0x03 << 18)); //5 line |
| else |
| DI_Wr(DNR_CTRL, 0x1df00); |
| if (is_meson_gxlx_cpu()) { |
| /* disable chroma dm according to baozheng */ |
| DI_Wr_reg_bits(DNR_DM_CTRL, 0, 8, 1); |
| DI_Wr(DNR_CTRL, 0x1dd00); |
| } else if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX)) { |
| /*disable */ |
| if (width > 1280) { |
| DI_Wr_reg_bits(DNR_DM_CTRL, 0, 8, 1); |
| /* disable dm for 1080 which will cause pre timeout*/ |
| DI_Wr_reg_bits(DNR_DM_CTRL, 0, 9, 1); |
| } else { |
| DI_Wr_reg_bits(DNR_DM_CTRL, 1, 8, 1); |
| DI_Wr_reg_bits(DNR_DM_CTRL, dnr_dm_en, 9, 1); |
| } |
| } else { |
| if (width >= 1920) |
| DI_Wr_reg_bits(DNR_DM_CTRL, 0, 9, 1); |
| else |
| DI_Wr_reg_bits(DNR_DM_CTRL, dnr_dm_en, 9, 1); |
| } |
| } |
| static void nr4_config(struct NR4_PARM_s *nr4_parm_p, |
| unsigned short width, unsigned short height) |
| { |
| unsigned short val = 0; |
| |
| val = nr4_parm_p->border_offset; |
| /* luma enhancement*/ |
| DI_Wr(NR4_MCNR_LUMA_STAT_LIMTX, (val<<16) | (width-val-1)); |
| DI_Wr(NR4_MCNR_LUMA_STAT_LIMTY, (val<<16) | (height-val-1)); |
| /* noise meter */ |
| DI_Wr(NR4_NM_X_CFG, (val<<16) | (width-val-1)); |
| DI_Wr(NR4_NM_Y_CFG, (val<<16) | (height-val-1)); |
| /* enable nr4 */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 16, 1); |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 18, 1); |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 3, 1); |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 5, 1); |
| nr4_parm_p->width = width - val - val - 1; |
| nr4_parm_p->height = height - val - val - 1; |
| } |
| /* |
| * line buffer ctrl such as 5 lines or 3 lines |
| * yuv444 or yuv422 |
| */ |
| static void linebuffer_config(unsigned short width) |
| { |
| unsigned short val = 0; |
| unsigned short line5_444 = 1368, line5_422 = 2052; |
| unsigned short line3_444 = 2736; |
| |
| if (is_meson_txhd_cpu()) { |
| line5_444 = 640; |
| line5_422 = 960; |
| line3_444 = 1280; |
| } |
| if (width <= line5_444) |
| val = 3; |
| else if (width <= line5_422) |
| val = 1; |
| else if (width <= line3_444) |
| val = 2; |
| else |
| val = 0; |
| /* line buffer no gate clock */ |
| DI_Wr_reg_bits(LBUF_TOP_CTRL, 0, 20, 6); |
| DI_Wr_reg_bits(LBUF_TOP_CTRL, val, 16, 2); |
| } |
| |
| static void nr2_config(unsigned short width, unsigned short height) |
| { |
| if (is_meson_txlx_cpu() || is_meson_g12a_cpu() || |
| is_meson_g12b_cpu() || is_meson_tl1_cpu() || |
| is_meson_sm1_cpu()) { |
| DI_Wr_reg_bits(NR4_TOP_CTRL, nr2_en, 2, 1); |
| DI_Wr_reg_bits(NR4_TOP_CTRL, nr2_en, 15, 1); |
| DI_Wr_reg_bits(NR4_TOP_CTRL, nr2_en, 17, 1); |
| } else { |
| /*set max height to disable nfram cnt in cue*/ |
| if (is_meson_gxlx_cpu()) |
| DI_Wr(NR2_FRM_SIZE, (0xfff<<16)|width); |
| else |
| DI_Wr(NR2_FRM_SIZE, (height<<16)|width); |
| DI_Wr_reg_bits(NR2_SW_EN, nr2_en, 4, 1); |
| } |
| } |
| |
| static bool cue_en = true; |
| module_param_named(cue_en, cue_en, bool, 0664); |
| /* |
| * workaround for nframe count |
| * indicating error field type in cue |
| */ |
| static void cue_config(struct CUE_PARM_s *pcue_parm, unsigned short field_type) |
| { |
| pcue_parm->field_count = 8; |
| pcue_parm->frame_count = 8; |
| if (field_type != VIDTYPE_PROGRESSIVE) { |
| DI_Wr_reg_bits(NR2_CUE_PRG_DIF, 0, 20, 1); |
| DI_Wr_reg_bits(DI_NR_CTRL0, 0, 26, 1); |
| /* cur row mode avoid seek error */ |
| Wr_reg_bits(NR2_CUE_MODE, 5, 0, 4); |
| } else { |
| DI_Wr_reg_bits(NR2_CUE_PRG_DIF, 1, 20, 1); |
| /* disable cue for progressive issue */ |
| DI_Wr_reg_bits(DI_NR_CTRL0, 0, 26, 1); |
| } |
| } |
| |
| void nr_all_config(unsigned short width, unsigned short height, |
| unsigned short field_type) |
| { |
| nr_param.width = width; |
| nr_param.height = height; |
| nr_param.frame_count = 0; |
| nr_param.prog_flag = field_type?false:true; |
| nr2_config(width, height); |
| dnr_config(nr_param.pdnr_parm, width, height); |
| |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXLX)) |
| cue_config(nr_param.pcue_parm, field_type); |
| if (is_meson_txlx_cpu() || is_meson_g12a_cpu() || |
| is_meson_g12b_cpu() || is_meson_tl1_cpu() || |
| is_meson_sm1_cpu()) { |
| linebuffer_config(width); |
| nr4_config(nr_param.pnr4_parm, width, height); |
| } |
| if (is_meson_txhd_cpu()) |
| linebuffer_config(width); |
| } |
| |
| static int find_lut16(unsigned int val, int *pLut) |
| { |
| int idx_L, shft, dist; |
| int left, right, norm; |
| int res; |
| |
| if (val < 2) { |
| idx_L = 0; |
| dist = val - 0; |
| shft = 1; |
| } else if (val < 4) { |
| idx_L = 1; |
| dist = val - 2; |
| shft = 1; |
| } else if (val < 8) { |
| idx_L = 2; |
| dist = val - 4; |
| shft = 2; |
| } else if (val < 16) { |
| idx_L = 3; |
| dist = val - 8; |
| shft = 3; |
| } else if (val < 32) { |
| idx_L = 4; |
| dist = val - 16; |
| shft = 4; |
| } else if (val < 48) { |
| idx_L = 5; |
| dist = val - 32; |
| shft = 4; |
| } else if (val < 64) { |
| idx_L = 6; |
| dist = val - 48; |
| shft = 4; |
| } else if (val < 80) { |
| idx_L = 7; |
| dist = val - 64; |
| shft = 4; |
| } else if (val < 96) { |
| idx_L = 8; |
| dist = val - 80; |
| shft = 4; |
| } else if (val < 112) { |
| idx_L = 9; |
| dist = val - 96; |
| shft = 4; |
| } else if (val < 128) { |
| idx_L = 10; |
| dist = val - 112; |
| shft = 4; |
| } else if (val < 160) { |
| idx_L = 11; |
| dist = val - 128; |
| shft = 5; |
| } else if (val < 192) { |
| idx_L = 12; |
| dist = val - 160; |
| shft = 5; |
| } else if (val < 224) { |
| idx_L = 13; |
| dist = val - 192; |
| shft = 5; |
| } else { |
| idx_L = 14; |
| dist = val - 224; |
| shft = 5; |
| } |
| left = pLut[idx_L]; |
| right = pLut[idx_L+1]; |
| norm = (1<<shft); |
| res = ((left*(norm-dist) + right*dist + (norm>>1))>>shft); |
| return res; |
| } |
| static void noise_meter_process(struct NR4_PARM_s *nr4_param_p, |
| unsigned int field_cnt) |
| { |
| unsigned int val1 = 0, val2 = 0, field_sad = 0, field_var = 0; |
| int val = 0; |
| |
| val1 = Rd(NR4_RO_NM_SAD_CNT); |
| val2 = Rd(NR4_RO_NM_SAD_SUM); |
| |
| field_sad = (val1 == 0 ? 0 : (val2 + (val1>>1)) / val1); |
| |
| val1 = Rd(NR4_RO_NM_VAR_SCNT); |
| val2 = Rd(NR4_RO_NM_VAR_SUM); |
| field_var = (val1 == 0 ? 0 : (val2 + (val1>>1)) / val1); |
| /* |
| * field sad based global noise level to gain, |
| * maybe improved further |
| */ |
| if (nr4_param_p->sw_nr4_sad2gain_en == 1) { |
| val2 = (field_sad<<2) < 255 ? (field_sad<<2) : 255; |
| val1 = find_lut16(val2, &nr4_param_p->sw_nr4_sad2gain_lut[0]); |
| } else |
| val1 = 64; |
| DI_Wr_reg_bits(NR4_MCNR_MV_CTRL_REG, val1, 4, 8); |
| /*add for TL1------*/ |
| if (nr4_param_p->sw_nr4_noise_ctrl_dm_en == 1) { |
| if (nr4_param_p->sw_nr4_noise_sel == 0) { |
| val2 = val1 >= nr4_param_p->sw_nr4_noise_thd ? 1 : 0; |
| } else { |
| val2 = |
| field_sad >= nr4_param_p->sw_nr4_noise_thd ? 1 : 0; |
| } |
| |
| DI_Wr_reg_bits(DNR_DM_NR_BLND, val2, 24, 1); |
| } |
| /*------------------*/ |
| /* scene change processing */ |
| nr4_param_p->sw_nr4_scene_change_flg[0] = |
| nr4_param_p->sw_nr4_scene_change_flg[1]; |
| nr4_param_p->sw_nr4_scene_change_flg[1] = |
| nr4_param_p->sw_nr4_scene_change_flg[2]; |
| val = field_sad - nr4_param_p->sw_nr4_field_sad[1]; |
| if (field_cnt > 2 |
| && (val > nr4_param_p->sw_nr4_scene_change_thd)) { |
| nr4_param_p->sw_nr4_scene_change_flg[2] = 1; |
| if (nr4_param_p->nr4_debug) { |
| pr_info("NR4 current field_sad=%d, sad[1]=%d, val=%d", |
| field_sad, nr4_param_p->sw_nr4_field_sad[1], val); |
| } |
| } else |
| nr4_param_p->sw_nr4_scene_change_flg[2] = 0; |
| if (nr4_param_p->sw_nr4_scene_change_flg[1] || |
| nr4_param_p->sw_nr4_scene_change_flg[2]) |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 0, 1); |
| else |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 0, 1); |
| |
| /*fot TL1 **************/ |
| if (nr4_param_p->sw_dm_scene_change_en == 1) { |
| val = field_sad >= nr4_param_p->sw_nr4_scene_change_thd2 |
| && nr4_param_p->sw_nr4_field_sad[1] |
| >= nr4_param_p->sw_nr4_scene_change_thd2; |
| |
| DI_Wr_reg_bits(DNR_DM_CTRL, val, 12, 1); |
| } |
| /***********************/ |
| nr4_param_p->sw_nr4_field_sad[0] = nr4_param_p->sw_nr4_field_sad[1]; |
| nr4_param_p->sw_nr4_field_sad[1] = field_sad; |
| } |
| static void luma_enhancement_process(struct NR4_PARM_s *nr4_param_p, |
| unsigned int field_cnt) |
| { |
| unsigned int reg_val = 0, tmp1 = 0; |
| |
| tmp1 = nr4_param_p->width * nr4_param_p->height; |
| if (field_cnt <= 2) { |
| reg_val = (Rd(NR4_MCNR_RO_U_SUM) + (tmp1>>1))/tmp1; |
| DI_Wr_reg_bits(NR4_MCNR_LUMAPRE_CAL_PRAM, reg_val, 8, 8); |
| reg_val = (Rd(NR4_MCNR_RO_V_SUM) + (tmp1>>1))/tmp1; |
| DI_Wr_reg_bits(NR4_MCNR_LUMAPRE_CAL_PRAM, reg_val, 0, 8); |
| } else { |
| reg_val = Rd_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, 8, 8); |
| DI_Wr_reg_bits(NR4_MCNR_LUMAPRE_CAL_PRAM, reg_val, 8, 8); |
| reg_val = Rd_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, 0, 8); |
| DI_Wr_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, reg_val, 0, 8); |
| } |
| reg_val = Rd_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, 24, 2); |
| DI_Wr_reg_bits(NR4_MCNR_LUMAPRE_CAL_PRAM, reg_val, 24, 2); |
| reg_val = Rd_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, 16, 2); |
| DI_Wr_reg_bits(NR4_MCNR_LUMAPRE_CAL_PRAM, reg_val, 16, 2); |
| reg_val = (Rd(NR4_MCNR_RO_U_SUM) + (tmp1>>1))/tmp1; |
| DI_Wr_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, reg_val, 8, 8); |
| reg_val = (Rd(NR4_MCNR_RO_V_SUM) + (tmp1>>1))/tmp1; |
| DI_Wr_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, reg_val, 0, 8); |
| reg_val = SGN2(Rd(NR4_MCNR_RO_GRDU_SUM)); |
| DI_Wr_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, reg_val, 24, 2); |
| reg_val = SGN2(Rd(NR4_MCNR_RO_GRDV_SUM)); |
| DI_Wr_reg_bits(NR4_MCNR_LUMACUR_CAL_PRAM, reg_val, 16, 2); |
| } |
| static void dnr_process(struct DNR_PARM_s *pDnrPrm) |
| { |
| static int ro_gbs_stat_lr = 0, ro_gbs_stat_ll = 0, ro_gbs_stat_rr = 0, |
| ro_gbs_stat_dif = 0, ro_gbs_stat_cnt = 0; |
| /* int reg_dnr_stat_xst=0,reg_dnr_stat_xed=0, |
| * reg_dnr_stat_yst=0,reg_dnr_stat_yed=0; |
| */ |
| #ifdef DNR_HV_SHIFT |
| int ro_hbof_stat_cnt[32], ro_vbof_stat_cnt[32], i = 0; |
| #endif |
| int ll, lr; |
| |
| if (is_meson_tl1_cpu()) { |
| ll = Rd(DNR_RO_GBS_STAT_LR); |
| lr = Rd(DNR_RO_GBS_STAT_LL); |
| } else { |
| ll = Rd(DNR_RO_GBS_STAT_LL); |
| lr = Rd(DNR_RO_GBS_STAT_LR); |
| |
| } |
| if (ro_gbs_stat_lr != lr || |
| ro_gbs_stat_ll != ll || |
| ro_gbs_stat_rr != Rd(DNR_RO_GBS_STAT_RR) || |
| ro_gbs_stat_dif != Rd(DNR_RO_GBS_STAT_DIF) || |
| ro_gbs_stat_cnt != Rd(DNR_RO_GBS_STAT_CNT)) { |
| |
| ro_gbs_stat_lr = lr; |
| ro_gbs_stat_ll = ll; |
| ro_gbs_stat_rr = Rd(DNR_RO_GBS_STAT_RR); |
| ro_gbs_stat_dif = Rd(DNR_RO_GBS_STAT_DIF); |
| ro_gbs_stat_cnt = Rd(DNR_RO_GBS_STAT_CNT); |
| } else { |
| return; |
| } |
| |
| global_bs_calc_sw(&pDnrPrm->sw_gbs_vld_cnt, |
| &pDnrPrm->sw_gbs_vld_flg, |
| &pDnrPrm->sw_gbs, |
| ro_gbs_stat_lr, |
| ro_gbs_stat_ll, |
| ro_gbs_stat_rr, |
| ro_gbs_stat_dif, |
| ro_gbs_stat_cnt, |
| pDnrPrm->prm_gbs_vldcntthd, /* prm below */ |
| pDnrPrm->prm_gbs_cnt_min, |
| pDnrPrm->prm_gbs_ratcalcmod, |
| pDnrPrm->prm_gbs_ratthd, |
| pDnrPrm->prm_gbs_difthd, |
| pDnrPrm->prm_gbs_bsdifthd, |
| pDnrPrm->prm_gbs_calcmod); |
| #ifdef DNR_HV_SHIFT |
| for (i = 0; i < 32; i++) |
| ro_hbof_stat_cnt[i] = Rd(DNR_RO_HBOF_STAT_CNT_0+i); |
| for (i = 0; i < 32; i++) |
| ro_vbof_stat_cnt[i] = Rd(DNR_RO_VBOF_STAT_CNT_0+i); |
| hor_blk_ofst_calc_sw(&pDnrPrm->sw_hbof_vld_cnt, |
| &pDnrPrm->sw_hbof_vld_flg, |
| &pDnrPrm->sw_hbof, |
| ro_hbof_stat_cnt, |
| 0, |
| nCol-1, |
| pDnrPrm->prm_hbof_minthd, |
| pDnrPrm->prm_hbof_ratthd0, |
| pDnrPrm->prm_hbof_ratthd1, |
| pDnrPrm->prm_hbof_vldcntthd, |
| nRow, |
| nCol); |
| |
| ver_blk_ofst_calc_sw(&pDnrPrm->sw_vbof_vld_cnt, |
| &pDnrPrm->sw_vbof_vld_flg, |
| &pDnrPrm->sw_vbof, |
| ro_vbof_stat_cnt, |
| 0, |
| nRow-1, |
| pDnrPrm->prm_vbof_minthd, |
| pDnrPrm->prm_vbof_ratthd0, |
| pDnrPrm->prm_vbof_ratthd1, |
| pDnrPrm->prm_vbof_vldcntthd, |
| nRow, |
| nCol); |
| #endif |
| /* update hardware registers */ |
| if (pDnrPrm->prm_sw_gbs_ctrl == 0) { |
| DI_Wr(DNR_GBS, |
| (pDnrPrm->sw_gbs_vld_flg == 1)?pDnrPrm->sw_gbs : 0); |
| } else if (pDnrPrm->prm_sw_gbs_ctrl == 1) { |
| DI_Wr_reg_bits(DNR_BLK_OFFST, |
| (pDnrPrm->sw_hbof_vld_flg == 1)?pDnrPrm->sw_hbof:0, 4, 3); |
| DI_Wr(DNR_GBS, (pDnrPrm->sw_hbof_vld_flg == 1 && |
| pDnrPrm->sw_gbs_vld_flg == 1)?pDnrPrm->sw_gbs:0); |
| } else if (pDnrPrm->prm_sw_gbs_ctrl == 2) { |
| DI_Wr_reg_bits(DNR_BLK_OFFST, |
| (pDnrPrm->sw_vbof_vld_flg == 1)?pDnrPrm->sw_vbof:0, 0, 3); |
| DI_Wr(DNR_GBS, (pDnrPrm->sw_vbof_vld_flg == 1 && |
| pDnrPrm->sw_gbs_vld_flg == 1)?pDnrPrm->sw_gbs:0); |
| } else if (pDnrPrm->prm_sw_gbs_ctrl == 1) { |
| DI_Wr_reg_bits(DNR_BLK_OFFST, |
| pDnrPrm->sw_hbof_vld_flg == 1 ? pDnrPrm->sw_hbof : 0, 4, 3); |
| DI_Wr_reg_bits(DNR_BLK_OFFST, |
| pDnrPrm->sw_vbof_vld_flg == 1 ? pDnrPrm->sw_vbof : 0, 0, 3); |
| DI_Wr(DNR_GBS, (pDnrPrm->sw_hbof_vld_flg == 1 && |
| pDnrPrm->sw_vbof_vld_flg == 1 && |
| pDnrPrm->sw_gbs_vld_flg == 1)?pDnrPrm->sw_gbs:0); |
| } |
| } |
| |
| static bool invert_cue_phase; |
| module_param_named(invert_cue_phase, invert_cue_phase, bool, 0644); |
| |
| static unsigned int cue_pr_cnt; |
| module_param_named(cue_pr_cnt, cue_pr_cnt, uint, 0644); |
| |
| static bool cue_glb_mot_check_en = true; |
| module_param_named(cue_glb_mot_check_en, cue_glb_mot_check_en, bool, 0644); |
| |
| static void cue_process_irq(void) |
| { |
| |
| int pre_field_num = 0, cue_invert = 0; |
| |
| if (is_meson_gxlx_cpu()) { |
| pre_field_num = Rd_reg_bits(DI_PRE_CTRL, 29, 1); |
| if (invert_cue_phase) |
| cue_invert = (pre_field_num?3:0); |
| else |
| cue_invert = (pre_field_num?0:3); |
| if (cue_pr_cnt > 0) { |
| pr_info("[DI]: chan2 field num %d, cue_invert %d.\n", |
| pre_field_num, cue_invert); |
| cue_pr_cnt--; |
| } |
| Wr_reg_bits(NR2_CUE_MODE, cue_invert, 10, 2); |
| } |
| if (!nr_param.prog_flag) { |
| if (nr_param.frame_count > 1 && cue_glb_mot_check_en) |
| DI_Wr_reg_bits(DI_NR_CTRL0, cue_en?1:0, 26, 1); |
| } |
| if (nr_param.frame_count == 5) |
| Wr_reg_bits(NR2_CUE_MODE, 7, 0, 4); |
| } |
| void cue_int(void) |
| { |
| /*confirm with vlsi-liuyanling, G12a cue must be disabled*/ |
| if (is_meson_g12a_cpu()) { |
| cue_en = false; |
| cue_glb_mot_check_en = false; |
| } |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12B)) { |
| if (cue_en) |
| Wr_reg_bits(NR2_CUE_MODE, 3, 10, 2); |
| } |
| } |
| static bool glb_fieldck_en = true; |
| module_param_named(glb_fieldck_en, glb_fieldck_en, bool, 0644); |
| |
| void adaptive_cue_adjust(unsigned int frame_diff, unsigned int field_diff) |
| { |
| struct CUE_PARM_s *pcue_parm = nr_param.pcue_parm; |
| unsigned int mask1, mask2; |
| |
| if (is_meson_tl1_cpu()) { |
| /*value from VLSI(yanling.liu) 2018-12-07: */ |
| mask1 = 0x50332; |
| mask2 = 0x00054357; |
| } else { /*ori value*/ |
| mask1 = 0x50323; |
| mask2 = 0x00054375; |
| } |
| |
| if (frame_diff > pcue_parm->glb_mot_framethr) { |
| pcue_parm->frame_count = pcue_parm->frame_count > 0 ? |
| (pcue_parm->frame_count - 1) : 0; |
| } else if (pcue_parm->frame_count < pcue_parm->glb_mot_fieldnum) { |
| pcue_parm->frame_count = pcue_parm->frame_count + 1; |
| } |
| if (glb_fieldck_en) { |
| if (field_diff < pcue_parm->glb_mot_fieldthr) |
| pcue_parm->field_count = pcue_parm->field_count + 1; |
| else if (pcue_parm->field_count < pcue_parm->glb_mot_fieldnum) { |
| pcue_parm->field_count = pcue_parm->field_count > 0 ? |
| (pcue_parm->field_count - 1) : 0; |
| } |
| } |
| |
| if (cue_glb_mot_check_en) { |
| if (pcue_parm->frame_count > (pcue_parm->glb_mot_fieldnum - 6)) |
| cue_en = true; |
| else |
| cue_en = false; |
| /* for clockfuliness clip */ |
| if (pcue_parm->field_count > |
| (pcue_parm->glb_mot_fieldnum - 6)) { |
| Wr(NR2_CUE_MODE, mask1|(Rd(NR2_CUE_MODE)&0xc00)); |
| Wr(NR2_CUE_CON_MOT_TH, 0x03010e01); |
| } else { |
| Wr(NR2_CUE_MODE, mask2|(Rd(NR2_CUE_MODE)&0xc00)); |
| Wr(NR2_CUE_CON_MOT_TH, 0xa03c8c3c); |
| } |
| } |
| } |
| |
| /* |
| * insert nr ctrl regs into ctrl table |
| */ |
| bool set_nr_ctrl_reg_table(unsigned int addr, unsigned int value) |
| { |
| unsigned int i = 0; |
| struct NR_CTRL_REGS_s *pnr_regs = NULL; |
| |
| pnr_regs = nr_param.pnr_regs; |
| for (i = 0; i < NR_CTRL_REG_NUM; i++) { |
| if (pnr_regs->regs[i].addr == addr) { |
| pnr_regs->regs[i].addr = addr; |
| pnr_regs->regs[i].value = value; |
| atomic_set(&pnr_regs->regs[i].load_flag, 1); |
| if (nr_ctrl_reg) |
| pr_info("NR_CTRL_REG[0x%x]=[0x%x].\n", |
| addr, value); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* load nr related ctrl regs */ |
| static void nr_ctrl_reg_load(struct NR_CTRL_REGS_s *pnr_regs) |
| { |
| unsigned int i = 0; |
| |
| for (i = 0; i < pnr_regs->reg_num; i++) { |
| if (atomic_read(&pnr_regs->regs[i].load_flag)) { |
| DI_Wr(pnr_regs->regs[i].addr, |
| pnr_regs->regs[i].value); |
| atomic_set(&pnr_regs->regs[i].load_flag, 0); |
| if (nr_ctrl_reg) { |
| pr_info("LOAD NR[0x%x]=[0x%x]\n", |
| pnr_regs->regs[i].addr, |
| pnr_regs->regs[i].value); |
| } |
| } |
| } |
| } |
| |
| void nr_process_in_irq(void) |
| { |
| nr_param.frame_count++; |
| nr_ctrl_reg_load(nr_param.pnr_regs); |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXLX)) |
| cue_process_irq(); |
| if (dnr_en) |
| dnr_process(&dnr_param); |
| if (is_meson_txlx_cpu() || is_meson_g12a_cpu() |
| || is_meson_g12a_cpu() || is_meson_tl1_cpu() || |
| is_meson_sm1_cpu()) { |
| noise_meter_process(nr_param.pnr4_parm, nr_param.frame_count); |
| luma_enhancement_process(nr_param.pnr4_parm, |
| nr_param.frame_count); |
| } |
| } |
| static void parse_cmd_params(char *buf_orig, char **parm) |
| { |
| char *ps, *token; |
| char delim1[3] = " "; |
| char delim2[2] = "\n"; |
| unsigned int n = 0; |
| |
| ps = buf_orig; |
| strcat(delim1, delim2); |
| while (1) { |
| token = strsep(&ps, delim1); |
| if (token == NULL) |
| break; |
| if (*token == '\0') |
| continue; |
| parm[n++] = token; |
| } |
| } |
| |
| static dnr_param_t dnr_params[] = { |
| {"prm_sw_gbs_ctrl", &(dnr_param.prm_sw_gbs_ctrl)}, |
| {"prm_gbs_vldcntthd", &(dnr_param.prm_gbs_vldcntthd)}, |
| {"prm_gbs_cnt_min", &(dnr_param.prm_gbs_cnt_min)}, |
| {"prm_gbs_ratcalcmod", &(dnr_param.prm_gbs_ratcalcmod)}, |
| {"prm_gbs_ratthd[0]", &(dnr_param.prm_gbs_ratthd[0])}, |
| {"prm_gbs_ratthd[1]", &(dnr_param.prm_gbs_ratthd[1])}, |
| {"prm_gbs_ratthd[2]", &(dnr_param.prm_gbs_ratthd[2])}, |
| {"prm_gbs_difthd[0]", &(dnr_param.prm_gbs_difthd[0])}, |
| {"prm_gbs_difthd[1]", &(dnr_param.prm_gbs_difthd[1])}, |
| {"prm_gbs_difthd[2]", &(dnr_param.prm_gbs_difthd[2])}, |
| {"prm_gbs_bsdifthd", &(dnr_param.prm_gbs_bsdifthd)}, |
| {"prm_gbs_calcmod", &(dnr_param.prm_gbs_calcmod)}, |
| {"sw_gbs", &(dnr_param.sw_gbs)}, |
| {"sw_gbs_vld_flg", &(dnr_param.sw_gbs_vld_flg)}, |
| {"sw_gbs_vld_cnt", &(dnr_param.sw_gbs_vld_cnt)}, |
| {"prm_hbof_minthd", &(dnr_param.prm_hbof_minthd)}, |
| {"prm_hbof_ratthd0", &(dnr_param.prm_hbof_ratthd0)}, |
| {"prm_hbof_ratthd1", &(dnr_param.prm_hbof_ratthd1)}, |
| {"prm_hbof_vldcntthd", &(dnr_param.prm_hbof_vldcntthd)}, |
| {"sw_hbof", &(dnr_param.sw_hbof)}, |
| {"sw_hbof_vld_flg", &(dnr_param.sw_hbof_vld_flg)}, |
| {"sw_hbof_vld_cnt", &(dnr_param.sw_hbof_vld_cnt)}, |
| {"prm_vbof_minthd", &(dnr_param.prm_vbof_minthd)}, |
| {"prm_vbof_ratthd0", &(dnr_param.prm_vbof_ratthd0)}, |
| {"prm_vbof_ratthd1", &(dnr_param.prm_vbof_ratthd1)}, |
| {"prm_vbof_vldcntthd", &(dnr_param.prm_vbof_vldcntthd)}, |
| {"sw_vbof", &(dnr_param.sw_vbof)}, |
| {"sw_vbof_vld_flg", &(dnr_param.sw_vbof_vld_flg)}, |
| {"sw_vbof_vld_cnt", &(dnr_param.sw_vbof_vld_cnt)}, |
| {"dnr_stat_coef", &(dnr_param.dnr_stat_coef)}, |
| {"", NULL} |
| }; |
| static ssize_t dnr_param_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buff, size_t count) |
| { |
| int i = 0, value = 0; |
| char *parm[2] = {NULL}, *buf_orig; |
| |
| buf_orig = kstrdup(buff, GFP_KERNEL); |
| parse_cmd_params(buf_orig, (char **)(&parm)); |
| for (i = 0; dnr_params[i].addr; i++) { |
| if (!strcmp(parm[0], dnr_params[i].name)) { |
| value = kstrtol(parm[1], 10, NULL); |
| *(dnr_params[i].addr) = value; |
| pr_dbg("%s=%d.\n", dnr_params[i].name, |
| *(dnr_params[i].addr)); |
| } |
| } |
| |
| kfree(buf_orig); |
| return count; |
| } |
| |
| static ssize_t dnr_param_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buff) |
| { |
| ssize_t len = 0; |
| int i = 0; |
| |
| for (i = 0; dnr_params[i].addr; i++) |
| len += sprintf(buff+len, "%s=%d.\n", |
| dnr_params[i].name, *(dnr_params[i].addr)); |
| return len; |
| } |
| |
| static nr4_param_t nr4_params[NR4_PARAMS_NUM]; |
| static void nr4_params_init(struct NR4_PARM_s *nr4_parm_p) |
| { |
| nr4_params[0].name = "prm_nr4_srch_stp"; |
| nr4_params[0].addr = &(nr4_parm_p->prm_nr4_srch_stp); |
| nr4_params[1].name = "sw_nr4_field_sad[0]"; |
| nr4_params[1].addr = &(nr4_parm_p->sw_nr4_field_sad[0]); |
| nr4_params[2].name = "sw_nr4_field_sad[1]"; |
| nr4_params[2].addr = &(nr4_parm_p->sw_nr4_field_sad[1]); |
| nr4_params[3].name = "sw_nr4_scene_change_thd"; |
| nr4_params[3].addr = &(nr4_parm_p->sw_nr4_scene_change_thd); |
| nr4_params[4].name = "sw_nr4_scene_change_flg[0]"; |
| nr4_params[4].addr = &(nr4_parm_p->sw_nr4_scene_change_flg[0]); |
| nr4_params[5].name = "sw_nr4_scene_change_flg[1]"; |
| nr4_params[5].addr = &(nr4_parm_p->sw_nr4_scene_change_flg[1]); |
| nr4_params[6].name = "sw_nr4_scene_change_flg[2]"; |
| nr4_params[6].addr = &(nr4_parm_p->sw_nr4_scene_change_flg[2]); |
| nr4_params[7].name = "sw_nr4_sad2gain_en"; |
| nr4_params[7].addr = &(nr4_parm_p->sw_nr4_sad2gain_en); |
| nr4_params[8].name = "sw_nr4_sad2gain_lut[0]"; |
| nr4_params[8].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[0]); |
| nr4_params[9].name = "sw_nr4_sad2gain_lut[1]"; |
| nr4_params[9].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[1]); |
| nr4_params[10].name = "sw_nr4_sad2gain_lut[2]"; |
| nr4_params[10].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[2]); |
| nr4_params[11].name = "sw_nr4_sad2gain_lut[3]"; |
| nr4_params[11].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[3]); |
| nr4_params[12].name = "sw_nr4_sad2gain_lut[4]"; |
| nr4_params[12].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[4]); |
| nr4_params[13].name = "sw_nr4_sad2gain_lut[5]"; |
| nr4_params[13].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[5]); |
| nr4_params[14].name = "sw_nr4_sad2gain_lut[6]"; |
| nr4_params[14].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[6]); |
| nr4_params[15].name = "sw_nr4_sad2gain_lut[7]"; |
| nr4_params[15].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[7]); |
| nr4_params[16].name = "sw_nr4_sad2gain_lut[8]"; |
| nr4_params[16].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[8]); |
| nr4_params[17].name = "sw_nr4_sad2gain_lut[9]"; |
| nr4_params[17].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[9]); |
| nr4_params[18].name = "sw_nr4_sad2gain_lut[10]"; |
| nr4_params[18].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[10]); |
| nr4_params[19].name = "sw_nr4_sad2gain_lut11]"; |
| nr4_params[19].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[11]); |
| nr4_params[20].name = "sw_nr4_sad2gain_lut[12]"; |
| nr4_params[20].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[12]); |
| nr4_params[21].name = "sw_nr4_sad2gain_lut13]"; |
| nr4_params[21].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[13]); |
| nr4_params[22].name = "sw_nr4_sad2gain_lut[14]"; |
| nr4_params[22].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[14]); |
| nr4_params[23].name = "sw_nr4_sad2gain_lut[15]"; |
| nr4_params[23].addr = &(nr4_parm_p->sw_nr4_sad2gain_lut[15]); |
| nr4_params[24].name = "nr4_debug"; |
| nr4_params[24].addr = &(nr4_parm_p->nr4_debug); |
| |
| nr4_params[25].name = "sw_nr4_noise_thd"; |
| nr4_params[25].addr = &(nr4_parm_p->sw_nr4_noise_thd); |
| nr4_params[26].name = "sw_nr4_noise_sel"; |
| nr4_params[26].addr = &(nr4_parm_p->sw_nr4_noise_sel); |
| nr4_params[27].name = "sw_nr4_noise_ctrl_dm_en"; |
| nr4_params[27].addr = &(nr4_parm_p->sw_nr4_noise_ctrl_dm_en); |
| nr4_params[28].name = "sw_nr4_scene_change_thd2"; |
| nr4_params[28].addr = &(nr4_parm_p->sw_nr4_scene_change_thd2); |
| nr4_params[29].name = "sw_dm_scene_change_en"; |
| nr4_params[29].addr = &(nr4_parm_p->sw_dm_scene_change_en); |
| |
| }; |
| |
| static ssize_t nr4_param_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buff, size_t count) |
| { |
| long i = 0, value = 0; |
| char *parm[2] = {NULL}, *buf_orig; |
| |
| buf_orig = kstrdup(buff, GFP_KERNEL); |
| parse_cmd_params(buf_orig, (char **)(&parm)); |
| for (i = 0; i < NR4_PARAMS_NUM; i++) { |
| if (IS_ERR_OR_NULL(nr4_params[i].name) || |
| IS_ERR_OR_NULL(nr4_params[i].addr)) |
| continue; |
| if (!strcmp(parm[0], nr4_params[i].name)) { |
| if (parm[1]) { |
| if (kstrtol(parm[1], 10, &value) < 0) |
| pr_err("DI: input value error.\n"); |
| *(nr4_params[i].addr) = value; |
| } |
| pr_info(" %d\n", *(nr4_params[i].addr)); |
| } |
| } |
| |
| kfree(buf_orig); |
| return count; |
| } |
| |
| static ssize_t nr4_param_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buff) |
| { |
| ssize_t len = 0; |
| int i = 0; |
| |
| for (i = 0; i < NR4_PARAMS_NUM; i++) { |
| if (IS_ERR_OR_NULL(nr4_params[i].name) || |
| IS_ERR_OR_NULL(nr4_params[i].addr)) |
| continue; |
| len += sprintf(buff+len, "%s=%d.\n", |
| nr4_params[i].name, *(nr4_params[i].addr)); |
| } |
| |
| return len; |
| } |
| |
| static DEVICE_ATTR(nr4_param, 0664, nr4_param_show, nr4_param_store); |
| |
| static void nr4_param_init(struct NR4_PARM_s *nr4_parm_p) |
| { |
| int k = 0; |
| |
| nr4_parm_p->border_offset = 8; |
| nr4_parm_p->nr4_debug = 0; |
| nr4_parm_p->prm_nr4_srch_stp = 1; |
| nr4_parm_p->sw_nr4_field_sad[0] = 0; |
| nr4_parm_p->sw_nr4_field_sad[1] = 0; |
| nr4_parm_p->sw_nr4_scene_change_thd = 20; |
| for (k = 0; k < 3; k++) |
| nr4_parm_p->sw_nr4_scene_change_flg[k] = 0; |
| nr4_parm_p->sw_nr4_sad2gain_en = 1; |
| nr4_parm_p->sw_nr4_sad2gain_lut[0] = 1; |
| nr4_parm_p->sw_nr4_sad2gain_lut[1] = 2; |
| nr4_parm_p->sw_nr4_sad2gain_lut[2] = 2; |
| nr4_parm_p->sw_nr4_sad2gain_lut[3] = 4; |
| nr4_parm_p->sw_nr4_sad2gain_lut[4] = 8; |
| nr4_parm_p->sw_nr4_sad2gain_lut[5] = 16; |
| nr4_parm_p->sw_nr4_sad2gain_lut[6] = 32; |
| nr4_parm_p->sw_nr4_sad2gain_lut[7] = 63; |
| nr4_parm_p->sw_nr4_sad2gain_lut[8] = 67; |
| nr4_parm_p->sw_nr4_sad2gain_lut[9] = 104; |
| nr4_parm_p->sw_nr4_sad2gain_lut[10] = 48; |
| nr4_parm_p->sw_nr4_sad2gain_lut[11] = 32; |
| nr4_parm_p->sw_nr4_sad2gain_lut[12] = 20; |
| nr4_parm_p->sw_nr4_sad2gain_lut[13] = 16; |
| nr4_parm_p->sw_nr4_sad2gain_lut[14] = 14; |
| nr4_parm_p->sw_nr4_sad2gain_lut[15] = 9; |
| |
| if (is_meson_tl1_cpu()) { |
| nr4_parm_p->sw_nr4_noise_thd = 32; |
| nr4_parm_p->sw_nr4_noise_sel = 0; |
| nr4_parm_p->sw_nr4_noise_ctrl_dm_en = 0; |
| nr4_parm_p->sw_nr4_scene_change_thd2 = 80; |
| nr4_parm_p->sw_dm_scene_change_en = 0; |
| } else { |
| nr4_parm_p->sw_nr4_noise_thd = 32; |
| nr4_parm_p->sw_nr4_noise_sel = 0; |
| nr4_parm_p->sw_nr4_noise_ctrl_dm_en = 0; |
| nr4_parm_p->sw_nr4_scene_change_thd2 = 80; |
| nr4_parm_p->sw_dm_scene_change_en = 0; |
| } |
| } |
| |
| static void cue_param_init(struct CUE_PARM_s *cue_parm_p) |
| { |
| cue_parm_p->glb_mot_framethr = 1000; |
| cue_parm_p->glb_mot_fieldnum = 20; |
| cue_parm_p->glb_mot_fieldthr = 10; |
| cue_parm_p->field_count = 8; |
| cue_parm_p->frame_count = 8; |
| } |
| static int dnr_prm_init(DNR_PRM_t *pPrm) |
| { |
| pPrm->prm_sw_gbs_ctrl = 0; |
| /* |
| * 0: update gbs, 1: update hoffst & gbs, |
| * 2: update voffst & gbs, 3: update all (hoffst & voffst & gbs). |
| */ |
| |
| pPrm->prm_gbs_vldcntthd = 4; |
| pPrm->prm_gbs_cnt_min = 32; |
| pPrm->prm_gbs_ratcalcmod = 1;/* 0: use LR, 1: use Dif */ |
| pPrm->prm_gbs_ratthd[0] = 40; |
| pPrm->prm_gbs_ratthd[1] = 80; |
| pPrm->prm_gbs_ratthd[2] = 120; |
| pPrm->prm_gbs_difthd[0] = 25; |
| pPrm->prm_gbs_difthd[1] = 75; |
| pPrm->prm_gbs_difthd[2] = 125; |
| pPrm->prm_gbs_bsdifthd = 1; |
| pPrm->prm_gbs_calcmod = 1; /* 0:dif0, 1:dif1, 2: dif2 */ |
| |
| pPrm->sw_gbs = 0; |
| pPrm->sw_gbs_vld_flg = 0; |
| pPrm->sw_gbs_vld_cnt = 0; |
| |
| pPrm->prm_hbof_minthd = 32; |
| pPrm->prm_hbof_ratthd0 = 150; |
| pPrm->prm_hbof_ratthd1 = 150; |
| pPrm->prm_hbof_vldcntthd = 4; |
| pPrm->sw_hbof = 0; |
| pPrm->sw_hbof_vld_flg = 0; |
| pPrm->sw_hbof_vld_cnt = 0; |
| |
| pPrm->prm_vbof_minthd = 32; |
| pPrm->prm_vbof_ratthd0 = 150; |
| pPrm->prm_vbof_ratthd1 = 120; |
| pPrm->prm_vbof_vldcntthd = 4; |
| pPrm->sw_vbof = 0; |
| pPrm->sw_vbof_vld_flg = 0; |
| pPrm->sw_vbof_vld_cnt = 0; |
| pPrm->dnr_stat_coef = 3; |
| return 0; |
| } |
| |
| static DEVICE_ATTR(dnr_param, 0664, dnr_param_show, dnr_param_store); |
| |
| static void nr_all_ctrl(bool enable) |
| { |
| unsigned char value = 0; |
| |
| value = enable ? 1 : 0; |
| |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX)) { |
| /* nr4 nr2*/ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, value, 18, 1); |
| DI_Wr_reg_bits(NR4_TOP_CTRL, value, 2, 1); |
| } else { |
| DI_Wr_reg_bits(NR2_SW_EN, value, 4, 1); |
| } |
| DI_Wr_reg_bits(DNR_CTRL, value, 16, 1); |
| |
| } |
| static ssize_t nr_dbg_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buff, size_t count) |
| { |
| char *parm[2] = {NULL}, *buf_orig; |
| |
| buf_orig = kstrdup(buff, GFP_KERNEL); |
| parse_cmd_params(buf_orig, (char **)(&parm)); |
| if (!strcmp(parm[0], "disable")) |
| nr_all_ctrl(false); |
| else if (!strcmp(parm[0], "enable")) |
| nr_all_ctrl(true); |
| |
| kfree(buf_orig); |
| return count; |
| } |
| |
| static ssize_t nr_dbg_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buff) |
| { |
| ssize_t len = 0; |
| |
| len += sprintf(buff+len, |
| "echo disable/enable to disable/enable nr(nr2/nr4/dnr).\n"); |
| len += sprintf(buff+len, |
| "NR4_TOP_CTRL=0x%x DNR_CTRL=0x%x DI_NR_CTRL0=0x%x\n", |
| Rd(NR4_TOP_CTRL), Rd(DNR_CTRL), Rd(DI_NR_CTRL0)); |
| |
| return len; |
| } |
| |
| |
| static DEVICE_ATTR(nr_debug, 0664, nr_dbg_show, nr_dbg_store); |
| |
| void nr_hw_init(void) |
| { |
| |
| nr_gate_control(true); |
| if (is_meson_tl1_cpu()) |
| DI_Wr(DNR_CTRL, 0x1df00|(0x03<<18));//5 line |
| else |
| DI_Wr(DNR_CTRL, 0x1df00); |
| DI_Wr(NR3_MODE, 0x3); |
| DI_Wr(NR3_COOP_PARA, 0x28ff00); |
| DI_Wr(NR3_CNOOP_GAIN, 0x881900); |
| DI_Wr(NR3_YMOT_PARA, 0x0c0a1e); |
| DI_Wr(NR3_CMOT_PARA, 0x08140f); |
| DI_Wr(NR3_SUREMOT_YGAIN, 0x100c4014); |
| DI_Wr(NR3_SUREMOT_CGAIN, 0x22264014); |
| nr_gate_control(false); |
| } |
| void nr_gate_control(bool gate) |
| { |
| if (!is_meson_txlx_cpu() && !is_meson_g12a_cpu() |
| && !is_meson_g12b_cpu() && !is_meson_sm1_cpu() |
| && !is_meson_tl1_cpu()) |
| return; |
| if (gate) { |
| /* enable nr auto gate */ |
| DI_Wr_reg_bits(VIUB_GCLK_CTRL2, 0, 0, 2); |
| /* enable dnr auto gate */ |
| DI_Wr_reg_bits(VIUB_GCLK_CTRL2, 0, 8, 2); |
| /* enable nr/dm blend auto gate */ |
| DI_Wr_reg_bits(VIUB_GCLK_CTRL2, 0, 10, 2); |
| /* enable nr internal snr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 30, 2); |
| /* enable nr internal tnr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 28, 2); |
| /* enable nr internal mcnr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 26, 2); |
| /* enable nr internal cfr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 24, 2); |
| /* enable nr internal det_polar gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 22, 2); |
| /* enable nr internal 3ddet gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 20, 2); |
| } else { |
| /* enable nr auto gate */ |
| DI_Wr_reg_bits(VIUB_GCLK_CTRL2, 1, 0, 2); |
| /* enable dnr auto gate */ |
| DI_Wr_reg_bits(VIUB_GCLK_CTRL2, 1, 8, 2); |
| /* disable nr/dm blend auto gate */ |
| DI_Wr_reg_bits(VIUB_GCLK_CTRL2, 1, 10, 2); |
| /* disable nr internal snr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 30, 2); |
| /* disable nr internal tnr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 28, 2); |
| /* disable nr internal mcnr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 26, 2); |
| /* disable nr internal cfr gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 24, 2); |
| /* disable nr internal det_polar gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 22, 2); |
| /* disable nr internal 3ddet gate */ |
| DI_Wr_reg_bits(NR4_TOP_CTRL, 1, 20, 2); |
| } |
| } |
| /* |
| * set ctrl reg address need load in irq |
| */ |
| static void nr_ctrl_regs_init(struct NR_CTRL_REGS_s *pnr_regs) |
| { |
| unsigned int i = 0; |
| |
| pnr_regs->regs[0].addr = NR4_TOP_CTRL; |
| pnr_regs->regs[1].addr = NR_DB_FLT_CTRL; |
| pnr_regs->regs[2].addr = DNR_DM_CTRL; |
| pnr_regs->regs[3].addr = DI_NR_CTRL0; |
| pnr_regs->regs[4].addr = DNR_CTRL; |
| pnr_regs->regs[5].addr = NR2_CUE_PRG_DIF; |
| pnr_regs->reg_num = NR_CTRL_REG_NUM; |
| for (i = 0; i < pnr_regs->reg_num; i++) { |
| pnr_regs->regs[i].value = 0; |
| atomic_set(&pnr_regs->regs[i].load_flag, 0); |
| } |
| } |
| |
| void nr_drv_uninit(struct device *dev) |
| { |
| if (nr_param.pnr4_parm) { |
| vfree(nr_param.pnr4_parm); |
| nr_param.pnr4_parm = NULL; |
| } |
| if (nr_param.pnr_regs) { |
| vfree(nr_param.pnr_regs); |
| nr_param.pnr_regs = NULL; |
| } |
| if (nr_param.pcue_parm) { |
| vfree(nr_param.pcue_parm); |
| nr_param.pcue_parm = NULL; |
| } |
| |
| device_remove_file(dev, &dev_attr_nr4_param); |
| device_remove_file(dev, &dev_attr_dnr_param); |
| device_remove_file(dev, &dev_attr_nr_debug); |
| } |
| void nr_drv_init(struct device *dev) |
| { |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX)) { |
| nr_param.pnr4_parm = vmalloc(sizeof(struct NR4_PARM_s)); |
| if (IS_ERR(nr_param.pnr4_parm)) |
| pr_err("%s allocate nr4 parm error.\n", __func__); |
| else { |
| nr4_params_init(nr_param.pnr4_parm); |
| nr4_param_init(nr_param.pnr4_parm); |
| device_create_file(dev, &dev_attr_nr4_param); |
| } |
| } |
| nr_param.pnr_regs = vmalloc(sizeof(struct NR_CTRL_REGS_s)); |
| if (IS_ERR(nr_param.pnr_regs)) |
| pr_err("%s allocate ctrl regs error.\n", __func__); |
| else |
| nr_ctrl_regs_init(nr_param.pnr_regs); |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXLX)) { |
| nr_param.pcue_parm = vmalloc(sizeof(struct CUE_PARM_s)); |
| if (IS_ERR(nr_param.pcue_parm)) |
| pr_err("%s allocate cue parm error.\n", __func__); |
| else |
| cue_param_init(nr_param.pcue_parm); |
| } |
| dnr_prm_init(&dnr_param); |
| nr_param.pdnr_parm = &dnr_param; |
| device_create_file(dev, &dev_attr_dnr_param); |
| device_create_file(dev, &dev_attr_nr_debug); |
| if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB)) |
| dnr_dm_en = true; |
| else |
| dnr_dm_en = false; |
| } |