| /* |
| * drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.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/types.h> |
| #include <linux/init.h> |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/fs.h> |
| #include <linux/uaccess.h> |
| #include <linux/io.h> |
| #include <linux/errno.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/platform_device.h> |
| #include <linux/amlogic/media/vfm/vframe.h> |
| #include <linux/amlogic/media/video_sink/video.h> |
| #include <linux/amlogic/media/amvecm/amvecm.h> |
| #include <linux/amlogic/media/vout/vout_notify.h> |
| #include <linux/amlogic/media/vfm/vframe_provider.h> |
| #include <linux/amlogic/media/vfm/vframe_receiver.h> |
| #include <linux/amlogic/media/utils/amstream.h> |
| #include "../amvecm/arch/vpp_regs.h" |
| #include "../amvecm/arch/vpp_hdr_regs.h" |
| #include "../amvecm/arch/vpp_dolbyvision_regs.h" |
| #include <linux/amlogic/media/registers/regs/viu_regs.h> |
| #include <linux/amlogic/media/amdolbyvision/dolby_vision.h> |
| #include <linux/cma.h> |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/dma-contiguous.h> |
| #include <linux/amlogic/iomap.h> |
| #include "amdolby_vision.h" |
| |
| #include <linux/device.h> |
| #include <linux/cdev.h> |
| #include <linux/of.h> |
| #include <linux/string.h> |
| #include <linux/mm.h> |
| #include <linux/slab.h> |
| #include <linux/stat.h> |
| #include <linux/ctype.h>/* for parse_para_pq */ |
| #include <linux/string.h> |
| #include <linux/vmalloc.h> |
| #include <linux/arm-smccc.h> |
| |
| DEFINE_SPINLOCK(dovi_lock); |
| |
| static const struct dolby_vision_func_s *p_funcs; |
| |
| #define AMDOLBY_VISION_NAME "amdolby_vision" |
| #define AMDOLBY_VISION_CLASS_NAME "amdolby_vision" |
| |
| struct amdolby_vision_dev_s { |
| dev_t devt; |
| struct cdev cdev; |
| dev_t devno; |
| struct device *dev; |
| struct class *clsp; |
| }; |
| static struct amdolby_vision_dev_s amdolby_vision_dev; |
| struct dv_device_data_s dv_meson_dev; |
| static unsigned int dolby_vision_request_mode = 0xff; |
| |
| #define DOLBY_VISION_OUTPUT_MODE_IPT 0 |
| #define DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL 1 |
| #define DOLBY_VISION_OUTPUT_MODE_HDR10 2 |
| #define DOLBY_VISION_OUTPUT_MODE_SDR10 3 |
| #define DOLBY_VISION_OUTPUT_MODE_SDR8 4 |
| #define DOLBY_VISION_OUTPUT_MODE_BYPASS 5 |
| static unsigned int dolby_vision_mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| module_param(dolby_vision_mode, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_mode, "\n dolby_vision_mode\n"); |
| |
| static unsigned int dolby_vision_profile = 0xff; |
| module_param(dolby_vision_profile, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_profile, "\n dolby_vision_profile\n"); |
| |
| static unsigned int dolby_vision_level = 0xff; |
| module_param(dolby_vision_level, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_level, "\n dolby_vision_level\n"); |
| |
| /* STB: if sink support DV, always output DV*/ |
| /* else always output SDR/HDR */ |
| /* TV: when source is DV, convert to SDR */ |
| #define DOLBY_VISION_FOLLOW_SINK 0 |
| |
| /* STB: output DV only if source is DV*/ |
| /* and sink support DV*/ |
| /* else always output SDR/HDR */ |
| /* TV: when source is DV or HDR, convert to SDR */ |
| #define DOLBY_VISION_FOLLOW_SOURCE 1 |
| |
| /* STB: always follow dolby_vision_mode */ |
| /* TV: if set dolby_vision_mode to SDR8,*/ |
| /* convert all format to SDR by TV core,*/ |
| /* else bypass Dolby Vision */ |
| #define DOLBY_VISION_FORCE_OUTPUT_MODE 2 |
| |
| static unsigned int dolby_vision_policy; |
| module_param(dolby_vision_policy, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_policy, "\n dolby_vision_policy\n"); |
| |
| /* bit0: 0: bypass hdr to vpp, 1: process hdr by dolby core */ |
| /* bit1: 0: output to sdr, 1: output to hdr if sink support hdr not dovi */ |
| static unsigned int dolby_vision_hdr10_policy; |
| module_param(dolby_vision_hdr10_policy, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_hdr10_policy, "\n dolby_vision_hdr10_policy\n"); |
| |
| static bool dolby_vision_enable; |
| module_param(dolby_vision_enable, bool, 0664); |
| MODULE_PARM_DESC(dolby_vision_enable, "\n dolby_vision_enable\n"); |
| |
| static bool force_stb_mode; |
| |
| static bool dolby_vision_efuse_bypass; |
| module_param(dolby_vision_efuse_bypass, bool, 0664); |
| MODULE_PARM_DESC(dolby_vision_efuse_bypass, "\n dolby_vision_efuse_bypass\n"); |
| static bool efuse_mode; |
| |
| static bool el_mode; |
| module_param(force_stb_mode, bool, 0664); |
| MODULE_PARM_DESC(force_stb_mode, "\n force_stb_mode\n"); |
| |
| static uint dolby_vision_mask = 7; |
| module_param(dolby_vision_mask, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_mask, "\n dolby_vision_mask\n"); |
| |
| #define BYPASS_PROCESS 0 |
| #define SDR_PROCESS 1 |
| #define HDR_PROCESS 2 |
| #define DV_PROCESS 3 |
| static uint dolby_vision_status; |
| module_param(dolby_vision_status, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_status, "\n dolby_vision_status\n"); |
| |
| /* delay before first frame toggle when core off->on */ |
| static uint dolby_vision_wait_delay; |
| module_param(dolby_vision_wait_delay, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_wait_delay, "\n dolby_vision_wait_delay\n"); |
| static int dolby_vision_wait_count; |
| |
| /* reset 1st fake frame (bit 0)*/ |
| /* and other fake frames (bit 1)*/ |
| /* and other toggle frames (bit 2) */ |
| static uint dolby_vision_reset = (1 << 1) | (1 << 0); |
| module_param(dolby_vision_reset, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_reset, "\n dolby_vision_reset\n"); |
| |
| /* force run mode */ |
| static uint dolby_vision_run_mode = 0xff; /* not force */ |
| module_param(dolby_vision_run_mode, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_run_mode, "\n dolby_vision_run_mode\n"); |
| |
| /* number of fake frame (run mode = 1) */ |
| #define RUN_MODE_DELAY 2 |
| static uint dolby_vision_run_mode_delay = RUN_MODE_DELAY; |
| module_param(dolby_vision_run_mode_delay, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_run_mode_delay, "\n dolby_vision_run_mode_delay\n"); |
| |
| /* reset control -- end << 8 | start */ |
| static uint dolby_vision_reset_delay = |
| (RUN_MODE_DELAY << 8) | RUN_MODE_DELAY; |
| module_param(dolby_vision_reset_delay, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_reset_delay, "\n dolby_vision_reset_delay\n"); |
| |
| static unsigned int dolby_vision_tunning_mode; |
| module_param(dolby_vision_tunning_mode, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_tunning_mode, "\n dolby_vision_tunning_mode\n"); |
| |
| #ifdef V2_4 |
| static unsigned int dv_ll_output_mode = DOLBY_VISION_OUTPUT_MODE_HDR10; |
| module_param(dv_ll_output_mode, uint, 0664); |
| MODULE_PARM_DESC(dv_ll_output_mode, "\n dv_ll_output_mode\n"); |
| |
| #define DOLBY_VISION_LL_DISABLE 0 |
| #define DOLBY_VISION_LL_YUV422 1 |
| #define DOLBY_VISION_LL_RGB444 2 |
| static u32 dolby_vision_ll_policy = DOLBY_VISION_LL_DISABLE; |
| module_param(dolby_vision_ll_policy, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_ll_policy, "\n dolby_vision_ll_policy\n"); |
| static u32 last_dolby_vision_ll_policy = DOLBY_VISION_LL_DISABLE; |
| #endif |
| |
| static uint dolby_vision_on_count; |
| |
| #define FLAG_FORCE_CVM 0x01 |
| #define FLAG_BYPASS_CVM 0x02 |
| #define FLAG_BYPASS_VPP 0x04 |
| #define FLAG_USE_SINK_MIN_MAX 0x08 |
| #define FLAG_CLKGATE_WHEN_LOAD_LUT 0x10 |
| #define FLAG_SINGLE_STEP 0x20 |
| #define FLAG_CERTIFICAION 0x40 |
| #define FLAG_CHANGE_SEQ_HEAD 0x80 |
| #define FLAG_DISABLE_COMPOSER 0x100 |
| #define FLAG_BYPASS_CSC 0x200 |
| #define FLAG_CHECK_ES_PTS 0x400 |
| #define FLAG_DISABE_CORE_SETTING 0x800 |
| #define FLAG_DISABLE_DMA_UPDATE 0x1000 |
| #define FLAG_DISABLE_DOVI_OUT 0x2000 |
| #define FLAG_FORCE_DOVI_LL 0x4000 |
| #define FLAG_FORCE_RGB_OUTPUT 0x8000 |
| /* #define FLAG_DOVI_LL_RGB_DESIRED 0x8000 */ |
| #define FLAG_DOVI2HDR10_NOMAPPING 0x100000 |
| #define FLAG_PRIORITY_GRAPHIC 0x200000 |
| #define FLAG_DISABLE_LOAD_VSVDB 0x400000 |
| #define FLAG_DISABLE_CRC 0x800000 |
| #define FLAG_TOGGLE_FRAME 0x80000000 |
| |
| #define FLAG_FRAME_DELAY_MASK 0xf |
| #define FLAG_FRAME_DELAY_SHIFT 16 |
| |
| static unsigned int dolby_vision_flags = FLAG_BYPASS_VPP | FLAG_FORCE_CVM; |
| module_param(dolby_vision_flags, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_flags, "\n dolby_vision_flags\n"); |
| |
| static unsigned int htotal_add = 0x140; |
| static unsigned int vtotal_add = 0x40; |
| static unsigned int vsize_add; |
| static unsigned int vwidth = 0x8; |
| static unsigned int hwidth = 0x8; |
| static unsigned int vpotch = 0x10; |
| static unsigned int hpotch = 0x8; |
| static unsigned int g_htotal_add = 0x40; |
| static unsigned int g_vtotal_add = 0x80; |
| static unsigned int g_vsize_add; |
| static unsigned int g_vwidth = 0x18; |
| static unsigned int g_hwidth = 0x10; |
| static unsigned int g_vpotch = 0x8; |
| static unsigned int g_hpotch = 0x10; |
| /*dma size:1877x2x64 bit = 30032 byte*/ |
| #define TV_DMA_TBL_SIZE 3754 |
| static unsigned int dma_size = 30032; |
| static dma_addr_t dma_paddr; |
| static void *dma_vaddr; |
| static unsigned int dma_start_line = 0x400; |
| |
| #define CRC_BUFF_SIZE (256 * 1024) |
| static char *crc_output_buf; |
| static u32 crc_outpuf_buff_off; |
| static u32 crc_count; |
| static u32 crc_bypass_count; |
| static u32 setting_update_count; |
| static s32 crc_read_delay; |
| static u32 core1_disp_hsize; |
| static u32 core1_disp_vsize; |
| static u32 vsync_count; |
| #define FLAG_VSYNC_CNT 10 |
| |
| static bool is_osd_off; |
| static bool force_reset_core2; |
| |
| module_param(vtotal_add, uint, 0664); |
| MODULE_PARM_DESC(vtotal_add, "\n vtotal_add\n"); |
| module_param(vpotch, uint, 0664); |
| MODULE_PARM_DESC(vpotch, "\n vpotch\n"); |
| |
| static unsigned int dolby_vision_target_min = 50; /* 0.0001 */ |
| #ifdef V2_4 |
| static unsigned int dolby_vision_target_max[3][3] = { |
| { 4000, 1000, 100 }, /* DOVI => DOVI/HDR/SDR */ |
| { 1000, 1000, 100 }, /* HDR => DOVI/HDR/SDR */ |
| { 600, 1000, 100 }, /* SDR => DOVI/HDR/SDR */ |
| }; |
| #else |
| static unsigned int dolby_vision_target_max[3][3] = { |
| { 4000, 4000, 100 }, /* DOVI => DOVI/HDR/SDR */ |
| { 1000, 1000, 100 }, /* HDR => DOVI/HDR/SDR */ |
| { 600, 1000, 100 }, /* SDR => DOVI/HDR/SDR */ |
| }; |
| #endif |
| |
| static unsigned int dolby_vision_default_max[3][3] = { |
| { 4000, 4000, 100 }, /* DOVI => DOVI/HDR/SDR */ |
| { 1000, 1000, 100 }, /* HDR => DOVI/HDR/SDR */ |
| { 600, 1000, 100 }, /* SDR => DOVI/HDR/SDR */ |
| }; |
| |
| static unsigned int dolby_vision_graphic_min = 50; /* 0.0001 */ |
| static unsigned int dolby_vision_graphic_max = 100; /* 1 */ |
| module_param(dolby_vision_graphic_min, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_graphic_min, "\n dolby_vision_graphic_min\n"); |
| module_param(dolby_vision_graphic_max, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_graphic_max, "\n dolby_vision_graphic_max\n"); |
| |
| /*these two parameters form OSD*/ |
| static unsigned int osd_graphic_width = 1920; |
| static unsigned int osd_graphic_height = 1080; |
| |
| static unsigned int dv_cert_graphic_width = 1920; |
| static unsigned int dv_cert_graphic_height = 1080; |
| module_param(dv_cert_graphic_width, uint, 0664); |
| MODULE_PARM_DESC(dv_cert_graphic_width, "\n dv_cert_graphic_width\n"); |
| module_param(dv_cert_graphic_height, uint, 0664); |
| MODULE_PARM_DESC(dv_cert_graphic_height, "\n dv_cert_graphic_height\n"); |
| |
| /* 0: video priority 1: graphic priority */ |
| static unsigned int dolby_vision_graphics_priority; |
| module_param(dolby_vision_graphics_priority, uint, 0664); |
| MODULE_PARM_DESC(dolby_vision_graphics_priority, "\n dolby_vision_graphics_priority\n"); |
| |
| uint16_t L2PQ_100_500[] = { |
| 2081, /* 100 */ |
| 2157, /* 120 */ |
| 2221, /* 140 */ |
| 2277, /* 160 */ |
| 2327, /* 180 */ |
| 2372, /* 200 */ |
| 2413, /* 220 */ |
| 2450, /* 240 */ |
| 2485, /* 260 */ |
| 2517, /* 280 */ |
| 2547, /* 300 */ |
| 2575, /* 320 */ |
| 2602, /* 340 */ |
| 2627, /* 360 */ |
| 2651, /* 380 */ |
| 2673, /* 400 */ |
| 2694, /* 420 */ |
| 2715, /* 440 */ |
| 2734, /* 460 */ |
| 2753, /* 480 */ |
| 2771, /* 500 */ |
| }; |
| |
| uint16_t L2PQ_500_4000[] = { |
| 2771, /* 500 */ |
| 2852, /* 600 */ |
| 2920, /* 700 */ |
| 2980, /* 800 */ |
| 3032, /* 900 */ |
| 3079, /* 1000 */ |
| 3122, /* 1100 */ |
| 3161, /* 1200 */ |
| 3197, /* 1300 */ |
| 3230, /* 1400 */ |
| 3261, /* 1500 */ |
| 3289, /* 1600 */ |
| 3317, /* 1700 */ |
| 3342, /* 1800 */ |
| 3366, /* 1900 */ |
| 3389, /* 2000 */ |
| 3411, /* 2100 */ |
| 3432, /* 2200 */ |
| 3451, /* 2300 */ |
| 3470, /* 2400 */ |
| 3489, /* 2500 */ |
| 3506, /* 2600 */ |
| 3523, /* 2700 */ |
| 3539, /* 2800 */ |
| 3554, /* 2900 */ |
| 3570, /* 3000 */ |
| 3584, /* 3100 */ |
| 3598, /* 3200 */ |
| 3612, /* 3300 */ |
| 3625, /* 3400 */ |
| 3638, /* 3500 */ |
| 3651, /* 3600 */ |
| 3662, /* 3700 */ |
| 3674, /* 3800 */ |
| 3686, /* 3900 */ |
| 3697, /* 4000 */ |
| }; |
| |
| static uint32_t tv_max_lin = 200; |
| static uint16_t tv_max_pq = 2372; |
| |
| static unsigned int panel_max_lumin; |
| module_param(panel_max_lumin, uint, 0664); |
| MODULE_PARM_DESC(panel_max_lumin, "\n panel_max_lumin\n"); |
| |
| #ifdef V1_5 |
| struct TargetDisplayConfig def_tgt_display_cfg = { |
| 4095, /* gain */ |
| 0, /* offset */ |
| 39322, /* gamma */ |
| 0, /* eotf */ |
| 12, /* bitDepth */ |
| 0, /* rangeSpec */ |
| 42, /* diagSize */ |
| 2771, /* maxPq */ |
| 62, /* minPq */ |
| 2048, /* mSWeight */ |
| 16380, /* mSEdgeWeight */ |
| 0, /* minPQBias */ |
| 0, /* midPQBias */ |
| 0, /* maxPQBias */ |
| 0, /* trimSlopeBias */ |
| 0, /* trimOffsetBias */ |
| 0, /* trimPowerBias */ |
| 0, /* msWeightBias */ |
| 0, /* brightness */ |
| 0, /* contrast */ |
| 0, /* chromaWeightBias */ |
| 0, /* saturationGainBias */ |
| 2048, /* chromaWeight */ |
| 2048, /* saturationGain */ |
| 655, /* crossTalk */ |
| 0, /* tuningMode */ |
| 0, /* reserved0 */ |
| 0, /* dbgExecParamsPrintPeriod */ |
| 0, /* dbgDmMdPrintPeriod */ |
| 0, /* dbgDmCfgPrintPeriod */ |
| 2771, /* maxPq_dupli */ |
| 62, /* minPq_dupli */ |
| 12288, /* keyWeight */ |
| 24576, /* intensityVectorWeight */ |
| 24576, /* chromaVectorWeight */ |
| 0, /* chip_fpga_lowcomplex */ |
| { |
| -245, |
| -208, |
| -171, |
| -130, |
| -93, |
| -56, |
| -19, |
| 20, |
| 57, |
| 94, |
| 131, |
| 172, |
| 209, |
| 246, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| -3685, |
| -3070, |
| -2456, |
| -1842, |
| -1228, |
| -613, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 1, /* gdEnable */ |
| 6553, /* gdWMin */ |
| 131072000, /* gdWMax */ |
| 26214400, /* gdWMm */ |
| 16579442, /* gdWDynRngSqrt */ |
| 4096, /* gdWeightMean */ |
| 4096, /* gdWeightStd */ |
| 0, /* gdDelayMilliSec_hdmi */ |
| 1, /* gdRgb2YuvExt */ |
| { |
| {5960, 20047, 2023}, |
| {-3286, -11052, 14336}, |
| {14336, -13022, -1316} |
| }, /* gdM33Rgb2Yuv[3][3] */ |
| 15, /* gdM33Rgb2YuvScale2P */ |
| 1, /* gdRgb2YuvOffExt */ |
| {2048, 16384, 16384},/* gdV3Rgb2YuvOff[3] */ |
| 2072430, /* gdUpBound */ |
| 414486, /* gdLowBound */ |
| 0, /* lastMaxPq */ |
| 137, /*gdWMinPq */ |
| 2771, /*gdWMaxPq */ |
| 2081, /*gdWMmPq */ |
| 0, /*gdTriggerPeriod */ |
| 0, /* gdTriggerLinThresh */ |
| 0, /* gdDelayMilliSec_ott */ |
| #ifdef V1_5 |
| {0, 0, 0, 0, 0, 0}, |
| #else |
| {0, 0, 0, 0, 0, 0, 0, 0, 0} |
| #endif |
| }, |
| #ifdef V1_5 |
| {0, 0, 0, 68, 124, 49, 230}, |
| {0, 0, 0, 0, 0}, |
| #endif |
| 1311, /* min_lin */ |
| 131072000, /* max_lin */ |
| 0, /* backlight_scaler */ |
| 1311, /* min_lin_dupli */ |
| 131072000, /* max_lin_dupli */ |
| { |
| /* lms2RgbMat[3][3] */ |
| { |
| {22416, -19015, 695}, |
| {-4609, 9392, -688}, |
| {122, -791, 4765} |
| }, |
| 12, /* lms2RgbMatScale */ |
| {128, 128, 128}, /* whitePoint */ |
| 7, /* whitePointScale */ |
| {0, 0, 0} /* reserved[3] */ |
| }, |
| 0, /* reserved00 */ |
| 0, /* brightnessPreservation */ |
| 81920, /* iintensityVectorWeight */ |
| 24576, /* ichromaVectorWeight */ |
| 0, /* isaturationGainBias */ |
| 0, /* chip_12b_ocsc */ |
| 0, /* chip_512_tonecurve */ |
| 0, /* chip_nolvl5 */ |
| {0, 0, 0, 0, 0, 0, 0, 0} /* padding[8] */ |
| }; |
| struct TargetDisplayConfig def_tgt_display_cfg_ll = { |
| 4095, /* gain */ |
| 0, /* offset */ |
| 39322, /* gamma */ |
| 2, /* eotf */ |
| 12, /* bitDepth */ |
| 0, /* rangeSpec */ |
| 42, /* diagSize */ |
| 2873, /* maxPq */ |
| 263, /* minPq */ |
| 2048, /* mSWeight */ |
| 16380, /* mSEdgeWeight */ |
| 0, /* minPQBias */ |
| 0, /* midPQBias */ |
| 0, /* maxPQBias */ |
| 0, /* trimSlopeBias */ |
| 0, /* trimOffsetBias */ |
| 0, /* trimPowerBias */ |
| 0, /* msWeightBias */ |
| 0, /* brightness */ |
| 0, /* contrast */ |
| 0, /* chromaWeightBias */ |
| 0, /* saturationGainBias */ |
| 2048, /* chromaWeight */ |
| 2048, /* saturationGain */ |
| 655, /* crossTalk */ |
| 0, /* tuningMode */ |
| 0, /* reserved0 */ |
| 0, /* dbgExecParamsPrintPeriod */ |
| 0, /* dbgDmMdPrintPeriod */ |
| 0, /* dbgDmCfgPrintPeriod */ |
| 2873, /* maxPq_dupli */ |
| 263, /* minPq_dupli */ |
| 12288, /* keyWeight */ |
| 24576, /* intensityVectorWeight */ |
| 24576, /* chromaVectorWeight */ |
| 0, /* chip_fpga_lowcomplex */ |
| { |
| -245, |
| -208, |
| -171, |
| -130, |
| -93, |
| -56, |
| -19, |
| 20, |
| 57, |
| 94, |
| 131, |
| 172, |
| 209, |
| 246, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| -3685, |
| -3070, |
| -2456, |
| -1842, |
| -1228, |
| -613, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 1, /* gdEnable */ |
| 4452, /* gdWMin */ |
| 165150720, /* gdWMax */ |
| 26214400, /* gdWMm */ |
| 20114920, /* gdWDynRngSqrt */ |
| 4096, /* gdWeightMean */ |
| 4096, /* gdWeightStd */ |
| 0, /* gdDelayMilliSec_hdmi */ |
| 1, /* gdRgb2YuvExt */ |
| { |
| {5967, 20067, 2026}, |
| {-3289, -11061, 14350}, |
| {14350, -13034, -1316} |
| }, /* gdM33Rgb2Yuv[3][3] */ |
| 15, /* gdM33Rgb2YuvScale2P */ |
| 1, /* gdRgb2YuvOffExt */ |
| {2048, 16384, 16384},/* gdV3Rgb2YuvOff[3] */ |
| 2152296, /* gdUpBound */ |
| 341634, /* gdLowBound */ |
| 0, /* lastMaxPq */ |
| 114, /*gdWMinPq */ |
| 2873, /*gdWMaxPq */ |
| 2081, /*gdWMmPq */ |
| 0, /*gdTriggerPeriod */ |
| 0, /* gdTriggerLinThresh */ |
| 0, /* gdDelayMilliSec_ott */ |
| #ifdef V1_5 |
| {0, 0, 0, 0, 0, 0}, |
| #else |
| {0, 0, 0, 0, 0, 0, 0, 0, 0} |
| #endif |
| }, |
| #ifdef V1_5 |
| {36, 23, 83, 181, 139, 88, 101}, |
| {0, 0, 0, 0, 0}, |
| #endif |
| 28049, /* min_lin */ |
| 165150720, /* max_lin */ |
| 0, /* backlight_scaler */ |
| 28049, /* min_lin_dupli */ |
| 165150720, /* max_lin_dupli */ |
| { |
| /* lms2RgbMat[3][3] */ |
| { |
| {17486, -13950, 560}, |
| {-4081, 8776, -599}, |
| {257, -562, 4401} |
| }, |
| 12, /* lms2RgbMatScale */ |
| {128, 128, 128}, /* whitePoint */ |
| 7, /* whitePointScale */ |
| {0, 0, 0} /* reserved[3] */ |
| }, |
| 0, /* reserved00 */ |
| 0, /* brightnessPreservation */ |
| 81920, /* iintensityVectorWeight */ |
| 24576, /* ichromaVectorWeight */ |
| 0, /* isaturationGainBias */ |
| 0, /* chip_12b_ocsc */ |
| 0, /* chip_512_tonecurve */ |
| 0, /* chip_nolvl5 */ |
| {0, 0, 0, 0, 0, 0, 0, 0} /* padding[8] */ |
| }; |
| |
| #else |
| struct TargetDisplayConfig def_tgt_display_cfg = { |
| 2048, /* gain */ |
| 4095, /* offset */ |
| 39322, /* gamma */ |
| 0, /* eotf */ |
| 12, /* bitDepth */ |
| 0, /* rangeSpec */ |
| 42, /* diagSize */ |
| 2372, /* maxPq */ |
| 62, /* minPq */ |
| 2048, /* mSWeight */ |
| 16380, /* mSEdgeWeight */ |
| 0, /* minPQBias */ |
| 0, /* midPQBias */ |
| 0, /* maxPQBias */ |
| 0, /* trimSlopeBias */ |
| 0, /* trimOffsetBias */ |
| 0, /* trimPowerBias */ |
| 0, /* msWeightBias */ |
| 0, /* brightness */ |
| 0, /* contrast */ |
| 0, /* chromaWeightBias */ |
| 0, /* saturationGainBias */ |
| 2048, /* chromaWeight */ |
| 2048, /* saturationGain */ |
| 655, /* crossTalk */ |
| 0, /* tuningMode */ |
| 0, /* reserved0 */ |
| 0, /* dbgExecParamsPrintPeriod */ |
| 0, /* dbgDmMdPrintPeriod */ |
| 0, /* dbgDmCfgPrintPeriod */ |
| 2372, /* maxPq_dupli */ |
| 62, /* minPq_dupli */ |
| 12288, /* keyWeight */ |
| 24576, /* intensityVectorWeight */ |
| 24576, /* chromaVectorWeight */ |
| 0, /* chip_fpga_lowcomplex */ |
| { |
| -245, |
| -207, |
| -169, |
| -131, |
| -94, |
| -56, |
| -18, |
| 19, |
| 57, |
| 95, |
| 132, |
| 170, |
| 208, |
| 246, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| 0, |
| }, |
| { |
| 0, /* gdEnable */ |
| 262, /* gdWMin */ |
| 131072000, /* gdWMax */ |
| 26214400, /* gdWMm */ |
| 82897211, /* gdWDynRngSqrt */ |
| 4096, /* gdWeightMean */ |
| 4096, /* gdWeightStd */ |
| 0, /* gdDelayMilliSec_hdmi */ |
| 1, /* gdRgb2YuvExt */ |
| { |
| {5960, 20047, 2023}, |
| {-3286, -11052, 14336}, |
| {14336, -13022, -1316} |
| }, /* gdM33Rgb2Yuv[3][3] */ |
| 15, /* gdM33Rgb2YuvScale2P */ |
| 1, /* gdRgb2YuvOffExt */ |
| {2048, 16384, 16384},/* gdV3Rgb2YuvOff[3] */ |
| 414486, /* gdUpBound */ |
| 82897, /* gdLowBound */ |
| 0, /* lastMaxPq */ |
| 26, /*gdWMinPq */ |
| 2771, /*gdWMaxPq */ |
| 2081, /*gdWMmPq */ |
| 0, /*gdTriggerPeriod */ |
| 0, /* gdTriggerLinThresh */ |
| 0, /* gdDelayMilliSec_ott */ |
| #ifdef V1_5 |
| {0, 0, 0, 0, 0, 0}, |
| #else |
| {0, 0, 0, 0, 0, 0, 0, 0, 0} |
| #endif |
| }, |
| #ifdef V1_5 |
| {0, 0, 0, 0, 0, 0, 0}, |
| {0, 0, 0, 0, 0}, |
| #endif |
| 1311, /* min_lin */ |
| 200 << 18, /* max_lin 131072000 */ |
| 4096, /* backlight_scaler */ |
| 1311, /* min_lin_dupli */ |
| 200 << 18, /* max_lin_dupli 131072000 */ |
| { |
| /* lms2RgbMat[3][3] */ |
| { |
| {17507, -14019, 608}, |
| {-3765, 8450, -589}, |
| {285, -640, 4451} |
| }, |
| 12, /* lms2RgbMatScale */ |
| {128, 128, 128}, /* whitePoint */ |
| 7, /* whitePointScale */ |
| {0, 0, 0} /* reserved[3] */ |
| }, |
| 0, /* reserved00 */ |
| 0, /* brightnessPreservation */ |
| 81920, /* iintensityVectorWeight */ |
| 24576, /* ichromaVectorWeight */ |
| 0, /* isaturationGainBias */ |
| 0, /* chip_12b_ocsc */ |
| 0, /* chip_512_tonecurve */ |
| 0, /* chip_nolvl5 */ |
| {0, 0, 0, 0, 0, 0, 0, 0} /* padding[8] */ |
| }; |
| #endif |
| |
| static unsigned int debug_dolby; |
| module_param(debug_dolby, uint, 0664); |
| MODULE_PARM_DESC(debug_dolby, "\n debug_dolby\n"); |
| |
| static unsigned int debug_dolby_frame = 0xffff; |
| module_param(debug_dolby_frame, uint, 0664); |
| MODULE_PARM_DESC(debug_dolby_frame, "\n debug_dolby_frame\n"); |
| |
| #define pr_dolby_dbg(fmt, args...)\ |
| do {\ |
| if (debug_dolby)\ |
| pr_info("DOLBY: " fmt, ## args);\ |
| } while (0) |
| #define pr_dolby_error(fmt, args...)\ |
| pr_info("DOLBY ERROR: " fmt, ## args) |
| #define dump_enable \ |
| ((debug_dolby_frame >= 0xffff) || \ |
| (debug_dolby_frame + 1 == frame_count)) |
| static int is_graphics_output_off(void) |
| { |
| if (is_meson_g12()) |
| return !(READ_VPP_REG(OSD1_BLEND_SRC_CTRL) & (1<<8)); |
| else |
| return (!(READ_VPP_REG(VPP_MISC) & (1<<12))); |
| } |
| #define single_step_enable \ |
| (((debug_dolby_frame >= 0xffff) || \ |
| ((debug_dolby_frame + 1) == frame_count)) && \ |
| (debug_dolby & 0x80)) |
| |
| static bool dolby_vision_on; |
| static bool dolby_vision_core1_on; |
| static bool dolby_vision_wait_on; |
| static bool dolby_vision_wait_init; |
| static unsigned int frame_count; |
| static struct hdr10_param_s hdr10_param; |
| static struct master_display_info_s hdr10_data; |
| #define MD_BUF_SIZE 1024 |
| #define COMP_BUF_SIZE 8196 |
| static char *md_buf[2]; |
| static char *comp_buf[2]; |
| static int currentId = 1; |
| static int backup_comp_size; |
| static int backup_md_size; |
| static struct dovi_setting_s dovi_setting; |
| static struct dovi_setting_s new_dovi_setting; |
| |
| void *pq_config_fake; |
| void *tv_dovi_setting; |
| static bool pq_config_set_flag; |
| struct ui_menu_params_s menu_param = {50, 50, 50}; |
| static bool tv_dovi_setting_change_flag; |
| static bool tv_dovi_setting_update_flag; |
| static bool dovi_setting_video_flag; |
| static struct platform_device *dovi_pdev; |
| static bool vsvdb_config_set_flag; |
| |
| /* general control config change */ |
| #define FLAG_CHANGE_CFG 0x000001 |
| /* general metadata change */ |
| #define FLAG_CHANGE_MDS 0x000002 |
| /* metadata config (below level 2) change */ |
| #define FLAG_CHANGE_MDS_CFG 0x000004 |
| /* global dimming change */ |
| #define FLAG_CHANGE_GD 0x000008 |
| /* tone curve lut change */ |
| #define FLAG_CHANGE_TC 0x000010 |
| /* 2nd tone curve (graphics) lut change */ |
| #define FLAG_CHANGE_TC2 0x000020 |
| /* L2NL lut change (for DM3.1) */ |
| #define FLAG_CHANGE_L2NL 0x000040 |
| /* 3D lut change (for DM2.12) */ |
| #define FLAG_CHANGE_3DLUT 0x000080 |
| /* 0xX00000 for other status */ |
| /* (video) tone mapping to a constant */ |
| #define FLAG_CONST_TC 0x100000 |
| /* 2nd tone mapping to a constant */ |
| #define FLAG_CONST_TC2 0x200000 |
| #define FLAG_CHANGE_ALL 0xffffffff |
| /* update all core */ |
| static u32 stb_core_setting_update_flag = FLAG_CHANGE_ALL; |
| static bool stb_core2_const_flag; |
| |
| /* 256+(256*4+256*2)*4/8 64bit */ |
| #define STB_DMA_TBL_SIZE (256+(256*4+256*2)*4/8) |
| static uint64_t stb_core1_lut[STB_DMA_TBL_SIZE]; |
| |
| static bool tv_mode; |
| bool is_meson_gxm(void) |
| { |
| if (dv_meson_dev.cpu_id == _CPU_MAJOR_ID_GXM) |
| return true; |
| else |
| return false; |
| } |
| |
| bool is_meson_txlx(void) |
| { |
| if (dv_meson_dev.cpu_id == _CPU_MAJOR_ID_TXLX) |
| return true; |
| else |
| return false; |
| } |
| |
| bool is_meson_txlx_tvmode(void) |
| { |
| if ((is_meson_txlx()) && (tv_mode == 1)) |
| return true; |
| else |
| return false; |
| } |
| |
| bool is_meson_txlx_stbmode(void) |
| { |
| if ((is_meson_txlx()) && (tv_mode == 0)) |
| return true; |
| else |
| return false; |
| } |
| |
| bool is_meson_g12(void) |
| { |
| if (dv_meson_dev.cpu_id == _CPU_MAJOR_ID_G12) |
| return true; |
| else |
| return false; |
| } |
| static void dump_tv_setting( |
| struct tv_dovi_setting_s *setting, |
| int frame_cnt, int debug_flag) |
| { |
| int i; |
| uint64_t *p; |
| |
| if ((debug_flag & 0x10) && dump_enable) { |
| pr_info("\nreg\n"); |
| p = (uint64_t *)&setting->core1_reg_lut[0]; |
| for (i = 0; i < 222; i += 2) |
| pr_info("%016llx, %016llx,\n", p[i], p[i+1]); |
| } |
| if ((debug_flag & 0x20) && dump_enable) { |
| pr_info("\ng2l_lut\n"); |
| p = (uint64_t *)&setting->core1_reg_lut[0]; |
| for (i = 222; i < 222 + 256; i += 2) |
| pr_info("%016llx %016llx\n", p[i], p[i+1]); |
| } |
| if ((debug_flag & 0x40) && dump_enable) { |
| pr_info("\n3d_lut\n"); |
| p = (uint64_t *)&setting->core1_reg_lut[0]; |
| for (i = 222 + 256; i < 222 + 256 + 3276; i += 2) |
| pr_info("%016llx %016llx\n", p[i], p[i+1]); |
| pr_info("\n"); |
| } |
| } |
| |
| void dolby_vision_update_pq_config(char *pq_config_buf) |
| { |
| memcpy((struct pq_config_s *)pq_config_fake, |
| pq_config_buf, sizeof(struct pq_config_s)); |
| pr_info("update_pq_config[%zu] %x %x %x %x\n", |
| sizeof(struct pq_config_s), |
| pq_config_buf[1], |
| pq_config_buf[2], |
| pq_config_buf[3], |
| pq_config_buf[4]); |
| pq_config_set_flag = true; |
| } |
| |
| void dolby_vision_update_vsvdb_config(char *vsvdb_buf, u32 tbl_size) |
| { |
| #ifdef V2_4 |
| if (tbl_size > sizeof(new_dovi_setting.vsvdb_tbl)) { |
| pr_info( |
| "update_vsvdb_config tbl size overflow %d\n", tbl_size); |
| return; |
| } |
| memset(&new_dovi_setting.vsvdb_tbl[0], |
| 0, sizeof(new_dovi_setting.vsvdb_tbl)); |
| memcpy(&new_dovi_setting.vsvdb_tbl[0], |
| vsvdb_buf, tbl_size); |
| new_dovi_setting.vsvdb_len = tbl_size; |
| new_dovi_setting.vsvdb_changed = 1; |
| dolby_vision_set_toggle_flag(1); |
| if (tbl_size >= 8) |
| pr_info( |
| "update_vsvdb_config[%d] %x %x %x %x %x %x %x %x\n", |
| tbl_size, |
| vsvdb_buf[0], |
| vsvdb_buf[1], |
| vsvdb_buf[2], |
| vsvdb_buf[3], |
| vsvdb_buf[4], |
| vsvdb_buf[5], |
| vsvdb_buf[6], |
| vsvdb_buf[7]); |
| #endif |
| vsvdb_config_set_flag = true; |
| } |
| |
| static int prepare_stb_dolby_core1_reg( |
| uint32_t run_mode, |
| uint32_t *p_core1_dm_regs, |
| uint32_t *p_core1_comp_regs) |
| { |
| int index = 0; |
| int i; |
| |
| /* 4 */ |
| stb_core1_lut[index++] = ((uint64_t)4 << 32) | 4; |
| stb_core1_lut[index++] = ((uint64_t)4 << 32) | 4; |
| stb_core1_lut[index++] = ((uint64_t)3 << 32) | 1; |
| stb_core1_lut[index++] = ((uint64_t)2 << 32) | 1; |
| |
| /* 1 + 14 + 10 + 1 */ |
| stb_core1_lut[index++] = ((uint64_t)1 << 32) | run_mode; |
| for (i = 0; i < 14; i++) |
| stb_core1_lut[index++] = |
| ((uint64_t)(6 + i) << 32) |
| | p_core1_dm_regs[i]; |
| for (i = 17; i < 27; i++) |
| stb_core1_lut[index++] = |
| ((uint64_t)(6 + i) << 32) |
| | p_core1_dm_regs[i-3]; |
| stb_core1_lut[index++] = ((uint64_t)(6 + 27) << 32) | 0; |
| |
| /* 173 + 1 */ |
| for (i = 0; i < 173; i++) |
| stb_core1_lut[index++] = |
| ((uint64_t)(6 + 44 + i) << 32) |
| | p_core1_comp_regs[i]; |
| stb_core1_lut[index++] = ((uint64_t)3 << 32) | 1; |
| |
| if (index & 1) { |
| pr_dolby_error("stb core1 reg tbl odd size\n"); |
| stb_core1_lut[index++] = ((uint64_t)3 << 32) | 1; |
| } |
| return index; |
| } |
| |
| static void prepare_stb_dolby_core1_lut(uint32_t base, uint32_t *p_core1_lut) |
| { |
| uint32_t *p_lut; |
| int i; |
| |
| p_lut = &p_core1_lut[256*4]; /* g2l */ |
| for (i = 0; i < 128; i++) { |
| stb_core1_lut[base+i] = |
| stb_core1_lut[base+i+128] = |
| ((uint64_t)p_lut[1] << 32) | |
| ((uint64_t)p_lut[0] & 0xffffffff); |
| p_lut += 2; |
| } |
| p_lut = &p_core1_lut[0]; /* 4 lut */ |
| for (i = 256; i < 768; i++) { |
| stb_core1_lut[base+i] = |
| ((uint64_t)p_lut[1] << 32) | |
| ((uint64_t)p_lut[0] & 0xffffffff); |
| p_lut += 2; |
| } |
| } |
| |
| static bool skip_cvm_tbl[2][2][4][4] = { |
| { /* core1: video */ |
| { /* video priority */ |
| {1, 1, 0, 0}, /* dv in */ |
| {1, 1, 0, 0}, /* hdr in */ |
| {0, 0, 1, 0}, /* sdr in */ |
| {0, 0, 0, 0} /* only hdmi in */ |
| }, |
| { /* graphic priority */ |
| {0, 0, 0, 0}, /* dv in */ |
| {0, 0, 0, 0}, /* hdr in */ |
| {0, 0, 1, 0}, /* sdr in */ |
| {0, 0, 0, 0} /* only hdmi in */ |
| } |
| }, |
| { /* core2: graphic */ |
| { /* video priority */ |
| {0, 0, 0, 0}, /* dv in */ |
| {0, 0, 0, 0}, /* hdr in */ |
| {0, 0, 1, 0}, /* sdr in */ |
| {0, 0, 0, 0} /* only hdmi in */ |
| }, |
| { /* graphic priority */ |
| {0, 0, 0, 0}, /* dv in */ |
| {0, 0, 0, 0}, /* hdr in */ |
| {0, 0, 1, 0}, /* sdr in */ |
| {0, 0, 0, 0} /* only hdmi in */ |
| } |
| } |
| }; |
| |
| static bool need_skip_cvm(unsigned int is_graphic) |
| { |
| if (dolby_vision_flags & FLAG_CERTIFICAION) |
| return false; |
| if (dolby_vision_flags & FLAG_FORCE_CVM) |
| return false; |
| #ifdef V2_4 |
| return skip_cvm_tbl[is_graphic] |
| [dolby_vision_graphics_priority] |
| [new_dovi_setting.src_format == FORMAT_INVALID ? |
| FORMAT_SDR : new_dovi_setting.src_format] |
| [new_dovi_setting.dovi_ll_enable ? |
| FORMAT_DOVI_LL : new_dovi_setting.dst_format]; |
| #else |
| return skip_cvm_tbl[is_graphic] |
| [dolby_vision_graphics_priority] |
| [new_dovi_setting.src_format == FORMAT_INVALID ? |
| FORMAT_SDR : new_dovi_setting.src_format] |
| [new_dovi_setting.dst_format]; |
| #endif |
| } |
| |
| static int stb_dolby_core1_set( |
| uint32_t dm_count, |
| uint32_t comp_count, |
| uint32_t lut_count, |
| uint32_t *p_core1_dm_regs, |
| uint32_t *p_core1_comp_regs, |
| uint32_t *p_core1_lut, |
| int hsize, |
| int vsize, |
| int bl_enable, |
| int el_enable, |
| int el_41_mode, |
| int scramble_en, |
| bool dovi_src, |
| int lut_endian, |
| bool reset) |
| { |
| uint32_t bypass_flag = 0; |
| int composer_enable = el_enable; |
| uint32_t run_mode = 0; |
| int reg_size = 0; |
| bool bypass_core1 = (!hsize || !vsize |
| || !(dolby_vision_mask & 1)); |
| |
| if (dolby_vision_on |
| && (dolby_vision_flags & |
| FLAG_DISABE_CORE_SETTING)) |
| return 0; |
| |
| WRITE_VPP_REG( |
| DOLBY_TV_CLKGATE_CTRL, 0x2800); |
| if (reset) { |
| if (!dolby_vision_core1_on) { |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 1 << 9); |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 0); |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_TV_CLKGATE_CTRL, 0x2800); |
| } else |
| reset = 0; |
| } |
| |
| if (!bl_enable) |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL5, 0x446); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL0, 0); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL1, |
| ((hsize + 0x80) << 16) | (vsize + 0x40)); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL3, |
| (hwidth << 16) | vwidth); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL4, |
| (hpotch << 16) | vpotch); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL2, |
| (hsize << 16) | vsize); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL6, 0xba000000); |
| if (dolby_vision_flags & FLAG_DISABLE_COMPOSER) |
| composer_enable = 0; |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL0, |
| /* el dly 3, bl dly 1 after de*/ |
| (el_41_mode ? (0x3 << 4) : (0x1 << 8)) | |
| bl_enable << 0 | composer_enable << 1 | el_41_mode << 2); |
| |
| if (el_enable && (dolby_vision_mask & 1)) |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* vd2 to core1 */ |
| 0, 17, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* vd2 to vpp */ |
| 1, 17, 1); |
| if (dolby_vision_core1_on |
| && !bypass_core1) |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* enable core 1 */ |
| 0, 16, 1); |
| else if (dolby_vision_core1_on |
| && bypass_core1) |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* bypass core 1 */ |
| 1, 16, 1); |
| /* run mode = bypass, when fake frame */ |
| if (!bl_enable) |
| bypass_flag |= 1; |
| if (dolby_vision_flags & FLAG_BYPASS_CSC) |
| bypass_flag |= 1 << 12; /* bypass CSC */ |
| if (dolby_vision_flags & FLAG_BYPASS_CVM) |
| bypass_flag |= 1 << 13; /* bypass CVM */ |
| if (need_skip_cvm(0)) |
| bypass_flag |= 1 << 13; /* bypass CVM when tunnel out */ |
| /* bypass composer to get 12bit when SDR and HDR source */ |
| #ifndef V2_4 |
| if (!dovi_src) |
| bypass_flag |= 1 << 14; /* bypass composer */ |
| #endif |
| if (dolby_vision_run_mode != 0xff) |
| run_mode = dolby_vision_run_mode; |
| else { |
| run_mode = (0x7 << 6) | |
| ((el_41_mode ? 3 : 1) << 2) | |
| bypass_flag; |
| if (dolby_vision_on_count < dolby_vision_run_mode_delay) { |
| run_mode |= 1; |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC0, |
| (0x200 << 10) | 0x200); |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC1, |
| (0x200 << 10) | 0x200); |
| } else if (dolby_vision_on_count == |
| dolby_vision_run_mode_delay) { |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC0, |
| (0x200 << 10) | 0x200); |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC1, |
| (0x200 << 10) | 0x200); |
| } else { |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC0, |
| (0x3ff << 20) | (0x3ff << 10) | 0x3ff); |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC1, |
| 0); |
| } |
| } |
| if (reset) |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_REG_START + 1, run_mode); |
| |
| /* 962e work around to fix the uv swap issue when bl:el = 1:1 */ |
| if (el_41_mode) |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL5, 0x6); |
| else |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL5, 0xa); |
| |
| /* axi dma for reg table */ |
| reg_size = prepare_stb_dolby_core1_reg( |
| run_mode, p_core1_dm_regs, p_core1_comp_regs); |
| /* axi dma for lut table */ |
| prepare_stb_dolby_core1_lut(reg_size, p_core1_lut); |
| |
| if (!dolby_vision_on) { |
| /* dma1:11-0 tv_oo+g2l size, dma2:23-12 3d lut size */ |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL1, |
| 0x00000080 | (reg_size << 23)); |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL2, (u32)dma_paddr); |
| /* dma3:23-12 cvm size */ |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL3, |
| 0x80100000 | dma_start_line); |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x01000062); |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x80400042); |
| } |
| if (reset) { |
| /* dma1:11-0 tv_oo+g2l size, dma2:23-12 3d lut size */ |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL1, |
| 0x00000080 | (reg_size << 23)); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL2, (u32)dma_paddr); |
| /* dma3:23-12 cvm size */ |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL3, |
| 0x80100000 | dma_start_line); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x01000062); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x80400042); |
| } |
| |
| tv_dovi_setting_update_flag = true; |
| return 0; |
| } |
| |
| static uint32_t tv_run_mode(int vsize, bool hdmi, bool hdr10, int el_41_mode) |
| { |
| uint32_t run_mode = 1; |
| |
| if (hdmi) { |
| if (vsize > 1080) |
| run_mode = |
| 0x00000043; |
| else |
| run_mode = |
| 0x00000042; |
| } else { |
| if (hdr10) { |
| run_mode = |
| 0x0000004c; |
| #ifndef V1_5 |
| run_mode |= 1 << 14; /* bypass COMPOSER */ |
| #endif |
| } else { |
| if (el_41_mode) |
| run_mode = |
| 0x0000004c; |
| else |
| run_mode = |
| 0x00000044; |
| } |
| } |
| if (dolby_vision_flags & FLAG_BYPASS_CSC) |
| run_mode |= 1 << 12; /* bypass CSC */ |
| if ((dolby_vision_flags & FLAG_BYPASS_CVM) |
| && !(dolby_vision_flags & FLAG_FORCE_CVM)) |
| run_mode |= 1 << 13; /* bypass CVM */ |
| return run_mode; |
| } |
| |
| static int tv_dolby_core1_set( |
| uint64_t *dma_data, |
| int hsize, |
| int vsize, |
| int bl_enable, |
| int el_enable, |
| int el_41_mode, |
| int src_chroma_format, |
| bool hdmi, |
| bool hdr10, |
| bool reset) |
| { |
| uint64_t run_mode; |
| int composer_enable = el_enable; |
| bool bypass_core1 = (!hsize || !vsize |
| || !(dolby_vision_mask & 1)); |
| if (dolby_vision_on |
| && (dolby_vision_flags & |
| FLAG_DISABE_CORE_SETTING)) |
| return 0; |
| |
| WRITE_VPP_REG( |
| DOLBY_TV_CLKGATE_CTRL, 0x2800); |
| |
| if (reset) { |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 1 << 9); |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 0); |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_TV_CLKGATE_CTRL, 0x2800); |
| } |
| |
| if (dolby_vision_flags & FLAG_DISABLE_COMPOSER) |
| composer_enable = 0; |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL0, |
| /* el dly 3, bl dly 1 after de*/ |
| (el_41_mode ? (0x3 << 4) : (0x1 << 8)) | |
| bl_enable << 0 | composer_enable << 1 | el_41_mode << 2); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL1, |
| ((hsize + 0x80) << 16 | (vsize + 0x40))); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL3, (hwidth << 16) | vwidth); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL4, (hpotch << 16) | vpotch); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_SWAP_CTRL2, (hsize << 16) | vsize); |
| /*0x2c2d0:5-4-1-3-2-0*/ |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL5, 0x2c2d0, 14, 18); |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL5, 0xa, 0, 4); |
| |
| if ((hdmi) && (!hdr10)) |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL5, 1, 4, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL5, 0, 4, 1); |
| |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL6, 1, 20, 1); |
| /* bypass dither */ |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL6, 1, 25, 1); |
| if (src_chroma_format == 2) |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL6, 1, 29, 1); |
| else if (src_chroma_format == 1) |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL6, 0, 29, 1); |
| /* input 12 or 10 bit */ |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_TV_SWAP_CTRL7, 12, 0, 8); |
| |
| if (el_enable && (dolby_vision_mask & 1)) |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* vd2 to core1 */ |
| 0, 17, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* vd2 to vpp */ |
| 1, 17, 1); |
| |
| if (dolby_vision_core1_on |
| && !bypass_core1) |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* enable core 1 */ |
| 0, 16, 1); |
| else if (dolby_vision_core1_on |
| && bypass_core1) |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* bypass core 1 */ |
| 1, 16, 1); |
| |
| if (dolby_vision_run_mode != 0xff) |
| run_mode = dolby_vision_run_mode; |
| else { |
| run_mode = tv_run_mode(vsize, hdmi, hdr10, el_41_mode); |
| if (dolby_vision_on_count < dolby_vision_run_mode_delay) { |
| run_mode = (run_mode & 0xfffffffc) | 1; |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC0, |
| (0x200 << 10) | 0x200); |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC1, |
| (0x200 << 10) | 0x200); |
| } else if (dolby_vision_on_count == |
| dolby_vision_run_mode_delay) { |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC0, |
| (0x200 << 10) | 0x200); |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC1, |
| (0x200 << 10) | 0x200); |
| } else { |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC0, |
| (0x3ff << 20) | (0x3ff << 10) | 0x3ff); |
| _VSYNC_WR_MPEG_REG(VPP_VD1_CLIP_MISC1, |
| 0); |
| } |
| } |
| ((struct tv_dovi_setting_s *)tv_dovi_setting)->core1_reg_lut[1] = |
| 0x0000000100000000 | run_mode; |
| if (reset) |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_REG_START + 1, run_mode); |
| |
| if (!dolby_vision_on) { |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL1, 0x6f666080); |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL2, (u32)dma_paddr); |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL3, |
| 0x80000000 | dma_start_line); |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x01000042); |
| WRITE_VPP_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x80400042); |
| } |
| if (reset) { |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL1, 0x6f666080); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL2, (u32)dma_paddr); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL3, |
| 0x80000000 | dma_start_line); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x01000042); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL0, 0x80400042); |
| } |
| |
| tv_dovi_setting_update_flag = true; |
| return 0; |
| } |
| |
| int dolby_vision_update_setting(void) |
| { |
| uint64_t *dma_data; |
| uint32_t size = 0; |
| int i; |
| uint64_t *p; |
| |
| if (!p_funcs) |
| return -1; |
| if (!tv_dovi_setting_update_flag) |
| return 0; |
| if (dolby_vision_flags & |
| FLAG_DISABLE_DMA_UPDATE) { |
| tv_dovi_setting_update_flag = false; |
| setting_update_count++; |
| return -1; |
| } |
| if (dma_vaddr == NULL) |
| return -1; |
| if (efuse_mode == 1) { |
| tv_dovi_setting_update_flag = false; |
| setting_update_count++; |
| return -1; |
| } |
| if (is_meson_txlx_tvmode() && !force_stb_mode) { |
| dma_data = ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->core1_reg_lut; |
| size = 8 * TV_DMA_TBL_SIZE; |
| memcpy(dma_vaddr, dma_data, size); |
| } else if (is_meson_txlx_stbmode() || force_stb_mode) { |
| dma_data = stb_core1_lut; |
| size = 8 * STB_DMA_TBL_SIZE; |
| memcpy(dma_vaddr, dma_data, size); |
| } |
| if (size && (debug_dolby & 0x8)) { |
| p = (uint64_t *)dma_vaddr; |
| pr_info("dma size = %d\n", STB_DMA_TBL_SIZE); |
| for (i = 0; i < size / 8; i += 2) |
| pr_info("%016llx, %016llx\n", p[i], p[i+1]); |
| } |
| tv_dovi_setting_update_flag = false; |
| setting_update_count = frame_count; |
| return -1; |
| } |
| EXPORT_SYMBOL(dolby_vision_update_setting); |
| |
| static int dolby_core1_set( |
| uint32_t dm_count, |
| uint32_t comp_count, |
| uint32_t lut_count, |
| uint32_t *p_core1_dm_regs, |
| uint32_t *p_core1_comp_regs, |
| uint32_t *p_core1_lut, |
| int hsize, |
| int vsize, |
| int bl_enable, |
| int el_enable, |
| int el_41_mode, |
| int scramble_en, |
| bool dovi_src, |
| int lut_endian, |
| bool reset) |
| { |
| uint32_t count; |
| uint32_t bypass_flag = 0; |
| int composer_enable = |
| bl_enable && el_enable && (dolby_vision_mask & 1); |
| int i; |
| bool set_lut = false; |
| uint32_t *last_dm = (uint32_t *)&dovi_setting.dm_reg1; |
| uint32_t *last_comp = (uint32_t *)&dovi_setting.comp_reg; |
| bool bypass_core1 = (!hsize || !vsize |
| || !(dolby_vision_mask & 1)); |
| |
| /* G12A: make sure the BL is enable for the very 1st frame*/ |
| /* Register: dolby_path_ctrl[0] = 0 to enable BL*/ |
| /* dolby_path_ctrl[1] = 0 to enable EL*/ |
| /* dolby_path_ctrl[2] = 0 to enable OSD*/ |
| if (is_meson_g12() && frame_count == 1 |
| && dolby_vision_core1_on == 0) { |
| pr_dolby_dbg("((%s %d, register DOLBY_PATH_CTRL: %x))\n", |
| __func__, __LINE__, |
| _VSYNC_RD_MPEG_REG(DOLBY_PATH_CTRL)); |
| if ((_VSYNC_RD_MPEG_REG(DOLBY_PATH_CTRL) & 0x1) != 0) { |
| pr_dolby_dbg("BL is disable for 1st frame.Re-enable BL\n"); |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_PATH_CTRL, 0, 0, 1); |
| pr_dolby_dbg("((%s %d, enable_bl, DOLBY_PATH_CTRL: %x))\n", |
| __func__, __LINE__, |
| _VSYNC_RD_MPEG_REG(DOLBY_PATH_CTRL)); |
| } |
| if (el_enable) { |
| if ((_VSYNC_RD_MPEG_REG(DOLBY_PATH_CTRL) & 0x10) != 0) { |
| pr_dolby_dbg("((%s %d enable el))\n", |
| __func__, __LINE__); |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_PATH_CTRL, |
| 0, 1, 1); |
| pr_dolby_dbg("((%s %d, enable_el, DOLBY_PATH_CTRL: %x))\n", |
| __func__, __LINE__, |
| _VSYNC_RD_MPEG_REG(DOLBY_PATH_CTRL)); |
| } |
| } |
| } |
| |
| if (dolby_vision_on |
| && (dolby_vision_flags & |
| FLAG_DISABE_CORE_SETTING)) |
| return 0; |
| |
| if (dolby_vision_flags & FLAG_DISABLE_COMPOSER) |
| composer_enable = 0; |
| |
| if (dolby_vision_on_count |
| == dolby_vision_run_mode_delay) |
| reset = true; |
| |
| if ((!dolby_vision_on || reset) && bl_enable) { |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 1 << 9); |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 0); |
| reset = true; |
| } |
| |
| if (dolby_vision_flags & FLAG_CERTIFICAION) |
| reset = true; |
| |
| if (stb_core_setting_update_flag & FLAG_CHANGE_TC) |
| set_lut = true; |
| |
| if (bl_enable && el_enable && (dolby_vision_mask & 1)) { |
| if (is_meson_g12()) |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| /* vd2 to core1 */ |
| 0, 1, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* vd2 to core1 */ |
| 0, 17, 1); |
| } else { |
| if (is_meson_g12()) |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| /* vd2 to core1 */ |
| 1, 1, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* vd2 to vpp */ |
| 1, 17, 1); |
| } |
| |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_CLKGATE_CTRL, 0); |
| /* _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL0, 0); */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL1, |
| ((hsize + 0x80) << 16) | (vsize + 0x40)); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL3, (hwidth << 16) | vwidth); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL4, (hpotch << 16) | vpotch); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL2, (hsize << 16) | vsize); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL5, 0xa); |
| |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_DMA_CTRL, 0x0); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_REG_START + 4, 4); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_REG_START + 2, 1); |
| |
| /* bypass composer to get 12bit when SDR and HDR source */ |
| #ifndef V2_4 |
| if (!dovi_src) |
| bypass_flag |= 1 << 0; |
| #endif |
| if (dolby_vision_flags & FLAG_BYPASS_CSC) |
| bypass_flag |= 1 << 1; |
| if (dolby_vision_flags & FLAG_BYPASS_CVM) |
| bypass_flag |= 1 << 2; |
| if (need_skip_cvm(0)) |
| bypass_flag |= 1 << 2; |
| if (el_41_mode) |
| bypass_flag |= 1 << 3; |
| |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_REG_START + 1, |
| 0x70 | bypass_flag); /* bypass CVM and/or CSC */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_REG_START + 1, |
| 0x70 | bypass_flag); /* for delay */ |
| if (dm_count == 0) |
| count = 24; |
| else |
| count = dm_count; |
| for (i = 0; i < count; i++) |
| if (reset || |
| (p_core1_dm_regs[i] != |
| last_dm[i])) |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE1_REG_START + 6 + i, |
| p_core1_dm_regs[i]); |
| |
| if (comp_count == 0) |
| count = 173; |
| else |
| count = comp_count; |
| for (i = 0; i < count; i++) |
| if (reset || |
| (p_core1_comp_regs[i] != |
| last_comp[i])) |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE1_REG_START + 6 + 44 + i, |
| p_core1_comp_regs[i]); |
| |
| /* metadata program done */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_REG_START + 3, 1); |
| |
| if (lut_count == 0) |
| count = 256 * 5; |
| else |
| count = lut_count; |
| if (count && (set_lut || reset)) { |
| if (dolby_vision_flags & FLAG_CLKGATE_WHEN_LOAD_LUT) |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_CORE1_CLKGATE_CTRL, |
| 2, 2, 2); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_DMA_CTRL, 0x1401); |
| if (lut_endian) |
| for (i = 0; i < count; i += 4) { |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_DMA_PORT, |
| p_core1_lut[i+3]); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_DMA_PORT, |
| p_core1_lut[i+2]); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_DMA_PORT, |
| p_core1_lut[i+1]); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_DMA_PORT, |
| p_core1_lut[i]); |
| } |
| else |
| for (i = 0; i < count; i++) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_DMA_PORT, |
| p_core1_lut[i]); |
| if (dolby_vision_flags & FLAG_CLKGATE_WHEN_LOAD_LUT) |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_CORE1_CLKGATE_CTRL, |
| 0, 2, 2); |
| } |
| |
| if (dolby_vision_on_count |
| <= dolby_vision_run_mode_delay) { |
| _VSYNC_WR_MPEG_REG( |
| VPP_VD1_CLIP_MISC0, |
| (0x200 << 10) | 0x200); |
| _VSYNC_WR_MPEG_REG( |
| VPP_VD1_CLIP_MISC1, |
| (0x200 << 10) | 0x200); |
| if (is_meson_g12()) |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| 1, |
| 0, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 1, 16, 1); |
| } else { |
| if (dolby_vision_on_count > |
| dolby_vision_run_mode_delay) { |
| _VSYNC_WR_MPEG_REG( |
| VPP_VD1_CLIP_MISC0, |
| (0x3ff << 20) | |
| (0x3ff << 10) | |
| 0x3ff); |
| _VSYNC_WR_MPEG_REG( |
| VPP_VD1_CLIP_MISC1, |
| 0); |
| } |
| if (dolby_vision_core1_on |
| && !bypass_core1) { |
| if (is_meson_g12()) |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| 0, |
| 0, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* enable core 1 */ |
| 0, 16, 1); |
| } else if (dolby_vision_core1_on |
| && bypass_core1) { |
| if (is_meson_g12()) |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| 1, |
| 0, 1); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* bypass core 1 */ |
| 1, 16, 1); |
| } |
| } |
| |
| if (is_meson_g12()) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL0, |
| (el_41_mode ? (0x3 << 4) : (0x0 << 4)) | |
| bl_enable | composer_enable << 1 | el_41_mode << 2); |
| else |
| /* enable core1 */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE1_SWAP_CTRL0, |
| bl_enable << 0 | |
| composer_enable << 1 | |
| el_41_mode << 2); |
| |
| tv_dovi_setting_update_flag = true; |
| return 0; |
| } |
| |
| static int dolby_core2_set( |
| uint32_t dm_count, |
| uint32_t lut_count, |
| uint32_t *p_core2_dm_regs, |
| uint32_t *p_core2_lut, |
| int hsize, |
| int vsize, |
| int dolby_enable, |
| int lut_endian) |
| { |
| uint32_t count; |
| int i; |
| bool set_lut = false; |
| bool reset = false; |
| uint32_t *last_dm = (uint32_t *)&dovi_setting.dm_reg2; |
| uint32_t bypass_flag = 0; |
| |
| if (dolby_vision_on |
| && (dolby_vision_flags & |
| FLAG_DISABE_CORE_SETTING)) |
| return 0; |
| |
| if (!dolby_vision_on || force_reset_core2) { |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, (1 << 10)); |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 0); |
| force_reset_core2 = false; |
| reset = true; |
| } |
| |
| if (dolby_vision_flags & FLAG_CERTIFICAION) |
| reset = true; |
| |
| if (stb_core_setting_update_flag & FLAG_CHANGE_TC2) |
| set_lut = true; |
| |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_CLKGATE_CTRL, 0); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL0, 0); |
| if (is_meson_gxm() || is_meson_g12() || reset) { |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL1, |
| ((hsize + g_htotal_add) << 16) |
| | (vsize + g_vtotal_add + g_vsize_add)); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL2, |
| (hsize << 16) | (vsize + g_vsize_add)); |
| } |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL3, |
| (g_hwidth << 16) | g_vwidth); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL4, |
| (g_hpotch << 16) | g_vpotch); |
| if (is_meson_txlx_stbmode() || force_stb_mode) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL5, 0xf8000000); |
| else if (is_meson_g12()) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL5, 0xa8000000); |
| else |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL5, 0x0); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_DMA_CTRL, 0x0); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_REG_START + 2, 1); |
| if (need_skip_cvm(1)) |
| bypass_flag |= 1 << 0; |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_REG_START + 2, 1); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_REG_START + 1, |
| 2 | bypass_flag); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_REG_START + 1, |
| 2 | bypass_flag); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_CTRL, 0); |
| |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_CTRL, 0); |
| |
| if (dm_count == 0) |
| count = 24; |
| else |
| count = dm_count; |
| for (i = 0; i < count; i++) |
| if (reset || |
| (p_core2_dm_regs[i] != |
| last_dm[i])) { |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE2A_REG_START + 6 + i, |
| p_core2_dm_regs[i]); |
| set_lut = true; |
| } |
| |
| if (stb_core_setting_update_flag & FLAG_CONST_TC2) |
| set_lut = false; |
| |
| /* core2 metadata program done */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_REG_START + 3, 1); |
| |
| if (lut_count == 0) |
| count = 256 * 5; |
| else |
| count = lut_count; |
| if (count && (set_lut || reset)) { |
| if (dolby_vision_flags & FLAG_CLKGATE_WHEN_LOAD_LUT) |
| _VSYNC_WR_MPEG_REG_BITS(DOLBY_CORE2A_CLKGATE_CTRL, |
| 2, 2, 2); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_DMA_CTRL, 0x1401); |
| if (lut_endian) |
| for (i = 0; i < count; i += 4) { |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_DMA_PORT, |
| p_core2_lut[i+3]); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_DMA_PORT, |
| p_core2_lut[i+2]); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_DMA_PORT, |
| p_core2_lut[i+1]); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_DMA_PORT, |
| p_core2_lut[i]); |
| } |
| else |
| for (i = 0; i < count; i++) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_DMA_PORT, |
| p_core2_lut[i]); |
| /* core2 lookup table program done */ |
| if (dolby_vision_flags & FLAG_CLKGATE_WHEN_LOAD_LUT) |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_CORE2A_CLKGATE_CTRL, 0, 2, 2); |
| } |
| |
| /* enable core2 */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL0, dolby_enable << 0); |
| return 0; |
| } |
| |
| static int dolby_core3_set( |
| uint32_t dm_count, |
| uint32_t md_count, |
| uint32_t *p_core3_dm_regs, |
| uint32_t *p_core3_md_regs, |
| int hsize, |
| int vsize, |
| int dolby_enable, |
| int scramble_en, |
| u8 pps_state) |
| { |
| uint32_t count; |
| int i; |
| int vsize_hold = 0x10; |
| uint32_t diag_mode = 0; |
| uint32_t cur_dv_mode = dolby_vision_mode; |
| uint32_t *last_dm = (uint32_t *)&dovi_setting.dm_reg3; |
| bool reset = false; |
| #ifdef V2_4 |
| u32 diag_enable = 0; |
| bool reset_post_table = false; |
| |
| if (new_dovi_setting.diagnostic_enable |
| || new_dovi_setting.dovi_ll_enable) |
| diag_enable = 1; |
| #endif |
| if (dolby_vision_on |
| && (dolby_vision_flags & |
| FLAG_DISABE_CORE_SETTING)) |
| return 0; |
| |
| if (!dolby_vision_on || |
| (dolby_vision_flags & FLAG_CERTIFICAION)) |
| reset = true; |
| #ifdef V2_4 |
| if (((cur_dv_mode == DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) |
| || (cur_dv_mode == DOLBY_VISION_OUTPUT_MODE_IPT)) |
| && diag_enable) { |
| cur_dv_mode = dv_ll_output_mode & 0xff; |
| |
| if (is_meson_g12()) { |
| if (dolby_vision_ll_policy == DOLBY_VISION_LL_YUV422) |
| diag_mode = 0x20; |
| else |
| diag_mode = 3; |
| } else |
| diag_mode = 3; |
| } |
| if (dolby_vision_on && |
| ((last_dolby_vision_ll_policy != |
| dolby_vision_ll_policy) || |
| new_dovi_setting.mode_changed || |
| new_dovi_setting.vsvdb_changed || |
| pps_state)) { |
| last_dolby_vision_ll_policy = |
| dolby_vision_ll_policy; |
| new_dovi_setting.vsvdb_changed = 0; |
| new_dovi_setting.mode_changed = 0; |
| /* TODO: verify 962e case */ |
| if (is_meson_gxm() || |
| is_meson_g12()) { |
| if (new_dovi_setting.dovi_ll_enable && |
| new_dovi_setting.diagnostic_enable == 0) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, |
| 3, 6, 2); /* post matrix */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_MATRIX_CTRL, |
| 1, 0, 1); /* post matrix */ |
| } else { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, |
| 0, 6, 2); /* post matrix */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_MATRIX_CTRL, |
| 0, 0, 1); /* post matrix */ |
| } |
| } else if (is_meson_txlx_stbmode() |
| || force_stb_mode) { |
| if (pps_state == 2) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, |
| 1, 0, 1); /* skip pps/dither/cm */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x08000800); |
| } else if (pps_state == 1) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, |
| 0, 0, 1); /* enable pps/dither/cm */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x20002000); |
| } |
| if (new_dovi_setting.dovi_ll_enable && |
| new_dovi_setting.diagnostic_enable == 0) { |
| /*bypass gainoff to vks */ |
| /*enable wn tp vks*/ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 0, 2, 1); |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 1, 1, 1); |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x8000800); |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_MATRIX_CTRL, |
| 1, 0, 1); /* post matrix */ |
| } else { |
| /* bypass wm tp vks*/ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 1, 2, 1); |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 0, 1, 1); |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x20002000); |
| if (is_meson_txlx_tvmode()) |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 0, NULL, 12); |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_MATRIX_CTRL, |
| 0, 0, 1); |
| } |
| } |
| reset_post_table = true; |
| } |
| /* flush post matrix table when ll mode on and setting changed */ |
| if (new_dovi_setting.dovi_ll_enable && |
| (new_dovi_setting.diagnostic_enable == 0) && |
| dolby_vision_on && |
| (reset_post_table || reset || |
| memcmp(&p_core3_dm_regs[18], |
| &last_dm[18], 32))) |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 1, &p_core3_dm_regs[18], 12); |
| #endif |
| |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_CLKGATE_CTRL, 0); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL1, |
| ((hsize + htotal_add) << 16) |
| | (vsize + vtotal_add + vsize_add + vsize_hold * 2)); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL2, |
| (hsize << 16) | (vsize + vsize_add)); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL3, |
| (0x80 << 16) | vsize_hold); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL4, |
| (0x04 << 16) | vsize_hold); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL5, 0x0000); |
| if (cur_dv_mode != |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL6, 0); |
| else |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL6, |
| 0x10000000); /* swap UV */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 5, 7); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 4, 4); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 4, 2); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 2, 1); |
| /* Control Register, address 0x04 2:0 RW */ |
| /* Output_operating mode*/ |
| /* 00- IPT 12 bit 444 bypass Dolby Vision output*/ |
| /* 01- IPT 12 bit tunnelled over RGB 8 bit 444, dolby vision output*/ |
| /* 02- HDR10 output, RGB 10 bit 444 PQ*/ |
| /* 03- Deep color SDR, RGB 10 bit 444 Gamma*/ |
| /* 04- SDR, RGB 8 bit 444 Gamma*/ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 1, cur_dv_mode); |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 1, cur_dv_mode); |
| /* for delay */ |
| |
| if (dm_count == 0) |
| count = 26; |
| else |
| count = dm_count; |
| for (i = 0; i < count; i++) |
| if (reset || (p_core3_dm_regs[i] != |
| last_dm[i])) |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE3_REG_START + 0x6 + i, |
| p_core3_dm_regs[i]); |
| /* from addr 0x18 */ |
| |
| count = md_count; |
| for (i = 0; i < count; i++) { |
| #ifdef FORCE_HDMI_META |
| if ((i == 20) && (p_core3_md_regs[i] == 0x5140a3e)) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 0x24 + i, |
| (p_core3_md_regs[i] & 0xffffff00) | 0x80); |
| else |
| #endif |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 0x24 + i, |
| p_core3_md_regs[i]); |
| } |
| for (; i < 30; i++) |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 0x24 + i, 0); |
| |
| /* from addr 0x90 */ |
| /* core3 metadata program done */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_REG_START + 3, 1); |
| |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE3_DIAG_CTRL, |
| diag_mode); |
| |
| if ((dolby_vision_flags & FLAG_CERTIFICAION) |
| && !(dolby_vision_flags & FLAG_DISABLE_CRC)) |
| _VSYNC_WR_MPEG_REG(0x36fb, 1); |
| /* enable core3 */ |
| _VSYNC_WR_MPEG_REG(DOLBY_CORE3_SWAP_CTRL0, (dolby_enable << 0)); |
| return 0; |
| } |
| |
| void update_graphic_width_height(unsigned int width, |
| unsigned int height) |
| { |
| osd_graphic_width = width; |
| osd_graphic_height = height; |
| } |
| |
| static void apply_stb_core_settings( |
| int enable, unsigned int mask, |
| bool reset, u32 frame_size, u8 pps_state) |
| { |
| const struct vinfo_s *vinfo = get_current_vinfo(); |
| u32 h_size = (frame_size >> 16) & 0xffff; |
| u32 v_size = frame_size & 0xffff; |
| #ifdef V2_4 |
| u32 core1_dm_count = 27; |
| #else |
| u32 core1_dm_count = 24; |
| #endif |
| u32 graphics_w = osd_graphic_width; |
| u32 graphics_h = osd_graphic_height; |
| |
| if (is_dolby_vision_stb_mode() |
| && (dolby_vision_flags & FLAG_CERTIFICAION)) { |
| graphics_w = dv_cert_graphic_width; |
| graphics_h = dv_cert_graphic_height; |
| } |
| if (is_meson_txlx_stbmode() |
| || force_stb_mode) { |
| if ((vinfo->width >= 1920) && |
| (vinfo->height >= 1080) && |
| (vinfo->field_height >= 1080)) |
| dma_start_line = 0x400; |
| else |
| dma_start_line = 0x180; |
| /* adjust core2 setting to work around*/ |
| /* fixing with 1080p24hz and 480p60hz */ |
| if ((vinfo->width < 1280) && |
| (vinfo->height < 720) && |
| (vinfo->field_height < 720)) |
| g_vpotch = 0x60; |
| else |
| g_vpotch = 0x20; |
| } |
| if (mask & 1) { |
| if (is_meson_txlx_stbmode() |
| || force_stb_mode) { |
| stb_dolby_core1_set( |
| 27, 173, 256 * 5, |
| (uint32_t *)&new_dovi_setting.dm_reg1, |
| (uint32_t *)&new_dovi_setting.comp_reg, |
| (uint32_t *)&new_dovi_setting.dm_lut1, |
| h_size, |
| v_size, |
| /* BL enable */ |
| enable, |
| /* EL enable */ |
| enable && new_dovi_setting.el_flag, |
| new_dovi_setting.el_halfsize_flag, |
| dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL, |
| new_dovi_setting.src_format == FORMAT_DOVI, |
| 1, |
| reset); |
| } else |
| dolby_core1_set( |
| core1_dm_count, 173, 256 * 5, |
| (uint32_t *)&new_dovi_setting.dm_reg1, |
| (uint32_t *)&new_dovi_setting.comp_reg, |
| (uint32_t *)&new_dovi_setting.dm_lut1, |
| h_size, |
| v_size, |
| /* BL enable */ |
| enable, |
| /* EL enable */ |
| enable && new_dovi_setting.el_flag, |
| new_dovi_setting.el_halfsize_flag, |
| dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL, |
| new_dovi_setting.src_format == FORMAT_DOVI, |
| 1, |
| reset); |
| } |
| |
| if (stb_core_setting_update_flag != FLAG_CHANGE_ALL) { |
| /* when FLAG_CONST_TC2 is set, */ |
| /* set the stb_core_setting_update_flag */ |
| /* until only meeting the FLAG_CHANGE_TC2 */ |
| if (stb_core_setting_update_flag & FLAG_CONST_TC2) |
| stb_core2_const_flag = true; |
| else if (stb_core_setting_update_flag & FLAG_CHANGE_TC2) |
| stb_core2_const_flag = false; |
| } |
| |
| /* revert the core2 lut as last corret one when const case */ |
| if (stb_core2_const_flag) |
| memcpy(&new_dovi_setting.dm_lut2, |
| &dovi_setting.dm_lut2, |
| sizeof(struct dm_lut_ipcore_s)); |
| |
| if (mask & 2) |
| dolby_core2_set( |
| 24, 256 * 5, |
| (uint32_t *)&new_dovi_setting.dm_reg2, |
| (uint32_t *)&new_dovi_setting.dm_lut2, |
| graphics_h, graphics_w, 1, 1); |
| v_size = vinfo->height; |
| if (((vinfo->width == 720) && |
| (vinfo->height == 480) && |
| (vinfo->height != vinfo->field_height)) || |
| ((vinfo->width == 720) && |
| (vinfo->height == 576) && |
| (vinfo->height != vinfo->field_height)) || |
| ((vinfo->width == 1920) && |
| (vinfo->height == 1080) && |
| (vinfo->height != vinfo->field_height)) || |
| ((vinfo->width == 1920) && |
| (vinfo->height == 1080) && |
| (vinfo->height != vinfo->field_height) && |
| (vinfo->sync_duration_num / vinfo->sync_duration_den == 50))) |
| v_size = v_size/2; |
| if (mask & 4) |
| dolby_core3_set( |
| 26, new_dovi_setting.md_reg3.size, |
| (uint32_t *)&new_dovi_setting.dm_reg3, |
| new_dovi_setting.md_reg3.raw_metadata, |
| vinfo->width, v_size, |
| 1, |
| dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL, |
| pps_state); |
| } |
| |
| static void osd_bypass(int bypass) |
| { |
| static uint32_t osd_backup_ctrl; |
| static uint32_t osd_backup_eotf; |
| static uint32_t osd_backup_mtx; |
| |
| if (bypass) { |
| osd_backup_ctrl = _VSYNC_RD_MPEG_REG(VIU_OSD1_CTRL_STAT); |
| osd_backup_eotf = _VSYNC_RD_MPEG_REG(VIU_OSD1_EOTF_CTL); |
| osd_backup_mtx = _VSYNC_RD_MPEG_REG(VPP_MATRIX_CTRL); |
| _VSYNC_WR_MPEG_REG_BITS(VIU_OSD1_EOTF_CTL, 0, 31, 1); |
| _VSYNC_WR_MPEG_REG_BITS(VIU_OSD1_CTRL_STAT, 0, 3, 1); |
| _VSYNC_WR_MPEG_REG_BITS(VPP_MATRIX_CTRL, 0, 7, 1); |
| } else { |
| _VSYNC_WR_MPEG_REG(VPP_MATRIX_CTRL, osd_backup_mtx); |
| _VSYNC_WR_MPEG_REG(VIU_OSD1_CTRL_STAT, osd_backup_ctrl); |
| _VSYNC_WR_MPEG_REG(VIU_OSD1_EOTF_CTL, osd_backup_eotf); |
| } |
| } |
| |
| static uint32_t viu_eotf_ctrl_backup; |
| static uint32_t xvycc_lut_ctrl_backup; |
| static uint32_t inv_lut_ctrl_backup; |
| static uint32_t vpp_vadj_backup; |
| static uint32_t vpp_gainoff_backup; |
| static uint32_t vpp_ve_enable_ctrl_backup; |
| static uint32_t xvycc_vd1_rgb_ctrst_backup; |
| static bool is_video_effect_bypass; |
| |
| static void video_effect_bypass(int bypass) |
| { |
| if (bypass) { |
| if (!is_video_effect_bypass) { |
| viu_eotf_ctrl_backup = |
| _VSYNC_RD_MPEG_REG(VIU_EOTF_CTL); |
| xvycc_lut_ctrl_backup = |
| _VSYNC_RD_MPEG_REG(XVYCC_LUT_CTL); |
| inv_lut_ctrl_backup = |
| _VSYNC_RD_MPEG_REG(XVYCC_INV_LUT_CTL); |
| vpp_vadj_backup = |
| _VSYNC_RD_MPEG_REG(VPP_VADJ_CTRL); |
| vpp_gainoff_backup = |
| _VSYNC_RD_MPEG_REG(VPP_GAINOFF_CTRL0); |
| vpp_ve_enable_ctrl_backup = |
| _VSYNC_RD_MPEG_REG(VPP_VE_ENABLE_CTRL); |
| xvycc_vd1_rgb_ctrst_backup = |
| _VSYNC_RD_MPEG_REG(XVYCC_VD1_RGB_CTRST); |
| is_video_effect_bypass = true; |
| } |
| _VSYNC_WR_MPEG_REG(VIU_EOTF_CTL, 0); |
| _VSYNC_WR_MPEG_REG(XVYCC_LUT_CTL, 0); |
| _VSYNC_WR_MPEG_REG(XVYCC_INV_LUT_CTL, 0); |
| _VSYNC_WR_MPEG_REG(VPP_VADJ_CTRL, 0); |
| _VSYNC_WR_MPEG_REG(VPP_GAINOFF_CTRL0, 0); |
| _VSYNC_WR_MPEG_REG(VPP_VE_ENABLE_CTRL, 0); |
| _VSYNC_WR_MPEG_REG(XVYCC_VD1_RGB_CTRST, 0); |
| } else if (is_video_effect_bypass) { |
| _VSYNC_WR_MPEG_REG(VIU_EOTF_CTL, |
| viu_eotf_ctrl_backup); |
| _VSYNC_WR_MPEG_REG(XVYCC_LUT_CTL, |
| xvycc_lut_ctrl_backup); |
| _VSYNC_WR_MPEG_REG(XVYCC_INV_LUT_CTL, |
| inv_lut_ctrl_backup); |
| _VSYNC_WR_MPEG_REG(VPP_VADJ_CTRL, |
| vpp_vadj_backup); |
| _VSYNC_WR_MPEG_REG(VPP_GAINOFF_CTRL0, |
| vpp_gainoff_backup); |
| _VSYNC_WR_MPEG_REG(VPP_VE_ENABLE_CTRL, |
| vpp_ve_enable_ctrl_backup); |
| _VSYNC_WR_MPEG_REG(XVYCC_VD1_RGB_CTRST, |
| xvycc_vd1_rgb_ctrst_backup); |
| } |
| } |
| |
| static void osd_path_enable(int on) |
| { |
| u32 i = 0; |
| u32 addr_port; |
| u32 data_port; |
| struct hdr_osd_lut_s *lut = &hdr_osd_reg.lut_val; |
| |
| if (!on) { |
| enable_osd_path(0, 0); |
| _VSYNC_WR_MPEG_REG(VIU_OSD1_EOTF_CTL, 0); |
| _VSYNC_WR_MPEG_REG(VIU_OSD1_OETF_CTL, 0); |
| } else { |
| enable_osd_path(1, -1); |
| if ((hdr_osd_reg.viu_osd1_eotf_ctl & 0x80000000) != 0) { |
| addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT; |
| data_port = VIU_OSD1_EOTF_LUT_DATA_PORT; |
| _VSYNC_WR_MPEG_REG( |
| addr_port, 0); |
| for (i = 0; i < 16; i++) |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->r_map[i * 2] |
| | (lut->r_map[i * 2 + 1] << 16)); |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->r_map[EOTF_LUT_SIZE - 1] |
| | (lut->g_map[0] << 16)); |
| for (i = 0; i < 16; i++) |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->g_map[i * 2 + 1] |
| | (lut->b_map[i * 2 + 2] << 16)); |
| for (i = 0; i < 16; i++) |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->b_map[i * 2] |
| | (lut->b_map[i * 2 + 1] << 16)); |
| _VSYNC_WR_MPEG_REG( |
| data_port, lut->b_map[EOTF_LUT_SIZE - 1]); |
| |
| /* load eotf matrix */ |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_EOTF_COEF00_01, |
| hdr_osd_reg.viu_osd1_eotf_coef00_01); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_EOTF_COEF02_10, |
| hdr_osd_reg.viu_osd1_eotf_coef02_10); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_EOTF_COEF11_12, |
| hdr_osd_reg.viu_osd1_eotf_coef11_12); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_EOTF_COEF20_21, |
| hdr_osd_reg.viu_osd1_eotf_coef20_21); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_EOTF_COEF22_RS, |
| hdr_osd_reg.viu_osd1_eotf_coef22_rs); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_EOTF_CTL, |
| hdr_osd_reg.viu_osd1_eotf_ctl); |
| } |
| /* restore oetf lut */ |
| if ((hdr_osd_reg.viu_osd1_oetf_ctl & 0xe0000000) != 0) { |
| addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT; |
| data_port = VIU_OSD1_OETF_LUT_DATA_PORT; |
| for (i = 0; i < 20; i++) { |
| _VSYNC_WR_MPEG_REG( |
| addr_port, i); |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->or_map[i * 2] |
| | (lut->or_map[i * 2 + 1] << 16)); |
| } |
| _VSYNC_WR_MPEG_REG( |
| addr_port, 20); |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->or_map[41 - 1] |
| | (lut->og_map[0] << 16)); |
| for (i = 0; i < 20; i++) { |
| _VSYNC_WR_MPEG_REG( |
| addr_port, 21 + i); |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->og_map[i * 2 + 1] |
| | (lut->og_map[i * 2 + 2] << 16)); |
| } |
| for (i = 0; i < 20; i++) { |
| _VSYNC_WR_MPEG_REG( |
| addr_port, 41 + i); |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->ob_map[i * 2] |
| | (lut->ob_map[i * 2 + 1] << 16)); |
| } |
| _VSYNC_WR_MPEG_REG( |
| addr_port, 61); |
| _VSYNC_WR_MPEG_REG( |
| data_port, |
| lut->ob_map[41 - 1]); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_OETF_CTL, |
| hdr_osd_reg.viu_osd1_oetf_ctl); |
| } |
| } |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_PRE_OFFSET0_1, |
| hdr_osd_reg.viu_osd1_matrix_pre_offset0_1); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_PRE_OFFSET2, |
| hdr_osd_reg.viu_osd1_matrix_pre_offset2); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COEF00_01, |
| hdr_osd_reg.viu_osd1_matrix_coef00_01); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COEF02_10, |
| hdr_osd_reg.viu_osd1_matrix_coef02_10); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COEF11_12, |
| hdr_osd_reg.viu_osd1_matrix_coef11_12); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COEF20_21, |
| hdr_osd_reg.viu_osd1_matrix_coef20_21); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COEF22_30, |
| hdr_osd_reg.viu_osd1_matrix_coef22_30); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COEF31_32, |
| hdr_osd_reg.viu_osd1_matrix_coef31_32); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COEF40_41, |
| hdr_osd_reg.viu_osd1_matrix_coef40_41); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_COLMOD_COEF42, |
| hdr_osd_reg.viu_osd1_matrix_colmod_coef42); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_OFFSET0_1, |
| hdr_osd_reg.viu_osd1_matrix_offset0_1); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_OFFSET2, |
| hdr_osd_reg.viu_osd1_matrix_offset2); |
| _VSYNC_WR_MPEG_REG( |
| VIU_OSD1_MATRIX_CTRL, |
| hdr_osd_reg.viu_osd1_matrix_ctrl); |
| } |
| |
| static uint32_t dolby_ctrl_backup; |
| static uint32_t viu_misc_ctrl_backup; |
| static uint32_t vpp_matrix_backup; |
| static uint32_t vpp_dummy1_backup; |
| static uint32_t vpp_data_conv_para0_backup; |
| static uint32_t vpp_data_conv_para1_backup; |
| void enable_dolby_vision(int enable) |
| { |
| uint32_t size = 0; |
| uint64_t *dma_data = ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->core1_reg_lut; |
| |
| if (enable) { |
| if (!dolby_vision_on) { |
| dolby_ctrl_backup = |
| _VSYNC_RD_MPEG_REG(VPP_DOLBY_CTRL); |
| viu_misc_ctrl_backup = |
| _VSYNC_RD_MPEG_REG(VIU_MISC_CTRL1); |
| vpp_matrix_backup = |
| _VSYNC_RD_MPEG_REG(VPP_MATRIX_CTRL); |
| vpp_dummy1_backup = |
| _VSYNC_RD_MPEG_REG(VPP_DUMMY_DATA1); |
| if (is_meson_txlx()) { |
| vpp_data_conv_para0_backup = |
| _VSYNC_RD_MPEG_REG(VPP_DAT_CONV_PARA0); |
| vpp_data_conv_para1_backup = |
| _VSYNC_RD_MPEG_REG(VPP_DAT_CONV_PARA1); |
| setting_update_count = 0; |
| } |
| if (is_meson_txlx_tvmode() && !force_stb_mode) { |
| if (efuse_mode == 1) { |
| size = 8 * TV_DMA_TBL_SIZE; |
| memset(dma_vaddr, 0x0, size); |
| memcpy((uint64_t *)dma_vaddr + 1, |
| dma_data + 1, |
| 8); |
| } |
| if ((dolby_vision_mask & 1) |
| && dovi_setting_video_flag) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 0, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = true; |
| } else { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 1, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = false; |
| } |
| if (dolby_vision_flags & FLAG_CERTIFICAION) { |
| /* bypass dither/PPS/SR/CM, EO/OE */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 3, 0, 2); |
| /* bypass all video effect */ |
| video_effect_bypass(1); |
| /* 12 bit unsigned to sign*/ |
| /* before vadj1 */ |
| /* 12 bit sign to unsign*/ |
| /* before post blend */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x08000800); |
| /* 12->10 before vadj2*/ |
| /* 10->12 after gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x20002000); |
| WRITE_VPP_REG(0x33e7, 0xb); |
| } else { |
| /* bypass all video effect */ |
| if (dolby_vision_flags |
| & FLAG_BYPASS_VPP) |
| video_effect_bypass(1); |
| /* 12->10 before vadj1*/ |
| /* 10->12 before post blend */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x20002000); |
| /* 12->10 before vadj2*/ |
| /* 10->12 after gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x20002000); |
| } |
| _VSYNC_WR_MPEG_REG( |
| VPP_DUMMY_DATA1, |
| 0x80200); |
| /* osd rgb to yuv, vpp out yuv to rgb */ |
| _VSYNC_WR_MPEG_REG(VPP_MATRIX_CTRL, 0x81); |
| pr_dolby_dbg("Dolby Vision TV core turn on\n"); |
| } else if (is_meson_txlx_stbmode() |
| || force_stb_mode) { |
| size = 8 * STB_DMA_TBL_SIZE; |
| if (efuse_mode == 1) |
| memset(dma_vaddr, 0x0, size); |
| osd_bypass(1); |
| if (dolby_vision_mask & 4) |
| _VSYNC_WR_MPEG_REG_BITS(VPP_DOLBY_CTRL, |
| 1, 3, 1); /* core3 enable */ |
| if ((dolby_vision_mask & 1) |
| && dovi_setting_video_flag) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 0, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = true; |
| } else { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 1, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = false; |
| } |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| (((dolby_vision_mask & 1) |
| && dovi_setting_video_flag) |
| ? 0 : 1), |
| 16, 1); /* core1 */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| ((dolby_vision_mask & 2) ? 0 : 1), |
| 18, 1); /* core2 */ |
| if (dolby_vision_flags & FLAG_CERTIFICAION) { |
| /* bypass dither/PPS/SR/CM*/ |
| /* bypass EO/OE*/ |
| /* bypass vadj2/mtx/gainoff */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 7, 0, 3); |
| /* bypass all video effect */ |
| video_effect_bypass(1); |
| /* 12 bit unsigned to sign*/ |
| /* before vadj1 */ |
| /* 12 bit sign to unsign*/ |
| /* before post blend */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x08000800); |
| /* 12->10 before vadj2*/ |
| /* 10->12 after gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x20002000); |
| } else { |
| /* bypass all video effect */ |
| if (dolby_vision_flags |
| & FLAG_BYPASS_VPP) |
| video_effect_bypass(1); |
| /* 12->10 before vadj1*/ |
| /* 10->12 before post blend */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x20002000); |
| /* 12->10 before vadj2*/ |
| /* 10->12 after gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x20002000); |
| } |
| _VSYNC_WR_MPEG_REG(VPP_DUMMY_DATA1, |
| 0x80200); |
| if (is_meson_txlx_tvmode()) |
| _VSYNC_WR_MPEG_REG(VPP_MATRIX_CTRL, 1); |
| else |
| _VSYNC_WR_MPEG_REG(VPP_MATRIX_CTRL, 0); |
| #ifdef V2_4 |
| if (((dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) |
| || (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT)) && |
| (dovi_setting.diagnostic_enable == 0) && |
| dovi_setting.dovi_ll_enable) { |
| u32 *reg = |
| (u32 *)&dovi_setting.dm_reg3; |
| /* input u12 -0x800 to s12 */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x8000800); |
| /* bypass vadj */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_VADJ_CTRL, 0); |
| /* bypass gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_GAINOFF_CTRL0, 0); |
| /* enable wm tp vks*/ |
| /* bypass gainoff to vks */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 1, 1, 2); |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 1, ®[18], 12); |
| } else |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 0, NULL, 12); |
| last_dolby_vision_ll_policy = |
| dolby_vision_ll_policy; |
| #endif |
| pr_dolby_dbg("Dolby Vision STB cores turn on\n"); |
| } else if (is_meson_g12()) { |
| if (dolby_vision_mask & 4) |
| _VSYNC_WR_MPEG_REG_BITS(VPP_DOLBY_CTRL, |
| 1, 3, 1); /* core3 enable */ |
| else |
| _VSYNC_WR_MPEG_REG_BITS(VPP_DOLBY_CTRL, |
| 0, 3, 1); /* bypass core3 */ |
| _VSYNC_WR_MPEG_REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL, |
| 0x0); |
| _VSYNC_WR_MPEG_REG(VPP_WRAP_OSD2_MATRIX_EN_CTRL, |
| 0x0); |
| _VSYNC_WR_MPEG_REG(VPP_WRAP_OSD3_MATRIX_EN_CTRL, |
| 0x0); |
| if (dolby_vision_mask & 2) |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| 0, |
| 2, 1);/*core2 enable*/ |
| else |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| 1, |
| 2, 1);/*core2 bypass*/ |
| if ((dolby_vision_mask & 1) |
| && dovi_setting_video_flag) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| 0, |
| 0, 1); /* core1 */ |
| dolby_vision_core1_on = true; |
| } else { |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| 1, |
| 0, 1); /* core1 */ |
| dolby_vision_core1_on = false; |
| } |
| if (dolby_vision_flags & FLAG_CERTIFICAION) { |
| /* bypass dither/PPS/SR/CM*/ |
| /* bypass EO/OE*/ |
| /* bypass vadj2/mtx/gainoff */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 7, 0, 3); |
| /* bypass all video effect */ |
| video_effect_bypass(1); |
| /* 12 bit unsigned to sign*/ |
| /* before vadj1 */ |
| /* 12 bit sign to unsign*/ |
| /* before post blend */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x08000800); |
| /* 12->10 before vadj2*/ |
| /* 10->12 after gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x20002000); |
| } else { |
| /* bypass all video effect */ |
| if (dolby_vision_flags |
| & FLAG_BYPASS_VPP) |
| video_effect_bypass(1); |
| /* 12->10 before vadj1*/ |
| /* 10->12 before post blend */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x20002000); |
| /* 12->10 before vadj2*/ |
| /* 10->12 after gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x20002000); |
| } |
| _VSYNC_WR_MPEG_REG(VPP_MATRIX_CTRL, 0); |
| _VSYNC_WR_MPEG_REG(VPP_DUMMY_DATA1, |
| 0x80200); |
| #ifdef V2_4 |
| if (((dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) |
| || (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT)) && |
| (dovi_setting.diagnostic_enable == 0) && |
| dovi_setting.dovi_ll_enable) { |
| u32 *reg = |
| (u32 *)&dovi_setting.dm_reg3; |
| /* input u12 -0x800 to s12 */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA1, 0x8000800); |
| /* bypass vadj */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_VADJ_CTRL, 0); |
| /* bypass gainoff */ |
| _VSYNC_WR_MPEG_REG( |
| VPP_GAINOFF_CTRL0, 0); |
| /* enable wm tp vks*/ |
| /* bypass gainoff to vks */ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 1, 1, 2); |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 1, ®[18], |
| (dv_ll_output_mode >> 8) |
| & 0xff); |
| } else |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 0, NULL, 12); |
| last_dolby_vision_ll_policy = |
| dolby_vision_ll_policy; |
| #endif |
| pr_dolby_dbg("Dolby Vision G12a turn on\n"); |
| } else { |
| _VSYNC_WR_MPEG_REG(VPP_DOLBY_CTRL, |
| /* cm_datx4_mode */ |
| (0x0<<21) | |
| /* reg_front_cti_bit_mode */ |
| (0x0<<20) | |
| /* vpp_clip_ext_mode 19:17 */ |
| (0x0<<17) | |
| /* vpp_dolby2_en core3 */ |
| (((dolby_vision_mask & 4) ? |
| (1 << 0) : (0 << 0)) << 16) | |
| /* mat_xvy_dat_mode */ |
| (0x0<<15) | |
| /* vpp_ve_din_mode */ |
| (0x1<<14) | |
| /* mat_vd2_dat_mode 13:12 */ |
| (0x1<<12) | |
| /* vpp_dpath_sel 10:8 */ |
| (0x3<<8) | |
| /* vpp_uns2s_mode 7:0 */ |
| 0x1f); |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* 23-20 ext mode */ |
| (0 << 2) | |
| /* 19 osd2 enable */ |
| ((dolby_vision_flags |
| & FLAG_CERTIFICAION) |
| ? (0 << 1) : (1 << 1)) | |
| /* 18 core2 bypass */ |
| ((dolby_vision_mask & 2) ? |
| 0 : 1), |
| 18, 6); |
| if ((dolby_vision_mask & 1) |
| && dovi_setting_video_flag) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 0, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = true; |
| } else { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 1, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = false; |
| } |
| /* bypass all video effect */ |
| if ((dolby_vision_flags & FLAG_BYPASS_VPP) |
| || (dolby_vision_flags & FLAG_CERTIFICAION)) |
| video_effect_bypass(1); |
| _VSYNC_WR_MPEG_REG(VPP_MATRIX_CTRL, 0); |
| _VSYNC_WR_MPEG_REG(VPP_DUMMY_DATA1, 0x20000000); |
| /* disable osd effect and shadow mode */ |
| osd_path_enable(0); |
| #ifdef V2_4 |
| if (((dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) |
| || (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT)) && |
| (dovi_setting.diagnostic_enable == 0) && |
| dovi_setting.dovi_ll_enable) { |
| u32 *reg = |
| (u32 *)&dovi_setting.dm_reg3; |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, |
| 3, 6, 2); /* post matrix */ |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 1, ®[18], 12); |
| } else |
| enable_rgb_to_yuv_matrix_for_dvll( |
| 0, NULL, 12); |
| last_dolby_vision_ll_policy = |
| dolby_vision_ll_policy; |
| #endif |
| pr_dolby_dbg("Dolby Vision turn on\n"); |
| } |
| } else { |
| if (!dolby_vision_core1_on |
| && (dolby_vision_mask & 1) |
| && dovi_setting_video_flag) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 0, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = true; |
| } else if (dolby_vision_core1_on |
| && (!(dolby_vision_mask & 1) |
| || !dovi_setting_video_flag)){ |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| 1, |
| 16, 1); /* core1 */ |
| dolby_vision_core1_on = false; |
| } |
| } |
| dolby_vision_on = true; |
| dolby_vision_wait_on = false; |
| dolby_vision_wait_init = false; |
| dolby_vision_wait_count = 0; |
| vsync_count = 0; |
| } else { |
| if (dolby_vision_on) { |
| if (is_meson_txlx_tvmode() && !force_stb_mode) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| /* vd2 connect to vpp */ |
| (1 << 1) | |
| /* 16 core1 bl bypass */ |
| (1 << 0), |
| 16, 2); |
| #ifdef V1_5 |
| if (p_funcs) /* destroy ctx */ |
| p_funcs->tv_control_path( |
| FORMAT_INVALID, 0, |
| NULL, 0, |
| NULL, 0, |
| 0, 0, |
| SIG_RANGE_SMPTE, |
| NULL, NULL, |
| 0, |
| NULL, |
| NULL); |
| #endif |
| pr_dolby_dbg("Dolby Vision TV core turn off\n"); |
| } else if (is_meson_txlx_stbmode() |
| || force_stb_mode) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| (1 << 2) | /* core2 bypass */ |
| (1 << 1) | /* vd2 connect to vpp */ |
| (1 << 0), /* core1 bl bypass */ |
| 16, 3); |
| _VSYNC_WR_MPEG_REG_BITS(VPP_DOLBY_CTRL, |
| 0, 3, 1); /* core3 disable */ |
| osd_bypass(0); |
| #ifdef V2_4 |
| if (p_funcs) /* destroy ctx */ |
| p_funcs->control_path( |
| FORMAT_INVALID, 0, |
| comp_buf[currentId], 0, |
| md_buf[currentId], 0, |
| 0, 0, 0, SIG_RANGE_SMPTE, |
| 0, 0, 0, 0, |
| 0, |
| &hdr10_param, |
| &new_dovi_setting); |
| last_dolby_vision_ll_policy = |
| DOLBY_VISION_LL_DISABLE; |
| #endif |
| stb_core_setting_update_flag = FLAG_CHANGE_ALL; |
| stb_core2_const_flag = false; |
| memset(&dovi_setting, 0, sizeof(dovi_setting)); |
| pr_dolby_dbg("Dolby Vision STB cores turn off\n"); |
| } else if (is_meson_g12()) { |
| _VSYNC_WR_MPEG_REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL, |
| 0x1); |
| _VSYNC_WR_MPEG_REG(VPP_WRAP_OSD2_MATRIX_EN_CTRL, |
| 0x1); |
| _VSYNC_WR_MPEG_REG(VPP_WRAP_OSD3_MATRIX_EN_CTRL, |
| 0x1); |
| _VSYNC_WR_MPEG_REG_BITS( |
| DOLBY_PATH_CTRL, |
| (1 << 2) | /* core2 bypass */ |
| (1 << 1) | /* vd2 connect to vpp */ |
| (1 << 0), /* core1 bl bypass */ |
| 0, 3); |
| _VSYNC_WR_MPEG_REG_BITS(VPP_DOLBY_CTRL, |
| 0, 3, 1); /* core3 disable */ |
| #ifdef V2_4 |
| if (p_funcs) /* destroy ctx */ |
| p_funcs->control_path( |
| FORMAT_INVALID, 0, |
| comp_buf[currentId], 0, |
| md_buf[currentId], 0, |
| 0, 0, 0, SIG_RANGE_SMPTE, |
| 0, 0, 0, 0, |
| 0, |
| &hdr10_param, |
| &new_dovi_setting); |
| last_dolby_vision_ll_policy = |
| DOLBY_VISION_LL_DISABLE; |
| #endif |
| stb_core_setting_update_flag = FLAG_CHANGE_ALL; |
| stb_core2_const_flag = false; |
| memset(&dovi_setting, 0, sizeof(dovi_setting)); |
| pr_dolby_dbg("Dolby Vision G12a turn off\n"); |
| } else { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VIU_MISC_CTRL1, |
| (1 << 2) | /* core2 bypass */ |
| (1 << 1) | /* vd2 connect to vpp */ |
| (1 << 0), /* core1 bl bypass */ |
| 16, 3); |
| _VSYNC_WR_MPEG_REG_BITS(VPP_DOLBY_CTRL, |
| 0, 16, 1); /* core3 disable */ |
| /* enable osd effect and*/ |
| /* use default shadow mode */ |
| osd_path_enable(1); |
| #ifdef V2_4 |
| if (p_funcs) /* destroy ctx */ |
| p_funcs->control_path( |
| FORMAT_INVALID, 0, |
| comp_buf[currentId], 0, |
| md_buf[currentId], 0, |
| 0, 0, 0, SIG_RANGE_SMPTE, |
| 0, 0, 0, 0, |
| 0, |
| &hdr10_param, |
| &new_dovi_setting); |
| last_dolby_vision_ll_policy = |
| DOLBY_VISION_LL_DISABLE; |
| #endif |
| stb_core_setting_update_flag = FLAG_CHANGE_ALL; |
| stb_core2_const_flag = false; |
| memset(&dovi_setting, 0, sizeof(dovi_setting)); |
| pr_dolby_dbg("Dolby Vision turn off\n"); |
| } |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 3 << 9); |
| _VSYNC_WR_MPEG_REG(VIU_SW_RESET, 0); |
| if (is_meson_txlx()) { |
| _VSYNC_WR_MPEG_REG(VPP_DAT_CONV_PARA0, |
| vpp_data_conv_para0_backup); |
| _VSYNC_WR_MPEG_REG(VPP_DAT_CONV_PARA1, |
| vpp_data_conv_para1_backup); |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_TV_CLKGATE_CTRL, |
| 0x2414); |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE2A_CLKGATE_CTRL, |
| 0x4); |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE3_CLKGATE_CTRL, |
| 0x414); |
| _VSYNC_WR_MPEG_REG(DOLBY_TV_AXI2DMA_CTRL0, |
| 0x01000042); |
| } |
| if (is_meson_gxm() || |
| is_meson_g12()) { |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE1_CLKGATE_CTRL, |
| 0x55555555); |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE2A_CLKGATE_CTRL, |
| 0x55555555); |
| _VSYNC_WR_MPEG_REG( |
| DOLBY_CORE3_CLKGATE_CTRL, |
| 0x55555555); |
| } |
| _VSYNC_WR_MPEG_REG( |
| VPP_VD1_CLIP_MISC0, |
| (0x3ff << 20) |
| | (0x3ff << 10) | 0x3ff); |
| _VSYNC_WR_MPEG_REG( |
| VPP_VD1_CLIP_MISC1, |
| 0); |
| video_effect_bypass(0); |
| _VSYNC_WR_MPEG_REG(VPP_DOLBY_CTRL, |
| dolby_ctrl_backup); |
| /* always vd2 to vpp and bypass core 1 */ |
| viu_misc_ctrl_backup |= |
| (_VSYNC_RD_MPEG_REG(VIU_MISC_CTRL1) & 2); |
| _VSYNC_WR_MPEG_REG(VIU_MISC_CTRL1, |
| viu_misc_ctrl_backup |
| | (3 << 16)); |
| _VSYNC_WR_MPEG_REG(VPP_MATRIX_CTRL, |
| vpp_matrix_backup); |
| _VSYNC_WR_MPEG_REG(VPP_DUMMY_DATA1, |
| vpp_dummy1_backup); |
| } |
| frame_count = 0; |
| core1_disp_hsize = 0; |
| core1_disp_vsize = 0; |
| dolby_vision_on = false; |
| dolby_vision_core1_on = false; |
| dolby_vision_wait_on = false; |
| dolby_vision_wait_init = false; |
| dolby_vision_wait_count = 0; |
| dolby_vision_status = BYPASS_PROCESS; |
| dolby_vision_on_count = 0; |
| } |
| } |
| EXPORT_SYMBOL(enable_dolby_vision); |
| |
| /* dolby vision enhanced layer receiver*/ |
| |
| #define DVEL_RECV_NAME "dvel" |
| |
| static inline void dvel_vf_put(struct vframe_s *vf) |
| { |
| struct vframe_provider_s *vfp = vf_get_provider(DVEL_RECV_NAME); |
| int event = 0; |
| |
| if (vfp) { |
| vf_put(vf, DVEL_RECV_NAME); |
| event |= VFRAME_EVENT_RECEIVER_PUT; |
| vf_notify_provider(DVEL_RECV_NAME, event, NULL); |
| } |
| } |
| |
| static inline struct vframe_s *dvel_vf_peek(void) |
| { |
| return vf_peek(DVEL_RECV_NAME); |
| } |
| |
| static inline struct vframe_s *dvel_vf_get(void) |
| { |
| int event = 0; |
| struct vframe_s *vf = vf_get(DVEL_RECV_NAME); |
| |
| if (vf) { |
| event |= VFRAME_EVENT_RECEIVER_GET; |
| vf_notify_provider(DVEL_RECV_NAME, event, NULL); |
| } |
| return vf; |
| } |
| |
| static struct vframe_s *dv_vf[16][2]; |
| static void *metadata_parser; |
| static bool metadata_parser_reset_flag; |
| static char meta_buf[1024]; |
| static int dvel_receiver_event_fun(int type, void *data, void *arg) |
| { |
| char *provider_name = (char *)data; |
| int i; |
| unsigned long flags; |
| |
| if (type == VFRAME_EVENT_PROVIDER_UNREG) { |
| pr_info("%s, provider %s unregistered\n", |
| __func__, provider_name); |
| spin_lock_irqsave(&dovi_lock, flags); |
| for (i = 0; i < 16; i++) { |
| if (dv_vf[i][0]) { |
| if (dv_vf[i][1]) |
| dvel_vf_put(dv_vf[i][1]); |
| dv_vf[i][1] = NULL; |
| } |
| dv_vf[i][0] = NULL; |
| } |
| /* if (metadata_parser && p_funcs) {*/ |
| /* p_funcs->metadata_parser_release();*/ |
| /* metadata_parser = NULL;*/ |
| /*} */ |
| new_dovi_setting.video_width = |
| new_dovi_setting.video_height = 0; |
| spin_unlock_irqrestore(&dovi_lock, flags); |
| memset(&hdr10_data, 0, sizeof(hdr10_data)); |
| memset(&hdr10_param, 0, sizeof(hdr10_param)); |
| frame_count = 0; |
| setting_update_count = 0; |
| crc_count = 0; |
| crc_bypass_count = 0; |
| return -1; |
| } else if (type == VFRAME_EVENT_PROVIDER_QUREY_STATE) { |
| return RECEIVER_ACTIVE; |
| } else if (type == VFRAME_EVENT_PROVIDER_REG) { |
| pr_info("%s, provider %s registered\n", |
| __func__, provider_name); |
| spin_lock_irqsave(&dovi_lock, flags); |
| for (i = 0; i < 16; i++) |
| dv_vf[i][0] = dv_vf[i][1] = NULL; |
| new_dovi_setting.video_width = |
| new_dovi_setting.video_height = 0; |
| spin_unlock_irqrestore(&dovi_lock, flags); |
| memset(&hdr10_data, 0, sizeof(hdr10_data)); |
| memset(&hdr10_param, 0, sizeof(hdr10_param)); |
| frame_count = 0; |
| setting_update_count = 0; |
| crc_count = 0; |
| crc_bypass_count = 0; |
| } |
| return 0; |
| } |
| |
| static const struct vframe_receiver_op_s dvel_vf_receiver = { |
| .event_cb = dvel_receiver_event_fun |
| }; |
| |
| static struct vframe_receiver_s dvel_vf_recv; |
| |
| void dolby_vision_init_receiver(void *pdev) |
| { |
| ulong alloc_size; |
| int i; |
| |
| pr_info("%s(%s)\n", __func__, DVEL_RECV_NAME); |
| vf_receiver_init(&dvel_vf_recv, DVEL_RECV_NAME, |
| &dvel_vf_receiver, &dvel_vf_recv); |
| vf_reg_receiver(&dvel_vf_recv); |
| pr_info("%s: %s\n", __func__, dvel_vf_recv.name); |
| dovi_pdev = (struct platform_device *)pdev; |
| alloc_size = dma_size; |
| alloc_size = (alloc_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); |
| dma_vaddr = dma_alloc_coherent(&dovi_pdev->dev, |
| alloc_size, &dma_paddr, GFP_KERNEL); |
| for (i = 0; i < 2; i++) { |
| md_buf[i] = vmalloc(MD_BUF_SIZE); |
| if (md_buf[i] != NULL) |
| memset(md_buf[i], 0, MD_BUF_SIZE); |
| comp_buf[i] = vmalloc(COMP_BUF_SIZE); |
| if (comp_buf[i] != NULL) |
| memset(comp_buf[i], 0, COMP_BUF_SIZE); |
| } |
| } |
| |
| #define MAX_FILENAME_LENGTH 64 |
| static const char comp_file[] = "%s_comp.%04d.reg"; |
| static const char dm_reg_core1_file[] = "%s_dm_core1.%04d.reg"; |
| static const char dm_reg_core2_file[] = "%s_dm_core2.%04d.reg"; |
| static const char dm_reg_core3_file[] = "%s_dm_core3.%04d.reg"; |
| static const char dm_lut_core1_file[] = "%s_dm_core1.%04d.lut"; |
| static const char dm_lut_core2_file[] = "%s_dm_core2.%04d.lut"; |
| |
| static void dump_struct(void *structure, int struct_length, |
| const char file_string[], int frame_nr) |
| { |
| char fn[MAX_FILENAME_LENGTH]; |
| struct file *fp; |
| loff_t pos = 0; |
| mm_segment_t old_fs = get_fs(); |
| |
| if (frame_nr == 0) |
| return; |
| set_fs(KERNEL_DS); |
| snprintf(fn, MAX_FILENAME_LENGTH, file_string, |
| "/data/tmp/tmp", frame_nr-1); |
| fp = filp_open(fn, O_RDWR|O_CREAT, 0666); |
| if (fp == NULL) |
| pr_info("Error open file for writing %s\n", fn); |
| else { |
| vfs_write(fp, structure, struct_length, &pos); |
| vfs_fsync(fp, 0); |
| filp_close(fp, NULL); |
| } |
| set_fs(old_fs); |
| } |
| |
| void dolby_vision_dump_struct(void) |
| { |
| dump_struct(&dovi_setting.dm_reg1, |
| sizeof(dovi_setting.dm_reg1), |
| dm_reg_core1_file, frame_count); |
| if (dovi_setting.el_flag) |
| dump_struct(&dovi_setting.comp_reg, |
| sizeof(dovi_setting.comp_reg), |
| comp_file, frame_count); |
| |
| if (!is_graphics_output_off()) |
| dump_struct(&dovi_setting.dm_reg2, |
| sizeof(dovi_setting.dm_reg2), |
| dm_reg_core2_file, frame_count); |
| |
| dump_struct(&dovi_setting.dm_reg3, |
| sizeof(dovi_setting.dm_reg3), |
| dm_reg_core3_file, frame_count); |
| |
| dump_struct(&dovi_setting.dm_lut1, |
| sizeof(dovi_setting.dm_lut1), |
| dm_lut_core1_file, frame_count); |
| if (!is_graphics_output_off()) |
| dump_struct(&dovi_setting.dm_lut2, |
| sizeof(dovi_setting.dm_lut2), |
| dm_lut_core2_file, frame_count); |
| pr_dolby_dbg("setting for frame %d dumped\n", frame_count); |
| } |
| EXPORT_SYMBOL(dolby_vision_dump_struct); |
| |
| static void dump_setting( |
| struct dovi_setting_s *setting, |
| int frame_cnt, int debug_flag) |
| { |
| int i; |
| uint32_t *p; |
| |
| if ((debug_flag & 0x10) && dump_enable) { |
| pr_info("core1\n"); |
| p = (uint32_t *)&setting->dm_reg1; |
| for (i = 0; i < 27; i++) |
| pr_info("%08x\n", p[i]); |
| pr_info("\ncomposer\n"); |
| p = (uint32_t *)&setting->comp_reg; |
| for (i = 0; i < 173; i++) |
| pr_info("%08x\n", p[i]); |
| if (is_meson_gxm()) { |
| pr_info("core1 swap\n"); |
| for (i = DOLBY_CORE1_CLKGATE_CTRL; |
| i <= DOLBY_CORE1_DMA_PORT; i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| pr_info("core1 real reg\n"); |
| for (i = DOLBY_CORE1_REG_START; |
| i <= DOLBY_CORE1_REG_START + 5; |
| i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| pr_info("core1 composer real reg\n"); |
| for (i = 0; i < 173 ; i++) |
| pr_info("%08x\n", |
| READ_VPP_REG( |
| DOLBY_CORE1_REG_START |
| + 50 + i)); |
| } else if (is_meson_txlx()) { |
| pr_info("core1 swap\n"); |
| for (i = DOLBY_TV_SWAP_CTRL0; |
| i <= DOLBY_TV_STATUS1; i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| pr_info("core1 real reg\n"); |
| for (i = DOLBY_TV_REG_START; |
| i <= DOLBY_CORE1_REG_START + 5; |
| i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| } |
| } |
| |
| if ((debug_flag & 0x20) && dump_enable) { |
| pr_info("\ncore1lut\n"); |
| p = (uint32_t *)&setting->dm_lut1.TmLutI; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut1.TmLutS; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut1.SmLutI; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut1.SmLutS; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut1.G2L; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| } |
| |
| if ((debug_flag & 0x10) && dump_enable && !is_graphics_output_off()) { |
| pr_info("core2\n"); |
| p = (uint32_t *)&setting->dm_reg2; |
| for (i = 0; i < 24; i++) |
| pr_info("%08x\n", p[i]); |
| pr_info("core2 swap\n"); |
| for (i = DOLBY_CORE2A_CLKGATE_CTRL; |
| i <= DOLBY_CORE2A_DMA_PORT; i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| pr_info("core2 real reg\n"); |
| for (i = DOLBY_CORE2A_REG_START; |
| i <= DOLBY_CORE2A_REG_START + 5; i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| } |
| |
| if ((debug_flag & 0x20) && dump_enable && !is_graphics_output_off()) { |
| pr_info("\ncore2lut\n"); |
| p = (uint32_t *)&setting->dm_lut2.TmLutI; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut2.TmLutS; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut2.SmLutI; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut2.SmLutS; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| p = (uint32_t *)&setting->dm_lut2.G2L; |
| for (i = 0; i < 64; i++) |
| pr_info("%08x, %08x, %08x, %08x\n", |
| p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]); |
| pr_info("\n"); |
| } |
| |
| if ((debug_flag & 0x10) && dump_enable) { |
| pr_info("core3\n"); |
| p = (uint32_t *)&setting->dm_reg3; |
| for (i = 0; i < 26; i++) |
| pr_info("%08x\n", p[i]); |
| pr_info("core3 swap\n"); |
| for (i = DOLBY_CORE3_CLKGATE_CTRL; |
| i <= DOLBY_CORE3_OUTPUT_CSC_CRC; i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| pr_info("core3 real reg\n"); |
| for (i = DOLBY_CORE3_REG_START; |
| i <= DOLBY_CORE3_REG_START + 67; i++) |
| pr_info("[0x%4x] = 0x%x\n", |
| i, READ_VPP_REG(i)); |
| } |
| |
| if ((debug_flag & 0x40) && dump_enable |
| && (dolby_vision_mode <= DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL)) { |
| pr_info("\ncore3_meta %d\n", setting->md_reg3.size); |
| p = setting->md_reg3.raw_metadata; |
| for (i = 0; i < setting->md_reg3.size; i++) |
| pr_info("%08x\n", p[i]); |
| pr_info("\n"); |
| } |
| } |
| |
| void dolby_vision_dump_setting(int debug_flag) |
| { |
| pr_dolby_dbg("\n====== setting for frame %d ======\n", frame_count); |
| if (is_meson_txlx_tvmode() && !force_stb_mode) |
| dump_tv_setting((struct tv_dovi_setting_s *)tv_dovi_setting, |
| frame_count, debug_flag); |
| else |
| dump_setting(&new_dovi_setting, frame_count, debug_flag); |
| pr_dolby_dbg("=== setting for frame %d dumped ===\n\n", frame_count); |
| } |
| EXPORT_SYMBOL(dolby_vision_dump_setting); |
| |
| static int sink_support_dolby_vision(const struct vinfo_s *vinfo) |
| { |
| if (!vinfo || !vinfo->vout_device || !vinfo->vout_device->dv_info) |
| return 0; |
| if (vinfo->vout_device->dv_info->ieeeoui != 0x00d046) |
| return 0; |
| if (vinfo->vout_device->dv_info->block_flag != CORRECT) |
| return 0; |
| if (dolby_vision_flags & FLAG_DISABLE_DOVI_OUT) |
| return 0; |
| if ((vinfo->width >= 1920) && |
| (vinfo->height >= 1080) && |
| (vinfo->field_height >= 1080)) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static int sink_support_hdr(const struct vinfo_s *vinfo) |
| { |
| #define HDR_SUPPORT (1 << 2) |
| if (!vinfo) |
| return 0; |
| if (vinfo->hdr_info.hdr_support & HDR_SUPPORT) |
| return 1; |
| return 0; |
| } |
| |
| static int dolby_vision_policy_process( |
| int *mode, enum signal_format_e src_format) |
| { |
| const struct vinfo_s *vinfo; |
| int mode_change = 0; |
| |
| if ((!dolby_vision_enable) || (!p_funcs)) |
| return mode_change; |
| |
| if (is_meson_txlx_tvmode() && !force_stb_mode) { |
| if (dolby_vision_policy == DOLBY_VISION_FORCE_OUTPUT_MODE) { |
| if (*mode == DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| pr_dolby_dbg("dovi tv output mode change %d -> %d\n", |
| dolby_vision_mode, *mode); |
| mode_change = 1; |
| } |
| } else if (*mode == DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| pr_dolby_dbg("dovi tv output mode change %d -> %d\n", |
| dolby_vision_mode, *mode); |
| mode_change = 1; |
| } |
| } else { |
| pr_dolby_error( |
| "not support dovi output mode %d\n", |
| *mode); |
| return mode_change; |
| } |
| } else if (dolby_vision_policy == DOLBY_VISION_FOLLOW_SINK) { |
| /* bypass dv_mode with efuse */ |
| if ((efuse_mode == 1) && !dolby_vision_efuse_bypass) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } else |
| mode_change = 0; |
| return mode_change; |
| } |
| if ((src_format == FORMAT_DOVI) || |
| (src_format == FORMAT_DOVI_LL)) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| pr_dolby_dbg("dovi tv output -> DOLBY_VISION_OUTPUT_MODE_SDR8\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_SDR8; |
| mode_change = 1; |
| } |
| } else { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| pr_dolby_dbg("dovi tv output -> DOLBY_VISION_OUTPUT_MODE_BYPASS\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } |
| } |
| } else if (dolby_vision_policy == DOLBY_VISION_FOLLOW_SOURCE) { |
| /* bypass dv_mode with efuse */ |
| if ((efuse_mode == 1) && !dolby_vision_efuse_bypass) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } else |
| mode_change = 0; |
| return mode_change; |
| } |
| if ((src_format == FORMAT_DOVI) || |
| (src_format == FORMAT_DOVI_LL) || |
| (src_format == FORMAT_HDR10)) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| pr_dolby_dbg("dovi tv output -> DOLBY_VISION_OUTPUT_MODE_SDR8\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_SDR8; |
| mode_change = 1; |
| } |
| } else { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| pr_dolby_dbg("dovi tv output -> DOLBY_VISION_OUTPUT_MODE_BYPASS\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } |
| } |
| } |
| return mode_change; |
| } |
| |
| vinfo = get_current_vinfo(); |
| if (dolby_vision_policy == DOLBY_VISION_FOLLOW_SINK) { |
| /* bypass dv_mode with efuse */ |
| if ((efuse_mode == 1) && !dolby_vision_efuse_bypass) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } else |
| mode_change = 0; |
| return mode_change; |
| } |
| if (vinfo && sink_support_dolby_vision(vinfo)) { |
| /* TV support DOVI, All -> DOVI */ |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) { |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL; |
| mode_change = 1; |
| } |
| } else if (vinfo && sink_support_hdr(vinfo) |
| && (dolby_vision_hdr10_policy & 2)) { |
| /* TV support HDR, All -> HDR */ |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_HDR10) { |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_HDR10\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_HDR10; |
| mode_change = 1; |
| } |
| } else { |
| /* TV not support DOVI */ |
| if ((src_format == FORMAT_DOVI) || |
| (src_format == FORMAT_DOVI_LL)) { |
| /* DOVI to SDR */ |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_SDR8\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_SDR8; |
| mode_change = 1; |
| } |
| } else if (src_format == FORMAT_HDR10 |
| && (dolby_vision_hdr10_policy & 1)) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| /* HDR10 to SDR */ |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_SDR8\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_SDR8; |
| mode_change = 1; |
| } |
| } else if (src_format == FORMAT_HDR10 |
| && (!(dolby_vision_hdr10_policy & 1))) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| /* HDR bypass */ |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_BYPASS\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } |
| } else if ((is_meson_g12b_cpu() && is_meson_rev_a()) || |
| is_meson_g12a_cpu()) { |
| /*g12 verA has a hardware bug.Therefore,dv cores |
| *must keep working even if under sdr mode |
| */ |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| /* SDR to SDR */ |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_SDR8\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_SDR8; |
| mode_change = 1; |
| } |
| } else if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| /* SDR bypass */ |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_BYPASS\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } |
| } |
| } else if (dolby_vision_policy == DOLBY_VISION_FOLLOW_SOURCE) { |
| /* bypass dv_mode with efuse */ |
| if ((efuse_mode == 1) && !dolby_vision_efuse_bypass) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } else |
| mode_change = 0; |
| return mode_change; |
| } |
| if ((src_format == FORMAT_DOVI) || |
| (src_format == FORMAT_DOVI_LL)) { |
| /* DOVI source */ |
| if (vinfo && sink_support_dolby_vision(vinfo)) { |
| /* TV support DOVI, DOVI -> DOVI */ |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) { |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL\n"); |
| *mode = |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL; |
| mode_change = 1; |
| } |
| } else { |
| /* TV not support DOVI, DOVI -> SDR */ |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_SDR8\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_SDR8; |
| mode_change = 1; |
| } |
| } |
| } else if (src_format == FORMAT_HDR10 |
| && (dolby_vision_hdr10_policy & 1)) { |
| if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_SDR8) { |
| /* HDR10 to SDR */ |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_SDR8\n"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_SDR8; |
| mode_change = 1; |
| } |
| } else if (dolby_vision_mode != |
| DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| /* HDR/SDR bypass */ |
| pr_dolby_dbg("dovi output -> DOLBY_VISION_OUTPUT_MODE_BYPASS"); |
| *mode = DOLBY_VISION_OUTPUT_MODE_BYPASS; |
| mode_change = 1; |
| } |
| } else if (dolby_vision_policy == DOLBY_VISION_FORCE_OUTPUT_MODE) { |
| if (dolby_vision_mode != *mode) { |
| pr_dolby_dbg("dovi output mode change %d -> %d\n", |
| dolby_vision_mode, *mode); |
| mode_change = 1; |
| } |
| } |
| return mode_change; |
| } |
| |
| bool is_dovi_frame(struct vframe_s *vf) |
| { |
| struct provider_aux_req_s req; |
| char *p; |
| unsigned int size = 0; |
| unsigned int type = 0; |
| |
| req.vf = vf; |
| req.bot_flag = 0; |
| req.aux_buf = NULL; |
| req.aux_size = 0; |
| req.dv_enhance_exist = 0; |
| |
| if ((vf->source_type == VFRAME_SOURCE_TYPE_HDMI) |
| && is_meson_txlx_tvmode() && !force_stb_mode) { |
| vf_notify_provider_by_name("dv_vdin", |
| VFRAME_EVENT_RECEIVER_GET_AUX_DATA, |
| (void *)&req); |
| if ((req.aux_buf && req.aux_size) || |
| (dolby_vision_flags & FLAG_FORCE_DOVI_LL)) |
| return 1; |
| else |
| return 0; |
| } else if (vf->source_type == VFRAME_SOURCE_TYPE_OTHERS) { |
| vf_notify_provider_by_name("dvbldec", |
| VFRAME_EVENT_RECEIVER_GET_AUX_DATA, |
| (void *)&req); |
| if (req.dv_enhance_exist) |
| return true; |
| if (!req.aux_buf || !req.aux_size) |
| return 0; |
| p = req.aux_buf; |
| while (p < req.aux_buf + req.aux_size - 8) { |
| size = *p++; |
| size = (size << 8) | *p++; |
| size = (size << 8) | *p++; |
| size = (size << 8) | *p++; |
| type = *p++; |
| type = (type << 8) | *p++; |
| type = (type << 8) | *p++; |
| type = (type << 8) | *p++; |
| if (type == 0x01000000) |
| return true; |
| p += size; |
| } |
| } |
| return false; |
| } |
| EXPORT_SYMBOL(is_dovi_frame); |
| |
| #define signal_color_primaries ((vf->signal_type >> 16) & 0xff) |
| #define signal_transfer_characteristic ((vf->signal_type >> 8) & 0xff) |
| static bool is_hdr10_frame(struct vframe_s *vf) |
| { |
| if ((signal_transfer_characteristic == 16) |
| && ((signal_color_primaries == 9) |
| || (signal_color_primaries == 2))) |
| return true; |
| return false; |
| } |
| |
| int dolby_vision_check_hdr10(struct vframe_s *vf) |
| { |
| int mode; |
| |
| if (is_hdr10_frame(vf) && !dolby_vision_on) { |
| /* dovi source, but dovi not enabled */ |
| mode = dolby_vision_mode; |
| if (dolby_vision_policy_process( |
| &mode, FORMAT_HDR10)) { |
| if ((mode != DOLBY_VISION_OUTPUT_MODE_BYPASS) |
| && (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_BYPASS)) |
| dolby_vision_wait_on = true; |
| return 1; |
| } |
| } |
| return 0; |
| } |
| EXPORT_SYMBOL(dolby_vision_check_hdr10); |
| |
| void dolby_vision_vf_put(struct vframe_s *vf) |
| { |
| int i; |
| |
| if (vf) |
| for (i = 0; i < 16; i++) { |
| if (dv_vf[i][0] == vf) { |
| if (dv_vf[i][1]) { |
| if (debug_dolby & 2) |
| pr_dolby_dbg("--- put bl(%p-%lld) with el(%p-%lld) ---\n", |
| vf, vf->pts_us64, |
| dv_vf[i][1], |
| dv_vf[i][1]->pts_us64); |
| dvel_vf_put(dv_vf[i][1]); |
| } else if (debug_dolby & 2) { |
| pr_dolby_dbg("--- put bl(%p-%lld) ---\n", |
| vf, vf->pts_us64); |
| } |
| dv_vf[i][0] = NULL; |
| dv_vf[i][1] = NULL; |
| } |
| } |
| } |
| EXPORT_SYMBOL(dolby_vision_vf_put); |
| |
| struct vframe_s *dolby_vision_vf_peek_el(struct vframe_s *vf) |
| { |
| int i; |
| |
| if (dolby_vision_flags && p_funcs) { |
| for (i = 0; i < 16; i++) { |
| if (dv_vf[i][0] == vf) { |
| if (dv_vf[i][1] |
| && (dolby_vision_status == BYPASS_PROCESS) |
| && !is_dolby_vision_on()) |
| dv_vf[i][1]->type |= VIDTYPE_VD2; |
| return dv_vf[i][1]; |
| } |
| } |
| } |
| return NULL; |
| } |
| EXPORT_SYMBOL(dolby_vision_vf_peek_el); |
| |
| static void dolby_vision_vf_add(struct vframe_s *vf, struct vframe_s *el_vf) |
| { |
| int i; |
| |
| for (i = 0; i < 16; i++) { |
| if (dv_vf[i][0] == NULL) { |
| dv_vf[i][0] = vf; |
| dv_vf[i][1] = el_vf; |
| break; |
| } |
| } |
| } |
| |
| static int dolby_vision_vf_check(struct vframe_s *vf) |
| { |
| int i; |
| |
| for (i = 0; i < 16; i++) { |
| if (dv_vf[i][0] == vf) { |
| if (debug_dolby & 2) { |
| if (dv_vf[i][1]) |
| pr_dolby_dbg("=== bl(%p-%lld) with el(%p-%lld) toggled ===\n", |
| vf, |
| vf->pts_us64, |
| dv_vf[i][1], |
| dv_vf[i][1]->pts_us64); |
| else |
| pr_dolby_dbg("=== bl(%p-%lld) toggled ===\n", |
| vf, |
| vf->pts_us64); |
| } |
| return 0; |
| } |
| } |
| return 1; |
| } |
| |
| static int parse_sei_and_meta( |
| struct vframe_s *vf, |
| struct provider_aux_req_s *req, |
| int *total_comp_size, |
| int *total_md_size, |
| enum signal_format_e *src_format, |
| int *ret_flags) |
| { |
| int i; |
| char *p; |
| unsigned int size = 0; |
| unsigned int type = 0; |
| int md_size = 0; |
| int comp_size = 0; |
| int parser_ready = 0; |
| int ret = 2; |
| unsigned long flags; |
| bool parser_overflow = false; |
| int nextId; |
| int rpu_ret = 0; |
| |
| nextId = currentId ^ 1; |
| if ((req->aux_buf == NULL) |
| || (req->aux_size == 0)) |
| return 1; |
| |
| p = req->aux_buf; |
| while (p < req->aux_buf + req->aux_size - 8) { |
| size = *p++; |
| size = (size << 8) | *p++; |
| size = (size << 8) | *p++; |
| size = (size << 8) | *p++; |
| type = *p++; |
| type = (type << 8) | *p++; |
| type = (type << 8) | *p++; |
| type = (type << 8) | *p++; |
| |
| if (type == 0x01000000) { |
| /* source is VS10 */ |
| *total_comp_size = 0; |
| *total_md_size = 0; |
| *src_format = FORMAT_DOVI; |
| if (size > (sizeof(meta_buf) - 3)) |
| size = (sizeof(meta_buf) - 3); |
| meta_buf[0] = meta_buf[1] = meta_buf[2] = 0; |
| memcpy(&meta_buf[3], p+1, size-1); |
| if ((debug_dolby & 4) && dump_enable) { |
| pr_dolby_dbg("metadata(%d):\n", size); |
| for (i = 0; i < size+2; i += 8) |
| pr_info("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", |
| meta_buf[i], |
| meta_buf[i+1], |
| meta_buf[i+2], |
| meta_buf[i+3], |
| meta_buf[i+4], |
| meta_buf[i+5], |
| meta_buf[i+6], |
| meta_buf[i+7]); |
| } |
| |
| if (!p_funcs) |
| return -1; |
| /* prepare metadata parser */ |
| spin_lock_irqsave(&dovi_lock, flags); |
| parser_ready = 0; |
| if (metadata_parser == NULL) { |
| metadata_parser = |
| p_funcs->metadata_parser_init( |
| dolby_vision_flags |
| & FLAG_CHANGE_SEQ_HEAD |
| ? 1 : 0); |
| p_funcs->metadata_parser_reset(1); |
| if (metadata_parser != NULL) { |
| parser_ready = 1; |
| if (debug_dolby & 1) |
| pr_dolby_dbg("metadata parser init OK\n"); |
| } |
| } else { |
| if (p_funcs->metadata_parser_reset( |
| metadata_parser_reset_flag) == 0) |
| metadata_parser_reset_flag = 0; |
| parser_ready = 1; |
| } |
| if (!parser_ready) { |
| spin_unlock_irqrestore(&dovi_lock, flags); |
| pr_dolby_error( |
| "meta(%d), pts(%lld) -> metadata parser init fail\n", |
| size, vf->pts_us64); |
| *total_comp_size = backup_comp_size; |
| *total_md_size = backup_md_size; |
| return 2; |
| } |
| |
| md_size = comp_size = 0; |
| rpu_ret = p_funcs->metadata_parser_process( |
| meta_buf, size + 2, |
| comp_buf[nextId] + *total_comp_size, |
| &comp_size, |
| md_buf[nextId] + *total_md_size, |
| &md_size, |
| true); |
| if (rpu_ret < 0) { |
| pr_dolby_error( |
| "meta(%d), pts(%lld) -> metadata parser process fail\n", |
| size, vf->pts_us64); |
| ret = 3; |
| } else { |
| if (*total_comp_size + comp_size |
| < COMP_BUF_SIZE) |
| *total_comp_size += comp_size; |
| else |
| parser_overflow = true; |
| |
| if (*total_md_size + md_size |
| < MD_BUF_SIZE) |
| *total_md_size += md_size; |
| else |
| parser_overflow = true; |
| if (rpu_ret == 1) |
| *ret_flags = 1; |
| ret = 0; |
| } |
| spin_unlock_irqrestore(&dovi_lock, flags); |
| if (parser_overflow) { |
| ret = 2; |
| break; |
| } |
| /*dolby type just appears once in metadata |
| *after parsing dolby type,breaking the |
| *circulation directly |
| */ |
| break; |
| } |
| p += size; |
| } |
| if (ret == 0) { |
| currentId = nextId; |
| backup_comp_size = *total_comp_size; |
| backup_md_size = *total_md_size; |
| } |
| if (ret == 3) { |
| *total_comp_size = backup_comp_size; |
| *total_md_size = backup_md_size; |
| } |
| if (*total_md_size) { |
| if (debug_dolby & 1) |
| pr_dolby_dbg( |
| "meta(%d), pts(%lld) -> md(%d), comp(%d)\n", |
| size, vf->pts_us64, |
| *total_md_size, *total_comp_size); |
| if ((debug_dolby & 4) && dump_enable) { |
| pr_dolby_dbg("parsed md(%d):\n", *total_md_size); |
| for (i = 0; i < *total_md_size + 7; i += 8) { |
| pr_info("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", |
| md_buf[currentId][i], |
| md_buf[currentId][i+1], |
| md_buf[currentId][i+2], |
| md_buf[currentId][i+3], |
| md_buf[currentId][i+4], |
| md_buf[currentId][i+5], |
| md_buf[currentId][i+6], |
| md_buf[currentId][i+7]); |
| } |
| } |
| } |
| return ret; |
| } |
| |
| #define INORM 50000 |
| static u32 bt2020_primaries[3][2] = { |
| {0.17 * INORM + 0.5, 0.797 * INORM + 0.5}, /* G */ |
| {0.131 * INORM + 0.5, 0.046 * INORM + 0.5}, /* B */ |
| {0.708 * INORM + 0.5, 0.292 * INORM + 0.5}, /* R */ |
| }; |
| |
| static u32 bt2020_white_point[2] = { |
| 0.3127 * INORM + 0.5, 0.3290 * INORM + 0.5 |
| }; |
| |
| static int check_primaries(struct vframe_master_display_colour_s *p_mdc) |
| { |
| if (!p_mdc->present_flag) |
| return 0; |
| if ((p_mdc->primaries[0][1] > p_mdc->primaries[1][1]) |
| && (p_mdc->primaries[0][1] > p_mdc->primaries[2][1]) |
| && (p_mdc->primaries[2][0] > p_mdc->primaries[0][0]) |
| && (p_mdc->primaries[2][0] > p_mdc->primaries[1][0])) { |
| /* reasonable g,b,r */ |
| return 2; |
| } else if ((p_mdc->primaries[0][0] > p_mdc->primaries[1][0]) |
| && (p_mdc->primaries[0][0] > p_mdc->primaries[2][0]) |
| && (p_mdc->primaries[1][1] > p_mdc->primaries[0][1]) |
| && (p_mdc->primaries[1][1] > p_mdc->primaries[2][1])) { |
| /* reasonable r,g,b */ |
| return 1; |
| } |
| /* source not usable, use standard bt2020 */ |
| return 0; |
| } |
| |
| |
| void prepare_hdr10_param( |
| struct vframe_master_display_colour_s *p_mdc, |
| struct hdr10_param_s *p_hdr10_param) |
| { |
| struct vframe_content_light_level_s *p_cll = |
| &p_mdc->content_light_level; |
| uint8_t flag = 0; |
| uint32_t max_lum = 1000 * 10000; |
| uint32_t min_lum = 50; |
| int primaries_type = 0; |
| |
| if (dolby_vision_flags & FLAG_CERTIFICAION) { |
| p_hdr10_param-> |
| min_display_mastering_luminance |
| = min_lum; |
| p_hdr10_param-> |
| max_display_mastering_luminance |
| = max_lum; |
| p_hdr10_param->Rx |
| = bt2020_primaries[2][0]; |
| p_hdr10_param->Ry |
| = bt2020_primaries[2][1]; |
| p_hdr10_param->Gx |
| = bt2020_primaries[0][0]; |
| p_hdr10_param->Gy |
| = bt2020_primaries[0][1]; |
| p_hdr10_param->Bx |
| = bt2020_primaries[1][0]; |
| p_hdr10_param->By |
| = bt2020_primaries[1][1]; |
| p_hdr10_param->Wx |
| = bt2020_white_point[0]; |
| p_hdr10_param->Wy |
| = bt2020_white_point[1]; |
| p_hdr10_param->max_content_light_level = 0; |
| p_hdr10_param->max_pic_average_light_level = 0; |
| return; |
| } |
| |
| primaries_type = check_primaries(p_mdc); |
| if (primaries_type == 2) { |
| if ((p_hdr10_param-> |
| max_display_mastering_luminance |
| != p_mdc->luminance[0]) |
| || (p_hdr10_param-> |
| min_display_mastering_luminance |
| != p_mdc->luminance[1]) |
| || (p_hdr10_param->Rx |
| != p_mdc->primaries[2][0]) |
| || (p_hdr10_param->Ry |
| != p_mdc->primaries[2][1]) |
| || (p_hdr10_param->Gx |
| != p_mdc->primaries[0][0]) |
| || (p_hdr10_param->Gy |
| != p_mdc->primaries[0][1]) |
| || (p_hdr10_param->Bx |
| != p_mdc->primaries[1][0]) |
| || (p_hdr10_param->By |
| != p_mdc->primaries[1][1]) |
| || (p_hdr10_param->Wx |
| != p_mdc->white_point[0]) |
| || (p_hdr10_param->Wy |
| != p_mdc->white_point[1])) { |
| flag |= 1; |
| p_hdr10_param-> |
| max_display_mastering_luminance |
| = p_mdc->luminance[0]; |
| p_hdr10_param-> |
| min_display_mastering_luminance |
| = p_mdc->luminance[1]; |
| p_hdr10_param->Rx |
| = p_mdc->primaries[2][0]; |
| p_hdr10_param->Ry |
| = p_mdc->primaries[2][1]; |
| p_hdr10_param->Gx |
| = p_mdc->primaries[0][0]; |
| p_hdr10_param->Gy |
| = p_mdc->primaries[0][1]; |
| p_hdr10_param->Bx |
| = p_mdc->primaries[1][0]; |
| p_hdr10_param->By |
| = p_mdc->primaries[1][1]; |
| p_hdr10_param->Wx |
| = p_mdc->white_point[0]; |
| p_hdr10_param->Wy |
| = p_mdc->white_point[1]; |
| } |
| } else if (primaries_type == 1) { |
| if ((p_hdr10_param-> |
| max_display_mastering_luminance |
| != p_mdc->luminance[0]) |
| || (p_hdr10_param-> |
| min_display_mastering_luminance |
| != p_mdc->luminance[1]) |
| || (p_hdr10_param->Rx |
| != p_mdc->primaries[0][0]) |
| || (p_hdr10_param->Ry |
| != p_mdc->primaries[0][1]) |
| || (p_hdr10_param->Gx |
| != p_mdc->primaries[1][0]) |
| || (p_hdr10_param->Gy |
| != p_mdc->primaries[1][1]) |
| || (p_hdr10_param->Bx |
| != p_mdc->primaries[2][0]) |
| || (p_hdr10_param->By |
| != p_mdc->primaries[2][1]) |
| || (p_hdr10_param->Wx |
| != p_mdc->white_point[0]) |
| || (p_hdr10_param->Wy |
| != p_mdc->white_point[1])) { |
| flag |= 1; |
| p_hdr10_param-> |
| max_display_mastering_luminance |
| = p_mdc->luminance[0]; |
| p_hdr10_param-> |
| min_display_mastering_luminance |
| = p_mdc->luminance[1]; |
| p_hdr10_param->Rx |
| = p_mdc->primaries[0][0]; |
| p_hdr10_param->Ry |
| = p_mdc->primaries[0][1]; |
| p_hdr10_param->Gx |
| = p_mdc->primaries[1][0]; |
| p_hdr10_param->Gy |
| = p_mdc->primaries[1][1]; |
| p_hdr10_param->Bx |
| = p_mdc->primaries[2][0]; |
| p_hdr10_param->By |
| = p_mdc->primaries[2][1]; |
| p_hdr10_param->Wx |
| = p_mdc->white_point[0]; |
| p_hdr10_param->Wy |
| = p_mdc->white_point[1]; |
| } |
| } else { |
| if ((p_hdr10_param-> |
| min_display_mastering_luminance |
| != min_lum) |
| || (p_hdr10_param-> |
| max_display_mastering_luminance |
| != max_lum) |
| || (p_hdr10_param->Rx |
| != bt2020_primaries[2][0]) |
| || (p_hdr10_param->Ry |
| != bt2020_primaries[2][1]) |
| || (p_hdr10_param->Gx |
| != bt2020_primaries[0][0]) |
| || (p_hdr10_param->Gy |
| != bt2020_primaries[0][1]) |
| || (p_hdr10_param->Bx |
| != bt2020_primaries[1][0]) |
| || (p_hdr10_param->By |
| != bt2020_primaries[1][1]) |
| || (p_hdr10_param->Wx |
| != bt2020_white_point[0]) |
| || (p_hdr10_param->Wy |
| != bt2020_white_point[1])) { |
| flag |= 2; |
| p_hdr10_param-> |
| min_display_mastering_luminance |
| = min_lum; |
| p_hdr10_param-> |
| max_display_mastering_luminance |
| = max_lum; |
| p_hdr10_param->Rx |
| = bt2020_primaries[2][0]; |
| p_hdr10_param->Ry |
| = bt2020_primaries[2][1]; |
| p_hdr10_param->Gx |
| = bt2020_primaries[0][0]; |
| p_hdr10_param->Gy |
| = bt2020_primaries[0][1]; |
| p_hdr10_param->Bx |
| = bt2020_primaries[1][0]; |
| p_hdr10_param->By |
| = bt2020_primaries[1][1]; |
| p_hdr10_param->Wx |
| = bt2020_white_point[0]; |
| p_hdr10_param->Wy |
| = bt2020_white_point[1]; |
| } |
| } |
| |
| if (p_cll->present_flag) { |
| if ((p_hdr10_param->max_content_light_level |
| != p_cll->max_content) |
| || (p_hdr10_param->max_pic_average_light_level |
| != p_cll->max_pic_average)) |
| flag |= 4; |
| if (flag & 4) { |
| p_hdr10_param->max_content_light_level |
| = p_cll->max_content; |
| p_hdr10_param->max_pic_average_light_level |
| = p_cll->max_pic_average; |
| } |
| } else { |
| if ((p_hdr10_param->max_content_light_level != 0) |
| || (p_hdr10_param->max_pic_average_light_level != 0)) { |
| p_hdr10_param->max_content_light_level = 0; |
| p_hdr10_param->max_pic_average_light_level = 0; |
| flag |= 8; |
| } |
| } |
| |
| if (flag) { |
| pr_dolby_dbg("HDR10: primaries %d, maxcontent %d, flag %d\n", |
| p_mdc->present_flag, |
| p_cll->present_flag, |
| flag); |
| pr_dolby_dbg("\tR = %04x, %04x\n", |
| p_hdr10_param->Rx, |
| p_hdr10_param->Ry); |
| pr_dolby_dbg("\tG = %04x, %04x\n", |
| p_hdr10_param->Gx, |
| p_hdr10_param->Gy); |
| pr_dolby_dbg("\tB = %04x, %04x\n", |
| p_hdr10_param->Bx, |
| p_hdr10_param->By); |
| pr_dolby_dbg("\tW = %04x, %04x\n", |
| p_hdr10_param->Wx, |
| p_hdr10_param->Wy); |
| pr_dolby_dbg("\tMax = %d\n", |
| p_hdr10_param-> |
| max_display_mastering_luminance); |
| pr_dolby_dbg("\tMin = %d\n", |
| p_hdr10_param-> |
| min_display_mastering_luminance); |
| pr_dolby_dbg("\tMCLL = %d\n", |
| p_hdr10_param-> |
| max_content_light_level); |
| pr_dolby_dbg("\tMPALL = %d\n\n", |
| p_hdr10_param-> |
| max_pic_average_light_level); |
| } |
| } |
| |
| #ifdef V2_4 |
| static int prepare_vsif_pkt( |
| struct dv_vsif_para *vsif, |
| struct dovi_setting_s *setting, |
| const struct vinfo_s *vinfo) |
| { |
| if (!vsif || !vinfo || !setting || |
| !vinfo->vout_device || !vinfo->vout_device->dv_info) |
| return -1; |
| vsif->vers.ver2.low_latency = |
| setting->dovi_ll_enable; |
| vsif->vers.ver2.dobly_vision_signal = 1; |
| if (vinfo->vout_device->dv_info |
| && vinfo->vout_device->dv_info->sup_backlight_control |
| && (setting->ext_md.available_level_mask |
| & EXT_MD_AVAIL_LEVEL_2)) { |
| vsif->vers.ver2.backlt_ctrl_MD_present = 1; |
| vsif->vers.ver2.eff_tmax_PQ_hi = |
| setting->ext_md.level_2.target_max_PQ_hi & 0xf; |
| vsif->vers.ver2.eff_tmax_PQ_low = |
| setting->ext_md.level_2.target_max_PQ_lo; |
| } else { |
| vsif->vers.ver2.backlt_ctrl_MD_present = 0; |
| vsif->vers.ver2.eff_tmax_PQ_hi = 0; |
| vsif->vers.ver2.eff_tmax_PQ_low = 0; |
| } |
| |
| if (setting->dovi_ll_enable |
| && (setting->ext_md.available_level_mask |
| & EXT_MD_AVAIL_LEVEL_255)) { |
| vsif->vers.ver2.auxiliary_MD_present = 1; |
| vsif->vers.ver2.auxiliary_runmode = |
| setting->ext_md.level_255.dm_run_mode; |
| vsif->vers.ver2.auxiliary_runversion = |
| setting->ext_md.level_255.dm_run_version; |
| vsif->vers.ver2.auxiliary_debug0 = |
| setting->ext_md.level_255.dm_debug0; |
| } else { |
| vsif->vers.ver2.auxiliary_MD_present = 0; |
| vsif->vers.ver2.auxiliary_runmode = 0; |
| vsif->vers.ver2.auxiliary_runversion = 0; |
| vsif->vers.ver2.auxiliary_debug0 = 0; |
| } |
| return 0; |
| } |
| #endif |
| |
| /* #define HDMI_SEND_ALL_PKT */ |
| static u32 last_dst_format = FORMAT_SDR; |
| static bool send_hdmi_pkt( |
| enum signal_format_e dst_format, |
| const struct vinfo_s *vinfo) |
| { |
| struct hdr_10_infoframe_s *p_hdr; |
| int i; |
| bool flag = false; |
| |
| if (dst_format == FORMAT_HDR10) { |
| p_hdr = &dovi_setting.hdr_info; |
| hdr10_data.features = |
| (1 << 29) /* video available */ |
| | (5 << 26) /* unspecified */ |
| | (0 << 25) /* limit */ |
| | (1 << 24) /* color available */ |
| | (9 << 16) /* bt2020 */ |
| | (0x10 << 8) /* bt2020-10 */ |
| | (10 << 0);/* bt2020c */ |
| /* need invert to g,b,r */ |
| if (hdr10_data.primaries[0][0] != |
| ((p_hdr->display_primaries_x_1_MSB << 8) |
| | p_hdr->display_primaries_x_1_LSB)) |
| flag = true; |
| hdr10_data.primaries[0][0] = |
| (p_hdr->display_primaries_x_1_MSB << 8) |
| | p_hdr->display_primaries_x_1_LSB; |
| |
| if (hdr10_data.primaries[0][1] != |
| ((p_hdr->display_primaries_y_1_MSB << 8) |
| | p_hdr->display_primaries_y_1_LSB)) |
| flag = true; |
| hdr10_data.primaries[0][1] = |
| (p_hdr->display_primaries_y_1_MSB << 8) |
| | p_hdr->display_primaries_y_1_LSB; |
| |
| if (hdr10_data.primaries[1][0] != |
| ((p_hdr->display_primaries_x_2_MSB << 8) |
| | p_hdr->display_primaries_x_2_LSB)) |
| flag = true; |
| hdr10_data.primaries[1][0] = |
| (p_hdr->display_primaries_x_2_MSB << 8) |
| | p_hdr->display_primaries_x_2_LSB; |
| |
| if (hdr10_data.primaries[1][1] != |
| ((p_hdr->display_primaries_y_2_MSB << 8) |
| | p_hdr->display_primaries_y_2_LSB)) |
| flag = true; |
| hdr10_data.primaries[1][1] = |
| (p_hdr->display_primaries_y_2_MSB << 8) |
| | p_hdr->display_primaries_y_2_LSB; |
| if (hdr10_data.primaries[2][0] != |
| ((p_hdr->display_primaries_x_0_MSB << 8) |
| | p_hdr->display_primaries_x_0_LSB)) |
| flag = true; |
| hdr10_data.primaries[2][0] = |
| (p_hdr->display_primaries_x_0_MSB << 8) |
| | p_hdr->display_primaries_x_0_LSB; |
| |
| if (hdr10_data.primaries[2][1] != |
| ((p_hdr->display_primaries_y_0_MSB << 8) |
| | p_hdr->display_primaries_y_0_LSB)) |
| flag = true; |
| hdr10_data.primaries[2][1] = |
| (p_hdr->display_primaries_y_0_MSB << 8) |
| | p_hdr->display_primaries_y_0_LSB; |
| |
| if (hdr10_data.white_point[0] != |
| ((p_hdr->white_point_x_MSB << 8) |
| | p_hdr->white_point_x_LSB)) |
| flag = true; |
| hdr10_data.white_point[0] = |
| (p_hdr->white_point_x_MSB << 8) |
| | p_hdr->white_point_x_LSB; |
| |
| if (hdr10_data.white_point[1] != |
| ((p_hdr->white_point_y_MSB << 8) |
| | p_hdr->white_point_y_LSB)) |
| flag = true; |
| hdr10_data.white_point[1] = |
| (p_hdr->white_point_y_MSB << 8) |
| | p_hdr->white_point_y_LSB; |
| |
| if (hdr10_data.luminance[0] != |
| ((p_hdr->max_display_mastering_luminance_MSB << 8) |
| | p_hdr->max_display_mastering_luminance_LSB)) |
| flag = true; |
| hdr10_data.luminance[0] = |
| (p_hdr->max_display_mastering_luminance_MSB << 8) |
| | p_hdr->max_display_mastering_luminance_LSB; |
| |
| if (hdr10_data.luminance[1] != |
| ((p_hdr->min_display_mastering_luminance_MSB << 8) |
| | p_hdr->min_display_mastering_luminance_LSB)) |
| flag = true; |
| hdr10_data.luminance[1] = |
| (p_hdr->min_display_mastering_luminance_MSB << 8) |
| | p_hdr->min_display_mastering_luminance_LSB; |
| |
| if (hdr10_data.max_content != |
| ((p_hdr->max_content_light_level_MSB << 8) |
| | p_hdr->max_content_light_level_LSB)) |
| flag = true; |
| hdr10_data.max_content = |
| (p_hdr->max_content_light_level_MSB << 8) |
| | p_hdr->max_content_light_level_LSB; |
| |
| if (hdr10_data.max_frame_average != |
| ((p_hdr->max_frame_average_light_level_MSB << 8) |
| | p_hdr->max_frame_average_light_level_LSB)) |
| flag = true; |
| hdr10_data.max_frame_average = |
| (p_hdr->max_frame_average_light_level_MSB << 8) |
| | p_hdr->max_frame_average_light_level_LSB; |
| if (vinfo && vinfo->vout_device && |
| vinfo->vout_device->fresh_tx_hdr_pkt) |
| vinfo->vout_device->fresh_tx_hdr_pkt(&hdr10_data); |
| #ifdef HDMI_SEND_ALL_PKT |
| if (vinfo && vinfo->vout_device && |
| vinfo->vout_device->fresh_tx_vsif_pkt) |
| vinfo->vout_device->fresh_tx_vsif_pkt(0, 0, NULL); |
| #endif |
| last_dst_format = dst_format; |
| if (flag) { |
| pr_dolby_dbg("Info frame for hdr10 changed:\n"); |
| for (i = 0; i < 3; i++) |
| pr_dolby_dbg( |
| "\tprimaries[%1d] = %04x, %04x\n", |
| i, |
| hdr10_data.primaries[i][0], |
| hdr10_data.primaries[i][1]); |
| pr_dolby_dbg("\twhite_point = %04x, %04x\n", |
| hdr10_data.white_point[0], |
| hdr10_data.white_point[1]); |
| pr_dolby_dbg("\tMax = %d\n", |
| hdr10_data.luminance[0]); |
| pr_dolby_dbg("\tMin = %d\n", |
| hdr10_data.luminance[1]); |
| pr_dolby_dbg("\tMCLL = %d\n", |
| hdr10_data.max_content); |
| pr_dolby_dbg("\tMPALL = %d\n\n", |
| hdr10_data.max_frame_average); |
| } |
| } else if (dst_format == FORMAT_DOVI) { |
| struct dv_vsif_para vsif; |
| |
| memset(&vsif, 0, sizeof(vsif)); |
| #ifdef V2_4 |
| if (vinfo) |
| prepare_vsif_pkt( |
| &vsif, &dovi_setting, vinfo); |
| #endif |
| #ifdef HDMI_SEND_ALL_PKT |
| hdr10_data.features = |
| (1 << 29) /* video available */ |
| | (5 << 26) /* unspecified */ |
| | (0 << 25) /* limit */ |
| | (1 << 24) /* color available */ |
| | (1 << 16) /* bt709 */ |
| | (1 << 8) /* bt709 */ |
| | (1 << 0); /* bt709 */ |
| for (i = 0; i < 3; i++) { |
| hdr10_data.primaries[i][0] = 0; |
| hdr10_data.primaries[i][1] = 0; |
| } |
| hdr10_data.white_point[0] = 0; |
| hdr10_data.white_point[1] = 0; |
| hdr10_data.luminance[0] = 0; |
| hdr10_data.luminance[1] = 0; |
| hdr10_data.max_content = 0; |
| hdr10_data.max_frame_average = 0; |
| if (vinfo && vinfo->vout_device && |
| vinfo->vout_device->fresh_tx_hdr_pkt) |
| vinfo->vout_device->fresh_tx_hdr_pkt(&hdr10_data); |
| #endif |
| if (vinfo && vinfo->vout_device && |
| vinfo->vout_device->fresh_tx_vsif_pkt) { |
| #ifdef V2_4 |
| if (dovi_setting.dovi_ll_enable) |
| vinfo->vout_device->fresh_tx_vsif_pkt( |
| EOTF_T_LL_MODE, |
| dovi_setting.diagnostic_enable |
| ? RGB_10_12BIT : YUV422_BIT12, |
| &vsif); |
| else |
| #endif |
| vinfo->vout_device->fresh_tx_vsif_pkt( |
| EOTF_T_DOLBYVISION, |
| dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL |
| ? RGB_8BIT : YUV422_BIT12, &vsif); |
| } |
| last_dst_format = dst_format; |
| } else if (last_dst_format != dst_format) { |
| if (last_dst_format == FORMAT_HDR10) { |
| hdr10_data.features = |
| (1 << 29) /* video available */ |
| | (5 << 26) /* unspecified */ |
| | (0 << 25) /* limit */ |
| | (1 << 24) /* color available */ |
| | (1 << 16) /* bt709 */ |
| | (1 << 8) /* bt709 */ |
| | (1 << 0); /* bt709 */ |
| for (i = 0; i < 3; i++) { |
| hdr10_data.primaries[i][0] = 0; |
| hdr10_data.primaries[i][1] = 0; |
| } |
| hdr10_data.white_point[0] = 0; |
| hdr10_data.white_point[1] = 0; |
| hdr10_data.luminance[0] = 0; |
| hdr10_data.luminance[1] = 0; |
| hdr10_data.max_content = 0; |
| hdr10_data.max_frame_average = 0; |
| if (vinfo && vinfo->vout_device && |
| vinfo->vout_device->fresh_tx_hdr_pkt) |
| vinfo->vout_device->fresh_tx_hdr_pkt( |
| &hdr10_data); |
| } else if (last_dst_format == FORMAT_DOVI) { |
| if (vinfo && vinfo->vout_device && |
| vinfo->vout_device->fresh_tx_vsif_pkt) |
| vinfo->vout_device->fresh_tx_vsif_pkt( |
| 0, 0, NULL); |
| } |
| last_dst_format = dst_format; |
| } |
| return flag; |
| } |
| |
| static uint32_t null_vf_cnt; |
| static bool video_off_handled; |
| static int is_video_output_off(struct vframe_s *vf) |
| { |
| if ((READ_VPP_REG(VPP_MISC) & (1<<10)) == 0) { |
| /*Not reset frame0/1 clipping*/ |
| /*when core off to avoid green garbage*/ |
| if (is_meson_txlx_tvmode() && (vf == NULL) && |
| (dolby_vision_on_count <= dolby_vision_run_mode_delay)) |
| return 0; |
| if (vf == NULL) |
| null_vf_cnt++; |
| else |
| null_vf_cnt = 0; |
| if (null_vf_cnt > dolby_vision_wait_delay + 3) { |
| null_vf_cnt = 0; |
| return 1; |
| } |
| } else |
| video_off_handled = 0; |
| return 0; |
| } |
| |
| static void calculate_panel_max_pq( |
| const struct vinfo_s *vinfo, |
| struct TargetDisplayConfig *config) |
| { |
| uint32_t max_lin = tv_max_lin; |
| uint16_t max_pq = tv_max_pq; |
| |
| if (dolby_vision_flags & FLAG_CERTIFICAION) |
| return; |
| if (panel_max_lumin) |
| max_lin = panel_max_lumin; |
| else if (vinfo->mode == VMODE_LCD) |
| max_lin = vinfo->hdr_info.lumi_max; |
| if (max_lin < 100) |
| max_lin = 100; |
| else if (max_lin > 4000) |
| max_lin = 4000; |
| if (max_lin != tv_max_lin) { |
| if (max_lin < 500) { |
| max_lin = max_lin - 100 + 10; |
| max_lin = (max_lin / 20) * 20 + 100; |
| max_pq = L2PQ_100_500[(max_lin - 100) / 20]; |
| } else { |
| max_lin = max_lin - 500 + 50; |
| max_lin = (max_lin / 100) * 100 + 500; |
| max_pq = L2PQ_500_4000[(max_lin - 500) / 100]; |
| } |
| pr_info("panel max lumin changed from %d(%d) to %d(%d)\n", |
| tv_max_lin, tv_max_pq, max_lin, max_pq); |
| tv_max_lin = max_lin; |
| tv_max_pq = max_pq; |
| config->max_lin = |
| config->max_lin_dupli = |
| tv_max_lin << 18; |
| config->maxPq = |
| config->maxPq_dupli = |
| tv_max_pq; |
| } |
| } |
| |
| bool is_dv_standard_es( |
| int dvel, int mflag, int width) |
| { |
| if ((dolby_vision_profile == 4) && |
| (dvel == 1) && (mflag == 0) && |
| (width >= 3840)) |
| return false; |
| else |
| return true; |
| } |
| |
| static u32 last_total_md_size; |
| static u32 last_total_comp_size; |
| /* toggle mode: 0: not toggle; 1: toggle frame; 2: use keep frame */ |
| int dolby_vision_parse_metadata( |
| struct vframe_s *vf, u8 toggle_mode, bool bypass_release) |
| { |
| const struct vinfo_s *vinfo = get_current_vinfo(); |
| struct vframe_s *el_vf; |
| struct provider_aux_req_s req; |
| struct provider_aux_req_s el_req; |
| int flag; |
| enum signal_format_e src_format = FORMAT_SDR; |
| enum signal_format_e check_format; |
| enum signal_format_e dst_format; |
| int total_md_size = 0; |
| int total_comp_size = 0; |
| bool el_flag = 0; |
| bool el_halfsize_flag = 1; |
| uint32_t w = 3840; |
| uint32_t h = 2160; |
| int meta_flag_bl = 1; |
| int meta_flag_el = 1; |
| int src_chroma_format = 0; |
| int src_bdp = 12; |
| bool video_frame = false; |
| int i; |
| struct vframe_master_display_colour_s *p_mdc; |
| unsigned int current_mode = dolby_vision_mode; |
| uint32_t target_lumin_max = 0; |
| enum input_mode_e input_mode = INPUT_MODE_OTT; |
| enum priority_mode_e pri_mode = VIDEO_PRIORITY; |
| u32 graphic_min = 50; /* 0.0001 */ |
| u32 graphic_max = 100; /* 1 */ |
| int ret_flags = 0; |
| int ret = -1; |
| |
| memset(&req, 0, (sizeof(struct provider_aux_req_s))); |
| memset(&el_req, 0, (sizeof(struct provider_aux_req_s))); |
| |
| if (!dolby_vision_enable) |
| return -1; |
| |
| if (vf) { |
| video_frame = true; |
| w = (vf->type & VIDTYPE_COMPRESS) ? |
| vf->compWidth : vf->width; |
| h = (vf->type & VIDTYPE_COMPRESS) ? |
| vf->compHeight : vf->height; |
| } |
| |
| if (is_meson_txlx_tvmode() && !force_stb_mode && vf |
| && (vf->source_type == VFRAME_SOURCE_TYPE_HDMI)) { |
| req.vf = vf; |
| req.bot_flag = 0; |
| req.aux_buf = NULL; |
| req.aux_size = 0; |
| req.dv_enhance_exist = 0; |
| req.low_latency = 0; |
| vf_notify_provider_by_name("dv_vdin", |
| VFRAME_EVENT_RECEIVER_GET_AUX_DATA, |
| (void *)&req); |
| input_mode = INPUT_MODE_HDMI; |
| if (debug_dolby & 1) |
| pr_dolby_dbg("vdin0 get aux data %p %x, ll:%d\n", |
| req.aux_buf, req.aux_size, req.low_latency); |
| |
| if ((dolby_vision_flags & FLAG_FORCE_DOVI_LL) |
| || (req.low_latency == 1)) { |
| src_format = FORMAT_DOVI_LL; |
| src_chroma_format = 0; |
| for (i = 0; i < 2; i++) { |
| if (md_buf[i] != NULL) |
| memset(md_buf[i], 0, MD_BUF_SIZE); |
| if (comp_buf[i] != NULL) |
| memset(comp_buf[i], 0, COMP_BUF_SIZE); |
| } |
| req.aux_size = 0; |
| req.aux_buf = NULL; |
| } else if (req.aux_buf && req.aux_size) { |
| memcpy(md_buf[currentId], req.aux_buf, req.aux_size); |
| src_format = FORMAT_DOVI; |
| } else { |
| if (toggle_mode == 2) |
| src_format = ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format; |
| if (vf->type & VIDTYPE_VIU_422) |
| src_chroma_format = 1; |
| p_mdc = &vf->prop.master_display_colour; |
| if (is_hdr10_frame(vf)) { |
| src_format = FORMAT_HDR10; |
| /* prepare parameter from hdmi for hdr10 */ |
| p_mdc->luminance[0] *= 10000; |
| prepare_hdr10_param( |
| p_mdc, &hdr10_param); |
| } |
| } |
| if (debug_dolby & 4) { |
| pr_dolby_dbg("metadata(%d):\n", req.aux_size); |
| for (i = 0; i < req.aux_size + 8; i += 8) |
| pr_info("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", |
| md_buf[currentId][i], |
| md_buf[currentId][i+1], |
| md_buf[currentId][i+2], |
| md_buf[currentId][i+3], |
| md_buf[currentId][i+4], |
| md_buf[currentId][i+5], |
| md_buf[currentId][i+6], |
| md_buf[currentId][i+7]); |
| } |
| |
| total_md_size = req.aux_size; |
| total_comp_size = 0; |
| meta_flag_bl = 0; |
| if (req.aux_buf && req.aux_size) { |
| last_total_md_size = total_md_size; |
| last_total_comp_size = total_comp_size; |
| } else if (toggle_mode == 2) { |
| total_md_size = last_total_md_size; |
| total_comp_size = last_total_comp_size; |
| } |
| if (debug_dolby & 1) |
| pr_dolby_dbg( |
| "frame %d pts %lld, format: %s\n", |
| frame_count, vf->pts_us64, |
| (src_format == FORMAT_HDR10) ? "HDR10" : |
| ((src_format == FORMAT_DOVI) ? "DOVI" : |
| ((src_format == FORMAT_DOVI_LL) ? "DOVI_LL" : "SDR"))); |
| |
| if (toggle_mode == 1) { |
| if (debug_dolby & 2) |
| pr_dolby_dbg( |
| "+++ get bl(%p-%lld) +++\n", |
| vf, vf->pts_us64); |
| dolby_vision_vf_add(vf, NULL); |
| } |
| } else if (vf && (vf->source_type == VFRAME_SOURCE_TYPE_OTHERS)) { |
| /* check source format */ |
| input_mode = INPUT_MODE_OTT; |
| req.vf = vf; |
| req.bot_flag = 0; |
| req.aux_buf = NULL; |
| req.aux_size = 0; |
| req.dv_enhance_exist = 0; |
| vf_notify_provider_by_name("dvbldec", |
| VFRAME_EVENT_RECEIVER_GET_AUX_DATA, |
| (void *)&req); |
| if (debug_dolby & 1 && req.aux_buf && req.aux_size) |
| pr_dolby_dbg("dvbldec get aux data %p %x\n", |
| req.aux_buf, req.aux_size); |
| /* parse meta in base layer */ |
| if (toggle_mode != 2) { |
| meta_flag_bl = |
| parse_sei_and_meta( |
| vf, &req, |
| &total_comp_size, |
| &total_md_size, |
| &src_format, |
| &ret_flags); |
| if (ret_flags && req.dv_enhance_exist |
| && (frame_count == 0)) |
| vf_notify_provider_by_name("dvbldec", |
| VFRAME_EVENT_RECEIVER_DOLBY_BYPASS_EL, |
| (void *)&req); |
| if (!is_dv_standard_es(req.dv_enhance_exist, |
| ret_flags, w)) { |
| src_format = FORMAT_SDR; |
| dovi_setting.src_format = src_format; |
| total_comp_size = 0; |
| total_md_size = 0; |
| src_bdp = 10; |
| bypass_release = true; |
| } |
| } else if (is_dolby_vision_stb_mode()) |
| src_format = dovi_setting.src_format; |
| else if (is_meson_txlx_tvmode()) |
| src_format = ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format; |
| |
| if ((src_format != FORMAT_DOVI) |
| && is_hdr10_frame(vf)) { |
| src_format = FORMAT_HDR10; |
| /* prepare parameter from SEI for hdr10 */ |
| p_mdc = &vf->prop.master_display_colour; |
| prepare_hdr10_param(p_mdc, &hdr10_param); |
| /* for 962x with v1.4 or stb with v2.3 may use 12 bit */ |
| src_bdp = 10; |
| req.dv_enhance_exist = 0; |
| } |
| #ifdef V2_4 |
| /* TODO: need 962e ? */ |
| if ((src_format == FORMAT_SDR) |
| && is_dolby_vision_stb_mode() |
| && !req.dv_enhance_exist) |
| src_bdp = 10; |
| #endif |
| if (((debug_dolby & 1) |
| || (frame_count == 0)) |
| && (toggle_mode == 1)) |
| pr_info( |
| "DOLBY: frame %d pts %lld, src bdp: %d format: %s, aux_size:%d, enhance: %d\n", |
| frame_count, vf->pts_us64, src_bdp, |
| (src_format == FORMAT_HDR10) ? "HDR10" : |
| (src_format == FORMAT_DOVI ? "DOVI" : |
| (req.dv_enhance_exist ? "DOVI (el meta)" : "SDR")), |
| req.aux_size, req.dv_enhance_exist); |
| if ((src_format != FORMAT_DOVI) |
| && !req.dv_enhance_exist) |
| memset(&req, 0, sizeof(req)); |
| if (req.dv_enhance_exist && |
| (toggle_mode == 1)) { |
| el_vf = dvel_vf_get(); |
| if (el_vf && |
| ((el_vf->pts_us64 == vf->pts_us64) |
| || !(dolby_vision_flags & FLAG_CHECK_ES_PTS))) { |
| if (debug_dolby & 2) |
| pr_dolby_dbg("+++ get bl(%p-%lld) with el(%p-%lld) +++\n", |
| vf, vf->pts_us64, |
| el_vf, el_vf->pts_us64); |
| if (meta_flag_bl) { |
| int el_md_size = 0; |
| int el_comp_size = 0; |
| |
| el_req.vf = el_vf; |
| el_req.bot_flag = 0; |
| el_req.aux_buf = NULL; |
| el_req.aux_size = 0; |
| vf_notify_provider_by_name("dveldec", |
| VFRAME_EVENT_RECEIVER_GET_AUX_DATA, |
| (void *)&el_req); |
| if (el_req.aux_buf |
| && el_req.aux_size) { |
| meta_flag_el = |
| parse_sei_and_meta( |
| el_vf, &el_req, |
| &el_comp_size, |
| &el_md_size, |
| &src_format, |
| &ret_flags); |
| } |
| if (!meta_flag_el) { |
| total_comp_size = |
| el_comp_size; |
| total_md_size = |
| el_md_size; |
| src_bdp = 12; |
| } |
| /* force set format as DOVI*/ |
| /* when meta data error */ |
| if (meta_flag_el |
| && el_req.aux_buf |
| && el_req.aux_size) |
| src_format = FORMAT_DOVI; |
| if (debug_dolby & 2) |
| pr_dolby_dbg( |
| "meta data el mode: el_src_format: %d, meta_flag_el: %d\n", |
| src_format, |
| meta_flag_el); |
| if (meta_flag_el && frame_count == 0) |
| pr_info( |
| "DOVI el meta mode, but parser meta error, el vf %p, size:%d\n", |
| el_req.aux_buf, |
| el_req.aux_size); |
| } |
| dolby_vision_vf_add(vf, el_vf); |
| el_flag = 1; |
| if (vf->width == el_vf->width) |
| el_halfsize_flag = 0; |
| } else { |
| if (!el_vf) |
| pr_dolby_error( |
| "bl(%p-%lld) not found el\n", |
| vf, vf->pts_us64); |
| else |
| pr_dolby_error( |
| "bl(%p-%lld) not found el(%p-%lld)\n", |
| vf, vf->pts_us64, |
| el_vf, el_vf->pts_us64); |
| } |
| } else if (toggle_mode == 1) { |
| if (debug_dolby & 2) |
| pr_dolby_dbg( |
| "+++ get bl(%p-%lld) +++\n", |
| vf, vf->pts_us64); |
| dolby_vision_vf_add(vf, NULL); |
| } |
| |
| if ((toggle_mode == 0) |
| && req.dv_enhance_exist) |
| el_flag = 1; |
| |
| if (toggle_mode != 2) { |
| last_total_md_size = total_md_size; |
| last_total_comp_size = total_comp_size; |
| } else if (meta_flag_bl && meta_flag_el) { |
| total_md_size = last_total_md_size; |
| total_comp_size = last_total_comp_size; |
| if (is_dolby_vision_stb_mode()) |
| el_flag = dovi_setting.el_flag; |
| else |
| el_flag = ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->el_flag; |
| meta_flag_bl = 0; |
| } |
| if ((src_format == FORMAT_DOVI) |
| && meta_flag_bl && meta_flag_el) { |
| /* dovi frame no meta or meta error */ |
| /* use old setting for this frame */ |
| return -1; |
| } |
| w = (vf->type & VIDTYPE_COMPRESS) ? |
| vf->compWidth : vf->width; |
| h = (vf->type & VIDTYPE_COMPRESS) ? |
| vf->compHeight : vf->height; |
| } |
| |
| if ((src_format == FORMAT_DOVI) |
| && meta_flag_bl && meta_flag_el) { |
| /* dovi frame no meta or meta error */ |
| /* use old setting for this frame */ |
| return -1; |
| } |
| |
| /* if not DOVI, release metadata_parser */ |
| if ((src_format != FORMAT_DOVI) |
| && metadata_parser |
| && !bypass_release) { |
| if (p_funcs) |
| p_funcs->metadata_parser_release(); |
| metadata_parser = NULL; |
| } |
| |
| check_format = src_format; |
| if (dolby_vision_request_mode != 0xff) { |
| dolby_vision_mode = dolby_vision_request_mode; |
| dolby_vision_request_mode = 0xff; |
| } |
| current_mode = dolby_vision_mode; |
| |
| if (dolby_vision_policy_process( |
| ¤t_mode, check_format)) { |
| if (!dolby_vision_wait_init) |
| dolby_vision_set_toggle_flag(1); |
| pr_dolby_dbg("[dolby_vision_parse_metadata] output change from %d to %d\n", |
| dolby_vision_mode, current_mode); |
| dolby_vision_mode = current_mode; |
| if (is_dolby_vision_stb_mode()) |
| new_dovi_setting.mode_changed = 1; |
| } |
| |
| if (dolby_vision_mode == DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| new_dovi_setting.video_width = 0; |
| new_dovi_setting.video_height = 0; |
| new_dovi_setting.mode_changed = 0; |
| return -1; |
| } |
| |
| if (!p_funcs) |
| return -1; |
| |
| /* TV core */ |
| if (is_meson_txlx_tvmode() && !force_stb_mode) { |
| if (src_format != ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format) |
| pq_config_set_flag = false; |
| if (!pq_config_set_flag) { |
| if ((dolby_vision_flags & FLAG_FORCE_DOVI_LL) |
| || (req.low_latency == 1)) |
| memcpy(&(((struct pq_config_s *) |
| pq_config_fake)->target_display_config), |
| &def_tgt_display_cfg_ll, |
| sizeof(def_tgt_display_cfg_ll)); |
| else |
| memcpy(&(((struct pq_config_s *) |
| pq_config_fake)->target_display_config), |
| &def_tgt_display_cfg, |
| sizeof(def_tgt_display_cfg)); |
| pq_config_set_flag = true; |
| } |
| calculate_panel_max_pq( |
| vinfo, |
| &(((struct pq_config_s *) |
| pq_config_fake)->target_display_config)); |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->video_width = w << 16; |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->video_height = h << 16; |
| ((struct pq_config_s *) |
| pq_config_fake)->target_display_config.tuningMode = |
| dolby_vision_tunning_mode; |
| if (dolby_vision_flags & FLAG_DISABLE_COMPOSER) { |
| ((struct pq_config_s *)pq_config_fake) |
| ->target_display_config.tuningMode |= |
| TUNINGMODE_EL_FORCEDDISABLE; |
| el_halfsize_flag = 0; |
| } else |
| ((struct pq_config_s *)pq_config_fake) |
| ->target_display_config.tuningMode &= |
| (~TUNINGMODE_EL_FORCEDDISABLE); |
| #ifdef V1_5 |
| /* disable global dimming */ |
| if (dolby_vision_flags & FLAG_CERTIFICAION) |
| ((struct pq_config_s *)pq_config_fake) |
| ->target_display_config.tuningMode &= |
| (~TUNINGMODE_EXTLEVEL4_DISABLE); |
| else |
| ((struct pq_config_s *)pq_config_fake) |
| ->target_display_config.tuningMode |= |
| TUNINGMODE_EXTLEVEL4_DISABLE; |
| |
| if (src_format != ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format) { |
| if (p_funcs->tv_control_path) |
| p_funcs->tv_control_path( |
| FORMAT_INVALID, 0, |
| NULL, 0, |
| NULL, 0, |
| 0, 0, |
| SIG_RANGE_SMPTE, |
| NULL, NULL, |
| 0, |
| NULL, |
| NULL); |
| } |
| #endif |
| if (!p_funcs->tv_control_path) |
| return -1; |
| flag = p_funcs->tv_control_path( |
| src_format, input_mode, |
| comp_buf[currentId], total_comp_size, |
| md_buf[currentId], total_md_size, |
| src_bdp, |
| src_chroma_format, |
| SIG_RANGE_SMPTE, /* bit/chroma/range */ |
| (struct pq_config_s *)pq_config_fake, &menu_param, |
| (!el_flag) || |
| (dolby_vision_flags & FLAG_DISABLE_COMPOSER), |
| &hdr10_param, |
| tv_dovi_setting); |
| if (flag >= 0) { |
| if (input_mode == INPUT_MODE_HDMI) { |
| if (h > 1080) |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting) |
| ->core1_reg_lut[1] = |
| 0x0000000100000043; |
| else |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting) |
| ->core1_reg_lut[1] = |
| 0x0000000100000042; |
| } else { |
| if (src_format == FORMAT_HDR10) |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting) |
| ->core1_reg_lut[1] = |
| 0x000000010000404c; |
| else if (el_halfsize_flag) |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting) |
| ->core1_reg_lut[1] = |
| 0x000000010000004c; |
| else |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting) |
| ->core1_reg_lut[1] = |
| 0x0000000100000044; |
| } |
| /* enable CRC */ |
| if (dolby_vision_flags & FLAG_CERTIFICAION) |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->core1_reg_lut[3] = |
| 0x000000ea00000001; |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format = src_format; |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->el_flag = el_flag; |
| ((struct tv_dovi_setting_s *)tv_dovi_setting) |
| ->el_halfsize_flag = el_halfsize_flag; |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->video_width = w; |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->video_height = h; |
| ((struct tv_dovi_setting_s *)tv_dovi_setting) |
| ->input_mode = input_mode; |
| tv_dovi_setting_change_flag = true; |
| dovi_setting_video_flag = video_frame; |
| if (debug_dolby & 1) { |
| if (el_flag) |
| pr_dolby_dbg("tv setting %s-%d: flag=%02x,md=%d,comp=%d\n", |
| input_mode == INPUT_MODE_HDMI ? |
| "hdmi" : "ott", |
| src_format, |
| flag, |
| total_md_size, |
| total_comp_size); |
| else |
| pr_dolby_dbg("tv setting %s-%d: flag=%02x,md=%d\n", |
| input_mode == INPUT_MODE_HDMI ? |
| "hdmi" : "ott", |
| src_format, |
| flag, |
| total_md_size); |
| } |
| dump_tv_setting( |
| (struct tv_dovi_setting_s *)tv_dovi_setting, |
| frame_count, debug_dolby); |
| el_mode = el_flag; |
| ret = 0; /* setting updated */ |
| } else { |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->video_width = 0; |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->video_height = 0; |
| pr_dolby_error("tv_control_path() failed\n"); |
| } |
| return ret; |
| } |
| |
| /* STB core */ |
| /* check target luminance */ |
| if (is_graphics_output_off()) { |
| graphic_min = 0; |
| graphic_max = 0; |
| is_osd_off = true; |
| } else { |
| graphic_min = dolby_vision_graphic_min; |
| graphic_max = dolby_vision_graphic_max; |
| /* force reset core2 when osd off->on */ |
| /* TODO: 962e need ? */ |
| if (is_osd_off) |
| force_reset_core2 = true; |
| if (new_dovi_setting.mode_changed) |
| force_reset_core2 = true; |
| is_osd_off = false; |
| } |
| if (dolby_vision_flags & FLAG_USE_SINK_MIN_MAX) { |
| if (vinfo->vout_device->dv_info->ieeeoui == 0x00d046) { |
| if (vinfo->vout_device->dv_info->ver == 0) { |
| /* need lookup PQ table ... */ |
| } else if (vinfo->vout_device->dv_info->ver == 1) { |
| if (vinfo->vout_device->dv_info->tmaxLUM) { |
| /* Target max luminance = 100+50*CV */ |
| graphic_max = |
| target_lumin_max = |
| (vinfo->vout_device |
| ->dv_info->tmaxLUM |
| * 50 + 100); |
| /* Target min luminance = (CV/127)^2 */ |
| graphic_min = |
| dolby_vision_target_min = |
| (vinfo->vout_device-> |
| dv_info->tminLUM ^ 2) |
| * 10000 / (127 * 127); |
| } |
| } |
| } else if (vinfo->hdr_info.hdr_support & 4) { |
| if (vinfo->hdr_info.lumi_max) { |
| /* Luminance value = 50 * (2 ^ (CV/32)) */ |
| graphic_max = |
| target_lumin_max = 50 * |
| (2 ^ (vinfo->hdr_info.lumi_max >> 5)); |
| /* Desired Content Min Luminance =*/ |
| /* Desired Content Max Luminance*/ |
| /* * (CV/255) * (CV/255) / 100 */ |
| graphic_min = |
| dolby_vision_target_min = |
| target_lumin_max * 10000 |
| * vinfo->hdr_info.lumi_min |
| * vinfo->hdr_info.lumi_min |
| / (255 * 255 * 100); |
| } |
| } |
| if (target_lumin_max) { |
| dolby_vision_target_max[0][0] = |
| dolby_vision_target_max[0][1] = |
| dolby_vision_target_max[1][0] = |
| dolby_vision_target_max[1][1] = |
| dolby_vision_target_max[2][0] = |
| dolby_vision_target_max[2][1] = |
| target_lumin_max; |
| } else { |
| memcpy( |
| dolby_vision_target_max, |
| dolby_vision_default_max, |
| sizeof(dolby_vision_target_max)); |
| } |
| } |
| |
| /* check dst format */ |
| if ((dolby_vision_mode == DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) |
| || (dolby_vision_mode == DOLBY_VISION_OUTPUT_MODE_IPT)) |
| dst_format = FORMAT_DOVI; |
| else if (dolby_vision_mode == DOLBY_VISION_OUTPUT_MODE_HDR10) |
| dst_format = FORMAT_HDR10; |
| else |
| dst_format = FORMAT_SDR; |
| #ifdef V2_4 |
| if ((src_format != dovi_setting.src_format) |
| || (dst_format != dovi_setting.dst_format) || |
| ((!(dolby_vision_flags & FLAG_CERTIFICAION)) |
| && (frame_count == 0))) |
| p_funcs->control_path( |
| FORMAT_INVALID, 0, |
| comp_buf[currentId], 0, |
| md_buf[currentId], 0, |
| 0, 0, 0, SIG_RANGE_SMPTE, |
| 0, 0, 0, 0, |
| 0, |
| &hdr10_param, |
| &new_dovi_setting); |
| if (!vsvdb_config_set_flag) { |
| memset(&new_dovi_setting.vsvdb_tbl[0], |
| 0, sizeof(new_dovi_setting.vsvdb_tbl)); |
| new_dovi_setting.vsvdb_len = 0; |
| new_dovi_setting.vsvdb_changed = 1; |
| vsvdb_config_set_flag = true; |
| } |
| if ((dolby_vision_flags & |
| FLAG_DISABLE_LOAD_VSVDB) == 0) { |
| /* check if vsvdb is changed */ |
| if (vinfo && vinfo->vout_device && |
| vinfo->vout_device->dv_info && |
| (vinfo->vout_device->dv_info->ieeeoui == 0x00d046) |
| && (vinfo->vout_device->dv_info |
| ->block_flag == CORRECT)) { |
| if (new_dovi_setting.vsvdb_len |
| != vinfo->vout_device->dv_info->length + 1) |
| new_dovi_setting.vsvdb_changed = 1; |
| else if (memcmp(&new_dovi_setting.vsvdb_tbl[0], |
| &vinfo->vout_device->dv_info->rawdata[0], |
| vinfo->vout_device->dv_info->length + 1)) |
| new_dovi_setting.vsvdb_changed = 1; |
| memset(&new_dovi_setting.vsvdb_tbl[0], |
| 0, sizeof(new_dovi_setting.vsvdb_tbl)); |
| memcpy(&new_dovi_setting.vsvdb_tbl[0], |
| &vinfo->vout_device->dv_info->rawdata[0], |
| vinfo->vout_device->dv_info->length + 1); |
| new_dovi_setting.vsvdb_len = |
| vinfo->vout_device->dv_info->length + 1; |
| if (new_dovi_setting.vsvdb_changed |
| && new_dovi_setting.vsvdb_len) { |
| int k = 0; |
| |
| pr_dolby_dbg( |
| "new vsvdb[%d]:\n", |
| new_dovi_setting.vsvdb_len); |
| pr_dolby_dbg( |
| "---%02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n", |
| new_dovi_setting.vsvdb_tbl[k + 0], |
| new_dovi_setting.vsvdb_tbl[k + 1], |
| new_dovi_setting.vsvdb_tbl[k + 2], |
| new_dovi_setting.vsvdb_tbl[k + 3], |
| new_dovi_setting.vsvdb_tbl[k + 4], |
| new_dovi_setting.vsvdb_tbl[k + 5], |
| new_dovi_setting.vsvdb_tbl[k + 6], |
| new_dovi_setting.vsvdb_tbl[k + 7]); |
| k += 8; |
| pr_dolby_dbg( |
| "---%02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n", |
| new_dovi_setting.vsvdb_tbl[k + 0], |
| new_dovi_setting.vsvdb_tbl[k + 1], |
| new_dovi_setting.vsvdb_tbl[k + 2], |
| new_dovi_setting.vsvdb_tbl[k + 3], |
| new_dovi_setting.vsvdb_tbl[k + 4], |
| new_dovi_setting.vsvdb_tbl[k + 5], |
| new_dovi_setting.vsvdb_tbl[k + 6], |
| new_dovi_setting.vsvdb_tbl[k + 7]); |
| k += 8; |
| pr_dolby_dbg( |
| "---%02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n", |
| new_dovi_setting.vsvdb_tbl[k + 0], |
| new_dovi_setting.vsvdb_tbl[k + 1], |
| new_dovi_setting.vsvdb_tbl[k + 2], |
| new_dovi_setting.vsvdb_tbl[k + 3], |
| new_dovi_setting.vsvdb_tbl[k + 4], |
| new_dovi_setting.vsvdb_tbl[k + 5], |
| new_dovi_setting.vsvdb_tbl[k + 6], |
| new_dovi_setting.vsvdb_tbl[k + 7]); |
| k += 8; |
| pr_dolby_dbg( |
| "---%02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n", |
| new_dovi_setting.vsvdb_tbl[k + 0], |
| new_dovi_setting.vsvdb_tbl[k + 1], |
| new_dovi_setting.vsvdb_tbl[k + 2], |
| new_dovi_setting.vsvdb_tbl[k + 3], |
| new_dovi_setting.vsvdb_tbl[k + 4], |
| new_dovi_setting.vsvdb_tbl[k + 5], |
| new_dovi_setting.vsvdb_tbl[k + 6], |
| new_dovi_setting.vsvdb_tbl[k + 7]); |
| } |
| } else { |
| if (new_dovi_setting.vsvdb_len) |
| new_dovi_setting.vsvdb_changed = 1; |
| memset(&new_dovi_setting.vsvdb_tbl[0], |
| 0, sizeof(new_dovi_setting.vsvdb_tbl)); |
| new_dovi_setting.vsvdb_len = 0; |
| } |
| } |
| if (dolby_vision_graphics_priority || |
| (dolby_vision_flags & |
| FLAG_PRIORITY_GRAPHIC)) |
| pri_mode = GRAPHIC_PRIORITY; |
| else |
| pri_mode = VIDEO_PRIORITY; |
| |
| if (dst_format == FORMAT_DOVI) { |
| if ((dolby_vision_flags |
| & FLAG_FORCE_DOVI_LL) || |
| (dolby_vision_ll_policy |
| >= DOLBY_VISION_LL_YUV422)) |
| new_dovi_setting.use_ll_flag = 1; |
| else |
| new_dovi_setting.use_ll_flag = 0; |
| if ((dolby_vision_ll_policy == |
| DOLBY_VISION_LL_RGB444) |
| || (dolby_vision_flags |
| & FLAG_FORCE_RGB_OUTPUT)) |
| new_dovi_setting.ll_rgb_desired = 1; |
| else |
| new_dovi_setting.ll_rgb_desired = 0; |
| } else { |
| new_dovi_setting.use_ll_flag = 0; |
| new_dovi_setting.ll_rgb_desired = 0; |
| } |
| if ((dst_format == FORMAT_HDR10) && |
| (dolby_vision_flags & FLAG_DOVI2HDR10_NOMAPPING)) |
| new_dovi_setting.dovi2hdr10_nomapping = 1; |
| else |
| new_dovi_setting.dovi2hdr10_nomapping = 0; |
| |
| /* always use rgb setting */ |
| #if 1 |
| new_dovi_setting.g_bitdepth = 8; |
| new_dovi_setting.g_format = GF_SDR_RGB; |
| #else |
| if (dolby_vision_flags & FLAG_CERTIFICAION) { |
| new_dovi_setting.g_bitdepth = 8; |
| new_dovi_setting.g_format = GF_SDR_RGB; |
| } else { |
| new_dovi_setting.g_bitdepth = 10; |
| new_dovi_setting.g_format = GF_SDR_YUV; |
| } |
| #endif |
| new_dovi_setting.diagnostic_enable = 0; |
| new_dovi_setting.diagnostic_mux_select = 0; |
| new_dovi_setting.dovi_ll_enable = 0; |
| if (vinfo) { |
| new_dovi_setting.vout_width = vinfo->width; |
| new_dovi_setting.vout_height = vinfo->height; |
| } else { |
| new_dovi_setting.vout_width = 0; |
| new_dovi_setting.vout_height = 0; |
| } |
| memset(&new_dovi_setting.ext_md, 0, sizeof(struct ext_md_s)); |
| #endif |
| new_dovi_setting.video_width = w << 16; |
| new_dovi_setting.video_height = h << 16; |
| flag = p_funcs->control_path( |
| src_format, dst_format, |
| comp_buf[currentId], |
| ((src_format == FORMAT_DOVI) |
| || (src_format == FORMAT_DOVI_LL)) ? total_comp_size : 0, |
| md_buf[currentId], |
| ((src_format == FORMAT_DOVI) |
| || (src_format == FORMAT_DOVI_LL)) ? total_md_size : 0, |
| pri_mode, |
| src_bdp, 0, SIG_RANGE_SMPTE, /* bit/chroma/range */ |
| graphic_min, |
| graphic_max * 10000, |
| dolby_vision_target_min, |
| dolby_vision_target_max[src_format][dst_format] * 10000, |
| (!el_flag) || |
| (dolby_vision_flags & FLAG_DISABLE_COMPOSER), |
| &hdr10_param, |
| &new_dovi_setting); |
| if (flag >= 0) { |
| #ifdef V2_4 |
| stb_core_setting_update_flag = flag; |
| if ((dolby_vision_flags |
| & FLAG_FORCE_DOVI_LL) |
| && (dst_format == FORMAT_DOVI)) |
| new_dovi_setting.dovi_ll_enable = 1; |
| if ((dolby_vision_flags |
| & FLAG_FORCE_RGB_OUTPUT) |
| && (dst_format == FORMAT_DOVI)) { |
| new_dovi_setting.dovi_ll_enable = 1; |
| new_dovi_setting.diagnostic_enable = 1; |
| new_dovi_setting.diagnostic_mux_select = 1; |
| } |
| if (debug_dolby & 2) |
| pr_dolby_dbg( |
| "ll_enable=%d,diagnostic=%d,ll_policy=%d\n", |
| new_dovi_setting.dovi_ll_enable, |
| new_dovi_setting.diagnostic_enable, |
| dolby_vision_ll_policy); |
| #endif |
| new_dovi_setting.src_format = src_format; |
| new_dovi_setting.dst_format = dst_format; |
| new_dovi_setting.el_flag = el_flag; |
| new_dovi_setting.el_halfsize_flag = el_halfsize_flag; |
| new_dovi_setting.video_width = w; |
| new_dovi_setting.video_height = h; |
| dovi_setting_video_flag = video_frame; |
| if (debug_dolby & 1) { |
| if (el_flag) |
| pr_dolby_dbg("setting %d->%d(T:%d-%d): flag=%x,md=%d,comp=%d, frame:%d\n", |
| src_format, dst_format, |
| dolby_vision_target_min, |
| dolby_vision_target_max[src_format][dst_format], |
| flag, |
| total_md_size, total_comp_size, |
| frame_count); |
| else |
| pr_dolby_dbg("setting %d->%d(T:%d-%d): flag=%x,md=%d, frame:%d\n", |
| src_format, dst_format, |
| dolby_vision_target_min, |
| dolby_vision_target_max[src_format][dst_format], |
| flag, |
| total_md_size, frame_count); |
| } |
| dump_setting(&new_dovi_setting, frame_count, debug_dolby); |
| el_mode = el_flag; |
| return 0; /* setting updated */ |
| } |
| if (flag < 0) { |
| new_dovi_setting.video_width = 0; |
| new_dovi_setting.video_height = 0; |
| pr_dolby_error("control_path() failed\n"); |
| } |
| return -1; /* do nothing for this frame */ |
| } |
| EXPORT_SYMBOL(dolby_vision_parse_metadata); |
| |
| /* 0: no el; >0: with el */ |
| /* 1: need wait el vf */ |
| /* 2: no match el found */ |
| /* 3: found match el */ |
| int dolby_vision_wait_metadata(struct vframe_s *vf) |
| { |
| struct provider_aux_req_s req; |
| struct vframe_s *el_vf; |
| int ret = 0; |
| unsigned int mode = dolby_vision_mode; |
| |
| if (single_step_enable) { |
| if (dolby_vision_flags & FLAG_SINGLE_STEP) |
| /* wait fake el for "step" */ |
| return 1; |
| |
| dolby_vision_flags |= FLAG_SINGLE_STEP; |
| } |
| |
| if (dolby_vision_flags & FLAG_CERTIFICAION) { |
| bool ott_mode = true; |
| |
| if (is_meson_txlx_tvmode() |
| && !force_stb_mode) |
| ott_mode = |
| (((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->input_mode != |
| INPUT_MODE_HDMI); |
| if ((setting_update_count > crc_count) |
| && (ott_mode == true)) |
| return 1; |
| } |
| |
| req.vf = vf; |
| req.bot_flag = 0; |
| req.aux_buf = NULL; |
| req.aux_size = 0; |
| req.dv_enhance_exist = 0; |
| |
| if (vf->source_type == VFRAME_SOURCE_TYPE_OTHERS) |
| vf_notify_provider_by_name("dvbldec", |
| VFRAME_EVENT_RECEIVER_GET_AUX_DATA, |
| (void *)&req); |
| if (req.dv_enhance_exist) { |
| el_vf = dvel_vf_peek(); |
| while (el_vf) { |
| if (debug_dolby & 2) |
| pr_dolby_dbg("=== peek bl(%p-%lld) with el(%p-%lld) ===\n", |
| vf, vf->pts_us64, |
| el_vf, el_vf->pts_us64); |
| if ((el_vf->pts_us64 == vf->pts_us64) |
| || !(dolby_vision_flags & FLAG_CHECK_ES_PTS)) { |
| /* found el */ |
| ret = 3; |
| break; |
| } else if (el_vf->pts_us64 < vf->pts_us64) { |
| if (debug_dolby & 2) |
| pr_dolby_dbg("bl(%p-%lld) => skip el pts(%p-%lld)\n", |
| vf, vf->pts_us64, |
| el_vf, el_vf->pts_us64); |
| el_vf = dvel_vf_get(); |
| dvel_vf_put(el_vf); |
| vf_notify_provider(DVEL_RECV_NAME, |
| VFRAME_EVENT_RECEIVER_PUT, NULL); |
| if (debug_dolby & 2) |
| pr_dolby_dbg("=== get & put el(%p-%lld) ===\n", |
| el_vf, el_vf->pts_us64); |
| |
| /* skip old el and peek new */ |
| el_vf = dvel_vf_peek(); |
| } else { |
| /* no el found */ |
| ret = 2; |
| break; |
| } |
| } |
| /* need wait el */ |
| if (el_vf == NULL) { |
| if (debug_dolby & 2) |
| pr_dolby_dbg( |
| "=== bl wait el(%p-%lld) ===\n", |
| vf, vf->pts_us64); |
| ret = 1; |
| } |
| } |
| if (ret == 1) |
| return ret; |
| |
| if (!dolby_vision_wait_init |
| && !dolby_vision_core1_on) { |
| if (is_dovi_frame(vf)) { |
| if (dolby_vision_policy_process( |
| &mode, FORMAT_DOVI)) { |
| if ((mode != DOLBY_VISION_OUTPUT_MODE_BYPASS) |
| && (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_BYPASS)) { |
| dolby_vision_wait_init = true; |
| dolby_vision_wait_count = |
| dolby_vision_wait_delay; |
| dolby_vision_wait_on = true; |
| } |
| } |
| } else if (is_hdr10_frame(vf)) { |
| if (dolby_vision_policy_process( |
| &mode, FORMAT_HDR10)) { |
| if ((mode != DOLBY_VISION_OUTPUT_MODE_BYPASS) |
| && (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_BYPASS)) { |
| dolby_vision_wait_init = true; |
| dolby_vision_wait_count = |
| dolby_vision_wait_delay; |
| dolby_vision_wait_on = true; |
| } |
| } |
| } else if (dolby_vision_policy_process( |
| &mode, FORMAT_SDR)) { |
| if ((mode != DOLBY_VISION_OUTPUT_MODE_BYPASS) |
| && (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_BYPASS)) { |
| dolby_vision_wait_init = true; |
| dolby_vision_wait_count = |
| dolby_vision_wait_delay; |
| dolby_vision_wait_on = true; |
| } |
| } |
| /* don't use run mode when sdr -> dv and vd1 not disable */ |
| if (dolby_vision_wait_init && |
| (READ_VPP_REG(VPP_MISC) & (1<<10))) |
| dolby_vision_on_count = |
| dolby_vision_run_mode_delay + 1; |
| } |
| if (dolby_vision_wait_init |
| && dolby_vision_wait_count) { |
| dolby_vision_wait_count--; |
| pr_dolby_dbg("delay wait %d\n", |
| dolby_vision_wait_count); |
| ret = 1; |
| } else if (dolby_vision_core1_on |
| && (dolby_vision_on_count <= |
| dolby_vision_run_mode_delay)) |
| ret = 1; |
| |
| return ret; |
| } |
| |
| int dolby_vision_update_metadata(struct vframe_s *vf) |
| { |
| int ret = -1; |
| |
| if (!dolby_vision_enable) |
| return -1; |
| if (vf && dolby_vision_vf_check(vf)) { |
| ret = dolby_vision_parse_metadata( |
| vf, 1, false); |
| frame_count++; |
| } |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(dolby_vision_update_metadata); |
| |
| static void update_dolby_vision_status(enum signal_format_e src_format) |
| { |
| if (((src_format == FORMAT_DOVI) |
| || (src_format == FORMAT_DOVI_LL)) |
| && (dolby_vision_status != DV_PROCESS)) { |
| pr_dolby_dbg( |
| "Dolby Vision mode changed to DV_PROCESS %d\n", |
| src_format); |
| dolby_vision_status = DV_PROCESS; |
| } else if ((src_format == FORMAT_HDR10) |
| && (dolby_vision_status != HDR_PROCESS)) { |
| pr_dolby_dbg( |
| "Dolby Vision mode changed to HDR_PROCESS %d\n", |
| src_format); |
| dolby_vision_status = HDR_PROCESS; |
| } else if ((src_format == FORMAT_SDR) |
| && (dolby_vision_status != SDR_PROCESS)) { |
| pr_dolby_dbg( |
| "Dolby Vision mode changed to SDR_PROCESS %d\n", |
| src_format); |
| dolby_vision_status = SDR_PROCESS; |
| } |
| } |
| |
| static u8 last_pps_state; |
| static void bypass_pps_path(u8 pps_state) |
| { |
| if (is_meson_txlx_package_962E() |
| || force_stb_mode) { |
| if (pps_state == 2) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 1, 0, 1); |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x08000800); |
| } else if (pps_state == 1) { |
| _VSYNC_WR_MPEG_REG_BITS( |
| VPP_DOLBY_CTRL, 0, 0, 1); |
| _VSYNC_WR_MPEG_REG( |
| VPP_DAT_CONV_PARA0, 0x20002000); |
| } |
| } |
| if (pps_state && last_pps_state != pps_state) { |
| pr_dolby_dbg("pps_state %d => %d\n", |
| last_pps_state, pps_state); |
| last_pps_state = pps_state; |
| } |
| } |
| |
| static unsigned int last_dolby_vision_policy; |
| int dolby_vision_process(struct vframe_s *vf, u32 display_size, |
| u8 pps_state) /* 0: no change, 1: pps enable, 2: pps disable */ |
| { |
| int src_chroma_format = 0; |
| u32 h_size = (display_size >> 16) & 0xffff; |
| u32 v_size = display_size & 0xffff; |
| const struct vinfo_s *vinfo = get_current_vinfo(); |
| bool reset_flag = false; |
| bool force_set = false; |
| |
| if (!is_meson_gxm() && !is_meson_txlx() |
| && !is_meson_g12()) |
| return -1; |
| |
| if (dolby_vision_flags & FLAG_CERTIFICAION) { |
| if (vf) { |
| h_size = (vf->type & VIDTYPE_COMPRESS) ? |
| vf->compWidth : vf->width; |
| v_size = (vf->type & VIDTYPE_COMPRESS) ? |
| vf->compHeight : vf->height; |
| } else { |
| h_size = 0; |
| v_size = 0; |
| } |
| dolby_vision_on_count = 1 + |
| dolby_vision_run_mode_delay; |
| } |
| |
| if ((core1_disp_hsize != h_size) |
| || (core1_disp_vsize != v_size)) |
| force_set = true; |
| |
| if ((dolby_vision_flags & FLAG_CERTIFICAION) |
| && (setting_update_count > crc_count) |
| && is_dolby_vision_on()) { |
| s32 delay_count = |
| (dolby_vision_flags >> |
| FLAG_FRAME_DELAY_SHIFT) |
| & FLAG_FRAME_DELAY_MASK; |
| bool ott_mode = true; |
| |
| if (is_meson_txlx_tvmode() |
| && !force_stb_mode) |
| ott_mode = |
| (((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->input_mode != |
| INPUT_MODE_HDMI); |
| if ((is_meson_txlx_stbmode() |
| || is_meson_gxm() |
| || is_meson_g12() |
| || force_stb_mode) |
| && (setting_update_count == 1) |
| && (crc_read_delay == 1)) { |
| /* work around to enable crc for frame 0 */ |
| _VSYNC_WR_MPEG_REG(0x36fb, 1); |
| crc_read_delay++; |
| } else { |
| crc_read_delay++; |
| if ((crc_read_delay > delay_count) |
| && (ott_mode == true)) { |
| tv_dolby_vision_insert_crc( |
| (crc_count == 0) ? true : false); |
| crc_read_delay = 0; |
| } |
| } |
| } |
| |
| if (dolby_vision_on |
| && is_video_output_off(vf) |
| && !video_off_handled) { |
| dolby_vision_set_toggle_flag(1); |
| frame_count = 0; |
| if (debug_dolby & 2) { |
| video_off_handled = 1; |
| pr_dolby_dbg("video off\n"); |
| } |
| } |
| |
| if (last_dolby_vision_policy != dolby_vision_policy) { |
| /* handle policy change */ |
| dolby_vision_set_toggle_flag(1); |
| last_dolby_vision_policy = dolby_vision_policy; |
| } |
| |
| #ifdef V2_4 |
| if (is_meson_txlx_stbmode() |
| || is_meson_gxm() |
| || is_meson_g12() |
| || force_stb_mode) { |
| if (last_dolby_vision_ll_policy |
| != dolby_vision_ll_policy) { |
| /* handle ll mode policy change */ |
| dolby_vision_set_toggle_flag(1); |
| } |
| } |
| #endif |
| if (!vf) { |
| if (dolby_vision_flags & FLAG_TOGGLE_FRAME) |
| dolby_vision_parse_metadata( |
| NULL, 1, false); |
| } |
| if (dolby_vision_mode == DOLBY_VISION_OUTPUT_MODE_BYPASS) { |
| if (vinfo && sink_support_dolby_vision(vinfo)) |
| dolby_vision_set_toggle_flag(1); |
| if (!is_meson_txlx_tvmode() || force_stb_mode) { |
| if (vinfo && vinfo->vout_device && |
| (!vinfo->vout_device->dv_info) |
| && (vsync_count < FLAG_VSYNC_CNT)) { |
| vsync_count++; |
| return 0; |
| } |
| } |
| if (dolby_vision_status != BYPASS_PROCESS) { |
| enable_dolby_vision(0); |
| if (vinfo && |
| !is_meson_txlx_tvmode() && |
| !force_stb_mode) |
| send_hdmi_pkt(FORMAT_SDR, vinfo); |
| if (dolby_vision_flags & FLAG_TOGGLE_FRAME) |
| dolby_vision_flags &= ~FLAG_TOGGLE_FRAME; |
| } |
| return 0; |
| } |
| |
| if ((dolby_vision_flags & FLAG_CERTIFICAION) |
| || (dolby_vision_flags & FLAG_BYPASS_VPP)) |
| video_effect_bypass(1); |
| |
| if (!p_funcs) { |
| dolby_vision_flags &= ~FLAG_TOGGLE_FRAME; |
| tv_dovi_setting_change_flag = false; |
| new_dovi_setting.video_width = 0; |
| new_dovi_setting.video_height = 0; |
| return 0; |
| } |
| if ((debug_dolby & 2) && force_set |
| && !(dolby_vision_flags & FLAG_CERTIFICAION)) |
| pr_dolby_dbg( |
| "core1 size changed--old: %d x %d, new: %d x %d\n", |
| core1_disp_hsize, core1_disp_vsize, |
| h_size, v_size); |
| if (dolby_vision_flags & FLAG_TOGGLE_FRAME) { |
| if (!(dolby_vision_flags & FLAG_CERTIFICAION)) |
| reset_flag = |
| (dolby_vision_reset & 1) |
| && (!dolby_vision_core1_on) |
| && (dolby_vision_on_count == 0); |
| if (is_meson_txlx_tvmode() && !force_stb_mode) { |
| if (tv_dovi_setting_change_flag) { |
| if (vf && (vf->type & VIDTYPE_VIU_422)) |
| src_chroma_format = 2; |
| else if (vf) |
| src_chroma_format = 1; |
| if (force_set && |
| !(dolby_vision_flags |
| & FLAG_CERTIFICAION)) |
| reset_flag = true; |
| tv_dolby_core1_set( |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->core1_reg_lut, |
| h_size, |
| v_size, |
| dovi_setting_video_flag, /* BL enable */ |
| dovi_setting_video_flag |
| && (((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->el_flag), /* EL en */ |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->el_halfsize_flag, |
| src_chroma_format, |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->input_mode == |
| INPUT_MODE_HDMI, |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format == |
| FORMAT_HDR10, |
| reset_flag |
| ); |
| if (!h_size || !v_size) |
| dovi_setting_video_flag = false; |
| if (dovi_setting_video_flag |
| && (dolby_vision_on_count == 0)) |
| pr_dolby_dbg("first frame reset %d\n", |
| reset_flag); |
| enable_dolby_vision(1); |
| tv_dovi_setting_change_flag = false; |
| core1_disp_hsize = h_size; |
| core1_disp_vsize = v_size; |
| update_dolby_vision_status( |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format); |
| } |
| } else { |
| if ((new_dovi_setting.video_width & 0xffff) |
| && (new_dovi_setting.video_height & 0xffff)) { |
| if (force_set && |
| !(dolby_vision_flags |
| & FLAG_CERTIFICAION)) |
| reset_flag = true; |
| apply_stb_core_settings( |
| dovi_setting_video_flag, |
| dolby_vision_mask & 0x7, |
| reset_flag, |
| (h_size << 16) | v_size, |
| pps_state); |
| memcpy(&dovi_setting, &new_dovi_setting, |
| sizeof(dovi_setting)); |
| new_dovi_setting.video_width = |
| new_dovi_setting.video_height = 0; |
| if (!h_size || !v_size) |
| dovi_setting_video_flag = false; |
| if (dovi_setting_video_flag |
| && (dolby_vision_on_count == 0)) |
| pr_dolby_dbg("first frame reset %d\n", |
| reset_flag); |
| enable_dolby_vision(1); |
| bypass_pps_path(pps_state); |
| core1_disp_hsize = h_size; |
| core1_disp_vsize = v_size; |
| /* send HDMI packet according to dst_format */ |
| if (vinfo && !force_stb_mode) |
| send_hdmi_pkt( |
| dovi_setting.dst_format, vinfo); |
| update_dolby_vision_status( |
| dovi_setting.src_format); |
| } |
| } |
| dolby_vision_flags &= ~FLAG_TOGGLE_FRAME; |
| } else if (dolby_vision_core1_on && |
| !(dolby_vision_flags & FLAG_CERTIFICAION)) { |
| bool reset_flag = |
| (dolby_vision_reset & 2) |
| && (dolby_vision_on_count |
| <= (dolby_vision_reset_delay >> 8)) |
| && (dolby_vision_on_count |
| >= (dolby_vision_reset_delay & 0xff)); |
| if (is_meson_txlx_stbmode() |
| || force_stb_mode) { |
| if ((dolby_vision_on_count <= |
| dolby_vision_run_mode_delay) |
| || force_set) { |
| if (force_set) |
| reset_flag = true; |
| apply_stb_core_settings( |
| dovi_setting_video_flag, |
| /* core 1 only */ |
| dolby_vision_mask & 0x1, |
| reset_flag, |
| (h_size << 16) | v_size, |
| pps_state); |
| bypass_pps_path(pps_state); |
| core1_disp_hsize = h_size; |
| core1_disp_vsize = v_size; |
| if (dolby_vision_on_count <= |
| dolby_vision_run_mode_delay) |
| pr_dolby_dbg("fake frame %d reset %d\n", |
| dolby_vision_on_count, |
| reset_flag); |
| } |
| } else if (is_meson_txlx_tvmode()) { |
| if ((dolby_vision_on_count <= |
| dolby_vision_run_mode_delay) |
| || force_set) { |
| if (force_set) |
| reset_flag = true; |
| tv_dolby_core1_set( |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->core1_reg_lut, |
| h_size, |
| v_size, |
| dovi_setting_video_flag, /* BL enable */ |
| dovi_setting_video_flag && |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->el_flag, /*ELenable*/ |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->el_halfsize_flag, |
| src_chroma_format, |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->input_mode == |
| INPUT_MODE_HDMI, |
| ((struct tv_dovi_setting_s *) |
| tv_dovi_setting)->src_format == |
| FORMAT_HDR10, |
| reset_flag); |
| core1_disp_hsize = h_size; |
| core1_disp_vsize = v_size; |
| if (dolby_vision_on_count <= |
| dolby_vision_run_mode_delay) |
| pr_dolby_dbg("fake frame %d reset %d\n", |
| dolby_vision_on_count, |
| reset_flag); |
| } |
| } else if (is_meson_gxm() || |
| is_meson_g12()) { |
| if ((dolby_vision_on_count <= |
| dolby_vision_run_mode_delay) |
| || force_set) { |
| if (force_set) |
| reset_flag = true; |
| apply_stb_core_settings( |
| true, /* always enable */ |
| /* core 1 only */ |
| dolby_vision_mask & 0x1, |
| reset_flag, |
| (h_size << 16) | v_size, |
| pps_state); |
| core1_disp_hsize = h_size; |
| core1_disp_vsize = v_size; |
| if (dolby_vision_on_count < |
| dolby_vision_run_mode_delay) |
| pr_dolby_dbg("fake frame %d reset %d\n", |
| dolby_vision_on_count, |
| reset_flag); |
| } |
| } |
| } |
| if (dolby_vision_core1_on) { |
| if (dolby_vision_on_count <= |
| dolby_vision_run_mode_delay) |
| dolby_vision_on_count++; |
| } else |
| dolby_vision_on_count = 0; |
| return 0; |
| } |
| EXPORT_SYMBOL(dolby_vision_process); |
| |
| bool is_dolby_vision_on(void) |
| { |
| return dolby_vision_on |
| || dolby_vision_wait_on; |
| } |
| EXPORT_SYMBOL(is_dolby_vision_on); |
| |
| bool for_dolby_vision_certification(void) |
| { |
| return is_dolby_vision_on() && |
| dolby_vision_flags & FLAG_CERTIFICAION; |
| } |
| EXPORT_SYMBOL(for_dolby_vision_certification); |
| |
| void dolby_vision_set_toggle_flag(int flag) |
| { |
| if (flag) |
| dolby_vision_flags |= FLAG_TOGGLE_FRAME; |
| else |
| dolby_vision_flags &= ~FLAG_TOGGLE_FRAME; |
| } |
| EXPORT_SYMBOL(dolby_vision_set_toggle_flag); |
| |
| void set_dolby_vision_mode(int mode) |
| { |
| if ((is_meson_gxm() || is_meson_txlx() || |
| is_meson_g12()) |
| && dolby_vision_enable |
| && (dolby_vision_request_mode == 0xff)) { |
| if (dolby_vision_policy_process( |
| &mode, FORMAT_SDR)) { |
| dolby_vision_set_toggle_flag(1); |
| if ((mode != DOLBY_VISION_OUTPUT_MODE_BYPASS) |
| && (dolby_vision_mode == |
| DOLBY_VISION_OUTPUT_MODE_BYPASS)) |
| dolby_vision_wait_on = true; |
| pr_info("DOVI output change from %d to %d\n", |
| dolby_vision_mode, mode); |
| dolby_vision_mode = mode; |
| } |
| } |
| } |
| EXPORT_SYMBOL(set_dolby_vision_mode); |
| |
| int get_dolby_vision_mode(void) |
| { |
| return dolby_vision_mode; |
| } |
| EXPORT_SYMBOL(get_dolby_vision_mode); |
| |
| bool is_dolby_vision_enable(void) |
| { |
| return dolby_vision_enable; |
| } |
| EXPORT_SYMBOL(is_dolby_vision_enable); |
| |
| bool is_dolby_vision_stb_mode(void) |
| { |
| return force_stb_mode || |
| is_meson_txlx_stbmode() || |
| is_meson_gxm() || |
| is_meson_g12(); |
| } |
| EXPORT_SYMBOL(is_dolby_vision_stb_mode); |
| |
| int register_dv_functions(const struct dolby_vision_func_s *func) |
| { |
| int ret = -1; |
| unsigned int reg_clk; |
| unsigned int reg_value; |
| struct pq_config_s *pq_config; |
| struct tv_dovi_setting_s *dovi_setting; |
| const struct vinfo_s *vinfo = get_current_vinfo(); |
| |
| if (!p_funcs && func) { |
| pr_info("*** register_dv_functions. version %s ***\n", |
| func->version_info); |
| ret = 0; |
| /* get efuse flag*/ |
| reg_clk = READ_VPP_REG(DOLBY_TV_CLKGATE_CTRL); |
| WRITE_VPP_REG(DOLBY_TV_CLKGATE_CTRL, 0x2800); |
| reg_value = READ_VPP_REG(DOLBY_TV_REG_START + 1); |
| if (is_meson_txlx_tvmode() |
| || is_meson_txlx_stbmode()) { |
| if ((reg_value & 0x400) == 0) |
| efuse_mode = 0; |
| else |
| efuse_mode = 1; |
| } else { |
| if ((reg_value & 0x100) == 0) |
| efuse_mode = 0; |
| else |
| efuse_mode = 1; |
| } |
| WRITE_VPP_REG(DOLBY_TV_CLKGATE_CTRL, reg_clk); |
| pr_dolby_dbg |
| ("efuse_mode=%d reg_value = 0x%x\n", |
| efuse_mode, |
| reg_value); |
| /*stb core doesn't need run mode*/ |
| /*TV core need run mode and the value is 2*/ |
| if (is_meson_gxm() || is_meson_g12() || |
| is_meson_txlx_stbmode() || force_stb_mode) |
| dolby_vision_run_mode_delay = 0; |
| else |
| dolby_vision_run_mode_delay = RUN_MODE_DELAY; |
| |
| pq_config = vmalloc(sizeof(struct pq_config_s)); |
| if (!pq_config) |
| return -ENOMEM; |
| |
| pq_config_fake = (struct pq_config_s *)pq_config; |
| dovi_setting = vmalloc(sizeof(struct tv_dovi_setting_s)); |
| if (!dovi_setting) |
| return -ENOMEM; |
| |
| tv_dovi_setting = (struct tv_dovi_setting_s *)dovi_setting; |
| /* adjust core2 setting to work around fixing with 1080p24hz */ |
| if (is_meson_txlx()) |
| g_vpotch = 0x20; |
| else if (is_meson_g12()) { |
| if (vinfo) { |
| if ((vinfo->width < 1280) && |
| (vinfo->height < 720) && |
| (vinfo->field_height < 720)) |
| g_vpotch = 0x60; |
| else |
| g_vpotch = 0x8; |
| } else |
| g_vpotch = 0x8; |
| } else |
| g_vpotch = 0x8; |
| p_funcs = func; |
| } |
| return ret; |
| } |
| EXPORT_SYMBOL(register_dv_functions); |
| |
| int unregister_dv_functions(void) |
| { |
| int ret = -1; |
| int i; |
| |
| for (i = 0; i < 2; i++) { |
| if (md_buf[i] != NULL) { |
| vfree(md_buf[i]); |
| md_buf[i] = NULL; |
| } |
| if (comp_buf[i] != NULL) { |
| vfree(comp_buf[i]); |
| comp_buf[i] = NULL; |
| } |
| } |
| if (p_funcs) { |
| pr_info("*** unregister_dv_functions ***\n"); |
| if (pq_config_fake) { |
| vfree(pq_config_fake); |
| pq_config_fake = NULL; |
| } |
| if (tv_dovi_setting) { |
| vfree(tv_dovi_setting); |
| tv_dovi_setting = NULL; |
| } |
| p_funcs = NULL; |
| ret = 0; |
| } |
| return ret; |
| } |
| EXPORT_SYMBOL(unregister_dv_functions); |
| |
| void tv_dolby_vision_crc_clear(int flag) |
| { |
| crc_outpuf_buff_off = 0; |
| crc_count = 0; |
| crc_bypass_count = 0; |
| setting_update_count = 0; |
| if (!crc_output_buf) |
| crc_output_buf = vmalloc(CRC_BUFF_SIZE); |
| pr_info( |
| "tv_dolby_vision_crc_clear, crc_output_buf %p\n", |
| crc_output_buf); |
| if (crc_output_buf) |
| memset(crc_output_buf, 0, CRC_BUFF_SIZE); |
| } |
| |
| char *tv_dolby_vision_get_crc(u32 *len) |
| { |
| if ((!crc_output_buf) || |
| (!len) || |
| (crc_outpuf_buff_off == 0)) |
| return NULL; |
| *len = crc_outpuf_buff_off; |
| return crc_output_buf; |
| } |
| |
| void tv_dolby_vision_insert_crc(bool print) |
| { |
| char str[64]; |
| int len; |
| bool crc_enable; |
| u32 crc; |
| |
| if (dolby_vision_flags & FLAG_DISABLE_CRC) { |
| crc_bypass_count++; |
| crc_count++; |
| return; |
| } |
| if (is_meson_txlx_tvmode() |
| && !force_stb_mode) { |
| crc_enable = (READ_VPP_REG(0x33e7) == 0xb); |
| crc = READ_VPP_REG(0x33ef); |
| } else { |
| crc_enable = true; /* (READ_VPP_REG(0x36fb) & 1); */ |
| crc = READ_VPP_REG(0x36fd); |
| } |
| if ((crc == 0) || (crc_enable == false) || (!crc_output_buf)) { |
| crc_bypass_count++; |
| crc_count++; |
| return; |
| } |
| if (crc_count < crc_bypass_count) |
| crc_bypass_count = crc_count; |
| memset(str, 0, sizeof(str)); |
| snprintf(str, 64, "crc(%d) = 0x%08x", |
| crc_count - crc_bypass_count, crc); |
| len = strlen(str); |
| str[len] = 0xa; |
| len++; |
| memcpy( |
| &crc_output_buf[crc_outpuf_buff_off], |
| &str[0], len); |
| crc_outpuf_buff_off += len; |
| if (print || (debug_dolby & 2)) |
| pr_info("%s\n", str); |
| crc_count++; |
| } |
| |
| void tv_dolby_vision_dma_table_modify(u32 tbl_id, uint64_t value) |
| { |
| uint64_t *tbl = NULL; |
| |
| if (!dma_vaddr || (tbl_id >= 3754)) { |
| pr_info("No dma table %p to write or id %d overflow\n", |
| dma_vaddr, tbl_id); |
| return; |
| } |
| tbl = (uint64_t *)dma_vaddr; |
| pr_info("dma_vaddr:%p, modify table[%d]=0x%llx -> 0x%llx\n", |
| dma_vaddr, tbl_id, tbl[tbl_id], value); |
| tbl[tbl_id] = value; |
| } |
| |
| void tv_dolby_vision_efuse_info(void) |
| { |
| if (p_funcs != NULL) { |
| pr_info("\n dv efuse info:\n"); |
| pr_info("efuse_mode:%d, version: %s\n", |
| efuse_mode, p_funcs->version_info); |
| } else { |
| pr_info("\n p_funcs is NULL\n"); |
| pr_info("efuse_mode:%d\n", efuse_mode); |
| } |
| } |
| |
| void tv_dolby_vision_el_info(void) |
| { |
| pr_info("el_mode:%d\n", el_mode); |
| } |
| |
| static int amdolby_vision_open(struct inode *inode, struct file *file) |
| { |
| struct amdolby_vision_dev_s *devp; |
| /* Get the per-device structure that contains this cdev */ |
| devp = container_of(inode->i_cdev, struct amdolby_vision_dev_s, cdev); |
| file->private_data = devp; |
| return 0; |
| |
| } |
| |
| static char *pq_config_buf; |
| static uint32_t pq_config_level; |
| static ssize_t amdolby_vision_write( |
| struct file *file, |
| const char *buf, |
| size_t len, |
| loff_t *off) |
| { |
| int i; |
| |
| if (pq_config_buf == NULL) { |
| pq_config_buf = vmalloc(108*1024); |
| pq_config_level = 0; |
| if (pq_config_buf == NULL) |
| return -ENOSPC; |
| } |
| for (i = 0; i < len; i++) { |
| pq_config_buf[pq_config_level] = buf[i]; |
| pq_config_level++; |
| if (pq_config_level == sizeof(struct pq_config_s)) { |
| dolby_vision_update_pq_config(pq_config_buf); |
| pq_config_level = 0; |
| break; |
| } |
| } |
| if (len <= 0x1f) { |
| dolby_vision_update_vsvdb_config( |
| pq_config_buf, len); |
| pq_config_level = 0; |
| } |
| return len; |
| } |
| |
| static ssize_t amdolby_vision_read( |
| struct file *file, char __user *buf, |
| size_t count, loff_t *ppos) |
| { |
| char *out; |
| u32 data_size = 0, res, retVal = 0; |
| |
| if (!is_dolby_vision_enable()) |
| return retVal; |
| out = tv_dolby_vision_get_crc(&data_size); |
| if (out && data_size > 0) { |
| res = copy_to_user((void *)buf, |
| (void *)out, |
| data_size); |
| retVal = data_size - res; |
| pr_info( |
| "amdolby_vision_read crc size %d, res: %d, ret: %d\n", |
| data_size, res, retVal); |
| tv_dolby_vision_crc_clear(0); |
| } |
| return retVal; |
| } |
| |
| static int amdolby_vision_release(struct inode *inode, struct file *file) |
| { |
| file->private_data = NULL; |
| return 0; |
| } |
| |
| static long amdolby_vision_ioctl(struct file *file, |
| unsigned int cmd, unsigned long arg) |
| { |
| return 0; |
| } |
| |
| |
| #ifdef CONFIG_COMPAT |
| static long amdolby_vision_compat_ioctl(struct file *file, unsigned int cmd, |
| unsigned long arg) |
| { |
| unsigned long ret; |
| |
| arg = (unsigned long)compat_ptr(arg); |
| ret = amdolby_vision_ioctl(file, cmd, arg); |
| return ret; |
| } |
| #endif |
| |
| static const struct file_operations amdolby_vision_fops = { |
| .owner = THIS_MODULE, |
| .open = amdolby_vision_open, |
| .write = amdolby_vision_write, |
| .read = amdolby_vision_read, |
| .release = amdolby_vision_release, |
| .unlocked_ioctl = amdolby_vision_ioctl, |
| #ifdef CONFIG_COMPAT |
| .compat_ioctl = amdolby_vision_compat_ioctl, |
| #endif |
| }; |
| |
| static void parse_param_amdolby_vision(char *buf_orig, char **parm) |
| { |
| char *ps, *token; |
| unsigned int n = 0; |
| char delim1[3] = " "; |
| char delim2[2] = "\n"; |
| |
| ps = buf_orig; |
| strcat(delim1, delim2); |
| while (1) { |
| token = strsep(&ps, delim1); |
| if (token == NULL) |
| break; |
| if (*token == '\0') |
| continue; |
| parm[n++] = token; |
| } |
| } |
| |
| static const char *amdolby_vision_debug_usage_str = { |
| "Usage:\n" |
| "echo dolby_crc 0/1 > /sys/class/amdolby_vision/debug; dolby_crc insert or clr\n" |
| "echo dolby_dma index(D) value(H) > /sys/class/amdolby_vision/debug; dolby dma table modify\n" |
| "echo dv_efuse > /sys/class/amdolby_vision/debug; get dv efuse info\n" |
| "echo dv_el > /sys/class/amdolby_vision/debug; get dv enhanced layer info\n" |
| }; |
| static ssize_t amdolby_vision_debug_show(struct class *cla, |
| struct class_attribute *attr, char *buf) |
| { |
| return sprintf(buf, "%s\n", amdolby_vision_debug_usage_str); |
| } |
| |
| static ssize_t amdolby_vision_debug_store(struct class *cla, |
| struct class_attribute *attr, |
| const char *buf, size_t count) |
| { |
| char *buf_orig, *parm[8] = {NULL}; |
| long val = 0; |
| |
| if (!buf) |
| return count; |
| buf_orig = kstrdup(buf, GFP_KERNEL); |
| parse_param_amdolby_vision(buf_orig, (char **)&parm); |
| if (!strcmp(parm[0], "dolby_crc")) { |
| if (kstrtoul(parm[1], 10, &val) < 0) |
| return -EINVAL; |
| if (val == 1) |
| tv_dolby_vision_crc_clear(val); |
| else |
| tv_dolby_vision_insert_crc(true); |
| } else if (!strcmp(parm[0], "dolby_dma")) { |
| long tbl_id; |
| long value; |
| |
| if (kstrtoul(parm[1], 10, &tbl_id) < 0) |
| return -EINVAL; |
| if (kstrtoul(parm[2], 16, &value) < 0) |
| return -EINVAL; |
| tv_dolby_vision_dma_table_modify((u32)tbl_id, (uint64_t)value); |
| } else if (!strcmp(parm[0], "dv_efuse")) { |
| tv_dolby_vision_efuse_info(); |
| } else if (!strcmp(parm[0], "dv_el")) { |
| tv_dolby_vision_el_info(); |
| } else { |
| pr_info("unsupport cmd\n"); |
| } |
| |
| kfree(buf_orig); |
| return count; |
| } |
| |
| /* supported mode: IPT_TUNNEL/HDR10/SDR10 */ |
| static const int dv_mode_table[6] = { |
| 5, /*DOLBY_VISION_OUTPUT_MODE_BYPASS*/ |
| 0, /*DOLBY_VISION_OUTPUT_MODE_IPT*/ |
| 1, /*DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL*/ |
| 2, /*DOLBY_VISION_OUTPUT_MODE_HDR10*/ |
| 3, /*DOLBY_VISION_OUTPUT_MODE_SDR10*/ |
| 4, /*DOLBY_VISION_OUTPUT_MODE_SDR8*/ |
| }; |
| |
| static const char dv_mode_str[6][12] = { |
| "IPT", |
| "IPT_TUNNEL", |
| "HDR10", |
| "SDR10", |
| "SDR8", |
| "BYPASS" |
| }; |
| |
| static ssize_t amdolby_vision_dv_mode_show(struct class *cla, |
| struct class_attribute *attr, char *buf) |
| { |
| pr_info("usage: echo mode > /sys/class/amdolby_vision/dv_mode\n"); |
| pr_info("\tDOLBY_VISION_OUTPUT_MODE_BYPASS 0\n"); |
| pr_info("\tDOLBY_VISION_OUTPUT_MODE_IPT 1\n"); |
| pr_info("\tDOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL 2\n"); |
| pr_info("\tDOLBY_VISION_OUTPUT_MODE_HDR10 3\n"); |
| pr_info("\tDOLBY_VISION_OUTPUT_MODE_SDR10 4\n"); |
| pr_info("\tDOLBY_VISION_OUTPUT_MODE_SDR8 5\n"); |
| if (is_dolby_vision_enable()) |
| pr_info("current dv_mode = %s\n", |
| dv_mode_str[get_dolby_vision_mode()]); |
| else |
| pr_info("current dv_mode = off\n"); |
| return 0; |
| } |
| static ssize_t amdolby_vision_dv_mode_store(struct class *cla, |
| struct class_attribute *attr, |
| const char *buf, size_t count) |
| { |
| size_t r; |
| int val; |
| |
| r = kstrtoint(buf, 0, &val); |
| if (r != 0) |
| return -EINVAL; |
| |
| if ((val >= 0) && (val < 6)) |
| set_dolby_vision_mode(dv_mode_table[val]); |
| else if (val & 0x200) |
| dolby_vision_dump_struct(); |
| else if (val & 0x70) |
| dolby_vision_dump_setting(val); |
| return count; |
| } |
| |
| |
| static struct class_attribute amdolby_vision_class_attrs[] = { |
| __ATTR(debug, 0644, |
| amdolby_vision_debug_show, amdolby_vision_debug_store), |
| __ATTR(dv_mode, 0644, |
| amdolby_vision_dv_mode_show, amdolby_vision_dv_mode_store), |
| __ATTR_NULL |
| }; |
| |
| static struct dv_device_data_s dolby_vision_gxm = { |
| .cpu_id = _CPU_MAJOR_ID_GXM, |
| }; |
| |
| static struct dv_device_data_s dolby_vision_txlx = { |
| .cpu_id = _CPU_MAJOR_ID_TXLX, |
| }; |
| |
| static struct dv_device_data_s dolby_vision_g12 = { |
| .cpu_id = _CPU_MAJOR_ID_G12, |
| }; |
| |
| static const struct of_device_id amlogic_dolby_vision_match[] = { |
| { |
| .compatible = "amlogic, dolby_vision_gxm", |
| .data = &dolby_vision_gxm, |
| }, |
| { |
| .compatible = "amlogic, dolby_vision_txlx", |
| .data = &dolby_vision_txlx, |
| }, |
| { |
| .compatible = "amlogic, dolby_vision_g12a", |
| .data = &dolby_vision_g12, |
| }, |
| { |
| .compatible = "amlogic, dolby_vision_g12b", |
| .data = &dolby_vision_g12, |
| }, |
| { |
| .compatible = "amlogic, dolby_vision_sm1", |
| .data = &dolby_vision_g12, |
| }, |
| {}, |
| }; |
| |
| static int amdolby_vision_probe(struct platform_device *pdev) |
| { |
| int ret = 0; |
| int i = 0; |
| struct amdolby_vision_dev_s *devp = &amdolby_vision_dev; |
| unsigned int val; |
| |
| pr_info("\n amdolby_vision probe start & ver: %s\n", DRIVER_VER); |
| if (pdev->dev.of_node) { |
| const struct of_device_id *match; |
| struct dv_device_data_s *dv_meson; |
| struct device_node *of_node = pdev->dev.of_node; |
| |
| match = of_match_node(amlogic_dolby_vision_match, of_node); |
| if (match) { |
| dv_meson = (struct dv_device_data_s *)match->data; |
| if (dv_meson) |
| memcpy(&dv_meson_dev, dv_meson, |
| sizeof(struct dv_device_data_s)); |
| else { |
| pr_err("%s data NOT match\n", __func__); |
| return -ENODEV; |
| } |
| } else { |
| pr_err("%s NOT match\n", __func__); |
| return -ENODEV; |
| } |
| ret = of_property_read_u32(of_node, "tv_mode", &val); |
| if (ret) |
| pr_info("Can't find tv_mode.\n"); |
| else |
| tv_mode = val; |
| } |
| pr_info("\n cpu_id=%d tvmode=%d\n", dv_meson_dev.cpu_id, tv_mode); |
| memset(devp, 0, (sizeof(struct amdolby_vision_dev_s))); |
| ret = alloc_chrdev_region(&devp->devno, 0, 1, AMDOLBY_VISION_NAME); |
| if (ret < 0) |
| goto fail_alloc_region; |
| devp->clsp = class_create(THIS_MODULE, |
| AMDOLBY_VISION_CLASS_NAME); |
| if (IS_ERR(devp->clsp)) { |
| ret = PTR_ERR(devp->clsp); |
| goto fail_create_class; |
| } |
| for (i = 0; amdolby_vision_class_attrs[i].attr.name; i++) { |
| if (class_create_file(devp->clsp, |
| &amdolby_vision_class_attrs[i]) < 0) |
| goto fail_class_create_file; |
| } |
| cdev_init(&devp->cdev, &amdolby_vision_fops); |
| devp->cdev.owner = THIS_MODULE; |
| ret = cdev_add(&devp->cdev, devp->devno, 1); |
| if (ret) |
| goto fail_add_cdev; |
| |
| devp->dev = device_create(devp->clsp, NULL, devp->devno, |
| NULL, AMDOLBY_VISION_NAME); |
| if (IS_ERR(devp->dev)) { |
| ret = PTR_ERR(devp->dev); |
| goto fail_create_device; |
| } |
| |
| dolby_vision_init_receiver(pdev); |
| pr_info("%s: ok\n", __func__); |
| return 0; |
| |
| fail_create_device: |
| pr_info("[amdolby_vision.] : amdolby_vision device create error.\n"); |
| cdev_del(&devp->cdev); |
| fail_add_cdev: |
| pr_info("[amdolby_vision.] : amdolby_vision add device error.\n"); |
| fail_class_create_file: |
| pr_info("[amdolby_vision.] : amdolby_vision class create file error.\n"); |
| for (i = 0; amdolby_vision_class_attrs[i].attr.name; i++) { |
| class_remove_file(devp->clsp, |
| &amdolby_vision_class_attrs[i]); |
| } |
| class_destroy(devp->clsp); |
| fail_create_class: |
| pr_info("[amdolby_vision.] : amdolby_vision class create error.\n"); |
| unregister_chrdev_region(devp->devno, 1); |
| fail_alloc_region: |
| pr_info("[amdolby_vision.] : amdolby_vision alloc error.\n"); |
| pr_info("[amdolby_vision.] : amdolby_vision_init.\n"); |
| return ret; |
| |
| |
| } |
| |
| static int __exit amdolby_vision_remove(struct platform_device *pdev) |
| { |
| struct amdolby_vision_dev_s *devp = &amdolby_vision_dev; |
| |
| if (pq_config_buf) { |
| vfree(pq_config_buf); |
| pq_config_buf = NULL; |
| } |
| |
| device_destroy(devp->clsp, devp->devno); |
| cdev_del(&devp->cdev); |
| class_destroy(devp->clsp); |
| unregister_chrdev_region(devp->devno, 1); |
| pr_info("[ amdolby_vision.] : amdolby_vision_exit.\n"); |
| return 0; |
| } |
| |
| static struct platform_driver aml_amdolby_vision_driver = { |
| .driver = { |
| .owner = THIS_MODULE, |
| .name = "aml_amdolby_vision_driver", |
| .of_match_table = amlogic_dolby_vision_match, |
| }, |
| .probe = amdolby_vision_probe, |
| .remove = __exit_p(amdolby_vision_remove), |
| }; |
| |
| static int __init amdolby_vision_init(void) |
| { |
| pr_info("%s:module init\n", __func__); |
| |
| if (platform_driver_register(&aml_amdolby_vision_driver)) { |
| pr_err("failed to register amdolby_vision module\n"); |
| return -ENODEV; |
| } |
| return 0; |
| } |
| |
| static void __exit amdolby_vision_exit(void) |
| { |
| pr_info("%s:module exit\n", __func__); |
| platform_driver_unregister(&aml_amdolby_vision_driver); |
| } |
| |
| module_init(amdolby_vision_init); |
| module_exit(amdolby_vision_exit); |
| |
| MODULE_DESCRIPTION("AMLOGIC amdolby_vision driver"); |
| MODULE_LICENSE("GPL"); |
| |
| |