[PATCH v2] drm: zte: add overlay plane support

Sean Paul seanpaul at chromium.org
Thu Dec 22 06:56:01 PST 2016


On Tue, Dec 20, 2016 at 7:09 AM, Shawn Guo <shawnguo at kernel.org> wrote:
> From: Shawn Guo <shawn.guo at linaro.org>
>
> It enables VOU VL (Video Layer) to support overlay plane with scaling
> function.  VL0 has some quirks on scaling support.  We chose to skip it
> and only adds VL1 and VL2 into DRM core for now.
>
> Signed-off-by: Shawn Guo <shawn.guo at linaro.org>
> ---
> Changes for v2:
>  - Use clipped coordinates for overlay position calculation
>
>  drivers/gpu/drm/zte/zx_plane.c      | 293 ++++++++++++++++++++++++++++++++++--
>  drivers/gpu/drm/zte/zx_plane_regs.h |  51 +++++++
>  drivers/gpu/drm/zte/zx_vou.c        | 149 +++++++++++++++++-
>  drivers/gpu/drm/zte/zx_vou.h        |   3 +
>  drivers/gpu/drm/zte/zx_vou_regs.h   |  18 +++
>  5 files changed, 497 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
> index 546eb92a94e8..8cd7cf71b2b0 100644
> --- a/drivers/gpu/drm/zte/zx_plane.c
> +++ b/drivers/gpu/drm/zte/zx_plane.c
> @@ -40,6 +40,269 @@ struct zx_plane {
>         DRM_FORMAT_ARGB4444,
>  };
>
> +static const uint32_t vl_formats[] = {
> +       DRM_FORMAT_NV12,        /* Semi-planar YUV420 */
> +       DRM_FORMAT_YUV420,      /* Planar YUV420 */
> +       DRM_FORMAT_YUYV,        /* Packed YUV422 */
> +       DRM_FORMAT_YVYU,
> +       DRM_FORMAT_UYVY,
> +       DRM_FORMAT_VYUY,
> +       DRM_FORMAT_YUV444,      /* YUV444 8bit */
> +       /*
> +        * TODO: add formats below that HW supports:
> +        *  - YUV420 P010
> +        *  - YUV420 Hantro
> +        *  - YUV444 10bit
> +        */
> +};
> +
> +#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
> +
> +static int zx_vl_plane_atomic_check(struct drm_plane *plane,
> +                                   struct drm_plane_state *plane_state)
> +{
> +       struct drm_framebuffer *fb = plane_state->fb;
> +       struct drm_crtc *crtc = plane_state->crtc;
> +       struct drm_crtc_state *crtc_state;
> +       struct drm_rect clip;
> +       int min_scale = FRAC_16_16(1, 8);
> +       int max_scale = FRAC_16_16(8, 1);
> +
> +       if (!crtc || !fb)
> +               return 0;
> +
> +       crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
> +                                                       crtc);
> +       if (WARN_ON(!crtc_state))
> +               return -EINVAL;
> +
> +       /* nothing to check when disabling or disabled */
> +       if (!crtc_state->enable)
> +               return 0;
> +
> +       /* plane must be enabled */
> +       if (!plane_state->crtc)
> +               return -EINVAL;
> +
> +       clip.x1 = 0;
> +       clip.y1 = 0;
> +       clip.x2 = crtc_state->adjusted_mode.hdisplay;
> +       clip.y2 = crtc_state->adjusted_mode.vdisplay;
> +
> +       return drm_plane_helper_check_state(plane_state, &clip,
> +                                           min_scale, max_scale,
> +                                           true, true);
> +}
> +
> +static u32 zx_vl_get_fmt(uint32_t format)
> +{
> +       u32 val = 0;
> +
> +       switch (format) {
> +       case DRM_FORMAT_NV12:
> +               val = VL_FMT_YUV420;
> +               break;
> +       case DRM_FORMAT_YUV420:
> +               val = VL_YUV420_PLANAR | VL_FMT_YUV420;
> +               break;
> +       case DRM_FORMAT_YUYV:
> +               val = VL_YUV422_YUYV | VL_FMT_YUV422;
> +               break;
> +       case DRM_FORMAT_YVYU:
> +               val = VL_YUV422_YVYU | VL_FMT_YUV422;
> +               break;
> +       case DRM_FORMAT_UYVY:
> +               val = VL_YUV422_UYVY | VL_FMT_YUV422;
> +               break;
> +       case DRM_FORMAT_VYUY:
> +               val = VL_YUV422_VYUY | VL_FMT_YUV422;
> +               break;
> +       case DRM_FORMAT_YUV444:
> +               val = VL_FMT_YUV444_8BIT;
> +               break;
> +       default:
> +               WARN_ONCE(1, "invalid pixel format %d\n", format);
> +       }
> +
> +       return val;
> +}
> +
> +static inline void zx_vl_set_update(struct zx_plane *zplane)
> +{
> +       void __iomem *layer = zplane->layer;
> +
> +       zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
> +}
> +
> +static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
> +{
> +       zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
> +}
> +
> +static u32 zx_vl_rsz_get_fmt(uint32_t format)
> +{
> +       u32 val = 0;
> +
> +       switch (format) {
> +       case DRM_FORMAT_NV12:
> +       case DRM_FORMAT_YUV420:
> +               val = RSZ_VL_FMT_YCBCR420;
> +               break;
> +       case DRM_FORMAT_YUYV:
> +       case DRM_FORMAT_YVYU:
> +       case DRM_FORMAT_UYVY:
> +       case DRM_FORMAT_VYUY:
> +               val = RSZ_VL_FMT_YCBCR422;
> +               break;
> +       case DRM_FORMAT_YUV444:
> +               val = RSZ_VL_FMT_YCBCR444;
> +               break;
> +       default:
> +               WARN_ONCE(1, "invalid pixel format %d\n", format);
> +       }
> +
> +       return val;
> +}
> +
> +static inline u32 rsz_step_value(u32 src, u32 dst)
> +{
> +       u32 val = 0;
> +
> +       if (src == dst)
> +               val = 0;
> +       else if (src < dst)
> +               val = RSZ_PARA_STEP((src << 16) / dst);
> +       else if (src > dst)
> +               val = RSZ_DATA_STEP(src / dst) |
> +                     RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
> +
> +       return val;
> +}
> +
> +static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
> +                           u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
> +{
> +       void __iomem *rsz = zplane->rsz;
> +       u32 src_chroma_w = src_w;
> +       u32 src_chroma_h = src_h;
> +       u32 fmt;
> +
> +       /* Set up source and destination resolution */
> +       zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
> +       zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
> +
> +       /* Configure data format for VL RSZ */
> +       fmt = zx_vl_rsz_get_fmt(format);
> +       zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
> +
> +       /* Calculate Chroma heigth and width */
> +       if (fmt == RSZ_VL_FMT_YCBCR420) {
> +               src_chroma_w = src_w >> 1;
> +               src_chroma_h = src_h >> 1;
> +       } else if (fmt == RSZ_VL_FMT_YCBCR422) {
> +               src_chroma_w = src_w >> 1;
> +       }
> +
> +       /* Set up Luma and Chroma step registers */
> +       zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
> +       zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
> +       zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
> +       zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
> +
> +       zx_vl_rsz_set_update(zplane);
> +}
> +
> +static void zx_vl_plane_atomic_update(struct drm_plane *plane,
> +                                     struct drm_plane_state *old_state)
> +{
> +       struct zx_plane *zplane = to_zx_plane(plane);
> +       struct drm_plane_state *state = plane->state;
> +       struct drm_framebuffer *fb = state->fb;
> +       struct drm_rect *src = &state->src;
> +       struct drm_rect *dst = &state->dst;
> +       struct drm_gem_cma_object *cma_obj;
> +       void __iomem *layer = zplane->layer;
> +       void __iomem *hbsc = zplane->hbsc;
> +       void __iomem *paddr_reg;
> +       dma_addr_t paddr;
> +       u32 src_x, src_y, src_w, src_h;
> +       u32 dst_x, dst_y, dst_w, dst_h;
> +       uint32_t format;
> +       u32 fmt;
> +       int num_planes;
> +       int i;
> +
> +       if (!fb)
> +               return;
> +
> +       format = fb->pixel_format;
> +
> +       src_x = src->x1 >> 16;
> +       src_y = src->y1 >> 16;
> +       src_w = drm_rect_width(src) >> 16;
> +       src_h = drm_rect_height(src) >> 16;
> +
> +       dst_x = dst->x1;
> +       dst_y = dst->y1;
> +       dst_w = drm_rect_width(dst);
> +       dst_h = drm_rect_height(dst);
> +
> +       /* Set up data address registers for Y, Cb and Cr planes */
> +       num_planes = drm_format_num_planes(format);
> +       paddr_reg = layer + VL_Y;
> +       for (i = 0; i < num_planes; i++) {
> +               cma_obj = drm_fb_cma_get_gem_obj(fb, i);
> +               paddr = cma_obj->paddr + fb->offsets[i];
> +               paddr += src_y * fb->pitches[i];
> +               paddr += src_x * drm_format_plane_cpp(format, i);
> +               zx_writel(paddr_reg, paddr);
> +               paddr_reg += 4;
> +       }
> +
> +       /* Set up source height/width register */
> +       zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
> +
> +       /* Set up start position register */
> +       zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
> +
> +       /* Set up end position register */
> +       zx_writel(layer + VL_POS_END,
> +                 GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
> +
> +       /* Strides of Cb and Cr planes should be identical */
> +       zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
> +                 CHROMA_STRIDE(fb->pitches[1]));
> +
> +       /* Set up video layer data format */
> +       fmt = zx_vl_get_fmt(format);
> +       zx_writel(layer + VL_CTRL1, fmt);
> +
> +       /* Always use scaler since it exists (set for not bypass) */
> +       zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
> +                      VL_SCALER_BYPASS_MODE);
> +
> +       zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
> +
> +       /* Enable HBSC block */
> +       zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
> +
> +       zx_overlay_enable(plane);
> +
> +       zx_vl_set_update(zplane);
> +}
> +
> +static void zx_vl_plane_atomic_disable(struct drm_plane *plane,
> +                                      struct drm_plane_state *old_state)
> +{
> +       zx_overlay_disable(plane);
> +}
> +
> +static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
> +       .atomic_check = zx_vl_plane_atomic_check,
> +       .atomic_update = zx_vl_plane_atomic_update,
> +       .atomic_disable = zx_vl_plane_atomic_disable,
> +};
> +
>  static int zx_gl_plane_atomic_check(struct drm_plane *plane,
>                                     struct drm_plane_state *plane_state)
>  {
> @@ -107,14 +370,6 @@ static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
>         zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
>  }
>
> -void zx_plane_set_update(struct drm_plane *plane)
> -{
> -       struct zx_plane *zplane = to_zx_plane(plane);
> -
> -       zx_gl_rsz_set_update(zplane);
> -       zx_gl_set_update(zplane);
> -}
> -
>  static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
>                             u32 dst_w, u32 dst_h)
>  {
> @@ -230,6 +485,24 @@ static void zx_plane_destroy(struct drm_plane *plane)
>         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
>  };
>
> +void zx_plane_set_update(struct drm_plane *plane)
> +{
> +       struct zx_plane *zplane = to_zx_plane(plane);
> +
> +       switch (plane->type) {
> +       case DRM_PLANE_TYPE_PRIMARY:
> +               zx_gl_rsz_set_update(zplane);
> +               zx_gl_set_update(zplane);
> +               break;
> +       case DRM_PLANE_TYPE_OVERLAY:
> +               zx_vl_rsz_set_update(zplane);
> +               zx_vl_set_update(zplane);
> +               break;
> +       default:
> +               WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
> +       }
> +}
> +
>  static void zx_plane_hbsc_init(struct zx_plane *zplane)
>  {
>         void __iomem *hbsc = zplane->hbsc;
> @@ -279,7 +552,9 @@ struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
>                 format_count = ARRAY_SIZE(gl_formats);
>                 break;
>         case DRM_PLANE_TYPE_OVERLAY:
> -               /* TODO: add video layer (vl) support */
> +               helper = &zx_vl_plane_helper_funcs;
> +               formats = vl_formats;
> +               format_count = ARRAY_SIZE(vl_formats);
>                 break;
>         default:
>                 return ERR_PTR(-ENODEV);
> diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h
> index 3dde6716a558..65f271aeabed 100644
> --- a/drivers/gpu/drm/zte/zx_plane_regs.h
> +++ b/drivers/gpu/drm/zte/zx_plane_regs.h
> @@ -46,6 +46,37 @@
>  #define GL_POS_X(x)    (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK)
>  #define GL_POS_Y(x)    (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK)
>
> +/* VL registers */
> +#define VL_CTRL0                       0x00
> +#define VL_UPDATE                      BIT(3)
> +#define VL_CTRL1                       0x04
> +#define VL_YUV420_PLANAR               BIT(5)
> +#define VL_YUV422_SHIFT                        3
> +#define VL_YUV422_YUYV                 (0 << VL_YUV422_SHIFT)
> +#define VL_YUV422_YVYU                 (1 << VL_YUV422_SHIFT)
> +#define VL_YUV422_UYVY                 (2 << VL_YUV422_SHIFT)
> +#define VL_YUV422_VYUY                 (3 << VL_YUV422_SHIFT)
> +#define VL_FMT_YUV420                  0
> +#define VL_FMT_YUV422                  1
> +#define VL_FMT_YUV420_P010             2
> +#define VL_FMT_YUV420_HANTRO           3
> +#define VL_FMT_YUV444_8BIT             4
> +#define VL_FMT_YUV444_10BIT            5
> +#define VL_CTRL2                       0x08
> +#define VL_SCALER_BYPASS_MODE          BIT(0)
> +#define VL_STRIDE                      0x0c
> +#define LUMA_STRIDE_SHIFT              16
> +#define LUMA_STRIDE_MASK               (0xffff << LUMA_STRIDE_SHIFT)
> +#define CHROMA_STRIDE_SHIFT            0
> +#define CHROMA_STRIDE_MASK             (0xffff << CHROMA_STRIDE_SHIFT)
> +#define VL_SRC_SIZE                    0x10
> +#define VL_Y                           0x14
> +#define VL_POS_START                   0x30
> +#define VL_POS_END                     0x34
> +
> +#define LUMA_STRIDE(x)  (((x) << LUMA_STRIDE_SHIFT) & LUMA_STRIDE_MASK)
> +#define CHROMA_STRIDE(x) (((x) << CHROMA_STRIDE_SHIFT) & CHROMA_STRIDE_MASK)
> +
>  /* CSC registers */
>  #define CSC_CTRL0                      0x30
>  #define CSC_COV_MODE_SHIFT             16
> @@ -69,6 +100,18 @@
>  #define RSZ_DEST_CFG                   0x04
>  #define RSZ_ENABLE_CFG                 0x14
>
> +#define RSZ_VL_LUMA_HOR                        0x08
> +#define RSZ_VL_LUMA_VER                        0x0c
> +#define RSZ_VL_CHROMA_HOR              0x10
> +#define RSZ_VL_CHROMA_VER              0x14
> +#define RSZ_VL_CTRL_CFG                        0x18
> +#define RSZ_VL_FMT_SHIFT               3
> +#define RSZ_VL_FMT_MASK                        (0x3 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_FMT_YCBCR420            (0x0 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_FMT_YCBCR422            (0x1 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_FMT_YCBCR444            (0x2 << RSZ_VL_FMT_SHIFT)
> +#define RSZ_VL_ENABLE_CFG              0x1c
> +
>  #define RSZ_VER_SHIFT                  16
>  #define RSZ_VER_MASK                   (0xffff << RSZ_VER_SHIFT)
>  #define RSZ_HOR_SHIFT                  0
> @@ -77,6 +120,14 @@
>  #define RSZ_VER(x)     (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK)
>  #define RSZ_HOR(x)     (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK)
>
> +#define RSZ_DATA_STEP_SHIFT            16
> +#define RSZ_DATA_STEP_MASK             (0xffff << RSZ_DATA_STEP_SHIFT)
> +#define RSZ_PARA_STEP_SHIFT            0
> +#define RSZ_PARA_STEP_MASK             (0xffff << RSZ_PARA_STEP_SHIFT)
> +
> +#define RSZ_DATA_STEP(x) (((x) << RSZ_DATA_STEP_SHIFT) & RSZ_DATA_STEP_MASK)
> +#define RSZ_PARA_STEP(x) (((x) << RSZ_PARA_STEP_SHIFT) & RSZ_PARA_STEP_MASK)
> +
>  /* HBSC registers */
>  #define HBSC_SATURATION                        0x00
>  #define HBSC_HUE                       0x04
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index 73fe15c17c32..8ca9c4bdeeaf 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -93,10 +93,38 @@ struct zx_crtc {
>         const struct zx_crtc_bits *bits;
>         enum vou_chn_type chn_type;
>         struct clk *pixclk;
> +       u32 overlay_bitmap;
>  };
>
>  #define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc)
>
> +struct zx_vl_bits {
> +       u32 enable;
> +       u32 chnsel;
> +       u32 clksel;
> +};
> +
> +static const struct zx_vl_bits zx_vl_bits[VL_NUM] = {
> +       {
> +               .enable = OSD_CTRL0_VL0_EN,
> +               .chnsel = OSD_CTRL0_VL0_SEL,
> +               .clksel = VOU_CLK_VL0_SEL,
> +       }, {
> +               .enable = OSD_CTRL0_VL1_EN,
> +               .chnsel = OSD_CTRL0_VL1_SEL,
> +               .clksel = VOU_CLK_VL1_SEL,
> +       }, {
> +               .enable = OSD_CTRL0_VL2_EN,
> +               .chnsel = OSD_CTRL0_VL2_SEL,
> +               .clksel = VOU_CLK_VL2_SEL,
> +       },
> +};
> +
> +struct zx_overlay {
> +       struct drm_plane *plane;

If you subclass plane instead of storing the pointer, you don't need
to keep an array of overlays in vou_hw or the find_vl_idx function.

> +       const struct zx_vl_bits *bits;
> +};
> +
>  struct zx_vou_hw {
>         struct device *dev;
>         void __iomem *osd;
> @@ -110,6 +138,7 @@ struct zx_vou_hw {
>         struct clk *aux_clk;
>         struct zx_crtc *main_crtc;
>         struct zx_crtc *aux_crtc;
> +       struct zx_overlay overlays[VL_NUM];
>  };
>
>  static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
> @@ -404,6 +433,112 @@ void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe)
>                        zcrtc->bits->int_frame_mask, 0);
>  }
>
> +static int zx_overlay_find_vl_idx(struct drm_plane *plane,
> +                                 struct zx_vou_hw *vou)
> +{
> +       int i;
> +
> +       for (i = 0; i < VL_NUM; i++) {
> +               if (vou->overlays[i].plane == plane)
> +                       break;
> +       }
> +
> +       if (i == VL_NUM) {
> +               DRM_DEV_ERROR(vou->dev, "failed to find VL\n");
> +               return -EINVAL;
> +       }
> +
> +       return i;
> +}
> +
> +void zx_overlay_enable(struct drm_plane *plane)
> +{
> +       struct zx_crtc *zcrtc = to_zx_crtc(plane->state->crtc);
> +       struct zx_vou_hw *vou = zcrtc->vou;
> +       const struct zx_vl_bits *bits;
> +       int idx;
> +
> +       idx = zx_overlay_find_vl_idx(plane, vou);
> +       if (idx < 0)
> +               return;
> +
> +       bits = vou->overlays[idx].bits;
> +       zcrtc->overlay_bitmap |= 1 << idx;
> +
> +       if (zcrtc->chn_type == VOU_CHN_MAIN) {
> +               zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, 0);
> +               zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, 0);
> +       } else {
> +               zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel,
> +                              bits->chnsel);
> +               zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel,
> +                              bits->clksel);
> +       }
> +
> +       zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable);
> +}
> +
> +void zx_overlay_disable(struct drm_plane *plane)
> +{
> +       struct zx_crtc *zcrtc = to_zx_crtc(plane->crtc);
> +       struct zx_vou_hw *vou = zcrtc->vou;
> +       const struct zx_vl_bits *bits;
> +       int idx;
> +
> +       idx = zx_overlay_find_vl_idx(plane, vou);
> +       if (idx < 0)
> +               return;
> +
> +       bits = vou->overlays[idx].bits;
> +       zcrtc->overlay_bitmap &= ~(1 << idx);
> +
> +       zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0);
> +}
> +
> +static void zx_overlay_init(struct drm_device *drm, struct zx_vou_hw *vou)
> +{
> +       struct device *dev = vou->dev;
> +       struct drm_plane *plane;
> +       struct zx_layer_data data;
> +       int i;
> +
> +       /*
> +        * VL0 has some quirks on scaling support which need special handling.
> +        * Let's leave it out for now.
> +        */
> +       for (i = 1; i < VL_NUM; i++) {
> +               data.layer = vou->osd + OSD_VL_OFFSET(i);
> +               data.hbsc = vou->osd + HBSC_VL_OFFSET(i);
> +               data.rsz = vou->otfppu + RSZ_VL_OFFSET(i);
> +
> +               plane = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_OVERLAY);
> +               if (IS_ERR(plane)) {
> +                       DRM_DEV_ERROR(dev, "failed to init overlay %d\n", i);
> +                       continue;
> +               }
> +
> +               vou->overlays[i].plane = plane;
> +               vou->overlays[i].bits = &zx_vl_bits[i];
> +       }
> +}
> +
> +static inline void zx_osd_int_update(struct zx_crtc *zcrtc)
> +{
> +       u32 bitmap = zcrtc->overlay_bitmap;
> +       int i;
> +
> +       vou_chn_set_update(zcrtc);
> +       zx_plane_set_update(zcrtc->primary);
> +
> +       if (bitmap) {
> +               for (i = 0; i < VL_NUM; i++)  {
> +                       if ((bitmap & (1 << i)) == 0)
> +                               continue;
> +                       zx_plane_set_update(zcrtc->vou->overlays[i].plane);
> +               }
> +       }
> +}
> +
>  static irqreturn_t vou_irq_handler(int irq, void *dev_id)
>  {
>         struct zx_vou_hw *vou = dev_id;
> @@ -423,15 +558,11 @@ static irqreturn_t vou_irq_handler(int irq, void *dev_id)
>         state = zx_readl(vou->osd + OSD_INT_STA);
>         zx_writel(vou->osd + OSD_INT_CLRSTA, state);
>
> -       if (state & OSD_INT_MAIN_UPT) {
> -               vou_chn_set_update(vou->main_crtc);
> -               zx_plane_set_update(vou->main_crtc->primary);
> -       }
> +       if (state & OSD_INT_MAIN_UPT)
> +               zx_osd_int_update(vou->main_crtc);
>
> -       if (state & OSD_INT_AUX_UPT) {
> -               vou_chn_set_update(vou->aux_crtc);
> -               zx_plane_set_update(vou->aux_crtc->primary);
> -       }
> +       if (state & OSD_INT_AUX_UPT)
> +               zx_osd_int_update(vou->aux_crtc);
>
>         if (state & OSD_INT_ERROR)
>                 DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state);
> @@ -611,6 +742,8 @@ static int zx_crtc_bind(struct device *dev, struct device *master, void *data)
>                 goto disable_ppu_clk;
>         }
>
> +       zx_overlay_init(drm, vou);
> +
>         return 0;
>
>  disable_ppu_clk:
> diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
> index 349e06cd86f4..1559c1f79db7 100644
> --- a/drivers/gpu/drm/zte/zx_vou.h
> +++ b/drivers/gpu/drm/zte/zx_vou.h
> @@ -43,4 +43,7 @@ struct vou_inf {
>  int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
>  void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
>
> +void zx_overlay_enable(struct drm_plane *plane);
> +void zx_overlay_disable(struct drm_plane *plane);
> +
>  #endif /* __ZX_VOU_H__ */
> diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
> index f44e7a4ae441..193c1ce01fe7 100644
> --- a/drivers/gpu/drm/zte/zx_vou_regs.h
> +++ b/drivers/gpu/drm/zte/zx_vou_regs.h
> @@ -22,6 +22,15 @@
>  #define AUX_HBSC_OFFSET                        0x860
>  #define AUX_RSZ_OFFSET                 0x800
>
> +#define OSD_VL0_OFFSET                 0x040
> +#define OSD_VL_OFFSET(i)               (OSD_VL0_OFFSET + 0x050 * (i))
> +
> +#define HBSC_VL0_OFFSET                        0x760
> +#define HBSC_VL_OFFSET(i)              (HBSC_VL0_OFFSET + 0x040 * (i))
> +
> +#define RSZ_VL1_U0                     0xa00
> +#define RSZ_VL_OFFSET(i)               (RSZ_VL1_U0 + 0x200 * (i))
> +
>  /* OSD (GPC_GLOBAL) registers */
>  #define OSD_INT_STA                    0x04
>  #define OSD_INT_CLRSTA                 0x08
> @@ -42,6 +51,12 @@
>  )
>  #define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
>  #define OSD_CTRL0                      0x10
> +#define OSD_CTRL0_VL0_EN               BIT(13)
> +#define OSD_CTRL0_VL0_SEL              BIT(12)
> +#define OSD_CTRL0_VL1_EN               BIT(11)
> +#define OSD_CTRL0_VL1_SEL              BIT(10)
> +#define OSD_CTRL0_VL2_EN               BIT(9)
> +#define OSD_CTRL0_VL2_SEL              BIT(8)
>  #define OSD_CTRL0_GL0_EN               BIT(7)
>  #define OSD_CTRL0_GL0_SEL              BIT(6)
>  #define OSD_CTRL0_GL1_EN               BIT(5)
> @@ -146,6 +161,9 @@
>  #define VOU_INF_DATA_SEL               0x08
>  #define VOU_SOFT_RST                   0x14
>  #define VOU_CLK_SEL                    0x18
> +#define VOU_CLK_VL2_SEL                        BIT(8)
> +#define VOU_CLK_VL1_SEL                        BIT(7)
> +#define VOU_CLK_VL0_SEL                        BIT(6)
>  #define VOU_CLK_GL1_SEL                        BIT(5)
>  #define VOU_CLK_GL0_SEL                        BIT(4)
>  #define VOU_CLK_REQEN                  0x20
> --
> 1.9.1
>



-- 
Sean Paul, Software Engineer, Google / Chromium OS



More information about the linux-arm-kernel mailing list