linux/drivers/gpu/drm/zte/zx_plane.c
<<
>>
Prefs
   1/*
   2 * Copyright 2016 Linaro Ltd.
   3 * Copyright 2016 ZTE Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 */
  10
  11#include <drm/drm_atomic.h>
  12#include <drm/drm_atomic_helper.h>
  13#include <drm/drm_fb_cma_helper.h>
  14#include <drm/drm_gem_cma_helper.h>
  15#include <drm/drm_modeset_helper_vtables.h>
  16#include <drm/drm_plane_helper.h>
  17#include <drm/drmP.h>
  18
  19#include "zx_drm_drv.h"
  20#include "zx_plane.h"
  21#include "zx_plane_regs.h"
  22#include "zx_vou.h"
  23
  24struct zx_plane {
  25        struct drm_plane plane;
  26        void __iomem *layer;
  27        void __iomem *csc;
  28        void __iomem *hbsc;
  29        void __iomem *rsz;
  30};
  31
  32#define to_zx_plane(plane)      container_of(plane, struct zx_plane, plane)
  33
  34static const uint32_t gl_formats[] = {
  35        DRM_FORMAT_ARGB8888,
  36        DRM_FORMAT_XRGB8888,
  37        DRM_FORMAT_RGB888,
  38        DRM_FORMAT_RGB565,
  39        DRM_FORMAT_ARGB1555,
  40        DRM_FORMAT_ARGB4444,
  41};
  42
  43static int zx_gl_plane_atomic_check(struct drm_plane *plane,
  44                                    struct drm_plane_state *plane_state)
  45{
  46        struct drm_framebuffer *fb = plane_state->fb;
  47        struct drm_crtc *crtc = plane_state->crtc;
  48        struct drm_crtc_state *crtc_state;
  49        struct drm_rect clip;
  50
  51        if (!crtc || !fb)
  52                return 0;
  53
  54        crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
  55                                                        crtc);
  56        if (WARN_ON(!crtc_state))
  57                return -EINVAL;
  58
  59        /* nothing to check when disabling or disabled */
  60        if (!crtc_state->enable)
  61                return 0;
  62
  63        /* plane must be enabled */
  64        if (!plane_state->crtc)
  65                return -EINVAL;
  66
  67        clip.x1 = 0;
  68        clip.y1 = 0;
  69        clip.x2 = crtc_state->adjusted_mode.hdisplay;
  70        clip.y2 = crtc_state->adjusted_mode.vdisplay;
  71
  72        return drm_plane_helper_check_state(plane_state, &clip,
  73                                            DRM_PLANE_HELPER_NO_SCALING,
  74                                            DRM_PLANE_HELPER_NO_SCALING,
  75                                            false, true);
  76}
  77
  78static int zx_gl_get_fmt(uint32_t format)
  79{
  80        switch (format) {
  81        case DRM_FORMAT_ARGB8888:
  82        case DRM_FORMAT_XRGB8888:
  83                return GL_FMT_ARGB8888;
  84        case DRM_FORMAT_RGB888:
  85                return GL_FMT_RGB888;
  86        case DRM_FORMAT_RGB565:
  87                return GL_FMT_RGB565;
  88        case DRM_FORMAT_ARGB1555:
  89                return GL_FMT_ARGB1555;
  90        case DRM_FORMAT_ARGB4444:
  91                return GL_FMT_ARGB4444;
  92        default:
  93                WARN_ONCE(1, "invalid pixel format %d\n", format);
  94                return -EINVAL;
  95        }
  96}
  97
  98static inline void zx_gl_set_update(struct zx_plane *zplane)
  99{
 100        void __iomem *layer = zplane->layer;
 101
 102        zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
 103}
 104
 105static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
 106{
 107        zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
 108}
 109
 110void zx_plane_set_update(struct drm_plane *plane)
 111{
 112        struct zx_plane *zplane = to_zx_plane(plane);
 113
 114        zx_gl_rsz_set_update(zplane);
 115        zx_gl_set_update(zplane);
 116}
 117
 118static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
 119                            u32 dst_w, u32 dst_h)
 120{
 121        void __iomem *rsz = zplane->rsz;
 122
 123        zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
 124        zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
 125
 126        zx_gl_rsz_set_update(zplane);
 127}
 128
 129static void zx_gl_plane_atomic_update(struct drm_plane *plane,
 130                                      struct drm_plane_state *old_state)
 131{
 132        struct zx_plane *zplane = to_zx_plane(plane);
 133        struct drm_framebuffer *fb = plane->state->fb;
 134        struct drm_gem_cma_object *cma_obj;
 135        void __iomem *layer = zplane->layer;
 136        void __iomem *csc = zplane->csc;
 137        void __iomem *hbsc = zplane->hbsc;
 138        u32 src_x, src_y, src_w, src_h;
 139        u32 dst_x, dst_y, dst_w, dst_h;
 140        unsigned int bpp;
 141        uint32_t format;
 142        dma_addr_t paddr;
 143        u32 stride;
 144        int fmt;
 145
 146        if (!fb)
 147                return;
 148
 149        format = fb->pixel_format;
 150        stride = fb->pitches[0];
 151
 152        src_x = plane->state->src_x >> 16;
 153        src_y = plane->state->src_y >> 16;
 154        src_w = plane->state->src_w >> 16;
 155        src_h = plane->state->src_h >> 16;
 156
 157        dst_x = plane->state->crtc_x;
 158        dst_y = plane->state->crtc_y;
 159        dst_w = plane->state->crtc_w;
 160        dst_h = plane->state->crtc_h;
 161
 162        bpp = drm_format_plane_cpp(format, 0);
 163
 164        cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
 165        paddr = cma_obj->paddr + fb->offsets[0];
 166        paddr += src_y * stride + src_x * bpp / 8;
 167        zx_writel(layer + GL_ADDR, paddr);
 168
 169        /* Set up source height/width register */
 170        zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
 171
 172        /* Set up start position register */
 173        zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
 174
 175        /* Set up end position register */
 176        zx_writel(layer + GL_POS_END,
 177                  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
 178
 179        /* Set up stride register */
 180        zx_writel(layer + GL_STRIDE, stride & 0xffff);
 181
 182        /* Set up graphic layer data format */
 183        fmt = zx_gl_get_fmt(format);
 184        if (fmt >= 0)
 185                zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
 186                               fmt << GL_DATA_FMT_SHIFT);
 187
 188        /* Initialize global alpha with a sane value */
 189        zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
 190                       0xff << GL_GLOBAL_ALPHA_SHIFT);
 191
 192        /* Setup CSC for the GL */
 193        if (dst_h > 720)
 194                zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
 195                               CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
 196        else
 197                zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
 198                               CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
 199        zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
 200
 201        /* Always use scaler since it exists (set for not bypass) */
 202        zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
 203                       GL_SCALER_BYPASS_MODE);
 204
 205        zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
 206
 207        /* Enable HBSC block */
 208        zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
 209
 210        zx_gl_set_update(zplane);
 211}
 212
 213static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
 214        .atomic_check = zx_gl_plane_atomic_check,
 215        .atomic_update = zx_gl_plane_atomic_update,
 216};
 217
 218static void zx_plane_destroy(struct drm_plane *plane)
 219{
 220        drm_plane_helper_disable(plane);
 221        drm_plane_cleanup(plane);
 222}
 223
 224static const struct drm_plane_funcs zx_plane_funcs = {
 225        .update_plane = drm_atomic_helper_update_plane,
 226        .disable_plane = drm_atomic_helper_disable_plane,
 227        .destroy = zx_plane_destroy,
 228        .reset = drm_atomic_helper_plane_reset,
 229        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 230        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 231};
 232
 233static void zx_plane_hbsc_init(struct zx_plane *zplane)
 234{
 235        void __iomem *hbsc = zplane->hbsc;
 236
 237        /*
 238         *  Initialize HBSC block with a sane configuration per recommedation
 239         *  from ZTE BSP code.
 240         */
 241        zx_writel(hbsc + HBSC_SATURATION, 0x200);
 242        zx_writel(hbsc + HBSC_HUE, 0x0);
 243        zx_writel(hbsc + HBSC_BRIGHT, 0x0);
 244        zx_writel(hbsc + HBSC_CONTRAST, 0x200);
 245
 246        zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
 247        zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
 248        zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
 249}
 250
 251struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
 252                                struct zx_layer_data *data,
 253                                enum drm_plane_type type)
 254{
 255        const struct drm_plane_helper_funcs *helper;
 256        struct zx_plane *zplane;
 257        struct drm_plane *plane;
 258        const uint32_t *formats;
 259        unsigned int format_count;
 260        int ret;
 261
 262        zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
 263        if (!zplane)
 264                return ERR_PTR(-ENOMEM);
 265
 266        plane = &zplane->plane;
 267
 268        zplane->layer = data->layer;
 269        zplane->hbsc = data->hbsc;
 270        zplane->csc = data->csc;
 271        zplane->rsz = data->rsz;
 272
 273        zx_plane_hbsc_init(zplane);
 274
 275        switch (type) {
 276        case DRM_PLANE_TYPE_PRIMARY:
 277                helper = &zx_gl_plane_helper_funcs;
 278                formats = gl_formats;
 279                format_count = ARRAY_SIZE(gl_formats);
 280                break;
 281        case DRM_PLANE_TYPE_OVERLAY:
 282                /* TODO: add video layer (vl) support */
 283                break;
 284        default:
 285                return ERR_PTR(-ENODEV);
 286        }
 287
 288        ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
 289                                       &zx_plane_funcs, formats, format_count,
 290                                       type, NULL);
 291        if (ret) {
 292                DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
 293                return ERR_PTR(ret);
 294        }
 295
 296        drm_plane_helper_add(plane, helper);
 297
 298        return plane;
 299}
 300