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_atomic.h>
  17#include <drm/drm_atomic_helper.h>
  18#include <drm/drm_encoder.h>
  19#include <drm/drm_probe_helper.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 const struct drm_crtc_funcs exynos_crtc_funcs = {
 166        .set_config     = drm_atomic_helper_set_config,
 167        .page_flip      = drm_atomic_helper_page_flip,
 168        .destroy        = exynos_drm_crtc_destroy,
 169        .reset = drm_atomic_helper_crtc_reset,
 170        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
 171        .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 172        .enable_vblank = exynos_drm_crtc_enable_vblank,
 173        .disable_vblank = exynos_drm_crtc_disable_vblank,
 174};
 175
 176struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
 177                                        struct drm_plane *plane,
 178                                        enum exynos_drm_output_type type,
 179                                        const struct exynos_drm_crtc_ops *ops,
 180                                        void *ctx)
 181{
 182        struct exynos_drm_crtc *exynos_crtc;
 183        struct drm_crtc *crtc;
 184        int ret;
 185
 186        exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
 187        if (!exynos_crtc)
 188                return ERR_PTR(-ENOMEM);
 189
 190        exynos_crtc->type = type;
 191        exynos_crtc->ops = ops;
 192        exynos_crtc->ctx = ctx;
 193
 194        crtc = &exynos_crtc->base;
 195
 196        ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
 197                                        &exynos_crtc_funcs, NULL);
 198        if (ret < 0)
 199                goto err_crtc;
 200
 201        drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 202
 203        return exynos_crtc;
 204
 205err_crtc:
 206        plane->funcs->destroy(plane);
 207        kfree(exynos_crtc);
 208        return ERR_PTR(ret);
 209}
 210
 211struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev,
 212                                       enum exynos_drm_output_type out_type)
 213{
 214        struct drm_crtc *crtc;
 215
 216        drm_for_each_crtc(crtc, drm_dev)
 217                if (to_exynos_crtc(crtc)->type == out_type)
 218                        return to_exynos_crtc(crtc);
 219
 220        return ERR_PTR(-ENODEV);
 221}
 222
 223int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder,
 224                enum exynos_drm_output_type out_type)
 225{
 226        struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev,
 227                                                out_type);
 228
 229        if (IS_ERR(crtc))
 230                return PTR_ERR(crtc);
 231
 232        encoder->possible_crtcs = drm_crtc_mask(&crtc->base);
 233
 234        return 0;
 235}
 236
 237void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
 238{
 239        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 240
 241        if (exynos_crtc->ops->te_handler)
 242                exynos_crtc->ops->te_handler(exynos_crtc);
 243}
 244