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

Reply via email to