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