Subversion Repositories Kolibri OS

Rev

Rev 1179 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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 <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.