[PATCH 7/7] drm/imx: ipuv3-plane: add support for separate alpha planes
Daniel Vetter
daniel at ffwll.ch
Tue May 19 09:58:08 PDT 2015
On Tue, May 19, 2015 at 06:06:01PM +0200, Philipp Zabel wrote:
> The IPUv3 can read 8-bit alpha values from a separate plane buffer using a
> companion IDMAC channel driven by the Alpha Transparency Controller (ATC)
> for the graphics channels. The conditional read mechanism allows to reduce
> memory bandwidth by skipping reads of color data for completely transparent
> bursts.
>
> Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
> ---
> drivers/gpu/drm/imx/ipuv3-plane.c | 72 +++++++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/imx/ipuv3-plane.h | 2 ++
> 2 files changed, 74 insertions(+)
>
> diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
> index d030990..ca10d55 100644
> --- a/drivers/gpu/drm/imx/ipuv3-plane.c
> +++ b/drivers/gpu/drm/imx/ipuv3-plane.c
> @@ -41,6 +41,12 @@ static const uint32_t ipu_plane_formats[] = {
> DRM_FORMAT_YVYU,
> DRM_FORMAT_YUV420,
> DRM_FORMAT_YVU420,
> + DRM_FORMAT_RGB565_A8,
> + DRM_FORMAT_BGR565_A8,
> + DRM_FORMAT_RGB888_A8,
> + DRM_FORMAT_BGR888_A8,
> + DRM_FORMAT_RGBX8888_A8,
> + DRM_FORMAT_BGRX8888_A8,
> };
>
> int ipu_plane_irq(struct ipu_plane *ipu_plane)
> @@ -71,6 +77,7 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
> int x, int y)
> {
> struct drm_gem_cma_object *cma_obj;
> + unsigned long alpha_eba = 0;
> unsigned long eba;
> int active;
>
> @@ -86,13 +93,36 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
> eba = cma_obj->paddr + fb->offsets[0] +
> fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
>
> + switch (fb->pixel_format) {
> + case DRM_FORMAT_RGB565_A8:
> + case DRM_FORMAT_BGR565_A8:
> + case DRM_FORMAT_RGB888_A8:
> + case DRM_FORMAT_BGR888_A8:
> + case DRM_FORMAT_RGBX8888_A8:
> + case DRM_FORMAT_BGRX8888_A8:
> + alpha_eba = cma_obj->paddr + fb->offsets[1] +
> + fb->pitches[1] * y + x;
You need to look at the 2nd cma_obj here, i.e. drm_fb_cma_get_gem_obj(fb, 1);
Yes, userspace is allowed to hand in non-matching. And given that you
you just reuse the cma helpers and don't reject framebuffers with
non-matching cma objects your current planar yuv support is also already
broken. Would be good if you could also patch modetest a bit to exercise
this ...
-Daniel
> + break;
> + }
> +
> if (ipu_plane->enabled) {
> active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
> ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
> ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
> + if (alpha_eba) {
> + active = ipu_idmac_get_current_buffer(
> + ipu_plane->alpha_ch);
> + ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
> + alpha_eba);
> + ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
> + }
> } else {
> ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
> ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
> + if (alpha_eba) {
> + ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
> + ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
> + }
> }
>
> /* cache offsets for subsequent pageflips */
> @@ -163,6 +193,7 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
> return ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
> }
>
> + ipu_plane->separate_alpha = false;
> switch (ipu_plane->dp_flow) {
> case IPU_DP_FLOW_SYNC_BG:
> ret = ipu_dp_setup_channel(ipu_plane->dp,
> @@ -183,6 +214,16 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
> ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
> /* Enable local alpha on partial plane */
> switch (fb->pixel_format) {
> + case DRM_FORMAT_RGB565_A8:
> + case DRM_FORMAT_BGR565_A8:
> + case DRM_FORMAT_RGB888_A8:
> + case DRM_FORMAT_BGR888_A8:
> + case DRM_FORMAT_RGBX8888_A8:
> + case DRM_FORMAT_BGRX8888_A8:
> + if (!ipu_plane->alpha_ch)
> + return -EINVAL;
> + ipu_plane->separate_alpha = true;
> + /* fallthrough */
> case DRM_FORMAT_ARGB1555:
> case DRM_FORMAT_ABGR1555:
> case DRM_FORMAT_RGBA5551:
> @@ -224,6 +265,18 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
> ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
> ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
>
> + if (ipu_plane->separate_alpha) {
> + ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
> +
> + ipu_cpmem_zero(ipu_plane->alpha_ch);
> + ipu_cpmem_set_resolution(ipu_plane->alpha_ch, src_w, src_h);
> + ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
> + ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
> + ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
> + ipu_cpmem_set_stride(ipu_plane->alpha_ch, fb->pitches[1]);
> + ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
> + }
> +
> ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
> if (ret < 0)
> return ret;
> @@ -244,11 +297,14 @@ void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
> ipu_dmfc_put(ipu_plane->dmfc);
> if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
> ipu_idmac_put(ipu_plane->ipu_ch);
> + if (!IS_ERR_OR_NULL(ipu_plane->alpha_ch))
> + ipu_idmac_put(ipu_plane->alpha_ch);
> }
>
> int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
> {
> int ret;
> + int alpha_ch;
>
> ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
> if (IS_ERR(ipu_plane->ipu_ch)) {
> @@ -257,6 +313,18 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
> return ret;
> }
>
> + alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
> + if (alpha_ch >= 0) {
> + ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
> + if (IS_ERR(ipu_plane->alpha_ch)) {
> + ipu_idmac_put(ipu_plane->ipu_ch);
> + ret = PTR_ERR(ipu_plane->alpha_ch);
> + DRM_ERROR("failed to get alpha idmac channel %d: %d\n",
> + alpha_ch, ret);
> + return ret;
> + }
> + }
> +
> ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
> if (IS_ERR(ipu_plane->dmfc)) {
> ret = PTR_ERR(ipu_plane->dmfc);
> @@ -286,6 +354,8 @@ void ipu_plane_enable(struct ipu_plane *ipu_plane)
> ipu_dp_enable(ipu_plane->ipu);
> ipu_dmfc_enable_channel(ipu_plane->dmfc);
> ipu_idmac_enable_channel(ipu_plane->ipu_ch);
> + if (ipu_plane->separate_alpha)
> + ipu_idmac_enable_channel(ipu_plane->alpha_ch);
> if (ipu_plane->dp)
> ipu_dp_enable_channel(ipu_plane->dp);
>
> @@ -300,6 +370,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane)
>
> if (ipu_plane->dp)
> ipu_dp_disable_channel(ipu_plane->dp);
> + if (ipu_plane->separate_alpha)
> + ipu_idmac_disable_channel(ipu_plane->alpha_ch);
> ipu_idmac_disable_channel(ipu_plane->ipu_ch);
> ipu_dmfc_disable_channel(ipu_plane->dmfc);
> if (ipu_plane->dp)
> diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h
> index 9b5eff1..c8913ed 100644
> --- a/drivers/gpu/drm/imx/ipuv3-plane.h
> +++ b/drivers/gpu/drm/imx/ipuv3-plane.h
> @@ -18,6 +18,7 @@ struct ipu_plane {
>
> struct ipu_soc *ipu;
> struct ipuv3_channel *ipu_ch;
> + struct ipuv3_channel *alpha_ch;
> struct dmfc_channel *dmfc;
> struct ipu_dp *dp;
>
> @@ -30,6 +31,7 @@ struct ipu_plane {
> int h;
>
> bool enabled;
> + bool separate_alpha;
> };
>
> struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
> --
> 2.1.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the dri-devel
mailing list