linux/drivers/gpu/drm/exynos/exynos_drm_crtc.c
<<
>>
Prefs
   1/* exynos_drm_crtc.c
   2 *
   3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
   4 * Authors:
   5 *      Inki Dae <inki.dae@samsung.com>
   6 *      Joonyoung Shim <jy0922.shim@samsung.com>
   7 *      Seung-Woo Kim <sw0312.kim@samsung.com>
   8 *
   9 * This program is free software; you can redistribute  it and/or modify it
  10 * under  the terms of  the GNU General  Public License as published by the
  11 * Free Software Foundation;  either version 2 of the  License, or (at your
  12 * option) any later version.
  13 */
  14
  15#include <drm/drmP.h>
  16#include <drm/drm_crtc_helper.h>
  17#include <drm/drm_atomic.h>
  18#include <drm/drm_atomic_helper.h>
  19#include <drm/drm_encoder.h>
  20
  21#include "exynos_drm_crtc.h"
  22#include "exynos_drm_drv.h"
  23#include "exynos_drm_plane.h"
  24
  25static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc,
  26                                          struct drm_crtc_state *old_state)
  27{
  28        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
  29
  30        if (exynos_crtc->ops->enable)
  31                exynos_crtc->ops->enable(exynos_crtc);
  32
  33        drm_crtc_vblank_on(crtc);
  34}
  35
  36static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc,
  37                                           struct drm_crtc_state *old_state)
  38{
  39        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
  40
  41        drm_crtc_vblank_off(crtc);
  42
  43        if (exynos_crtc->ops->disable)
  44                exynos_crtc->ops->disable(exynos_crtc);
  45
  46        if (crtc->state->event && !crtc->state->active) {
  47                spin_lock_irq(&crtc->dev->event_lock);
  48                drm_crtc_send_vblank_event(crtc, crtc->state->event);
  49                spin_unlock_irq(&crtc->dev->event_lock);
  50
  51                crtc->state->event = NULL;
  52        }
  53}
  54
  55static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
  56                                     struct drm_crtc_state *state)
  57{
  58        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
  59
  60        if (!state->enable)
  61                return 0;
  62
  63        if (exynos_crtc->ops->atomic_check)
  64                return exynos_crtc->ops->atomic_check(exynos_crtc, state);
  65
  66        return 0;
  67}
  68
  69static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
  70                                     struct drm_crtc_state *old_crtc_state)
  71{
  72        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
  73
  74        if (exynos_crtc->ops->atomic_begin)
  75                exynos_crtc->ops->atomic_begin(exynos_crtc);
  76}
  77
  78static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
  79                                     struct drm_crtc_state *old_crtc_state)
  80{
  81        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
  82
  83        if (exynos_crtc->ops->atomic_flush)
  84                exynos_crtc->ops->atomic_flush(exynos_crtc);
  85}
  86
  87static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc,
  88        const struct drm_display_mode *mode)
  89{
  90        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
  91
  92        if (exynos_crtc->ops->mode_valid)
  93                return exynos_crtc->ops->mode_valid(exynos_crtc, mode);
  94
  95        return MODE_OK;
  96}
  97
  98static bool exynos_crtc_mode_fixup(struct drm_crtc *crtc,
  99                const struct drm_display_mode *mode,
 100                struct drm_display_mode *adjusted_mode)
 101{
 102        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 103
 104        if (exynos_crtc->ops->mode_fixup)
 105                return exynos_crtc->ops->mode_fixup(exynos_crtc, mode,
 106                                adjusted_mode);
 107
 108        return true;
 109}
 110
 111
 112static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
 113        .mode_valid     = exynos_crtc_mode_valid,
 114        .mode_fixup     = exynos_crtc_mode_fixup,
 115        .atomic_check   = exynos_crtc_atomic_check,
 116        .atomic_begin   = exynos_crtc_atomic_begin,
 117        .atomic_flush   = exynos_crtc_atomic_flush,
 118        .atomic_enable  = exynos_drm_crtc_atomic_enable,
 119        .atomic_disable = exynos_drm_crtc_atomic_disable,
 120};
 121
 122void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc)
 123{
 124        struct drm_crtc *crtc = &exynos_crtc->base;
 125        struct drm_pending_vblank_event *event = crtc->state->event;
 126        unsigned long flags;
 127
 128        if (!event)
 129                return;
 130        crtc->state->event = NULL;
 131
 132        WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 133
 134        spin_lock_irqsave(&crtc->dev->event_lock, flags);
 135        drm_crtc_arm_vblank_event(crtc, event);
 136        spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 137}
 138
 139static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
 140{
 141        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 142
 143        drm_crtc_cleanup(crtc);
 144        kfree(exynos_crtc);
 145}
 146
 147static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc)
 148{
 149        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 150
 151        if (exynos_crtc->ops->enable_vblank)
 152                return exynos_crtc->ops->enable_vblank(exynos_crtc);
 153
 154        return 0;
 155}
 156
 157static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
 158{
 159        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 160
 161        if (exynos_crtc->ops->disable_vblank)
 162                exynos_crtc->ops->disable_vblank(exynos_crtc);
 163}
 164
 165static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc)
 166{
 167        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 168
 169        if (exynos_crtc->ops->get_vblank_counter)
 170                return exynos_crtc->ops->get_vblank_counter(exynos_crtc);
 171
 172        return 0;
 173}
 174
 175static const struct drm_crtc_funcs exynos_crtc_funcs = {
 176        .set_config     = drm_atomic_helper_set_config,
 177        .page_flip      = drm_atomic_helper_page_flip,
 178        .destroy        = exynos_drm_crtc_destroy,
 179        .reset = drm_atomic_helper_crtc_reset,
 180        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
 181        .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 182        .enable_vblank = exynos_drm_crtc_enable_vblank,
 183        .disable_vblank = exynos_drm_crtc_disable_vblank,
 184        .get_vblank_counter = exynos_drm_crtc_get_vblank_counter,
 185};
 186
 187struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
 188                                        struct drm_plane *plane,
 189                                        enum exynos_drm_output_type type,
 190                                        const struct exynos_drm_crtc_ops *ops,
 191                                        void *ctx)
 192{
 193        struct exynos_drm_crtc *exynos_crtc;
 194        struct drm_crtc *crtc;
 195        int ret;
 196
 197        exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
 198        if (!exynos_crtc)
 199                return ERR_PTR(-ENOMEM);
 200
 201        exynos_crtc->type = type;
 202        exynos_crtc->ops = ops;
 203        exynos_crtc->ctx = ctx;
 204
 205        crtc = &exynos_crtc->base;
 206
 207        ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
 208                                        &exynos_crtc_funcs, NULL);
 209        if (ret < 0)
 210                goto err_crtc;
 211
 212        drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 213
 214        return exynos_crtc;
 215
 216err_crtc:
 217        plane->funcs->destroy(plane);
 218        kfree(exynos_crtc);
 219        return ERR_PTR(ret);
 220}
 221
 222struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev,
 223                                       enum exynos_drm_output_type out_type)
 224{
 225        struct drm_crtc *crtc;
 226
 227        drm_for_each_crtc(crtc, drm_dev)
 228                if (to_exynos_crtc(crtc)->type == out_type)
 229                        return to_exynos_crtc(crtc);
 230
 231        return ERR_PTR(-ENODEV);
 232}
 233
 234int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder,
 235                enum exynos_drm_output_type out_type)
 236{
 237        struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev,
 238                                                out_type);
 239
 240        if (IS_ERR(crtc))
 241                return PTR_ERR(crtc);
 242
 243        encoder->possible_crtcs = drm_crtc_mask(&crtc->base);
 244
 245        return 0;
 246}
 247
 248void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
 249{
 250        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 251
 252        if (exynos_crtc->ops->te_handler)
 253                exynos_crtc->ops->te_handler(exynos_crtc);
 254}
 255