1393 lines
38 KiB
C
1393 lines
38 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* drivers/display/osd/dolby_vision.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/arch/io.h>
|
|
#include <asm/arch/secure_apb.h>
|
|
#include <amlogic/vmode.h>
|
|
#include <amlogic/storage_if.h>
|
|
#include <amlogic/vout.h>
|
|
#include <amlogic/hdmi.h>
|
|
#include <amlogic/dolby_vision.h>
|
|
#include <malloc.h>
|
|
|
|
#include <config.h>
|
|
#include <mmc.h>
|
|
#include <asm/byteorder.h>
|
|
#include <asm/unaligned.h>
|
|
#include <amlogic/dolby_vision_func.h>
|
|
#include <asm/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, 375, 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;
|
|
|
|
static bool dv_fw_valid = true;
|
|
|
|
#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
|
|
|
|
#define REG_OFFSET_VCBUS(reg) ((reg << 2))
|
|
#define REG_ADDR_VCBUS(reg) (REG_BASE_VCBUS + REG_OFFSET_VCBUS(reg))
|
|
|
|
static inline u32 READ_VPP_REG(u32 reg)
|
|
{
|
|
return (*(volatile unsigned int *)REG_ADDR_VCBUS(reg));
|
|
}
|
|
|
|
static inline void WRITE_VPP_REG(u32 reg,
|
|
const u32 val)
|
|
{
|
|
*(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 bool is_meson_gxm(void)
|
|
{
|
|
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_GXM)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
static 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 bool is_meson_box(void)
|
|
{
|
|
if (is_meson_gxm() || is_meson_g12())
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool is_meson_txlx(void)
|
|
{
|
|
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_TXLX)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool is_meson_txlx_tvmode(void)
|
|
{
|
|
if ((is_meson_txlx()) && (tv_mode == 1))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
static bool is_meson_txlx_stbmode(void)
|
|
{
|
|
if ((is_meson_txlx()) && (tv_mode == 0))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
static bool is_meson_tm2(void)
|
|
{
|
|
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_TM2)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool is_meson_tm2_tvmode(void)
|
|
{
|
|
if ((is_meson_tm2()) && (tv_mode == 1))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool is_meson_tm2_stbmode(void)
|
|
{
|
|
if ((is_meson_tm2()) && (tv_mode == 0))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool is_meson_tvmode(void)
|
|
{
|
|
if (is_meson_tm2_tvmode() ||
|
|
is_meson_txlx_tvmode())
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
#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 = getenv("dolby_status");
|
|
|
|
printf("dolby_status %s %d\n", dolby_status, dv_fw_valid);
|
|
|
|
if (!dv_fw_valid || !dolby_status)
|
|
return 0;
|
|
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 = getenv("dolby_status");
|
|
|
|
if (!dolby_status)
|
|
return false;
|
|
|
|
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)) {
|
|
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_get_hpd_state_ext();
|
|
}
|
|
|
|
|
|
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 = getenv("outputmode");
|
|
printf("check_tv_support_dv, outputmode %s\n", outputmode);
|
|
|
|
if (!hdmitx_device)
|
|
return 0;
|
|
if (hdmitx_device->RXCap.dv_info.ieeeoui != 0x00d046)
|
|
return 0;
|
|
if (hdmitx_device->RXCap.dv_info.block_flag != CORRECT)
|
|
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 (!strcmp(outputmode, "2160p60hz420"))
|
|
setenv("outputmode", "2160p60hz");
|
|
if (!strcmp(outputmode, "2160p50hz420"))
|
|
setenv("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) {
|
|
setenv("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))
|
|
setenv("outputmode", "2160p60hz");
|
|
else
|
|
setenv("outputmode", "1080p60hz");
|
|
} else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1920x1080p60_16x9)
|
|
setenv("outputmode", "1080p60hz");
|
|
else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1920x1080p50_16x9)
|
|
setenv("outputmode", "1080p50hz");
|
|
else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1280x720p60_16x9)
|
|
setenv("outputmode", "720p60hz");
|
|
else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1280x720p50_16x9)
|
|
setenv("outputmode", "720p50hz");
|
|
else
|
|
setenv("outputmode", "1080p60hz");
|
|
printf("output dv standard mode : mode is : %s attr: %s\n",
|
|
getenv("outputmode"), getenv("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))
|
|
setenv("outputmode", "2160p60hz");
|
|
else
|
|
setenv("outputmode", "1080p60hz");
|
|
} else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1920x1080p60_16x9)
|
|
setenv("outputmode", "1080p60hz");
|
|
else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1920x1080p50_16x9)
|
|
setenv("outputmode", "1080p50hz");
|
|
else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1280x720p60_16x9)
|
|
setenv("outputmode", "720p60hz");
|
|
else if (hdmitx_device->RXCap.preferred_mode
|
|
== HDMI_1280x720p50_16x9)
|
|
setenv("outputmode", "720p50hz");
|
|
else
|
|
setenv("outputmode", "1080p60hz");
|
|
printf("output dv LL 422 mode : mode is : %s attr: %s\n",
|
|
getenv("outputmode"), getenv("colorattribute"));
|
|
} else if (dovi_mode.ll_rgb_444_10bit) {
|
|
setenv("colorattribute", "444,10bit");
|
|
setenv("outputmode", "1080p60hz");
|
|
printf("output dv LL 444 mode : mode is : %s attr: %s\n",
|
|
getenv("outputmode"), getenv("colorattribute"));
|
|
} else if (dovi_mode.ll_rgb_444_12bit) {
|
|
setenv("colorattribute", "444,12bit");
|
|
setenv("outputmode", "1080p60hz");
|
|
printf("output dv LL 444 mode : mode is : %s attr: %s\n",
|
|
getenv("outputmode"), getenv("colorattribute"));
|
|
} else {
|
|
setenv("colorattribute", "444,8bit");
|
|
setenv("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 = getenv("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 (strncmp(attr, "444,8bit", strlen("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 (strncmp(attr, "422,12bit", strlen("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 (strncmp(attr, "444,10bit", strlen("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",
|
|
getenv("outputmode"), getenv("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",
|
|
getenv("outputmode"), getenv("colorattribute"));
|
|
} else {
|
|
dovi_setting.dst_format = FORMAT_SDR;
|
|
printf("output sdr mode: mode is : %s attr: %s\n",
|
|
getenv("outputmode"), getenv("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 = getenv("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 int dolby_vision_parse(struct hdmitx_dev *hdmitx_device)
|
|
{
|
|
enum signal_format_enum src_format = FORMAT_SDR;
|
|
enum signal_format_enum 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;
|
|
int ret = 0;
|
|
|
|
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 = G_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];
|
|
|
|
ret = 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);
|
|
return ret;
|
|
}
|
|
|
|
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;
|
|
|
|
/* 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())
|
|
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_REG_START + 2, 1);
|
|
if (need_skip_cvm(1))
|
|
bypass_flag |= 1 << 0;
|
|
WRITE_VPP_REG(DOLBY_CORE2A_REG_START + 2, 1);
|
|
WRITE_VPP_REG(DOLBY_CORE2A_REG_START + 1,
|
|
2 | bypass_flag);
|
|
WRITE_VPP_REG(DOLBY_CORE2A_REG_START + 1,
|
|
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;
|
|
for (i = 0; i < count; i++)
|
|
WRITE_VPP_REG(
|
|
DOLBY_CORE2A_REG_START + 6 + i,
|
|
p_core2_dm_regs[i]);
|
|
|
|
/* core2 metadata program done */
|
|
WRITE_VPP_REG(DOLBY_CORE2A_REG_START + 3, 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++)
|
|
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));
|
|
}
|
|
|
|
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;
|
|
|
|
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()) {
|
|
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_REG_START + 5, 7);
|
|
WRITE_VPP_REG(DOLBY_CORE3_REG_START + 4, 4);
|
|
WRITE_VPP_REG(DOLBY_CORE3_REG_START + 4, 2);
|
|
WRITE_VPP_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*/
|
|
WRITE_VPP_REG(DOLBY_CORE3_REG_START + 1, cur_dv_mode);
|
|
WRITE_VPP_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++)
|
|
WRITE_VPP_REG(DOLBY_CORE3_REG_START + 0x6 + i,
|
|
p_core3_dm_regs[i]);
|
|
/* from addr 0x18 */
|
|
|
|
count = md_count;
|
|
for (i = 0; i < count; i++)
|
|
WRITE_VPP_REG(DOLBY_CORE3_REG_START + 0x24 + i,
|
|
p_core3_md_regs[i]);
|
|
for (; i < (128+1); i++)
|
|
WRITE_VPP_REG(DOLBY_CORE3_REG_START + 0x24 + i, 0);
|
|
|
|
/* from addr 0x90 */
|
|
/* core3 metadata program done */
|
|
WRITE_VPP_REG(DOLBY_CORE3_REG_START + 3, 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 <= 0x36fd; 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));
|
|
|
|
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("%s\n", __func__);
|
|
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("%s\n", __func__);
|
|
if (is_meson_g12() || is_meson_tm2_stbmode()) {
|
|
hdr_func(OSD1_HDR, HDR_BYPASS);
|
|
|
|
/*enable core3*/
|
|
WRITE_VPP_REG_BITS(VPP_DOLBY_CTRL, 1, 3, 1);
|
|
WRITE_VPP_REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL,
|
|
0x0);
|
|
WRITE_VPP_REG(VPP_WRAP_OSD2_MATRIX_EN_CTRL,
|
|
0x0);
|
|
WRITE_VPP_REG(VPP_WRAP_OSD3_MATRIX_EN_CTRL,
|
|
0x0);
|
|
|
|
/*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, ®[18],
|
|
(dv_ll_output_mode >> 8)& 0xff);
|
|
} else
|
|
enable_rgb_to_yuv_matrix_for_dvll(0, NULL, 12);
|
|
|
|
dolby_vision_on = true;
|
|
setenv("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 hdr10_infoframe *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);
|
|
|
|
/* ko return primaries in RGB order, uboot send pkt in RGB order, */
|
|
/* to keep same with kernel*/
|
|
data->primaries[0][0] = (p_hdr->primaries_x_0_msb << 8)
|
|
| p_hdr->primaries_x_0_lsb;
|
|
data->primaries[0][1] = (p_hdr->primaries_y_0_msb << 8)
|
|
| p_hdr->primaries_y_0_lsb;
|
|
data->primaries[1][0] = (p_hdr->primaries_x_1_msb << 8)
|
|
| p_hdr->primaries_x_1_lsb;
|
|
data->primaries[1][1] = (p_hdr->primaries_y_1_msb << 8)
|
|
| p_hdr->primaries_y_1_lsb;
|
|
data->primaries[2][0] = (p_hdr->primaries_x_2_msb << 8)
|
|
| p_hdr->primaries_x_2_lsb;
|
|
data->primaries[2][1] = (p_hdr->primaries_y_2_msb << 8)
|
|
| p_hdr->primaries_y_2_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_lum_msb << 8)
|
|
| p_hdr->max_display_mastering_lum_lsb;
|
|
data->luminance[1] =
|
|
(p_hdr->min_display_mastering_lum_msb << 8)
|
|
| p_hdr->min_display_mastering_lum_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_avg_light_level_msb << 8)
|
|
| p_hdr->max_frame_avg_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.avail_level_mask &
|
|
EXT_MD_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_h & 0xf;
|
|
vsif->vers.ver2.eff_tmax_PQ_low =
|
|
setting->ext_md.level_2.target_max_pq_l;
|
|
} 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.avail_level_mask &
|
|
EXT_MD_LEVEL_255)) {
|
|
vsif->vers.ver2.auxiliary_MD_present = 1;
|
|
vsif->vers.ver2.auxiliary_runmode =
|
|
setting->ext_md.level_255.run_mode;
|
|
vsif->vers.ver2.auxiliary_runversion =
|
|
setting->ext_md.level_255.run_version;
|
|
vsif->vers.ver2.auxiliary_debug0 =
|
|
setting->ext_md.level_255.dm_debug_0;
|
|
} 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;
|
|
}
|
|
|
|
static const char *output_str[4] = {
|
|
"DOVI",
|
|
"HDR10",
|
|
"SDR",
|
|
"DOVI_LL"
|
|
};
|
|
|
|
void send_hdmi_pkt(void)
|
|
{
|
|
struct dv_vsif_para vsif;
|
|
struct master_display_info_s drmif;
|
|
|
|
if (!is_dolby_enable())
|
|
return;
|
|
|
|
printf("send hdmi pkt %d [%s] dovi_setting.dst_format = %d\n",
|
|
dovi_setting.dst_format,
|
|
(dovi_setting.dst_format >= 0 && dovi_setting.dst_format < 4) ?
|
|
output_str[dovi_setting.dst_format] : "NULL",
|
|
dovi_setting.dst_format);
|
|
|
|
if (dovi_setting.dst_format == FORMAT_DOVI) {
|
|
memset(&vsif, 0, sizeof(vsif));
|
|
prepare_vsif_pkt(&vsif, &dovi_setting, &hdmitx_device);
|
|
|
|
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, &hdmitx_device);
|
|
hdmitx_set_drm_pkt(&drmif);
|
|
} 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)
|
|
{
|
|
if (!check_tv_hpd_status(&hdmitx_device)) {
|
|
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");
|
|
setenv("dolby_vision_on", "0");
|
|
run_command("saveenv", 0);
|
|
return;
|
|
}
|
|
} else {
|
|
if (is_dolby_enable()) {
|
|
check_tv_support(&hdmitx_device);
|
|
printf("dolby_vision_process: hpd: dst_format=%d\n",
|
|
dovi_setting.dst_format);
|
|
} else {
|
|
printf("dolby_vision_process: hpd: dv disabled\n");
|
|
setenv("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");
|
|
setenv("dolby_vision_on", "0");
|
|
run_command("saveenv", 0);
|
|
return;
|
|
}
|
|
if (dolby_vision_parse(&hdmitx_device) == 0) {
|
|
apply_stb_core_settings();
|
|
enable_dolby_vision();
|
|
} else {
|
|
printf("dolby_vision_process: control path failed\n");
|
|
dovi_setting.dst_format = FORMAT_INVALID;
|
|
dv_fw_valid = false;
|
|
setenv("dolby_vision_on", "0");
|
|
run_command("saveenv", 0);
|
|
return;
|
|
}
|
|
/*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.tm_lut_i;
|
|
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.tm_lut_s;
|
|
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.sm_lut_i;
|
|
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.sm_lut_s;
|
|
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.g_2_l;
|
|
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;
|
|
}
|