1/* exynos_drm_encoder.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 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the next 17 * paragraph) shall be included in all copies or substantial portions of the 18 * Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 */ 28 29#include "drmP.h" 30#include "drm_crtc_helper.h" 31 32#include "exynos_drm_drv.h" 33#include "exynos_drm_crtc.h" 34#include "exynos_drm_encoder.h" 35 36#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\ 37 drm_encoder) 38 39/* 40 * exynos specific encoder structure. 41 * 42 * @drm_encoder: encoder object. 43 * @manager: specific encoder has its own manager to control a hardware 44 * appropriately and we can access a hardware drawing on this manager. 45 * @dpms: store the encoder dpms value. 46 */ 47struct exynos_drm_encoder { 48 struct drm_encoder drm_encoder; 49 struct exynos_drm_manager *manager; 50 int dpms; 51}; 52 53static void exynos_drm_display_power(struct drm_encoder *encoder, int mode) 54{ 55 struct drm_device *dev = encoder->dev; 56 struct drm_connector *connector; 57 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); 58 59 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 60 if (connector->encoder == encoder) { 61 struct exynos_drm_display_ops *display_ops = 62 manager->display_ops; 63 64 DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", 65 connector->base.id, mode); 66 if (display_ops && display_ops->power_on) 67 display_ops->power_on(manager->dev, mode); 68 } 69 } 70} 71 72static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) 73{ 74 struct drm_device *dev = encoder->dev; 75 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); 76 struct exynos_drm_manager_ops *manager_ops = manager->ops; 77 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); 78 79 DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode); 80 81 if (exynos_encoder->dpms == mode) { 82 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); 83 return; 84 } 85 86 mutex_lock(&dev->struct_mutex); 87 88 switch (mode) { 89 case DRM_MODE_DPMS_ON: 90 if (manager_ops && manager_ops->apply) 91 manager_ops->apply(manager->dev); 92 exynos_drm_display_power(encoder, mode); 93 exynos_encoder->dpms = mode; 94 break; 95 case DRM_MODE_DPMS_STANDBY: 96 case DRM_MODE_DPMS_SUSPEND: 97 case DRM_MODE_DPMS_OFF: 98 exynos_drm_display_power(encoder, mode); 99 exynos_encoder->dpms = mode; 100 break; 101 default: 102 DRM_ERROR("unspecified mode %d\n", mode); 103 break; 104 } 105 106 mutex_unlock(&dev->struct_mutex); 107} 108 109static bool 110exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, 111 struct drm_display_mode *mode, 112 struct drm_display_mode *adjusted_mode) 113{ 114 struct drm_device *dev = encoder->dev; 115 struct drm_connector *connector; 116 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); 117 struct exynos_drm_manager_ops *manager_ops = manager->ops; 118 119 DRM_DEBUG_KMS("%s\n", __FILE__); 120 121 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 122 if (connector->encoder == encoder) 123 if (manager_ops && manager_ops->mode_fixup) 124 manager_ops->mode_fixup(manager->dev, connector, 125 mode, adjusted_mode); 126 } 127 128 return true; 129} 130 131static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, 132 struct drm_display_mode *mode, 133 struct drm_display_mode *adjusted_mode) 134{ 135 struct drm_device *dev = encoder->dev; 136 struct drm_connector *connector; 137 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); 138 struct exynos_drm_manager_ops *manager_ops = manager->ops; 139 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; 140 struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev, 141 encoder->crtc); 142 143 DRM_DEBUG_KMS("%s\n", __FILE__); 144 145 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 146 if (connector->encoder == encoder) { 147 if (manager_ops && manager_ops->mode_set) 148 manager_ops->mode_set(manager->dev, 149 adjusted_mode); 150 151 if (overlay_ops && overlay_ops->mode_set) 152 overlay_ops->mode_set(manager->dev, overlay); 153 } 154 } 155} 156 157static void exynos_drm_encoder_prepare(struct drm_encoder *encoder) 158{ 159 DRM_DEBUG_KMS("%s\n", __FILE__); 160 161 /* drm framework doesn't check NULL. */ 162} 163 164static void exynos_drm_encoder_commit(struct drm_encoder *encoder) 165{ 166 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); 167 struct exynos_drm_manager_ops *manager_ops = manager->ops; 168 169 DRM_DEBUG_KMS("%s\n", __FILE__); 170 171 if (manager_ops && manager_ops->commit) 172 manager_ops->commit(manager->dev); 173} 174 175static struct drm_crtc * 176exynos_drm_encoder_get_crtc(struct drm_encoder *encoder) 177{ 178 return encoder->crtc; 179} 180 181static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { 182 .dpms = exynos_drm_encoder_dpms, 183 .mode_fixup = exynos_drm_encoder_mode_fixup, 184 .mode_set = exynos_drm_encoder_mode_set, 185 .prepare = exynos_drm_encoder_prepare, 186 .commit = exynos_drm_encoder_commit, 187 .get_crtc = exynos_drm_encoder_get_crtc, 188}; 189 190static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) 191{ 192 struct exynos_drm_encoder *exynos_encoder = 193 to_exynos_encoder(encoder); 194 195 DRM_DEBUG_KMS("%s\n", __FILE__); 196 197 exynos_encoder->manager->pipe = -1; 198 199 drm_encoder_cleanup(encoder); 200 kfree(exynos_encoder); 201} 202 203static struct drm_encoder_funcs exynos_encoder_funcs = { 204 .destroy = exynos_drm_encoder_destroy, 205}; 206 207static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder) 208{ 209 struct drm_encoder *clone; 210 struct drm_device *dev = encoder->dev; 211 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); 212 struct exynos_drm_display_ops *display_ops = 213 exynos_encoder->manager->display_ops; 214 unsigned int clone_mask = 0; 215 int cnt = 0; 216 217 list_for_each_entry(clone, &dev->mode_config.encoder_list, head) { 218 switch (display_ops->type) { 219 case EXYNOS_DISPLAY_TYPE_LCD: 220 case EXYNOS_DISPLAY_TYPE_HDMI: 221 case EXYNOS_DISPLAY_TYPE_VIDI: 222 clone_mask |= (1 << (cnt++)); 223 break; 224 default: 225 continue; 226 } 227 } 228 229 return clone_mask; 230} 231 232void exynos_drm_encoder_setup(struct drm_device *dev) 233{ 234 struct drm_encoder *encoder; 235 236 DRM_DEBUG_KMS("%s\n", __FILE__); 237 238 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 239 encoder->possible_clones = exynos_drm_encoder_clones(encoder); 240} 241 242struct drm_encoder * 243exynos_drm_encoder_create(struct drm_device *dev, 244 struct exynos_drm_manager *manager, 245 unsigned int possible_crtcs) 246{ 247 struct drm_encoder *encoder; 248 struct exynos_drm_encoder *exynos_encoder; 249 250 DRM_DEBUG_KMS("%s\n", __FILE__); 251 252 if (!manager || !possible_crtcs) 253 return NULL; 254 255 if (!manager->dev) 256 return NULL; 257 258 exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL); 259 if (!exynos_encoder) { 260 DRM_ERROR("failed to allocate encoder\n"); 261 return NULL; 262 } 263 264 exynos_encoder->dpms = DRM_MODE_DPMS_OFF; 265 exynos_encoder->manager = manager; 266 encoder = &exynos_encoder->drm_encoder; 267 encoder->possible_crtcs = possible_crtcs; 268 269 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); 270 271 drm_encoder_init(dev, encoder, &exynos_encoder_funcs, 272 DRM_MODE_ENCODER_TMDS); 273 274 drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs); 275 276 DRM_DEBUG_KMS("encoder has been created\n"); 277 278 return encoder; 279} 280 281struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder) 282{ 283 return to_exynos_encoder(encoder)->manager; 284} 285 286void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data, 287 void (*fn)(struct drm_encoder *, void *)) 288{ 289 struct drm_device *dev = crtc->dev; 290 struct drm_encoder *encoder; 291 struct exynos_drm_private *private = dev->dev_private; 292 struct exynos_drm_manager *manager; 293 294 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 295 /* 296 * if crtc is detached from encoder, check pipe, 297 * otherwise check crtc attached to encoder 298 */ 299 if (!encoder->crtc) { 300 manager = to_exynos_encoder(encoder)->manager; 301 if (manager->pipe < 0 || 302 private->crtc[manager->pipe] != crtc) 303 continue; 304 } else { 305 if (encoder->crtc != crtc) 306 continue; 307 } 308 309 fn(encoder, data); 310 } 311} 312 313void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data) 314{ 315 struct exynos_drm_manager *manager = 316 to_exynos_encoder(encoder)->manager; 317 struct exynos_drm_manager_ops *manager_ops = manager->ops; 318 int crtc = *(int *)data; 319 320 if (manager->pipe == -1) 321 manager->pipe = crtc; 322 323 if (manager_ops->enable_vblank) 324 manager_ops->enable_vblank(manager->dev); 325} 326 327void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data) 328{ 329 struct exynos_drm_manager *manager = 330 to_exynos_encoder(encoder)->manager; 331 struct exynos_drm_manager_ops *manager_ops = manager->ops; 332 int crtc = *(int *)data; 333 334 if (manager->pipe == -1) 335 manager->pipe = crtc; 336 337 if (manager_ops->disable_vblank) 338 manager_ops->disable_vblank(manager->dev); 339} 340 341void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder, 342 void *data) 343{ 344 struct exynos_drm_manager *manager = 345 to_exynos_encoder(encoder)->manager; 346 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; 347 int zpos = DEFAULT_ZPOS; 348 349 if (data) 350 zpos = *(int *)data; 351 352 if (overlay_ops && overlay_ops->commit) 353 overlay_ops->commit(manager->dev, zpos); 354} 355 356void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data) 357{ 358 struct exynos_drm_manager *manager = 359 to_exynos_encoder(encoder)->manager; 360 int crtc = *(int *)data; 361 int zpos = DEFAULT_ZPOS; 362 363 DRM_DEBUG_KMS("%s\n", __FILE__); 364 365 /* 366 * when crtc is detached from encoder, this pipe is used 367 * to select manager operation 368 */ 369 manager->pipe = crtc; 370 371 exynos_drm_encoder_crtc_plane_commit(encoder, &zpos); 372} 373 374void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data) 375{ 376 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); 377 int mode = *(int *)data; 378 379 DRM_DEBUG_KMS("%s\n", __FILE__); 380 381 exynos_drm_encoder_dpms(encoder, mode); 382 383 exynos_encoder->dpms = mode; 384} 385 386void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data) 387{ 388 struct drm_device *dev = encoder->dev; 389 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); 390 struct exynos_drm_manager *manager = exynos_encoder->manager; 391 struct exynos_drm_manager_ops *manager_ops = manager->ops; 392 struct drm_connector *connector; 393 int mode = *(int *)data; 394 395 DRM_DEBUG_KMS("%s\n", __FILE__); 396 397 if (manager_ops && manager_ops->dpms) 398 manager_ops->dpms(manager->dev, mode); 399 400 /* 401 * set current dpms mode to the connector connected to 402 * current encoder. connector->dpms would be checked 403 * at drm_helper_connector_dpms() 404 */ 405 list_for_each_entry(connector, &dev->mode_config.connector_list, head) 406 if (connector->encoder == encoder) 407 connector->dpms = mode; 408 409 /* 410 * if this condition is ok then it means that the crtc is already 411 * detached from encoder and last function for detaching is properly 412 * done, so clear pipe from manager to prevent repeated call. 413 */ 414 if (mode > DRM_MODE_DPMS_ON) { 415 if (!encoder->crtc) 416 manager->pipe = -1; 417 } 418} 419 420void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data) 421{ 422 struct exynos_drm_manager *manager = 423 to_exynos_encoder(encoder)->manager; 424 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; 425 struct exynos_drm_overlay *overlay = data; 426 427 if (overlay_ops && overlay_ops->mode_set) 428 overlay_ops->mode_set(manager->dev, overlay); 429} 430 431void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data) 432{ 433 struct exynos_drm_manager *manager = 434 to_exynos_encoder(encoder)->manager; 435 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; 436 int zpos = DEFAULT_ZPOS; 437 438 DRM_DEBUG_KMS("\n"); 439 440 if (data) 441 zpos = *(int *)data; 442 443 if (overlay_ops && overlay_ops->disable) 444 overlay_ops->disable(manager->dev, zpos); 445} 446