drm/rockchip: vop3: sync with kernel 4.19

Signed-off-by: Sandy Huang <hjc@rock-chips.com>
Change-Id: I11c5491e51b0159ddfa8da778fe77cc9c617450b
This commit is contained in:
Sandy Huang
2022-12-22 11:38:25 +08:00
committed by Tao Huang
parent a7a63a477c
commit 9cb660cf9c
7 changed files with 629 additions and 353 deletions

View File

@@ -1125,7 +1125,47 @@ static int rockchip_drm_summary_show(struct seq_file *s, void *data)
return 0;
}
static int rockchip_drm_regs_dump(struct seq_file *s, void *data)
{
struct drm_info_node *node = s->private;
struct drm_minor *minor = node->minor;
struct drm_device *drm_dev = minor->dev;
struct rockchip_drm_private *priv = drm_dev->dev_private;
struct drm_crtc *crtc;
drm_for_each_crtc(crtc, drm_dev) {
int pipe = drm_crtc_index(crtc);
if (priv->crtc_funcs[pipe] &&
priv->crtc_funcs[pipe]->regs_dump)
priv->crtc_funcs[pipe]->regs_dump(crtc, s);
}
return 0;
}
static int rockchip_drm_active_regs_dump(struct seq_file *s, void *data)
{
struct drm_info_node *node = s->private;
struct drm_minor *minor = node->minor;
struct drm_device *drm_dev = minor->dev;
struct rockchip_drm_private *priv = drm_dev->dev_private;
struct drm_crtc *crtc;
drm_for_each_crtc(crtc, drm_dev) {
int pipe = drm_crtc_index(crtc);
if (priv->crtc_funcs[pipe] &&
priv->crtc_funcs[pipe]->active_regs_dump)
priv->crtc_funcs[pipe]->active_regs_dump(crtc, s);
}
return 0;
}
static struct drm_info_list rockchip_debugfs_files[] = {
{ "active_regs", rockchip_drm_active_regs_dump, 0, NULL },
{ "regs", rockchip_drm_regs_dump, 0, NULL },
{ "summary", rockchip_drm_summary_show, 0, NULL },
{ "mm_dump", rockchip_drm_mm_dump, 0, NULL },
};

View File

@@ -388,6 +388,7 @@ struct rockchip_crtc_funcs {
int (*debugfs_init)(struct drm_minor *minor, struct drm_crtc *crtc);
int (*debugfs_dump)(struct drm_crtc *crtc, struct seq_file *s);
void (*regs_dump)(struct drm_crtc *crtc, struct seq_file *s);
void (*active_regs_dump)(struct drm_crtc *crtc, struct seq_file *s);
enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
int output_type);

View File

