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