root/drivers/gpu/drm/tve200/tve200_display.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tve200_irq
  2. tve200_display_check
  3. tve200_display_enable
  4. tve200_display_disable
  5. tve200_display_update
  6. tve200_display_enable_vblank
  7. tve200_display_disable_vblank
  8. tve200_display_init

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

/* [<][>][^][v][top][bottom][index][help] */