From 7d07b3ae8ddad407913c5301877e694430a3263f Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 23 Nov 2023 08:24:31 +0000
Subject: [PATCH] add build kerneldeb
---
kernel/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 1176 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 1,063 insertions(+), 113 deletions(-)
diff --git a/kernel/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/kernel/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 35128d4..7757b07 100644
--- a/kernel/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/kernel/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -35,6 +35,8 @@
#include <linux/swab.h>
#include <linux/sort.h>
#include <linux/rockchip/cpu.h>
+#include <linux/workqueue.h>
+#include <linux/types.h>
#include <soc/rockchip/rockchip_dmc.h>
#include <soc/rockchip/rockchip-system-status.h>
#include <uapi/linux/videodev2.h>
@@ -47,6 +49,7 @@
#include "rockchip_drm_psr.h"
#include "rockchip_drm_vop.h"
#include "rockchip_vop_reg.h"
+#include "rockchip_post_csc.h"
#define _REG_SET(vop2, name, off, reg, mask, v, relaxed) \
vop2_mask_write(vop2, off + reg.offset, mask, reg.shift, v, reg.write_mask, relaxed)
@@ -78,6 +81,8 @@
#define VOP_CTRL_SET(x, name, v) \
REG_SET(x, name, 0, (x)->data->ctrl->name, v, false)
+
+#define VOP_CTRL_GET(x, name) vop2_read_reg(x, 0, &(x)->data->ctrl->name)
#define VOP_INTR_GET(vop2, name) \
vop2_read_reg(vop2, 0, &vop2->data->ctrl->name)
@@ -477,6 +482,8 @@
uint8_t id;
bool layer_sel_update;
bool xmirror_en;
+ bool need_reset_p2i_flag;
+ atomic_t post_buf_empty_flag;
const struct vop2_video_port_regs *regs;
struct completion dsp_hold_completion;
@@ -555,6 +562,11 @@
bool gamma_lut_active;
/**
+ * @lut_dma_rid: lut dma id
+ */
+ u16 lut_dma_rid;
+
+ /**
* @gamma_lut: atomic gamma look up table
*/
struct drm_color_lut *gamma_lut;
@@ -568,6 +580,11 @@
* @cubic_lut_gem_obj: gem obj to store cubic lut
*/
struct rockchip_gem_object *cubic_lut_gem_obj;
+
+ /**
+ * @hdr_lut_gem_obj: gem obj to store hdr lut
+ */
+ struct rockchip_gem_object *hdr_lut_gem_obj;
/**
* @cubic_lut: cubic look up table
@@ -591,10 +608,29 @@
struct drm_property *plane_mask_prop;
/**
+ * @hdr_ext_data_prop: hdr extend data interaction with userspace
+ */
+ struct drm_property *hdr_ext_data_prop;
+
+ int hdrvivid_mode;
+
+ /**
+ * @acm_lut_data_prop: acm lut data interaction with userspace
+ */
+ struct drm_property *acm_lut_data_prop;
+ /**
+ * @post_csc_data_prop: post csc data interaction with userspace
+ */
+ struct drm_property *post_csc_data_prop;
+
+ /**
* @primary_plane_phy_id: vp primary plane phy id, the primary plane
* will be used to show uboot logo and kernel logo
*/
enum vop2_layer_phy_id primary_plane_phy_id;
+
+ struct post_acm acm_info;
+ struct post_csc csc_info;
};
struct vop2 {
@@ -652,6 +688,7 @@
*/
uint32_t registered_num_wins;
uint8_t used_mixers;
+ uint8_t esmart_lb_mode;
/**
* @active_vp_mask: Bitmask of active video ports;
*/
@@ -684,6 +721,8 @@
unsigned int enable_count;
struct clk *hclk;
struct clk *aclk;
+ struct work_struct post_buf_empty_work;
+ struct workqueue_struct *workqueue;
struct vop2_layer layers[ROCKCHIP_MAX_LAYER];
/* must put at the end of the struct */
@@ -717,6 +756,7 @@
{ MEDIA_BUS_FMT_UYVY8_2X8, "UYVY8_2X8" },
{ MEDIA_BUS_FMT_YUYV8_1X16, "YUYV8_1X16" },
{ MEDIA_BUS_FMT_UYVY8_1X16, "UYVY8_1X16" },
+ { MEDIA_BUS_FMT_RGB101010_1X30, "RGB101010_1x30" },
};
static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list)
@@ -991,8 +1031,23 @@
static uint32_t vop2_read_vcnt(struct vop2_video_port *vp)
{
uint32_t offset = RK3568_SYS_STATUS0 + (vp->id << 2);
+ uint32_t vcnt0, vcnt1;
+ int i = 0;
- return vop2_readl(vp->vop2, offset) >> 16;
+ for (i = 0; i < 10; i++) {
+ vcnt0 = vop2_readl(vp->vop2, offset) >> 16;
+ vcnt1 = vop2_readl(vp->vop2, offset) >> 16;
+
+ if ((vcnt1 - vcnt0) <= 1)
+ break;
+ }
+
+ if (i == 10) {
+ DRM_DEV_ERROR(vp->vop2->dev, "read VP%d vcnt error: %d %d\n", vp->id, vcnt0, vcnt1);
+ vcnt1 = vop2_readl(vp->vop2, offset) >> 16;
+ }
+
+ return vcnt1;
}
static void vop2_wait_for_irq_handler(struct drm_crtc *crtc)
@@ -1864,7 +1919,7 @@
#define VOP2_COMMON_SCL_FAC_CHECK(src, dst, fac) \
(fac * (dst - 1) >> 16 < (src - 1))
#define VOP3_COMMON_HOR_SCL_FAC_CHECK(src, dst, fac) \
- (fac * (dst - 1) >> 16 <= (src - 1))
+ (fac * (dst - 1) >> 16 < (src - 1))
static uint16_t vop2_scale_factor(enum scale_mode mode,
int32_t filter_mode,
@@ -1983,12 +2038,30 @@
}
}
- if (src_h >= (4 * dst_h)) {
- ygt4 = 1;
- src_h >>= 2;
- } else if (src_h >= (2 * dst_h)) {
- ygt2 = 1;
- src_h >>= 1;
+ /**
+ * The rk3528 is processed as 2 pixel/cycle,
+ * so ygt2/ygt4 needs to be triggered in advance to improve performance
+ * when src_w is bigger than 1920.
+ * dst_h / src_h is at [1, 0.65) ygt2=0; ygt4=0;
+ * dst_h / src_h is at [0.65, 0.35) ygt2=1; ygt4=0;
+ * dst_h / src_h is at [0.35, 0) ygt2=0; ygt4=1;
+ */
+ if (vop2->version == VOP_VERSION_RK3528 && src_w > 1920) {
+ if (src_h >= (100 * dst_h / 35)) {
+ ygt4 = 1;
+ src_h >>= 2;
+ } else if ((src_h >= 100 * dst_h / 65) && (src_h < 100 * dst_h / 35)) {
+ ygt2 = 1;
+ src_h >>= 1;
+ }
+ } else {
+ if (src_h >= (4 * dst_h)) {
+ ygt4 = 1;
+ src_h >>= 2;
+ } else if (src_h >= (2 * dst_h)) {
+ ygt2 = 1;
+ src_h >>= 1;
+ }
}
yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
@@ -2065,10 +2138,17 @@
if (!is_vop3(vop2) ||
(!vpstate->afbc_en && !vpstate->tiled_en) ||
win_data->vsd_pre_filter_mode == VOP3_PRE_SCALE_DOWN_GT) {
- if (cbcr_src_h >= (4 * dst_h))
- ygt4 = 1;
- else if (cbcr_src_h >= (2 * dst_h))
- ygt2 = 1;
+ if (vop2->version == VOP_VERSION_RK3528 && src_w > 1920) {
+ if (cbcr_src_h >= (100 * dst_h / 35))
+ ygt4 = 1;
+ else if ((cbcr_src_h >= 100 * dst_h / 65) && (cbcr_src_h < 100 * dst_h / 35))
+ ygt2 = 1;
+ } else {
+ if (cbcr_src_h >= (4 * dst_h))
+ ygt4 = 1;
+ else if (cbcr_src_h >= (2 * dst_h))
+ ygt2 = 1;
+ }
if (ygt4)
cbcr_src_h >>= 2;
@@ -2230,29 +2310,49 @@
vpstate->r2y_en = 0;
vpstate->csc_mode = 0;
- /* hdr2sdr and sdr2hdr will do csc itself */
- if (vpstate->hdr2sdr_en) {
- /*
- * This is hdr2sdr enabled plane
- * If it's RGB layer do hdr2sdr, we need to do r2y before send to hdr2sdr,
- * because hdr2sdr only support yuv input.
- */
- if (!is_input_yuv) {
- vpstate->r2y_en = 1;
- vpstate->csc_mode = vop2_convert_csc_mode(output_csc, CSC_10BIT_DEPTH);
+ if (is_vop3(vp->vop2)) {
+ if (vpstate->hdr_in) {
+ if (is_input_yuv) {
+ vpstate->y2r_en = 1;
+ vpstate->csc_mode = vop2_convert_csc_mode(input_csc,
+ CSC_13BIT_DEPTH);
+ }
+ return;
+ } else if (vp->sdr2hdr_en) {
+ if (is_input_yuv) {
+ vpstate->y2r_en = 1;
+ vpstate->csc_mode = vop2_convert_csc_mode(input_csc,
+ csc_y2r_bit_depth);
+ }
+ return;
}
- return;
- } else if (!vpstate->hdr_in && vp->sdr2hdr_en) {
- /*
- * This is sdr2hdr enabled plane
- * If it's YUV layer do sdr2hdr, we need to do y2r before send to sdr2hdr,
- * because sdr2hdr only support rgb input.
- */
- if (is_input_yuv) {
- vpstate->y2r_en = 1;
- vpstate->csc_mode = vop2_convert_csc_mode(input_csc, csc_y2r_bit_depth);
+ } else {
+ /* hdr2sdr and sdr2hdr will do csc itself */
+ if (vpstate->hdr2sdr_en) {
+ /*
+ * This is hdr2sdr enabled plane
+ * If it's RGB layer do hdr2sdr, we need to do r2y before send to hdr2sdr,
+ * because hdr2sdr only support yuv input.
+ */
+ if (!is_input_yuv) {
+ vpstate->r2y_en = 1;
+ vpstate->csc_mode = vop2_convert_csc_mode(output_csc,
+ CSC_10BIT_DEPTH);
+ }
+ return;
+ } else if (!vpstate->hdr_in && vp->sdr2hdr_en) {
+ /*
+ * This is sdr2hdr enabled plane
+ * If it's YUV layer do sdr2hdr, we need to do y2r before send to sdr2hdr,
+ * because sdr2hdr only support rgb input.
+ */
+ if (is_input_yuv) {
+ vpstate->y2r_en = 1;
+ vpstate->csc_mode = vop2_convert_csc_mode(input_csc,
+ csc_y2r_bit_depth);
+ }
+ return;
}
- return;
}
if (is_input_yuv && !is_output_yuv) {
@@ -2657,7 +2757,7 @@
fifo_throd = fb->pitches[0] >> 4;
if (fifo_throd >= vop2->data->wb->fifo_depth)
fifo_throd = vop2->data->wb->fifo_depth;
- r2y = fb->format->is_yuv && (!is_yuv_output(vcstate->bus_format));
+ r2y = !vcstate->yuv_overlay && fb->format->is_yuv;
/*
* the vp_id register config done immediately
@@ -2963,25 +3063,16 @@
*/
static void vop3_layer_map_initial(struct vop2 *vop2, uint32_t current_vp_id)
{
- struct vop2_video_port *vp;
- struct vop2_win *win;
- unsigned long win_mask;
uint16_t vp_id;
- int phys_id;
- int i;
+ struct drm_plane *plane = NULL;
- for (i = 0; i < vop2->data->nr_vps; i++) {
- vp_id = i;
- vp = &vop2->vps[vp_id];
- vp->win_mask = vp->plane_mask;
- win_mask = vp->win_mask;
- for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) {
- win = vop2_find_win_by_phys_id(vop2, phys_id);
- VOP_CTRL_SET(vop2, win_vp_id[phys_id], vp_id);
- win->vp_mask = BIT(vp_id);
- win->old_vp_mask = win->vp_mask;
- DRM_DEV_DEBUG(vop2->dev, "%s attach to vp%d\n", win->name, vp_id);
- }
+ drm_for_each_plane(plane, vop2->drm_dev) {
+ struct vop2_win *win = to_vop2_win(plane);
+
+ vp_id = VOP_CTRL_GET(vop2, win_vp_id[win->phys_id]);
+ win->vp_mask = BIT(vp_id);
+ win->old_vp_mask = win->vp_mask;
+ vop2->vps[vp_id].win_mask |= BIT(win->phys_id);
}
}
@@ -3081,8 +3172,17 @@
VOP_MODULE_SET(vop2, wb, axi_uv_id, 0xe);
vop2_wb_cfg_done(vp);
- if (is_vop3(vop2))
- VOP_CTRL_SET(vop2, esmart_lb_mode, vop2->data->esmart_lb_mode);
+ if (is_vop3(vop2)) {
+ VOP_CTRL_SET(vop2, dsp_vs_t_sel, 0);
+ VOP_CTRL_SET(vop2, esmart_lb_mode, vop2->esmart_lb_mode);
+ }
+
+ /*
+ * This is unused and error init value for rk3528 vp1, if less of this config,
+ * vp1 can't display normally.
+ */
+ if (vop2->version == VOP_VERSION_RK3528)
+ vop2_mask_write(vop2, 0x700, 0x3, 4, 0, 0, true);
VOP_CTRL_SET(vop2, cfg_done_en, 1);
/*
@@ -3151,6 +3251,7 @@
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
+ const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id];
int ret;
WARN_ON(vp->event);
@@ -3163,6 +3264,8 @@
VOP_MODULE_SET(vop2, vp, cubic_lut_en, 0);
}
+ if (vp_data->feature & VOP_FEATURE_VIVID_HDR)
+ VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 0);
vop2_disable_all_planes_for_crtc(crtc);
/*
@@ -3188,6 +3291,7 @@
vop2_dsp_hold_valid_irq_disable(crtc);
vop2_disable(crtc);
+ memset(&vp->active_tv_state, 0, sizeof(vp->active_tv_state));
vop2_unlock(vop2);
vop2->active_vp_mask &= ~BIT(vp->id);
@@ -3500,7 +3604,7 @@
uint32_t actual_w, actual_h, dsp_w, dsp_h;
uint32_t dsp_stx, dsp_sty;
uint32_t act_info, dsp_info, dsp_st;
- uint32_t format;
+ uint32_t format, check_size;
uint32_t afbc_format;
uint32_t rb_swap;
uint32_t uv_swap;
@@ -3569,18 +3673,19 @@
actual_w = drm_rect_width(src) >> 16;
actual_h = drm_rect_height(src) >> 16;
dsp_w = drm_rect_width(dest);
- if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
+ if (dest->x1 + dsp_w > adjusted_mode->crtc_hdisplay) {
DRM_ERROR("vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n",
- vp->id, win->name, dest->x1, dsp_w, adjusted_mode->hdisplay);
+ vp->id, win->name, dest->x1, dsp_w, adjusted_mode->crtc_hdisplay);
dsp_w = adjusted_mode->hdisplay - dest->x1;
if (dsp_w < 4)
dsp_w = 4;
actual_w = dsp_w * actual_w / drm_rect_width(dest);
}
dsp_h = drm_rect_height(dest);
- if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
+ check_size = adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE ? adjusted_mode->vdisplay : adjusted_mode->crtc_vdisplay;
+ if (dest->y1 + dsp_h > check_size) {
DRM_ERROR("vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n",
- vp->id, win->name, dest->y1, dsp_h, adjusted_mode->vdisplay);
+ vp->id, win->name, dest->y1, dsp_h, adjusted_mode->crtc_vdisplay);
dsp_h = adjusted_mode->vdisplay - dest->y1;
if (dsp_h < 4)
dsp_h = 4;
@@ -3588,20 +3693,25 @@
}
/*
- * This is workaround solution for IC design:
- * esmart can't support scale down when actual_w % 16 == 1.
+ * Workaround only for rk3568 vop
*/
- if (!(win->feature & WIN_FEATURE_AFBDC)) {
- if (actual_w > dsp_w && (actual_w & 0xf) == 1) {
- DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->name, actual_w);
- actual_w -= 1;
+ if (vop2->version == VOP_VERSION_RK3568) {
+ /*
+ * This is workaround solution for IC design:
+ * esmart can't support scale down when actual_w % 16 == 1.
+ */
+ if (!(win->feature & WIN_FEATURE_AFBDC)) {
+ if (actual_w > dsp_w && (actual_w & 0xf) == 1) {
+ DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->name, actual_w);
+ actual_w -= 1;
+ }
}
- }
- if (vpstate->afbc_en && actual_w % 4) {
- DRM_ERROR("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n",
- vp->id, win->name, actual_w);
- actual_w = ALIGN_DOWN(actual_w, 4);
+ if (vpstate->afbc_en && actual_w % 4) {
+ DRM_ERROR("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n",
+ vp->id, win->name, actual_w);
+ actual_w = ALIGN_DOWN(actual_w, 4);
+ }
}
act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
@@ -3633,7 +3743,7 @@
if (vop2->version != VOP_VERSION_RK3568)
rk3588_vop2_win_cfg_axi(win);
- if (is_vop3(vop2) && !vop2_cluster_window(win))
+ if (is_vop3(vop2) && !vop2_cluster_window(win) && !win->parent)
VOP_WIN_SET(vop2, win, scale_engine_num, win->scale_engine_num);
if (vpstate->afbc_en) {
@@ -3765,7 +3875,9 @@
if (vop2_cluster_window(win)) {
lb_mode = vop2_get_cluster_lb_mode(win, vpstate);
VOP_CLUSTER_SET(vop2, win, lb_mode, lb_mode);
+ VOP_CLUSTER_SET(vop2, win, scl_lb_mode, lb_mode == 1 ? 3 : 0);
VOP_CLUSTER_SET(vop2, win, enable, 1);
+ VOP_CLUSTER_SET(vop2, win, frm_reset_en, 1);
}
if (vcstate->output_if & VOP_OUTPUT_IF_BT1120 ||
vcstate->output_if & VOP_OUTPUT_IF_BT656)
@@ -4736,6 +4848,27 @@
struct drm_display_mode *adj_mode)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
+ struct vop2 *vop2 = vp->vop2;
+
+ /*
+ * For RK3568 and RK3588, the hactive of video timing must
+ * be 4-pixel aligned.
+ */
+ if (vop2->version == VOP_VERSION_RK3568 || vop2->version == VOP_VERSION_RK3588) {
+ if (adj_mode->hdisplay % 4) {
+ u16 old_hdisplay = adj_mode->hdisplay;
+ u16 align;
+
+ align = 4 - (adj_mode->hdisplay % 4);
+ adj_mode->hdisplay += align;
+ adj_mode->hsync_start += align;
+ adj_mode->hsync_end += align;
+ adj_mode->htotal += align;
+
+ DRM_WARN("VP%d: hactive need to be aligned with 4-pixel, %d -> %d\n",
+ vp->id, old_hdisplay, adj_mode->hdisplay);
+ }
+ }
drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
@@ -4799,6 +4932,8 @@
to_rockchip_crtc_state(crtc->state);
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];
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
u16 vtotal = mode->crtc_vtotal;
u16 hdisplay = mode->crtc_hdisplay;
@@ -4838,8 +4973,16 @@
val = vact_st_f1 << 16 | vact_end_f1;
VOP_MODULE_SET(vop2, vp, vpost_st_end_f1, val);
}
- VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y,
- is_yuv_output(vcstate->bus_format));
+
+ /*
+ * BCSH[R2Y] -> POST Linebuffer[post scale] -> the background R2Y will be deal by post_dsp_out_r2y
+ *
+ * POST Linebuffer[post scale] -> ACM[R2Y] -> the background R2Y will be deal by ACM[R2Y]
+ */
+ if (vp_data->feature & VOP_FEATURE_POST_ACM)
+ VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, vcstate->yuv_overlay);
+ else
+ VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, is_yuv_output(vcstate->bus_format));
}
/*
@@ -4880,6 +5023,107 @@
return false;
}
+/*
+ * For vop3 video port0, if hdr_vivid is not enable, the pipe delay time as follow:
+ * win_dly + config_win_dly + layer_mix_dly + sdr2hdr_dly + * hdr_mix_dly = config_bg_dly
+ *
+ * if hdr_vivid is enable, the hdr layer's pipe delay time as follow:
+ * win_dly + config_win_dly +hdrvivid_dly + hdr_mix_dly = config_bg_dly
+ *
+ * If hdrvivid and sdr2hdr bot enable, the time arrivr hdr_mix should be the same:
+ * win_dly + config_win_dly0 + hdrvivid_dly = win_dly + config_win_dly1 + laer_mix_dly +
+ * sdr2hdr_dly
+ *
+ * For vop3 video port1, the pipe delay time as follow:
+ * win_dly + config_win_dly + layer_mix_dly = config_bg_dly
+ *
+ * Here, win_dly, layer_mix_dly, sdr2hdr_dly, hdr_mix_dly, hdrvivid_dly is the hardware
+ * delay cycles. Config_win_dly and config_bg_dly is the register value that we can config.
+ * Different hdr vivid mode have different hdrvivid_dly. For sdr2hdr_dly, only sde2hdr
+ * enable, it will delay, otherwise, the sdr2hdr_dly is 0.
+ *
+ * For default, the config_win_dly will be 0, it just user to make the pipe to arrive
+ * hdr_mix at the same time.
+ */
+static void vop3_setup_pipe_dly(struct vop2_video_port *vp, const struct vop2_zpos *vop2_zpos)
+{
+ struct vop2 *vop2 = vp->vop2;
+ struct drm_crtc *crtc = &vp->crtc;
+ const struct vop2_zpos *zpos;
+ struct drm_plane *plane;
+ struct vop2_plane_state *vpstate;
+ struct vop2_win *win;
+ const struct vop2_data *vop2_data = vop2->data;
+ const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
+ struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
+ u16 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+ u16 hdisplay = adjusted_mode->crtc_hdisplay;
+ int bg_dly = 0x0;
+ int dly = 0x0;
+ int hdr_win_dly;
+ int sdr_win_dly;
+ int sdr2hdr_dly;
+ int pre_scan_dly;
+ int i;
+
+ /**
+ * config bg dly, select the max delay num of hdrvivid and sdr2hdr module
+ * as the increase value of bg delay num. If hdrvivid and sdr2hdr is not
+ * work, the default bg_dly is 0x10. and the default win delay num is 0.
+ */
+ if ((vp->hdr_en || vp->sdr2hdr_en) &&
+ (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) {
+ /* set sdr2hdr_dly to 0 if sdr2hdr is disable */
+ sdr2hdr_dly = vp->sdr2hdr_en ? vp_data->sdr2hdr_dly : 0;
+
+ /* set the max delay pipe's config_win_dly as 0 */
+ if (vp_data->hdrvivid_dly[vp->hdrvivid_mode] >=
+ sdr2hdr_dly + vp_data->layer_mix_dly) {
+ bg_dly = vp_data->win_dly + vp_data->hdrvivid_dly[vp->hdrvivid_mode] +
+ vp_data->hdr_mix_dly;
+ hdr_win_dly = 0;
+ sdr_win_dly = vp_data->hdrvivid_dly[vp->hdrvivid_mode] -
+ vp_data->layer_mix_dly - sdr2hdr_dly;
+ } else {
+ bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + sdr2hdr_dly +
+ vp_data->hdr_mix_dly;
+ hdr_win_dly = sdr2hdr_dly + vp_data->layer_mix_dly -
+ vp_data->hdrvivid_dly[vp->hdrvivid_mode];
+ sdr_win_dly = 0;
+ }
+ } else {
+ bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + vp_data->hdr_mix_dly;
+ sdr_win_dly = 0;
+ }
+
+ pre_scan_dly = bg_dly + (hdisplay >> 1) - 1;
+ pre_scan_dly = (pre_scan_dly << 16) | hsync_len;
+ VOP_MODULE_SET(vop2, vp, bg_dly, bg_dly);
+ VOP_MODULE_SET(vop2, vp, pre_scan_htiming, pre_scan_dly);
+
+ /**
+ * config win dly
+ */
+ if (!vop2_zpos)
+ return;
+
+ for (i = 0; i < vp->nr_layers; i++) {
+ zpos = &vop2_zpos[i];
+ win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id);
+ plane = &win->base;
+ vpstate = to_vop2_plane_state(plane->state);
+
+ if ((vp->hdr_en || vp->sdr2hdr_en) &&
+ (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) {
+ dly = vpstate->hdr_in ? hdr_win_dly : sdr_win_dly;
+ }
+ if (vop2_cluster_window(win))
+ dly |= dly << 8;
+
+ VOP_CTRL_SET(vop2, win_dly[win->phys_id], dly);
+ }
+}
+
static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
@@ -4900,7 +5144,6 @@
u16 vact_st = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_start;
u16 vact_end = vact_st + vdisplay;
bool interlaced = !!(adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE);
- uint8_t out_mode;
bool dclk_inv, yc_swap = false;
int act_end;
uint32_t val;
@@ -4925,6 +5168,7 @@
if (vcstate->output_if & VOP_OUTPUT_IF_RGB) {
VOP_CTRL_SET(vop2, rgb_en, 1);
VOP_CTRL_SET(vop2, rgb_mux, vp_data->id);
+ VOP_CTRL_SET(vop2, rgb_pin_pol, val);
VOP_GRF_SET(vop2, grf_dclk_inv, dclk_inv);
}
@@ -5038,21 +5282,6 @@
VOP_CTRL_SET(vop2, hdmi_dclk_pol, 1);
}
- if ((vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
- !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) ||
- vcstate->output_if & VOP_OUTPUT_IF_BT656)
- out_mode = ROCKCHIP_OUT_MODE_P888;
- else
- out_mode = vcstate->output_mode;
- VOP_MODULE_SET(vop2, vp, out_mode, out_mode);
-
- if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
- VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RB_SWAP);
- else
- VOP_MODULE_SET(vop2, vp, dsp_data_swap, 0);
-
- vop2_dither_setup(crtc);
-
VOP_MODULE_SET(vop2, vp, htotal_pw, (htotal << 16) | hsync_len);
val = hact_st << 16;
val |= hact_end;
@@ -5105,9 +5334,20 @@
VOP_MODULE_SET(vop2, vp, dclk_div2_phase_lock, 0);
}
- clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000);
+ /*
+ * For RK3528, the path of CVBS output is like:
+ * VOP BT656 ENCODER -> CVBS BT656 DECODER -> CVBS ENCODER -> CVBS VDAC
+ * The vop2 dclk should be four times crtc_clock for CVBS sampling clock needs.
+ */
+ if (vop2->version == VOP_VERSION_RK3528 && vcstate->output_if & VOP_OUTPUT_IF_BT656)
+ clk_set_rate(vp->dclk, 4 * adjusted_mode->crtc_clock * 1000);
+ else
+ clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000);
vop2_post_config(crtc);
+
+ if (is_vop3(vop2))
+ vop3_setup_pipe_dly(vp, NULL);
vop2_cfg_done(crtc);
@@ -5154,6 +5394,224 @@
struct drm_crtc_state *crtc_state)
{
return 0;
+}
+
+static void vop3_disable_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phys_id)
+{
+ struct vop2 *vop2 = vp->vop2;
+ struct vop2_win *win = vop2_find_win_by_phys_id(vop2, win_phys_id);
+ struct drm_plane *plane = &win->base;
+ struct drm_plane_state *pstate = plane->state;
+ struct vop2_plane_state *vpstate = to_vop2_plane_state(pstate);
+
+ VOP_MODULE_SET(vop2, vp, hdr10_en, 0);
+ VOP_MODULE_SET(vop2, vp, hdr_vivid_en, 0);
+ VOP_MODULE_SET(vop2, vp, hdr_vivid_bypass_en, 0);
+ VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 0);
+ VOP_MODULE_SET(vop2, vp, sdr2hdr_en, 0);
+ VOP_MODULE_SET(vop2, vp, sdr2hdr_path_en, 0);
+ VOP_MODULE_SET(vop2, vp, sdr2hdr_auto_gating_en, 1);
+
+ vp->hdr_en = false;
+ vp->hdr_in = false;
+ vp->hdr_out = false;
+ vp->sdr2hdr_en = false;
+ vpstate->hdr_in = false;
+ vpstate->hdr2sdr_en = false;
+}
+
+static void vop3_setup_hdrvivid(struct vop2_video_port *vp, uint8_t win_phys_id)
+{
+ struct vop2 *vop2 = vp->vop2;
+ struct vop2_win *win = vop2_find_win_by_phys_id(vop2, win_phys_id);
+ struct drm_plane *plane = &win->base;
+ struct drm_plane_state *pstate = plane->state;
+ struct vop2_plane_state *vpstate = to_vop2_plane_state(pstate);
+ struct drm_crtc_state *cstate = vp->crtc.state;
+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(cstate);
+ unsigned long win_mask = vp->win_mask;
+ int phys_id;
+ struct hdrvivid_regs *hdrvivid_data;
+ struct hdr_extend *hdr_data;
+ bool have_sdr_layer = false;
+ uint32_t hdr_mode;
+ int i;
+ u32 *tone_lut_kvaddr;
+ dma_addr_t tone_lut_mst;
+
+ vp->hdr_en = false;
+ vp->hdr_in = false;
+ vp->hdr_out = false;
+ vp->sdr2hdr_en = false;
+ vpstate->hdr_in = false;
+ vpstate->hdr2sdr_en = false;
+
+ hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data;
+ hdrvivid_data = &hdr_data->hdrvivid_data;
+
+ hdr_mode = hdrvivid_data->hdr_mode;
+
+ if (hdr_mode > SDR2HLG && hdr_mode != SDR2HDR10_USERSPACE &&
+ hdr_mode != SDR2HLG_USERSPACE) {
+ DRM_ERROR("Invalid HDR mode:%d, beyond the mode range\n", hdr_mode);
+ return;
+ }
+
+ /* adjust userspace hdr mode value to kernel value */
+ if (hdr_mode == SDR2HDR10_USERSPACE)
+ hdr_mode = SDR2HDR10;
+ if (hdr_mode == SDR2HLG_USERSPACE)
+ hdr_mode = SDR2HLG;
+
+ if (hdr_mode <= HDR102SDR && vpstate->eotf != SMPTE_ST2084 && vpstate->eotf != HLG) {
+ DRM_ERROR("Invalid HDR mode:%d, mismatch plane eotf:%d\n", hdr_mode,
+ vpstate->eotf);
+ return;
+ }
+
+ vp->hdrvivid_mode = hdr_mode;
+ vcstate->yuv_overlay = false;
+
+ if (hdr_mode <= HDR102SDR) {
+ vp->hdr_en = true;
+ vp->hdr_in = true;
+ vpstate->hdr_in = true;
+ } else {
+ vp->sdr2hdr_en = true;
+ }
+
+ /*
+ * To confirm whether need to enable sdr2hdr.
+ */
+ for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) {
+ win = vop2_find_win_by_phys_id(vop2, phys_id);
+ plane = &win->base;
+ pstate = plane->state;
+ vpstate = to_vop2_plane_state(pstate);
+
+ /* skip inactive plane */
+ if (!vop2_plane_active(pstate))
+ continue;
+
+ if (vpstate->eotf != SMPTE_ST2084 && vpstate->eotf != HLG) {
+ have_sdr_layer = true;
+ break;
+ }
+ }
+
+ if (hdr_mode == PQHDR2SDR_WITH_DYNAMIC || hdr_mode == HLG2SDR_WITH_DYNAMIC ||
+ hdr_mode == HLG2SDR_WITHOUT_DYNAMIC || hdr_mode == HDR102SDR) {
+ vpstate->hdr2sdr_en = true;
+ } else {
+ vp->hdr_out = true;
+ if (have_sdr_layer)
+ vp->sdr2hdr_en = true;
+ }
+
+ /**
+ * Config hdr ctrl registers
+ */
+ vop2_writel(vop2, RK3528_SDR2HDR_CTRL, hdrvivid_data->sdr2hdr_ctrl);
+ vop2_writel(vop2, RK3528_HDRVIVID_CTRL, hdrvivid_data->hdrvivid_ctrl);
+
+ VOP_MODULE_SET(vop2, vp, hdr10_en, vp->hdr_en);
+ if (vp->hdr_en) {
+ VOP_MODULE_SET(vop2, vp, hdr_vivid_en, (hdr_mode == HDR_BYPASS) ? 0 : 1);
+ VOP_MODULE_SET(vop2, vp, hdr_vivid_path_mode,
+ (hdr_mode == HDR102SDR) ? PQHDR2SDR_WITH_DYNAMIC : hdr_mode);
+ VOP_MODULE_SET(vop2, vp, hdr_vivid_bypass_en, (hdr_mode == HDR_BYPASS) ? 1 : 0);
+ } else {
+ VOP_MODULE_SET(vop2, vp, hdr_vivid_en, 0);
+ }
+ VOP_MODULE_SET(vop2, vp, sdr2hdr_en, vp->sdr2hdr_en);
+ VOP_MODULE_SET(vop2, vp, sdr2hdr_path_en, vp->sdr2hdr_en);
+ VOP_MODULE_SET(vop2, vp, sdr2hdr_auto_gating_en, vp->sdr2hdr_en ? 0 : 1);
+
+ vop2_writel(vop2, RK3528_SDR_CFG_COE0, hdrvivid_data->sdr2hdr_coe0);
+ vop2_writel(vop2, RK3528_SDR_CFG_COE1, hdrvivid_data->sdr2hdr_coe1);
+ vop2_writel(vop2, RK3528_SDR_CSC_COE00_01, hdrvivid_data->sdr2hdr_csc_coe00_01);
+ vop2_writel(vop2, RK3528_SDR_CSC_COE02_10, hdrvivid_data->sdr2hdr_csc_coe02_10);
+ vop2_writel(vop2, RK3528_SDR_CSC_COE11_12, hdrvivid_data->sdr2hdr_csc_coe11_12);
+ vop2_writel(vop2, RK3528_SDR_CSC_COE20_21, hdrvivid_data->sdr2hdr_csc_coe20_21);
+ vop2_writel(vop2, RK3528_SDR_CSC_COE22, hdrvivid_data->sdr2hdr_csc_coe22);
+
+ vop2_writel(vop2, RK3528_HDR_PQ_GAMMA, hdrvivid_data->hdr_pq_gamma);
+ vop2_writel(vop2, RK3528_HLG_RFIX_SCALEFAC, hdrvivid_data->hlg_rfix_scalefac);
+ vop2_writel(vop2, RK3528_HLG_MAXLUMA, hdrvivid_data->hlg_maxluma);
+ vop2_writel(vop2, RK3528_HLG_R_TM_LIN2NON, hdrvivid_data->hlg_r_tm_lin2non);
+
+ vop2_writel(vop2, RK3528_HDR_CSC_COE00_01, hdrvivid_data->hdr_csc_coe00_01);
+ vop2_writel(vop2, RK3528_HDR_CSC_COE02_10, hdrvivid_data->hdr_csc_coe02_10);
+ vop2_writel(vop2, RK3528_HDR_CSC_COE11_12, hdrvivid_data->hdr_csc_coe11_12);
+ vop2_writel(vop2, RK3528_HDR_CSC_COE20_21, hdrvivid_data->hdr_csc_coe20_21);
+ vop2_writel(vop2, RK3528_HDR_CSC_COE22, hdrvivid_data->hdr_csc_coe22);
+
+ tone_lut_kvaddr = (u32 *)vp->hdr_lut_gem_obj->kvaddr;
+ tone_lut_mst = vp->hdr_lut_gem_obj->dma_addr;
+
+ for (i = 0; i < RK_HDRVIVID_TONE_SCA_AXI_TAB_LENGTH; i++)
+ *tone_lut_kvaddr++ = hdrvivid_data->tone_sca_axi_tab[i];
+
+ VOP_MODULE_SET(vop2, vp, lut_dma_rid, vp->lut_dma_rid - vp->id);
+ VOP_MODULE_SET(vop2, vp, hdr_lut_mode, 1);
+ VOP_MODULE_SET(vop2, vp, hdr_lut_mst, tone_lut_mst);
+ VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 1);
+ VOP_CTRL_SET(vop2, lut_dma_en, 1);
+
+ for (i = 0; i < RK_HDRVIVID_GAMMA_CURVE_LENGTH; i++)
+ vop2_writel(vop2, RK3528_HDRGAMMA_CURVE + i * 4, hdrvivid_data->hdrgamma_curve[i]);
+
+ for (i = 0; i < RK_HDRVIVID_GAMMA_MDFVALUE_LENGTH; i++)
+ vop2_writel(vop2, RK3528_HDRGAMMA_MDFVALUE + i * 4,
+ hdrvivid_data->hdrgamma_mdfvalue[i]);
+
+ for (i = 0; i < RK_SDR2HDR_INVGAMMA_CURVE_LENGTH; i++)
+ vop2_writel(vop2, RK3528_SDRINVGAMMA_CURVE + i * 4,
+ hdrvivid_data->sdrinvgamma_curve[i]);
+
+ for (i = 0; i < RK_SDR2HDR_INVGAMMA_S_IDX_LENGTH; i++)
+ vop2_writel(vop2, RK3528_SDRINVGAMMA_STARTIDX + i * 4,
+ hdrvivid_data->sdrinvgamma_startidx[i]);
+
+ for (i = 0; i < RK_SDR2HDR_INVGAMMA_C_IDX_LENGTH; i++)
+ vop2_writel(vop2, RK3528_SDRINVGAMMA_CHANGEIDX + i * 4,
+ hdrvivid_data->sdrinvgamma_changeidx[i]);
+
+ for (i = 0; i < RK_SDR2HDR_SMGAIN_LENGTH; i++)
+ vop2_writel(vop2, RK3528_SDR_SMGAIN + i * 4, hdrvivid_data->sdr_smgain[i]);
+}
+
+static void vop3_setup_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phys_id)
+{
+ struct drm_crtc_state *cstate = vp->crtc.state;
+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(cstate);
+ struct hdr_extend *hdr_data;
+ uint32_t hdr_format;
+
+ /* If hdr extend data is null, exit hdr mode */
+ if (!vcstate->hdr_ext_data) {
+ vop3_disable_dynamic_hdr(vp, win_phys_id);
+ return;
+ }
+
+ hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data;
+ hdr_format = hdr_data->hdr_type;
+
+ switch (hdr_format) {
+ case HDR_NONE:
+ case HDR_HDR10:
+ case HDR_HLGSTATIC:
+ case HDR_HDRVIVID:
+ /*
+ * hdr module support hdr10, hlg, vividhdr
+ * sdr2hdr module support hdrnone for sdr2hdr
+ */
+ vop3_setup_hdrvivid(vp, win_phys_id);
+ break;
+ default:
+ DRM_DEBUG("unsupprot hdr format:%u\n", hdr_format);
+ break;
+ }
}
static void vop2_setup_hdr10(struct vop2_video_port *vp, uint8_t win_phys_id)
@@ -5648,7 +6106,7 @@
vop2_writel(vop2, dst_alpha_ctrl_offset + offset, alpha.dst_alpha_ctrl.val);
}
- if (vp_data->feature & VOP_FEATURE_HDR10) {
+ if (vp_data->feature & (VOP_FEATURE_HDR10 | VOP_FEATURE_VIVID_HDR)) {
src_color_ctrl_offset = ovl_regs->hdr_mix_regs->src_color_ctrl.offset;
dst_color_ctrl_offset = ovl_regs->hdr_mix_regs->dst_color_ctrl.offset;
src_alpha_ctrl_offset = ovl_regs->hdr_mix_regs->src_alpha_ctrl.offset;
@@ -5923,6 +6381,7 @@
struct vop2_cluster cluster;
uint8_t nr_layers = 0;
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+ const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id];
vcstate->yuv_overlay = is_yuv_output(vcstate->bus_format);
vop2_zpos = kmalloc_array(vop2->data->win_size, sizeof(*vop2_zpos), GFP_KERNEL);
@@ -5982,21 +6441,26 @@
sort(vop2_zpos, nr_layers, sizeof(vop2_zpos[0]), vop2_zpos_cmp, NULL);
- if (is_vop3(vop2))
+ if (is_vop3(vop2)) {
vop3_setup_layer_sel_for_vp(vp, vop2_zpos);
- else
- vop2_setup_layer_mixer_for_vp(vp, vop2_zpos);
- vop2_setup_hdr10(vp, vop2_zpos[0].win_phys_id);
- if (is_vop3(vop2))
+ if (vp_data->feature & VOP_FEATURE_VIVID_HDR)
+ vop3_setup_dynamic_hdr(vp, vop2_zpos[0].win_phys_id);
vop3_setup_alpha(vp, vop2_zpos);
- else
+ vop3_setup_pipe_dly(vp, vop2_zpos);
+ } else {
+ vop2_setup_layer_mixer_for_vp(vp, vop2_zpos);
+ vop2_setup_hdr10(vp, vop2_zpos[0].win_phys_id);
vop2_setup_alpha(vp, vop2_zpos);
- vop2_setup_dly_for_vp(vp);
- vop2_setup_dly_for_window(vp, vop2_zpos);
+ vop2_setup_dly_for_vp(vp);
+ vop2_setup_dly_for_window(vp, vop2_zpos);
+ }
} else {
- if (!is_vop3(vop2))
+ if (!is_vop3(vop2)) {
vop2_calc_bg_ovl_and_port_mux(vp);
- vop2_setup_dly_for_vp(vp);
+ vop2_setup_dly_for_vp(vp);
+ } else {
+ vop3_setup_pipe_dly(vp, NULL);
+ }
}
/* The pre alpha overlay of Cluster still need process in one win mode. */
@@ -6124,16 +6588,193 @@
vop2_bcsh_reg_update(vcstate, vp, &bcsh_state);
}
+static void vop3_post_csc_config(struct drm_crtc *crtc, struct post_acm *acm, struct post_csc *csc)
+{
+ 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;
+ struct post_csc_coef csc_coef;
+ bool acm_enable;
+ bool is_input_yuv = false;
+ bool is_output_yuv = false;
+ bool post_r2y_en = false;
+ bool post_csc_en = false;
+ int range_type;
+
+ if (!acm)
+ acm_enable = false;
+ else
+ acm_enable = acm->acm_enable;
+
+ if (acm_enable) {
+ if (!vcstate->yuv_overlay)
+ post_r2y_en = true;
+
+ /* do y2r in csc module */
+ if (!is_yuv_output(vcstate->bus_format))
+ post_csc_en = true;
+ } else {
+ if (!vcstate->yuv_overlay && is_yuv_output(vcstate->bus_format))
+ post_r2y_en = true;
+
+ /* do y2r in csc module */
+ if (vcstate->yuv_overlay && !is_yuv_output(vcstate->bus_format))
+ post_csc_en = true;
+ }
+
+ if (csc && csc->csc_enable)
+ post_csc_en = true;
+
+ if (vcstate->yuv_overlay || post_r2y_en)
+ is_input_yuv = true;
+
+ if (is_yuv_output(vcstate->bus_format))
+ is_output_yuv = true;
+
+ vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space, CSC_13BIT_DEPTH);
+
+ if (post_csc_en) {
+ rockchip_calc_post_csc(csc, &csc_coef, vcstate->post_csc_mode, is_input_yuv,
+ is_output_yuv);
+
+ VOP_MODULE_SET(vop2, vp, csc_coe00, csc_coef.csc_coef00);
+ VOP_MODULE_SET(vop2, vp, csc_coe01, csc_coef.csc_coef01);
+ VOP_MODULE_SET(vop2, vp, csc_coe02, csc_coef.csc_coef02);
+ VOP_MODULE_SET(vop2, vp, csc_coe10, csc_coef.csc_coef10);
+ VOP_MODULE_SET(vop2, vp, csc_coe11, csc_coef.csc_coef11);
+ VOP_MODULE_SET(vop2, vp, csc_coe12, csc_coef.csc_coef12);
+ VOP_MODULE_SET(vop2, vp, csc_coe20, csc_coef.csc_coef20);
+ VOP_MODULE_SET(vop2, vp, csc_coe21, csc_coef.csc_coef21);
+ VOP_MODULE_SET(vop2, vp, csc_coe22, csc_coef.csc_coef22);
+ VOP_MODULE_SET(vop2, vp, csc_offset0, csc_coef.csc_dc0);
+ VOP_MODULE_SET(vop2, vp, csc_offset1, csc_coef.csc_dc1);
+ VOP_MODULE_SET(vop2, vp, csc_offset2, csc_coef.csc_dc2);
+
+ range_type = csc_coef.range_type ? 0 : 1;
+ range_type <<= is_input_yuv ? 0 : 1;
+ VOP_MODULE_SET(vop2, vp, csc_mode, range_type);
+ }
+
+ VOP_MODULE_SET(vop2, vp, acm_r2y_en, post_r2y_en ? 1 : 0);
+ VOP_MODULE_SET(vop2, vp, csc_en, post_csc_en ? 1 : 0);
+ VOP_MODULE_SET(vop2, vp, acm_r2y_mode, vcstate->post_csc_mode);
+}
+
+static void vop3_post_acm_config(struct drm_crtc *crtc, struct post_acm *acm)
+{
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
+ struct vop2 *vop2 = vp->vop2;
+ struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
+ s16 *lut_y;
+ s16 *lut_h;
+ s16 *lut_s;
+ u32 value;
+ int i;
+
+ writel(0, vop2->acm_regs + RK3528_ACM_CTRL);
+ VOP_MODULE_SET(vop2, vp, acm_bypass_en, 0);
+
+ if (!acm || !acm->acm_enable)
+ return;
+
+ /*
+ * If acm update parameters, it need disable acm in the first frame,
+ * then update parameters and enable acm in second frame.
+ */
+ vop2_cfg_done(crtc);
+ readx_poll_timeout(readl, vop2->acm_regs + RK3528_ACM_CTRL, value, !value, 200, 50000);
+
+ value = RK3528_ACM_ENABLE + ((adjusted_mode->hdisplay & 0xfff) << 8) +
+ ((adjusted_mode->vdisplay & 0xfff) << 20);
+ writel(value, vop2->acm_regs + RK3528_ACM_CTRL);
+
+
+ writel(1, vop2->acm_regs + RK3528_ACM_FETCH_START);
+
+ value = (acm->y_gain & 0x3ff) + ((acm->h_gain << 10) & 0xffc00) +
+ ((acm->s_gain << 20) & 0x3ff00000);
+ writel(value, vop2->acm_regs + RK3528_ACM_DELTA_RANGE);
+
+ lut_y = &acm->gain_lut_hy[0];
+ lut_h = &acm->gain_lut_hy[ACM_GAIN_LUT_HY_LENGTH];
+ lut_s = &acm->gain_lut_hy[ACM_GAIN_LUT_HY_LENGTH * 2];
+ for (i = 0; i < ACM_GAIN_LUT_HY_LENGTH; i++) {
+ value = (lut_y[i] & 0xff) + ((lut_h[i] << 8) & 0xff00) +
+ ((lut_s[i] << 16) & 0xff0000);
+ writel(value, vop2->acm_regs + RK3528_ACM_YHS_DEL_HY_SEG0 + (i << 2));
+ }
+
+ lut_y = &acm->gain_lut_hs[0];
+ lut_h = &acm->gain_lut_hs[ACM_GAIN_LUT_HS_LENGTH];
+ lut_s = &acm->gain_lut_hs[ACM_GAIN_LUT_HS_LENGTH * 2];
+ for (i = 0; i < ACM_GAIN_LUT_HS_LENGTH; i++) {
+ value = (lut_y[i] & 0xff) + ((lut_h[i] << 8) & 0xff00) +
+ ((lut_s[i] << 16) & 0xff0000);
+ writel(value, vop2->acm_regs + RK3528_ACM_YHS_DEL_HS_SEG0 + (i << 2));
+ }
+
+ lut_y = &acm->delta_lut_h[0];
+ lut_h = &acm->delta_lut_h[ACM_DELTA_LUT_H_LENGTH];
+ lut_s = &acm->delta_lut_h[ACM_DELTA_LUT_H_LENGTH * 2];
+ for (i = 0; i < ACM_DELTA_LUT_H_LENGTH; i++) {
+ value = (lut_y[i] & 0x3ff) + ((lut_h[i] << 12) & 0xff000) +
+ ((lut_s[i] << 20) & 0x3ff00000);
+ writel(value, vop2->acm_regs + RK3528_ACM_YHS_DEL_HGAIN_SEG0 + (i << 2));
+ }
+
+ writel(1, vop2->acm_regs + RK3528_ACM_FETCH_DONE);
+}
+
+static void vop3_post_config(struct drm_crtc *crtc)
+{
+ struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
+ struct post_acm *acm;
+ struct post_csc *csc;
+
+ csc = vcstate->post_csc_data ? (struct post_csc *)vcstate->post_csc_data->data : NULL;
+ if (csc && memcmp(&vp->csc_info, csc, sizeof(struct post_csc)))
+ memcpy(&vp->csc_info, csc, sizeof(struct post_csc));
+ vop3_post_csc_config(crtc, &vp->acm_info, &vp->csc_info);
+
+ acm = vcstate->acm_lut_data ? (struct post_acm *)vcstate->acm_lut_data->data : NULL;
+
+ if (acm && memcmp(&vp->acm_info, acm, sizeof(struct post_acm))) {
+ memcpy(&vp->acm_info, acm, sizeof(struct post_acm));
+ vop3_post_acm_config(crtc, &vp->acm_info);
+ } else if (crtc->state->active_changed) {
+ vop3_post_acm_config(crtc, &vp->acm_info);
+ }
+}
+
static void vop2_cfg_update(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
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;
+ const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
uint32_t val;
uint32_t r, g, b;
+ uint8_t out_mode;
spin_lock(&vop2->reg_lock);
+
+ if ((vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
+ !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) ||
+ vcstate->output_if & VOP_OUTPUT_IF_BT656)
+ out_mode = ROCKCHIP_OUT_MODE_P888;
+ else
+ out_mode = vcstate->output_mode;
+ VOP_MODULE_SET(vop2, vp, out_mode, out_mode);
+
+ if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
+ VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RB_SWAP);
+ else
+ VOP_MODULE_SET(vop2, vp, dsp_data_swap, 0);
+
+ vop2_dither_setup(crtc);
VOP_MODULE_SET(vop2, vp, overlay_mode, vcstate->yuv_overlay);
@@ -6162,6 +6803,9 @@
vop2_post_config(crtc);
spin_unlock(&vop2->reg_lock);
+
+ if (vp_data->feature & (VOP_FEATURE_POST_ACM | VOP_FEATURE_POST_CSC))
+ vop3_post_config(crtc);
}
static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_cstate)
@@ -6304,6 +6948,13 @@
return NULL;
vcstate->vp_id = vp->id;
+ if (vcstate->hdr_ext_data)
+ drm_property_blob_get(vcstate->hdr_ext_data);
+ if (vcstate->acm_lut_data)
+ drm_property_blob_get(vcstate->acm_lut_data);
+ if (vcstate->post_csc_data)
+ drm_property_blob_get(vcstate->post_csc_data);
+
__drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base);
return &vcstate->base;
}
@@ -6314,6 +6965,9 @@
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state);
__drm_atomic_helper_crtc_destroy_state(&vcstate->base);
+ drm_property_blob_put(vcstate->hdr_ext_data);
+ drm_property_blob_put(vcstate->acm_lut_data);
+ drm_property_blob_put(vcstate->post_csc_data);
kfree(vcstate);
}
@@ -6436,9 +7090,52 @@
return 0;
}
+ if (property == vp->hdr_ext_data_prop)
+ return 0;
+
+ if (property == vp->acm_lut_data_prop)
+ return 0;
+
+ if (property == vp->post_csc_data_prop)
+ return 0;
+
DRM_ERROR("failed to get vop2 crtc property: %s\n", property->name);
return -EINVAL;
+}
+
+/* copied from drm_atomic.c */
+static int
+vop2_atomic_replace_property_blob_from_id(struct drm_device *dev,
+ struct drm_property_blob **blob,
+ uint64_t blob_id,
+ ssize_t expected_size,
+ ssize_t expected_elem_size,
+ bool *replaced)
+{
+ struct drm_property_blob *new_blob = NULL;
+
+ if (blob_id != 0) {
+ new_blob = drm_property_lookup_blob(dev, blob_id);
+ if (new_blob == NULL)
+ return -EINVAL;
+
+ if (expected_size > 0 &&
+ new_blob->length != expected_size) {
+ drm_property_blob_put(new_blob);
+ return -EINVAL;
+ }
+ if (expected_elem_size > 0 &&
+ new_blob->length % expected_elem_size != 0) {
+ drm_property_blob_put(new_blob);
+ return -EINVAL;
+ }
+ }
+
+ *replaced |= drm_property_replace_blob(blob, new_blob);
+ drm_property_blob_put(new_blob);
+
+ return 0;
}
static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc,
@@ -6451,6 +7148,8 @@
struct drm_mode_config *mode_config = &drm_dev->mode_config;
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2 *vop2 = vp->vop2;
+ bool replaced = false;
+ int ret;
if (property == mode_config->tv_left_margin_property) {
vcstate->left_margin = val;
@@ -6481,6 +7180,33 @@
if (property == vop2->line_flag_prop) {
vcstate->line_flag = val;
return 0;
+ }
+
+ if (property == vp->hdr_ext_data_prop) {
+ ret = vop2_atomic_replace_property_blob_from_id(drm_dev,
+ &vcstate->hdr_ext_data,
+ val,
+ -1, -1,
+ &replaced);
+ return ret;
+ }
+
+ if (property == vp->acm_lut_data_prop) {
+ ret = vop2_atomic_replace_property_blob_from_id(drm_dev,
+ &vcstate->acm_lut_data,
+ val,
+ sizeof(struct post_acm), -1,
+ &replaced);
+ return ret;
+ }
+
+ if (property == vp->post_csc_data_prop) {
+ ret = vop2_atomic_replace_property_blob_from_id(drm_dev,
+ &vcstate->post_csc_data,
+ val,
+ sizeof(struct post_csc), -1,
+ &replaced);
+ return ret;
}
DRM_ERROR("failed to set vop2 crtc property %s\n", property->name);
@@ -6694,6 +7420,16 @@
ret = IRQ_HANDLED;
}
+ if (vop2->version == VOP_VERSION_RK3528 && vp->id == 1) {
+ if (active_irqs & POST_BUF_EMPTY_INTR)
+ atomic_inc(&vp->post_buf_empty_flag);
+
+ if (active_irqs & FS_FIELD_INTR &&
+ (atomic_read(&vp->post_buf_empty_flag) > 0 ||
+ vp->need_reset_p2i_flag == true))
+ queue_work(vop2->workqueue, &vop2->post_buf_empty_work);
+ }
+
if (active_irqs & FS_FIELD_INTR) {
vop2_wb_handler(vp);
if (likely(!vp->skip_vsync) || (vp->layer_sel_update == false)) {
@@ -6784,6 +7520,51 @@
return 0;
}
+static bool vop3_ignore_plane(struct vop2 *vop2, struct vop2_win *win)
+{
+ if (!is_vop3(vop2))
+ return false;
+
+ if (vop2->esmart_lb_mode == VOP3_ESMART_8K_MODE &&
+ win->phys_id != ROCKCHIP_VOP2_ESMART0)
+ return true;
+ else if (vop2->esmart_lb_mode == VOP3_ESMART_4K_4K_MODE &&
+ (win->phys_id == ROCKCHIP_VOP2_ESMART1 || win->phys_id == ROCKCHIP_VOP2_ESMART3))
+ return true;
+ else if (vop2->esmart_lb_mode == VOP3_ESMART_4K_2K_2K_MODE &&
+ win->phys_id == ROCKCHIP_VOP2_ESMART1)
+ return true;
+ else
+ return false;
+}
+
+static u32 vop3_esmart_linebuffer_size(struct vop2 *vop2, struct vop2_win *win)
+{
+ if (!is_vop3(vop2) || vop2_cluster_window(win))
+ return vop2->data->max_output.width;
+
+ if (vop2->esmart_lb_mode == VOP3_ESMART_2K_2K_2K_2K_MODE ||
+ (vop2->esmart_lb_mode == VOP3_ESMART_4K_2K_2K_MODE && win->phys_id != ROCKCHIP_VOP2_ESMART0))
+ return vop2->data->max_output.width / 2;
+ else
+ return vop2->data->max_output.width;
+}
+
+static void vop3_init_esmart_scale_engine(struct vop2 *vop2)
+{
+ u8 scale_engine_num = 0;
+ struct drm_plane *plane = NULL;
+
+ drm_for_each_plane(plane, vop2->drm_dev) {
+ struct vop2_win *win = to_vop2_win(plane);
+
+ if (win->parent || vop2_cluster_window(win))
+ continue;
+
+ win->scale_engine_num = scale_engine_num++;
+ }
+}
+
static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned long possible_crtcs)
{
struct rockchip_drm_private *private = vop2->drm_dev->dev_private;
@@ -6807,6 +7588,10 @@
if (win->feature & WIN_FEATURE_CLUSTER_SUB)
return -EACCES;
}
+
+ /* ignore some plane register according vop3 esmart lb mode */
+ if (vop3_ignore_plane(vop2, win))
+ return -EACCES;
ret = drm_universal_plane_init(vop2->drm_dev, &win->base, possible_crtcs,
&vop2_plane_funcs, win->formats, win->nformats,
@@ -6847,7 +7632,7 @@
"INPUT_WIDTH", 0, max_width);
win->input_height_prop = drm_property_create_range(vop2->drm_dev, DRM_MODE_PROP_IMMUTABLE,
"INPUT_HEIGHT", 0, max_height);
- max_width = vop2->data->max_output.width;
+ max_width = vop3_esmart_linebuffer_size(vop2, win);
max_height = vop2->data->max_output.height;
if (win->feature & WIN_FEATURE_CLUSTER_SUB)
max_width >>= 1;
@@ -6883,15 +7668,27 @@
return 0;
}
-static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp,
- unsigned long possible_crtcs)
+static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp)
{
struct vop2 *vop2 = vp->vop2;
struct drm_plane *cursor = NULL;
struct vop2_win *win;
+ unsigned long possible_crtcs = 0;
win = vop2_find_win_by_phys_id(vop2, vp->cursor_win_id);
if (win) {
+ if (vop2->disable_win_move) {
+ const struct vop2_data *vop2_data = vop2->data;
+ struct drm_crtc *crtc = vop2_find_crtc_by_plane_mask(vop2, win->phys_id);
+
+ if (crtc)
+ possible_crtcs = drm_crtc_mask(crtc);
+ else
+ possible_crtcs = (1 << vop2_data->nr_vps) - 1;
+ }
+
+ if (win->possible_crtcs)
+ possible_crtcs = win->possible_crtcs;
win->type = DRM_PLANE_TYPE_CURSOR;
win->zpos = vop2->registered_num_wins - 1;
if (!vop2_plane_init(vop2, win, possible_crtcs))
@@ -6925,6 +7722,7 @@
if (!lut_len)
continue;
vp->gamma_lut_len = vp_data->gamma_lut_len;
+ vp->lut_dma_rid = vp_data->lut_dma_rid;
vp->lut = devm_kmalloc_array(dev, lut_len, sizeof(*vp->lut),
GFP_KERNEL);
if (!vp->lut)
@@ -7009,6 +7807,53 @@
return 0;
}
+static int vop2_crtc_create_hdr_property(struct vop2 *vop2, struct drm_crtc *crtc)
+{
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
+ struct drm_property *prop;
+
+ prop = drm_property_create(vop2->drm_dev, DRM_MODE_PROP_BLOB, "HDR_EXT_DATA", 0);
+ if (!prop) {
+ DRM_DEV_ERROR(vop2->dev, "create hdr ext data prop for vp%d failed\n", vp->id);
+ return -ENOMEM;
+ }
+ vp->hdr_ext_data_prop = prop;
+ drm_object_attach_property(&crtc->base, vp->hdr_ext_data_prop, 0);
+
+ return 0;
+}
+
+static int vop2_crtc_create_post_acm_property(struct vop2 *vop2, struct drm_crtc *crtc)
+{
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
+ struct drm_property *prop;
+
+ prop = drm_property_create(vop2->drm_dev, DRM_MODE_PROP_BLOB, "ACM_LUT_DATA", 0);
+ if (!prop) {
+ DRM_DEV_ERROR(vop2->dev, "create acm lut data prop for vp%d failed\n", vp->id);
+ return -ENOMEM;
+ }
+ vp->acm_lut_data_prop = prop;
+ drm_object_attach_property(&crtc->base, vp->acm_lut_data_prop, 0);
+
+ return 0;
+}
+
+static int vop2_crtc_create_post_csc_property(struct vop2 *vop2, struct drm_crtc *crtc)
+{
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
+ struct drm_property *prop;
+
+ prop = drm_property_create(vop2->drm_dev, DRM_MODE_PROP_BLOB, "POST_CSC_DATA", 0);
+ if (!prop) {
+ DRM_DEV_ERROR(vop2->dev, "create post csc data prop for vp%d failed\n", vp->id);
+ return -ENOMEM;
+ }
+ vp->post_csc_data_prop = prop;
+ drm_object_attach_property(&crtc->base, vp->post_csc_data_prop, 0);
+
+ return 0;
+}
#define RK3566_MIRROR_PLANE_MASK (BIT(ROCKCHIP_VOP2_CLUSTER1) | BIT(ROCKCHIP_VOP2_ESMART1) | \
BIT(ROCKCHIP_VOP2_SMART1))
@@ -7021,7 +7866,7 @@
const struct vop2_data *vop2_data = vop2->data;
struct drm_device *drm_dev = vop2->drm_dev;
struct device *dev = vop2->dev;
- struct drm_plane *plane;
+ struct drm_plane *primary;
struct drm_plane *cursor = NULL;
struct drm_crtc *crtc;
struct device_node *port;
@@ -7069,6 +7914,9 @@
vp->id = vp_data->id;
vp->regs = vp_data->regs;
vp->cursor_win_id = -1;
+ primary = NULL;
+ cursor = NULL;
+
if (vop2->disable_win_move)
possible_crtcs = BIT(registered_num_crtcs);
@@ -7116,6 +7964,7 @@
win->type = DRM_PLANE_TYPE_PRIMARY;
}
} else {
+ j = 0;
while (j < vop2->registered_num_wins) {
be_used_for_primary_plane = false;
win = &vop2->win[j];
@@ -7157,24 +8006,43 @@
DRM_DEV_ERROR(vop2->dev, "failed to init primary plane\n");
break;
}
- plane = &win->base;
+ primary = &win->base;
}
/* some times we want a cursor window for some vp */
+ if (vp->cursor_win_id < 0) {
+ bool be_used_for_cursor_plane = false;
+
+ j = 0;
+ while (j < vop2->registered_num_wins) {
+ win = &vop2->win[j++];
+
+ if (win->parent || (win->feature & WIN_FEATURE_CLUSTER_SUB))
+ continue;
+
+ if (win->type != DRM_PLANE_TYPE_CURSOR)
+ continue;
+
+ for (k = 0; k < vop2_data->nr_vps; k++) {
+ if (vop2->vps[k].cursor_win_id == win->phys_id)
+ be_used_for_cursor_plane = true;
+ }
+ if (be_used_for_cursor_plane)
+ continue;
+ vp->cursor_win_id = win->phys_id;
+ }
+ }
+
if (vp->cursor_win_id >= 0) {
- if (win->possible_crtcs)
- possible_crtcs = win->possible_crtcs;
- cursor = vop2_cursor_plane_init(vp, possible_crtcs);
+ cursor = vop2_cursor_plane_init(vp);
if (!cursor)
DRM_WARN("failed to init cursor plane for vp%d\n", vp->id);
else
DRM_DEV_INFO(vop2->dev, "%s as cursor plane for vp%d\n",
cursor->name, vp->id);
- } else {
- cursor = NULL;
}
- ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, cursor, &vop2_crtc_funcs,
+ ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &vop2_crtc_funcs,
"video_port%d", vp->id);
if (ret) {
DRM_DEV_ERROR(vop2->dev, "crtc init for video_port%d failed\n", i);
@@ -7202,7 +8070,23 @@
drm_dev->mode_config.tv_top_margin_property, 100);
drm_object_attach_property(&crtc->base,
drm_dev->mode_config.tv_bottom_margin_property, 100);
- vop2_crtc_create_plane_mask_property(vop2, crtc, plane_mask);
+ if (plane_mask)
+ vop2_crtc_create_plane_mask_property(vop2, crtc, plane_mask);
+
+ if (vp_data->feature & VOP_FEATURE_VIVID_HDR) {
+ vop2_crtc_create_hdr_property(vop2, crtc);
+ vp->hdr_lut_gem_obj = rockchip_gem_create_object(vop2->drm_dev,
+ RK_HDRVIVID_TONE_SCA_AXI_TAB_LENGTH * 4, true, 0);
+ if (IS_ERR(vp->hdr_lut_gem_obj)) {
+ DRM_ERROR("create hdr lut obj failed\n");
+ return -ENOMEM;
+ }
+ }
+ if (vp_data->feature & VOP_FEATURE_POST_ACM)
+ vop2_crtc_create_post_acm_property(vop2, crtc);
+ if (vp_data->feature & VOP_FEATURE_POST_CSC)
+ vop2_crtc_create_post_csc_property(vop2, crtc);
+
registered_num_crtcs++;
}
@@ -7260,12 +8144,18 @@
DRM_WARN("failed to init overlay plane %s, ret:%d\n", win->name, ret);
}
+ if (is_vop3(vop2))
+ vop3_init_esmart_scale_engine(vop2);
+
return registered_num_crtcs;
}
static void vop2_destroy_crtc(struct drm_crtc *crtc)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
+
+ if (vp->hdr_lut_gem_obj)
+ rockchip_gem_free_object(&vp->hdr_lut_gem_obj->base);
of_node_put(crtc->port);
@@ -7322,7 +8212,6 @@
win->axi_id = win_data->axi_id;
win->axi_yrgb_id = win_data->axi_yrgb_id;
win->axi_uv_id = win_data->axi_uv_id;
- win->scale_engine_num = win_data->scale_engine_num;
win->possible_crtcs = win_data->possible_crtcs;
num_wins++;
@@ -7351,6 +8240,7 @@
area->vsd_filter_mode = win_data->vsd_filter_mode;
area->hsd_pre_filter_mode = win_data->hsd_pre_filter_mode;
area->vsd_pre_filter_mode = win_data->vsd_pre_filter_mode;
+ area->possible_crtcs = win->possible_crtcs;
area->vop2 = vop2;
area->win_id = i;
@@ -7414,6 +8304,43 @@
return 0;
}
+static void post_buf_empty_work_event(struct work_struct *work)
+{
+ struct vop2 *vop2 = container_of(work, struct vop2, post_buf_empty_work);
+ struct rockchip_drm_private *private = vop2->drm_dev->dev_private;
+ struct vop2_video_port *vp = &vop2->vps[1];
+
+ /*
+ * For RK3528, VP1 only supports NTSC and PAL mode(both interlace). If
+ * POST_BUF_EMPTY_INTR comes, it is needed to reset the p2i_en bit, in
+ * order to update the line parity flag, which ensures the correct order
+ * of odd and even lines.
+ */
+ if (vop2->version == VOP_VERSION_RK3528) {
+ if (atomic_read(&vp->post_buf_empty_flag) > 0) {
+ atomic_set(&vp->post_buf_empty_flag, 0);
+
+ mutex_lock(&private->ovl_lock);
+ vop2_wait_for_fs_by_done_bit_status(vp);
+ VOP_MODULE_SET(vop2, vp, p2i_en, 0);
+ vop2_cfg_done(&vp->crtc);
+ vop2_wait_for_fs_by_done_bit_status(vp);
+ mutex_unlock(&private->ovl_lock);
+
+ vp->need_reset_p2i_flag = true;
+ } else if (vp->need_reset_p2i_flag == true) {
+ mutex_lock(&private->ovl_lock);
+ vop2_wait_for_fs_by_done_bit_status(vp);
+ VOP_MODULE_SET(vop2, vp, p2i_en, 1);
+ vop2_cfg_done(&vp->crtc);
+ vop2_wait_for_fs_by_done_bit_status(vp);
+ mutex_unlock(&private->ovl_lock);
+
+ vp->need_reset_p2i_flag = false;
+ }
+ }
+}
+
static int vop2_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -7454,6 +8381,23 @@
vop2->disable_afbc_win = of_property_read_bool(dev->of_node, "disable-afbc-win");
vop2->disable_win_move = of_property_read_bool(dev->of_node, "disable-win-move");
vop2->skip_ref_fb = of_property_read_bool(dev->of_node, "skip-ref-fb");
+
+ /*
+ * esmart lb mode default config at vop2_reg.c vop2_data.esmart_lb_mode,
+ * you can rewrite at dts vop node:
+ *
+ * VOP3_ESMART_8K_MODE = 0,
+ * VOP3_ESMART_4K_4K_MODE = 1,
+ * VOP3_ESMART_4K_2K_2K_MODE = 2,
+ * VOP3_ESMART_2K_2K_2K_2K_MODE = 3,
+ *
+ * &vop {
+ * esmart_lb_mode = /bits/ 8 <2>;
+ * };
+ */
+ ret = of_property_read_u8(dev->of_node, "esmart_lb_mode", &vop2->esmart_lb_mode);
+ if (ret < 0)
+ vop2->esmart_lb_mode = vop2->data->esmart_lb_mode;
ret = vop2_win_init(vop2);
if (ret)
@@ -7538,6 +8482,12 @@
spin_lock_init(&vop2->irq_lock);
mutex_init(&vop2->vop2_lock);
+ if (vop2->version == VOP_VERSION_RK3528) {
+ atomic_set(&vop2->vps[1].post_buf_empty_flag, 0);
+ vop2->workqueue = create_workqueue("post_buf_empty_wq");
+ INIT_WORK(&vop2->post_buf_empty_work, post_buf_empty_work_event);
+ }
+
ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
if (ret)
return ret;
--
Gitblit v1.6.2