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:
Mark Yao 2016-09-06 17:18:38 +08:00 committed by Huang, Tao
parent c762b0ce17
commit ce4accc725
3 changed files with 326 additions and 3 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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,