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 20 #include "exynos_drm_crtc.h" 21 #include "exynos_drm_drv.h" 22 #include "exynos_drm_encoder.h" 23 #include "exynos_drm_plane.h" 24 25 static void exynos_drm_crtc_enable(struct drm_crtc *crtc) 26 { 27 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 28 29 if (exynos_crtc->enabled) 30 return; 31 32 if (exynos_crtc->ops->enable) 33 exynos_crtc->ops->enable(exynos_crtc); 34 35 exynos_crtc->enabled = true; 36 37 drm_crtc_vblank_on(crtc); 38 } 39 40 static void exynos_drm_crtc_disable(struct drm_crtc *crtc) 41 { 42 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 43 44 if (!exynos_crtc->enabled) 45 return; 46 47 /* wait for the completion of page flip. */ 48 if (!wait_event_timeout(exynos_crtc->pending_flip_queue, 49 (exynos_crtc->event == NULL), HZ/20)) 50 exynos_crtc->event = NULL; 51 52 drm_crtc_vblank_off(crtc); 53 54 if (exynos_crtc->ops->disable) 55 exynos_crtc->ops->disable(exynos_crtc); 56 57 exynos_crtc->enabled = false; 58 } 59 60 static bool 61 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, 62 const struct drm_display_mode *mode, 63 struct drm_display_mode *adjusted_mode) 64 { 65 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 66 67 if (exynos_crtc->ops->mode_fixup) 68 return exynos_crtc->ops->mode_fixup(exynos_crtc, mode, 69 adjusted_mode); 70 71 return true; 72 } 73 74 static void 75 exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) 76 { 77 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 78 79 if (exynos_crtc->ops->commit) 80 exynos_crtc->ops->commit(exynos_crtc); 81 } 82 83 static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) 84 { 85 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 86 87 if (crtc->state->event) { 88 WARN_ON(drm_crtc_vblank_get(crtc) != 0); 89 exynos_crtc->event = crtc->state->event; 90 } 91 } 92 93 static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) 94 { 95 } 96 97 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 98 .enable = exynos_drm_crtc_enable, 99 .disable = exynos_drm_crtc_disable, 100 .mode_fixup = exynos_drm_crtc_mode_fixup, 101 .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, 102 .atomic_begin = exynos_crtc_atomic_begin, 103 .atomic_flush = exynos_crtc_atomic_flush, 104 }; 105 106 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 107 { 108 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 109 struct exynos_drm_private *private = crtc->dev->dev_private; 110 111 private->crtc[exynos_crtc->pipe] = NULL; 112 113 drm_crtc_cleanup(crtc); 114 kfree(exynos_crtc); 115 } 116 117 static struct drm_crtc_funcs exynos_crtc_funcs = { 118 .set_config = drm_atomic_helper_set_config, 119 .page_flip = drm_atomic_helper_page_flip, 120 .destroy = exynos_drm_crtc_destroy, 121 .reset = drm_atomic_helper_crtc_reset, 122 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 123 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 124 }; 125 126 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, 127 struct drm_plane *plane, 128 int pipe, 129 enum exynos_drm_output_type type, 130 const struct exynos_drm_crtc_ops *ops, 131 void *ctx) 132 { 133 struct exynos_drm_crtc *exynos_crtc; 134 struct exynos_drm_private *private = drm_dev->dev_private; 135 struct drm_crtc *crtc; 136 int ret; 137 138 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 139 if (!exynos_crtc) 140 return ERR_PTR(-ENOMEM); 141 142 init_waitqueue_head(&exynos_crtc->pending_flip_queue); 143 144 exynos_crtc->pipe = pipe; 145 exynos_crtc->type = type; 146 exynos_crtc->ops = ops; 147 exynos_crtc->ctx = ctx; 148 149 crtc = &exynos_crtc->base; 150 151 private->crtc[pipe] = crtc; 152 153 ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL, 154 &exynos_crtc_funcs); 155 if (ret < 0) 156 goto err_crtc; 157 158 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 159 160 return exynos_crtc; 161 162 err_crtc: 163 plane->funcs->destroy(plane); 164 kfree(exynos_crtc); 165 return ERR_PTR(ret); 166 } 167 168 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) 169 { 170 struct exynos_drm_private *private = dev->dev_private; 171 struct exynos_drm_crtc *exynos_crtc = 172 to_exynos_crtc(private->crtc[pipe]); 173 174 if (!exynos_crtc->enabled) 175 return -EPERM; 176 177 if (exynos_crtc->ops->enable_vblank) 178 exynos_crtc->ops->enable_vblank(exynos_crtc); 179 180 return 0; 181 } 182 183 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) 184 { 185 struct exynos_drm_private *private = dev->dev_private; 186 struct exynos_drm_crtc *exynos_crtc = 187 to_exynos_crtc(private->crtc[pipe]); 188 189 if (!exynos_crtc->enabled) 190 return; 191 192 if (exynos_crtc->ops->disable_vblank) 193 exynos_crtc->ops->disable_vblank(exynos_crtc); 194 } 195 196 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) 197 { 198 struct exynos_drm_private *dev_priv = dev->dev_private; 199 struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; 200 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); 201 unsigned long flags; 202 203 spin_lock_irqsave(&dev->event_lock, flags); 204 if (exynos_crtc->event) { 205 206 drm_send_vblank_event(dev, -1, exynos_crtc->event); 207 drm_vblank_put(dev, pipe); 208 wake_up(&exynos_crtc->pending_flip_queue); 209 210 } 211 212 exynos_crtc->event = NULL; 213 spin_unlock_irqrestore(&dev->event_lock, flags); 214 } 215 216 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) 217 { 218 struct exynos_drm_crtc *exynos_crtc; 219 struct drm_device *dev = fb->dev; 220 struct drm_crtc *crtc; 221 222 /* 223 * make sure that overlay data are updated to real hardware 224 * for all encoders. 225 */ 226 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 227 exynos_crtc = to_exynos_crtc(crtc); 228 229 /* 230 * wait for vblank interrupt 231 * - this makes sure that overlay data are updated to 232 * real hardware. 233 */ 234 if (exynos_crtc->ops->wait_for_vblank) 235 exynos_crtc->ops->wait_for_vblank(exynos_crtc); 236 } 237 } 238 239 int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, 240 unsigned int out_type) 241 { 242 struct drm_crtc *crtc; 243 244 list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { 245 struct exynos_drm_crtc *exynos_crtc; 246 247 exynos_crtc = to_exynos_crtc(crtc); 248 if (exynos_crtc->type == out_type) 249 return exynos_crtc->pipe; 250 } 251 252 return -EPERM; 253 } 254 255 void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) 256 { 257 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 258 259 if (exynos_crtc->ops->te_handler) 260 exynos_crtc->ops->te_handler(exynos_crtc); 261 } 262