drm_modes.c 14 KB

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