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