Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2004-2008  Luc Verhaegen <lverhaegen@novell.com>
  3.  * Copyright 2007, 2008 Matthias Hopf <mhopf@novell.com>
  4.  * Copyright 2007, 2008 Egbert Eich   <eich@novell.com>
  5.  * Copyright 2007, 2008 Advanced Micro Devices, Inc.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the "Software"),
  9.  * to deal in the Software without restriction, including without limitation
  10.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11.  * and/or sell copies of the Software, and to permit persons to whom the
  12.  * Software is furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included in
  15.  * all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.  * OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26. #ifdef HAVE_CONFIG_H
  27. #include "config.h"
  28. #endif
  29.  
  30. #include "xf86.h"
  31. #if HAVE_XF86_ANSIC_H
  32. # include "xf86_ansic.h"
  33. #else
  34. # include <stdio.h>
  35. # include <string.h>
  36. #endif
  37.  
  38.  
  39. #include "rhd.h"
  40.  
  41. #include "edid.h"
  42. #include "xf86DDC.h"
  43.  
  44. #include "rhd_crtc.h"
  45. #include "rhd_pll.h"
  46. #include "rhd_connector.h"
  47. #include "rhd_output.h"
  48. #include "rhd_modes.h"
  49. #include "rhd_monitor.h"
  50.  
  51. /* For Acceleration FB validation */
  52. //#include "r5xx_accel.h"
  53.  
  54. /*
  55.  * Define a set of own mode errors.
  56.  */
  57. #define RHD_MODE_STATUS 0x51B00
  58. #ifndef MONREC_HAS_REDUCED
  59. #define MODE_NO_REDUCED     0x01 + RHD_MODE_STATUS
  60. #endif
  61. #define MODE_MEM_BW         0x02 + RHD_MODE_STATUS
  62. #define MODE_OUTPUT_UNDEF   0x03 + RHD_MODE_STATUS
  63. #define MODE_NOT_PAL        0x04 + RHD_MODE_STATUS
  64. #define MODE_NOT_NTSC       0x05 + RHD_MODE_STATUS
  65. #define MODE_HTOTAL_WIDE    0x06 + RHD_MODE_STATUS
  66. #define MODE_HDISPLAY_WIDE  0x07 + RHD_MODE_STATUS
  67. #define MODE_HSYNC_RANGE    0x08 + RHD_MODE_STATUS
  68. #define MODE_HBLANK_RANGE   0x09 + RHD_MODE_STATUS
  69. #define MODE_VTOTAL_WIDE    0x0A + RHD_MODE_STATUS
  70. #define MODE_VDISPLAY_WIDE  0x0B + RHD_MODE_STATUS
  71. #define MODE_VSYNC_RANGE    0x0C + RHD_MODE_STATUS
  72. #define MODE_VBLANK_RANGE   0x0D + RHD_MODE_STATUS
  73. #define MODE_PITCH          0x0E + RHD_MODE_STATUS
  74. #define MODE_OFFSET         0x0F + RHD_MODE_STATUS
  75. #define MODE_MINHEIGHT      0x10 + RHD_MODE_STATUS
  76. #define MODE_FIXED          0x11 + RHD_MODE_STATUS
  77. #define MODE_SCALE          0x12 + RHD_MODE_STATUS
  78.  
  79. /*
  80.  * Don't bother with checking whether X offers this. Just use the internal one
  81.  * I'm the author of the X side one anyway.
  82.  */
  83.  
  84. /*
  85.  * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh.
  86.  *
  87.  * These calculations are stolen from the CVT calculation spreadsheet written
  88.  * by Graham Loveridge. He seems to be claiming no copyright and there seems to
  89.  * be no license attached to this. He apparently just wants to see his name
  90.  * mentioned.
  91.  *
  92.  * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls
  93.  *
  94.  * Comments and structure corresponds to the comments and structure of the xls.
  95.  * This should ease importing of future changes to the standard (not very
  96.  * likely though).
  97.  *
  98.  * About margins; i'm sure that they are to be the bit between HDisplay and
  99.  * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and
  100.  * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking
  101.  * outside sync "margin" for some reason. Since we prefer seeing proper
  102.  * blanking instead of the overscan colour, and since the Crtc* values will
  103.  * probably get altered after us, we will disable margins altogether. With
  104.  * these calculations, Margins will plainly expand H/VDisplay, and we don't
  105.  * want that. -- libv
  106.  *
  107.  */
  108. DisplayModePtr
  109. RHDCVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced,
  110.            Bool Interlaced)
  111. {
  112.     DisplayModeRec  *Mode = xnfalloc(sizeof(DisplayModeRec));
  113.  
  114.     /* 1) top/bottom margin size (% of height) - default: 1.8 */
  115. #define CVT_MARGIN_PERCENTAGE 1.8
  116.  
  117.     /* 2) character cell horizontal granularity (pixels) - default 8 */
  118. #define CVT_H_GRANULARITY 1
  119.  
  120.     /* 4) Minimum vertical porch (lines) - default 3 */
  121. #define CVT_MIN_V_PORCH 3
  122.  
  123.     /* 4) Minimum number of vertical back porch lines - default 6 */
  124. #define CVT_MIN_V_BPORCH 6
  125.  
  126.     /* Pixel Clock step (kHz) */
  127. #define CVT_CLOCK_STEP 250
  128.  
  129.     Bool Margins = FALSE;
  130.     float  VFieldRate, HPeriod;
  131.     int  HDisplayRnd, HMargin;
  132.     int  VDisplayRnd, VMargin, VSync;
  133.     float  Interlace; /* Please rename this */
  134.  
  135.     memset(Mode, 0, sizeof(DisplayModeRec));
  136.  
  137.     /* CVT default is 60.0Hz */
  138.     if (!VRefresh)
  139.         VRefresh = 60.0;
  140.  
  141.     /* 1. Required field rate */
  142.     if (Interlaced)
  143.         VFieldRate = VRefresh * 2;
  144.     else
  145.         VFieldRate = VRefresh;
  146.  
  147.     /* 2. Horizontal pixels */
  148.     HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY);
  149.  
  150.     /* 3. Determine left and right borders */
  151.     if (Margins) {
  152.         /* right margin is actually exactly the same as left */
  153.         HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
  154.         HMargin -= HMargin % CVT_H_GRANULARITY;
  155.     } else
  156.         HMargin = 0;
  157.  
  158.     /* 4. Find total active pixels */
  159.     Mode->HDisplay = HDisplayRnd + 2*HMargin;
  160.  
  161.     /* 5. Find number of lines per field */
  162.     if (Interlaced)
  163.         VDisplayRnd = VDisplay / 2;
  164.     else
  165.         VDisplayRnd = VDisplay;
  166.  
  167.     /* 6. Find top and bottom margins */
  168.     /* nope. */
  169.     if (Margins)
  170.         /* top and bottom margins are equal again. */
  171.         VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
  172.     else
  173.         VMargin = 0;
  174.  
  175.     Mode->VDisplay = VDisplay + 2*VMargin;
  176.  
  177.     /* 7. Interlace */
  178.     if (Interlaced)
  179.         Interlace = 0.5;
  180.     else
  181.         Interlace = 0.0;
  182.  
  183.     /* Determine VSync Width from aspect ratio */
  184.     if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay))
  185.         VSync = 4;
  186.     else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay))
  187.         VSync = 5;
  188.     else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay))
  189.         VSync = 6;
  190.     else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay))
  191.         VSync = 7;
  192.     else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))
  193.         VSync = 7;
  194.     else /* Custom */
  195.         VSync = 10;
  196.  
  197.     if (!Reduced) { /* simplified GTF calculation */
  198.  
  199.         /* 4) Minimum time of vertical sync + back porch interval (µs)
  200.          * default 550.0 */
  201. #define CVT_MIN_VSYNC_BP 550.0
  202.  
  203.         /* 3) Nominal HSync width (% of line period) - default 8 */
  204. #define CVT_HSYNC_PERCENTAGE 8
  205.  
  206.         float  HBlankPercentage;
  207.         int  VSyncAndBackPorch, VBackPorch;
  208.         int  HBlank;
  209.  
  210.         /* 8. Estimated Horizontal period */
  211.         HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) /
  212.             (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace);
  213.  
  214.         /* 9. Find number of lines in sync + backporch */
  215.         if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH))
  216.             VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH;
  217.         else
  218.             VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1;
  219.  
  220.         /* 10. Find number of lines in back porch */
  221.         VBackPorch = VSyncAndBackPorch - VSync;
  222.  
  223.         /* 11. Find total number of lines in vertical field */
  224.         Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace
  225.             + CVT_MIN_V_PORCH;
  226.  
  227.         /* 5) Definition of Horizontal blanking time limitation */
  228.         /* Gradient (%/kHz) - default 600 */
  229. #define CVT_M_FACTOR 600
  230.  
  231.         /* Offset (%) - default 40 */
  232. #define CVT_C_FACTOR 40
  233.  
  234.         /* Blanking time scaling factor - default 128 */
  235. #define CVT_K_FACTOR 128
  236.  
  237.         /* Scaling factor weighting - default 20 */
  238. #define CVT_J_FACTOR 20
  239.  
  240. #define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256
  241. #define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
  242.         CVT_J_FACTOR
  243.  
  244.         /* 12. Find ideal blanking duty cycle from formula */
  245.         HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0;
  246.  
  247.         /* 13. Blanking time */
  248.         if (HBlankPercentage < 20)
  249.             HBlankPercentage = 20;
  250.  
  251.         HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage);
  252.         HBlank -= HBlank % (2*CVT_H_GRANULARITY);
  253.  
  254.         /* 14. Find total number of pixels in a line. */
  255.         Mode->HTotal = Mode->HDisplay + HBlank;
  256.  
  257.         /* Fill in HSync values */
  258.         Mode->HSyncEnd = Mode->HDisplay + HBlank / 2;
  259.  
  260.         Mode->HSyncStart = Mode->HSyncEnd -
  261.             (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100;
  262.         Mode->HSyncStart += CVT_H_GRANULARITY -
  263.             Mode->HSyncStart % CVT_H_GRANULARITY;
  264.  
  265.         /* Fill in VSync values */
  266.         Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH;
  267.         Mode->VSyncEnd = Mode->VSyncStart + VSync;
  268.  
  269.     } else { /* Reduced blanking */
  270.         /* Minimum vertical blanking interval time (µs) - default 460 */
  271. #define CVT_RB_MIN_VBLANK 460.0
  272.  
  273.         /* Fixed number of clocks for horizontal sync */
  274. #define CVT_RB_H_SYNC 32.0
  275.  
  276.         /* Fixed number of clocks for horizontal blanking */
  277. #define CVT_RB_H_BLANK 160.0
  278.  
  279.         /* Fixed number of lines for vertical front porch - default 3 */
  280. #define CVT_RB_VFPORCH 3
  281.  
  282.         int  VBILines;
  283.  
  284.         /* 8. Estimate Horizontal period. */
  285.         HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) /
  286.             (VDisplayRnd + 2*VMargin);
  287.  
  288.         /* 9. Find number of lines in vertical blanking */
  289.         VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
  290.  
  291.         /* 10. Check if vertical blanking is sufficient */
  292.         if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
  293.             VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
  294.  
  295.         /* 11. Find total number of lines in vertical field */
  296.         Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines;
  297.  
  298.         /* 12. Find total number of pixels in a line */
  299.         Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK;
  300.  
  301.         /* Fill in HSync values */
  302.         Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2;
  303.         Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC;
  304.  
  305.         /* Fill in VSync values */
  306.         Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH;
  307.         Mode->VSyncEnd = Mode->VSyncStart + VSync;
  308.     }
  309.  
  310.     /* 15/13. Find pixel clock frequency (kHz for xf86) */
  311.     Mode->Clock = Mode->HTotal * 1000.0 / HPeriod;
  312.     Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP;
  313.  
  314.     /* 16/14. Find actual Horizontal Frequency (kHz) */
  315.     Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal);
  316.  
  317.     /* 17/15. Find actual Field rate */
  318.     Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
  319.         ((float) (Mode->HTotal * Mode->VTotal));
  320.  
  321.     /* 18/16. Find actual vertical frame frequency */
  322.     /* ignore - just set the mode flag for interlaced */
  323.     if (Interlaced)
  324.         Mode->VTotal *= 2;
  325.  
  326.     {
  327.         char  Name[256];
  328.         Name[0] = 0;
  329.  
  330.         snprintf(Name, 256, "%dx%d", HDisplay, VDisplay);
  331.         Mode->name = strdup(Name);
  332.     }
  333.  
  334.     if (Reduced)
  335.         Mode->Flags |= V_PHSYNC | V_NVSYNC;
  336.     else
  337.         Mode->Flags |= V_NHSYNC | V_PVSYNC;
  338.  
  339.     if (Interlaced)
  340.         Mode->Flags |= V_INTERLACE;
  341.  
  342.     return Mode;
  343. }
  344.  
  345. /*
  346.  * Temporary.
  347.  */
  348. static void
  349. add(char **p, char *new)
  350. {
  351. //  char *tmp = kmalloc(strlen(*p) + strlen(new) + 2);
  352.  
  353.   *p = (char*)realloc(*p, strlen(*p) + strlen(new) + 2);
  354.   strcat(*p, " ");
  355.   strcat(*p, new);
  356. }
  357.  
  358. /*
  359.  *
  360.  */
  361. Bool
  362. rhdModesEqual(DisplayModePtr mode1, DisplayModePtr mode2)
  363. {
  364.     if (mode1->Clock == mode2->Clock
  365.         && mode1->HDisplay == mode2->HDisplay
  366.         && mode1->HSyncStart == mode2->HSyncStart
  367.         && mode1->HSyncEnd == mode2->HSyncEnd
  368.         && mode1->HTotal == mode2->HTotal
  369.         && mode1->HSkew == mode2->HSkew
  370.         && mode1->VDisplay == mode2->VDisplay
  371.         && mode1->VSyncStart == mode2->VSyncStart
  372.         && mode1->VSyncEnd == mode2->VSyncEnd
  373.         && mode1->VTotal == mode2->VTotal
  374.         && mode1->VScan == mode2->VScan
  375.         && mode1->Flags == mode2->Flags)
  376.         return TRUE;
  377.  
  378.     return FALSE;
  379. }
  380.  
  381. /*
  382.  *
  383.  */
  384. void
  385. RHDPrintModeline(DisplayModePtr mode)
  386. {
  387.     char tmp[256];
  388.     char *flags = xnfcalloc(1, 1);
  389.  
  390.     if (mode->HSkew) {
  391.         snprintf(tmp, 256, "hskew %i", mode->HSkew);
  392.         add(&flags, tmp);
  393.     }
  394.     if (mode->VScan) {
  395.         snprintf(tmp, 256, "vscan %i", mode->VScan);
  396.         add(&flags, tmp);
  397.     }
  398.     if (mode->Flags & V_INTERLACE) add(&flags, "interlace");
  399.     if (mode->Flags & V_CSYNC) add(&flags, "composite");
  400.     if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan");
  401.     if (mode->Flags & V_BCAST) add(&flags, "bcast");
  402.     if (mode->Flags & V_PHSYNC) add(&flags, "+hsync");
  403.     if (mode->Flags & V_NHSYNC) add(&flags, "-hsync");
  404.     if (mode->Flags & V_PVSYNC) add(&flags, "+vsync");
  405.     if (mode->Flags & V_NVSYNC) add(&flags, "-vsync");
  406.     if (mode->Flags & V_PCSYNC) add(&flags, "+csync");
  407.     if (mode->Flags & V_NCSYNC) add(&flags, "-csync");
  408. #if 0
  409.     if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2");
  410. #endif
  411.     xf86Msg(X_NONE, "Modeline \"%s\"  %6.2f  %i %i %i %i  %i %i %i %i%s\n",
  412.             mode->name, mode->Clock/1000.,
  413.             mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
  414.             mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal,
  415.             flags);
  416.     xfree(flags);
  417. }
  418.  
  419. /*
  420.  * xf86Mode.c should have a some more DisplayModePtr list handling.
  421.  */
  422. DisplayModePtr
  423. RHDModesAdd(DisplayModePtr Modes, DisplayModePtr Additions)
  424. {
  425.     if (!Modes) {
  426.         if (Additions)
  427.             return Additions;
  428.         else
  429.             return NULL;
  430.     }
  431.  
  432.     if (Additions) {
  433.         DisplayModePtr Mode = Modes;
  434.  
  435.         while (Mode->next)
  436.             Mode = Mode->next;
  437.  
  438.         Mode->next = Additions;
  439.         Additions->prev = Mode;
  440.     }
  441.  
  442.     return Modes;
  443. }
  444.  
  445. /*
  446.  *
  447.  */
  448. static DisplayModePtr
  449. rhdModeDelete(DisplayModePtr Modes, DisplayModePtr Delete)
  450. {
  451.     DisplayModePtr Next, Previous;
  452.  
  453.     if (!Delete)
  454.         return Modes;
  455.  
  456.     if (Modes == Delete)
  457.         Modes = NULL;
  458.  
  459.     if (Delete->next == Delete)
  460.         Delete->next = NULL;
  461.  
  462.     if (Delete->prev == Delete)
  463.         Delete->next = NULL;
  464.  
  465.     Next = Delete->next;
  466.     Previous = Delete->prev;
  467.  
  468.     if (Next)
  469.         Next->prev = Previous;
  470.  
  471.     if (Previous)
  472.         Previous->next = Next;
  473.  
  474.     xfree(Delete->name);
  475.     xfree(Delete);
  476.  
  477.     if (Modes)
  478.         return Modes;
  479.  
  480.     if (Next)
  481.         return Next;
  482.  
  483.     if (Previous)
  484.         while (Previous->prev)
  485.             Previous = Previous->prev;
  486.  
  487.     return Previous;
  488. }
  489.  
  490. /*
  491.  *
  492.  */
  493. DisplayModePtr
  494. RHDModeCopy(DisplayModePtr Mode)
  495. {
  496.     DisplayModePtr New;
  497.  
  498.     if (!Mode)
  499.         return NULL;
  500.  
  501.     New = xnfalloc(sizeof(DisplayModeRec));
  502.     memcpy(New, Mode, sizeof(DisplayModeRec)); /* re-use private */
  503.     New->name = strdup(Mode->name);
  504.     New->prev = NULL;
  505.     New->next = NULL;
  506.     New->Private = Mode->Private;
  507.     New->PrivSize = Mode->PrivSize;
  508.  
  509.     return New;
  510. }
  511.  
  512. /*
  513.  *
  514.  */
  515. static void
  516. rhdModesDestroy(DisplayModePtr Modes)
  517. {
  518.     DisplayModePtr mode = Modes, next;
  519.  
  520.     while (mode) {
  521.         next = mode->next;
  522.         xfree(mode->name);
  523.         xfree(mode);
  524.         mode = next;
  525.     }
  526. }
  527.  
  528. /*
  529.  * Basic sanity checks.
  530.  */
  531. static int
  532. rhdModeSanity(RHDPtr rhdPtr, DisplayModePtr Mode)
  533. {
  534.     /* do we need to bother at all? */
  535.     if (Mode->status != MODE_OK)
  536.         return Mode->status;
  537.  
  538.     if (!Mode->name) {
  539.         xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
  540.                    "Validation found mode without name.\n");
  541.         return MODE_ERROR;
  542.     }
  543.  
  544.     if (Mode->Clock <= 0)
  545.         return MODE_NOCLOCK;
  546.  
  547.     if ((Mode->HDisplay <= 0) || (Mode->HSyncStart <= 0) ||
  548.         (Mode->HSyncEnd <= 0) || (Mode->HTotal <= 0))
  549.         return MODE_H_ILLEGAL;
  550.  
  551.     if ((Mode->HTotal <= Mode->HSyncEnd) ||
  552.         (Mode->HSyncEnd <= Mode->HSyncStart) ||
  553.         (Mode->HSyncStart < Mode->HDisplay))
  554.         return MODE_H_ILLEGAL;
  555.  
  556.     /* HSkew? */
  557.  
  558.     if ((Mode->VDisplay <= 0) || (Mode->VSyncStart <= 0) ||
  559.         (Mode->VSyncEnd <= 0) || (Mode->VTotal <= 0))
  560.         return MODE_V_ILLEGAL;
  561.  
  562.     if ((Mode->VTotal <= Mode->VSyncEnd) ||
  563.         (Mode->VSyncEnd <= Mode->VSyncStart) ||
  564.         (Mode->VSyncStart < Mode->VDisplay))
  565.         return MODE_V_ILLEGAL;
  566.  
  567.     if ((Mode->VScan != 0) && (Mode->VScan != 1))
  568.         return MODE_NO_VSCAN;
  569.  
  570.     if (Mode->Flags & V_DBLSCAN)
  571.         return MODE_NO_DBLESCAN;
  572.  
  573.     /* Flags */
  574.     return MODE_OK;
  575. }
  576.  
  577. /*
  578.  * After we passed the initial sanity check, we need to fill out the CRTC
  579.  * values.
  580.  */
  581. static void
  582. rhdModeFillOutCrtcValues(DisplayModePtr Mode)
  583. {
  584.     /* do we need to bother at all? */
  585.     if (Mode->status != MODE_OK)
  586.         return;
  587.  
  588.     Mode->ClockIndex = -1; /* Always! direct non-programmable support must die. */
  589.  
  590.     if (!Mode->SynthClock)
  591.         Mode->SynthClock = Mode->Clock;
  592.  
  593.     if (!Mode->CrtcHDisplay)
  594.         Mode->CrtcHDisplay = Mode->HDisplay;
  595.  
  596.     if (!Mode->CrtcHBlankStart)
  597.         Mode->CrtcHBlankStart = Mode->HDisplay;
  598.  
  599.     if (!Mode->CrtcHSyncStart)
  600.         Mode->CrtcHSyncStart = Mode->HSyncStart;
  601.  
  602.     if (!Mode->CrtcHSyncEnd)
  603.         Mode->CrtcHSyncEnd = Mode->HSyncEnd;
  604.  
  605.     if (!Mode->CrtcHBlankEnd)
  606.         Mode->CrtcHBlankEnd = Mode->HTotal;
  607.  
  608.     if (!Mode->CrtcHTotal)
  609.         Mode->CrtcHTotal = Mode->HTotal;
  610.  
  611.     if (!Mode->CrtcHSkew)
  612.         Mode->CrtcHSkew = Mode->HSkew;
  613.  
  614.     if (!Mode->CrtcVDisplay)
  615.         Mode->CrtcVDisplay = Mode->VDisplay;
  616.  
  617.     if (!Mode->CrtcVBlankStart)
  618.         Mode->CrtcVBlankStart = Mode->VDisplay;
  619.  
  620.     if (!Mode->CrtcVSyncStart)
  621.         Mode->CrtcVSyncStart = Mode->VSyncStart;
  622.  
  623.     if (!Mode->CrtcVSyncEnd)
  624.         Mode->CrtcVSyncEnd = Mode->VSyncEnd;
  625.  
  626.     if (!Mode->CrtcVBlankEnd)
  627.         Mode->CrtcVBlankEnd = Mode->VTotal;
  628.  
  629.     if (!Mode->CrtcVTotal)
  630.         Mode->CrtcVTotal = Mode->VTotal;
  631.  
  632.     /* Always change these */
  633.     Mode->HSync = ((float) Mode->SynthClock) / Mode->CrtcHTotal;
  634.     Mode->VRefresh = (Mode->SynthClock * 1000.0) /
  635.         (Mode->CrtcHTotal * Mode->CrtcVTotal);
  636.     if (Mode->Flags & V_INTERLACE)
  637.         Mode->VRefresh *= 2.0;
  638.     if (Mode->Flags & V_DBLSCAN)
  639.         Mode->VRefresh /= 2.0;
  640.  
  641.     /* We're usually first in the chain, right after rhdModeSanity. */
  642.     Mode->CrtcHAdjusted = FALSE;
  643.     Mode->CrtcVAdjusted = FALSE;
  644.  
  645.     /* Steer clear of PrivSize, Private and PrivFlags */
  646. }
  647.  
  648. /*
  649.  * Basic sanity checks.
  650.  */
  651. static int
  652. rhdModeCrtcSanity(DisplayModePtr Mode)
  653. {
  654.     if (Mode->SynthClock <= 0)
  655.         return MODE_NOCLOCK;
  656.  
  657.     if ((Mode->CrtcHDisplay <= 0) || (Mode->CrtcHBlankStart <= 0) ||
  658.         (Mode->CrtcHSyncStart <= 0) || (Mode->CrtcHSyncEnd <= 0) ||
  659.         (Mode->CrtcHBlankEnd <= 0) || (Mode->CrtcHTotal <= 0))
  660.         return MODE_H_ILLEGAL;
  661.  
  662.     /* there seem to be no alignment constraints on horizontal timing on our
  663.        hardware here */
  664.  
  665.     if ((Mode->CrtcHTotal < Mode->CrtcHBlankEnd) ||
  666.         (Mode->CrtcHBlankEnd <= Mode->CrtcHSyncEnd) ||
  667.         (Mode->CrtcHSyncEnd <= Mode->CrtcHSyncStart) ||
  668.         (Mode->CrtcHSyncStart < Mode->CrtcHBlankStart) ||
  669.         (Mode->CrtcHBlankStart < Mode->CrtcHDisplay))
  670.         return MODE_H_ILLEGAL;
  671.  
  672.     /* CrtcHSkew? */
  673.  
  674.     if ((Mode->CrtcVDisplay <= 0) || (Mode->CrtcVBlankStart <= 0) ||
  675.         (Mode->CrtcVSyncStart <= 0) || (Mode->CrtcVSyncEnd <= 0) ||
  676.         (Mode->CrtcVBlankEnd <= 0) || (Mode->CrtcVTotal <= 0))
  677.         return MODE_V_ILLEGAL;
  678.  
  679.     if ((Mode->CrtcVTotal < Mode->CrtcVBlankEnd) ||
  680.         (Mode->CrtcVBlankEnd <= Mode->CrtcVSyncEnd) ||
  681.         (Mode->CrtcVSyncEnd <= Mode->CrtcVSyncStart) ||
  682.         (Mode->CrtcVSyncStart < Mode->CrtcVBlankStart) ||
  683.         (Mode->CrtcVBlankStart < Mode->CrtcVDisplay))
  684.         return MODE_V_ILLEGAL;
  685.  
  686.     return MODE_OK;
  687. }
  688.  
  689. /*
  690.  *
  691.  */
  692. static Bool
  693. rhdMonitorFixedValid(struct rhdMonitor *Monitor, DisplayModePtr Mode)
  694. {
  695.     DisplayModePtr Fixed;
  696.  
  697.     for (Fixed = Monitor->Modes; Fixed; Fixed = Fixed->next) {
  698.         if ((Mode->Flags != Fixed->Flags) ||
  699.             (Mode->Clock != Fixed->Clock) ||
  700.             (Mode->SynthClock != Fixed->Clock))
  701.             continue;
  702.  
  703.         if ((Mode->HDisplay > Fixed->HDisplay) ||
  704.             (Mode->VDisplay > Fixed->VDisplay))
  705.             continue;
  706.  
  707.         if ((Mode->HSyncStart != Fixed->HSyncStart) ||
  708.             (Mode->HSyncEnd != Fixed->HSyncEnd))
  709.             continue;
  710.  
  711.         if ((Mode->VSyncStart != Fixed->VSyncStart) ||
  712.             (Mode->VSyncEnd != Fixed->VSyncEnd))
  713.             continue;
  714.  
  715.         if ((Mode->CrtcHDisplay > Fixed->HDisplay) ||
  716.             (Mode->CrtcVDisplay > Fixed->VDisplay))
  717.             continue;
  718.  
  719.         if ((Mode->CrtcHBlankStart != Fixed->HDisplay) ||
  720.             (Mode->CrtcHSyncStart != Fixed->HSyncStart) ||
  721.             (Mode->CrtcHSyncEnd != Fixed->HSyncEnd) ||
  722.             (Mode->CrtcHBlankEnd != Fixed->HTotal))
  723.             continue;
  724.  
  725.         if ((Mode->CrtcVBlankStart != Fixed->VDisplay) ||
  726.             (Mode->CrtcVSyncStart != Fixed->VSyncStart) ||
  727.             (Mode->CrtcVSyncEnd != Fixed->VSyncEnd) ||
  728.             (Mode->CrtcVBlankEnd != Fixed->VTotal))
  729.             continue;
  730.  
  731.         return TRUE;
  732.     }
  733.  
  734.     return FALSE;
  735. }
  736. /*
  737.  * TODO: review fixed modes when doing different modes on both crtcs.
  738.  */
  739. static int
  740. rhdMonitorValid(struct rhdMonitor *Monitor, DisplayModePtr Mode)
  741. {
  742.     int i;
  743.     Bool isNative = FALSE;
  744.  
  745.     if (Monitor->NativeMode && rhdModesEqual(Mode, Monitor->NativeMode))
  746.         isNative = TRUE;
  747.  
  748.     for (i = 0; i < Monitor->numHSync; i++)
  749.         if ((Mode->HSync >= (Monitor->HSync[i].lo * (1.0 - SYNC_TOLERANCE))) &&
  750.             (Mode->HSync <= (Monitor->HSync[i].hi * (1.0 + SYNC_TOLERANCE))))
  751.             break;
  752.     if (Monitor->numHSync && (i == Monitor->numHSync))
  753.         return MODE_HSYNC;
  754.  
  755.     for (i = 0; i < Monitor->numVRefresh; i++)
  756.         if ((Mode->VRefresh >= (Monitor->VRefresh[i].lo * (1.0 - SYNC_TOLERANCE))) &&
  757.             (Mode->VRefresh <= (Monitor->VRefresh[i].hi * (1.0 + SYNC_TOLERANCE))))
  758.             break;
  759.     if (Monitor->numVRefresh && (i == Monitor->numVRefresh))
  760.         return MODE_VSYNC;
  761.  
  762.     if (Monitor->Bandwidth &&
  763.         (Mode->SynthClock > (Monitor->Bandwidth * (1 + SYNC_TOLERANCE))))
  764.         return MODE_CLOCK_HIGH;
  765.  
  766.     if (isNative) { /* if it's this monitor's native mode be less strict on validation */
  767.     if (Monitor->ReducedAllowed) {
  768.             if ((Mode->CrtcHDisplay * 101) > (Mode->CrtcHTotal * 100)) /* 1% */
  769.             return MODE_HBLANK_NARROW;
  770.     } else { /* no reduced blanking */
  771.         if ((Mode->CrtcHDisplay * 23) > (Mode->CrtcHTotal * 20)) /* 15% */
  772.             return MODE_HBLANK_NARROW;
  773.     }
  774.     } else {
  775.         if (((Mode->CrtcHDisplay * 5 / 4) & ~0x07) > Mode->CrtcHTotal) {
  776.             /* is this a cvt -r Mode, and only a cvt -r Mode? */
  777.             if (((Mode->CrtcHTotal - Mode->CrtcHDisplay) == 160) &&
  778.                 ((Mode->CrtcHSyncEnd - Mode->CrtcHDisplay) == 80) &&
  779.                 ((Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart) == 32) &&
  780.                 ((Mode->CrtcVSyncStart - Mode->CrtcVDisplay) == 3)) {
  781.                 if (!Monitor->ReducedAllowed)
  782.                     return MODE_NO_REDUCED;
  783.             } else if ((Mode->CrtcHDisplay * 11) > (Mode->CrtcHTotal * 10))
  784.                 return MODE_HSYNC_NARROW;
  785.         }
  786.     }
  787.  
  788.     if (Monitor->UseFixedModes && !rhdMonitorFixedValid(Monitor, Mode))
  789.         return MODE_FIXED;
  790.  
  791.     return MODE_OK;
  792. }
  793.  
  794. #define RHD_MODE_VALIDATION_LOOPS 10
  795.  
  796. enum ValidationKind {
  797.     VALIDATE_SCALE_NONE,
  798.     VALIDATE_SCALE_FROM,
  799.     VALIDATE_SCALE_TO
  800. };
  801.  
  802. /*
  803.  *
  804.  */
  805. static int
  806. rhdModeValidateCrtc(struct rhdCrtc *Crtc, DisplayModePtr Mode, enum ValidationKind ValidateScaleModeKind)
  807. {
  808.     RHDPtr rhdPtr = RHDPTRI(Crtc);
  809.     ScrnInfoPtr pScrn = rhdPtr->pScrn;
  810.     int Status, i;
  811.  
  812.     RHDFUNC(Crtc);
  813.  
  814.     Status = rhdModeSanity(rhdPtr, Mode);
  815.     if (Status != MODE_OK)
  816.         return Status;
  817.  
  818.     rhdModeFillOutCrtcValues(Mode);
  819.  
  820.     /* We don't want to loop around this forever */
  821.     for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) {
  822.         struct rhdOutput *Output;
  823.  
  824.         Mode->CrtcHAdjusted = FALSE;
  825.         Mode->CrtcVAdjusted = FALSE;
  826.  
  827.         Status = rhdModeCrtcSanity(Mode);
  828.         if (Status != MODE_OK)
  829.             return Status;
  830.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  831.             continue;
  832.  
  833.         if (ValidateScaleModeKind != VALIDATE_SCALE_TO) {
  834.  
  835.         Status = Crtc->FBValid(Crtc, Mode->CrtcHDisplay, Mode->CrtcVDisplay,
  836.                                pScrn->bitsPerPixel, rhdPtr->FbScanoutStart,
  837.                                rhdPtr->FbScanoutSize, NULL);
  838.         if (Status != MODE_OK)
  839.             return Status;
  840.  
  841.             if (Crtc->ScaleValid) {
  842.                 if (ValidateScaleModeKind == VALIDATE_SCALE_NONE)
  843.                     Status = Crtc->ScaleValid(Crtc, RHD_CRTC_SCALE_TYPE_NONE, Mode, NULL);
  844.                 else
  845.                     Status = Crtc->ScaleValid(Crtc, Crtc->ScaleType, Mode, Crtc->ScaledToMode);
  846.         if (Status != MODE_OK)
  847.             return Status;
  848.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  849.             continue;
  850.             }
  851.         }
  852.  
  853.         if (ValidateScaleModeKind != VALIDATE_SCALE_FROM) {
  854.             Status = Crtc->ModeValid(Crtc, Mode);
  855.             if (Status != MODE_OK)
  856.                 return Status;
  857.             if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  858.                 continue;
  859.  
  860.             if (Crtc->PLL && Crtc->PLL->Valid) { /* RandR may not have PLL filled out. oh well... */
  861.             Status = Crtc->PLL->Valid(Crtc->PLL, Mode->Clock);
  862.             if (Status != MODE_OK)
  863.                 return Status;
  864.             if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  865.                 continue;
  866.         }
  867.  
  868.         for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
  869.             if (Output->Active && (Output->Crtc == Crtc)) {
  870.                 /* Check the output */
  871.                 Status = Output->ModeValid(Output, Mode);
  872.                 if (Status != MODE_OK)
  873.                     return Status;
  874.                 if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  875.                     break; /* restart. */
  876.  
  877.                 /* Check the monitor attached to this output */
  878.                 if (Output->Connector && Output->Connector->Monitor)
  879.                     Status = rhdMonitorValid(Output->Connector->Monitor, Mode);
  880.                 if (Status != MODE_OK)
  881.                     return Status;
  882.                 if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  883.                     break; /* restart. */
  884.             }
  885.  
  886.             if (Output) /* We're done. This must be a good mode. */
  887.                 continue;
  888.         }
  889.  
  890.             return MODE_OK;
  891.     }
  892.  
  893.     /* Mode has been bouncing around for ages, on adjustments */
  894.     xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was"
  895.                " thrown around for too long.\n", __func__, Mode->name,
  896.                Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0);
  897.     return MODE_ERROR;
  898. }
  899.  
  900. /*
  901.  *
  902.  */
  903. int
  904. RHDValidateScaledToMode(struct rhdCrtc *Crtc, DisplayModePtr Mode)
  905. {
  906.     RHDPtr rhdPtr = RHDPTRI(Crtc);
  907.     int Status;
  908.  
  909.     RHDFUNC(Crtc);
  910.  
  911.     Status = rhdModeSanity(rhdPtr, Mode);
  912.     if (Status != MODE_OK)
  913.         return Status;
  914.  
  915.     rhdModeFillOutCrtcValues(Mode);
  916.  
  917.     Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_TO);
  918.     if (Status != MODE_OK)
  919.         return Status;
  920.  
  921.     /* Do we want to also validate against a configured monitor? */
  922.     if (rhdPtr->ConfigMonitor) {
  923.         Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode);
  924.         if (Status != MODE_OK)
  925.             return Status;
  926.     }
  927.  
  928.     return MODE_OK;
  929. }
  930.  
  931. /*
  932.  *
  933.  */
  934. static int
  935. rhdModeValidate(ScrnInfoPtr pScrn, DisplayModePtr Mode)
  936. {
  937.     RHDPtr rhdPtr = RHDPTR(pScrn);
  938.     struct rhdCrtc *Crtc;
  939.     int Status;
  940.     int i;
  941.  
  942.     Status = rhdModeSanity(rhdPtr, Mode);
  943.     if (Status != MODE_OK)
  944.         return Status;
  945.  
  946.     rhdModeFillOutCrtcValues(Mode);
  947.  
  948.     /* now let our modesetting tree have its say */
  949.     for (i = 0; i < 2; i++) {
  950.         Crtc = rhdPtr->Crtc[i];
  951.         if (!Crtc->Active)
  952.             continue;
  953.  
  954.         if (!Crtc->ScaledToMode) {
  955.  
  956.             Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_NONE);
  957.         if (Status != MODE_OK)
  958.             return Status;
  959.  
  960.         } else {
  961.             Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_FROM);
  962.             if (Status != MODE_OK)
  963.                 return Status;
  964.     }
  965.     }
  966.  
  967.     /* throw them at the configured monitor, so that the inadequate
  968.      * conf file at least has some influence. */
  969.     if (rhdPtr->ConfigMonitor) {
  970.         Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode);
  971.         if (Status != MODE_OK)
  972.             return Status;
  973.     }
  974.  
  975.     /* Did we set up virtual resolution already? */
  976.     if ((pScrn->virtualX > 0) && (pScrn->virtualY > 0)) {
  977.         if (pScrn->virtualX < Mode->CrtcHDisplay)
  978.             return MODE_VIRTUAL_X;
  979.         if (pScrn->virtualY < Mode->CrtcVDisplay)
  980.             return MODE_VIRTUAL_Y;
  981.     }
  982.  
  983.     return MODE_OK;
  984. }
  985.  
  986. /*
  987.  * Wrap the limited xf86 Mode statusses with our own message.
  988.  */
  989. struct {
  990.     int Status;
  991.     char *Message;
  992. } rhdModeStatusMessages[] = {
  993.     { MODE_NO_REDUCED,    "Reduced blanking is not supported."},
  994.     { MODE_MEM_BW,        "Memory bandwidth exceeded."},
  995.     { MODE_OUTPUT_UNDEF,  "Mode not defined by output device."},
  996.     { MODE_NOT_PAL,       "This is not a PAL TV mode."},
  997.     { MODE_NOT_NTSC,      "This is not an NTSC TV mode."},
  998.     { MODE_HTOTAL_WIDE,   "Horizontal Total is out of range."},
  999.     { MODE_HDISPLAY_WIDE, "Mode is too wide."},
  1000.     { MODE_HSYNC_RANGE,   "Horizontal Sync Start is out of range."},
  1001.     { MODE_HBLANK_RANGE,  "Horizontal Blanking Start is out of range."},
  1002.     { MODE_VTOTAL_WIDE,   "Vertical Total is out of range.\n"},
  1003.     { MODE_VDISPLAY_WIDE, "Mode is too high."},
  1004.     { MODE_VSYNC_RANGE,   "Vertical Sync Start is out of range.\n"},
  1005.     { MODE_VBLANK_RANGE,  "Vertical Blanking Start is out of range."},
  1006.     { MODE_PITCH,         "Scanout buffer Pitch too wide."},
  1007.     { MODE_OFFSET,        "Scanout buffer offset too high in FB."},
  1008.     { MODE_MINHEIGHT,     "Height too low."},
  1009.     { MODE_FIXED,         "Mode not compatible with fixed mode."},
  1010.     { MODE_SCALE,         "Mode cannot be scaled to fixed mode."},
  1011.     { MODE_NO_ENCODER,    "No encoder available for this output."},
  1012.     { 0, NULL}
  1013. };
  1014.  
  1015. const char * xf86ModeStatusToString(ModeStatus status)
  1016. {
  1017.     switch (status) {
  1018.     case MODE_OK:
  1019.         return "Mode OK";
  1020.     case MODE_HSYNC:
  1021.         return "hsync out of range";
  1022.     case MODE_VSYNC:
  1023.         return "vrefresh out of range";
  1024.     case MODE_H_ILLEGAL:
  1025.         return "illegal horizontal timings";
  1026.     case MODE_V_ILLEGAL:
  1027.         return "illegal vertical timings";
  1028.     case MODE_BAD_WIDTH:
  1029.         return "width requires unsupported line pitch";
  1030.     case MODE_NOMODE:
  1031.         return "no mode of this name";
  1032.     case MODE_NO_INTERLACE:
  1033.         return "interlace mode not supported";
  1034.     case MODE_NO_DBLESCAN:
  1035.         return "doublescan mode not supported";
  1036.     case MODE_NO_VSCAN:
  1037.         return "multiscan mode not supported";
  1038.     case MODE_MEM:
  1039.         return "insufficient memory for mode";
  1040.     case MODE_VIRTUAL_X:
  1041.         return "width too large for virtual size";
  1042.     case MODE_VIRTUAL_Y:
  1043.         return "height too large for virtual size";
  1044.     case MODE_MEM_VIRT:
  1045.         return "insufficient memory given virtual size";
  1046.     case MODE_NOCLOCK:
  1047.         return "no clock available for mode";
  1048.     case MODE_CLOCK_HIGH:
  1049.         return "mode clock too high";
  1050.     case MODE_CLOCK_LOW:
  1051.         return "mode clock too low";
  1052.     case MODE_CLOCK_RANGE:
  1053.         return "bad mode clock/interlace/doublescan";
  1054.     case MODE_BAD_HVALUE:
  1055.         return "horizontal timing out of range";
  1056.     case MODE_BAD_VVALUE:
  1057.         return "vertical timing out of range";
  1058.     case MODE_BAD_VSCAN:
  1059.         return "VScan value out of range";
  1060.     case MODE_HSYNC_NARROW:
  1061.         return "horizontal sync too narrow";
  1062.     case MODE_HSYNC_WIDE:
  1063.         return "horizontal sync too wide";
  1064.     case MODE_HBLANK_NARROW:
  1065.         return "horizontal blanking too narrow";
  1066.     case MODE_HBLANK_WIDE:
  1067.         return "horizontal blanking too wide";
  1068.     case MODE_VSYNC_NARROW:
  1069.         return "vertical sync too narrow";
  1070.     case MODE_VSYNC_WIDE:
  1071.         return "vertical sync too wide";
  1072.     case MODE_VBLANK_NARROW:
  1073.         return "vertical blanking too narrow";
  1074.     case MODE_VBLANK_WIDE:
  1075.         return "vertical blanking too wide";
  1076.     case MODE_PANEL:
  1077.         return "exceeds panel dimensions";
  1078.     case MODE_INTERLACE_WIDTH:
  1079.         return "width too large for interlaced mode";
  1080.     case MODE_ONE_WIDTH:
  1081.         return "all modes must have the same width";
  1082.     case MODE_ONE_HEIGHT:
  1083.         return "all modes must have the same height";
  1084.     case MODE_ONE_SIZE:
  1085.         return "all modes must have the same resolution";
  1086.     case MODE_BAD:
  1087.         return "unknown reason";
  1088.     case MODE_ERROR:
  1089.         return "internal error";
  1090.     default:
  1091.         return "unknown";
  1092.     }
  1093. }
  1094.  
  1095.  
  1096. const char *
  1097. RHDModeStatusToString(int Status)
  1098. {
  1099.     if ((Status & 0xFFF00) == RHD_MODE_STATUS) {
  1100.         int i;
  1101.  
  1102.         for (i = 0; rhdModeStatusMessages[i].Message; i++)
  1103.             if (rhdModeStatusMessages[i].Status == Status)
  1104.                 return rhdModeStatusMessages[i].Message;
  1105.         ErrorF("%s: unhandled Status type: 0x%X\n", __func__, Status);
  1106.         return "Unknown status.";
  1107.  
  1108.     } else
  1109.         return xf86ModeStatusToString(Status);
  1110. }
  1111.  
  1112. /*
  1113.  *
  1114.  */
  1115. static DisplayModePtr
  1116. rhdModesGrabOnNameAll(DisplayModePtr *Modes, char *name)
  1117. {
  1118.     DisplayModePtr Mode, Matched = NULL, Temp;
  1119.  
  1120.     for (Mode = *Modes; Mode; ) {
  1121.         if (!strcmp(Mode->name, name)) {
  1122.             Temp = Mode;
  1123.             Mode = Mode->next;
  1124.  
  1125.             if (Temp->prev)
  1126.                 Temp->prev->next = Mode;
  1127.             else
  1128.                 *Modes = Mode;
  1129.  
  1130.             if (Mode)
  1131.                 Mode->prev = Temp->prev;
  1132.  
  1133.             Temp->prev = NULL;
  1134.             Temp->next = Matched;
  1135.             if (Matched)
  1136.                 Matched->prev = Temp;
  1137.             Matched = Temp;
  1138.         } else
  1139.             Mode = Mode->next;
  1140.     }
  1141.  
  1142.     return Matched;
  1143. }
  1144.  
  1145. /*
  1146.  *
  1147.  */
  1148. static DisplayModePtr
  1149. rhdModesGrabOnTypeAll(DisplayModePtr *Modes, int Type, int Mask)
  1150. {
  1151.     DisplayModePtr Mode, Matched = NULL, Temp;
  1152.  
  1153.     for (Mode = *Modes; Mode; ) {
  1154.         if ((Mode->type & Mask) == (Type & Mask)) {
  1155.             Temp = Mode;
  1156.             Mode = Mode->next;
  1157.  
  1158.             if (Temp->prev)
  1159.                 Temp->prev->next = Mode;
  1160.             else
  1161.                 *Modes = Mode;
  1162.  
  1163.             if (Mode)
  1164.                 Mode->prev = Temp->prev;
  1165.  
  1166.             Temp->next = Matched;
  1167.             if (Matched)
  1168.                 Matched->prev = Temp;
  1169.             Temp->prev = NULL;
  1170.             Matched = Temp;
  1171.         } else
  1172.             Mode = Mode->next;
  1173.     }
  1174.  
  1175.     return Matched;
  1176. }
  1177.  
  1178. /*
  1179.  *
  1180.  */
  1181. static DisplayModePtr
  1182. rhdModesGrabBestRefresh(DisplayModePtr *Modes)
  1183. {
  1184.     DisplayModePtr Mode, Best = NULL;
  1185.  
  1186.     if (!*Modes)
  1187.         return NULL;
  1188.  
  1189.     Best = *Modes;
  1190.  
  1191.     for (Mode = Best->next; Mode; Mode = Mode->next)
  1192.         if (Best->VRefresh < Mode->VRefresh)
  1193.             Best = Mode;
  1194.         else if (Best->VRefresh == Mode->VRefresh) {
  1195.             /* Same name != same resolution */
  1196.             if ((Best->HDisplay * Best->VDisplay) <
  1197.                 (Mode->HDisplay * Mode->VDisplay))
  1198.                 Best = Mode;
  1199.             else if ((Best->HDisplay * Best->VDisplay) ==
  1200.                      (Mode->HDisplay * Mode->VDisplay)) {
  1201.                 /* Lower bandwidth == better! */
  1202.                 if (Best->Clock > Mode->Clock)
  1203.                     Best = Mode;
  1204.             }
  1205.         }
  1206.  
  1207.     if (Best->next)
  1208.         Best->next->prev = Best->prev;
  1209.     if (Best->prev)
  1210.         Best->prev->next = Best->next;
  1211.     if (Best == *Modes)
  1212.         *Modes = (*Modes)->next;
  1213.  
  1214.     Best->next = NULL;
  1215.     Best->prev = NULL;
  1216.  
  1217.     return Best;
  1218. }
  1219.  
  1220. /*
  1221.  *
  1222.  */
  1223. static DisplayModePtr
  1224. rhdModesGrabOnHighestType(DisplayModePtr *Modes)
  1225. {
  1226.     DisplayModePtr Mode;
  1227.  
  1228.     /* User provided, but can also have another source. */
  1229.     Mode = rhdModesGrabOnTypeAll(Modes, M_T_USERDEF, 0xF0);
  1230.     if (Mode)
  1231.         return Mode;
  1232.  
  1233.     /* Often EDID provided, but can also have another source. */
  1234.     Mode = rhdModesGrabOnTypeAll(Modes, M_T_DRIVER, 0xF0);
  1235.     if (Mode)
  1236.         return Mode;
  1237.  
  1238.     /* No reason why we should treat built-in and vesa separately */
  1239.     Mode = *Modes;
  1240.     *Modes = NULL;
  1241.     return Mode;
  1242. }
  1243.  
  1244. /*
  1245.  *
  1246.  */
  1247. static DisplayModePtr
  1248. rhdModesSortOnSize(DisplayModePtr Modes)
  1249. {
  1250.     DisplayModePtr Sorted, Mode, Temp, Next;
  1251.  
  1252.     if (!Modes)
  1253.         return NULL;
  1254.  
  1255.     Sorted = Modes;
  1256.     Modes = Modes->next;
  1257.  
  1258.     Sorted->next = NULL;
  1259.     Sorted->prev = NULL;
  1260.  
  1261.     for (Next = Modes; Next; ) {
  1262.         /* since we're taking modelines from in between */
  1263.         Mode = Next;
  1264.         Next = Next->next;
  1265.  
  1266.         for (Temp = Sorted; Temp; Temp = Temp->next) {
  1267.             /* nasty ! */
  1268.             if (((Temp->CrtcHDisplay * Temp->CrtcVDisplay) <
  1269.                 (Mode->CrtcHDisplay * Mode->CrtcVDisplay)) ||
  1270.                 (((Temp->CrtcHDisplay * Temp->CrtcVDisplay) ==
  1271.                   (Mode->CrtcHDisplay * Mode->CrtcVDisplay)) &&
  1272.                  ((Temp->VRefresh < Mode->VRefresh)  ||
  1273.                   ((Temp->VRefresh < Mode->VRefresh) &&
  1274.                    (Temp->SynthClock < Mode->SynthClock))))) {
  1275.                 Mode->next = Temp;
  1276.                 Mode->prev = Temp->prev;
  1277.                 Temp->prev = Mode;
  1278.                 if (Mode->prev)
  1279.                     Mode->prev->next = Mode;
  1280.                 else
  1281.                     Sorted = Mode;
  1282.                 break;
  1283.             }
  1284.  
  1285.             if (!Temp->next) {
  1286.                 Temp->next = Mode;
  1287.                 Mode->prev = Temp;
  1288.                 Mode->next = NULL;
  1289.                 break;
  1290.             }
  1291.         }
  1292.     }
  1293.  
  1294.     return Sorted;
  1295. }
  1296.  
  1297. #if 0
  1298. /*
  1299.  * take a modename, try to parse it, if that works, generate the CVT modeline.
  1300.  */
  1301. static DisplayModePtr
  1302. rhdModeCreateFromName(ScrnInfoPtr pScrn, char *name, Bool Silent)
  1303. {
  1304.     DisplayModePtr Mode;
  1305.     int HDisplay = 0, VDisplay = 0, tmp;
  1306.     float VRefresh = 0;
  1307.     Bool Reduced;
  1308.     int Status;
  1309.  
  1310.     sscanf(name, "%dx%d@%f", &HDisplay, &VDisplay, &VRefresh);
  1311.     if (!HDisplay || !VDisplay) {
  1312.         if (!Silent)
  1313.             xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s: Unable to generate "
  1314.                        "Modeline for Mode \"%s\"\n", __func__, name);
  1315.         return NULL;
  1316.     }
  1317.  
  1318.     tmp = strlen(name) - 1;
  1319.     if ((name[tmp] == 'r') || (name[tmp] == 'R'))
  1320.         Reduced = TRUE;
  1321.     else
  1322.         Reduced = FALSE;
  1323.  
  1324.     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
  1325.                "Generating Modeline for \"%s\"\n", name);
  1326.  
  1327.     /* First, try a plain CVT mode */
  1328.     Mode = RHDCVTMode(HDisplay, VDisplay, VRefresh, Reduced, FALSE);
  1329.     xfree(Mode->name);
  1330.     Mode->name = xnfstrdup(name);
  1331.     Mode->type = M_T_USERDEF;
  1332.  
  1333.     Status = rhdModeValidate(pScrn, Mode);
  1334.     if (Status == MODE_OK)
  1335.         return Mode;
  1336.     rhdModesDestroy(Mode);
  1337.  
  1338. #if 0 /* noscale mode */
  1339.     /* Now see if we have fixed modes */
  1340.     for (i = 0; i < 2; i++) {
  1341.         Crtc = rhdPtr->Crtc[i];
  1342.  
  1343.         if (!Crtc->Active || !Crtc->FixedMode)
  1344.             continue;
  1345.  
  1346.         Mode = RHDModeCopy(Crtc->FixedMode);
  1347.         xfree(Mode->name);
  1348.         Mode->name = xnfstrdup(name);
  1349.         Mode->type = M_T_USERDEF;
  1350.  
  1351.         Mode->HDisplay = HDisplay;
  1352.         Mode->CrtcHDisplay = 0; /* set by validation code */
  1353.         Mode->VDisplay = VDisplay;
  1354.         Mode->CrtcVDisplay = 0;
  1355.  
  1356.         Status = rhdModeValidate(pScrn, Mode);
  1357.         if (Status == MODE_OK)
  1358.             return Mode;
  1359.         rhdModesDestroy(Mode);
  1360.     }
  1361. #endif
  1362.  
  1363.     if (!Silent)
  1364.         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Rejected mode \"%s\" "
  1365.                    "(%dx%d):\n\t %s\n", name, HDisplay, VDisplay,
  1366.                    RHDModeStatusToString(Status));
  1367.     return NULL;
  1368. }
  1369. #endif
  1370.  
  1371. /*
  1372.  *
  1373.  */
  1374. static DisplayModePtr
  1375. rhdModesListValidateAndCopy(ScrnInfoPtr pScrn, DisplayModePtr Modes, Bool Silent)
  1376. {
  1377.   DisplayModePtr Keepers = NULL, Check, Mode;
  1378.   int Status;
  1379.  
  1380.     for (Check = Modes; Check; Check = Check->next) {
  1381.     Mode = RHDModeCopy(Check);
  1382.  
  1383.     Status = rhdModeValidate(pScrn, Mode);
  1384.     if (Status == MODE_OK)
  1385.             Keepers = RHDModesAdd(Keepers, Mode);
  1386.         else {
  1387.             if (!Silent)
  1388.                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Rejected mode \"%s\" "
  1389.                            "(%dx%d:%3.1fMhz): %s\n", Mode->name,
  1390.                            Mode->HDisplay, Mode->VDisplay,
  1391.                            Mode->Clock / 1000.0, RHDModeStatusToString(Status));
  1392.             xfree(Mode->name);
  1393.             xfree(Mode);
  1394.     }
  1395.   }
  1396.  
  1397.   return Keepers;
  1398. }
  1399.  
  1400. /*
  1401.  * Create the list of all modes that are currently valid
  1402.  */
  1403. static DisplayModePtr
  1404. rhdCreateModesListAndValidate(ScrnInfoPtr pScrn, Bool Silent)
  1405. {
  1406.     RHDPtr rhdPtr = RHDPTR(pScrn);
  1407.   DisplayModePtr Keepers = NULL, Modes;
  1408.   struct rhdCrtc *Crtc;
  1409.   struct rhdOutput *Output;
  1410.   int i;
  1411.  
  1412.     RHDFUNC(pScrn);
  1413.  
  1414.     /* Cycle through our monitors list, and find a fixed mode one */
  1415.     for (i = 0; i < 2; i++) {
  1416.     Crtc = rhdPtr->Crtc[i];
  1417.         for (Output = rhdPtr->Outputs; Output; Output = Output->Next) {
  1418.             if (Output->Active && (Output->Crtc == Crtc)) {
  1419.         if (Output->Connector && Output->Connector->Monitor
  1420.                     && Output->Connector->Monitor->UseFixedModes
  1421.                     && !Crtc->ScaledToMode) {
  1422.           Modes = Output->Connector->Monitor->Modes;
  1423.           if (!Silent && Modes)
  1424.                         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Validating Fixed"
  1425.                       " Modes from Monitor \"%s\"\n\t on Connector"
  1426.                       " \"%s\"\n", Output->Connector->Monitor->Name,
  1427.                                    Output->Connector->Name);
  1428.  
  1429.           Modes = rhdModesListValidateAndCopy(pScrn, Modes, Silent);
  1430.           Keepers = RHDModesAdd(Keepers, Modes);
  1431.           return Keepers;
  1432.         }
  1433.             }
  1434.     }
  1435.   }
  1436.  
  1437.  
  1438.     /* Cycle through our actual monitors list */
  1439.     for (i = 0; i < 2; i++) {
  1440.     Crtc = rhdPtr->Crtc[i];
  1441.  
  1442.         for (Output = rhdPtr->Outputs; Output; Output = Output->Next) {
  1443.             if (Output->Active && (Output->Crtc == Crtc)) {
  1444.                 if (Output->Connector && Output->Connector->Monitor) {
  1445.           Modes = Output->Connector->Monitor->Modes;
  1446.           if (!Silent && Modes)
  1447.                         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Validating Modes "
  1448.                       "from Monitor \"%s\" on \"%s\"\n",
  1449.                       Output->Connector->Monitor->Name,
  1450.                                    Output->Connector->Name);
  1451.  
  1452.           Modes = rhdModesListValidateAndCopy(pScrn, Modes, Silent);
  1453.           Keepers = RHDModesAdd(Keepers, Modes);
  1454.         }
  1455.             }
  1456.     }
  1457.   }
  1458.  
  1459.   return Keepers;
  1460. }
  1461.  
  1462. /*
  1463.  *
  1464.  */
  1465. DisplayModePtr
  1466. RHDModesPoolCreate(ScrnInfoPtr pScrn, Bool Silent)
  1467. {
  1468.     DisplayModePtr Pool = NULL, List, TempList, Temp;
  1469.     char **ModeNames = NULL; //pScrn->display->modes;
  1470.     int i;
  1471.  
  1472.     RHDFUNC(pScrn);
  1473.  
  1474.     List = rhdCreateModesListAndValidate(pScrn, Silent);
  1475.     if (!List)
  1476.         return List;
  1477.  
  1478.     /* Reduce our list */
  1479.     if (ModeNames && ModeNames[0]) { /* Find the best matching mode for each name */
  1480.         for (i = 0; ModeNames[i]; i++) {
  1481.         TempList = rhdModesGrabOnNameAll(&List, ModeNames[i]);
  1482.             if (TempList) {
  1483.           Temp = rhdModesGrabOnHighestType(&TempList);
  1484.           rhdModesDestroy(TempList);
  1485.  
  1486.           TempList = Temp;
  1487.           Temp = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED);
  1488.                 if (Temp) {
  1489.             rhdModesDestroy(TempList);
  1490.             TempList = Temp;
  1491.           }
  1492.  
  1493.           Temp = rhdModesGrabBestRefresh(&TempList);
  1494.  
  1495.           rhdModesDestroy(TempList);
  1496.         }
  1497.       //  else /* No matching modes found, generate */
  1498.       //    Temp = rhdModeCreateFromName(pScrn, ModeNames[i], Silent);
  1499.  
  1500.         if (Temp)
  1501.           Pool = RHDModesAdd(Pool, Temp);
  1502.       }
  1503.       rhdModesDestroy(List);
  1504.     } else { /* No names, just work the list directly */
  1505.       Temp = rhdModesGrabOnHighestType(&List);
  1506.       rhdModesDestroy(List);
  1507.       List = Temp;
  1508.  
  1509.         while (List) {
  1510.         TempList = rhdModesGrabOnNameAll(&List, List->name);
  1511.  
  1512.         Temp = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED);
  1513.             if (Temp) {
  1514.            rhdModesDestroy(TempList);
  1515.            TempList = Temp;
  1516.         }
  1517.  
  1518.         Temp = rhdModesGrabBestRefresh(&TempList);
  1519.         rhdModesDestroy(TempList);
  1520.  
  1521.         Pool = RHDModesAdd(Pool, Temp);
  1522.       }
  1523.  
  1524.         /* Sort our list */
  1525.       TempList = Pool;
  1526.  
  1527.         /* Sort higher priority modes separately */
  1528.       Pool = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED);
  1529.       Pool = rhdModesSortOnSize(Pool);
  1530.  
  1531.       TempList = rhdModesSortOnSize(TempList);
  1532.  
  1533.       Pool = RHDModesAdd(Pool, TempList);
  1534.     }
  1535.  
  1536.     return Pool;
  1537. }
  1538.  
  1539. /*
  1540.  *
  1541.  */
  1542. void
  1543. RHDModesAttach(ScrnInfoPtr pScrn, DisplayModePtr Modes)
  1544. {
  1545.     DisplayModePtr Mode = Modes;
  1546.  
  1547.     pScrn->modes = Modes;
  1548.     pScrn->currentMode = Modes;
  1549.  
  1550.     while (Mode->next) {
  1551.         Mode->type = M_T_USERDEF; /* satisfy xf86ZoomViewport */
  1552.         Mode = Mode->next;
  1553.     }
  1554.  
  1555.     Mode->type = M_T_USERDEF;
  1556.  
  1557.     /* Make our list circular */
  1558.     Mode->next = pScrn->modes;
  1559.     pScrn->modes->prev = Mode;
  1560. }
  1561.  
  1562. /*
  1563.  *
  1564.  */
  1565. #if 0
  1566. Bool
  1567. RHDGetVirtualFromConfig(ScrnInfoPtr pScrn)
  1568. {
  1569.     RHDPtr rhdPtr = RHDPTR(pScrn);
  1570.     struct rhdCrtc *Crtc1 = rhdPtr->Crtc[0], *Crtc2 = rhdPtr->Crtc[1];
  1571.     CARD32 VirtualX = pScrn->display->virtualX;
  1572.     CARD32 VirtualY = pScrn->display->virtualY;
  1573.     CARD32 Pitch1, Pitch2;
  1574.     float Ratio = (float) pScrn->display->virtualY / pScrn->display->virtualX;
  1575.     int ret = FALSE;
  1576.  
  1577.     RHDFUNC(pScrn);
  1578.  
  1579.     while (VirtualX && VirtualY) {
  1580.         ret = Crtc1->FBValid(Crtc1, VirtualX, VirtualY, pScrn->bitsPerPixel,
  1581.                              rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch1);
  1582.         if (ret != MODE_OK)
  1583.             goto shrink;
  1584.         ret = Crtc2->FBValid(Crtc2, VirtualX, VirtualY, pScrn->bitsPerPixel,
  1585.                              rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch2);
  1586.         if (ret != MODE_OK)
  1587.             goto shrink;
  1588.  
  1589.         if (Pitch1 != Pitch2)
  1590.             goto shrink;
  1591. #if 0
  1592.         /* let 2d acceleration have a say as well */
  1593.         if (rhdPtr->AccelMethod >= RHD_ACCEL_XAA)
  1594.             if (rhdPtr->ChipSet < RHD_R600) /* badly abstracted, i know */
  1595.                 if (!R5xx2DFBValid(rhdPtr, VirtualX, VirtualY, pScrn->bitsPerPixel,
  1596.                                    rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, Pitch1))
  1597.                     goto shrink;
  1598. #endif
  1599.         break; /* must be good then. */
  1600.     shrink:
  1601.         VirtualX--;
  1602.         VirtualY = Ratio * VirtualX;
  1603.     }
  1604.  
  1605.     if (VirtualX && VirtualY) {
  1606.         pScrn->virtualX = VirtualX;
  1607.         pScrn->virtualY = VirtualY;
  1608.         pScrn->displayWidth = Pitch1;
  1609.         return TRUE;
  1610.     } else
  1611.         return FALSE;
  1612. }
  1613.  
  1614. /*
  1615.  *
  1616.  */
  1617. void
  1618. RHDGetVirtualFromModesAndFilter(ScrnInfoPtr pScrn, DisplayModePtr Modes, Bool Silent)
  1619. {
  1620.     RHDPtr rhdPtr = RHDPTR(pScrn);
  1621.     struct rhdCrtc *Crtc1 = rhdPtr->Crtc[0], *Crtc2 = rhdPtr->Crtc[1];
  1622.     DisplayModePtr Mode, Next;
  1623.     CARD32 VirtualX = 0;
  1624.     CARD32 VirtualY = 0;
  1625.     CARD32 Pitch1, Pitch2;
  1626.     int ret = FALSE;
  1627.  
  1628.     RHDFUNC(pScrn);
  1629.  
  1630.     /* assert */
  1631.     if (!Modes)
  1632.         return;
  1633.  
  1634.     Mode = Modes;
  1635.  
  1636.     while (Mode) {
  1637.         if ((Mode->CrtcHDisplay > pScrn->virtualX) ||
  1638.             (Mode->CrtcVDisplay > pScrn->virtualY)) {
  1639.             if (Mode->CrtcHDisplay > pScrn->virtualX)
  1640.                 VirtualX = Mode->CrtcHDisplay;
  1641.             else
  1642.                 VirtualX = pScrn->virtualX;
  1643.  
  1644.             if (Mode->CrtcVDisplay > pScrn->virtualY)
  1645.                 VirtualY = Mode->CrtcVDisplay;
  1646.             else
  1647.                 VirtualY = pScrn->virtualY;
  1648.  
  1649.             /* Check what Crtc1 thinks this should be. */
  1650.             ret = Crtc1->FBValid(Crtc1, VirtualX, VirtualY, pScrn->bitsPerPixel,
  1651.                                  rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch1);
  1652.             if (ret != MODE_OK) {
  1653.                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s rejected mode \"%s\" "
  1654.                            "(%dx%d): %s\n", Crtc1->Name, Mode->name,
  1655.                            Mode->HDisplay, Mode->VDisplay,
  1656.                            RHDModeStatusToString(ret));
  1657.                 goto rejected;
  1658.             }
  1659.  
  1660.             /* Check what Crtc2 thinks this should be. */
  1661.             ret = Crtc2->FBValid(Crtc2, VirtualX, VirtualY, pScrn->bitsPerPixel,
  1662.                                  rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch2);
  1663.             if (ret != MODE_OK) {
  1664.                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s rejected mode \"%s\" "
  1665.                            "(%dx%d): %s\n", Crtc2->Name, Mode->name,
  1666.                            Mode->HDisplay, Mode->VDisplay,
  1667.                            RHDModeStatusToString(ret));
  1668.                 goto rejected;
  1669.             }
  1670.  
  1671.             /* when needed, check whether this matches our 2D engine as well. */
  1672.             if (rhdPtr->AccelMethod >= RHD_ACCEL_XAA)
  1673.                 if (rhdPtr->ChipSet < RHD_R600) /* badly abstracted, i know */
  1674. #if 0
  1675.                     if (!R5xx2DFBValid(rhdPtr, VirtualX, VirtualY,
  1676.                                        pScrn->bitsPerPixel, rhdPtr->FbScanoutStart,
  1677.                                        rhdPtr->FbScanoutSize, Pitch1)) {
  1678.                         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration "
  1679.                                    "rejected mode \"%s\" (%dx%d).\n",
  1680.                                    Mode->name, Mode->HDisplay, Mode->VDisplay);
  1681.                         goto rejected;
  1682.                     }
  1683. #endif
  1684.             /* mode is perfectly valid FB wise */
  1685.             Mode = Mode->next;
  1686.             pScrn->virtualX = VirtualX;
  1687.             pScrn->virtualY = VirtualY;
  1688.             pScrn->displayWidth = Pitch1;
  1689.             continue;
  1690.  
  1691.         rejected:
  1692.             Next = Mode->next;
  1693.             Modes = rhdModeDelete(Modes, Mode);
  1694.             Mode = Next;
  1695.         } else
  1696.             Mode = Mode->next;
  1697.     }
  1698. }
  1699.  
  1700. /*
  1701.  * RandR entry point: fixup per Crtc and Output (in RandR speech)
  1702.  * Due to misconceptions we might end up fixing *everything* here.
  1703.  */
  1704. int
  1705. RHDRRModeFixup(ScrnInfoPtr pScrn, DisplayModePtr Mode, struct rhdCrtc *Crtc,
  1706.                struct rhdConnector *Connector, struct rhdOutput *Output,
  1707.                struct rhdMonitor *Monitor, Bool ScaledMode)
  1708. {
  1709.     RHDPtr rhdPtr = RHDPTR(pScrn);
  1710.     int i, Status;
  1711.  
  1712.     ASSERT(Connector);
  1713.     ASSERT(Output);
  1714.     RHDFUNC(Output);
  1715.  
  1716.     Status = rhdModeSanity(rhdPtr, Mode);
  1717.     if (Status != MODE_OK)
  1718.         return Status;
  1719.  
  1720.     rhdModeFillOutCrtcValues(Mode);
  1721.  
  1722.     if (!ScaledMode) {
  1723.     /* We don't want to loop around this forever */
  1724.         for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) {
  1725.         Mode->CrtcHAdjusted = FALSE;
  1726.         Mode->CrtcVAdjusted = FALSE;
  1727.  
  1728.         /* Sanitize */
  1729.         Status = rhdModeCrtcSanity(Mode);
  1730.         if (Status != MODE_OK)
  1731.             return Status;
  1732.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1733.             continue;
  1734.  
  1735.         if (Crtc) {
  1736.             /* Check FB */
  1737.             Status = Crtc->FBValid(Crtc, Mode->CrtcHDisplay, Mode->CrtcVDisplay,
  1738.                                    pScrn->bitsPerPixel, rhdPtr->FbScanoutStart,
  1739.                                    rhdPtr->FbScanoutSize, NULL);
  1740.             if (Status != MODE_OK)
  1741.                 return Status;
  1742.  
  1743.                 if (Crtc->ScaleValid) {
  1744.                     Status = Crtc->ScaleValid(Crtc, RHD_CRTC_SCALE_TYPE_NONE, Mode, NULL);
  1745.             if (Status != MODE_OK)
  1746.                 return Status;
  1747.             if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1748.                 continue;
  1749.                 }
  1750.  
  1751.                 /* Check Crtc */
  1752.                 Status = Crtc->ModeValid(Crtc, Mode);
  1753.                 if (Status != MODE_OK)
  1754.                     return Status;
  1755.                 if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1756.                     continue;
  1757.  
  1758.             /* Check PLL */
  1759.             if (Crtc->PLL->Valid) {
  1760.                 Status = Crtc->PLL->Valid(Crtc->PLL, Mode->Clock);
  1761.                 if (Status != MODE_OK)
  1762.                     return Status;
  1763.                 if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1764.                     continue;
  1765.             }
  1766.         }
  1767.  
  1768.         /* Check Output */
  1769.         Status = Output->ModeValid(Output, Mode);
  1770.         if (Status != MODE_OK)
  1771.             return Status;
  1772.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1773.             continue;
  1774.  
  1775.         /* Check the monitor attached to this output */
  1776.         if (Connector->Monitor)
  1777.             Status = rhdMonitorValid(Connector->Monitor, Mode);
  1778.         if (Status != MODE_OK)
  1779.             return Status;
  1780.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1781.             continue;
  1782.  
  1783.         /* Seems to be good */
  1784.         break;
  1785.     }
  1786.  
  1787.         if (i == RHD_MODE_VALIDATION_LOOPS) {
  1788.         /* Mode has been bouncing around for ages, on adjustments */
  1789.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  1790.                    "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was thrown around"
  1791.                    " for too long.\n", __func__, Mode->name,
  1792.                    Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0);
  1793.         return MODE_ERROR;
  1794.     }
  1795.  
  1796.     /* throw them at the configured monitor */
  1797.     if (Monitor) {
  1798.         Status = rhdMonitorValid(Monitor, Mode);
  1799.         if (Status != MODE_OK)
  1800.             return Status;
  1801.     }
  1802.  
  1803.     } else {
  1804.         if (Crtc) {
  1805.             Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_FROM);
  1806.             if (Status != MODE_OK)
  1807.                 return Status;
  1808.         }
  1809.     }
  1810.  
  1811.     /* Did we set up virtual resolution already? */
  1812.     if ((pScrn->virtualX > 0) && (pScrn->virtualY > 0)) {
  1813.         if (pScrn->virtualX < Mode->CrtcHDisplay)
  1814.             return MODE_VIRTUAL_X;
  1815.         if (pScrn->virtualY < Mode->CrtcVDisplay)
  1816.             return MODE_VIRTUAL_Y;
  1817.     }
  1818.  
  1819.     return MODE_OK;
  1820. }
  1821. #endif
  1822.  
  1823. /*
  1824.  * RHDRRValidateScaledToMode(): like RHDValidateScaledMode() - but we cannot validate against a CRTC
  1825.  * as this isn't known when this function is called. So at least validate against the 'output' here.
  1826.  */
  1827. int
  1828. RHDRRValidateScaledToMode(struct rhdOutput *Output, DisplayModePtr Mode)
  1829. {
  1830.     RHDPtr rhdPtr = RHDPTRI(Output);
  1831.     int Status;
  1832.     int i;
  1833.  
  1834.     RHDFUNC(Output);
  1835.  
  1836.     Status = rhdModeSanity(rhdPtr, Mode);
  1837.     if (Status != MODE_OK)
  1838.         return Status;
  1839.  
  1840.     rhdModeFillOutCrtcValues(Mode);
  1841.  
  1842.     for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) {
  1843.  
  1844.         Mode->CrtcHAdjusted = FALSE;
  1845.         Mode->CrtcVAdjusted = FALSE;
  1846.  
  1847.         Status = rhdModeCrtcSanity(Mode);
  1848.         if (Status != MODE_OK)
  1849.             return Status;
  1850.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1851.             continue;
  1852.  
  1853.         /* Check the output */
  1854.         Status = Output->ModeValid(Output, Mode);
  1855.         if (Status != MODE_OK)
  1856.             return Status;
  1857.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1858.             continue; /* restart. */
  1859.  
  1860.         /* Check the monitor attached to this output */
  1861.         if (Output->Connector && Output->Connector->Monitor)
  1862.             Status = rhdMonitorValid(Output->Connector->Monitor, Mode);
  1863.         if (Status != MODE_OK)
  1864.             return Status;
  1865.         if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
  1866.             continue;
  1867.  
  1868.         break;
  1869.     }
  1870.  
  1871.     if (i == RHD_MODE_VALIDATION_LOOPS) {
  1872.         /* Mode has been bouncing around for ages, on adjustments */
  1873.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  1874.                    "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was thrown around"
  1875.                    " for too long.\n", __func__, Mode->name,
  1876.                    Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0);
  1877.         return MODE_ERROR;
  1878.     }
  1879.  
  1880.     /* Do we want to also validate against a configured monitor? */
  1881.     if (rhdPtr->ConfigMonitor) {
  1882.         Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode);
  1883.         if (Status != MODE_OK)
  1884.             return Status;
  1885.     }
  1886.  
  1887.     return MODE_OK;
  1888. }
  1889.  
  1890. /*
  1891.  * RHDSynthModes(): synthesize CVT modes for well known resolutions.
  1892.  * For now we assume we want reduced modes only.
  1893.  */
  1894. void
  1895. RHDSynthModes(int scrnIndex, DisplayModePtr Mode)
  1896. {
  1897.     RHDPtr rhdPtr = (RHDPtr)(scrnIndex);
  1898.     DisplayModePtr Tmp;
  1899.     unsigned int i;
  1900.  
  1901.     struct resolution{
  1902.         int x;
  1903.         int y;
  1904.     } resolution_list[] = {
  1905.         {  320,  200 },  /* CGA */
  1906.         {  320,  240 },  /* QVGA */
  1907.         {  640,  480 },  /* VGA */
  1908.         {  720,  480 },  /* NTSC */
  1909.         {  854,  480 },  /* WVGA */
  1910.         {  768,  576 },  /* PAL */
  1911.         {  800,  600 },  /* SVGA */
  1912.         { 1024,  768 },  /* XGA */
  1913.         { 1152,  768 },
  1914.         { 1280,  720 },  /* HD720 */
  1915.         { 1280,  960 },
  1916.         { 1280,  854 },
  1917.         { 1280,  960 },
  1918.         { 1280, 1024 },  /* SXGA */
  1919.         { 1440,  960 },
  1920.         { 1400, 1050 },  /* SXGA+ */
  1921.         { 1680, 1050 },  /* WSXGA+ */
  1922.         { 1600, 1200 },  /* UXGA */
  1923.         { 1920, 1080 },  /* HD1080 */
  1924.         { 1920, 1200 },  /* WUXGA */
  1925.         { 2048, 1536 },  /* QXGA */
  1926.         { 2560, 1600 },  /* WQXGA */
  1927.         { 2560, 2048 }   /* QSXGA */
  1928.     };
  1929.  
  1930.     RHDFUNC(pScrn);
  1931.  
  1932.     for (i = 0; i < (sizeof(resolution_list) / sizeof(struct resolution)); i++) {
  1933.         /*
  1934.          *  chances are that the native mode of a display is a CVT mode with 60 Hz.
  1935.          *  This will make RandR share the CRTC which is undesireable for scaling.
  1936.          *  This we 'tweak' the frequency to be slightly higher.
  1937.          *  Don't tell me it's ugly - I know this already.
  1938.          */
  1939.         Tmp = RHDCVTMode(resolution_list[i].x, resolution_list[i].y, 60.5, TRUE, FALSE);
  1940.         Tmp->status = MODE_OK;
  1941.         rhdModeFillOutCrtcValues(Tmp);
  1942.         xfree(Tmp->name);
  1943.         Tmp->name = xnfalloc(20);
  1944.         snprintf(Tmp->name, 20, "%ix%iScaled",resolution_list[i].x,resolution_list[i].y);
  1945.         Tmp->type = M_T_BUILTIN;
  1946.   //  if (rhdPtr->verbosity > 6) {
  1947.   //      xf86DrvMsg(scrnIndex, X_INFO, "%s: Adding Modeline ",__func__);
  1948.   //      RHDPrintModeline(Tmp);
  1949.   //  }
  1950.         RHDModesAdd(Mode, Tmp);
  1951.     }
  1952. }
  1953.