1
0
Fork 0

MLK-17459-2: drm: imx: dcss: add cropping functionality and fix odd resolutions

This patch fixes playback for movies with unaligned widths/heights and
adds cropping functionality for tiled formats. Untiled formats will not
have this feature as cropping is a DTRC function.

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
pull/10/head
Laurentiu Palcu 2018-02-19 15:58:21 +02:00 committed by Jason Liu
parent 61f43a150f
commit 122d5302ad
4 changed files with 210 additions and 49 deletions

View File

@ -178,6 +178,7 @@ static int dcss_plane_atomic_check(struct drm_plane *plane,
struct drm_gem_cma_object *cma_obj;
struct drm_crtc_state *crtc_state;
int hdisplay, vdisplay;
struct drm_rect crtc_rect, disp_rect;
if (!fb)
return 0;
@ -194,11 +195,29 @@ static int dcss_plane_atomic_check(struct drm_plane *plane,
hdisplay = crtc_state->adjusted_mode.hdisplay;
vdisplay = crtc_state->adjusted_mode.vdisplay;
/* We don't support cropping yet */
crtc_rect.x1 = state->crtc_x;
crtc_rect.x2 = state->crtc_x + state->crtc_w;
crtc_rect.y1 = state->crtc_y;
crtc_rect.y2 = state->crtc_y + state->crtc_h;
disp_rect.x1 = 0;
disp_rect.y1 = 0;
disp_rect.x2 = hdisplay;
disp_rect.y2 = vdisplay;
/* make sure the crtc is visible */
if (!drm_rect_intersect(&crtc_rect, &disp_rect))
return -EINVAL;
/* cropping is only available on overlay planes when DTRC is used */
if (state->crtc_x < 0 || state->crtc_y < 0 ||
state->crtc_x + state->crtc_w > hdisplay ||
state->crtc_y + state->crtc_h > vdisplay)
return -EINVAL;
state->crtc_y + state->crtc_h > vdisplay) {
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
return -EINVAL;
else if (!(fb->flags & DRM_MODE_FB_MODIFIERS))
return -EINVAL;
}
if (!dcss_scaler_can_scale(dcss_plane->dcss, dcss_plane->ch_num,
state->src_w >> 16, state->src_h >> 16,
@ -240,8 +259,8 @@ static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
fb->pitches[1] * (state->src_y >> 16) +
fb->format->cpp[0] * (state->src_x >> 16);
dcss_dpr_addr_set(dcss_plane->dcss, dcss_plane->ch_num,
p1_ba, p2_ba, fb->pitches[0]);
dcss_dpr_addr_set(dcss_plane->dcss, dcss_plane->ch_num, p1_ba, p2_ba,
fb->pitches[0]);
switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
@ -312,6 +331,27 @@ static bool dcss_plane_needs_setup(struct drm_plane_state *state,
fb->modifier != old_fb->modifier;
}
static void dcss_plane_adjust(struct drm_rect *dis_rect,
struct drm_rect *crtc,
struct drm_rect *src)
{
struct drm_rect new_crtc = *dis_rect, new_src;
u32 hscale, vscale;
hscale = ((src->x2 - src->x1) << 16) / (crtc->x2 - crtc->x1);
vscale = ((src->y2 - src->y1) << 16) / (crtc->y2 - crtc->y1);
drm_rect_intersect(&new_crtc, crtc);
new_src.x1 = ((new_crtc.x1 - crtc->x1) * hscale + (1 << 15)) >> 16;
new_src.x2 = ((new_crtc.x2 - crtc->x1) * hscale + (1 << 15)) >> 16;
new_src.y1 = ((new_crtc.y1 - crtc->y1) * vscale + (1 << 15)) >> 16;
new_src.y2 = ((new_crtc.y2 - crtc->y1) * vscale + (1 << 15)) >> 16;
*crtc = new_crtc;
*src = new_src;
}
static void dcss_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@ -321,6 +361,8 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
u32 pixel_format = state->fb->format->format;
struct drm_crtc_state *crtc_state = state->crtc->state;
bool modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
u32 src_w, src_h, adj_w, adj_h;
struct drm_rect disp, crtc, src, old_src;
if (!state->fb)
return;
@ -336,11 +378,46 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
return;
}
dcss_dpr_enable(dcss_plane->dcss, dcss_plane->ch_num, false);
dcss_scaler_enable(dcss_plane->dcss, dcss_plane->ch_num, false);
dcss_dtg_ch_enable(dcss_plane->dcss, dcss_plane->ch_num, false);
disp.x1 = 0;
disp.y1 = 0;
disp.x2 = crtc_state->adjusted_mode.hdisplay;
disp.y2 = crtc_state->adjusted_mode.vdisplay;
crtc.x1 = state->crtc_x;
crtc.y1 = state->crtc_y;
crtc.x2 = state->crtc_x + state->crtc_w;
crtc.y2 = state->crtc_y + state->crtc_h;
src.x1 = state->src_x >> 16;
src.y1 = state->src_y >> 16;
src.x2 = (state->src_x >> 16) + (state->src_w >> 16);
src.y2 = (state->src_y >> 16) + (state->src_h >> 16);
old_src = src;
dcss_plane_adjust(&disp, &crtc, &src);
/*
* The width and height after clipping, if image was partially
* outside the display area.
*/
src_w = src.x2 - src.x1;
src_h = src.y2 - src.y1;
if (plane->type == DRM_PLANE_TYPE_OVERLAY)
dcss_dtrc_set_res(dcss_plane->dcss, dcss_plane->ch_num,
state->src_w >> 16, state->src_h >> 16);
&src, &old_src);
dcss_dpr_format_set(dcss_plane->dcss, dcss_plane->ch_num, pixel_format);
/* DTRC has probably aligned the sizes. */
adj_w = src.x2 - src.x1;
adj_h = src.y2 - src.y1;
dcss_dpr_format_set(dcss_plane->dcss, dcss_plane->ch_num, pixel_format,
modifiers_present);
if (!modifiers_present)
dcss_dpr_tile_derive(dcss_plane->dcss,
dcss_plane->ch_num,
@ -351,12 +428,13 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
fb->modifier);
dcss_dpr_set_res(dcss_plane->dcss, dcss_plane->ch_num,
state->src_w >> 16, state->src_h >> 16);
src_w, src_h, adj_w, adj_h);
dcss_plane_atomic_set_base(dcss_plane);
dcss_scaler_setup(dcss_plane->dcss, dcss_plane->ch_num,
pixel_format, state->src_w >> 16,
state->src_h >> 16, state->crtc_w, state->crtc_h,
pixel_format, src_w, src_h,
crtc.x2 - crtc.x1,
crtc.y2 - crtc.y1,
drm_mode_vrefresh(&crtc_state->mode));
/*
@ -368,8 +446,9 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
DCSS_COLORSPACE_RGB);
dcss_dtg_plane_pos_set(dcss_plane->dcss, dcss_plane->ch_num,
state->crtc_x, state->crtc_y,
state->crtc_w, state->crtc_h);
crtc.x1, crtc.y1,
crtc.x2 - crtc.x1,
crtc.y2 - crtc.y1);
dcss_dtg_plane_alpha_set(dcss_plane->dcss, dcss_plane->ch_num,
pixel_format, dcss_plane->alpha_val,
dcss_plane->use_global_val);

View File

@ -110,6 +110,10 @@ struct dcss_dpr_ch {
u32 mode_ctrl;
u32 sys_ctrl;
u32 rtram_ctrl;
u32 pitch;
bool use_dtrc;
};
struct dcss_dpr_priv {
@ -252,7 +256,8 @@ static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
return pix_high + offset;
}
void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres)
void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres,
u32 adj_w, u32 adj_h)
{
struct dcss_dpr_priv *dpr = dcss->dpr_priv;
struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
@ -269,13 +274,23 @@ void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres)
pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
/* DTRC may need another width alignment. If it does, use it. */
if (pix_x_wide != adj_w)
pix_x_wide = adj_w;
if (pix_y_high != adj_h)
pix_y_high = plane == 0 ? adj_h : adj_h >> 1;
if (plane == 0)
ch->pitch = pix_x_wide;
dcss_dpr_write(dpr, ch_num, pix_x_wide,
DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
dcss_dpr_write(dpr, ch_num, pix_y_high,
DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
dcss_dpr_write(dpr, ch_num, xres < 640 ? 3 :
xres < 1280 ? 4 : xres < 3840 ? 5 : 6,
dcss_dpr_write(dpr, ch_num, ch->use_dtrc ? 7 : 2,
DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
}
}
@ -286,6 +301,11 @@ void dcss_dpr_addr_set(struct dcss_soc *dcss, int ch_num, u32 luma_base_addr,
{
struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
if (ch->use_dtrc) {
luma_base_addr = 0x0;
chroma_base_addr = 0x10000000;
}
if (!dcss_dtrc_is_running(dcss, ch_num)) {
dcss_dpr_write(dcss->dpr_priv, ch_num, luma_base_addr,
DCSS_DPR_FRAME_1P_BASE_ADDR);
@ -294,6 +314,9 @@ void dcss_dpr_addr_set(struct dcss_soc *dcss, int ch_num, u32 luma_base_addr,
DCSS_DPR_FRAME_2P_BASE_ADDR);
}
if (ch->use_dtrc)
pitch = ch->pitch;
ch->frame_ctrl &= ~PITCH_MASK;
ch->frame_ctrl |= ((pitch << PITCH_POS) & PITCH_MASK);
}
@ -586,7 +609,8 @@ void dcss_dpr_tile_derive(struct dcss_soc *dcss,
}
EXPORT_SYMBOL(dcss_dpr_tile_set);
void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format)
void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format,
bool modifiers_present)
{
struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
struct drm_format_name_buf format_name;
@ -598,6 +622,7 @@ void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format)
ch->planes = drm_format_num_planes(pix_format);
ch->bpp = dcss_dpr_get_bpp(pix_format);
ch->pix_format = pix_format;
ch->use_dtrc = modifiers_present;
dev_dbg(dcss->dev, "pix_format = %s, colorspace = %d, bpp = %d\n",
drm_get_format_name(pix_format, &format_name), dcss_cs, ch->bpp);

View File

@ -43,6 +43,10 @@
#define DCSS_DTRC_SUVSEA 0x20
#define DCSS_DTRC_CROPORIG 0x24
#define DCSS_DTRC_CROPSIZE 0x28
#define CROP_HEIGHT_POS 16
#define CROP_HEIGHT_MASK GENMASK(28, 16)
#define CROP_WIDTH_POS 0
#define CROP_WIDTH_MASK GENMASK(12, 0)
#define DCSS_DTRC_DCTL 0x2C
#define CROPPING_EN BIT(18)
#define COMPRESSION_DIS BIT(17)
@ -299,28 +303,8 @@ void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba,
dcss_dtrc_write(dtrc, ch_num, p1_ba, DTRC_F1_OFS + DCSS_DTRC_DYDSADDR);
dcss_dtrc_write(dtrc, ch_num, p2_ba, DTRC_F1_OFS + DCSS_DTRC_DCDSADDR);
if (!ch->running) {
dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_SYSSA);
dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
DCSS_DTRC_SYSEA);
dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_SUVSSA);
dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 2,
DCSS_DTRC_SUVSEA);
dcss_dtrc_write(dtrc, ch_num, p1_ba,
DTRC_F1_OFS + DCSS_DTRC_SYSSA);
dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
DTRC_F1_OFS + DCSS_DTRC_SYSEA);
dcss_dtrc_write(dtrc, ch_num, p2_ba,
DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 2,
DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
ch->y_dec_ofs = dec_table_ofs & 0xFFFFFFFF;
ch->uv_dec_ofs = dec_table_ofs >> 32;
}
ch->y_dec_ofs = dec_table_ofs & 0xFFFFFFFF;
ch->uv_dec_ofs = dec_table_ofs >> 32;
dcss_dtrc_write(dtrc, ch_num,
p1_ba + ch->y_dec_ofs, DCSS_DTRC_DYTSADDR);
@ -335,12 +319,15 @@ void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba,
}
EXPORT_SYMBOL(dcss_dtrc_addr_set);
void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres)
void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src,
struct drm_rect *old_src)
{
struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
struct dcss_dtrc_ch *ch;
u32 frame_height, frame_width;
u32 crop_w, crop_h, crop_orig_w, crop_orig_h;
int bank;
u32 old_xres, old_yres, xres, yres;
if (ch_num == 0)
return;
@ -348,19 +335,83 @@ void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres)
ch_num -= 1;
ch = &dtrc->ch[ch_num];
bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
ch->xres = xres;
ch->yres = yres;
old_xres = old_src->x2 - old_src->x1;
old_yres = old_src->y2 - old_src->y1;
xres = src->x2 - src->x1;
yres = src->y2 - src->y1;
frame_height = ((yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK;
frame_width = ((xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK;
frame_height = ((old_yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK;
frame_width = ((old_xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK;
dcss_dtrc_write(dcss->dtrc_priv, ch_num, frame_height | frame_width,
DTRC_F1_OFS * bank + DCSS_DTRC_SIZE);
dcss_dtrc_write(dcss->dtrc_priv, ch_num, frame_height | frame_width,
DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_SIZE);
/*
* Image original size is aligned:
* - 128 pixels for width;
* - 8 lines for height;
*/
if (xres == old_xres && !(xres & 0x7f) &&
yres == old_yres && !(yres & 0xf)) {
ch->dctl &= ~CROPPING_EN;
goto exit;
}
/* align the image size */
xres = (xres + 0x7f) & ~0x7f;
yres = (yres + 0xf) & ~0xf;
src->x1 &= ~1;
src->x2 &= ~1;
crop_orig_w = (src->x1 << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
crop_orig_h = (src->y1 << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_orig_w | crop_orig_h,
DCSS_DTRC_CROPORIG);
dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_orig_w | crop_orig_h,
DTRC_F1_OFS + DCSS_DTRC_CROPORIG);
crop_w = (xres << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
crop_h = (yres << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_w | crop_h,
DTRC_F1_OFS * bank + DCSS_DTRC_CROPSIZE);
dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_w | crop_h,
DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_CROPSIZE);
ch->dctl |= CROPPING_EN;
exit:
dcss_dtrc_write(dtrc, ch_num, xres * yres,
DCSS_DTRC_SYSEA);
dcss_dtrc_write(dtrc, ch_num, xres * yres,
DTRC_F1_OFS + DCSS_DTRC_SYSEA);
dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres / 2,
DCSS_DTRC_SUVSEA);
dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres / 2,
DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
src->x2 = src->x1 + xres;
src->y2 = src->y1 + yres;
if (ch->running)
return;
dcss_dtrc_write(dtrc, ch_num, 0x0, DCSS_DTRC_SYSSA);
dcss_dtrc_write(dtrc, ch_num, 0x0,
DTRC_F1_OFS + DCSS_DTRC_SYSSA);
dcss_dtrc_write(dtrc, ch_num, 0x10000000, DCSS_DTRC_SUVSSA);
dcss_dtrc_write(dtrc, ch_num, 0x10000000,
DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
}
EXPORT_SYMBOL(dcss_dtrc_set_res);
@ -409,7 +460,9 @@ void dcss_dtrc_enable(struct dcss_soc *dcss, int ch_num, bool enable)
curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
fdctl = PIX_DEPTH_8BIT_EN;
fdctl = ch->dctl & ~(PIX_DEPTH_8BIT_EN | COMPRESSION_DIS);
fdctl |= PIX_DEPTH_8BIT_EN;
if (ch->format_modifier != DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED)
fdctl |= COMPRESSION_DIS;
@ -463,10 +516,10 @@ static void dcss_dtrc_ch_switch_banks(struct dcss_dtrc_priv *dtrc, int dtrc_ch)
if (!ch->running)
return;
ch->curr_frame ^= 1;
ch->curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
dcss_dtrc_write_irqsafe(dtrc, dtrc_ch, ch->dctl | CONFIG_READY,
ch->curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
(ch->curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
}
void dcss_dtrc_switch_banks(struct dcss_soc *dcss)

View File

@ -17,6 +17,7 @@
#include <linux/types.h>
#include <video/videomode.h>
#include <drm/drm_rect.h>
struct dcss_soc;
@ -48,11 +49,13 @@ enum dcss_pix_size {
PIX_SIZE_32,
};
void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres);
void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres,
u32 adj_w, u32 adj_h);
void dcss_dpr_addr_set(struct dcss_soc *dcss, int ch_num, u32 luma_base_addr,
u32 chroma_base_addr, u16 pitch);
void dcss_dpr_enable(struct dcss_soc *dcss, int ch_num, bool en);
void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format);
void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format,
bool modifiers_present);
void dcss_dpr_tile_derive(struct dcss_soc *dcss,
int ch_num,
uint64_t modifier);
@ -94,7 +97,8 @@ void dcss_hdr10_pipe_csc_setup(struct dcss_soc *dcss, int ch_num,
/* DTRC */
void dcss_dtrc_bypass(struct dcss_soc *dcss, int ch_num);
void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres);
void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src,
struct drm_rect *old_src);
void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba,
uint64_t dec_table_ofs);
void dcss_dtrc_enable(struct dcss_soc *dcss, int ch_num, bool enable);