drm/rockchip: vop2: add dolby vision supported for rk3588

The dolby vision will be supported by RK3588*-*V* SOCs,
e.g., RK3588S2-DV.

Signed-off-by: Sandy Huang <hjc@rock-chips.com>
Change-Id: I1e8cf8f0e2b1521b858704df9a88261cec038ebb
This commit is contained in:
Sandy Huang
2024-12-16 11:21:49 +08:00
committed by Tao Huang
parent 6cb13bd18d
commit 16391830d3
7 changed files with 947 additions and 45 deletions

View File

@@ -1613,7 +1613,7 @@ static int rockchip_drm_create_properties(struct drm_device *dev)
struct rockchip_drm_private *private = dev->dev_private;
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
"EOTF", 0, 5);
"EOTF", 0, HDMI_EOTF_DOVI);
if (!prop)
return -ENOMEM;
private->eotf_prop = prop;
@@ -1651,6 +1651,12 @@ static int rockchip_drm_create_properties(struct drm_device *dev)
"PORT_ID", DRM_MODE_OBJECT_CRTC);
private->port_id_prop = prop;
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
"DOVI_INPUT_TYPE", 0, DOVI_ENHANCE_LAYER);
if (!prop)
return -ENOMEM;
private->dovi_input_type_prop = prop;
private->aclk_prop = drm_property_create_range(dev, 0, "ACLK", 0, UINT_MAX);
private->bg_prop = drm_property_create_range(dev, 0, "BACKGROUND", 0, UINT_MAX);
private->line_flag_prop = drm_property_create_range(dev, 0, "LINE_FLAG1", 0, UINT_MAX);

View File

