mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
drm/rockchip: vop: support csc convert for win0/1
Change-Id: I7be5dfb7d2711de5a5aeed730aea0ffd9e080945 Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
This commit is contained in:
@@ -72,6 +72,8 @@
|
||||
|
||||
#define VOP_WIN_SET(x, win, name, v) \
|
||||
REG_SET(x, name, win->offset, VOP_WIN_NAME(win, name), v, true)
|
||||
#define VOP_WIN_SET_EXT(x, win, ext, name, v) \
|
||||
REG_SET(x, name, win->offset, win->ext->name, v, true)
|
||||
#define VOP_SCL_SET(x, win, name, v) \
|
||||
REG_SET(x, name, win->offset, win->phy->scl->name, v, true)
|
||||
#define VOP_SCL_SET_EXT(x, win, name, v) \
|
||||
@@ -130,6 +132,9 @@ struct vop_plane_state {
|
||||
struct drm_rect dest;
|
||||
dma_addr_t yrgb_mst;
|
||||
dma_addr_t uv_mst;
|
||||
const uint32_t *y2r_table;
|
||||
const uint32_t *r2r_table;
|
||||
const uint32_t *r2y_table;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
@@ -142,6 +147,7 @@ struct vop_win {
|
||||
uint32_t offset;
|
||||
enum drm_plane_type type;
|
||||
const struct vop_win_phy *phy;
|
||||
const struct vop_csc *csc;
|
||||
const uint32_t *data_formats;
|
||||
uint32_t nformats;
|
||||
struct vop *vop;
|
||||
@@ -258,6 +264,17 @@ static inline uint32_t vop_get_intr_type(struct vop *vop,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vop_load_csc_table(struct vop *vop, u32 offset, const u32 *table)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
vop_writel(vop, offset + i * 4, table[i]);
|
||||
}
|
||||
|
||||
static inline void vop_cfg_done(struct vop *vop)
|
||||
{
|
||||
VOP_CTRL_SET(vop, cfg_done, 1);
|
||||
@@ -483,6 +500,140 @@ static void scl_vop_cal_scl_fac(struct vop *vop, struct vop_win *win,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rk3399 colorspace path:
|
||||
* Input Win csc Output
|
||||
* 1. YUV(2020) --> Y2R->2020To709->R2Y --> YUV_OUTPUT(601/709)
|
||||
* RGB --> R2Y __/
|
||||
*
|
||||
* 2. YUV(2020) --> bypasss --> YUV_OUTPUT(2020)
|
||||
* RGB --> 709To2020->R2Y __/
|
||||
*
|
||||
* 3. YUV(2020) --> Y2R->2020To709 --> RGB_OUTPUT(709)
|
||||
* RGB --> R2Y __/
|
||||
*
|
||||
* 4. YUV(601/709)-> Y2R->709To2020->R2Y --> YUV_OUTPUT(2020)
|
||||
* RGB --> 709To2020->R2Y __/
|
||||
*
|
||||
* 5. YUV(601/709)-> bypass --> YUV_OUTPUT(709)
|
||||
* RGB --> R2Y __/
|
||||
*
|
||||
* 6. YUV(601/709)-> bypass --> YUV_OUTPUT(601)
|
||||
* RGB --> R2Y(601) __/
|
||||
*
|
||||
* 7. YUV --> Y2R(709) --> RGB_OUTPUT(709)
|
||||
* RGB --> bypass __/
|
||||
*
|
||||
* 8. RGB --> 709To2020->R2Y --> YUV_OUTPUT(2020)
|
||||
*
|
||||
* 9. RGB --> R2Y(709) --> YUV_OUTPUT(709)
|
||||
*
|
||||
* 10. RGB --> R2Y(601) --> YUV_OUTPUT(601)
|
||||
*
|
||||
* 11. RGB --> bypass --> RGB_OUTPUT(709)
|
||||
*/
|
||||
static int vop_csc_setup(const struct vop_csc_table *csc_table,
|
||||
bool is_input_yuv, bool is_output_yuv,
|
||||
int input_csc, int output_csc,
|
||||
const uint32_t **y2r_table,
|
||||
const uint32_t **r2r_table,
|
||||
const uint32_t **r2y_table)
|
||||
{
|
||||
*y2r_table = NULL;
|
||||
*r2r_table = NULL;
|
||||
*r2y_table = NULL;
|
||||
|
||||
if (is_output_yuv) {
|
||||
if (output_csc == CSC_BT2020) {
|
||||
if (is_input_yuv) {
|
||||
if (input_csc == CSC_BT2020)
|
||||
return 0;
|
||||
*y2r_table = csc_table->y2r_bt709;
|
||||
}
|
||||
if (input_csc != CSC_BT2020)
|
||||
*r2r_table = csc_table->r2r_bt709_to_bt2020;
|
||||
*r2y_table = csc_table->r2y_bt2020;
|
||||
} else {
|
||||
if (is_input_yuv && input_csc == CSC_BT2020)
|
||||
*y2r_table = csc_table->y2r_bt2020;
|
||||
if (input_csc == CSC_BT2020)
|
||||
*r2r_table = csc_table->r2r_bt2020_to_bt709;
|
||||
if (!is_input_yuv || y2r_table) {
|
||||
if (output_csc == CSC_BT709)
|
||||
*r2y_table = csc_table->r2y_bt709;
|
||||
else
|
||||
*r2y_table = csc_table->r2y_bt601;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!is_input_yuv)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* is possible use bt2020 on rgb mode?
|
||||
*/
|
||||
if (WARN_ON(output_csc == CSC_BT2020))
|
||||
return -EINVAL;
|
||||
|
||||
if (input_csc == CSC_BT2020)
|
||||
*y2r_table = csc_table->y2r_bt2020;
|
||||
else if (input_csc == CSC_BT709)
|
||||
*y2r_table = csc_table->y2r_bt709;
|
||||
else
|
||||
*y2r_table = csc_table->y2r_bt601;
|
||||
|
||||
if (input_csc == CSC_BT2020)
|
||||
/*
|
||||
* We don't have bt601 to bt709 table, force use bt709.
|
||||
*/
|
||||
*r2r_table = csc_table->r2r_bt2020_to_bt709;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vop_csc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *crtc_state)
|
||||
{
|
||||
struct vop *vop = to_vop(crtc);
|
||||
struct drm_atomic_state *state = crtc_state->state;
|
||||
const struct vop_csc_table *csc_table = vop->data->csc_table;
|
||||
struct drm_plane_state *pstate;
|
||||
struct drm_plane *plane;
|
||||
bool is_yuv;
|
||||
int ret;
|
||||
|
||||
if (!csc_table)
|
||||
return 0;
|
||||
|
||||
drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
|
||||
struct vop_plane_state *vop_plane_state;
|
||||
|
||||
pstate = drm_atomic_get_plane_state(state, plane);
|
||||
if (IS_ERR(pstate))
|
||||
return PTR_ERR(pstate);
|
||||
vop_plane_state = to_vop_plane_state(pstate);
|
||||
|
||||
if (!pstate->fb)
|
||||
continue;
|
||||
is_yuv = is_yuv_support(pstate->fb->pixel_format);
|
||||
|
||||
/*
|
||||
* TODO: force set input and output csc mode.
|
||||
*/
|
||||
ret = vop_csc_setup(csc_table, is_yuv, false,
|
||||
CSC_BT709, CSC_BT709,
|
||||
&vop_plane_state->y2r_table,
|
||||
&vop_plane_state->r2r_table,
|
||||
&vop_plane_state->r2y_table);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -774,6 +925,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
||||
uint32_t act_info, dsp_info, dsp_st;
|
||||
struct drm_rect *src = &vop_plane_state->src;
|
||||
struct drm_rect *dest = &vop_plane_state->dest;
|
||||
const uint32_t *y2r_table = vop_plane_state->y2r_table;
|
||||
const uint32_t *r2r_table = vop_plane_state->r2r_table;
|
||||
const uint32_t *r2y_table = vop_plane_state->r2y_table;
|
||||
int ymirror, xmirror;
|
||||
uint32_t val;
|
||||
bool rb_swap;
|
||||
@@ -843,6 +997,14 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
|
||||
VOP_WIN_SET(vop, win, alpha_en, 0);
|
||||
}
|
||||
|
||||
if (win->csc) {
|
||||
vop_load_csc_table(vop, win->csc->y2r_offset, y2r_table);
|
||||
vop_load_csc_table(vop, win->csc->r2r_offset, r2r_table);
|
||||
vop_load_csc_table(vop, win->csc->r2r_offset, r2y_table);
|
||||
VOP_WIN_SET_EXT(vop, win, csc, y2r_en, !!y2r_table);
|
||||
VOP_WIN_SET_EXT(vop, win, csc, r2r_en, !!r2r_table);
|
||||
VOP_WIN_SET_EXT(vop, win, csc, r2y_en, !!r2y_table);
|
||||
}
|
||||
VOP_WIN_SET(vop, win, enable, 1);
|
||||
spin_unlock(&vop->reg_lock);
|
||||
vop->is_iommu_needed = true;
|
||||
@@ -1164,6 +1326,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
int dsp_layer_sel = 0;
|
||||
int i, j, cnt = 0, ret = 0;
|
||||
|
||||
ret = vop_csc_atomic_check(crtc, crtc_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pzpos = kmalloc_array(vop_data->win_size, sizeof(*pzpos), GFP_KERNEL);
|
||||
if (!pzpos)
|
||||
return -ENOMEM;
|
||||
@@ -1576,6 +1742,7 @@ static int vop_win_init(struct vop *vop)
|
||||
continue;
|
||||
|
||||
vop_win->phy = win_data->phy;
|
||||
vop_win->csc = win_data->csc;
|
||||
vop_win->offset = win_data->base;
|
||||
vop_win->type = win_data->type;
|
||||
vop_win->data_formats = win_data->phy->data_formats;
|
||||
|
||||
@@ -23,6 +23,17 @@
|
||||
#define VOP_MAJOR(version) ((version) >> 8)
|
||||
#define VOP_MINOR(version) ((version) & 0xff)
|
||||
|
||||
enum vop_csc_format {
|
||||
CSC_BT601,
|
||||
CSC_BT709,
|
||||
CSC_BT2020,
|
||||
};
|
||||
|
||||
enum vop_csc_mode {
|
||||
CSC_RGB,
|
||||
CSC_YUV,
|
||||
};
|
||||
|
||||
enum vop_data_format {
|
||||
VOP_FMT_ARGB8888 = 0,
|
||||
VOP_FMT_RGB888,
|
||||
@@ -47,6 +58,16 @@ struct vop_reg {
|
||||
uint32_t write_mask:1;
|
||||
};
|
||||
|
||||
struct vop_csc {
|
||||
struct vop_reg y2r_en;
|
||||
struct vop_reg r2r_en;
|
||||
struct vop_reg r2y_en;
|
||||
|
||||
uint32_t y2r_offset;
|
||||
uint32_t r2r_offset;
|
||||
uint32_t r2y_offset;
|
||||
};
|
||||
|
||||
struct vop_ctrl {
|
||||
struct vop_reg standby;
|
||||
struct vop_reg htotal_pw;
|
||||
@@ -136,6 +157,39 @@ struct vop_scl_regs {
|
||||
struct vop_reg scale_cbcr_y;
|
||||
};
|
||||
|
||||
struct vop_csc_table {
|
||||
const uint32_t *y2r_bt601;
|
||||
const uint32_t *y2r_bt601_12_235;
|
||||
const uint32_t *y2r_bt601_10bit;
|
||||
const uint32_t *y2r_bt601_10bit_12_235;
|
||||
const uint32_t *r2y_bt601;
|
||||
const uint32_t *r2y_bt601_12_235;
|
||||
const uint32_t *r2y_bt601_10bit;
|
||||
const uint32_t *r2y_bt601_10bit_12_235;
|
||||
|
||||
const uint32_t *y2r_bt709;
|
||||
const uint32_t *y2r_bt709_10bit;
|
||||
const uint32_t *r2y_bt709;
|
||||
const uint32_t *r2y_bt709_10bit;
|
||||
|
||||
const uint32_t *y2r_bt2020;
|
||||
const uint32_t *r2y_bt2020;
|
||||
|
||||
const uint32_t *r2r_bt709_to_bt2020;
|
||||
const uint32_t *r2r_bt2020_to_bt709;
|
||||
};
|
||||
|
||||
enum {
|
||||
VOP_CSC_Y2R_BT601,
|
||||
VOP_CSC_Y2R_BT709,
|
||||
VOP_CSC_Y2R_BT2020,
|
||||
VOP_CSC_R2Y_BT601,
|
||||
VOP_CSC_R2Y_BT709,
|
||||
VOP_CSC_R2Y_BT2020,
|
||||
VOP_CSC_R2R_BT2020_TO_BT709,
|
||||
VOP_CSC_R2R_BT709_TO_2020,
|
||||
};
|
||||
|
||||
struct vop_win_phy {
|
||||
const struct vop_scl_regs *scl;
|
||||
const uint32_t *data_formats;
|
||||
@@ -168,6 +222,7 @@ struct vop_win_data {
|
||||
enum drm_plane_type type;
|
||||
const struct vop_win_phy *phy;
|
||||
const struct vop_win_phy **area;
|
||||
const struct vop_csc *csc;
|
||||
unsigned int area_size;
|
||||
};
|
||||
|
||||
@@ -179,6 +234,7 @@ struct vop_data {
|
||||
const struct vop_ctrl *ctrl;
|
||||
const struct vop_intr *intr;
|
||||
const struct vop_win_data *win;
|
||||
const struct vop_csc_table *csc_table;
|
||||
unsigned int win_size;
|
||||
uint32_t version;
|
||||
u64 feature;
|
||||
|
||||
@@ -371,17 +371,116 @@ static const struct vop_data rk3366_vop = {
|
||||
.win_size = ARRAY_SIZE(rk3368_vop_win_data),
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_y2r_bt601[] = {
|
||||
0x00000400, 0x0400059c, 0xfd25fea0, 0x07170400,
|
||||
0x00000000, 0xfffecab4, 0x00087932, 0xfff1d4f2,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_y2r_bt601_12_235[] = {
|
||||
0x000004a8, 0x04a80662, 0xfcbffe6f, 0x081204a8,
|
||||
0x00000000, 0xfff2134e, 0x00087b58, 0xffeeb4b0,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_r2y_bt601[] = {
|
||||
0x02590132, 0xff530075, 0x0200fead, 0xfe530200,
|
||||
0x0000ffad, 0x00000200, 0x00080200, 0x00080200,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_r2y_bt601_12_235[] = {
|
||||
0x02040107, 0xff680064, 0x01c2fed6, 0xffb7fe87,
|
||||
0x0000ffb7, 0x00010200, 0x00080200, 0x00080200,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_y2r_bt709[] = {
|
||||
0x000004a8, 0x04a8072c, 0xfddeff26, 0x087304a8,
|
||||
0x00000000, 0xfff08077, 0x0004cfed, 0xffedf1b8,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_r2y_bt709[] = {
|
||||
0x027500bb, 0xff99003f, 0x01c2fea5, 0xfe6801c2,
|
||||
0xffd7fe68, 0x00010200, 0x00080200, 0x00080200,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_y2r_bt2020[] = {
|
||||
0x000004a8, 0x04a806b6, 0xfd66ff40, 0x089004a8,
|
||||
0x00000000, 0xfff16bfc, 0x00058ae9, 0xffedb828,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_r2y_bt2020[] = {
|
||||
0x025300e6, 0xff830034, 0x01c1febd, 0xfe6401c1,
|
||||
0x0000ffdc, 0x00010200, 0x00080200, 0x00080200,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_r2r_bt709_to_bt2020[] = {
|
||||
0xfda606a4, 0xff80ffb5, 0xfff80488, 0xff99ffed,
|
||||
0x0000047a, 0x00000200, 0x00000200, 0x00000200,
|
||||
};
|
||||
|
||||
static const uint32_t vop_csc_r2r_bt2020_to_bt709[] = {
|
||||
0x01510282, 0x0047002c, 0x000c03ae, 0x005a0011,
|
||||
0x00000394, 0x00000200, 0x00000200, 0x00000200,
|
||||
};
|
||||
|
||||
static const struct vop_csc_table rk3399_csc_table = {
|
||||
.y2r_bt601 = vop_csc_y2r_bt601,
|
||||
.y2r_bt601_12_235 = vop_csc_y2r_bt601_12_235,
|
||||
.r2y_bt601 = vop_csc_r2y_bt601,
|
||||
.r2y_bt601_12_235 = vop_csc_r2y_bt601_12_235,
|
||||
|
||||
.y2r_bt709 = vop_csc_y2r_bt709,
|
||||
.r2y_bt709 = vop_csc_r2y_bt709,
|
||||
|
||||
.y2r_bt2020 = vop_csc_y2r_bt2020,
|
||||
.r2y_bt2020 = vop_csc_r2y_bt2020,
|
||||
|
||||
.r2r_bt709_to_bt2020 = vop_csc_r2r_bt709_to_bt2020,
|
||||
.r2r_bt2020_to_bt709 = vop_csc_r2r_bt2020_to_bt709,
|
||||
};
|
||||
|
||||
static const struct vop_csc rk3399_win0_csc = {
|
||||
.r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 0),
|
||||
.y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1),
|
||||
.r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 2),
|
||||
.y2r_offset = RK3399_WIN0_YUV2YUV_Y2R,
|
||||
.r2r_offset = RK3399_WIN0_YUV2YUV_3X3,
|
||||
.r2y_offset = RK3399_WIN0_YUV2YUV_R2Y,
|
||||
};
|
||||
|
||||
static const struct vop_csc rk3399_win1_csc = {
|
||||
.r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 8),
|
||||
.y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9),
|
||||
.r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 10),
|
||||
.y2r_offset = RK3399_WIN1_YUV2YUV_Y2R,
|
||||
.r2r_offset = RK3399_WIN1_YUV2YUV_3X3,
|
||||
.r2y_offset = RK3399_WIN1_YUV2YUV_R2Y,
|
||||
};
|
||||
|
||||
static const struct vop_win_data rk3399_vop_win_data[] = {
|
||||
{ .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY },
|
||||
{ .base = 0x40, .phy = &rk3288_win01_data, .csc = &rk3399_win1_csc,
|
||||
.type = DRM_PLANE_TYPE_OVERLAY },
|
||||
{ .base = 0x00, .phy = &rk3368_win23_data,
|
||||
.type = DRM_PLANE_TYPE_OVERLAY,
|
||||
.area = rk3368_area_data,
|
||||
.area_size = ARRAY_SIZE(rk3368_area_data), },
|
||||
{ .base = 0x50, .phy = &rk3368_win23_data,
|
||||
.type = DRM_PLANE_TYPE_CURSOR,
|
||||
.area = rk3368_area_data,
|
||||
.area_size = ARRAY_SIZE(rk3368_area_data), },
|
||||
};
|
||||
|
||||
static const struct vop_data rk3399_vop_big = {
|
||||
.version = VOP_VERSION(3, 5),
|
||||
.feature = VOP_FEATURE_OUTPUT_10BIT,
|
||||
.intr = &rk3366_vop_intr,
|
||||
.ctrl = &rk3288_ctrl_data,
|
||||
.win = rk3368_vop_win_data,
|
||||
.win_size = ARRAY_SIZE(rk3368_vop_win_data),
|
||||
.win = rk3399_vop_win_data,
|
||||
.win_size = ARRAY_SIZE(rk3399_vop_win_data),
|
||||
};
|
||||
|
||||
static const struct vop_win_data rk3399_vop_lit_win_data[] = {
|
||||
{ .base = 0x00, .phy = &rk3288_win01_data,
|
||||
{ .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY },
|
||||
{ .phy = NULL },
|
||||
{ .base = 0x00, .phy = &rk3368_win23_data,
|
||||
@@ -394,6 +493,7 @@ static const struct vop_win_data rk3399_vop_lit_win_data[] = {
|
||||
|
||||
static const struct vop_data rk3399_vop_lit = {
|
||||
.version = VOP_VERSION(3, 6),
|
||||
.csc_table = &rk3399_csc_table,
|
||||
.intr = &rk3366_vop_intr,
|
||||
.ctrl = &rk3288_ctrl_data,
|
||||
.win = rk3399_vop_lit_win_data,
|
||||
|
||||
Reference in New Issue
Block a user