diff options
author | Liu Ying <victor.liu@nxp.com> | 2017-07-21 16:21:26 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:41:33 +0300 |
commit | 58aa92e61e1f74076c13bc75c583003fe6e6346f (patch) | |
tree | d5c6b868c8f4f909450c2d9b9d387a164f032e78 | |
parent | 973b6b9deb54b4db7254248987c574daebdbc97f (diff) |
MLK-16075-21 drm/imx: dpu: kms: Add several YUV pixel formats support
This patch adds several YUV pixel formats support for dpu kms.
The pixel formats are YUYV, UYVY, NV12, NV21, NV16, NV61, NV24 and NV42.
Signed-off-by: Liu Ying <victor.liu@nxp.com>
-rw-r--r-- | drivers/gpu/drm/imx/dpu/dpu-crtc.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/dpu/dpu-kms.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/dpu/dpu-plane.c | 120 |
3 files changed, 160 insertions, 6 deletions
diff --git a/drivers/gpu/drm/imx/dpu/dpu-crtc.c b/drivers/gpu/drm/imx/dpu/dpu-crtc.c index 6ab102b93c05..00fc28196c4c 100644 --- a/drivers/gpu/drm/imx/dpu/dpu-crtc.c +++ b/drivers/gpu/drm/imx/dpu/dpu-crtc.c @@ -247,6 +247,7 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, struct dpu_plane *dplane; struct dpu_plane_res *res; struct dpu_fetchdecode *fd; + struct dpu_fetcheco *fe; struct dpu_hscaler *hs; struct dpu_vscaler *vs; struct dpu_layerblend *lb; @@ -272,11 +273,14 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, fd = res->fd[fd_id]; lb = res->lb[lb_id]; + fe = fetchdecode_get_fetcheco(fd); hs = fetchdecode_get_hscaler(fd); vs = fetchdecode_get_vscaler(fd); layerblend_pixengcfg_clken(lb, CLKEN__DISABLE); fetchdecode_source_buffer_disable(fd); + fetchdecode_pixengcfg_dynamic_src_sel(fd, FD_SRC_DISABLE); + fetcheco_source_buffer_disable(fe); hscaler_pixengcfg_clken(hs, CLKEN__DISABLE); vscaler_pixengcfg_clken(vs, CLKEN__DISABLE); hscaler_mode(hs, SCALER_NEUTRAL); @@ -307,6 +311,12 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, DPU_PLANE_SRC_DISABLED); } + for (i = 0; i < ARRAY_SIZE(res->fe); i++) { + if (res->fe[i] && !fetcheco_is_enabled(res->fe[i])) + fetcheco_set_stream_id(res->fe[i], + DPU_PLANE_SRC_DISABLED); + } + for (i = 0; i < ARRAY_SIZE(res->hs); i++) { if (res->hs[i] && !hscaler_is_enabled(res->hs[i])) hscaler_set_stream_id(res->hs[i], diff --git a/drivers/gpu/drm/imx/dpu/dpu-kms.c b/drivers/gpu/drm/imx/dpu/dpu-kms.c index 8f75b5be95f6..d0cad11f676a 100644 --- a/drivers/gpu/drm/imx/dpu/dpu-kms.c +++ b/drivers/gpu/drm/imx/dpu/dpu-kms.c @@ -131,18 +131,21 @@ dpu_atomic_assign_plane_source_per_crtc(struct drm_plane_state **states, int n) struct dpu_plane_state *dpstate; struct dpu_plane *dplane; struct dpu_plane_grp *grp; + struct drm_framebuffer *fb; struct dpu_fetchdecode *fd; + struct dpu_fetcheco *fe; struct dpu_hscaler *hs; struct dpu_vscaler *vs; unsigned int sid, src_sid; int i, j, k; int fd_id; - u32 cap_mask, hs_mask, vs_mask; + u32 cap_mask, fe_mask, hs_mask, vs_mask; /* for active planes only */ for (i = 0; i < n; i++) { dpstate = to_dpu_plane_state(states[i]); dplane = to_dpu_plane(states[i]->plane); + fb = states[i]->fb; grp = dplane->grp; sid = dplane->stream_id; @@ -163,6 +166,27 @@ dpu_atomic_assign_plane_source_per_crtc(struct drm_plane_state **states, int n) cap_mask = fetchdecode_get_vproc_mask(fd); + if (drm_format_num_planes(fb->pixel_format) > 1) { + fe = fetchdecode_get_fetcheco(fd); + + /* avoid on-the-fly/hot migration */ + src_sid = fetcheco_get_stream_id(fe); + if (src_sid && src_sid != BIT(sid)) + continue; + + /* fetch unit has the fetcheco capability? */ + if (!dpu_vproc_has_fetcheco_cap(cap_mask)) + continue; + + fe_mask = dpu_vproc_get_fetcheco_cap(cap_mask); + + /* fetcheco available? */ + if (grp->src_use_vproc_mask & fe_mask) + continue; + + grp->src_use_vproc_mask |= fe_mask; + } + if (states[i]->src_w >> 16 != states[i]->crtc_w) { hs = fetchdecode_get_hscaler(fd); @@ -239,11 +263,13 @@ static int dpu_drm_atomic_check(struct drm_device *dev, struct dpu_plane_grp *grp[MAX_DPU_PLANE_GRP]; int ret, i, grp_id; int active_plane[MAX_DPU_PLANE_GRP]; + int active_plane_fetcheco[MAX_DPU_PLANE_GRP]; int active_plane_hscale[MAX_DPU_PLANE_GRP]; int active_plane_vscale[MAX_DPU_PLANE_GRP]; for (i = 0; i < MAX_DPU_PLANE_GRP; i++) { active_plane[i] = 0; + active_plane_fetcheco[i] = 0; active_plane_hscale[i] = 0; active_plane_vscale[i] = 0; grp[i] = NULL; @@ -260,10 +286,14 @@ static int dpu_drm_atomic_check(struct drm_device *dev, drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) { + struct drm_framebuffer *fb = plane_state->fb; dpu_plane = to_dpu_plane(plane); grp_id = dpu_plane->grp->id; active_plane[grp_id]++; + if (drm_format_num_planes(fb->pixel_format) > 1) + active_plane_fetcheco[grp_id]++; + if (plane_state->src_w >> 16 != plane_state->crtc_w) active_plane_hscale[grp_id]++; @@ -281,6 +311,10 @@ static int dpu_drm_atomic_check(struct drm_device *dev, if (active_plane[i] > grp[i]->hw_plane_num) return -EINVAL; + if (active_plane_fetcheco[i] > + grp[i]->hw_plane_fetcheco_num) + return -EINVAL; + if (active_plane_hscale[i] > grp[i]->hw_plane_hscaler_num) return -EINVAL; diff --git a/drivers/gpu/drm/imx/dpu/dpu-plane.c b/drivers/gpu/drm/imx/dpu/dpu-plane.c index 21bf0be2ca54..f54cf8169cc6 100644 --- a/drivers/gpu/drm/imx/dpu/dpu-plane.c +++ b/drivers/gpu/drm/imx/dpu/dpu-plane.c @@ -22,7 +22,10 @@ #include "dpu-plane.h" #include "imx-drm.h" -/* RGB formats are widely supported by all fetch units */ +/* + * RGB and packed/2planar YUV formats + * are widely supported by many fetch units. + */ static const uint32_t dpu_common_formats[] = { /* DRM_FORMAT_ARGB8888, */ DRM_FORMAT_XRGB8888, @@ -35,6 +38,15 @@ static const uint32_t dpu_common_formats[] = { DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, DRM_FORMAT_RGB565, + + DRM_FORMAT_YUYV, + DRM_FORMAT_UYVY, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV16, + DRM_FORMAT_NV61, + DRM_FORMAT_NV24, + DRM_FORMAT_NV42, }; static void dpu_plane_destroy(struct drm_plane *plane) @@ -126,6 +138,24 @@ drm_plane_state_to_baseaddr(struct drm_plane_state *state) drm_format_plane_cpp(fb->pixel_format, 0) * x; } +static inline dma_addr_t +drm_plane_state_to_uvbaseaddr(struct drm_plane_state *state) +{ + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *cma_obj; + int x = state->src_x >> 16; + int y = state->src_y >> 16; + + cma_obj = drm_fb_cma_get_gem_obj(fb, 1); + BUG_ON(!cma_obj); + + x /= drm_format_horz_chroma_subsampling(fb->pixel_format); + y /= drm_format_vert_chroma_subsampling(fb->pixel_format); + + return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y + + drm_format_plane_cpp(fb->pixel_format, 1) * x; +} + static int dpu_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { @@ -189,9 +219,33 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, crtc_state->adjusted_mode.vdisplay) return -EINVAL; + /* pixel/line count and position parameters check */ + if (drm_format_horz_chroma_subsampling(fb->pixel_format) == 2 && + (((state->src_w >> 16) % 2) || ((state->src_x >> 16) % 2))) + return -EINVAL; + if (drm_format_vert_chroma_subsampling(fb->pixel_format) == 2 && + (((state->src_h >> 16) % 2) || ((state->src_y >> 16) % 2))) + return -EINVAL; + /* base address alignment check */ baseaddr = drm_plane_state_to_baseaddr(state); - drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); + switch (fb->pixel_format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + bpp = 16; + break; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + bpp = 8; + break; + default: + drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); + break; + } switch (bpp) { case 32: if (baseaddr & 0x3) @@ -206,6 +260,16 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, if (fb->pitches[0] > 0x10000) return -EINVAL; + /* UV base address alignment check, assuming 16bpp */ + if (drm_format_num_planes(fb->pixel_format) > 1) { + baseaddr = drm_plane_state_to_uvbaseaddr(state); + if (baseaddr & 0x1) + return -EINVAL; + + if (fb->pitches[1] > 0x10000) + return -EINVAL; + } + return 0; } @@ -218,17 +282,18 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, struct drm_framebuffer *fb = state->fb; struct dpu_plane_res *res = &dplane->grp->res; struct dpu_fetchdecode *fd; + struct dpu_fetcheco *fe; struct dpu_hscaler *hs; struct dpu_vscaler *vs; struct dpu_layerblend *lb; struct dpu_constframe *cf; struct dpu_extdst *ed; struct device *dev = plane->dev->dev; - dpu_block_id_t vs_id = ID_NONE, hs_id; + dpu_block_id_t fe_id, vs_id = ID_NONE, hs_id; lb_sec_sel_t lb_src = dpstate->source; unsigned int depth, src_w, src_h; int bpp, fd_id, lb_id; - bool need_hscaler = false, need_vscaler = false; + bool need_fetcheco = false, need_hscaler = false, need_vscaler = false; /* * Do nothing since the plane is disabled by @@ -251,6 +316,13 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, src_w = state->src_w >> 16; src_h = state->src_h >> 16; + if (fetchdecode_need_fetcheco(fd, fb->pixel_format)) { + need_fetcheco = true; + fe = fetchdecode_get_fetcheco(fd); + if (IS_ERR(fe)) + return; + } + if (src_w != state->crtc_w) { need_hscaler = true; hs = fetchdecode_get_hscaler(fd); @@ -265,7 +337,23 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, return; } - drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); + switch (fb->pixel_format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + bpp = 16; + break; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + bpp = 8; + break; + default: + drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); + break; + } fetchdecode_source_bpp(fd, bpp); fetchdecode_source_stride(fd, fb->pitches[0]); @@ -278,6 +366,28 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, DPU_PLANE_SRC_TO_DISP_STREAM1 : DPU_PLANE_SRC_TO_DISP_STREAM0); + if (need_fetcheco) { + fe_id = fetcheco_get_block_id(fe); + if (fe_id == ID_NONE) + return; + + fetchdecode_pixengcfg_dynamic_src_sel(fd, + (fd_dynamic_src_sel_t)fe_id); + fetcheco_source_bpp(fe, 16); + fetcheco_source_stride(fe, fb->pitches[1]); + fetcheco_set_fmt(fe, fb->pixel_format); + fetcheco_src_buf_dimensions(fe, src_w, src_h, fb->pixel_format); + fetcheco_framedimensions(fe, src_w, src_h); + fetcheco_baseaddress(fe, drm_plane_state_to_uvbaseaddr(state)); + fetcheco_source_buffer_enable(fe); + fetcheco_set_stream_id(fe, dplane->stream_id ? + DPU_PLANE_SRC_TO_DISP_STREAM1 : + DPU_PLANE_SRC_TO_DISP_STREAM0); + + dev_dbg(dev, "[PLANE:%d:%s] fetcheco-0x%02x\n", + plane->base.id, plane->name, fe_id); + } + /* vscaler comes first */ if (need_vscaler) { vs_id = vscaler_get_block_id(vs); |