linux/drivers/gpu/drm/tve200/tve200_display.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
   4 * Parts of this file were based on sources as follows:
   5 *
   6 * Copyright (C) 2006-2008 Intel Corporation
   7 * Copyright (C) 2007 Amos Lee <amos_lee@storlinksemi.com>
   8 * Copyright (C) 2007 Dave Airlie <airlied@linux.ie>
   9 * Copyright (C) 2011 Texas Instruments
  10 * Copyright (C) 2017 Eric Anholt
  11 */
  12#include <linux/clk.h>
  13#include <linux/version.h>
  14#include <linux/dma-buf.h>
  15#include <linux/of_graph.h>
  16
  17#include <drm/drmP.h>
  18#include <drm/drm_panel.h>
  19#include <drm/drm_gem_cma_helper.h>
  20#include <drm/drm_gem_framebuffer_helper.h>
  21#include <drm/drm_fb_cma_helper.h>
  22
  23#include "tve200_drm.h"
  24
  25irqreturn_t tve200_irq(int irq, void *data)
  26{
  27        struct tve200_drm_dev_private *priv = data;
  28        u32 stat;
  29        u32 val;
  30
  31        stat = readl(priv->regs + TVE200_INT_STAT);
  32
  33        if (!stat)
  34                return IRQ_NONE;
  35
  36        /*
  37         * Vblank IRQ
  38         *
  39         * The hardware is a bit tilted: the line stays high after clearing
  40         * the vblank IRQ, firing many more interrupts. We counter this
  41         * by toggling the IRQ back and forth from firing at vblank and
  42         * firing at start of active image, which works around the problem
  43         * since those occur strictly in sequence, and we get two IRQs for each
  44         * frame, one at start of Vblank (that we make call into the CRTC) and
  45         * another one at the start of the image (that we discard).
  46         */
  47        if (stat & TVE200_INT_V_STATUS) {
  48                val = readl(priv->regs + TVE200_CTRL);
  49                /* We have an actual start of vsync */
  50                if (!(val & TVE200_VSTSTYPE_BITS)) {
  51                        drm_crtc_handle_vblank(&priv->pipe.crtc);
  52                        /* Toggle trigger to start of active image */
  53                        val |= TVE200_VSTSTYPE_VAI;
  54                } else {
  55                        /* Toggle trigger back to start of vsync */
  56                        val &= ~TVE200_VSTSTYPE_BITS;
  57                }
  58                writel(val, priv->regs + TVE200_CTRL);
  59        } else
  60                dev_err(priv->drm->dev, "stray IRQ %08x\n", stat);
  61
  62        /* Clear the interrupt once done */
  63        writel(stat, priv->regs + TVE200_INT_CLR);
  64
  65        return IRQ_HANDLED;
  66}
  67
  68static int tve200_display_check(struct drm_simple_display_pipe *pipe,
  69                               struct drm_plane_state *pstate,
  70                               struct drm_crtc_state *cstate)
  71{
  72        const struct drm_display_mode *mode = &cstate->mode;
  73        struct drm_framebuffer *old_fb = pipe->plane.state->fb;
  74        struct drm_framebuffer *fb = pstate->fb;
  75
  76        /*
  77         * We support these specific resolutions and nothing else.
  78         */
  79        if (!(mode->hdisplay == 352 && mode->vdisplay == 240) && /* SIF(525) */
  80            !(mode->hdisplay == 352 && mode->vdisplay == 288) && /* CIF(625) */
  81            !(mode->hdisplay == 640 && mode->vdisplay == 480) && /* VGA */
  82            !(mode->hdisplay == 720 && mode->vdisplay == 480) && /* D1 */
  83            !(mode->hdisplay == 720 && mode->vdisplay == 576)) { /* D1 */
  84                DRM_DEBUG_KMS("unsupported display mode (%u x %u)\n",
  85                        mode->hdisplay, mode->vdisplay);
  86                return -EINVAL;
  87        }
  88
  89        if (fb) {
  90                u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0);
  91
  92                /* FB base address must be dword aligned. */
  93                if (offset & 3) {
  94                        DRM_DEBUG_KMS("FB not 32-bit aligned\n");
  95                        return -EINVAL;
  96                }
  97
  98                /*
  99                 * There's no pitch register, the mode's hdisplay
 100                 * controls this.
 101                 */
 102                if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) {
 103                        DRM_DEBUG_KMS("can't handle pitches\n");
 104                        return -EINVAL;
 105                }
 106
 107                /*
 108                 * We can't change the FB format in a flicker-free
 109                 * manner (and only update it during CRTC enable).
 110                 */
 111                if (old_fb && old_fb->format != fb->format)
 112                        cstate->mode_changed = true;
 113        }
 114
 115        return 0;
 116}
 117
 118static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
 119                                 struct drm_crtc_state *cstate,
 120                                 struct drm_plane_state *plane_state)
 121{
 122        struct drm_crtc *crtc = &pipe->crtc;
 123        struct drm_plane *plane = &pipe->plane;
 124        struct drm_device *drm = crtc->dev;
 125        struct tve200_drm_dev_private *priv = drm->dev_private;
 126        const struct drm_display_mode *mode = &cstate->mode;
 127        struct drm_framebuffer *fb = plane->state->fb;
 128        struct drm_connector *connector = priv->connector;
 129        u32 format = fb->format->format;
 130        u32 ctrl1 = 0;
 131
 132        clk_prepare_enable(priv->clk);
 133
 134        /* Function 1 */
 135        ctrl1 |= TVE200_CTRL_CSMODE;
 136        /* Interlace mode for CCIR656: parameterize? */
 137        ctrl1 |= TVE200_CTRL_NONINTERLACE;
 138        /* 32 words per burst */
 139        ctrl1 |= TVE200_CTRL_BURST_32_WORDS;
 140        /* 16 retries */
 141        ctrl1 |= TVE200_CTRL_RETRYCNT_16;
 142        /* NTSC mode: parametrize? */
 143        ctrl1 |= TVE200_CTRL_NTSC;
 144
 145        /* Vsync IRQ at start of Vsync at first */
 146        ctrl1 |= TVE200_VSTSTYPE_VSYNC;
 147
 148        if (connector->display_info.bus_flags &
 149            DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
 150                ctrl1 |= TVE200_CTRL_TVCLKP;
 151
 152        if ((mode->hdisplay == 352 && mode->vdisplay == 240) || /* SIF(525) */
 153            (mode->hdisplay == 352 && mode->vdisplay == 288)) { /* CIF(625) */
 154                ctrl1 |= TVE200_CTRL_IPRESOL_CIF;
 155                dev_info(drm->dev, "CIF mode\n");
 156        } else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
 157                ctrl1 |= TVE200_CTRL_IPRESOL_VGA;
 158                dev_info(drm->dev, "VGA mode\n");
 159        } else if ((mode->hdisplay == 720 && mode->vdisplay == 480) ||
 160                   (mode->hdisplay == 720 && mode->vdisplay == 576)) {
 161                ctrl1 |= TVE200_CTRL_IPRESOL_D1;
 162                dev_info(drm->dev, "D1 mode\n");
 163        }
 164
 165        if (format & DRM_FORMAT_BIG_ENDIAN) {
 166                ctrl1 |= TVE200_CTRL_BBBP;
 167                format &= ~DRM_FORMAT_BIG_ENDIAN;
 168        }
 169
 170        switch (format) {
 171        case DRM_FORMAT_XRGB8888:
 172                ctrl1 |= TVE200_IPDMOD_RGB888;
 173                break;
 174        case DRM_FORMAT_RGB565:
 175                ctrl1 |= TVE200_IPDMOD_RGB565;
 176                break;
 177        case DRM_FORMAT_XRGB1555:
 178                ctrl1 |= TVE200_IPDMOD_RGB555;
 179                break;
 180        case DRM_FORMAT_XBGR8888:
 181                ctrl1 |= TVE200_IPDMOD_RGB888 | TVE200_BGR;
 182                break;
 183        case DRM_FORMAT_BGR565:
 184                ctrl1 |= TVE200_IPDMOD_RGB565 | TVE200_BGR;
 185                break;
 186        case DRM_FORMAT_XBGR1555:
 187                ctrl1 |= TVE200_IPDMOD_RGB555 | TVE200_BGR;
 188                break;
 189        case DRM_FORMAT_YUYV:
 190                ctrl1 |= TVE200_IPDMOD_YUV422;
 191                ctrl1 |= TVE200_CTRL_YCBCRODR_CR0Y1CB0Y0;
 192                break;
 193        case DRM_FORMAT_YVYU:
 194                ctrl1 |= TVE200_IPDMOD_YUV422;
 195                ctrl1 |= TVE200_CTRL_YCBCRODR_CB0Y1CR0Y0;
 196                break;
 197        case DRM_FORMAT_UYVY:
 198                ctrl1 |= TVE200_IPDMOD_YUV422;
 199                ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CR0Y0CB0;
 200                break;
 201        case DRM_FORMAT_VYUY:
 202                ctrl1 |= TVE200_IPDMOD_YUV422;
 203                ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CB0Y0CR0;
 204                break;
 205        case DRM_FORMAT_YUV420:
 206                ctrl1 |= TVE200_CTRL_YUV420;
 207                ctrl1 |= TVE200_IPDMOD_YUV420;
 208                break;
 209        default:
 210                dev_err(drm->dev, "Unknown FB format 0x%08x\n",
 211                        fb->format->format);
 212                break;
 213        }
 214
 215        ctrl1 |= TVE200_TVEEN;
 216
 217        /* Turn it on */
 218        writel(ctrl1, priv->regs + TVE200_CTRL);
 219
 220        drm_crtc_vblank_on(crtc);
 221}
 222
 223static void tve200_display_disable(struct drm_simple_display_pipe *pipe)
 224{
 225        struct drm_crtc *crtc = &pipe->crtc;
 226        struct drm_device *drm = crtc->dev;
 227        struct tve200_drm_dev_private *priv = drm->dev_private;
 228
 229        drm_crtc_vblank_off(crtc);
 230
 231        /* Disable and Power Down */
 232        writel(0, priv->regs + TVE200_CTRL);
 233
 234        clk_disable_unprepare(priv->clk);
 235}
 236
 237static void tve200_display_update(struct drm_simple_display_pipe *pipe,
 238                                 struct drm_plane_state *old_pstate)
 239{
 240        struct drm_crtc *crtc = &pipe->crtc;
 241        struct drm_device *drm = crtc->dev;
 242        struct tve200_drm_dev_private *priv = drm->dev_private;
 243        struct drm_pending_vblank_event *event = crtc->state->event;
 244        struct drm_plane *plane = &pipe->plane;
 245        struct drm_plane_state *pstate = plane->state;
 246        struct drm_framebuffer *fb = pstate->fb;
 247
 248        if (fb) {
 249                /* For RGB, the Y component is used as base address */
 250                writel(drm_fb_cma_get_gem_addr(fb, pstate, 0),
 251                       priv->regs + TVE200_Y_FRAME_BASE_ADDR);
 252
 253                /* For three plane YUV we need two more addresses */
 254                if (fb->format->format == DRM_FORMAT_YUV420) {
 255                        writel(drm_fb_cma_get_gem_addr(fb, pstate, 1),
 256                               priv->regs + TVE200_U_FRAME_BASE_ADDR);
 257                        writel(drm_fb_cma_get_gem_addr(fb, pstate, 2),
 258                               priv->regs + TVE200_V_FRAME_BASE_ADDR);
 259                }
 260        }
 261
 262        if (event) {
 263                crtc->state->event = NULL;
 264
 265                spin_lock_irq(&crtc->dev->event_lock);
 266                if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
 267                        drm_crtc_arm_vblank_event(crtc, event);
 268                else
 269                        drm_crtc_send_vblank_event(crtc, event);
 270                spin_unlock_irq(&crtc->dev->event_lock);
 271        }
 272}
 273
 274static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
 275{
 276        struct drm_crtc *crtc = &pipe->crtc;
 277        struct drm_device *drm = crtc->dev;
 278        struct tve200_drm_dev_private *priv = drm->dev_private;
 279
 280        writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN);
 281        return 0;
 282}
 283
 284static void tve200_display_disable_vblank(struct drm_simple_display_pipe *pipe)
 285{
 286        struct drm_crtc *crtc = &pipe->crtc;
 287        struct drm_device *drm = crtc->dev;
 288        struct tve200_drm_dev_private *priv = drm->dev_private;
 289
 290        writel(0, priv->regs + TVE200_INT_EN);
 291}
 292
 293static const struct drm_simple_display_pipe_funcs tve200_display_funcs = {
 294        .check = tve200_display_check,
 295        .enable = tve200_display_enable,
 296        .disable = tve200_display_disable,
 297        .update = tve200_display_update,
 298        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 299        .enable_vblank = tve200_display_enable_vblank,
 300        .disable_vblank = tve200_display_disable_vblank,
 301};
 302
 303int tve200_display_init(struct drm_device *drm)
 304{
 305        struct tve200_drm_dev_private *priv = drm->dev_private;
 306        int ret;
 307        static const u32 formats[] = {
 308                DRM_FORMAT_XRGB8888,
 309                DRM_FORMAT_XBGR8888,
 310                DRM_FORMAT_RGB565,
 311                DRM_FORMAT_BGR565,
 312                DRM_FORMAT_XRGB1555,
 313                DRM_FORMAT_XBGR1555,
 314                /*
 315                 * The controller actually supports any YCbCr ordering,
 316                 * for packed YCbCr. This just lists the orderings that
 317                 * DRM supports.
 318                 */
 319                DRM_FORMAT_YUYV,
 320                DRM_FORMAT_YVYU,
 321                DRM_FORMAT_UYVY,
 322                DRM_FORMAT_VYUY,
 323                /* This uses three planes */
 324                DRM_FORMAT_YUV420,
 325        };
 326
 327        ret = drm_simple_display_pipe_init(drm, &priv->pipe,
 328                                           &tve200_display_funcs,
 329                                           formats, ARRAY_SIZE(formats),
 330                                           NULL,
 331                                           priv->connector);
 332        if (ret)
 333                return ret;
 334
 335        return 0;
 336}
 337