linux/drivers/gpu/drm/sun4i/sun4i_crtc.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Free Electrons
   3 * Copyright (C) 2015 NextThing Co
   4 *
   5 * Maxime Ripard <maxime.ripard@free-electrons.com>
   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
  10 * the License, or (at your option) any later version.
  11 */
  12
  13#include <drm/drmP.h>
  14#include <drm/drm_atomic_helper.h>
  15#include <drm/drm_crtc.h>
  16#include <drm/drm_crtc_helper.h>
  17#include <drm/drm_modes.h>
  18
  19#include <linux/clk-provider.h>
  20#include <linux/ioport.h>
  21#include <linux/of_address.h>
  22#include <linux/of_irq.h>
  23#include <linux/regmap.h>
  24
  25#include <video/videomode.h>
  26
  27#include "sun4i_backend.h"
  28#include "sun4i_crtc.h"
  29#include "sun4i_drv.h"
  30#include "sun4i_tcon.h"
  31
  32static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
  33                                    struct drm_crtc_state *old_state)
  34{
  35        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  36        struct drm_device *dev = crtc->dev;
  37        unsigned long flags;
  38
  39        if (crtc->state->event) {
  40                WARN_ON(drm_crtc_vblank_get(crtc) != 0);
  41
  42                spin_lock_irqsave(&dev->event_lock, flags);
  43                scrtc->event = crtc->state->event;
  44                spin_unlock_irqrestore(&dev->event_lock, flags);
  45                crtc->state->event = NULL;
  46         }
  47}
  48
  49static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
  50                                    struct drm_crtc_state *old_state)
  51{
  52        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  53        struct sun4i_drv *drv = scrtc->drv;
  54        struct drm_pending_vblank_event *event = crtc->state->event;
  55
  56        DRM_DEBUG_DRIVER("Committing plane changes\n");
  57
  58        sun4i_backend_commit(drv->backend);
  59
  60        if (event) {
  61                crtc->state->event = NULL;
  62
  63                spin_lock_irq(&crtc->dev->event_lock);
  64                if (drm_crtc_vblank_get(crtc) == 0)
  65                        drm_crtc_arm_vblank_event(crtc, event);
  66                else
  67                        drm_crtc_send_vblank_event(crtc, event);
  68                spin_unlock_irq(&crtc->dev->event_lock);
  69        }
  70}
  71
  72static void sun4i_crtc_disable(struct drm_crtc *crtc)
  73{
  74        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  75        struct sun4i_drv *drv = scrtc->drv;
  76
  77        DRM_DEBUG_DRIVER("Disabling the CRTC\n");
  78
  79        sun4i_tcon_disable(drv->tcon);
  80
  81        if (crtc->state->event && !crtc->state->active) {
  82                spin_lock_irq(&crtc->dev->event_lock);
  83                drm_crtc_send_vblank_event(crtc, crtc->state->event);
  84                spin_unlock_irq(&crtc->dev->event_lock);
  85
  86                crtc->state->event = NULL;
  87        }
  88}
  89
  90static void sun4i_crtc_enable(struct drm_crtc *crtc)
  91{
  92        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  93        struct sun4i_drv *drv = scrtc->drv;
  94
  95        DRM_DEBUG_DRIVER("Enabling the CRTC\n");
  96
  97        sun4i_tcon_enable(drv->tcon);
  98}
  99
 100static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
 101        .atomic_begin   = sun4i_crtc_atomic_begin,
 102        .atomic_flush   = sun4i_crtc_atomic_flush,
 103        .disable        = sun4i_crtc_disable,
 104        .enable         = sun4i_crtc_enable,
 105};
 106
 107static const struct drm_crtc_funcs sun4i_crtc_funcs = {
 108        .atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,
 109        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
 110        .destroy                = drm_crtc_cleanup,
 111        .page_flip              = drm_atomic_helper_page_flip,
 112        .reset                  = drm_atomic_helper_crtc_reset,
 113        .set_config             = drm_atomic_helper_set_config,
 114};
 115
 116struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm)
 117{
 118        struct sun4i_drv *drv = drm->dev_private;
 119        struct sun4i_crtc *scrtc;
 120        int ret;
 121
 122        scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
 123        if (!scrtc)
 124                return NULL;
 125        scrtc->drv = drv;
 126
 127        ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
 128                                        drv->primary,
 129                                        NULL,
 130                                        &sun4i_crtc_funcs,
 131                                        NULL);
 132        if (ret) {
 133                dev_err(drm->dev, "Couldn't init DRM CRTC\n");
 134                return NULL;
 135        }
 136
 137        drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
 138
 139        return scrtc;
 140}
 141