Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5 438 lines 13 kB view raw
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_encoder_helper_funcs exynos_encoder_helper_funcs = { 176 .dpms = exynos_drm_encoder_dpms, 177 .mode_fixup = exynos_drm_encoder_mode_fixup, 178 .mode_set = exynos_drm_encoder_mode_set, 179 .prepare = exynos_drm_encoder_prepare, 180 .commit = exynos_drm_encoder_commit, 181}; 182 183static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) 184{ 185 struct exynos_drm_encoder *exynos_encoder = 186 to_exynos_encoder(encoder); 187 188 DRM_DEBUG_KMS("%s\n", __FILE__); 189 190 exynos_encoder->manager->pipe = -1; 191 192 drm_encoder_cleanup(encoder); 193 kfree(exynos_encoder); 194} 195 196static struct drm_encoder_funcs exynos_encoder_funcs = { 197 .destroy = exynos_drm_encoder_destroy, 198}; 199 200static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder) 201{ 202 struct drm_encoder *clone; 203 struct drm_device *dev = encoder->dev; 204 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); 205 struct exynos_drm_display_ops *display_ops = 206 exynos_encoder->manager->display_ops; 207 unsigned int clone_mask = 0; 208 int cnt = 0; 209 210 list_for_each_entry(clone, &dev->mode_config.encoder_list, head) { 211 switch (display_ops->type) { 212 case EXYNOS_DISPLAY_TYPE_LCD: 213 case EXYNOS_DISPLAY_TYPE_HDMI: 214 case EXYNOS_DISPLAY_TYPE_VIDI: 215 clone_mask |= (1 << (cnt++)); 216 break; 217 default: 218 continue; 219 } 220 } 221 222 return clone_mask; 223} 224 225void exynos_drm_encoder_setup(struct drm_device *dev) 226{ 227 struct drm_encoder *encoder; 228 229 DRM_DEBUG_KMS("%s\n", __FILE__); 230 231 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 232 encoder->possible_clones = exynos_drm_encoder_clones(encoder); 233} 234 235struct drm_encoder * 236exynos_drm_encoder_create(struct drm_device *dev, 237 struct exynos_drm_manager *manager, 238 unsigned int possible_crtcs) 239{ 240 struct drm_encoder *encoder; 241 struct exynos_drm_encoder *exynos_encoder; 242 243 DRM_DEBUG_KMS("%s\n", __FILE__); 244 245 if (!manager || !possible_crtcs) 246 return NULL; 247 248 if (!manager->dev) 249 return NULL; 250 251 exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL); 252 if (!exynos_encoder) { 253 DRM_ERROR("failed to allocate encoder\n"); 254 return NULL; 255 } 256 257 exynos_encoder->dpms = DRM_MODE_DPMS_OFF; 258 exynos_encoder->manager = manager; 259 encoder = &exynos_encoder->drm_encoder; 260 encoder->possible_crtcs = possible_crtcs; 261 262 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); 263 264 drm_encoder_init(dev, encoder, &exynos_encoder_funcs, 265 DRM_MODE_ENCODER_TMDS); 266 267 drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs); 268 269 DRM_DEBUG_KMS("encoder has been created\n"); 270 271 return encoder; 272} 273 274struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder) 275{ 276 return to_exynos_encoder(encoder)->manager; 277} 278 279void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data, 280 void (*fn)(struct drm_encoder *, void *)) 281{ 282 struct drm_device *dev = crtc->dev; 283 struct drm_encoder *encoder; 284 struct exynos_drm_private *private = dev->dev_private; 285 struct exynos_drm_manager *manager; 286 287 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 288 /* 289 * if crtc is detached from encoder, check pipe, 290 * otherwise check crtc attached to encoder 291 */ 292 if (!encoder->crtc) { 293 manager = to_exynos_encoder(encoder)->manager; 294 if (manager->pipe < 0 || 295 private->crtc[manager->pipe] != crtc) 296 continue; 297 } else { 298 if (encoder->crtc != crtc) 299 continue; 300 } 301 302 fn(encoder, data); 303 } 304} 305 306void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data) 307{ 308 struct exynos_drm_manager *manager = 309 to_exynos_encoder(encoder)->manager; 310 struct exynos_drm_manager_ops *manager_ops = manager->ops; 311 int crtc = *(int *)data; 312 313 if (manager->pipe == -1) 314 manager->pipe = crtc; 315 316 if (manager_ops->enable_vblank) 317 manager_ops->enable_vblank(manager->dev); 318} 319 320void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data) 321{ 322 struct exynos_drm_manager *manager = 323 to_exynos_encoder(encoder)->manager; 324 struct exynos_drm_manager_ops *manager_ops = manager->ops; 325 int crtc = *(int *)data; 326 327 if (manager->pipe == -1) 328 manager->pipe = crtc; 329 330 if (manager_ops->disable_vblank) 331 manager_ops->disable_vblank(manager->dev); 332} 333 334void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder, 335 void *data) 336{ 337 struct exynos_drm_manager *manager = 338 to_exynos_encoder(encoder)->manager; 339 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; 340 int zpos = DEFAULT_ZPOS; 341 342 if (data) 343 zpos = *(int *)data; 344 345 if (overlay_ops && overlay_ops->commit) 346 overlay_ops->commit(manager->dev, zpos); 347} 348 349void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data) 350{ 351 struct exynos_drm_manager *manager = 352 to_exynos_encoder(encoder)->manager; 353 int crtc = *(int *)data; 354 int zpos = DEFAULT_ZPOS; 355 356 DRM_DEBUG_KMS("%s\n", __FILE__); 357 358 /* 359 * when crtc is detached from encoder, this pipe is used 360 * to select manager operation 361 */ 362 manager->pipe = crtc; 363 364 exynos_drm_encoder_crtc_plane_commit(encoder, &zpos); 365} 366 367void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data) 368{ 369 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); 370 int mode = *(int *)data; 371 372 DRM_DEBUG_KMS("%s\n", __FILE__); 373 374 exynos_drm_encoder_dpms(encoder, mode); 375 376 exynos_encoder->dpms = mode; 377} 378 379void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data) 380{ 381 struct drm_device *dev = encoder->dev; 382 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); 383 struct exynos_drm_manager *manager = exynos_encoder->manager; 384 struct exynos_drm_manager_ops *manager_ops = manager->ops; 385 struct drm_connector *connector; 386 int mode = *(int *)data; 387 388 DRM_DEBUG_KMS("%s\n", __FILE__); 389 390 if (manager_ops && manager_ops->dpms) 391 manager_ops->dpms(manager->dev, mode); 392 393 /* 394 * set current dpms mode to the connector connected to 395 * current encoder. connector->dpms would be checked 396 * at drm_helper_connector_dpms() 397 */ 398 list_for_each_entry(connector, &dev->mode_config.connector_list, head) 399 if (connector->encoder == encoder) 400 connector->dpms = mode; 401 402 /* 403 * if this condition is ok then it means that the crtc is already 404 * detached from encoder and last function for detaching is properly 405 * done, so clear pipe from manager to prevent repeated call. 406 */ 407 if (mode > DRM_MODE_DPMS_ON) { 408 if (!encoder->crtc) 409 manager->pipe = -1; 410 } 411} 412 413void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data) 414{ 415 struct exynos_drm_manager *manager = 416 to_exynos_encoder(encoder)->manager; 417 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; 418 struct exynos_drm_overlay *overlay = data; 419 420 if (overlay_ops && overlay_ops->mode_set) 421 overlay_ops->mode_set(manager->dev, overlay); 422} 423 424void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data) 425{ 426 struct exynos_drm_manager *manager = 427 to_exynos_encoder(encoder)->manager; 428 struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; 429 int zpos = DEFAULT_ZPOS; 430 431 DRM_DEBUG_KMS("\n"); 432 433 if (data) 434 zpos = *(int *)data; 435 436 if (overlay_ops && overlay_ops->disable) 437 overlay_ops->disable(manager->dev, zpos); 438}