drm_modes.c 14 KB

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