1 /* 2 * The list_sort function is (presumably) licensed under the GPL (see the 3 * top level "COPYING" file for details). 4 * 5 * The remainder of this file is: 6 * 7 * Copyright © 1997-2003 by The XFree86 Project, Inc. 8 * Copyright © 2007 Dave Airlie 9 * Copyright © 2007-2008 Intel Corporation 10 * Jesse Barnes <jesse.barnes@intel.com> 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * copy of this software and associated documentation files (the "Software"), 14 * to deal in the Software without restriction, including without limitation 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 16 * and/or sell copies of the Software, and to permit persons to whom the 17 * Software is furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included in 20 * all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 26 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 * OTHER DEALINGS IN THE SOFTWARE. 29 * 30 * Except as contained in this notice, the name of the copyright holder(s) 31 * and author(s) shall not be used in advertising or otherwise to promote 32 * the sale, use or other dealings in this Software without prior written 33 * authorization from the copyright holder(s) and author(s). 34 */ 35 36 #include <linux/list.h> 37 #include "drmP.h" 38 #include "drm.h" 39 #include "drm_crtc.h" 40 41 #define DRM_MODESET_DEBUG "drm_mode" 42 /** 43 * drm_mode_debug_printmodeline - debug print a mode 44 * @dev: DRM device 45 * @mode: mode to print 46 * 47 * LOCKING: 48 * None. 49 * 50 * Describe @mode using DRM_DEBUG. 51 */ 52 void drm_mode_debug_printmodeline(struct drm_display_mode *mode) 53 { 54 DRM_DEBUG_MODE(DRM_MODESET_DEBUG, 55 "Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", 56 mode->base.id, mode->name, mode->vrefresh, mode->clock, 57 mode->hdisplay, mode->hsync_start, 58 mode->hsync_end, mode->htotal, 59 mode->vdisplay, mode->vsync_start, 60 mode->vsync_end, mode->vtotal, mode->type, mode->flags); 61 } 62 EXPORT_SYMBOL(drm_mode_debug_printmodeline); 63 64 /** 65 * drm_mode_set_name - set the name on a mode 66 * @mode: name will be set in this mode 67 * 68 * LOCKING: 69 * None. 70 * 71 * Set the name of @mode to a standard format. 72 */ 73 void drm_mode_set_name(struct drm_display_mode *mode) 74 { 75 snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, 76 mode->vdisplay); 77 } 78 EXPORT_SYMBOL(drm_mode_set_name); 79 80 /** 81 * drm_mode_list_concat - move modes from one list to another 82 * @head: source list 83 * @new: dst list 84 * 85 * LOCKING: 86 * Caller must ensure both lists are locked. 87 * 88 * Move all the modes from @head to @new. 89 */ 90 void drm_mode_list_concat(struct list_head *head, struct list_head *new) 91 { 92 93 struct list_head *entry, *tmp; 94 95 list_for_each_safe(entry, tmp, head) { 96 list_move_tail(entry, new); 97 } 98 } 99 EXPORT_SYMBOL(drm_mode_list_concat); 100 101 /** 102 * drm_mode_width - get the width of a mode 103 * @mode: mode 104 * 105 * LOCKING: 106 * None. 107 * 108 * Return @mode's width (hdisplay) value. 109 * 110 * FIXME: is this needed? 111 * 112 * RETURNS: 113 * @mode->hdisplay 114 */ 115 int drm_mode_width(struct drm_display_mode *mode) 116 { 117 return mode->hdisplay; 118 119 } 120 EXPORT_SYMBOL(drm_mode_width); 121 122 /** 123 * drm_mode_height - get the height of a mode 124 * @mode: mode 125 * 126 * LOCKING: 127 * None. 128 * 129 * Return @mode's height (vdisplay) value. 130 * 131 * FIXME: is this needed? 132 * 133 * RETURNS: 134 * @mode->vdisplay 135 */ 136 int drm_mode_height(struct drm_display_mode *mode) 137 { 138 return mode->vdisplay; 139 } 140 EXPORT_SYMBOL(drm_mode_height); 141 142 /** 143 * drm_mode_vrefresh - get the vrefresh of a mode 144 * @mode: mode 145 * 146 * LOCKING: 147 * None. 148 * 149 * Return @mode's vrefresh rate or calculate it if necessary. 150 * 151 * FIXME: why is this needed? shouldn't vrefresh be set already? 152 * 153 * RETURNS: 154 * Vertical refresh rate of @mode x 1000. For precision reasons. 155 */ 156 int drm_mode_vrefresh(struct drm_display_mode *mode) 157 { 158 int refresh = 0; 159 unsigned int calc_val; 160 161 if (mode->vrefresh > 0) 162 refresh = mode->vrefresh; 163 else if (mode->htotal > 0 && mode->vtotal > 0) { 164 /* work out vrefresh the value will be x1000 */ 165 calc_val = (mode->clock * 1000); 166 167 calc_val /= mode->htotal; 168 calc_val *= 1000; 169 calc_val /= mode->vtotal; 170 171 refresh = calc_val; 172 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 173 refresh *= 2; 174 if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 175 refresh /= 2; 176 if (mode->vscan > 1) 177 refresh /= mode->vscan; 178 } 179 return refresh; 180 } 181 EXPORT_SYMBOL(drm_mode_vrefresh); 182 183 /** 184 * drm_mode_set_crtcinfo - set CRTC modesetting parameters 185 * @p: mode 186 * @adjust_flags: unused? (FIXME) 187 * 188 * LOCKING: 189 * None. 190 * 191 * Setup the CRTC modesetting parameters for @p, adjusting if necessary. 192 */ 193 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) 194 { 195 if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) 196 return; 197 198 p->crtc_hdisplay = p->hdisplay; 199 p->crtc_hsync_start = p->hsync_start; 200 p->crtc_hsync_end = p->hsync_end; 201 p->crtc_htotal = p->htotal; 202 p->crtc_hskew = p->hskew; 203 p->crtc_vdisplay = p->vdisplay; 204 p->crtc_vsync_start = p->vsync_start; 205 p->crtc_vsync_end = p->vsync_end; 206 p->crtc_vtotal = p->vtotal; 207 208 if (p->flags & DRM_MODE_FLAG_INTERLACE) { 209 if (adjust_flags & CRTC_INTERLACE_HALVE_V) { 210 p->crtc_vdisplay /= 2; 211 p->crtc_vsync_start /= 2; 212 p->crtc_vsync_end /= 2; 213 p->crtc_vtotal /= 2; 214 } 215 216 p->crtc_vtotal |= 1; 217 } 218 219 if (p->flags & DRM_MODE_FLAG_DBLSCAN) { 220 p->crtc_vdisplay *= 2; 221 p->crtc_vsync_start *= 2; 222 p->crtc_vsync_end *= 2; 223 p->crtc_vtotal *= 2; 224 } 225 226 if (p->vscan > 1) { 227 p->crtc_vdisplay *= p->vscan; 228 p->crtc_vsync_start *= p->vscan; 229 p->crtc_vsync_end *= p->vscan; 230 p->crtc_vtotal *= p->vscan; 231 } 232 233 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); 234 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); 235 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); 236 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal); 237 238 p->crtc_hadjusted = false; 239 p->crtc_vadjusted = false; 240 } 241 EXPORT_SYMBOL(drm_mode_set_crtcinfo); 242 243 244 /** 245 * drm_mode_duplicate - allocate and duplicate an existing mode 246 * @m: mode to duplicate 247 * 248 * LOCKING: 249 * None. 250 * 251 * Just allocate a new mode, copy the existing mode into it, and return 252 * a pointer to it. Used to create new instances of established modes. 253 */ 254 struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, 255 struct drm_display_mode *mode) 256 { 257 struct drm_display_mode *nmode; 258 int new_id; 259 260 nmode = drm_mode_create(dev); 261 if (!nmode) 262 return NULL; 263 264 new_id = nmode->base.id; 265 *nmode = *mode; 266 nmode->base.id = new_id; 267 INIT_LIST_HEAD(&nmode->head); 268 return nmode; 269 } 270 EXPORT_SYMBOL(drm_mode_duplicate); 271 272 /** 273 * drm_mode_equal - test modes for equality 274 * @mode1: first mode 275 * @mode2: second mode 276 * 277 * LOCKING: 278 * None. 279 * 280 * Check to see if @mode1 and @mode2 are equivalent. 281 * 282 * RETURNS: 283 * True if the modes are equal, false otherwise. 284 */ 285 bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) 286 { 287 /* do clock check convert to PICOS so fb modes get matched 288 * the same */ 289 if (mode1->clock && mode2->clock) { 290 if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock)) 291 return false; 292 } else if (mode1->clock != mode2->clock) 293 return false; 294 295 if (mode1->hdisplay == mode2->hdisplay && 296 mode1->hsync_start == mode2->hsync_start && 297 mode1->hsync_end == mode2->hsync_end && 298 mode1->htotal == mode2->htotal && 299 mode1->hskew == mode2->hskew && 300 mode1->vdisplay == mode2->vdisplay && 301 mode1->vsync_start == mode2->vsync_start && 302 mode1->vsync_end == mode2->vsync_end && 303 mode1->vtotal == mode2->vtotal && 304 mode1->vscan == mode2->vscan && 305 mode1->flags == mode2->flags) 306 return true; 307 308 return false; 309 } 310 EXPORT_SYMBOL(drm_mode_equal); 311 312 /** 313 * drm_mode_validate_size - make sure modes adhere to size constraints 314 * @dev: DRM device 315 * @mode_list: list of modes to check 316 * @maxX: maximum width 317 * @maxY: maximum height 318 * @maxPitch: max pitch 319 * 320 * LOCKING: 321 * Caller must hold a lock protecting @mode_list. 322 * 323 * The DRM device (@dev) has size and pitch limits. Here we validate the 324 * modes we probed for @dev against those limits and set their status as 325 * necessary. 326 */ 327 void drm_mode_validate_size(struct drm_device *dev, 328 struct list_head *mode_list, 329 int maxX, int maxY, int maxPitch) 330 { 331 struct drm_display_mode *mode; 332 333 list_for_each_entry(mode, mode_list, head) { 334 if (maxPitch > 0 && mode->hdisplay > maxPitch) 335 mode->status = MODE_BAD_WIDTH; 336 337 if (maxX > 0 && mode->hdisplay > maxX) 338 mode->status = MODE_VIRTUAL_X; 339 340 if (maxY > 0 && mode->vdisplay > maxY) 341 mode->status = MODE_VIRTUAL_Y; 342 } 343 } 344 EXPORT_SYMBOL(drm_mode_validate_size); 345 346 /** 347 * drm_mode_validate_clocks - validate modes against clock limits 348 * @dev: DRM device 349 * @mode_list: list of modes to check 350 * @min: minimum clock rate array 351 * @max: maximum clock rate array 352 * @n_ranges: number of clock ranges (size of arrays) 353 * 354 * LOCKING: 355 * Caller must hold a lock protecting @mode_list. 356 * 357 * Some code may need to check a mode list against the clock limits of the 358 * device in question. This function walks the mode list, testing to make 359 * sure each mode falls within a given range (defined by @min and @max 360 * arrays) and sets @mode->status as needed. 361 */ 362 void drm_mode_validate_clocks(struct drm_device *dev, 363 struct list_head *mode_list, 364 int *min, int *max, int n_ranges) 365 { 366 struct drm_display_mode *mode; 367 int i; 368 369 list_for_each_entry(mode, mode_list, head) { 370 bool good = false; 371 for (i = 0; i < n_ranges; i++) { 372 if (mode->clock >= min[i] && mode->clock <= max[i]) { 373 good = true; 374 break; 375 } 376 } 377 if (!good) 378 mode->status = MODE_CLOCK_RANGE; 379 } 380 } 381 EXPORT_SYMBOL(drm_mode_validate_clocks); 382 383 /** 384 * drm_mode_prune_invalid - remove invalid modes from mode list 385 * @dev: DRM device 386 * @mode_list: list of modes to check 387 * @verbose: be verbose about it 388 * 389 * LOCKING: 390 * Caller must hold a lock protecting @mode_list. 391 * 392 * Once mode list generation is complete, a caller can use this routine to 393 * remove invalid modes from a mode list. If any of the modes have a 394 * status other than %MODE_OK, they are removed from @mode_list and freed. 395 */ 396 void drm_mode_prune_invalid(struct drm_device *dev, 397 struct list_head *mode_list, bool verbose) 398 { 399 struct drm_display_mode *mode, *t; 400 401 list_for_each_entry_safe(mode, t, mode_list, head) { 402 if (mode->status != MODE_OK) { 403 list_del(&mode->head); 404 if (verbose) { 405 drm_mode_debug_printmodeline(mode); 406 DRM_DEBUG_MODE(DRM_MODESET_DEBUG, 407 "Not using %s mode %d\n", 408 mode->name, mode->status); 409 } 410 drm_mode_destroy(dev, mode); 411 } 412 } 413 } 414 EXPORT_SYMBOL(drm_mode_prune_invalid); 415 416 /** 417 * drm_mode_compare - compare modes for favorability 418 * @lh_a: list_head for first mode 419 * @lh_b: list_head for second mode 420 * 421 * LOCKING: 422 * None. 423 * 424 * Compare two modes, given by @lh_a and @lh_b, returning a value indicating 425 * which is better. 426 * 427 * RETURNS: 428 * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or 429 * positive if @lh_b is better than @lh_a. 430 */ 431 static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) 432 { 433 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); 434 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head); 435 int diff; 436 437 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) - 438 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0); 439 if (diff) 440 return diff; 441 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay; 442 if (diff) 443 return diff; 444 diff = b->clock - a->clock; 445 return diff; 446 } 447 448 /* FIXME: what we don't have a list sort function? */ 449 /* list sort from Mark J Roberts (mjr@znex.org) */ 450 void list_sort(struct list_head *head, 451 int (*cmp)(struct list_head *a, struct list_head *b)) 452 { 453 struct list_head *p, *q, *e, *list, *tail, *oldhead; 454 int insize, nmerges, psize, qsize, i; 455 456 list = head->next; 457 list_del(head); 458 insize = 1; 459 for (;;) { 460 p = oldhead = list; 461 list = tail = NULL; 462 nmerges = 0; 463 464 while (p) { 465 nmerges++; 466 q = p; 467 psize = 0; 468 for (i = 0; i < insize; i++) { 469 psize++; 470 q = q->next == oldhead ? NULL : q->next; 471 if (!q) 472 break; 473 } 474 475 qsize = insize; 476 while (psize > 0 || (qsize > 0 && q)) { 477 if (!psize) { 478 e = q; 479 q = q->next; 480 qsize--; 481 if (q == oldhead) 482 q = NULL; 483 } else if (!qsize || !q) { 484 e = p; 485 p = p->next; 486 psize--; 487 if (p == oldhead) 488 p = NULL; 489 } else if (cmp(p, q) <= 0) { 490 e = p; 491 p = p->next; 492 psize--; 493 if (p == oldhead) 494 p = NULL; 495 } else { 496 e = q; 497 q = q->next; 498 qsize--; 499 if (q == oldhead) 500 q = NULL; 501 } 502 if (tail) 503 tail->next = e; 504 else 505 list = e; 506 e->prev = tail; 507 tail = e; 508 } 509 p = q; 510 } 511 512 tail->next = list; 513 list->prev = tail; 514 515 if (nmerges <= 1) 516 break; 517 518 insize *= 2; 519 } 520 521 head->next = list; 522 head->prev = list->prev; 523 list->prev->next = head; 524 list->prev = head; 525 } 526 527 /** 528 * drm_mode_sort - sort mode list 529 * @mode_list: list to sort 530 * 531 * LOCKING: 532 * Caller must hold a lock protecting @mode_list. 533 * 534 * Sort @mode_list by favorability, putting good modes first. 535 */ 536 void drm_mode_sort(struct list_head *mode_list) 537 { 538 list_sort(mode_list, drm_mode_compare); 539 } 540 EXPORT_SYMBOL(drm_mode_sort); 541 542 /** 543 * drm_mode_connector_list_update - update the mode list for the connector 544 * @connector: the connector to update 545 * 546 * LOCKING: 547 * Caller must hold a lock protecting @mode_list. 548 * 549 * This moves the modes from the @connector probed_modes list 550 * to the actual mode list. It compares the probed mode against the current 551 * list and only adds different modes. All modes unverified after this point 552 * will be removed by the prune invalid modes. 553 */ 554 void drm_mode_connector_list_update(struct drm_connector *connector) 555 { 556 struct drm_display_mode *mode; 557 struct drm_display_mode *pmode, *pt; 558 int found_it; 559 560 list_for_each_entry_safe(pmode, pt, &connector->probed_modes, 561 head) { 562 found_it = 0; 563 /* go through current modes checking for the new probed mode */ 564 list_for_each_entry(mode, &connector->modes, head) { 565 if (drm_mode_equal(pmode, mode)) { 566 found_it = 1; 567 /* if equal delete the probed mode */ 568 mode->status = pmode->status; 569 list_del(&pmode->head); 570 drm_mode_destroy(connector->dev, pmode); 571 break; 572 } 573 } 574 575 if (!found_it) { 576 list_move_tail(&pmode->head, &connector->modes); 577 } 578 } 579 } 580 EXPORT_SYMBOL(drm_mode_connector_list_update); 581