@@ -1072,16 +1072,14 @@ void rockchip_drm_show_logo(struct drm_device *drm_dev)
private->loader_protect = true;
drm_modeset_unlock_all(drm_dev);
drm_for_each_crtc(crtc, drm_dev) {
struct drm_fb_helper *helper = private->fbdev_helper;
struct rockchip_crtc_state *s = NULL;
if (private->fbdev_helper && private->fbdev_helper->fb) {
drm_for_each_crtc(crtc, drm_dev) {
struct rockchip_crtc_state *s = NULL;
if (!helper)
break;
s = to_rockchip_crtc_state(crtc->state);
if (is_support_hotplug(s->output_type))
drm_framebuffer_get(helper->fb);
s = to_rockchip_crtc_state(crtc->state);
if (is_support_hotplug(s->output_type))
drm_framebuffer_get(private->fbdev_helper->fb);
}
}
return;

View File

@@ -123,10 +123,10 @@ enum vop2_win_dly_mode {
};
enum vop3_esmart_lb_mode {
VOP3_ESMART_ONE_8K_MODE,
VOP3_ESMART_TWO_4K_MODE,
VOP3_ESMART_ONE_4K_AND_TWO_2K_MODE,
VOP3_ESMART_FOUR_2K_MODE,
VOP3_ESMART_8K_MODE,
VOP3_ESMART_4K_4K_MODE,
VOP3_ESMART_4K_2K_2K_MODE,
VOP3_ESMART_2K_2K_2K_2K_MODE,
};
/*
@@ -559,7 +559,7 @@ struct hdr_extend {
};
enum _vop_hdrvivid_mode {
PQHDR2HDR_WITH_DYNAMIC,
PQHDR2HDR_WITH_DYNAMIC = 0,
PQHDR2SDR_WITH_DYNAMIC,
HLG2PQHDR_WITH_DYNAMIC,
HLG2SDR_WITH_DYNAMIC,
@@ -567,14 +567,16 @@ enum _vop_hdrvivid_mode {
HLG2SDR_WITHOUT_DYNAMIC,
HDR_BYPASS,
HDR102SDR,
SDR2PQ,
SDR2HDR10,
SDR2HLG,
SDR2HDR10_USERSPACE = 100,
SDR2HLG_USERSPACE = 101,
};
enum vop_hdr_format {
HDR_NONE = 0,
HDR_HDR10 = 1,
HDR_HGGSTATIC = 2,
HDR_HLGSTATIC = 2,
RESERVED3 = 3, /* reserved for more future static hdr format */
RESERVED4 = 4, /* reserved for more future static hdr format */
HDR_HDRVIVID = 5,
@@ -720,6 +722,7 @@ struct vop2_cluster_regs {
struct vop_reg enable;
struct vop_reg afbc_enable;
struct vop_reg lb_mode;
struct vop_reg scl_lb_mode;
struct vop_reg src_color_ctrl;
struct vop_reg dst_color_ctrl;
@@ -1039,7 +1042,6 @@ struct vop2_win_data {
uint8_t axi_id;
uint8_t axi_yrgb_id;
uint8_t axi_uv_id;
uint8_t scale_engine_num;
uint8_t possible_crtcs;
uint32_t base;
@@ -1211,6 +1213,7 @@ struct vop2_ctrl {
struct vop_reg version;
struct vop_reg standby;
struct vop_reg dma_stop;
struct vop_reg dsp_vs_t_sel;
struct vop_reg lut_dma_en;
struct vop_reg axi_outstanding_max_num;
struct vop_reg axi_max_outstanding_en;
@@ -1307,6 +1310,8 @@ struct vop2_ctrl {
struct vop_dump_regs {
uint32_t offset;
const char *name;
struct vop_reg state;
bool enable_state;
};
/**

View File

@@ -44,6 +44,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>
@@ -66,6 +68,8 @@
#define REG_SET_MASK(x, name, off, reg, mask, v, relaxed) \
_REG_SET(x, name, off, reg, reg.mask & mask, v, relaxed)
#define REG_GET(vop2, reg) ((vop2_readl(vop2, reg.offset) >> reg.shift) & reg.mask)
#define VOP_CLUSTER_SET(x, win, name, v) \
do { \
if (win->regs->cluster) \
@@ -87,6 +91,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)
@@ -563,6 +569,8 @@ struct vop2_video_port {
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;
@@ -736,10 +744,8 @@ struct vop2_video_port {
*/
struct drm_property *hdr_ext_data_prop;
bool hdr_ext_data_change;
int hdrvivid_mode;
/**
* @acm_lut_data_prop: acm lut data interaction with userspace
*/
@@ -822,6 +828,7 @@ struct vop2 {
*/
uint32_t registered_num_wins;
uint8_t used_mixers;
uint8_t esmart_lb_mode;
/**
* @active_vp_mask: Bitmask of active video ports;
*/
@@ -867,6 +874,8 @@ struct vop2 {
/* list_head of internal clk */
struct list_head clk_list_head;
struct list_head pd_list_head;
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 */
@@ -2414,7 +2423,7 @@ static int vop2_get_cluster_lb_mode(struct vop2_win *win, struct vop2_plane_stat
#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,
@@ -3238,7 +3247,7 @@ static void vop2_wb_commit(struct drm_crtc *crtc)
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
@@ -3610,25 +3619,15 @@ err:
*/
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;
}
}
@@ -3746,8 +3745,10 @@ static void vop2_initial(struct drm_crtc *crtc)
VOP_MODULE_SET(vop2, wb, axi_uv_id, 0xe);
vop2_wb_cfg_done(vp);
if (is_vop3(vop2))
if (is_vop3(vop2)) {
VOP_CTRL_SET(vop2, dsp_vs_t_sel, 0);
VOP_CTRL_SET(vop2, esmart_lb_mode, vop2->data->esmart_lb_mode);
}
/*
* This is unused and error init value for rk3528 vp1, if less of this config,
@@ -3762,6 +3763,9 @@ static void vop2_initial(struct drm_crtc *crtc)
* avoid display image shift when a window enabled.
*/
VOP_CTRL_SET(vop2, auto_gating_en, 0);
VOP_CTRL_SET(vop2, aclk_pre_auto_gating_en, 0);
/*
* Register OVERLAY_LAYER_SEL and OVERLAY_PORT_SEL should take effect immediately,
* than windows configuration(CLUSTER/ESMART/SMART) can take effect according the
@@ -4249,6 +4253,8 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
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);
/*
@@ -4980,7 +4986,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s
if (vop2->version != VOP_VERSION_RK3568)
rk3588_vop2_win_cfg_axi(win);
if (is_vop3(vop2) && !vop2_cluster_window(win))
if (!win->parent && !vop2_cluster_window(win) && is_vop3(vop2))
VOP_WIN_SET(vop2, win, scale_engine_num, win->scale_engine_num);
if (vpstate->afbc_en) {
@@ -5079,7 +5085,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s
}
VOP_WIN_SET(vop2, win, uv_vir, uv_stride);
VOP_WIN_SET(vop2, win, uv_mst, vpstate->uv_mst);
VOP_WIN_SET(vop2, win, uv_mst, uv_mst);
}
/* tile 4x4 m0 format, y and uv is packed together */
@@ -5108,6 +5114,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s
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);
}
spin_unlock(&vop2->reg_lock);
@@ -5916,6 +5923,7 @@ static void vop2_crtc_regs_dump(struct drm_crtc *crtc, struct seq_file *s)
{
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_crtc_state *cstate = crtc->state;
const struct vop_dump_regs *regs = vop2->data->dump_regs;
uint32_t buf[68];
@@ -5923,20 +5931,80 @@ static void vop2_crtc_regs_dump(struct drm_crtc *crtc, struct seq_file *s)
unsigned int n, i, j;
resource_size_t offset_addr;
uint32_t base;
struct drm_crtc *first_active_crtc = NULL;
if (!cstate->active)
return;
n = vop2->data->dump_regs_size;
/* only need to dump once at first active crtc for vop2 */
for (i = 0; i < vop2_data->nr_vps; i++) {
if (vop2->vps[i].rockchip_crtc.crtc.state->active) {
first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc;
break;
}
}
if (first_active_crtc != crtc)
return;
n = vop2->data->dump_regs_size;
for (i = 0; i < n; i++) {
base = regs[i].offset;
offset_addr = vop2->res->start + base;
pr_info("%s[%pa]:\n", regs[i].name, &offset_addr);
for (j = 0; j < len; j++)
buf[j] = vop2_readl(vop2, base + (4 * j));
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, buf,
len << 2, 0);
DEBUG_PRINT("\n%s:\n", regs[i].name);
for (j = 0; j < len;) {
DEBUG_PRINT("%08x: %08x %08x %08x %08x\n", (u32)offset_addr + j * 4,
vop2_readl(vop2, base + (4 * j)),
vop2_readl(vop2, base + (4 * (j + 1))),
vop2_readl(vop2, base + (4 * (j + 2))),
vop2_readl(vop2, base + (4 * (j + 3))));
j += 4;
}
}
}
static void vop2_crtc_active_regs_dump(struct drm_crtc *crtc, struct seq_file *s)
{
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_crtc_state *cstate = crtc->state;
const struct vop_dump_regs *regs = vop2->data->dump_regs;
uint32_t buf[68];
uint32_t len = ARRAY_SIZE(buf);
unsigned int n, i, j;
resource_size_t offset_addr;
uint32_t base;
struct drm_crtc *first_active_crtc = NULL;
if (!cstate->active)
return;
/* only need to dump once at first active crtc for vop2 */
for (i = 0; i < vop2_data->nr_vps; i++) {
if (vop2->vps[i].rockchip_crtc.crtc.state->active) {
first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc;
break;
}
}
if (first_active_crtc != crtc)
return;
n = vop2->data->dump_regs_size;
for (i = 0; i < n; i++) {
if (regs[i].state.mask &&
REG_GET(vop2, regs[i].state) != regs[i].enable_state)
continue;
base = regs[i].offset;
offset_addr = vop2->res->start + base;
DEBUG_PRINT("\n%s:\n", regs[i].name);
for (j = 0; j < len;) {
DEBUG_PRINT("%08x: %08x %08x %08x %08x\n", (u32)offset_addr + j * 4,
vop2_readl(vop2, base + (4 * j)),
vop2_readl(vop2, base + (4 * (j + 1))),
vop2_readl(vop2, base + (4 * (j + 2))),
vop2_readl(vop2, base + (4 * (j + 3))));
j += 4;
}
}
}
@@ -6284,6 +6352,7 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {
.debugfs_init = vop2_crtc_debugfs_init,
.debugfs_dump = vop2_crtc_debugfs_dump,
.regs_dump = vop2_crtc_regs_dump,
.active_regs_dump = vop2_crtc_active_regs_dump,
.bandwidth = vop2_crtc_bandwidth,
.crtc_close = vop2_crtc_close,
.te_handler = vop2_crtc_te_handler,
@@ -6375,6 +6444,8 @@ static void vop2_post_config(struct drm_crtc *crtc)
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;
@@ -6414,8 +6485,16 @@ static void vop2_post_config(struct drm_crtc *crtc)
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));
}
/*
@@ -7044,6 +7123,107 @@ static void vop2_post_color_swap(struct drm_crtc *crtc)
VOP_MODULE_SET(vop2, vp, dsp_data_swap, data_swap);
}
/*
* 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->rockchip_crtc.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);
@@ -7435,6 +7615,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state
if (vp_data->feature & VOP_FEATURE_OVERSCAN)
vop2_post_config(crtc);
/*
* 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);
if (vcstate->dsc_enable) {
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) {
@@ -7454,6 +7643,9 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state
*/
if (vop2->version == VOP_VERSION_RK3588)
VOP_MODULE_SET(vop2, vp, dsp_background, 0x80000000);
if (is_vop3(vop2))
vop3_setup_pipe_dly(vp, NULL);
vop2_cfg_done(crtc);
/*
@@ -7498,53 +7690,9 @@ static int vop2_zpos_cmp(const void *a, const void *b)
return pa->plane->base.id - pb->plane->base.id;
}
static bool vop3_hdr_ext_data_equal(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)
return old_blob == new_blob;
if (old_blob->length != new_blob->length)
return false;
return !memcmp(old_blob->data, new_blob->data, old_blob->length);
}
static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *crtc_state)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
struct vop2_video_port *splice_vp;
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 rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
struct rockchip_crtc_state *new_vcstate = to_rockchip_crtc_state(crtc_state);
struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
if (vop2_has_feature(vop2, VOP_FEATURE_SPLICE)) {
if (adjusted_mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) {
vcstate->splice_mode = true;
splice_vp = &vop2->vps[vp_data->splice_vp_id];
splice_vp->splice_mode_right = true;
splice_vp->left_vp = vp;
}
}
if ((vcstate->request_refresh_rate != new_vcstate->request_refresh_rate) ||
crtc_state->active_changed || crtc_state->mode_changed)
vp->refresh_rate_change = true;
else
vp->refresh_rate_change = false;
vp->hdr_ext_data_change = !vop3_hdr_ext_data_equal(crtc->state, crtc_state) |
crtc_state->active_changed;
return 0;
}
@@ -7559,8 +7707,10 @@ static void vop3_disable_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phy
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;
@@ -7601,13 +7751,19 @@ static void vop3_setup_hdrvivid(struct vop2_video_port *vp, uint8_t win_phys_id)
hdr_mode = hdrvivid_data->hdr_mode;
if (hdr_mode > SDR2HLG) {
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;
}
if (hdr_mode <= HDR102SDR && vpstate->eotf != HDMI_EOTF_SMPTE_ST2084 &&
vpstate->eotf != HDMI_EOTF_BT_2100_HLG) {
/* 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 != HDMI_EOTF_SMPTE_ST2084 && vpstate->eotf != HDMI_EOTF_BT_2100_HLG) {
DRM_ERROR("Invalid HDR mode:%d, mismatch plane eotf:%d\n", hdr_mode,
vpstate->eotf);
return;
@@ -7670,6 +7826,7 @@ static void vop3_setup_hdrvivid(struct vop2_video_port *vp, uint8_t win_phys_id)
}
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);
@@ -7738,15 +7895,18 @@ static void vop3_setup_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phys_
return;
}
/* If hdr ext data is not change, do nothing here */
if (!vp->hdr_ext_data_change)
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:
@@ -8689,107 +8849,6 @@ static void vop2_crtc_update_vrr(struct drm_crtc *crtc)
rockchip_connector_update_vfp_for_vrr(crtc, adjust_mode, new_vfp);
}
/*
* 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->rockchip_crtc.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_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state)
{
struct vop2_video_port *vp = to_vop2_video_port(crtc);
@@ -8919,7 +8978,8 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state
}
if (is_vop3(vop2)) {
vop3_setup_dynamic_hdr(vp, vop2_zpos[0].win_phys_id);
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);
vop3_setup_pipe_dly(vp, vop2_zpos);
} else {
@@ -9143,7 +9203,7 @@ static void vop3_post_csc_config(struct drm_crtc *crtc, struct post_acm *acm, st
if (is_yuv_output(vcstate->bus_format))
is_output_yuv = true;
vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space, CSC_10BIT_DEPTH);
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,
@@ -9165,23 +9225,6 @@ static void vop3_post_csc_config(struct drm_crtc *crtc, struct post_acm *acm, st
range_type = csc_coef.range_type ? 0 : 1;
range_type <<= is_input_yuv ? 0 : 1;
VOP_MODULE_SET(vop2, vp, csc_mode, range_type);
/* rgb input rgb output for csc need rg swap and bg swap */
if (!is_input_yuv && !is_output_yuv)
VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RG_SWAP | DSP_BG_SWAP);
/* rgb input yuv output for csc need rg swap */
if (!is_input_yuv && is_output_yuv)
VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RG_SWAP);
/* yuv input yuv output for csc need rg swap */
if (is_input_yuv && is_output_yuv)
VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RG_SWAP);
} else {
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);
}
VOP_MODULE_SET(vop2, vp, acm_r2y_en, post_r2y_en ? 1 : 0);
@@ -9989,6 +10032,16 @@ static irqreturn_t vop2_isr(int irq, void *data)
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) {
rockchip_drm_dbg(vop2->dev, VOP_DEBUG_VSYNC, "vsync_vp%d\n", vp->id);
vop2_wb_handler(vp);
@@ -10083,6 +10136,39 @@ static int vop2_plane_create_feature_property(struct vop2 *vop2, struct vop2_win
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 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;
@@ -10107,6 +10193,10 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned lon
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,
win->format_modifiers, win->type, win->name);
@@ -10182,15 +10272,27 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned lon
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))
@@ -10415,7 +10517,7 @@ static int vop2_create_crtc(struct vop2 *vop2)
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;
@@ -10464,6 +10566,9 @@ static int vop2_create_crtc(struct vop2 *vop2)
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);
@@ -10524,6 +10629,7 @@ static int vop2_create_crtc(struct vop2 *vop2)
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];
@@ -10565,24 +10671,43 @@ static int vop2_create_crtc(struct vop2 *vop2)
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);
@@ -10612,7 +10737,8 @@ static int vop2_create_crtc(struct vop2 *vop2)
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);
vop2_crtc_create_feature_property(vop2, crtc);
vop2_crtc_create_vrr_property(vop2, crtc);
@@ -10693,6 +10819,9 @@ static int vop2_create_crtc(struct vop2 *vop2)
DRM_WARN("failed to init overlay plane %s\n", win->name);
}
if (is_vop3(vop2))
vop3_init_esmart_scale_engine(vop2);
return registered_num_crtcs;
}
@@ -10812,7 +10941,6 @@ static int vop2_win_init(struct vop2 *vop2)
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;
if (win_data->pd_id)
@@ -10844,6 +10972,7 @@ static int vop2_win_init(struct vop2 *vop2)
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;
@@ -10888,6 +11017,42 @@ static int vop2_win_init(struct vop2 *vop2)
}
#include "rockchip_vop2_clk.c"
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->rockchip_crtc.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->rockchip_crtc.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)
{
@@ -10933,6 +11098,22 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
ret = vop2_pd_data_init(vop2);
if (ret)
return ret;
/*
* 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)
@@ -11045,6 +11226,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
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;

View File

@@ -670,7 +670,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = {
&rk_csc_table_rgb_to_xv_yccsdy_cb_cr_full,
&rk_dc_csc_table_rgb_to_xv_yccsdy_cb_cr_full,
{
OPTM_CS_E_XV_YCC_601, OPTM_CS_E_RGB, true, true
OPTM_CS_E_RGB, OPTM_CS_E_XV_YCC_601, true, true
}
},
{
@@ -782,7 +782,7 @@ static const struct rk_csc_mode_coef g_mode_csc_coef[] = {
&rk_csc_table_rgb_limit_to_hdy_cb_cr,
&rk_dc_csc_table_rgb_limit_to_hdy_cb_cr,
{
OPTM_CS_E_RGB, OPTM_CS_E_XV_YCC_601, false, false
OPTM_CS_E_RGB, OPTM_CS_E_ITU_R_BT_709, false, false
}
},
{
@@ -991,8 +991,8 @@ struct csc_mapping {
enum vop_csc_format csc_format;
enum color_space_type rgb_color_space;
enum color_space_type yuv_color_space;
bool yuv_full_range;
bool rgb_full_range;
bool yuv_full_range;
};
static const struct csc_mapping csc_mapping_table[] = {
@@ -1000,14 +1000,14 @@ static const struct csc_mapping csc_mapping_table[] = {
CSC_BT601L,
OPTM_CS_E_RGB,
OPTM_CS_E_XV_YCC_601,
false,
true,
false,
},
{
CSC_BT709L,
OPTM_CS_E_RGB,
OPTM_CS_E_XV_YCC_709,
false,
true,
false,
},
{
@@ -1028,7 +1028,7 @@ static const struct csc_mapping csc_mapping_table[] = {
CSC_BT709L_13BIT,
OPTM_CS_E_RGB,
OPTM_CS_E_XV_YCC_709,
false,
true,
false,
},
{
@@ -1042,7 +1042,7 @@ static const struct csc_mapping csc_mapping_table[] = {
CSC_BT2020L_13BIT,
OPTM_CS_E_RGB_2020,
OPTM_CS_E_XV_YCC_2020,
false,
true,
false,
},
{
@@ -1054,6 +1054,30 @@ static const struct csc_mapping csc_mapping_table[] = {
},
};
static const struct rk_pq_csc_coef r2y_for_y2y = {
306, 601, 117,
-151, -296, 446,
630, -527, -102,
};
static const struct rk_pq_csc_coef y2r_for_y2y = {
1024, -0, 1167,
1024, -404, -594,
1024, 2081, -1,
};
static const struct rk_pq_csc_coef rgb_input_swap_matrix = {
0, 0, 1,
1, 0, 0,
0, 1, 0,
};
static const struct rk_pq_csc_coef yuv_output_swap_matrix = {
0, 0, 1,
1, 0, 0,
0, 1, 0,
};
static int csc_get_mode_index(int post_csc_mode, bool is_input_yuv, bool is_output_yuv)
{
const struct rk_csc_colorspace_info *colorspace_info;
@@ -1244,35 +1268,17 @@ static struct rk_pq_csc_coef create_saturation_matrix(s32 saturation)
return m;
}
static const struct rk_pq_csc_coef r2y_for_y2y = {
306, 601, 117,
-151, -296, 446,
630, -527, -102,
};
static const struct rk_pq_csc_coef y2r_for_y2y = {
1024, -0, 1167,
1024, -404, -594,
1024, 2081, -1,
};
static const struct rk_pq_csc_coef rgb_swap_matrix = {
0, 0, 1,
1, 0, 0,
0, 1, 0,
};
static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv,
struct post_csc *csc_input_cfg,
const struct rk_csc_mode_coef *csc_mode_cfg,
struct post_csc_coef *csc_output)
struct rk_pq_csc_coef *out_matrix,
struct rk_pq_csc_ventor *out_dc)
{
struct rk_pq_csc_coef gain_matrix;
struct rk_pq_csc_coef contrast_matrix;
struct rk_pq_csc_coef hue_matrix;
struct rk_pq_csc_coef saturation_matrix;
struct rk_pq_csc_coef temp0, temp1;
struct rk_pq_csc_coef output;
const struct rk_pq_csc_coef *r2y_matrix;
const struct rk_pq_csc_coef *y2r_matrix;
struct rk_pq_csc_ventor dc_in_ventor;
@@ -1336,8 +1342,8 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv,
csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH);
csc_matrix_multiply(&temp0, &temp1, &contrast_matrix);
csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH);
csc_matrix_multiply(&output, &temp0, y2r_matrix);
csc_matrix_element_left_shift(&output, PQ_CSC_PARAM_FIX_BIT_WIDTH +
csc_matrix_multiply(out_matrix, &temp0, y2r_matrix);
csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH +
PQ_CALC_ENHANCE_BIT);
dc_in_ventor.csc_offset0 = dc_in_offset;
@@ -1359,8 +1365,8 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv,
csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH);
csc_matrix_multiply(&temp0, &contrast_matrix, &temp1);
csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH);
csc_matrix_multiply(&output, &gain_matrix, &temp0);
csc_matrix_element_left_shift(&output, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH +
csc_matrix_multiply(out_matrix, &gain_matrix, &temp0);
csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH +
PQ_CALC_ENHANCE_BIT);
dc_in_ventor.csc_offset0 = dc_in_offset;
@@ -1382,14 +1388,9 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv,
csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH);
csc_matrix_multiply(&temp0, &saturation_matrix, &temp1);
csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH);
csc_matrix_multiply(&temp1, &hue_matrix, &temp0);
csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_FIX_BIT_WIDTH +
csc_matrix_multiply(out_matrix, &hue_matrix, &temp0);
csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH +
PQ_CALC_ENHANCE_BIT);
/*
* In rgb2yuv case, the rgb channel need swap, but vop post rgb swap
* function can't config the correct swap, do this work in csc.
*/
csc_matrix_multiply(&output, &temp1, &rgb_swap_matrix);
dc_in_ventor.csc_offset0 = dc_in_offset;
dc_in_ventor.csc_offset1 = dc_in_offset;
@@ -1426,12 +1427,12 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv,
csc_matrix_element_left_shift(&temp0, PQ_CSC_PARAM_FIX_BIT_WIDTH);
csc_matrix_multiply(&temp1, &temp0, &saturation_matrix);
csc_matrix_element_left_shift(&temp1, PQ_CSC_PARAM_HALF_FIX_BIT_WIDTH);
csc_matrix_multiply(&output, &temp1, r2y_matrix);
csc_matrix_element_left_shift(&output, PQ_CSC_PARAM_FIX_BIT_WIDTH +
csc_matrix_multiply(out_matrix, &temp1, r2y_matrix);
csc_matrix_element_left_shift(out_matrix, PQ_CSC_PARAM_FIX_BIT_WIDTH +
PQ_CALC_ENHANCE_BIT);
if (color_info->in_full_range && color_info->out_full_range)
output.csc_coef00 += 1;
out_matrix->csc_coef00 += 1;
dc_in_ventor.csc_offset0 = dc_in_offset;
dc_in_ventor.csc_offset1 = dc_in_offset;
@@ -1441,29 +1442,20 @@ static int csc_calc_adjust_output_coef(bool is_input_yuv, bool is_output_yuv,
dc_out_ventor.csc_offset2 = brightness + dc_out_offset + b_offset;
}
csc_output->csc_coef00 = output.csc_coef00;
csc_output->csc_coef01 = output.csc_coef01;
csc_output->csc_coef02 = output.csc_coef02;
csc_output->csc_coef10 = output.csc_coef10;
csc_output->csc_coef11 = output.csc_coef11;
csc_output->csc_coef12 = output.csc_coef12;
csc_output->csc_coef20 = output.csc_coef20;
csc_output->csc_coef21 = output.csc_coef21;
csc_output->csc_coef22 = output.csc_coef22;
csc_matrix_ventor_multiply(&v, &output, &dc_in_ventor);
csc_output->csc_dc0 = v.csc_offset0 + dc_out_ventor.csc_offset0 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
csc_output->csc_dc1 = v.csc_offset1 + dc_out_ventor.csc_offset1 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
csc_output->csc_dc2 = v.csc_offset2 + dc_out_ventor.csc_offset2 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
csc_matrix_ventor_multiply(&v, out_matrix, &dc_in_ventor);
out_dc->csc_offset0 = v.csc_offset0 + dc_out_ventor.csc_offset0 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
out_dc->csc_offset1 = v.csc_offset1 + dc_out_ventor.csc_offset1 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
out_dc->csc_offset2 = v.csc_offset2 + dc_out_ventor.csc_offset2 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
return 0;
}
static int csc_calc_default_output_coef(const struct rk_csc_mode_coef *csc_mode_cfg,
struct post_csc_coef *csc_output)
struct rk_pq_csc_coef *out_matrix,
struct rk_pq_csc_ventor *out_dc)
{
const struct rk_pq_csc_coef *csc_coef;
const struct rk_pq_csc_dc_coef *csc_dc_coef;
@@ -1474,15 +1466,15 @@ static int csc_calc_default_output_coef(const struct rk_csc_mode_coef *csc_mode_
csc_coef = csc_mode_cfg->pst_csc_coef;
csc_dc_coef = csc_mode_cfg->pst_csc_dc_coef;
csc_output->csc_coef00 = csc_coef->csc_coef00;
csc_output->csc_coef01 = csc_coef->csc_coef01;
csc_output->csc_coef02 = csc_coef->csc_coef02;
csc_output->csc_coef10 = csc_coef->csc_coef10;
csc_output->csc_coef11 = csc_coef->csc_coef11;
csc_output->csc_coef12 = csc_coef->csc_coef12;
csc_output->csc_coef20 = csc_coef->csc_coef20;
csc_output->csc_coef21 = csc_coef->csc_coef21;
csc_output->csc_coef22 = csc_coef->csc_coef22;
out_matrix->csc_coef00 = csc_coef->csc_coef00;
out_matrix->csc_coef01 = csc_coef->csc_coef01;
out_matrix->csc_coef02 = csc_coef->csc_coef02;
out_matrix->csc_coef10 = csc_coef->csc_coef10;
out_matrix->csc_coef11 = csc_coef->csc_coef11;
out_matrix->csc_coef12 = csc_coef->csc_coef12;
out_matrix->csc_coef20 = csc_coef->csc_coef20;
out_matrix->csc_coef21 = csc_coef->csc_coef21;
out_matrix->csc_coef22 = csc_coef->csc_coef22;
dc_in_ventor.csc_offset0 = csc_dc_coef->csc_in_dc0;
dc_in_ventor.csc_offset1 = csc_dc_coef->csc_in_dc1;
@@ -1492,11 +1484,11 @@ static int csc_calc_default_output_coef(const struct rk_csc_mode_coef *csc_mode_
dc_out_ventor.csc_offset2 = csc_dc_coef->csc_out_dc2;
csc_matrix_ventor_multiply(&v, csc_coef, &dc_in_ventor);
csc_output->csc_dc0 = v.csc_offset0 + dc_out_ventor.csc_offset0 *
out_dc->csc_offset0 = v.csc_offset0 + dc_out_ventor.csc_offset0 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
csc_output->csc_dc1 = v.csc_offset1 + dc_out_ventor.csc_offset1 *
out_dc->csc_offset1 = v.csc_offset1 + dc_out_ventor.csc_offset1 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
csc_output->csc_dc2 = v.csc_offset2 + dc_out_ventor.csc_offset2 *
out_dc->csc_offset2 = v.csc_offset2 + dc_out_ventor.csc_offset2 *
PQ_CSC_SIMPLE_MAT_PARAM_FIX_NUM;
return 0;
@@ -1513,10 +1505,46 @@ static inline s32 pq_csc_simple_round(s32 x, s32 n)
return (((x) >= 0) ? value : -value);
}
static void rockchip_swap_color_channel(bool is_input_yuv, bool is_output_yuv,
struct post_csc_coef *csc_simple_coef,
struct rk_pq_csc_coef *out_matrix,
struct rk_pq_csc_ventor *out_dc)
{
struct rk_pq_csc_coef tmp_matrix;
struct rk_pq_csc_ventor tmp_v;
if (!is_input_yuv) {
memcpy(&tmp_matrix, out_matrix, sizeof(struct rk_pq_csc_coef));
csc_matrix_multiply(out_matrix, &tmp_matrix, &rgb_input_swap_matrix);
}
if (is_output_yuv) {
memcpy(&tmp_matrix, out_matrix, sizeof(struct rk_pq_csc_coef));
memcpy(&tmp_v, out_dc, sizeof(struct rk_pq_csc_ventor));
csc_matrix_multiply(out_matrix, &yuv_output_swap_matrix, &tmp_matrix);
csc_matrix_ventor_multiply(out_dc, &yuv_output_swap_matrix, &tmp_v);
}
csc_simple_coef->csc_coef00 = out_matrix->csc_coef00;
csc_simple_coef->csc_coef01 = out_matrix->csc_coef01;
csc_simple_coef->csc_coef02 = out_matrix->csc_coef02;
csc_simple_coef->csc_coef10 = out_matrix->csc_coef10;
csc_simple_coef->csc_coef11 = out_matrix->csc_coef11;
csc_simple_coef->csc_coef12 = out_matrix->csc_coef12;
csc_simple_coef->csc_coef20 = out_matrix->csc_coef20;
csc_simple_coef->csc_coef21 = out_matrix->csc_coef21;
csc_simple_coef->csc_coef22 = out_matrix->csc_coef22;
csc_simple_coef->csc_dc0 = out_dc->csc_offset0;
csc_simple_coef->csc_dc1 = out_dc->csc_offset1;
csc_simple_coef->csc_dc2 = out_dc->csc_offset2;
}
int rockchip_calc_post_csc(struct post_csc *csc_cfg, struct post_csc_coef *csc_simple_coef,
int csc_mode, bool is_input_yuv, bool is_output_yuv)
{
int ret = 0;
struct rk_pq_csc_coef out_matrix;
struct rk_pq_csc_ventor out_dc;
const struct rk_csc_mode_coef *csc_mode_cfg;
int bit_num = PQ_CSC_SIMPLE_MAT_PARAM_FIX_BIT_WIDTH;
@@ -1530,9 +1558,12 @@ int rockchip_calc_post_csc(struct post_csc *csc_cfg, struct post_csc_coef *csc_s
if (csc_cfg)
ret = csc_calc_adjust_output_coef(is_input_yuv, is_output_yuv, csc_cfg,
csc_mode_cfg, csc_simple_coef);
csc_mode_cfg, &out_matrix, &out_dc);
else
ret = csc_calc_default_output_coef(csc_mode_cfg, csc_simple_coef);
ret = csc_calc_default_output_coef(csc_mode_cfg, &out_matrix, &out_dc);
rockchip_swap_color_channel(is_input_yuv, is_output_yuv, csc_simple_coef, &out_matrix,
&out_dc);
csc_simple_coef->csc_dc0 = pq_csc_simple_round(csc_simple_coef->csc_dc0, bit_num);
csc_simple_coef->csc_dc1 = pq_csc_simple_round(csc_simple_coef->csc_dc1, bit_num);

View File

@@ -776,7 +776,9 @@ static const struct vop2_video_port_regs rk3528_vop_vp0_regs = {
.overlay_mode = VOP_REG(RK3528_OVL_PORT0_CTRL, 0x1, 0),
.dsp_background = VOP_REG(RK3568_VP0_DSP_BG, 0xffffffff, 0),
.out_mode = VOP_REG(RK3568_VP0_DSP_CTRL, 0xf, 0),
.core_dclk_div = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 4),
.dclk_div2 = VOP_REG(RK3568_VP0_CLK_CTRL, 0x1, 4),
.dclk_div2_phase_lock = VOP_REG(RK3568_VP0_DUAL_CHANNEL_CTRL, 0x1, 4),
.p2i_en = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 5),
.dsp_filed_pol = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 6),
.dsp_interlace = VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 7),
@@ -818,6 +820,7 @@ static const struct vop2_video_port_regs rk3528_vop_vp0_regs = {
.hdr10_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 4),
.sdr2hdr_path_en = VOP_REG(RK3568_OVL_CTRL, 0x1, 5),
.sdr2hdr_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 0),
.sdr2hdr_auto_gating_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 1),
.sdr2hdr_bypass_en = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 2),
.sdr2hdr_dstmode = VOP_REG(RK3568_SDR2HDR_CTRL, 0x1, 3),
.hdr_vivid_en = VOP_REG(RK3528_HDRVIVID_CTRL, 0x1, 0),
@@ -928,7 +931,7 @@ static const struct vop2_video_port_data rk3528_vop_video_ports[] = {
.soc_id = { 0x3528, 0x3528 },
.lut_dma_rid = 14,
.feature = VOP_FEATURE_ALPHA_SCALE | VOP_FEATURE_OVERSCAN | VOP_FEATURE_VIVID_HDR |
VOP_FEATURE_POST_ACM | VOP_FEATURE_POST_CSC,
VOP_FEATURE_POST_ACM | VOP_FEATURE_POST_CSC | VOP_FEATURE_OUTPUT_10BIT,
.gamma_lut_len = 1024,
.max_output = { 4096, 4096 },
.hdrvivid_dly = {17, 29, 32, 44, 15, 38, 1, 29, 0, 0},
@@ -1738,6 +1741,7 @@ static const struct vop2_cluster_regs rk3528_vop_cluster0 = {
.afbc_enable = VOP_REG(RK3568_CLUSTER0_CTRL, 0x1, 1),
.enable = VOP_REG(RK3568_CLUSTER0_CTRL, 1, 0),
.lb_mode = VOP_REG(RK3568_CLUSTER0_CTRL, 0xf, 4),
.scl_lb_mode = VOP_REG(RK3568_CLUSTER0_CTRL, 0x3, 9),
.src_color_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_SRC_COLOR_CTRL, 0xffffffff, 0),
.dst_color_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_DST_COLOR_CTRL, 0xffffffff, 0),
.src_alpha_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0),
@@ -1810,6 +1814,9 @@ static const struct vop2_scl_regs rk3528_cluster0_win_scl = {
.yrgb_ver_scl_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 14),
.yrgb_hor_scl_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 22),
.yrgb_hscl_filter_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 12),/* supported from vop3 */
.yrgb_vscl_filter_mode = VOP_REG(RK3528_CLUSTER0_WIN0_CTRL1, 0x3, 20),/* supported from vop3 */
.vsd_yrgb_gt2 = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL1, 0x1, 28),
.vsd_yrgb_gt4 = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL1, 0x1, 29),
.vsd_cbcr_gt2 = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL1, 0x1, 30),
@@ -1963,6 +1970,9 @@ static const struct vop2_scl_regs rk3568_area1_scl = {
.vsd_yrgb_gt4 = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 9),
.vsd_cbcr_gt2 = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 10),
.vsd_cbcr_gt4 = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 11),
.xavg_en = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 20),/* supported from vop3 */
.xgt_en = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x1, 21),
.xgt_mode = VOP_REG(RK3568_ESMART0_REGION1_CTRL, 0x3, 22),
};
static const struct vop2_scl_regs rk3568_area2_scl = {
@@ -1983,6 +1993,9 @@ static const struct vop2_scl_regs rk3568_area2_scl = {
.vsd_yrgb_gt4 = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 9),
.vsd_cbcr_gt2 = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 10),
.vsd_cbcr_gt4 = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 11),
.xavg_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 20),/* supported from vop3 */
.xgt_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 21),
.xgt_mode = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x3, 22),
};
static const struct vop2_scl_regs rk3568_area3_scl = {
@@ -2003,6 +2016,9 @@ static const struct vop2_scl_regs rk3568_area3_scl = {
.vsd_yrgb_gt4 = VOP_REG(RK3568_ESMART0_REGION3_CTRL, 0x1, 9),
.vsd_cbcr_gt2 = VOP_REG(RK3568_ESMART0_REGION3_CTRL, 0x1, 10),
.vsd_cbcr_gt4 = VOP_REG(RK3568_ESMART0_REGION3_CTRL, 0x1, 11),
.xavg_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 20),/* supported from vop3 */
.xgt_en = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x1, 21),
.xgt_mode = VOP_REG(RK3568_ESMART0_REGION2_CTRL, 0x3, 22),
};
static const struct vop2_win_regs rk3568_area1_data = {
@@ -2244,7 +2260,6 @@ static const struct vop2_win_data rk3528_vop_win_data[] = {
.axi_id = 0,
.axi_yrgb_id = 0x06,
.axi_uv_id = 0x07,
.scale_engine_num = 0,
.possible_crtcs = 0x1,/* vp0 only */
.max_upscale_factor = 8,
.max_downscale_factor = 8,
@@ -2274,7 +2289,6 @@ static const struct vop2_win_data rk3528_vop_win_data[] = {
.axi_id = 0,
.axi_yrgb_id = 0x08,
.axi_uv_id = 0x09,
.scale_engine_num = 1,
.possible_crtcs = 0x1,/* vp0 only */
.max_upscale_factor = 8,
.max_downscale_factor = 8,
@@ -2300,11 +2314,10 @@ static const struct vop2_win_data rk3528_vop_win_data[] = {
.regs = &rk3568_esmart_win_data,
.area = rk3568_area_data,
.area_size = ARRAY_SIZE(rk3568_area_data),
.type = DRM_PLANE_TYPE_OVERLAY,
.type = DRM_PLANE_TYPE_CURSOR,
.axi_id = 0,
.axi_yrgb_id = 0x0a,
.axi_uv_id = 0x0b,
.scale_engine_num = 2,
.possible_crtcs = 0x3,/* vp0 or vp1 */
.max_upscale_factor = 8,
.max_downscale_factor = 8,
@@ -2334,7 +2347,6 @@ static const struct vop2_win_data rk3528_vop_win_data[] = {
.axi_id = 0,
.axi_yrgb_id = 0x0c,
.axi_uv_id = 0x0d,
.scale_engine_num = 3,
.possible_crtcs = 0x2,/* vp1 only */
.max_upscale_factor = 8,
.max_downscale_factor = 8,
@@ -3136,6 +3148,7 @@ static const struct vop2_ctrl rk3528_vop_ctrl = {
.if_ctrl_cfg_done_imd = VOP_REG(RK3568_DSP_IF_POL, 0x1, 28),
.version = VOP_REG(RK3568_VERSION_INFO, 0xffff, 16),
.lut_dma_en = VOP_REG(RK3568_SYS_AXI_LUT_CTRL, 0x1, 0),
.dsp_vs_t_sel = VOP_REG(RK3568_SYS_AXI_LUT_CTRL, 0x1, 16),
.rgb_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 0),
.hdmi0_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 1),
.bt656_en = VOP_REG(RK3568_DSP_IF_EN, 0x1, 7),
@@ -3324,50 +3337,51 @@ static const struct vop2_ctrl rk3588_vop_ctrl = {
};
static const struct vop_dump_regs rk3528_dump_regs[] = {
{ RK3568_REG_CFG_DONE, "SYS" },
{ RK3528_OVL_SYS, "OVL_SYS" },
{ RK3528_OVL_PORT0_CTRL, "OVL_VP0" },
{ RK3528_OVL_PORT1_CTRL, "OVL_VP1" },
{ RK3568_VP0_DSP_CTRL, "VP0" },
{ RK3568_VP1_DSP_CTRL, "VP1" },
{ RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0" },
{ RK3568_ESMART0_CTRL0, "Esmart0" },
{ RK3568_ESMART1_CTRL0, "Esmart1" },
{ RK3568_SMART0_CTRL0, "Esmart2" },
{ RK3568_SMART1_CTRL0, "Esmart3" },
{ RK3568_REG_CFG_DONE, "SYS", {0}, 0 },
{ RK3528_OVL_SYS, "OVL_SYS", {0}, 0 },
{ RK3528_OVL_PORT0_CTRL, "OVL_VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 },
{ RK3528_OVL_PORT1_CTRL, "OVL_VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_VP0_DSP_CTRL, "VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_VP1_DSP_CTRL, "VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0", VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 0), 1 },
{ RK3568_ESMART0_CTRL0, "Esmart0", VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_ESMART1_CTRL0, "Esmart1", VOP_REG(RK3568_ESMART1_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_SMART0_CTRL0, "Esmart2", VOP_REG(RK3568_SMART0_CTRL0, 0x1, 0), 1 },
{ RK3568_SMART1_CTRL0, "Esmart3", VOP_REG(RK3568_SMART1_CTRL0, 0x1, 0), 1 },
{ RK3528_HDR_LUT_CTRL, "HDR", {0}, 0 },
};
static const struct vop_dump_regs rk3568_dump_regs[] = {
{ RK3568_REG_CFG_DONE, "SYS" },
{ RK3568_OVL_CTRL, "OVL" },
{ RK3568_VP0_DSP_CTRL, "VP0" },
{ RK3568_VP1_DSP_CTRL, "VP1" },
{ RK3568_VP2_DSP_CTRL, "VP2" },
{ RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0" },
{ RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1" },
{ RK3568_ESMART0_CTRL0, "Esmart0" },
{ RK3568_ESMART1_CTRL0, "Esmart1" },
{ RK3568_SMART0_CTRL0, "Smart0" },
{ RK3568_SMART1_CTRL0, "Smart1" },
{ RK3568_HDR_LUT_CTRL, "HDR" },
{ RK3568_REG_CFG_DONE, "SYS", {0}, 0 },
{ RK3568_OVL_CTRL, "OVL", {0}, 0 },
{ RK3568_VP0_DSP_CTRL, "VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_VP1_DSP_CTRL, "VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_VP2_DSP_CTRL, "VP2", VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0", VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 0), 1 },
{ RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1", VOP_REG(RK3568_CLUSTER1_WIN0_CTRL0, 0x1, 0), 1 },
{ RK3568_ESMART0_CTRL0, "Esmart0", VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_ESMART1_CTRL0, "Esmart1", VOP_REG(RK3568_ESMART1_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_SMART0_CTRL0, "Smart0", VOP_REG(RK3568_SMART0_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_SMART1_CTRL0, "Smart1", VOP_REG(RK3568_SMART1_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_HDR_LUT_CTRL, "HDR", {0}, 0 },
};
static const struct vop_dump_regs rk3588_dump_regs[] = {
{ RK3568_REG_CFG_DONE, "SYS" },
{ RK3568_OVL_CTRL, "OVL" },
{ RK3568_VP0_DSP_CTRL, "VP0" },
{ RK3568_VP1_DSP_CTRL, "VP1" },
{ RK3568_VP2_DSP_CTRL, "VP2" },
{ RK3588_VP3_DSP_CTRL, "VP3" },
{ RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0" },
{ RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1" },
{ RK3588_CLUSTER2_WIN0_CTRL0, "Cluster2" },
{ RK3588_CLUSTER3_WIN0_CTRL0, "Cluster3" },
{ RK3568_ESMART0_CTRL0, "Esmart0" },
{ RK3568_ESMART1_CTRL0, "Esmart1" },
{ RK3568_SMART0_CTRL0, "Esmart2" },
{ RK3568_SMART1_CTRL0, "Esmart3" },
{ RK3568_HDR_LUT_CTRL, "HDR" },
{ RK3568_REG_CFG_DONE, "SYS", {0}, 0 },
{ RK3568_OVL_CTRL, "OVL", {0}, 0 },
{ RK3568_VP0_DSP_CTRL, "VP0", VOP_REG(RK3568_VP0_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_VP1_DSP_CTRL, "VP1", VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_VP2_DSP_CTRL, "VP2", VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 31), 0 },
{ RK3588_VP3_DSP_CTRL, "VP3", VOP_REG(RK3588_VP3_DSP_CTRL, 0x1, 31), 0 },
{ RK3568_CLUSTER0_WIN0_CTRL0, "Cluster0", VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 0), 1 },
{ RK3568_CLUSTER1_WIN0_CTRL0, "Cluster1", VOP_REG(RK3568_CLUSTER1_WIN0_CTRL0, 0x1, 0), 1 },
{ RK3588_CLUSTER2_WIN0_CTRL0, "Cluster2", VOP_REG(RK3588_CLUSTER2_WIN0_CTRL0, 0x1, 0), 1 },
{ RK3588_CLUSTER3_WIN0_CTRL0, "Cluster3", VOP_REG(RK3588_CLUSTER3_WIN0_CTRL0, 0x1, 0), 1 },
{ RK3568_ESMART0_CTRL0, "Esmart0", VOP_REG(RK3568_ESMART0_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_ESMART1_CTRL0, "Esmart1", VOP_REG(RK3568_ESMART1_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_SMART0_CTRL0, "Esmart2", VOP_REG(RK3568_SMART0_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_SMART1_CTRL0, "Esmart3", VOP_REG(RK3568_SMART1_REGION0_CTRL, 0x1, 0), 1 },
{ RK3568_HDR_LUT_CTRL, "HDR", {0}, 0 },
};
static const struct vop2_data rk3528_vop = {
@@ -3375,10 +3389,10 @@ static const struct vop2_data rk3528_vop = {
.nr_vps = 2,
.nr_mixers = 4,
.nr_layers = 4,
.nr_gammas = 1,
.esmart_lb_mode = VOP3_ESMART_FOUR_2K_MODE,
.max_input = { 4096, 2304 },
.max_output = { 4096, 2304 },
.nr_gammas = 2,
.esmart_lb_mode = VOP3_ESMART_4K_2K_2K_MODE,
.max_input = { 4096, 4096 },
.max_output = { 4096, 4096 },
.ctrl = &rk3528_vop_ctrl,
.axi_intr = rk3528_vop_axi_intr,
.nr_axi_intr = ARRAY_SIZE(rk3528_vop_axi_intr),