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