linux/drivers/gpu/drm/meson/meson_crtc.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 BayLibre, SAS
   3 * Author: Neil Armstrong <narmstrong@baylibre.com>
   4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
   5 * Copyright (C) 2014 Endless Mobile
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of the
  10 * License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  19 *
  20 * Written by:
  21 *     Jasper St. Pierre <jstpierre@mecheye.net>
  22 */
  23
  24#include <linux/kernel.h>
  25#include <linux/module.h>
  26#include <linux/mutex.h>
  27#include <linux/platform_device.h>
  28#include <drm/drmP.h>
  29#include <drm/drm_atomic.h>
  30#include <drm/drm_atomic_helper.h>
  31#include <drm/drm_flip_work.h>
  32#include <drm/drm_crtc_helper.h>
  33
  34#include "meson_crtc.h"
  35#include "meson_plane.h"
  36#include "meson_vpp.h"
  37#include "meson_viu.h"
  38#include "meson_registers.h"
  39
  40/* CRTC definition */
  41
  42struct meson_crtc {
  43        struct drm_crtc base;
  44        struct drm_pending_vblank_event *event;
  45        struct meson_drm *priv;
  46};
  47#define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
  48
  49/* CRTC */
  50
  51static const struct drm_crtc_funcs meson_crtc_funcs = {
  52        .atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,
  53        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  54        .destroy                = drm_crtc_cleanup,
  55        .page_flip              = drm_atomic_helper_page_flip,
  56        .reset                  = drm_atomic_helper_crtc_reset,
  57        .set_config             = drm_atomic_helper_set_config,
  58};
  59
  60static void meson_crtc_enable(struct drm_crtc *crtc)
  61{
  62        struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
  63        struct drm_plane *plane = meson_crtc->priv->primary_plane;
  64        struct meson_drm *priv = meson_crtc->priv;
  65
  66        /* Enable VPP Postblend */
  67        writel(plane->state->crtc_w,
  68               priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
  69
  70        writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
  71                            priv->io_base + _REG(VPP_MISC));
  72
  73        priv->viu.osd1_enabled = true;
  74}
  75
  76static void meson_crtc_disable(struct drm_crtc *crtc)
  77{
  78        struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
  79        struct meson_drm *priv = meson_crtc->priv;
  80
  81        priv->viu.osd1_enabled = false;
  82
  83        /* Disable VPP Postblend */
  84        writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
  85                            priv->io_base + _REG(VPP_MISC));
  86
  87        if (crtc->state->event && !crtc->state->active) {
  88                spin_lock_irq(&crtc->dev->event_lock);
  89                drm_crtc_send_vblank_event(crtc, crtc->state->event);
  90                spin_unlock_irq(&crtc->dev->event_lock);
  91
  92                crtc->state->event = NULL;
  93        }
  94}
  95
  96static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
  97                                    struct drm_crtc_state *state)
  98{
  99        struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 100        unsigned long flags;
 101
 102        if (crtc->state->event) {
 103                WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 104
 105                spin_lock_irqsave(&crtc->dev->event_lock, flags);
 106                meson_crtc->event = crtc->state->event;
 107                spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 108                crtc->state->event = NULL;
 109        }
 110}
 111
 112static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
 113                                    struct drm_crtc_state *old_crtc_state)
 114{
 115        struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 116        struct meson_drm *priv = meson_crtc->priv;
 117
 118        if (priv->viu.osd1_enabled)
 119                priv->viu.osd1_commit = true;
 120}
 121
 122static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
 123        .enable         = meson_crtc_enable,
 124        .disable        = meson_crtc_disable,
 125        .atomic_begin   = meson_crtc_atomic_begin,
 126        .atomic_flush   = meson_crtc_atomic_flush,
 127};
 128
 129void meson_crtc_irq(struct meson_drm *priv)
 130{
 131        struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc);
 132        unsigned long flags;
 133
 134        /* Update the OSD registers */
 135        if (priv->viu.osd1_enabled && priv->viu.osd1_commit) {
 136                writel_relaxed(priv->viu.osd1_ctrl_stat,
 137                                priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
 138                writel_relaxed(priv->viu.osd1_blk0_cfg[0],
 139                                priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0));
 140                writel_relaxed(priv->viu.osd1_blk0_cfg[1],
 141                                priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1));
 142                writel_relaxed(priv->viu.osd1_blk0_cfg[2],
 143                                priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2));
 144                writel_relaxed(priv->viu.osd1_blk0_cfg[3],
 145                                priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
 146                writel_relaxed(priv->viu.osd1_blk0_cfg[4],
 147                                priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
 148
 149                /* If output is interlace, make use of the Scaler */
 150                if (priv->viu.osd1_interlace) {
 151                        struct drm_plane *plane = priv->primary_plane;
 152                        struct drm_plane_state *state = plane->state;
 153                        struct drm_rect dest = {
 154                                .x1 = state->crtc_x,
 155                                .y1 = state->crtc_y,
 156                                .x2 = state->crtc_x + state->crtc_w,
 157                                .y2 = state->crtc_y + state->crtc_h,
 158                        };
 159
 160                        meson_vpp_setup_interlace_vscaler_osd1(priv, &dest);
 161                } else
 162                        meson_vpp_disable_interlace_vscaler_osd1(priv);
 163
 164                /* Enable OSD1 */
 165                writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
 166                                    priv->io_base + _REG(VPP_MISC));
 167
 168                priv->viu.osd1_commit = false;
 169        }
 170
 171        drm_crtc_handle_vblank(priv->crtc);
 172
 173        spin_lock_irqsave(&priv->drm->event_lock, flags);
 174        if (meson_crtc->event) {
 175                drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
 176                drm_crtc_vblank_put(priv->crtc);
 177                meson_crtc->event = NULL;
 178        }
 179        spin_unlock_irqrestore(&priv->drm->event_lock, flags);
 180}
 181
 182int meson_crtc_create(struct meson_drm *priv)
 183{
 184        struct meson_crtc *meson_crtc;
 185        struct drm_crtc *crtc;
 186        int ret;
 187
 188        meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
 189                                  GFP_KERNEL);
 190        if (!meson_crtc)
 191                return -ENOMEM;
 192
 193        meson_crtc->priv = priv;
 194        crtc = &meson_crtc->base;
 195        ret = drm_crtc_init_with_planes(priv->drm, crtc,
 196                                        priv->primary_plane, NULL,
 197                                        &meson_crtc_funcs, "meson_crtc");
 198        if (ret) {
 199                dev_err(priv->drm->dev, "Failed to init CRTC\n");
 200                return ret;
 201        }
 202
 203        drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs);
 204
 205        priv->crtc = crtc;
 206
 207        return 0;
 208}
 209