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;
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,
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:
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)
{
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;
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);
+
+ /* 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);
+ 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,
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));
/*
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);
u32 mode_ctrl;
u32 sys_ctrl;
u32 rtram_ctrl;
+
+ u32 pitch;
+
+ bool use_dtrc;
};
struct dcss_dpr_priv {
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];
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);
}
}
{
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);
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);
}
}
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;
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);
#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)
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);
}
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;
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);
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;
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)
#include <linux/types.h>
#include <video/videomode.h>
+#include <drm/drm_rect.h>
struct dcss_soc;
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);
/* 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);