@@ -31,7 +31,7 @@
#define ROCKCHIP_MAX_CONNECTOR 2
#define ROCKCHIP_MAX_CRTC 4
#define ROCKCHIP_MAX_LAYER 16
#define ROCKCHIP_MAX_DOVI_CORE 3
struct drm_device;
struct drm_connector;
@@ -61,6 +61,20 @@ struct iommu_domain;
#define RK_IF_PROP_COLOR_FORMAT_CAPS "color_format_caps"
#define RK_IF_PROP_ENCRYPTED "hdcp_encrypted"
/*
* This is extend by rockchip, the other EOTF is defined at hdmi.h
*
* enum hdmi_eotf {
* HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
* HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
* HDMI_EOTF_SMPTE_ST2084,
* HDMI_EOTF_BT_2100_HLG,
*};
*/
#define HDMI_EOTF_HDR10PLUS 0x10
#define HDMI_EOTF_HDRVIVID 0x11
#define HDMI_EOTF_DOVI 0x12
enum rockchip_drm_debug_category {
VOP_DEBUG_PLANE = BIT(0),
VOP_DEBUG_OVERLAY = BIT(1),
@@ -158,6 +172,8 @@ struct rockchip_bcsh_state {
struct rockchip_crtc {
struct drm_crtc crtc;
/* @frme_count: the frame num of commit buf */
u32 frame_count;
#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
/**
* @vop_dump_status the status of vop dump control
@@ -553,6 +569,7 @@ struct rockchip_drm_private {
struct drm_property *eotf_prop;
struct drm_property *async_commit_prop;
struct drm_property *share_id_prop;
struct drm_property *dovi_input_type_prop;
/* private connector prop */
struct drm_property *connector_id_prop;

View File

@@ -70,7 +70,6 @@
#define VOP_FEATURE_INTERNAL_RGB BIT(1)
#define VOP_FEATURE_ALPHA_SCALE BIT(2)
#define VOP_FEATURE_HDR10 BIT(3)
#define VOP_FEATURE_NEXT_HDR BIT(4)
#define VOP_FEATURE_DOVI BIT(4)
/* a feature to splice two windows and two vps to support resolution > 4096 */
#define VOP_FEATURE_SPLICE BIT(5)
@@ -141,6 +140,10 @@ enum vop2_win_dly_mode {
VOP2_DLY_MODE_DEFAULT, /**< default mode */
VOP2_DLY_MODE_HISO_S, /** HDR in SDR out mode, as a SDR window */
VOP2_DLY_MODE_HIHO_H, /** HDR in HDR out mode, as a HDR window */
VOP2_DLY_MODE_DOVI_IN_CORE1, /* dovi video input, as dovi core1 */
VOP2_DLY_MODE_DOVI_IN_CORE2, /* dovi video input, as dovi core2 */
VOP2_DLY_MODE_NONDOVI_IN_CORE1, /* ndovi video input, as dovi core1 */
VOP2_DLY_MODE_NONDOVI_IN_CORE2, /* ndovi video input, as dovi core2 */
VOP2_DLY_MODE_MAX,
};
@@ -615,11 +618,40 @@ struct hdrvivid_regs {
#define RK_HDR_TYPE_MASK 0xff
#define RK_HDR_PLAT_MASK (0xff << 8)
/* byte unit */
#define VOP2_DOVI_CORE1_LUT_SIZE 5120
#define VOP2_DOVI_TONE_SCA_AXI_TAB_SIZE (2560 * 4)
/* word unit */
#define DOVI_LUT_SIZE 1280
#define DOVI_CORE1_SIZE 242
#define DOVI_CORE2_SIZE 43
#define DOVI_CORE3_SIZE 256
enum vop_dovi_input_type {
COMMON_LAYER = 0,
DOVI_BASE_LAYER = 1,
DOVI_ENHANCE_LAYER = 2,
};
struct dovi_regs {
uint32_t version;
uint32_t valid;
uint32_t input_mode;
uint32_t output_mode;
uint32_t core1_lut[DOVI_LUT_SIZE];
uint32_t core2_lut[DOVI_LUT_SIZE];
uint32_t core1[DOVI_CORE1_SIZE];
uint32_t core2[DOVI_CORE2_SIZE];
uint32_t core3[DOVI_CORE3_SIZE];
};
struct hdr_extend {
uint32_t hdr_type;
uint32_t length;
union {
struct hdrvivid_regs hdrvivid_data;
struct dovi_regs dovi_data;
};
};
@@ -650,7 +682,7 @@ enum vop_hdr_format {
HDR_HDR10PLUS = 8,
RESERVED9 = 9, /* reserved for hdr hdr10+ */
RESERVED10 = 10, /* reserved for hdr hdr10+ */
HDR_NEXT = 11,
HDR_DOVI = 11,
RESERVED12 = 12, /* reserved for other dynamic hdr format */
RESERVED13 = 13, /* reserved for other dynamic hdr format */
HDR_FORMAT_MAX,
@@ -883,6 +915,10 @@ struct vop2_video_port_regs {
struct vop_reg dsp_x_mir_en;
struct vop_reg post_dsp_out_r2y;
struct vop_reg pre_scan_htiming;
struct vop_reg dovi_pre_scan_en;
struct vop_reg pre_scan_htiming1;
struct vop_reg pre_scan_htiming2;
struct vop_reg pre_scan_htiming3;
struct vop_reg htotal_pw;
struct vop_reg hact_st_end;
struct vop_reg dsp_vtotal;
@@ -905,6 +941,8 @@ struct vop2_video_port_regs {
struct vop_reg dither_frc_2;
struct vop_reg dither_up_en;
struct vop_reg bg_dly;
struct vop_reg dp_line_end_mode;
struct vop_reg dp_bg_bottom_disable;
struct vop_reg p2i_en;
struct vop_reg dual_channel_en;
@@ -1050,6 +1088,37 @@ struct vop2_power_domain_regs {
struct vop_reg pmu_status;
};
struct vop2_dovi_regs {
/* common */
struct vop_reg enable;
struct vop_reg interrupt_enable;
struct vop_reg interrupt_raw;
struct vop_reg metadata_program_st;
struct vop_reg metadata_program_end;
struct vop_reg metadata_copy_finish;
/* core1 */
struct vop_reg bypass_composer;
struct vop_reg bypass_csc;
struct vop_reg bypass_cvm;
struct vop_reg operating_mode;
struct vop_reg pixel_rate;
/* core2 */
struct vop_reg yuv2rgb_en;
struct vop_reg yuv422to444_en;
struct vop_reg yuv_swap;
struct vop_reg yuv422_en;
struct vop_reg dly_en;
/* core1 and core2 */
struct vop_reg lut_mst;
struct vop_reg lut_update;
/* core3 */
struct vop_reg output_mode;
};
struct vop2_dsc_regs {
/* DSC SYS CTRL */
struct vop_reg dsc_port_sel;
@@ -1184,6 +1253,21 @@ struct vop2_win_data {
const uint8_t dly[VOP2_DLY_MODE_MAX];
};
struct vop2_dovi_core_data {
const uint8_t id;
const uint32_t ctrl_offset;
const uint32_t srange_offset;
const uint32_t srange_offset_from_core;
const struct vop2_dovi_regs *regs;
};
struct vop2_dovi_data {
const uint8_t nr_dovi_cores;
const uint8_t dovi_max_delay[2];
const uint32_t enhance_layer_phy_id;
const struct vop2_dovi_core_data *dovi_core_data;
};
struct dsc_error_info {
u32 dsc_error_val;
char dsc_error_info[50];
@@ -1481,6 +1565,10 @@ struct vop2_ctrl {
struct vop_reg vp_intr_merge_en;
struct vop_reg reg_done_frm;
struct vop_reg cfg_done;
struct vop_reg dovi_core1_en;
struct vop_reg dovi_core2_en;
struct vop_reg dovi_core3_en;
};
struct vop_dump_regs {
@@ -1529,6 +1617,7 @@ struct vop2_data {
const struct vop2_esmart_lb_map *esmart_lb_mode_map;
const struct vop_intr *axi_intr;
const struct vop2_ctrl *ctrl;
const struct vop2_dovi_data *dovi;
const struct vop2_dsc_data *dsc;
const struct dsc_error_info *dsc_error_ecw;
const struct dsc_error_info *dsc_error_buffer_flow;
@@ -1581,6 +1670,9 @@ struct vop2_data {
#define WB_YRGB_FIFO_FULL_INTR BIT(18)
#define WB_COMPLETE_INTR BIT(19)
#define MMU_EN_INTR BIT(20)
#define DOLBY_CORE1_INTR BIT(21)
#define DOLBY_CORE2_INTR BIT(22)
#define DOLBY_CORE3_INTR BIT(23)
#define INTR_MASK (DSP_HOLD_VALID_INTR | FS_INTR | \
LINE_FLAG_INTR | BUS_ERROR_INTR | \
@@ -1590,7 +1682,8 @@ struct vop2_data {
HWC_EMPTY_INTR | \
POST_BUF_EMPTY_INTR | \
DMA_FINISH_INTR | FS_FIELD_INTR | \
FE_INTR | WB_COMPLETE_INTR | MMU_EN_INTR)
FE_INTR | WB_COMPLETE_INTR | MMU_EN_INTR | \
DOLBY_CORE1_INTR | DOLBY_CORE2_INTR | DOLBY_CORE3_INTR)
#define DSP_HOLD_VALID_INTR_EN(x) ((x) << 4)
#define FS_INTR_EN(x) ((x) << 5)
#define LINE_FLAG_INTR_EN(x) ((x) << 6)

View File

@@ -370,6 +370,7 @@ struct vop2_plane_state {
uint64_t color_key;
unsigned long offset;
int pdaf_data_type;
u8 dovi_input_type;
bool async_commit;
struct drm_property_blob *dci_data;
@@ -539,6 +540,12 @@ struct vop2_wb {
};
struct vop2_dovi_core {
uint8_t id;
struct vop2 *vop2;
const struct vop2_dovi_regs *regs;
};
struct vop2_dsc {
uint8_t id;
uint8_t max_slice_num;
@@ -635,6 +642,19 @@ struct vop2_video_port {
*/
int hdr_en;
/**
* @dovi_hdr_mode: Set when use dovi.
*/
bool dovi_hdr_mode;
/**
* @dovi_hdr_en: Set when dovi enabled.
*/
bool dovi_hdr_en;
/**
* @dovi_hdr_in: Set when dovi input.
*/
bool dovi_hdr_in;
/**
* -----------------
* | | |
@@ -722,6 +742,11 @@ struct vop2_video_port {
*/
struct rockchip_gem_object *hdr_lut_gem_obj;
/**
* @dovi_lut_gem_obj: gem obj to store dovi lut
*/
struct rockchip_gem_object *dovi_lut_gem_obj;
/**
* @cubic_lut: cubic look up table
*/
@@ -856,6 +881,7 @@ struct vop2 {
u32 version;
struct device *dev;
struct drm_device *drm_dev;
struct vop2_dovi_core dovi_cores[ROCKCHIP_MAX_DOVI_CORE];
struct vop2_dsc dscs[ROCKCHIP_MAX_CRTC];
struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];
struct vop2_wb wb;
@@ -962,6 +988,9 @@ struct vop2 {
struct clk *hclk;
struct clk *aclk;
struct clk *pclk;
struct clk *aclk_dovi;
struct clk *aclk_div2_src;
struct clk *aclk_root;
struct reset_control *ahb_rst;
struct reset_control *axi_rst;
struct csu_clk *csu_aclk;
@@ -1175,6 +1204,11 @@ static inline bool is_vop3(struct vop2 *vop2)
return true;
}
static inline bool vop2_is_dovi_mode(struct vop2_video_port *vp)
{
return vp->dovi_hdr_mode;
}
static bool vop2_soc_is_rk3566(void)
{
return soc_is_rk3566();
@@ -3302,6 +3336,19 @@ static void vop2_setup_csc_mode(struct vop2_video_port *vp,
vpstate->r2y_en = 0;
vpstate->csc_mode = 0;
/**
* DOVI core1 input format must YUV422, VOP win will do:
* [YUV420/422 -> YUV444], [YUV444 -> YUV422] -> core1
* DOVI core2 input format must RGB
*/
if (vop2_is_dovi_mode(vp)) {
if (vpstate->dovi_input_type && !is_input_yuv)
drm_err(vp->vop2, "DOVI core1 input format must YUV format\n");
if (!vpstate->dovi_input_type && is_input_yuv)
drm_err(vp->vop2, "DOVI core2 input format must RGB format\n");
return;
}
if (is_vop3(vp->vop2)) {
if (vpstate->hdr_in) {
if (is_input_yuv) {
@@ -4719,6 +4766,379 @@ static void vop2_power_off_all_pd(struct vop2 *vop2)
}
}
static bool vop2_check_dovi_core_enabled(int id, u32 valid)
{
if (valid & (BIT(id - 1)))
return true;
return false;
}
/* The dovi always trigger error interrupt, so it's disabled by default */
static void __maybe_unused vop2_enable_dovi_sys_irqs(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
const struct vop2_data *vop2_data = vop2->data;
const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
const struct vop_intr *intr = vp_data->intr;
uint32_t irqs = DOLBY_CORE1_INTR | DOLBY_CORE2_INTR | DOLBY_CORE3_INTR;
struct vop2_dovi_core *dovi_core;
int i = 0;
VOP_INTR_SET_TYPE(vop2, intr, clear, irqs, 1);
VOP_INTR_SET_TYPE(vop2, intr, enable, irqs, 1);
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
dovi_core = &vop2->dovi_cores[i];
/* enable memtadata program error and unmatched frame detect error */
VOP_MODULE_SET(vop2, dovi_core, interrupt_enable, 3);
}
}
static int vop2_hdr_get_eotf_by_output_mode(int output_mode)
{
switch (output_mode) {
case HDR_HDR10:
return HDMI_EOTF_SMPTE_ST2084;
case HDR_HDRVIVID:
return HDMI_EOTF_HDRVIVID;
case HDR_HDR10PLUS:
return HDMI_EOTF_HDR10PLUS;
case HDR_DOVI:
return HDMI_EOTF_DOVI;
case HDR_NONE:
default:
return HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
}
}
static void vop2_dovi_enable(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct vop2 *vop2 = vp->vop2;
const struct vop2_data *vop2_data = vop2->data;
struct vop2_dovi_core *dovi_core;
struct dovi_regs *dovi_data;
struct hdr_extend *hdr_data;
int i = 0;
if (vp->dovi_hdr_en)
return;
hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data;
if (!hdr_data)
return;
dovi_data = &hdr_data->dovi_data;
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
dovi_core = &vop2->dovi_cores[i];
if (vop2_check_dovi_core_enabled(dovi_core->id, dovi_data->valid))
VOP_MODULE_SET(vop2, dovi_core, enable, 1);
}
vp->dovi_hdr_en = true;
DRM_DEV_INFO(vop2->dev, "vp%d dovi enabled\n", vp->id);
}
static int vop2_dovi_init(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct hdr_extend *hdr_data;
unsigned long aclk_rate;
int ret = 0;
if (!vcstate || !vcstate->hdr_ext_data)
return 0;
hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data;
if (!hdr_data || hdr_data->hdr_type != HDR_DOVI)
return 0;
aclk_rate = clk_get_rate(vop2->aclk);
if (!vp->dovi_lut_gem_obj) {
vp->dovi_lut_gem_obj =
rockchip_gem_create_object(vop2->drm_dev,
VOP2_DOVI_TONE_SCA_AXI_TAB_SIZE * 2,
true, 0);
if (IS_ERR(vp->dovi_lut_gem_obj)) {
drm_err(vop2, "create dovi lut obj failed\n");
return 0;
}
}
ret = clk_prepare_enable(vop2->aclk_dovi);
if (ret < 0)
drm_err(vop2, "failed to enable aclk_dovi - %d\n", ret);
ret = clk_set_parent(vop2->aclk, vop2->aclk_div2_src);
if (ret < 0) {
drm_err(vop2, "failed to set parent(%s) for %s\n",
__clk_get_name(vop2->aclk_div2_src),
__clk_get_name(vop2->aclk));
}
clk_set_rate(vop2->aclk_dovi, aclk_rate);
/* vop2_enable_dovi_sys_irqs(crtc); */
vp->dovi_hdr_mode = true;
vop2_dovi_enable(crtc);
return 0;
}
static void vop2_dovi_pre_disable(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
const struct vop2_data *vop2_data = vop2->data;
struct vop2_dovi_core *dovi_core;
int i;
if (!vp->dovi_hdr_en)
return;
VOP_MODULE_SET(vop2, vp, dp_line_end_mode, 0);
VOP_MODULE_SET(vop2, vp, dp_bg_bottom_disable, 0);
VOP_MODULE_SET(vop2, vp, dovi_pre_scan_en, 0);
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
dovi_core = &vop2->dovi_cores[i];
VOP_MODULE_SET(vop2, dovi_core, enable, 0);
VOP_MODULE_SET(vop2, dovi_core, lut_update, 0);
if (dovi_core->id == 2)
VOP_MODULE_SET(vop2, dovi_core, dly_en, 0);
}
VOP_CTRL_SET(vop2, lut_dma_en, 0);
}
static void vop2_dovi_post_disable(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
int ret;
if (!vp->dovi_hdr_en)
return;
ret = clk_set_parent(vop2->aclk, vop2->aclk_root);
if (ret < 0)
drm_err(vop2,
"failed to set aclk vop parent back to aclk vop root\n");
clk_disable_unprepare(vop2->aclk_dovi);
if (vp->dovi_lut_gem_obj)
rockchip_gem_free_object(&vp->dovi_lut_gem_obj->base);
vp->dovi_lut_gem_obj = NULL;
vp->dovi_hdr_mode = false;
vp->dovi_hdr_en = false;
vp->dovi_hdr_in = false;
drm_info(vop2, "vp%d dovi disabled\n", vp->id);
}
static u32 vop2_read_dovi_metadata_copy_finish(struct vop2_dovi_core *dovi_core)
{
struct vop2 *vop2 = dovi_core->vop2;
return VOP_MODULE_GET(vop2, dovi_core, metadata_copy_finish);
}
static void vop2_wait_for_dovi_metadata_copy_finish(struct vop2_dovi_core *dovi_core)
{
struct vop2 *vop2 = dovi_core->vop2;
bool finish;
int ret;
ret = readx_poll_timeout_atomic(vop2_read_dovi_metadata_copy_finish,
dovi_core, finish, finish == true, 0, 10 * 1000);
if (ret)
DRM_DEV_DEBUG(vop2->dev, "Wait dovi%d metadata copy finish timeout: 0x%x\n",
dovi_core->id, vop2_readl(vop2, dovi_core->regs->metadata_copy_finish.offset));
}
static u32 vop2_read_dovi_core_enable(struct vop2_dovi_core *dovi_core)
{
struct vop2 *vop2 = dovi_core->vop2;
return VOP_MODULE_GET(vop2, dovi_core, enable);
}
static void vop2_wait_for_dovi_core_enabled(struct vop2_dovi_core *dovi_core)
{
struct vop2 *vop2 = dovi_core->vop2;
bool enable;
int ret;
ret = readx_poll_timeout_atomic(vop2_read_dovi_core_enable,
dovi_core, enable, enable == true, 0, 10 * 1000);
if (ret)
DRM_DEV_DEBUG(vop2->dev, "Wait dovi%d metadata copy finish timeout: 0x%x\n",
dovi_core->id, vop2_readl(vop2, dovi_core->regs->metadata_copy_finish.offset));
}
static void vop2_load_dovi_coe_table(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct dovi_regs *dovi_reg_data;
struct hdr_extend *hdr_data;
const struct vop2_data *vop2_data = vop2->data;
const struct vop2_dovi_core_data *dovi_core_data;
struct vop2_dovi_core *dovi_core;
u32 *dovi_lut_kvaddr;
u32 dovi_lut_mst;
int i = 0, j = 0;
u32 offset = vp->rockchip_crtc.frame_count % 2 ? 0 : VOP2_DOVI_TONE_SCA_AXI_TAB_SIZE;
if (!vop2_is_dovi_mode(vp))
return;
if (!vcstate->hdr_ext_data)
return;
hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data;
dovi_reg_data = &hdr_data->dovi_data;
vcstate->eotf = vop2_hdr_get_eotf_by_output_mode(dovi_reg_data->output_mode);
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
dovi_core = &vop2->dovi_cores[i];
if (!vop2_check_dovi_core_enabled(dovi_core->id, dovi_reg_data->valid))
continue;
vop2_wait_for_dovi_core_enabled(dovi_core);
/*
* The metadata_copy_finish maybe cleared by vop2_dovi_hanle_irqs,
* but vop2_dovi_hanle_irqs is disabled now.
*/
vop2_wait_for_dovi_metadata_copy_finish(dovi_core);
VOP_MODULE_SET(vop2, dovi_core, metadata_copy_finish, 1);
}
dovi_lut_kvaddr = (u32 *)vp->dovi_lut_gem_obj->kvaddr + offset / 4;
memcpy(dovi_lut_kvaddr, &dovi_reg_data->core1_lut, VOP2_DOVI_CORE1_LUT_SIZE);
dovi_lut_kvaddr += VOP2_DOVI_CORE1_LUT_SIZE / 4;
memcpy(dovi_lut_kvaddr, &dovi_reg_data->core2_lut, VOP2_DOVI_CORE1_LUT_SIZE);
dovi_lut_mst = vp->dovi_lut_gem_obj->dma_addr + offset;
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
dovi_core = &vop2->dovi_cores[i];
if (!vop2_check_dovi_core_enabled(dovi_core->id, dovi_reg_data->valid))
continue;
if (dovi_core->id == 1)
VOP_MODULE_SET(vop2, dovi_core, lut_mst, dovi_lut_mst);
if (dovi_core->id == 2)
VOP_MODULE_SET(vop2, dovi_core, lut_mst, dovi_lut_mst + VOP2_DOVI_CORE1_LUT_SIZE);
}
VOP_CTRL_SET(vop2, lut_dma_en, 1);
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
dovi_core = &vop2->dovi_cores[i];
if (!vop2_check_dovi_core_enabled(dovi_core->id, dovi_reg_data->valid))
continue;
VOP_MODULE_SET(vop2, dovi_core, lut_update, 1);
}
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
u32 *core_data = NULL;
int size;
int offset;
dovi_core_data = &vop2_data->dovi->dovi_core_data[i];
dovi_core = &vop2->dovi_cores[i];
if (!vop2_check_dovi_core_enabled(dovi_core->id, dovi_reg_data->valid))
continue;
if (dovi_core->id == 1) {
core_data = (u32 *)&dovi_reg_data->core1;
offset = dovi_core_data->srange_offset_from_core >> 2;
size = DOVI_CORE1_SIZE - offset;
} else if (dovi_core->id == 2) {
core_data = (u32 *)&dovi_reg_data->core2;
offset = dovi_core_data->srange_offset_from_core >> 2;
size = DOVI_CORE2_SIZE - offset;
size -= 2; /* core2 last 2 word is reserved */
} else if (dovi_core->id == 3) {
core_data = (u32 *)&dovi_reg_data->core3;
offset = dovi_core_data->srange_offset_from_core >> 2;
size = DOVI_CORE3_SIZE - offset;
}
if (!core_data)
continue;
VOP_MODULE_SET(vop2, dovi_core, metadata_program_st, 1);
vop2_writel(vop2, dovi_core_data->ctrl_offset, core_data[1]);
/* write regs start from SRANGE_REGISTER */
core_data += offset;
for (j = 0; j < size; j++)
vop2_writel(vop2, dovi_core_data->srange_offset + (j << 2), *(core_data++));
VOP_MODULE_SET(vop2, dovi_core, metadata_program_end, 1);
if (dovi_core->id == 2) {
if (dovi_reg_data->input_mode != HDR_DOVI)
VOP_MODULE_SET(vop2, dovi_core, dly_en, 1);
else
VOP_MODULE_SET(vop2, dovi_core, dly_en, 0);
}
}
}
static void vop2_dovi_mode_config(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
const struct vop2_data *vop2_data = vop2->data;
struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
u16 hsync_len = (adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start) >> 1;
u16 hdisplay = (adjusted_mode->crtc_hdisplay) >> 1;
u16 hact_st = (adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_start) >> 1;
u16 hact_end = hact_st + hdisplay;
u16 hfp = (adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay) >> 1;
u16 htotal;
u16 vdisplay = adjusted_mode->crtc_vdisplay;
u16 vtotal = adjusted_mode->crtc_vtotal;
u16 vsync_len = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
u16 vact_st = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_start;
u16 vact_end = vact_st + vdisplay;
u32 val = 0;
int dovi_max_delay = vp->dovi_hdr_in ?
vop2_data->dovi->dovi_max_delay[0] : vop2_data->dovi->dovi_max_delay[1];
if (!vop2_is_dovi_mode(vp)) {
VOP_MODULE_SET(vop2, vp, dovi_pre_scan_en, 0);
return;
}
hact_end = hact_end + dovi_max_delay;
val = hact_st << 16 | hact_end;
VOP_MODULE_SET(vop2, vp, pre_scan_htiming1, val);
hfp = hfp >= 20 ? hfp : 20;
htotal = hact_end + hfp;
val = htotal << 16 | hsync_len;
VOP_MODULE_SET(vop2, vp, pre_scan_htiming, val);
val = vtotal << 16 | vsync_len;
VOP_MODULE_SET(vop2, vp, pre_scan_htiming2, val);
val = vact_st << 16 | vact_end;
VOP_MODULE_SET(vop2, vp, pre_scan_htiming3, val);
VOP_MODULE_SET(vop2, vp, dovi_pre_scan_en, 1);
}
static void vop2_disable(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
@@ -5182,7 +5602,9 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
if (vp_data->feature & VOP_FEATURE_VIVID_HDR)
VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 0);
vop2_dovi_pre_disable(crtc);
vop2_disable_all_planes_for_crtc(crtc);
vop2_dovi_post_disable(crtc);
if (vop2->dscs[vcstate->dsc_id].enabled &&
vop2->dscs[vcstate->dsc_id].attach_vp_id == vp->id &&
@@ -5282,6 +5704,7 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
vcstate->output_type = 0;
vp->splice_mode_right = false;
vp->loader_protect = false;
vp->enabled_win_mask = 0;
splice_vp->splice_mode_right = false;
memset(&vp->active_tv_state, 0, sizeof(vp->active_tv_state));
vop2_unlock(vop2);
@@ -6829,6 +7252,11 @@ static int vop2_atomic_plane_set_property(struct drm_plane *plane,
return ret;
}
if (property == private->dovi_input_type_prop) {
vpstate->dovi_input_type = val;
return 0;
}
DRM_ERROR("failed to set vop2 plane property id:%d, name:%s\n",
property->base.id, property->name);
@@ -6881,6 +7309,11 @@ static int vop2_atomic_plane_get_property(struct drm_plane *plane,
return 0;
}
if (property == private->dovi_input_type_prop) {
*val = vpstate->dovi_input_type;
return 0;
}
DRM_ERROR("failed to get vop2 plane property id:%d, name:%s\n",
property->base.id, property->name);
@@ -7326,6 +7759,27 @@ static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on, void *data)
return 0;
}
static const char *hdr_to_string(int eotf)
{
switch (eotf) {
case HDMI_EOTF_TRADITIONAL_GAMMA_HDR:
return "GAMMA HDR";
case HDMI_EOTF_SMPTE_ST2084:
return "HDR10";
case HDMI_EOTF_BT_2100_HLG:
return "HLG";
case HDMI_EOTF_HDR10PLUS:
return "HDR10PLUS";
case HDMI_EOTF_HDRVIVID:
return "HDRVIVID";
case HDMI_EOTF_DOVI:
return "DOVI";
case HDMI_EOTF_TRADITIONAL_GAMMA_SDR:
default:
return "SDR";
}
}
#define DEBUG_PRINT(args...) \
do { \
if (s) \
@@ -7360,10 +7814,9 @@ static int vop2_plane_info_dump(struct seq_file *s, struct drm_plane *plane)
&fb->format->format, rockchip_drm_modifier_to_string(fb->modifier),
pstate->pixel_blend_mode, vpstate->global_alpha);
DEBUG_PRINT("\tcolor: %s[%d] color-encoding[%s] color-range[%s]\n",
vpstate->eotf ? "HDR" : "SDR", vpstate->eotf,
hdr_to_string(vpstate->eotf), vpstate->eotf,
rockchip_drm_get_color_encoding_name(pstate->color_encoding),
rockchip_drm_get_color_range_name(pstate->color_range));
DEBUG_PRINT("\trotate: xmirror: %d ymirror: %d rotate_90: %d rotate_270: %d\n",
vpstate->xmirror_en, vpstate->ymirror_en, vpstate->rotate_90_en,
vpstate->rotate_270_en);
@@ -7435,7 +7888,7 @@ static int vop2_crtc_debugfs_dump(struct drm_crtc *crtc, struct seq_file *s)
DEBUG_PRINT("\toverlay_mode[%d] output_mode[%x] ",
state->yuv_overlay, state->output_mode);
DEBUG_PRINT("%s[%d] color-encoding[%s] color-range[%s]\n",
state->eotf ? "HDR" : "SDR", state->eotf,
hdr_to_string(state->eotf), state->eotf,
rockchip_drm_get_color_encoding_name(state->color_encoding),
rockchip_drm_get_color_range_name(state->color_range));
DEBUG_PRINT(" Display mode: %dx%d%s%d\n",
@@ -9821,6 +10274,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
}
if (is_vop3(vop2))
vop3_setup_pipe_dly(vp, NULL);
if (vp_data->feature & VOP_FEATURE_DOVI)
vop2_dovi_init(crtc);
vop2_crtc_setup_output_mode(crtc);
@@ -9964,6 +10419,26 @@ static void vop2_update_post_csc_info(struct vop2_video_port *vp,
memset(&vp->csc_info, 0, sizeof(struct post_csc));
}
/*
* Check hdr_ext_data switch from valid to NULL or
* NULL to valid.
* This is used to check a switch from dynamic HDR2SDR
* or SDR2HDR output mode switch.
*/
static bool vop_hdr_ext_data_switch(struct drm_crtc_state *old_state,
struct drm_crtc_state *new_state)
{
struct rockchip_crtc_state *new_vcstate = to_rockchip_crtc_state(new_state);
struct rockchip_crtc_state *old_vcstate = to_rockchip_crtc_state(old_state);
struct drm_property_blob *new_blob = new_vcstate->hdr_ext_data;
struct drm_property_blob *old_blob = old_vcstate->hdr_ext_data;
if ((!old_blob && new_blob) || (!new_blob && old_blob))
return false;
return true;
}
static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_atomic_state *state)
{
@@ -9978,6 +10453,7 @@ static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
struct rockchip_crtc_state *new_vcstate = to_rockchip_crtc_state(new_crtc_state);
struct rockchip_crtc_state *old_vcstate = to_rockchip_crtc_state(old_crtc_state);
struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
bool hdr_ext_data_change;
if (vop2_has_feature(vop2, VOP_FEATURE_SPLICE)) {
if (adjusted_mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) {
@@ -10002,6 +10478,11 @@ static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
else
vp->acm_state_changed = false;
hdr_ext_data_change = !vop_hdr_ext_data_switch(old_crtc_state, new_crtc_state) |
new_crtc_state->active_changed;
if (hdr_ext_data_change)
new_crtc_state->mode_changed = true;
return 0;
}
@@ -10235,6 +10716,29 @@ static void vop3_setup_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phys_
}
}
static void vop2_setup_hdr_dovi(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
const struct vop2_data *vop2_data = vop2->data;
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct dovi_regs *dovi_data;
struct hdr_extend *hdr_data;
if (!vop2_data->dovi->nr_dovi_cores || !vcstate || !vcstate->hdr_ext_data)
return;
hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data;
if (!hdr_data || hdr_data->hdr_type != HDR_DOVI)
return;
dovi_data = &hdr_data->dovi_data;
if (dovi_data->input_mode == HDR_DOVI)
vp->dovi_hdr_in = true;
else
vp->dovi_hdr_in = false;
}
static void vop2_setup_hdr10(struct vop2_video_port *vp, uint8_t win_phys_id)
{
struct vop2 *vop2 = vp->vop2;
@@ -10549,7 +11053,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp,
int mixer_id;
int phys_id;
uint32_t offset;
int i;
int i, begin_layer = 0;
bool bottom_layer_alpha_en = false;
u32 dst_global_alpha = 0xff;
@@ -10590,8 +11094,24 @@ static void vop2_setup_alpha(struct vop2_video_port *vp,
vp->hdr10_at_splice_mode && vp->id == 0)
mixer_id++;/* fixed path for rk3588: layer1 -> hdr10_1 */
/*
* vp0 begin from mix0, mix0 input is layer0 and layer1, we need to use
* layer1 format to config mix0, the layer0 alpha[bottom_layer_alpha_en is true],
* will use the following formulas: Cd = Cs + (1 - As) * Cd * Agd to do overlay;
* vp1/2/3 layer0 will enter first mix src layer, so we need to init it.
*
* rk3588 hdr splice mode, vp1 hdr layer will be insert to layer1[vp0],
* so we need to ignore layer0 and begin from layer1 to config mix for vp1.
*/
if (vp->id == 0 || vp->hdr10_at_splice_mode)
begin_layer = 1;
/* dovi core1 base layer and enhance layer no need to do overlay */
if (vop2_is_dovi_mode(vp))
begin_layer = 2;
alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */
for (i = 1; i < vp->nr_layers; i++) {
for (i = begin_layer; i < vp->nr_layers; i++) {
zpos = &vop2_zpos[i];
win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id);
if (win->splice_mode_right)
@@ -10609,7 +11129,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp,
pixel_alpha_en = is_alpha_support(fb->format->format);
alpha_config.src_premulti_en = premulti_en;
if (bottom_layer_alpha_en && i == 1) {
if (bottom_layer_alpha_en && i == begin_layer && vp->id == 0) {/* Cd = Cs + (1 - As) * Cd * Agd */
/**
* The data from cluster mix is always premultiplied alpha;
* cluster layer or esmart layer[premulti_en = 1]
@@ -10638,6 +11158,13 @@ static void vop2_setup_alpha(struct vop2_video_port *vp,
}
vop2_parse_alpha(&alpha_config, &alpha);
/*
* The first UI enter dovi core2 no need to do alpha blending, but
* the alpha value need to transfer to next mix and enter core2.
*/
if (vop2_is_dovi_mode(vp) && i == begin_layer)
alpha.src_color_ctrl.bits.alpha_en = false;
offset = (mixer_id + i - 1) * 0x10;
vop2_writel(vop2, src_color_ctrl_offset + offset, alpha.src_color_ctrl.val);
vop2_writel(vop2, dst_color_ctrl_offset + offset, alpha.dst_color_ctrl.val);
@@ -10645,7 +11172,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp,
vop2_writel(vop2, dst_alpha_ctrl_offset + offset, alpha.dst_alpha_ctrl.val);
}
if (bottom_layer_alpha_en || vp->hdr_en) {
if (bottom_layer_alpha_en || vp->hdr_en || (vop2_is_dovi_mode(vp) && vp->nr_layers > 1)) {
/* Transfer pixel alpha to hdr mix */
alpha_config.src_premulti_en = premulti_en;
alpha_config.dst_premulti_en = true;
@@ -10653,6 +11180,16 @@ static void vop2_setup_alpha(struct vop2_video_port *vp,
alpha_config.src_glb_alpha_value = 0xff;
alpha_config.dst_glb_alpha_value = 0xff;
vop2_parse_alpha(&alpha_config, &alpha);
if (vop2_is_dovi_mode(vp)) {
/* dovi core2 output must be no pre mul alpha
* color_mode = ALPHA_SRC_NO_PRE_MUL && factor_mode = ALPHA_ONE is
* roughly equal to color_mode = ALPHA_SRC_PRE_MUL && factor_mode = ALPHA_NO_SATURATION,
* but the secondary is more correctly.
*/
alpha.src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL;
alpha.src_color_ctrl.bits.factor_mode = ALPHA_SRC_GLOBAL;
alpha.src_color_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION;
}
VOP_MODULE_SET(vop2, vp, hdr_src_color_ctrl,
alpha.src_color_ctrl.val);
@@ -10968,6 +11505,13 @@ static u16 vop2_calc_bg_ovl_and_port_mux(struct vop2_video_port *vp)
used_layers += 1;
if (vop2->vps[0].hdr10_at_splice_mode && i == 1)
used_layers -= 1;
/*
* At RK3588 dovi mode, layer1 always used by enhance layer,
* so the used_layers at least 3 layers, include:
* base layer[video], enhance layer[reserved] and UI layer.
*/
if (vop2_is_dovi_mode(prev_vp) && used_layers < 3)
used_layers++;
}
/*
* when a window move from vp0 to vp1, or vp0 to vp2,
@@ -11216,6 +11760,12 @@ static void vop2_setup_dly_for_vp(struct vop2_video_port *vp)
pre_scan_dly = (pre_scan_dly << 16) | hsync_len;
VOP_MODULE_SET(vop2, vp, bg_dly, bg_dly);
/* Disable bg bottom overlay */
if (vop2_is_dovi_mode(vp)) {
VOP_MODULE_SET(vop2, vp, dp_line_end_mode, 1);
VOP_MODULE_SET(vop2, vp, dp_bg_bottom_disable, 1);
}
/* will be rewrite at dovi_mode_config when at dovi mode */
VOP_MODULE_SET(vop2, vp, pre_scan_htiming, pre_scan_dly);
}
@@ -11249,6 +11799,18 @@ static void vop2_setup_dly_for_window(struct vop2_video_port *vp, const struct v
} else if (vp->hdr_in && vp->hdr_out && vpstate->hdr_in) {
dly = win->dly[VOP2_DLY_MODE_HIHO_H];
dly -= vp->bg_ovl_dly;
} else if (vop2_is_dovi_mode(vp)) {
if (vp->dovi_hdr_in) {
if (vpstate->dovi_input_type)
dly = win->dly[VOP2_DLY_MODE_DOVI_IN_CORE1];
else
dly = win->dly[VOP2_DLY_MODE_DOVI_IN_CORE2];
} else {
if (vpstate->dovi_input_type)
dly = win->dly[VOP2_DLY_MODE_NONDOVI_IN_CORE1];
else
dly = win->dly[VOP2_DLY_MODE_NONDOVI_IN_CORE2];
}
} else {
dly = win->dly[VOP2_DLY_MODE_DEFAULT];
}
@@ -11498,6 +12060,33 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat
vp->nr_layers = nr_layers;
sort(vop2_zpos, nr_layers, sizeof(vop2_zpos[0]), vop2_zpos_cmp, NULL);
/*
* At RK3588 dovi mode, the layer0 and layer1 is used for dovi layer,
* layer0 for base layer, layer1 for enhance layer, the enhance layer
* is option, but it's always occupy this layer, and the other layer
* must be assigned from layer2, so copy the other layers to &vop_zpos[2].
*/
if (vop2->version == VOP_VERSION_RK3588 &&
vop2_is_dovi_mode(vp) && vp->nr_layers > 1) {
const struct vop2_data *vop2_data = vop2->data;
struct vop2_zpos *vop2_zpos_tmp;
int i = 0;
vop2_zpos_tmp = kmalloc_array(nr_layers - 1, sizeof(struct vop2_zpos), GFP_KERNEL);
if (!vop2_zpos_tmp)
goto dovi_err;
/* Insert esmart3 as core1 enhance layer to zpos1 */
memcpy(vop2_zpos_tmp, &vop2_zpos[1], (nr_layers - 1) * sizeof(struct vop2_zpos));
vp->nr_layers++;
vop2_zpos[1].zpos = 1;
vop2_zpos[1].win_phys_id = vop2_data->dovi->enhance_layer_phy_id;
memcpy(&vop2_zpos[2], vop2_zpos_tmp, (nr_layers - 1) * sizeof(struct vop2_zpos));
for (i = 0; i < nr_layers - 1; i++)
vop2_zpos[2 + i].zpos = 2 + i;
kfree(vop2_zpos_tmp);
}
if (!vp->hdr10_at_splice_mode) {
if (is_vop3(vop2)) {
@@ -11514,7 +12103,10 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat
vop3_setup_alpha(vp, vop2_zpos);
vop3_setup_pipe_dly(vp, vop2_zpos);
} else {
vop2_setup_hdr10(vp, vop2_zpos[0].win_phys_id);
if (!vop2_is_dovi_mode(vp))
vop2_setup_hdr10(vp, vop2_zpos[0].win_phys_id);
else
vop2_setup_hdr_dovi(crtc);
vop2_setup_alpha(vp, vop2_zpos);
vop2_setup_dly_for_vp(vp);
vop2_setup_dly_for_window(vp, vop2_zpos);
@@ -11529,7 +12121,8 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat
vop2_setup_port_mux(vp);
if (!vp->hdr10_at_splice_mode)
vop2_setup_layer_mixer_for_vp(splice_vp, vop2_zpos_splice);
vop2_setup_hdr10(splice_vp, vop2_zpos_splice[0].win_phys_id);
if (!vop2_is_dovi_mode(vp))
vop2_setup_hdr10(splice_vp, vop2_zpos_splice[0].win_phys_id);
vop2_setup_alpha(splice_vp, vop2_zpos_splice);
vop2_setup_dly_for_vp(splice_vp);
vop2_setup_dly_for_window(splice_vp, vop2_zpos_splice);
@@ -11570,6 +12163,7 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_stat
}
}
dovi_err:
if (vcstate->splice_mode)
kfree(vop2_zpos_splice);
out:
@@ -11971,6 +12565,11 @@ static void vop2_cfg_update(struct drm_crtc *crtc,
if (vp_data->feature & VOP_FEATURE_OVERSCAN)
vop2_post_config(crtc);
if (vop2_is_dovi_mode(vp) && vp->enabled_win_mask) {
vop2_dovi_mode_config(crtc);
vop2_load_dovi_coe_table(crtc);
}
spin_unlock(&vop2->reg_lock);
if (vp_data->feature & VOP_FEATURE_POST_CSC) {
@@ -12069,7 +12668,9 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_stat
struct vop2_wb *wb = &vop2->wb;
struct drm_writeback_connector *wb_conn = &wb->conn;
struct drm_connector_state *conn_state = wb_conn->base.state;
bool wb_mode = conn_state && conn_state->writeback_job && conn_state->writeback_job->fb;
bool wb_oneframe_mode = VOP_MODULE_GET(vop2, wb, one_frame_mode);
bool dovi_mode = vop2_is_dovi_mode(vp) && vp->enabled_win_mask;
#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
if (vp->rockchip_crtc.vop_dump_status == DUMP_KEEP ||
@@ -12079,7 +12680,13 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_stat
}
#endif
if (conn_state && conn_state->writeback_job && conn_state->writeback_job->fb && !wb_oneframe_mode) {
if ((wb_mode && !wb_oneframe_mode) || dovi_mode) {
/**
* Avoid commit time close to vsync when enable writeback or dovi mode.
* For writeback may be lost writeback frame when close to vsync,
* For dovi mode may be appear dovi config and plane config take effect
* at different frame.
*/
u16 vtotal = VOP_MODULE_GET(vop2, vp, dsp_vtotal);
u32 current_line = vop2_read_vcnt(vp);
@@ -12156,6 +12763,7 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_stat
if (vp->mcu_timing.mcu_pix_total)
VOP_MODULE_SET(vop2, vp, mcu_hold_mode, 0);
vp->rockchip_crtc.frame_count++;
spin_unlock_irqrestore(&vop2->irq_lock, flags);
/*
@@ -12730,6 +13338,35 @@ static void vop2_wb_handler(struct vop2_video_port *vp)
spin_unlock_irqrestore(&wb->job_lock, flags);
}
static void vop2_dovi_hanle_irqs(struct drm_crtc *crtc, uint32_t active_irqs)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
struct vop2_dovi_core *dovi_core;
u32 val = 0;
if (active_irqs & DOLBY_CORE1_INTR) {
dovi_core = &vop2->dovi_cores[0];
val = VOP_MODULE_GET(vop2, dovi_core, interrupt_raw);
VOP_MODULE_SET(vop2, dovi_core, interrupt_raw, val);
drm_dbg(vop2, "dovi core1 irq: 0x%x\n", val);
}
if (active_irqs & DOLBY_CORE2_INTR) {
dovi_core = &vop2->dovi_cores[1];
val = VOP_MODULE_GET(vop2, dovi_core, interrupt_raw);
VOP_MODULE_SET(vop2, dovi_core, interrupt_raw, val);
drm_dbg(vop2, "dovi core2 irq: 0x%x\n", val);
}
if (active_irqs & DOLBY_CORE3_INTR) {
dovi_core = &vop2->dovi_cores[2];
val = VOP_MODULE_GET(vop2, dovi_core, interrupt_raw);
VOP_MODULE_SET(vop2, dovi_core, interrupt_raw, val);
drm_dbg(vop2, "dovi core3 irq: 0x%x\n", val);
}
}
static void vop2_dsc_isr(struct vop2 *vop2)
{
const struct vop2_data *vop2_data = vop2->data;
@@ -12859,6 +13496,12 @@ static irqreturn_t vop2_isr(int irq, void *data)
ret = IRQ_HANDLED;
}
if (active_irqs & (DOLBY_CORE1_INTR | DOLBY_CORE2_INTR | DOLBY_CORE3_INTR)) {
vop2_dovi_hanle_irqs(crtc, active_irqs);
active_irqs &= ~(DOLBY_CORE1_INTR | DOLBY_CORE2_INTR | DOLBY_CORE3_INTR);
ret = IRQ_HANDLED;
}
if (active_irqs & POST_BUF_EMPTY_INTR) {
vop2_handle_post_buf_empty(crtc);
DRM_DEV_ERROR_RATELIMITED(vop2->dev, "POST_BUF_EMPTY irq err at vp%d\n", vp->id);
@@ -13212,6 +13855,9 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned lon
else
drm_object_attach_property(&win->base.base, private->share_id_prop,
win->base.base.id);
drm_object_attach_property(&win->base.base, private->dovi_input_type_prop, 0);
if (win->supported_rotations)
drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 | win->supported_rotations);
@@ -13412,7 +14058,7 @@ static int vop2_crtc_create_feature_property(struct vop2 *vop2, struct drm_crtc
static const struct drm_prop_enum_list props[] = {
{ ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE, "ALPHA_SCALE" },
{ ROCKCHIP_DRM_CRTC_FEATURE_HDR10, "HDR10" },
{ ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR, "NEXT_HDR" },
{ ROCKCHIP_DRM_CRTC_FEATURE_DOVI, "DOVI" },
{ ROCKCHIP_DRM_CRTC_FEATURE_VIVID_HDR, "VIVID_HDR" },
};
@@ -13420,8 +14066,8 @@ static int vop2_crtc_create_feature_property(struct vop2 *vop2, struct drm_crtc
feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE);
if (vp_data->feature & VOP_FEATURE_HDR10)
feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_HDR10);
if (vp_data->feature & VOP_FEATURE_NEXT_HDR)
feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR);
if (vp_data->feature & VOP_FEATURE_DOVI)
feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_DOVI);
if (vp_data->feature & VOP_FEATURE_VIVID_HDR)
feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_VIVID_HDR);
@@ -13817,7 +14463,7 @@ static int vop2_create_crtc(struct vop2 *vop2, uint8_t enabled_vp_mask)
"Failed to init %s with SR helpers %d, ignoring\n",
crtc->name, ret);
if (vp_data->feature & VOP_FEATURE_VIVID_HDR)
if (vp_data->feature & (VOP_FEATURE_VIVID_HDR | VOP_FEATURE_DOVI))
vop2_crtc_create_hdr_property(vop2, crtc);
if (vp_data->feature & VOP_FEATURE_POST_ACM)
vop2_crtc_create_post_acm_property(vop2, crtc);
@@ -13950,6 +14596,22 @@ static int vop2_pd_data_init(struct vop2 *vop2)
return 0;
}
static void vop2_dovi_data_init(struct vop2 *vop2)
{
const struct vop2_data *vop2_data = vop2->data;
const struct vop2_dovi_core_data *dovi_core_data;
struct vop2_dovi_core *dovi_core;
int i;
for (i = 0; i < vop2_data->dovi->nr_dovi_cores; i++) {
dovi_core = &vop2->dovi_cores[i];
dovi_core_data = &vop2_data->dovi->dovi_core_data[i];
dovi_core->id = dovi_core_data->id;
dovi_core->regs = dovi_core_data->regs;
dovi_core->vop2 = vop2;
}
}
static void vop2_dsc_data_init(struct vop2 *vop2)
{
const struct vop2_data *vop2_data = vop2->data;
@@ -14668,6 +15330,24 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
return PTR_ERR(vop2->pclk);
}
vop2->aclk_dovi = devm_clk_get_optional(vop2->dev, "aclk_dovi");
if (IS_ERR(vop2->aclk_dovi)) {
DRM_DEV_ERROR(vop2->dev, "failed to get aclk dovi source\n");
return PTR_ERR(vop2->aclk_dovi);
}
vop2->aclk_div2_src = devm_clk_get_optional(vop2->dev, "aclk_vop_div2_src");
if (IS_ERR(vop2->aclk_div2_src)) {
DRM_DEV_ERROR(vop2->dev, "failed to get aclk div2 src\n");
return PTR_ERR(vop2->aclk_div2_src);
}
vop2->aclk_root = devm_clk_get_optional(vop2->dev, "aclk_vop_root");
if (IS_ERR(vop2->aclk_root)) {
DRM_DEV_ERROR(vop2->dev, "failed to get aclk vop root\n");
return PTR_ERR(vop2->aclk_root);
}
vop2->ahb_rst = devm_reset_control_get_optional(vop2->dev, "ahb");
if (IS_ERR(vop2->ahb_rst)) {
DRM_DEV_ERROR(vop2->dev, "failed to get ahb reset\n");
@@ -14776,6 +15456,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;
vop2_dovi_data_init(vop2);
vop2_dsc_data_init(vop2);
registered_num_crtcs = vop2_create_crtc(vop2, enabled_vp_mask);

View File

@@ -680,6 +680,10 @@ static const int rk3568_vop_intrs[] = {
POST_BUF_EMPTY_INTR,
FS_FIELD_INTR,
DSP_HOLD_VALID_INTR,
0, 0, 0, 0, 0,
DOLBY_CORE1_INTR,
DOLBY_CORE2_INTR,
DOLBY_CORE3_INTR,
};
static const struct vop_intr rk3568_vp0_intr = {
@@ -722,6 +726,88 @@ static const struct vop_intr rk3588_vp3_intr = {
.clear = VOP_REG_MASK(RK3588_VP3_INT_CLR, 0xffff, 0),
};
static const struct vop2_dovi_regs rk3588_vop_dovi_core1_regs = {
.enable = VOP_REG(RK3568_OVL_CTRL, 0x1, 8),
.interrupt_raw = VOP_REG(RK3588_DOLBY_CORE1_INTR_RAW_REG, 0xf, 0),
.interrupt_enable = VOP_REG(RK3588_DOLBY_CORE1_INTR_ENABLE_REG, 0xf, 0),
.metadata_program_st = VOP_REG(RK3588_DOLBY_CORE1_METADATA_PROGRAM_ST, 0x1, 0),
.metadata_program_end = VOP_REG(RK3588_DOLBY_CORE1_METADATA_PROGRAM_END, 0x1, 0),
.metadata_copy_finish = VOP_REG(RK3588_DOLBY_CORE1_INTR_RAW_REG, 0x1, 2),
.bypass_composer = VOP_REG(RK3588_DOLBY_CORE1_CONTROL_REG, 0x1, 0),
.bypass_csc = VOP_REG(RK3588_DOLBY_CORE1_CONTROL_REG, 0x1, 1),
.bypass_cvm = VOP_REG(RK3588_DOLBY_CORE1_CONTROL_REG, 0x1, 2),
.operating_mode = VOP_REG(RK3588_DOLBY_CORE1_CONTROL_REG, 0x1, 3),
.pixel_rate = VOP_REG(RK3588_DOLBY_CORE1_CONTROL_REG, 0xf, 4),
.lut_update = VOP_REG(RK3568_OVL_CTRL, 0x1, 11),
.lut_mst = VOP_REG(RK3588_DOLBY_LUT_MST, 0xffffffff, 0),
};
static const struct vop2_dovi_regs rk3588_vop_dovi_core2_regs = {
.enable = VOP_REG(RK3568_OVL_CTRL, 0x1, 9),
.interrupt_raw = VOP_REG(RK3588_DOLBY_CORE2_INTR_RAW_REG, 0xf, 0),
.interrupt_enable = VOP_REG(RK3588_DOLBY_CORE2_INTR_ENABLE_REG, 0xf, 0),
.metadata_program_st = VOP_REG(RK3588_DOLBY_CORE2_METADATA_PROGRAM_ST, 0x1, 0),
.metadata_program_end = VOP_REG(RK3588_DOLBY_CORE2_METADATA_PROGRAM_END, 0x1, 0),
.metadata_copy_finish = VOP_REG(RK3588_DOLBY_CORE2_INTR_RAW_REG, 0x1, 2),
.bypass_cvm = VOP_REG(RK3588_DOLBY_CORE2_CONTROL_REG, 0x1, 0),
.yuv2rgb_en = VOP_REG(RK3588_DOLBY_CORE2_CONTROL_REG, 0x1, 1),
.yuv422to444_en = VOP_REG(RK3588_DOLBY_CORE2_CONTROL_REG, 0x1, 2),
.yuv_swap = VOP_REG(RK3568_OVL_CTRL, 0x1, 6),
.yuv422_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 7),
.lut_update = VOP_REG(RK3568_OVL_CTRL, 0x1, 12),
.lut_mst = VOP_REG(RK3568_HDR_LUT_MST, 0xffffffff, 0),
.dly_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 13),
};
static const struct vop2_dovi_regs rk3588_vop_dovi_core3_regs = {
.enable = VOP_REG(RK3568_OVL_CTRL, 0x1, 10),
.interrupt_raw = VOP_REG(RK3588_DOLBY_CORE3_INTR_RAW_REG, 0xf, 0),
.interrupt_enable = VOP_REG(RK3588_DOLBY_CORE3_INTR_ENABLE_REG, 0xf, 0),
.metadata_program_st = VOP_REG(RK3588_DOLBY_CORE3_METADATA_PROGRAM_ST, 0x1, 0),
.metadata_program_end = VOP_REG(RK3588_DOLBY_CORE3_METADATA_PROGRAM_END, 0x1, 0),
.metadata_copy_finish = VOP_REG(RK3588_DOLBY_CORE3_INTR_RAW_REG, 0x1, 2),
.output_mode = VOP_REG(RK3588_DOLBY_CORE3_CONTROL_REG, 0xf, 0),
};
static const struct vop2_dovi_core_data rk3588_vop_dovi_core_data[3] = {
{
.id = 1,
.ctrl_offset = RK3588_DOLBY_CORE1_CONTROL_REG,
.srange_offset = RK3588_DOLBY_CORE1_SRANGE_REG,
.srange_offset_from_core = 0x18,
.regs = &rk3588_vop_dovi_core1_regs,
},
{
.id = 2,
.ctrl_offset = RK3588_DOLBY_CORE2_CONTROL_REG,
.srange_offset = RK3588_DOLBY_CORE2_SRANGE_REG,
.srange_offset_from_core = 0x18,
.regs = &rk3588_vop_dovi_core2_regs,
},
{
.id = 3,
.ctrl_offset = RK3588_DOLBY_CORE3_CONTROL_REG,
.srange_offset = RK3588_DOLBY_CORE3_SRANGE_REG,
.srange_offset_from_core = 0x18,
.regs = &rk3588_vop_dovi_core3_regs,
},
};
static const struct vop2_dovi_data rk3588_vop_dovi_data = {
.nr_dovi_cores = ROCKCHIP_MAX_DOVI_CORE,
.dovi_max_delay = { 54, 24 },
.enhance_layer_phy_id = ROCKCHIP_VOP2_ESMART3,
.dovi_core_data = rk3588_vop_dovi_core_data,
};
static const struct vop2_dsc_regs rk3588_vop_dsc_8k_regs = {
/* DSC SYS CTRL */
.dsc_port_sel = VOP_REG(RK3588_DSC_8K_SYS_CTRL, 0x3, 0),
@@ -1863,11 +1949,13 @@ static const struct vop2_video_port_regs rk3588_vop_vp0_regs = {
.dclk_core_div = VOP_REG(RK3568_VP0_CLK_CTRL, 0x3, 0),
.dclk_out_div = VOP_REG(RK3568_VP0_CLK_CTRL, 0x3, 2),
.pre_scan_htiming = VOP_REG(RK3568_VP0_PRE_SCAN_HTIMING, 0x1fff1fff, 0),
.dovi_pre_scan_en = VOP_REG(RK3568_VP0_PRE_SCAN_HTIMING, 0x1, 15),
.pre_scan_htiming1 = VOP_REG(RK3588_VP0_PRE_SCAN_HTIMING1, 0x1fff1fff, 0),
.pre_scan_htiming2 = VOP_REG(RK3588_VP0_PRE_SCAN_HTIMING2, 0x1fff1fff, 0),
.pre_scan_htiming3 = VOP_REG(RK3588_VP0_PRE_SCAN_HTIMING3, 0x1fff1fff, 0),
.dp_line_end_mode = VOP_REG(RK3568_VP0_BG_MIX_CTRL, 0x1, 4),
.dp_bg_bottom_disable = VOP_REG(RK3568_VP0_BG_MIX_CTRL, 0x1, 5),
.bg_dly = VOP_REG(RK3568_VP0_BG_MIX_CTRL, 0xff, 24),
.hpost_st_end = VOP_REG(RK3568_VP0_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
.vpost_st_end = VOP_REG(RK3568_VP0_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
.post_scl_factor = VOP_REG(RK3568_VP0_POST_SCL_FACTOR_YRGB, 0xffffffff, 0),
.post_scl_ctrl = VOP_REG(RK3568_VP0_POST_SCL_CTRL, 0x3, 0),
.htotal_pw = VOP_REG(RK3568_VP0_DSP_HTOTAL_HS_END, 0xffffffff, 0),
.hact_st_end = VOP_REG(RK3568_VP0_DSP_HACT_ST_END, 0xffffffff, 0),
.dsp_vtotal = VOP_REG(RK3568_VP0_DSP_VTOTAL_VS_END, 0x1fff, 16),
@@ -1965,10 +2053,6 @@ static const struct vop2_video_port_regs rk3588_vop_vp1_regs = {
.dclk_out_div = VOP_REG(RK3568_VP1_CLK_CTRL, 0x3, 2),
.pre_scan_htiming = VOP_REG(RK3568_VP1_PRE_SCAN_HTIMING, 0x1fff1fff, 0),
.bg_dly = VOP_REG(RK3568_VP1_BG_MIX_CTRL, 0xff, 24),
.hpost_st_end = VOP_REG(RK3568_VP1_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
.vpost_st_end = VOP_REG(RK3568_VP1_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
.post_scl_factor = VOP_REG(RK3568_VP1_POST_SCL_FACTOR_YRGB, 0xffffffff, 0),
.post_scl_ctrl = VOP_REG(RK3568_VP1_POST_SCL_CTRL, 0x3, 0),
.htotal_pw = VOP_REG(RK3568_VP1_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
.hact_st_end = VOP_REG(RK3568_VP1_DSP_HACT_ST_END, 0x1fff1fff, 0),
.dsp_vtotal = VOP_REG(RK3568_VP1_DSP_VTOTAL_VS_END, 0x1fff, 16),
@@ -2062,10 +2146,6 @@ static const struct vop2_video_port_regs rk3588_vop_vp2_regs = {
.dclk_out_div = VOP_REG(RK3568_VP2_CLK_CTRL, 0x3, 2),
.pre_scan_htiming = VOP_REG(RK3568_VP2_PRE_SCAN_HTIMING, 0x1fff1fff, 0),
.bg_dly = VOP_REG(RK3568_VP2_BG_MIX_CTRL, 0xff, 24),
.hpost_st_end = VOP_REG(RK3568_VP2_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
.vpost_st_end = VOP_REG(RK3568_VP2_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
.post_scl_factor = VOP_REG(RK3568_VP2_POST_SCL_FACTOR_YRGB, 0xffffffff, 0),
.post_scl_ctrl = VOP_REG(RK3568_VP2_POST_SCL_CTRL, 0x3, 0),
.htotal_pw = VOP_REG(RK3568_VP2_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
.hact_st_end = VOP_REG(RK3568_VP2_DSP_HACT_ST_END, 0x1fff1fff, 0),
.dsp_vtotal = VOP_REG(RK3568_VP2_DSP_VTOTAL_VS_END, 0x1fff, 16),
@@ -2129,10 +2209,6 @@ static const struct vop2_video_port_regs rk3588_vop_vp3_regs = {
.dclk_out_div = VOP_REG(RK3568_VP3_CLK_CTRL, 0x3, 2),
.pre_scan_htiming = VOP_REG(RK3588_VP3_PRE_SCAN_HTIMING, 0x1fff1fff, 0),
.bg_dly = VOP_REG(RK3588_VP3_BG_MIX_CTRL, 0xff, 24),
.hpost_st_end = VOP_REG(RK3588_VP3_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
.vpost_st_end = VOP_REG(RK3588_VP3_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
.post_scl_factor = VOP_REG(RK3588_VP3_POST_SCL_FACTOR_YRGB, 0xffffffff, 0),
.post_scl_ctrl = VOP_REG(RK3588_VP3_POST_SCL_CTRL, 0x3, 0),
.htotal_pw = VOP_REG(RK3588_VP3_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
.hact_st_end = VOP_REG(RK3588_VP3_DSP_HACT_ST_END, 0x1fff1fff, 0),
.dsp_vtotal = VOP_REG(RK3588_VP3_DSP_VTOTAL_VS_END, 0x1fff, 16),
@@ -2174,7 +2250,7 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
.lut_dma_rid = 0xd,
.soc_id = { 0x3588, 0x3588 },
.feature = VOP_FEATURE_OUTPUT_10BIT | VOP_FEATURE_ALPHA_SCALE |
VOP_FEATURE_HDR10 | VOP_FEATURE_NEXT_HDR,
VOP_FEATURE_HDR10 | VOP_FEATURE_DOVI,
.gamma_lut_len = 1024,
.cubic_lut_len = 729, /* 9x9x9 */
.dclk_max = 2400000000,
@@ -4203,7 +4279,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 4,
.max_downscale_factor = 4,
.dly = { 4, 26, 29 },
.dly = { 4, 26, 29, 4, 35, 3, 5 },
.type = DRM_PLANE_TYPE_OVERLAY,
.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN | WIN_FEATURE_SPLICE_LEFT,
},
@@ -4257,7 +4333,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 4,
.max_downscale_factor = 4,
.dly = { 4, 26, 29 },
.dly = { 4, 26, 29, 4, 35, 3, 5 },
.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN,
},
@@ -4311,7 +4387,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 4,
.max_downscale_factor = 4,
.dly = { 4, 26, 29 },
.dly = { 4, 26, 29, 4, 35, 3, 5 },
.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN | WIN_FEATURE_SPLICE_LEFT,
},
@@ -4364,7 +4440,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 4,
.max_downscale_factor = 4,
.dly = { 4, 26, 29 },
.dly = { 4, 26, 29, 4, 35, 3, 5 },
.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER_MAIN,
},
@@ -4418,7 +4494,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 8,
.max_downscale_factor = 8,
.dly = { 23, 45, 48 },
.dly = { 23, 45, 48, 23, 54, 22, 24 },
.feature = WIN_FEATURE_SPLICE_LEFT | WIN_FEATURE_MULTI_AREA,
},
@@ -4448,7 +4524,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 8,
.max_downscale_factor = 8,
.dly = { 23, 45, 48 },
.dly = { 23, 45, 48, 23, 54, 22, 24 },
.feature = WIN_FEATURE_SPLICE_LEFT | WIN_FEATURE_MULTI_AREA,
},
@@ -4477,7 +4553,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 8,
.max_downscale_factor = 8,
.dly = { 23, 45, 48 },
.dly = { 23, 45, 48, 23, 54, 22, 24 },
.feature = WIN_FEATURE_MULTI_AREA,
},
@@ -4506,7 +4582,7 @@ static const struct vop2_win_data rk3588_vop_win_data[] = {
BIT(ROCKCHIP_VOP_VP2) | BIT(ROCKCHIP_VOP_VP3),
.max_upscale_factor = 8,
.max_downscale_factor = 8,
.dly = { 23, 45, 48 },
.dly = { 23, 45, 48, 23, 54, 22, 24 },
.feature = WIN_FEATURE_MULTI_AREA,
},
};
@@ -4801,6 +4877,9 @@ static const struct vop2_ctrl rk3588_vop_ctrl = {
.wb_dma_finish_and_en = VOP_REG(RK3588_SYS_VAR_FREQ_CTRL, 0x1, 3),
.ovl_cfg_done_port = VOP_REG(RK3568_OVL_CTRL, 0x3, 30),
.ovl_port_mux_cfg_done_imd = VOP_REG(RK3568_OVL_CTRL, 0x1, 28),
.dovi_core3_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 10),
.dovi_core2_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 9),
.dovi_core1_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 8),
.ovl_port_mux_cfg = VOP_REG(RK3568_OVL_PORT_SEL, 0xffff, 0),
.if_ctrl_cfg_done_imd = VOP_REG(RK3568_DSP_IF_POL, 0x1, 28),
.version = VOP_REG(RK3568_VERSION_INFO, 0xffff, 16),
@@ -5243,6 +5322,7 @@ static const struct vop2_data rk3588_vop = {
.vo1_grf = &rk3588_vo1_grf_ctrl,
.axi_intr = rk3568_vop_axi_intr,
.nr_axi_intr = ARRAY_SIZE(rk3568_vop_axi_intr),
.dovi = &rk3588_vop_dovi_data,
.dsc = rk3588_vop_dsc_data,
.dsc_error_ecw = dsc_ecw,
.dsc_error_buffer_flow = dsc_buffer_flow,

View File

@@ -1142,6 +1142,9 @@
#define RK3576_VP0_POST_CRC 0xC28
#define RK3568_VP0_DSP_BG 0xC2C
#define RK3568_VP0_PRE_SCAN_HTIMING 0xC30
#define RK3588_VP0_PRE_SCAN_HTIMING1 0xC34
#define RK3588_VP0_PRE_SCAN_HTIMING2 0xC38
#define RK3588_VP0_PRE_SCAN_HTIMING3 0xC3c
#define RK3568_VP0_POST_DSP_HACT_INFO 0xC34
#define RK3568_VP0_POST_DSP_VACT_INFO 0xC38
#define RK3568_VP0_POST_SCL_FACTOR_YRGB 0xC3C
@@ -1326,6 +1329,7 @@
#define RK3568_OVL_CTRL 0x600
#define RK3568_OVL_LAYER_SEL 0x604
#define RK3568_OVL_PORT_SEL 0x608
#define RK3588_DOLBY_LUT_MST 0x60c
#define RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL 0x610
#define RK3568_CLUSTER0_MIX_DST_COLOR_CTRL 0x614
#define RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL 0x618
@@ -1781,6 +1785,28 @@
#define RK3568_HDR_OETF_DX_POW1 0x2200
#define RK3568_HDR_OETF_XN1 0x2300
/* DOLBY register definition */
#define RK3588_DOLBY_CORE1_CONTROL_REG 0x3004
#define RK3588_DOLBY_CORE1_METADATA_PROGRAM_ST 0x3008
#define RK3588_DOLBY_CORE1_METADATA_PROGRAM_END 0x300C
#define RK3588_DOLBY_CORE1_INTR_RAW_REG 0x3010
#define RK3588_DOLBY_CORE1_INTR_ENABLE_REG 0x3014
#define RK3588_DOLBY_CORE1_SRANGE_REG 0x3018
#define RK3588_DOLBY_CORE2_CONTROL_REG 0x3404
#define RK3588_DOLBY_CORE2_METADATA_PROGRAM_ST 0x3408
#define RK3588_DOLBY_CORE2_METADATA_PROGRAM_END 0x340C
#define RK3588_DOLBY_CORE2_INTR_RAW_REG 0x3410
#define RK3588_DOLBY_CORE2_INTR_ENABLE_REG 0x3414
#define RK3588_DOLBY_CORE2_SRANGE_REG 0x3418
#define RK3588_DOLBY_CORE3_CONTROL_REG 0x3504
#define RK3588_DOLBY_CORE3_METADATA_PROGRAM_ST 0x3508
#define RK3588_DOLBY_CORE3_METADATA_PROGRAM_END 0x350C
#define RK3588_DOLBY_CORE3_INTR_RAW_REG 0x3510
#define RK3588_DOLBY_CORE3_INTR_ENABLE_REG 0x3514
#define RK3588_DOLBY_CORE3_SRANGE_REG 0x3518
/* DSC register definition */
#define RK3588_DSC_8K_PPS0_3 0x4000
#define RK3588_DSC_8K_CTRL0 0x40A0

View File

@@ -90,7 +90,6 @@ enum drm_rockchip_gem_cpu_acquire_type {
enum rockchip_crtc_feture {
ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE,
ROCKCHIP_DRM_CRTC_FEATURE_HDR10,
ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR,
ROCKCHIP_DRM_CRTC_FEATURE_DOVI,
ROCKCHIP_DRM_CRTC_FEATURE_VIVID_HDR,
};