blob: 8c4791f1ca617008af4727ddca145815819353fe [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <asm/arch/io.h>
#include <asm/arch/secure_apb.h>
#include <amlogic/media/vout/aml_vmode.h>
#include <amlogic/storage.h>
#include <amlogic/media/vout/aml_vout.h>
#include <amlogic/media/vout/hdmitx/hdmitx_module.h>
#include <amlogic/media/dv/dolby_vision.h>
#include <amlogic/media/dv/dolby_vision_func.h>
#include <malloc.h>
#include <config.h>
#include <mmc.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <amlogic/cpu_id.h>
#include "./../vpp.h"
#include "./../hdr2.h"
#include <asm/arch/io.h>
//#include <asm/arch/secure_apb.h>
static struct dovi_setting_s dovi_setting;
static struct dovi_mode_s dovi_mode;
static unsigned int dolby_vision_mode = DOLBY_VISION_OUTPUT_MODE_BYPASS;
static unsigned int dolby_vision_ll_policy = DOLBY_VISION_LL_DISABLE;
static unsigned int dv_ll_output_mode = DOLBY_VISION_OUTPUT_MODE_HDR10;
static unsigned int dolby_vision_target_min = 50; /* 0.0001 */
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 */
};
static unsigned int dolby_vision_target_graphics_max[3] = {
300, 300, 100
}; /* DOVI/HDR/SDR */
/* 0: video priority 1: graphic priority */
static unsigned int dv_graphics_priority = 1;
static unsigned int vinfo_width = 1920;
static unsigned int vinfo_height = 1080;
static unsigned int vinfo_duration_num = 60;
static unsigned int vinfo_field_height = 1080;
static bool dolby_vision_on;
static char *dolby_status;
#define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
#define MATRIX_5x3_COEF_SIZE 24
static int RGB709_to_YUV709l_coeff[MATRIX_5x3_COEF_SIZE] = {
0, 0, 0, /* pre offset */
COEFF_NORM(0.181873), COEFF_NORM(0.611831), COEFF_NORM(0.061765),
COEFF_NORM(-0.100251), COEFF_NORM(-0.337249), COEFF_NORM(0.437500),
COEFF_NORM(0.437500), COEFF_NORM(-0.397384), COEFF_NORM(-0.040116),
0, 0, 0, /* 10'/11'/12' */
0, 0, 0, /* 20'/21'/22' */
64, 512, 512, /* offset */
0, 0, 0 /* mode, right_shift, clip_en */
};
static int bypass_coeff[MATRIX_5x3_COEF_SIZE] = {
0, 0, 0, /* pre offset */
COEFF_NORM(1.0), COEFF_NORM(0.0), COEFF_NORM(0.0),
COEFF_NORM(0.0), COEFF_NORM(1.0), COEFF_NORM(0.0),
COEFF_NORM(0.0), COEFF_NORM(0.0), COEFF_NORM(1.0),
0, 0, 0, /* 10'/11'/12' */
0, 0, 0, /* 20'/21'/22' */
0, 0, 0, /* offset */
0, 0, 0 /* mode, right_shift, clip_en */
};
static int dvll_RGB_to_YUV709l_coeff[MATRIX_5x3_COEF_SIZE] = {
0, 0, 0, /* pre offset */
COEFF_NORM(0.181873), COEFF_NORM(0.611831), COEFF_NORM(0.061765),
COEFF_NORM(-0.100251), COEFF_NORM(-0.337249), COEFF_NORM(0.437500),
COEFF_NORM(0.437500), COEFF_NORM(-0.397384), COEFF_NORM(-0.040116),
0, 0, 0, /* 10'/11'/12' */
0, 0, 0, /* 20'/21'/22' */
64, 512, 512, /* offset */
0, 0, 0 /* mode, right_shift, clip_en */
};
static int *cur_osd_mtx = RGB709_to_YUV709l_coeff;
static int *cur_vd1_mtx = bypass_coeff;
static unsigned int debug_enable = 0;
static bool tv_mode;
#define MAX_PARAM 8
#ifndef REG_BASE_VCBUS
#define REG_BASE_VCBUS (0xFF900000L)
#endif
#define REG_BASE_VCBUS_SC2 (0xFF000000L)
#define REG_OFFSET_VCBUS(reg) ((reg << 2))
#define REG_ADDR_VCBUS(reg) (REG_BASE_VCBUS + REG_OFFSET_VCBUS(reg))
#define REG_ADDR_VCBUS_SC2(reg) (REG_BASE_VCBUS_SC2 + REG_OFFSET_VCBUS(reg))
#define REG_DV_ADDR(reg) (reg + 0L)
static inline bool is_meson_gxm(void)
{
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_GXM)
return true;
else
return false;
}
static inline bool is_meson_g12(void)
{
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_G12A ||
get_cpu_id().family_id == MESON_CPU_MAJOR_ID_G12B ||
get_cpu_id().family_id == MESON_CPU_MAJOR_ID_SM1)
return true;
else
return false;
}
static inline bool is_meson_sc2(void)
{
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_SC2)
return true;
else
return false;
}
static inline bool is_meson_box(void)
{
if (is_meson_gxm() || is_meson_g12() || is_meson_sc2())
return true;
else
return false;
}
static inline bool is_meson_txlx(void)
{
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_TXLX)
return true;
else
return false;
}
static inline bool is_meson_txlx_tvmode(void)
{
if ((is_meson_txlx()) && (tv_mode == 1))
return true;
else
return false;
}
static inline bool is_meson_txlx_stbmode(void)
{
if ((is_meson_txlx()) && (tv_mode == 0))
return true;
else
return false;
}
static inline bool is_meson_tm2(void)
{
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_TM2)
return true;
else
return false;
}
static inline bool is_meson_tm2_tvmode(void)
{
if ((is_meson_tm2()) && (tv_mode == 1))
return true;
else
return false;
}
static inline bool is_meson_tm2_stbmode(void)
{
if ((is_meson_tm2()) && (tv_mode == 0))
return true;
else
return false;
}
static inline bool is_meson_tvmode(void)
{
if (is_meson_tm2_tvmode() ||
is_meson_txlx_tvmode())
return true;
else
return false;
}
static inline u32 READ_VPP_REG(u32 reg)
{
u32 val;
if (reg > 0x10000)
val = *(volatile unsigned int *)REG_DV_ADDR(reg);
else {
if (is_meson_sc2())
val = *(volatile unsigned int *)REG_ADDR_VCBUS_SC2(reg);
else
val = *(volatile unsigned int *)REG_ADDR_VCBUS(reg);
}
return val;
}
static inline void WRITE_VPP_REG(u32 reg,
const u32 val)
{
if (reg > 0x10000)
*(volatile unsigned int *)REG_DV_ADDR(reg) = (val);
else {
if (is_meson_sc2())
*(volatile unsigned int *)REG_ADDR_VCBUS_SC2(reg) = (val);
else
*(volatile unsigned int *)REG_ADDR_VCBUS(reg) = (val);
}
}
static inline void WRITE_VPP_REG_BITS(uint32_t reg,
const uint32_t value, const uint32_t start, const uint32_t len)
{
WRITE_VPP_REG(reg, ((READ_VPP_REG(reg) &
~(((1L << (len)) - 1) << (start))) |
(((value) & ((1L << (len)) - 1)) << (start))));
}
static inline u32 phyaddr_to_dvaddr(u32 reg) {
u32 val;
if (reg > 0x10000) {
if (is_meson_sc2())
val = (reg - REG_BASE_VCBUS_SC2) >> 2;
else
val = (reg - REG_BASE_VCBUS) >> 2;
return val;
} else {
return reg;
}
}
#ifdef CONFIG_AML_DOLBY
/*check dolby enable status,if status is disabled, not enable dolby
*/
int is_dolby_enable(void)
{
if (!dolby_status)
dolby_status = env_get("dolby_status");
printf("dolby_status %s\n", dolby_status);
if (!strcmp(dolby_status, DOLBY_VISION_SET_STD) ||
!strcmp(dolby_status, DOLBY_VISION_SET_LL_YUV) ||
!strcmp(dolby_status, DOLBY_VISION_SET_LL_RGB))
return 1;
else
return 0;
}
bool request_ll_mode(void)
{
if (!dolby_status)
dolby_status = env_get("dolby_status");
if (!strcmp(dolby_status, DOLBY_VISION_SET_LL_RGB) ||
!strcmp(dolby_status, DOLBY_VISION_SET_LL_YUV)) {
printf("request LL mode\n");
return true;
} else
return false;
}
bool check_dolby_vision_on(void)
{
if ((get_cpu_id().family_id == MESON_CPU_MAJOR_ID_G12A) ||
(get_cpu_id().family_id == MESON_CPU_MAJOR_ID_G12B) ||
(get_cpu_id().family_id == MESON_CPU_MAJOR_ID_SM1) ||
(get_cpu_id().family_id == MESON_CPU_MAJOR_ID_TM2) ||
(get_cpu_id().family_id == MESON_CPU_MAJOR_ID_SC2)) {
if (READ_VPP_REG(DOLBY_CORE3_SWAP_CTRL0) & 0x1)
return true;
}
return false;
}
#endif
unsigned int dv_read_reg(unsigned int addr)
{
return READ_VPP_REG(addr);
}
void dv_write_reg(unsigned int addr, unsigned int value)
{
WRITE_VPP_REG(addr, value);
}
/*
static int check_tv_has_changed(struct hdmitx_dev* hdmitx_device)
{
return hdmitx_device->RXCap.edid_changed;
}*/
static int check_tv_hpd_status(struct hdmitx_dev* hdmitx_device)
{
return hdmitx_device->hwop.get_hpd_state();
}
static int check_tv_support_dv(struct hdmitx_dev *hdmitx_device)
{
struct dv_info* dv_info = NULL;
int maxTMDSRate = 0;
//int preferredMode = hdmitx_device->RXCap.preferred_mode;
//1.tv not changed, use outputmode from env
//2.tv changed,hdmi will choose best mode and update outputmode to env
char *outputmode = env_get("outputmode");
printf("check_tv_support_dv, outputmode %s\n", outputmode);
if (!hdmitx_device) {
printf("null hdmitx_device\n");
return 0;
}
if (hdmitx_device->RXCap.dv_info.ieeeoui != 0x00d046) {
printf("dv_info.ieeeoui %x\n", hdmitx_device->RXCap.dv_info.ieeeoui);
return 0;
}
if (hdmitx_device->RXCap.dv_info.block_flag != CORRECT) {
printf("dv_info.block_flag %x\n", hdmitx_device->RXCap.dv_info.block_flag);
return 0;
}
dv_info = &hdmitx_device->RXCap.dv_info;
if (dv_info->ver == 0) {
dovi_mode.dv_rgb_444_8bit = 1;
if (dv_info->sup_2160p60hz)
dovi_mode.sup_2160p60hz = 1;
} else if ((dv_info->ver == 1) && (dv_info->length == 0xB)) {
dovi_mode.dv_rgb_444_8bit = 1;
if (dv_info->low_latency == 0x01)
dovi_mode.ll_ycbcr_422_12bit = 1;
if (dv_info->sup_2160p60hz)
dovi_mode.sup_2160p60hz = 1;
} else if ((dv_info->ver == 1) && (dv_info->length == 0xE)) {
dovi_mode.dv_rgb_444_8bit = 1;
if (dv_info->sup_2160p60hz)
dovi_mode.sup_2160p60hz = 1;
} else if (dv_info->ver == 2) {
dovi_mode.ll_ycbcr_422_12bit = 1;
if ((dv_info->Interface != 0x00) && (dv_info->Interface != 0x01))
dovi_mode.dv_rgb_444_8bit = 1;
if ((dv_info->Interface == 0x01) || (dv_info->Interface == 0x03)) {
if (dv_info->sup_10b_12b_444 == 0x1)
dovi_mode.ll_rgb_444_10bit = 1;
if (dv_info->sup_10b_12b_444 == 0x2)
dovi_mode.ll_rgb_444_12bit = 1;
}
dovi_mode.sup_2160p60hz = 1;
}
//if preferred mode is 4k, make sure it can be truly supported in DV format
if (hdmitx_device->RXCap.Max_TMDS_Clock2 != 0) {
maxTMDSRate = hdmitx_device->RXCap.Max_TMDS_Clock2 * 5;
printf("check_tv_support_dv: maxTMDSRate1 = %d\n", maxTMDSRate);
} else {
if (hdmitx_device->RXCap.Max_TMDS_Clock1 < 0xf)
hdmitx_device->RXCap.Max_TMDS_Clock1 = 0x1e;
maxTMDSRate = hdmitx_device->RXCap.Max_TMDS_Clock1 * 5;
printf("check_tv_support_dv: maxTMDSRate2 = %d\n", maxTMDSRate);
}
//return true only if DV can truly be supported for a given mode
if (strstr(outputmode, "2160p60hz") || strstr(outputmode, "2160p50hz")) {
if ((dovi_mode.sup_2160p60hz) && (maxTMDSRate >= 594)) {
//safety check for yuv420 - shudn't be the case
if (strstr(outputmode, "2160p60hz420"))
env_set("outputmode", "2160p60hz");
if (strstr(outputmode, "2160p50hz420"))
env_set("outputmode", "2160p50hz");
printf("check_tv_support_dv: 4k60 dovi supported\n");
return 1;
} else {
printf("check_tv_support_dv: 4k60 dovi NOT supported\n");
return 0;
}
}
return 1;
}
static int check_tv_support_hdr(struct hdmitx_dev *hdmitx_device)
{
if (!hdmitx_device)
return 0;
if (hdmitx_device->RXCap.hdr_info.hdr_sup_eotf_smpte_st_2084)
return 1;
return 0;
}
#if 0
/* not needed anymore */
/*if tv has changed, choose the preferred mode and check if dv support this preferred mode*/
static int check_tv_dv_mode(struct hdmitx_dev *hdmitx_device)
{
if (dovi_mode.dv_rgb_444_8bit) {
env_set("colorattribute", "444,8bit");
if ((hdmitx_device->RXCap.preferred_mode
== HDMI_3840x2160p50_16x9) ||
(hdmitx_device->RXCap.preferred_mode
== HDMI_3840x2160p60_16x9)) {
if ((dovi_mode.sup_2160p60hz) &&
(hdmitx_device->RXCap.Max_TMDS_Clock2 * 5 == 600))
env_set("outputmode", "2160p60hz");
else
env_set("outputmode", "1080p60hz");
} else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1920x1080p60_16x9)
env_set("outputmode", "1080p60hz");
else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1920x1080p50_16x9)
env_set("outputmode", "1080p50hz");
else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1280x720p60_16x9)
env_set("outputmode", "720p60hz");
else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1280x720p50_16x9)
env_set("outputmode", "720p50hz");
else
env_set("outputmode", "1080p60hz");
printf("output dv standard mode : mode is : %s attr: %s\n",
env_get("outputmode"), env_get("colorattribute"));
} else if (dovi_mode.ll_ycbcr_422_12bit) {
setenv("colorattribute", "422,12bit");
if ((hdmitx_device->RXCap.preferred_mode
== HDMI_3840x2160p50_16x9) ||
(hdmitx_device->RXCap.preferred_mode
== HDMI_3840x2160p60_16x9)) {
if ((dovi_mode.sup_2160p60hz) &&
(hdmitx_device->RXCap.Max_TMDS_Clock2 * 5 == 600))
env_set("outputmode", "2160p60hz");
else
env_set("outputmode", "1080p60hz");
} else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1920x1080p60_16x9)
env_set("outputmode", "1080p60hz");
else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1920x1080p50_16x9)
env_set("outputmode", "1080p50hz");
else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1280x720p60_16x9)
env_set("outputmode", "720p60hz");
else if (hdmitx_device->RXCap.preferred_mode
== HDMI_1280x720p50_16x9)
env_set("outputmode", "720p50hz");
else
env_set("outputmode", "1080p60hz");
printf("output dv LL 422 mode : mode is : %s attr: %s\n",
env_get("outputmode"), env_get("colorattribute"));
} else if (dovi_mode.ll_rgb_444_10bit) {
env_set("colorattribute", "444,10bit");
env_set("outputmode", "1080p60hz");
printf("output dv LL 444 mode : mode is : %s attr: %s\n",
env_get("outputmode"), env_get("colorattribute"));
} else if (dovi_mode.ll_rgb_444_12bit) {
env_set("colorattribute", "444,12bit");
env_set("outputmode", "1080p60hz");
printf("output dv LL 444 mode : mode is : %s attr: %s\n",
env_get("outputmode"), env_get("colorattribute"));
} else {
env_set("colorattribute", "444,8bit");
env_set("outputmode", "1080p60hz");
}
return 0;
}
#endif
/*true: attr match with dv_moder*/
/*false: attr not match with dv_mode*/
static bool is_attr_match(void)
{
char *attr = env_get("colorattribute");
/*two case use std mode: */
/*1.user not requeset LL mode*/
/*2.user request LL mode but sink not support LL mode*/
if (dovi_mode.dv_rgb_444_8bit &&
(!request_ll_mode() || dovi_mode.ll_ycbcr_422_12bit == 0)) { /*STD*/
if (!strstr(attr, "444,8bit")) {
printf("expect output DV, but attr is %s\n", attr);
return false;
}
} else if (dovi_mode.ll_ycbcr_422_12bit) { /*LL YUV*/
if (!strstr(attr, "422,12bit")) {
printf("expect output LL YUV, but attr is %s\n", attr);
dovi_setting.dst_format = FORMAT_SDR;
return false;
}
} else if (dovi_mode.ll_rgb_444_10bit) { /*LL RGB*/
if (!strstr(attr, "444,10bit")) {
printf("expect output LL RGB, but attr is %s\n", attr);
dovi_setting.dst_format = FORMAT_SDR;
return false;
}
}
return true;
}
static int check_tv_support(struct hdmitx_dev *hdmitx_device)
{
if (check_tv_support_dv(hdmitx_device)) {
if (is_attr_match()) {
dovi_setting.dst_format = FORMAT_DOVI;
printf("output dovi mode: mode is : %s attr: %s\n",
env_get("outputmode"), env_get("colorattribute"));
} else {
dovi_setting.dst_format = FORMAT_SDR;
printf("attr is not match, change to output SDR\n");
}
} else if (check_tv_support_hdr(hdmitx_device)) {
dovi_setting.dst_format = FORMAT_HDR10;
printf("output hdr mode: mode is : %s attr: %s\n",
env_get("outputmode"), env_get("colorattribute"));
} else {
dovi_setting.dst_format = FORMAT_SDR;
printf("output sdr mode: mode is : %s attr: %s\n",
env_get("outputmode"), env_get("colorattribute"));
}
return 0;
}
static void dolby_vision_get_vinfo(struct hdmitx_dev *hdmitx_device)
{
uint32_t width;
uint32_t height;
uint32_t sync_duration_num;
uint32_t field_height;
char *mode_name;
mode_name = env_get("outputmode");
if (strstr(mode_name, "1080")) {
width = 1920;
height = 1080;
} else if (strstr(mode_name, "2160")) {
width = 3840;
height = 2160;
} else if (strstr(mode_name, "720")) {
width = 1280;
height = 720;
} else if (strstr(mode_name, "576")) {
width = 720;
height = 576;
} else if (strstr(mode_name, "480")) {
width = 720;
height = 480;
} else if (strstr(mode_name, "smpte")) {
width = 4096;
height = 2160;
} else {
printf("unkown mode, use default 1080p\n");
width = 1920;
height = 1080;
}
if (strstr(mode_name, "60hz"))
sync_duration_num = 60;
else if (strstr(mode_name, "50hz"))
sync_duration_num = 50;
else if (strstr(mode_name, "30hz"))
sync_duration_num = 30;
else if (strstr(mode_name, "25hz"))
sync_duration_num = 25;
else if (strstr(mode_name, "24hz"))
sync_duration_num = 24;
else
sync_duration_num = 60;
if (strstr(mode_name, "i"))
field_height = height/2;
else
field_height = height;
vinfo_width = width;
vinfo_height = height;
vinfo_duration_num = sync_duration_num;
vinfo_field_height = field_height;
}
static void dolby_vision_parse(struct hdmitx_dev *hdmitx_device)
{
enum signal_format_e src_format = FORMAT_SDR;
enum signal_format_e dst_format = dovi_setting.dst_format;
unsigned int graphic_min = 50;
unsigned int graphic_max = 100;
unsigned int target_max = 100;
unsigned int w = 3840;
unsigned int h = 2160;
dolby_vision_get_vinfo(hdmitx_device);
dovi_setting.vout_width = vinfo_width;
dovi_setting.vout_height= vinfo_height;
dovi_setting.g_bitdepth = 8;
dovi_setting.g_format = GF_SDR_RGB;
dovi_setting.video_width = w << 16;
dovi_setting.video_height = h << 16;
if(dst_format >= 0
&& dst_format <= 2)
graphic_max = dolby_vision_target_graphics_max[dst_format];
if (dovi_setting.dst_format == FORMAT_DOVI) {
memset(&dovi_setting.vsvdb_tbl[0],
0, sizeof(dovi_setting.vsvdb_tbl));
memcpy(&dovi_setting.vsvdb_tbl[0],
&hdmitx_device->RXCap.dv_info.rawdata[0],
hdmitx_device->RXCap.dv_info.length + 1);
//two case use std mode:
//1.user not requeset LL mode
//2.user request LL mode but sink not support LL mode
if (dovi_mode.dv_rgb_444_8bit &&
(!request_ll_mode() || dovi_mode.ll_ycbcr_422_12bit == 0))
;
else if (dovi_mode.ll_ycbcr_422_12bit) {
dovi_setting.use_ll_flag = 1;
dovi_setting.dovi_ll_enable = 1;
} else if (dovi_mode.ll_rgb_444_10bit) {
dovi_setting.use_ll_flag = 1;
dovi_setting.dovi_ll_enable = 1;
dovi_setting.ll_rgb_desired= 1;
dovi_setting.diagnostic_enable = 1;
}
} else if (dovi_setting.dst_format == FORMAT_HDR10) {
if (hdmitx_device->RXCap.hdr_info.hdr_lum_max) {
graphic_max = 50 * (2 ^ (hdmitx_device->RXCap.hdr_info.hdr_lum_max >> 5));
graphic_max = graphic_max * 10000
* hdmitx_device->RXCap.hdr_info.hdr_lum_min
* hdmitx_device->RXCap.hdr_info.hdr_lum_min
/ (255 * 255 * 100);
}
} else
;
if ((src_format >= 0 && src_format <= 2) &&
(dst_format >= 0 && dst_format <= 2))
target_max = dolby_vision_target_max[src_format][dst_format];
DV_func.control_path(
src_format, dst_format,
NULL, 0,
NULL, 0,
dv_graphics_priority,
12, 0, 0,
graphic_min,
graphic_max * 10000,
dolby_vision_target_min,
target_max * 10000, 1,
NULL,
&dovi_setting);
}
static bool need_skip_cvm(unsigned int is_graphic) {
return false;
}
static unsigned int mtx_en_mux;
static void video_effect_bypass(int bypass)
{
WRITE_VPP_REG(VPP_EOTF_CTL, 0);
WRITE_VPP_REG(XVYCC_LUT_CTL, 0);
WRITE_VPP_REG(XVYCC_INV_LUT_CTL, 0);
WRITE_VPP_REG(VPP_VADJ_CTRL, 0);
WRITE_VPP_REG(VPP_GAINOFF_CTRL0, 0);
WRITE_VPP_REG(VPP_VE_ENABLE_CTRL, 0);
WRITE_VPP_REG(XVYCC_VD1_RGB_CTRST, 0);
}
static void vpp_set_mtx_en_write(void)
{
int reg_val;
reg_val = READ_VPP_REG(VPP_MATRIX_CTRL);
WRITE_VPP_REG(VPP_MATRIX_CTRL, (reg_val &
(~(POST_MTX_EN_MASK |
VD2_MTX_EN_MASK |
VD1_MTX_EN_MASK |
XVY_MTX_EN_MASK |
OSD1_MTX_EN_MASK))) |
mtx_en_mux);
}
static void vpp_set_mtx_en_read(void)
{
int reg_value;
reg_value = READ_VPP_REG(VPP_MATRIX_CTRL);
mtx_en_mux = reg_value &
(POST_MTX_EN_MASK |
VD2_MTX_EN_MASK |
VD1_MTX_EN_MASK |
XVY_MTX_EN_MASK |
OSD1_MTX_EN_MASK);
}
static int enable_rgb_to_yuv_matrix_for_dvll(
int32_t on, uint32_t *coeff_orig, uint32_t bits)
{
int32_t i;
uint32_t coeff01, coeff23, coeff45, coeff67, coeff89;
uint32_t scale, shift, offset[3];
int32_t *coeff = dvll_RGB_to_YUV709l_coeff;
if ((bits < 10) || (bits > 12))
return -1;
if (on && !coeff_orig)
return -2;
if (on) {
coeff01 = coeff_orig[0];
coeff23 = coeff_orig[1];
coeff45 = coeff_orig[2];
coeff67 = coeff_orig[3];
coeff89 = coeff_orig[4] & 0xffff;
scale = (coeff_orig[4] >> 16) & 0x0f;
offset[0] = coeff_orig[5];
offset[1] = 0; /* coeff_orig[6]; */
offset[2] = 0; /* coeff_orig[7]; */
coeff[0] = coeff[1] = coeff[2] = 0; /* pre offset */
coeff[5] = (int32_t)((coeff01 & 0xffff) << 16) >> 16;
coeff[3] = (int32_t)coeff01 >> 16;
coeff[4] = (int32_t)((coeff23 & 0xffff) << 16) >> 16;
coeff[8] = (int32_t)coeff23 >> 16;
coeff[6] = (int32_t)((coeff45 & 0xffff) << 16) >> 16;
coeff[7] = (int32_t)coeff45 >> 16;
coeff[11] = (int32_t)((coeff67 & 0xffff) << 16) >> 16;
coeff[9] = (int32_t)coeff67 >> 16;
coeff[10] = (int32_t)((coeff89 & 0xffff) << 16) >> 16;
if (scale > 12) {
shift = scale - 12;
for (i = 3; i < 12; i++)
coeff[i] = (coeff[i] + (1 << (shift - 1))) >> shift;
} else if (scale < 12) {
shift = 12 - scale;
for (i = 3; i < 12; i++)
coeff[i] <<= shift;
}
/* post offset */
coeff[18] = offset[0];
coeff[19] = offset[1];
coeff[20] = offset[2];
coeff[5] = ((coeff[3] + coeff[4] + coeff[5]) & 0xfffe)
- coeff[3] - coeff[4];
coeff[8] = 0 - coeff[6] - coeff[7];
coeff[11] = 0 - coeff[9] - coeff[10];
coeff[18] -= (0x1000 - coeff[3] - coeff[4] - coeff[5]) >> 1;
coeff[22] = 2;
vpp_set_mtx_en_read();
WRITE_VPP_REG(VPP_MATRIX_CTRL, 0);
set_vpp_matrix(VPP_MATRIX_OSD,
cur_osd_mtx, CSC_OFF);
set_vpp_matrix(VPP_MATRIX_VD1,
cur_vd1_mtx, CSC_OFF);
set_vpp_matrix(VPP_MATRIX_POST,
coeff, CSC_ON);
vpp_set_mtx_en_write();
}
return 0;
}
static int dolby_core2_set(
const uint32_t dm_count,
const 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;
uint32_t bypass_flag = 0;
uint32_t g_htotal_add = 0x40;
uint32_t g_vtotal_add = 0x80;
uint32_t g_vsize_add = 0;
uint32_t g_vwidth = 0x18;
uint32_t g_hwidth = 0x10;
uint32_t g_vpotch;
uint32_t g_hpotch = 0x10;
u32 addr = 0;
/* 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 if ((vinfo_width == 1280) &&
(vinfo_height == 720) &&
(vinfo_field_height < 720))
g_vpotch = 0x60;
else if ((vinfo_width == 1920) &&
(vinfo_height == 1080) &&
(vinfo_duration_num == 24))
g_vpotch = 0x60;
else if ((vinfo_width == 1920) &&
(vinfo_height == 1080) &&
(vinfo_field_height < 1080))
g_vpotch = 0x60;
else if ((vinfo_width == 1280) && (vinfo_height == 720))
g_vpotch = 0x38;
else
g_vpotch = 0x20;
WRITE_VPP_REG(DOLBY_CORE2A_CLKGATE_CTRL, 0);
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL0, 0);
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL1,
((hsize + g_htotal_add) << 16)
| (vsize + g_vtotal_add + g_vsize_add));
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL2,
(hsize << 16) | (vsize + g_vsize_add));
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL3,
(g_hwidth << 16) | g_vwidth);
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL4,
(g_hpotch << 16) | g_vpotch);
if (is_meson_txlx_stbmode())
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL5, 0xf8000000);
else if (is_meson_g12() || is_meson_tm2_stbmode() || is_meson_sc2())
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL5, 0xa8000000);
else
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL5, 0x0);
WRITE_VPP_REG(DOLBY_CORE2A_DMA_CTRL, 0x0);
WRITE_VPP_REG(DOLBY_CORE2A_Metadata_Start, 1);
if (need_skip_cvm(1))
bypass_flag |= 1 << 0;
WRITE_VPP_REG(DOLBY_CORE2A_Metadata_Start, 1);
WRITE_VPP_REG(DOLBY_CORE2A_CTRL,
2 | bypass_flag);
WRITE_VPP_REG(DOLBY_CORE2A_CTRL,
2 | bypass_flag);
WRITE_VPP_REG(DOLBY_CORE2A_CTRL, 0);
WRITE_VPP_REG(DOLBY_CORE2A_CTRL, 0);
if (dm_count == 0)
count = 24;
else
count = dm_count;
addr = phyaddr_to_dvaddr(DOLBY_CORE2A_REG_START);
for (i = 0; i < count; i++)
WRITE_VPP_REG(addr + 6 + i,
p_core2_dm_regs[i]);
/* core2 metadata program done */
WRITE_VPP_REG(DOLBY_CORE2A_Metadata_End, 1);
if (lut_count == 0)
count = 256 * 5;
else
count = lut_count;
WRITE_VPP_REG(DOLBY_CORE2A_DMA_CTRL, 0x1401);
if (lut_endian)
for (i = 0; i < count; i += 4) {
WRITE_VPP_REG(DOLBY_CORE2A_DMA_PORT,
p_core2_lut[i+3]);
WRITE_VPP_REG(DOLBY_CORE2A_DMA_PORT,
p_core2_lut[i+2]);
WRITE_VPP_REG(DOLBY_CORE2A_DMA_PORT,
p_core2_lut[i+1]);
WRITE_VPP_REG(DOLBY_CORE2A_DMA_PORT,
p_core2_lut[i]);
}
else
for (i = 0; i < count; i++)
WRITE_VPP_REG(DOLBY_CORE2A_DMA_PORT,
p_core2_lut[i]);
/* enable core2 */
WRITE_VPP_REG(DOLBY_CORE2A_SWAP_CTRL0, dolby_enable << 0);
if (debug_enable) {
printf("core2\n");
for (i = 0; i < 24; i++)
printf("%08x\n", p_core2_dm_regs[i]);
printf("core2 swap\n");
for (i = DOLBY_CORE2A_CLKGATE_CTRL;
i <= DOLBY_CORE2A_DMA_PORT; i+=4)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
addr = phyaddr_to_dvaddr(DOLBY_CORE2A_REG_START);
for (i = addr; i <= addr + 5; i++)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
}
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 diag_enable = 0;
uint32_t htotal_add = 0x140;
uint32_t vtotal_add = 0x40;
uint32_t vsize_add = 0;
u32 addr = 0;
if (dovi_setting.diagnostic_enable
|| dovi_setting.dovi_ll_enable)
diag_enable = 1;
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() || is_meson_tm2_stbmode() || is_meson_sc2()) {
if (dolby_vision_ll_policy == DOLBY_VISION_LL_YUV422)
diag_mode = 0x20;
else
diag_mode = 3;
} else
diag_mode = 3;
}
if (is_meson_box() || is_meson_tm2_stbmode()) {
if (dovi_setting.dovi_ll_enable &&
dovi_setting.diagnostic_enable == 0) {
WRITE_VPP_REG_BITS(
VPP_DOLBY_CTRL,
3, 6, 2); /* post matrix */
WRITE_VPP_REG_BITS(
VPP_MATRIX_CTRL,
1, 0, 1); /* post matrix */
} else {
WRITE_VPP_REG_BITS(
VPP_DOLBY_CTRL,
0, 6, 2); /* post matrix */
WRITE_VPP_REG_BITS(
VPP_MATRIX_CTRL,
0, 0, 1); /* post matrix */
}
} else if (is_meson_txlx_stbmode()) {
WRITE_VPP_REG_BITS(
VPP_DOLBY_CTRL,
1, 0, 1); /* skip pps/dither/cm */
WRITE_VPP_REG(
VPP_DAT_CONV_PARA0, 0x08000800);
if (dovi_setting.dovi_ll_enable &&
dovi_setting.diagnostic_enable == 0) {
/*bypass gainoff to vks */
/*enable wn tp vks*/
WRITE_VPP_REG_BITS(
VPP_DOLBY_CTRL, 0, 2, 1);
WRITE_VPP_REG_BITS(
VPP_DOLBY_CTRL, 1, 1, 1);
WRITE_VPP_REG(
VPP_DAT_CONV_PARA1, 0x8000800);
WRITE_VPP_REG_BITS(
VPP_MATRIX_CTRL,
1, 0, 1); /* post matrix */
} else {
/* bypass wm tp vks*/
WRITE_VPP_REG_BITS(
VPP_DOLBY_CTRL, 1, 2, 1);
WRITE_VPP_REG_BITS(
VPP_DOLBY_CTRL, 0, 1, 1);
WRITE_VPP_REG(
VPP_DAT_CONV_PARA1, 0x20002000);
if (is_meson_tvmode())
enable_rgb_to_yuv_matrix_for_dvll(
0, NULL, 12);
else
WRITE_VPP_REG_BITS(
VPP_MATRIX_CTRL,
0, 0, 1);
}
}
/* flush post matrix table when ll mode on and setting changed */
if (dovi_setting.dovi_ll_enable &&
(dovi_setting.diagnostic_enable == 0))
enable_rgb_to_yuv_matrix_for_dvll(
1, &p_core3_dm_regs[18], 12);
WRITE_VPP_REG(DOLBY_CORE3_CLKGATE_CTRL, 0);
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL1,
((hsize + htotal_add) << 16)
| (vsize + vtotal_add + vsize_add + vsize_hold * 2));
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL2,
(hsize << 16) | (vsize + vsize_add));
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL3,
(0x80 << 16) | vsize_hold);
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL4,
(0x04 << 16) | vsize_hold);
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL5, 0x0000);
if (cur_dv_mode != DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL)
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL6, 0);
else
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL6,
0x10000000); /* swap UV */
WRITE_VPP_REG(DOLBY_CORE3_Interrupt_Enable, 7);
WRITE_VPP_REG(DOLBY_CORE3_Interrupt_Raw, 4);
WRITE_VPP_REG(DOLBY_CORE3_Interrupt_Raw, 2);
WRITE_VPP_REG(DOLBY_CORE3_Metadata_Start, 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*/
WRITE_VPP_REG(DOLBY_CORE3_CTRL, cur_dv_mode);
WRITE_VPP_REG(DOLBY_CORE3_CTRL, cur_dv_mode);
/* for delay */
if (dm_count == 0)
count = 26;
else
count = dm_count;
addr = phyaddr_to_dvaddr(DOLBY_CORE3_REG_START);
for (i = 0; i < count; i++) {
WRITE_VPP_REG(addr + 0x6 + i,
p_core3_dm_regs[i]);
}
/* from addr 0x18 */
count = md_count;
for (i = 0; i < count; i++) {
WRITE_VPP_REG(addr + 0x24 + i,
p_core3_md_regs[i]);
}
for (; i < (128+1); i++) {
WRITE_VPP_REG(addr + (0x24 + i), 0);
}
/* from addr 0x90 */
/* core3 metadata program done */
WRITE_VPP_REG(DOLBY_CORE3_Metadata_End, 1);
WRITE_VPP_REG(DOLBY_CORE3_DIAG_CTRL, diag_mode);
/* enable core3 */
WRITE_VPP_REG(DOLBY_CORE3_SWAP_CTRL0, (dolby_enable << 0));
if (debug_enable) {
printf("core3\n");
for (i = 0; i < 26; i++)
printf("%08x\n", p_core3_dm_regs[i]);
printf("core3 swap\n");
for (i = DOLBY_CORE3_CLKGATE_CTRL;
i <= DOLBY_CORE3_OUTPUT_CSC_CRC; i+=4)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
printf("core3 real reg\n");
addr = phyaddr_to_dvaddr(DOLBY_CORE3_REG_START);
for (i = addr; i <= (addr + 67); i++)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
printf("core3 metadata, count %d\n",md_count);
for (i = 0; i < md_count; i++)
printf("%08x\n", p_core3_md_regs[i]);
}
return 0;
}
int apply_stb_core_settings(void)
{
uint32_t graphics_w = 1920;
uint32_t graphics_h = 1080;
if (!is_dolby_enable())
return 0;
if (dovi_setting.dst_format == FORMAT_INVALID)
return 0;
printf("apply_stb_core_settings\n");
if (dovi_setting.dst_format == FORMAT_DOVI) {
if (dovi_setting.dovi_ll_enable) {
if (dovi_setting.diagnostic_enable) {
dolby_vision_mode = DOLBY_VISION_OUTPUT_MODE_IPT;
dolby_vision_ll_policy = DOLBY_VISION_LL_RGB444;
} else {
dolby_vision_mode = DOLBY_VISION_OUTPUT_MODE_IPT;
dolby_vision_ll_policy = DOLBY_VISION_LL_YUV422;
}
} else
dolby_vision_mode = DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL;
} else if (dovi_setting.dst_format == FORMAT_HDR10)
dolby_vision_mode = DOLBY_VISION_OUTPUT_MODE_HDR10;
else
dolby_vision_mode = DOLBY_VISION_OUTPUT_MODE_SDR8;
dolby_core2_set(24, 256 * 5,
(uint32_t *)&dovi_setting.dm_reg2,
(uint32_t *)&dovi_setting.dm_lut2,
graphics_w, graphics_h, 1, 1);
dolby_core3_set(26, dovi_setting.md_reg3.size,
(uint32_t *)&dovi_setting.dm_reg3,
dovi_setting.md_reg3.raw_metadata,
vinfo_width, vinfo_height, 1, 1, 0);
return 0;
}
static int enable_dolby_vision(void)
{
printf("enable_dolby_vision\n");
if (is_meson_g12() || is_meson_tm2_stbmode() || is_meson_sc2()) {
hdr_func(OSD1_HDR, RGB_BYPASS);
hdr_func(OSD2_HDR, RGB_BYPASS);
/*enable core3*/
WRITE_VPP_REG_BITS(VPP_DOLBY_CTRL, 1, 3, 1);
/*enable core2*/
WRITE_VPP_REG_BITS(DOLBY_PATH_CTRL, 0, 2, 1);
/* bypass all video effect */
video_effect_bypass(1);
/* 12->10 before vadj1*/
/* 10->12 before post blend */
WRITE_VPP_REG(VPP_DAT_CONV_PARA0,
0x20002000);
/* 12->10 before vadj2*/
/* 10->12 after gainoff */
WRITE_VPP_REG(VPP_DAT_CONV_PARA1,
0x20002000);
WRITE_VPP_REG(VPP_MATRIX_CTRL, 0);
WRITE_VPP_REG(VPP_DUMMY_DATA1,0x80200);
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) {
uint32_t *reg = (uint32_t *)&dovi_setting.dm_reg3;
/* input u12 -0x800 to s12 */
WRITE_VPP_REG(VPP_DAT_CONV_PARA1,
0x8000800);
/* bypass vadj */
WRITE_VPP_REG(VPP_VADJ_CTRL, 0);
/* bypass gainoff */
WRITE_VPP_REG(VPP_GAINOFF_CTRL0, 0);
/* enable wm tp vks*/
/* bypass gainoff to vks */
WRITE_VPP_REG_BITS(VPP_DOLBY_CTRL, 1, 1, 2);
enable_rgb_to_yuv_matrix_for_dvll(1, &reg[18],
(dv_ll_output_mode >> 8)& 0xff);
} else
enable_rgb_to_yuv_matrix_for_dvll(0, NULL, 12);
dolby_vision_on = true;
env_set("dolby_vision_on", "1");
run_command("saveenv", 0);
printk("Dolby Vision turn on\n");
}
return 0;
}
static int prepare_drm_pkt(struct master_display_info_s *data,
struct dovi_setting_s *setting, const struct hdmitx_dev *hdmitx_device)
{
struct hdr_10_infoframe_s *p_hdr;
p_hdr = &(setting->hdr_info);
if (!data || !hdmitx_device || !setting)
return -1;
data->features = (1 << 29) | (5 << 26) | (0 << 25) | (1 << 24)
| (9 << 16) | (0x10 << 8) | (10 << 0);
data->primaries[0][0] =
(p_hdr->display_primaries_x_1_MSB << 8)
| p_hdr->display_primaries_x_1_LSB;
data->primaries[0][1] =
(p_hdr->display_primaries_y_1_MSB << 8)
| p_hdr->display_primaries_y_1_LSB;
data->primaries[1][0] =
(p_hdr->display_primaries_x_2_MSB << 8)
| p_hdr->display_primaries_x_2_LSB;
data->primaries[1][1] =
(p_hdr->display_primaries_y_2_MSB << 8)
| p_hdr->display_primaries_y_2_LSB;
data->primaries[2][0] =
(p_hdr->display_primaries_x_0_MSB << 8)
| p_hdr->display_primaries_x_0_LSB;
data->primaries[2][1] =
(p_hdr->display_primaries_y_0_MSB << 8)
| p_hdr->display_primaries_y_0_LSB;
data->white_point[0] =
(p_hdr->white_point_x_MSB << 8)
| p_hdr->white_point_x_LSB;
data->white_point[1] =
(p_hdr->white_point_y_MSB << 8)
| p_hdr->white_point_y_LSB;
data->luminance[0] =
(p_hdr->max_display_mastering_luminance_MSB << 8)
| p_hdr->max_display_mastering_luminance_LSB;
data->luminance[1] =
(p_hdr->min_display_mastering_luminance_MSB << 8)
| p_hdr->min_display_mastering_luminance_LSB;
data->max_content =
(p_hdr->max_content_light_level_MSB << 8)
| p_hdr->max_content_light_level_LSB;
data->max_frame_average =
(p_hdr->max_frame_average_light_level_MSB << 8)
| p_hdr->max_frame_average_light_level_LSB;
return 0;
}
static int prepare_vsif_pkt(struct dv_vsif_para *vsif,
struct dovi_setting_s *setting, const struct hdmitx_dev *hdmitx_device)
{
if (!vsif || !hdmitx_device || !setting)
return -1;
vsif->vers.ver2.low_latency = setting->dovi_ll_enable;
vsif->vers.ver2.dobly_vision_signal = 1;
if (hdmitx_device->RXCap.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;
}
void send_hdmi_pkt(void)
{
struct dv_vsif_para vsif;
struct master_display_info_s drmif;
struct hdmitx_dev *hdev = hdmitx_get_hdev();
if (!is_dolby_enable())
return;
printf("send_hdmi_pkt %d\n",dovi_setting.dst_format);
if (dovi_setting.dst_format == FORMAT_DOVI) {
memset(&vsif, 0, sizeof(vsif));
prepare_vsif_pkt(&vsif, &dovi_setting, hdev);
if (dovi_setting.dovi_ll_enable)
hdmitx_set_vsif_pkt( EOTF_T_LL_MODE,
dovi_setting.diagnostic_enable
? RGB_10_12BIT : YUV422_BIT12,
&vsif);
else
hdmitx_set_vsif_pkt(EOTF_T_DOLBYVISION, RGB_8BIT,
&vsif);
} else if (dovi_setting.dst_format == FORMAT_HDR10) {
memset(&drmif, 0, sizeof(drmif));
prepare_drm_pkt(&drmif, &dovi_setting, hdev);
#ifdef CONFIG_AML_HDMITX20
hdmitx_set_drm_pkt(&drmif);
#endif
} else
return;
}
/*check hpd status:
*1. hdmi connected: set hdr/dv mode based on capability of TV if dv enabled.
*2. no hdmi: output sdr if dv enabled.
*/
void dolby_vision_process(void)
{
struct hdmitx_dev *hdev = hdmitx_get_hdev();
if (!check_tv_hpd_status(hdev)) {
if (is_dolby_enable()) {
dovi_setting.dst_format = FORMAT_SDR;
printf("dolby_vision_process: no hpd, dst_format = SDR\n");
} else {
printf("dolby_vision_process: no tv and dv disabled\n");
env_set("dolby_vision_on", "0");
run_command("saveenv", 0);
return;
}
} else {
if (is_dolby_enable()) {
check_tv_support(hdev);
printf("dolby_vision_process: hpd: dst_format=%d\n",
dovi_setting.dst_format);
} else {
printf("dolby_vision_process: hpd: dv disabled\n");
env_set("dolby_vision_on", "0");
run_command("saveenv", 0);
return;
}
}
if (dovi_setting.dst_format == FORMAT_INVALID) {
printf("dolby_vision_process: dst_format = FORMAT_INVALID\n");
return;
}
dolby_vision_parse(hdev);
apply_stb_core_settings();
enable_dolby_vision();
/*dv send hdmi vsif after hdmi set mode*/
/* so we add another cmd to send this hdmi package solely*/
}
void dolbyvision_dump_setting() {
int i;
uint32_t *p;
if (!is_dolby_enable()) {
printf("dv is disabled\n");
return;
}
printf("core2\n");
p = (uint32_t *)&dovi_setting.dm_reg2;
for (i = 0; i < 24; i++)
printf("%08x\n", p[i]);
printf("core2 swap\n");
for (i = DOLBY_CORE2A_CLKGATE_CTRL;
i <= DOLBY_CORE2A_DMA_PORT; i++)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
printf("core2 real reg\n");
for (i = DOLBY_CORE2A_REG_START;
i <= DOLBY_CORE2A_REG_START + 5; i++)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
printf("\ncore2lut\n");
p = (uint32_t *)&dovi_setting.dm_lut2.TmLutI;
for (i = 0; i < 64; i++)
printf("%08x, %08x, %08x, %08x\n",
p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]);
printf("\n");
p = (uint32_t *)&dovi_setting.dm_lut2.TmLutS;
for (i = 0; i < 64; i++)
printf("%08x, %08x, %08x, %08x\n",
p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]);
printf("\n");
p = (uint32_t *)&dovi_setting.dm_lut2.SmLutI;
for (i = 0; i < 64; i++)
printf("%08x, %08x, %08x, %08x\n",
p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]);
printf("\n");
p = (uint32_t *)&dovi_setting.dm_lut2.SmLutS;
for (i = 0; i < 64; i++)
printf("%08x, %08x, %08x, %08x\n",
p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]);
printf("\n");
p = (uint32_t *)&dovi_setting.dm_lut2.G2L;
for (i = 0; i < 64; i++)
printf("%08x, %08x, %08x, %08x\n",
p[i*4+3], p[i*4+2], p[i*4+1], p[i*4]);
printf("\n");
printf("core3\n");
p = (uint32_t *)&dovi_setting.dm_reg3;
for (i = 0; i < 26; i++)
printf("%08x\n", p[i]);
printf("core3 swap\n");
for (i = DOLBY_CORE3_CLKGATE_CTRL;
i <= DOLBY_CORE3_CLKGATE_CTRL + 13; i++)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
printf("core3 real reg\n");
for (i = DOLBY_CORE3_REG_START;
i <= DOLBY_CORE3_REG_START + 67; i++)
printf("[0x%4x] = 0x%x\n",
i, READ_VPP_REG(i));
if (dolby_vision_mode <= DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) {
printf("\ncore3_meta %d\n", dovi_setting.md_reg3.size);
p = dovi_setting.md_reg3.raw_metadata;
for (i = 0; i < dovi_setting.md_reg3.size; i++)
printf("%08x\n", p[i]);
printf("\n");
}
}
void dolbyvision_debug(int enable_debug) {
debug_enable = enable_debug;
}