summaryrefslogtreecommitdiff
path: root/src/radeon_xf86Crtc.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@linux.ie>2007-01-04 12:29:51 +1100
committerDave Airlie <airlied@linux.ie>2007-01-04 12:29:51 +1100
commita43c1d55f5f855d9e6ae939dd4eec1c607b6d514 (patch)
tree3eb7861c6a9d2a1297d780bdceeaa46c6690e9cd /src/radeon_xf86Crtc.c
parent87592ffb717da1f0a1767a38918d16d60953599c (diff)
bring radeon randr code inline with intel randr code
Diffstat (limited to 'src/radeon_xf86Crtc.c')
-rw-r--r--src/radeon_xf86Crtc.c787
1 files changed, 709 insertions, 78 deletions
diff --git a/src/radeon_xf86Crtc.c b/src/radeon_xf86Crtc.c
index 76b03f5c..7414d34d 100644
--- a/src/radeon_xf86Crtc.c
+++ b/src/radeon_xf86Crtc.c
@@ -5,21 +5,21 @@
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
@@ -34,10 +34,12 @@
#include "xf86DDC.h"
//#include "i.h"
#include "radeon_xf86Crtc.h"
+#include "radeon_xf86Modes.h"
#include "X11/extensions/render.h"
#define DPMS_SERVER
#include "X11/extensions/dpms.h"
+#include "X11/Xatom.h"
/*
* Initialize xf86CrtcConfig structure
@@ -124,6 +126,79 @@ xf86CrtcDestroy (xf86CrtcPtr crtc)
/*
* Output functions
*/
+
+extern XF86ConfigPtr xf86configptr;
+
+typedef enum {
+ OPTION_PREFERRED_MODE,
+ OPTION_POSITION,
+ OPTION_BELOW,
+ OPTION_RIGHT_OF,
+ OPTION_ABOVE,
+ OPTION_LEFT_OF,
+ OPTION_ENABLE,
+ OPTION_DISABLE,
+ OPTION_MIN_CLOCK,
+ OPTION_MAX_CLOCK,
+} OutputOpts;
+
+static OptionInfoRec xf86OutputOptions[] = {
+ {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE },
+ {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE },
+ {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE },
+ {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE },
+ {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE },
+ {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE },
+ {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE },
+ {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE },
+ {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE },
+ {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE },
+ {-1, NULL, OPTV_NONE, {0}, FALSE },
+};
+
+static void
+xf86OutputSetMonitor (xf86OutputPtr output)
+{
+ char *option_name;
+ static const char monitor_prefix[] = "monitor-";
+ char *monitor;
+
+ if (output->options)
+ xfree (output->options);
+
+ output->options = xnfalloc (sizeof (xf86OutputOptions));
+ memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions));
+
+ option_name = xnfalloc (strlen (monitor_prefix) +
+ strlen (output->name) + 1);
+ strcpy (option_name, monitor_prefix);
+ strcat (option_name, output->name);
+ monitor = xf86findOptionValue (output->scrn->options, option_name);
+ if (!monitor)
+ monitor = output->name;
+ else
+ xf86MarkOptionUsedByName (output->scrn->options, option_name);
+ xfree (option_name);
+ output->conf_monitor = xf86findMonitor (monitor,
+ xf86configptr->conf_monitor_lst);
+ if (output->conf_monitor)
+ xf86ProcessOptions (output->scrn->scrnIndex,
+ output->conf_monitor->mon_option_lst,
+ output->options);
+}
+
+static Bool
+xf86OutputEnabled (xf86OutputPtr output)
+{
+ /* Check to see if this output was disabled in the config file */
+ if (xf86ReturnOptValBool (output->options, OPTION_ENABLE, TRUE) == FALSE ||
+ xf86ReturnOptValBool (output->options, OPTION_DISABLE, FALSE) == TRUE)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
xf86OutputPtr
xf86OutputCreate (ScrnInfoPtr scrn,
const xf86OutputFuncsRec *funcs,
@@ -144,6 +219,8 @@ xf86OutputCreate (ScrnInfoPtr scrn,
#ifdef RANDR_12_INTERFACE
output->randr_output = NULL;
#endif
+ xf86OutputSetMonitor (output);
+
if (xf86_config->output)
outputs = xrealloc (xf86_config->output,
(xf86_config->num_output + 1) * sizeof (xf86OutputPtr));
@@ -154,24 +231,28 @@ xf86OutputCreate (ScrnInfoPtr scrn,
xfree (output);
return NULL;
}
+
xf86_config->output = outputs;
xf86_config->output[xf86_config->num_output++] = output;
+
return output;
}
-void
+Bool
xf86OutputRename (xf86OutputPtr output, const char *name)
{
int len = strlen(name);
char *newname = xalloc (len + 1);
if (!newname)
- return; /* so sorry... */
+ return FALSE; /* so sorry... */
strcpy (newname, name);
if (output->name != (char *) (output + 1))
xfree (output->name);
output->name = newname;
+ xf86OutputSetMonitor (output);
+ return TRUE;
}
void
@@ -348,7 +429,9 @@ xf86PickCrtcs (ScrnInfoPtr pScrn,
* If the two outputs desire the same mode,
* see if they can be cloned
*/
- if (xf86ModesEqual (modes[o], modes[n]))
+ if (xf86ModesEqual (modes[o], modes[n]) &&
+ config->output[o]->initial_x == config->output[n]->initial_x &&
+ config->output[o]->initial_y == config->output[n]->initial_y)
{
for (l = 0; l < config->num_output; l++)
if (output->possible_clones & (1 << l))
@@ -362,7 +445,7 @@ xf86PickCrtcs (ScrnInfoPtr pScrn,
crtcs[n] = crtc;
memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr));
score = my_score + xf86PickCrtcs (pScrn, crtcs, modes, n+1, width, height);
- if (score >= best_score)
+ if (score > best_score)
{
best_crtc = crtc;
best_score = score;
@@ -376,7 +459,8 @@ xf86PickCrtcs (ScrnInfoPtr pScrn,
/*
* Compute the virtual size necessary to place all of the available
- * crtcs in a panorama configuration
+ * crtcs in the specified configuration and also large enough to
+ * resize any crtc to the largest available mode
*/
static void
@@ -391,7 +475,13 @@ xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp)
for (c = 0; c < config->num_crtc; c++)
{
int crtc_width = 0, crtc_height = 0;
+ xf86CrtcPtr crtc = config->crtc[c];
+ if (crtc->enabled)
+ {
+ crtc_width = crtc->x + crtc->desiredMode.HDisplay;
+ crtc_height = crtc->y + crtc->desiredMode.VDisplay;
+ }
for (o = 0; o < config->num_output; o++)
{
xf86OutputPtr output = config->output[o];
@@ -409,7 +499,8 @@ xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp)
}
}
}
- width += crtc_width;
+ if (crtc_width > width)
+ width = crtc_width;
if (crtc_height > height)
height = crtc_height;
}
@@ -421,6 +512,186 @@ xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp)
*heightp = height;
}
+#define POSITION_UNSET -100000
+
+static Bool
+xf86InitialOutputPositions (ScrnInfoPtr pScrn, DisplayModePtr *modes)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int o;
+ int min_x, min_y;
+
+ for (o = 0; o < config->num_output; o++)
+ {
+ xf86OutputPtr output = config->output[o];
+
+ output->initial_x = output->initial_y = POSITION_UNSET;
+ }
+
+ /*
+ * Loop until all outputs are set
+ */
+ for (;;)
+ {
+ Bool any_set = FALSE;
+ Bool keep_going = FALSE;
+
+ for (o = 0; o < config->num_output; o++)
+ {
+ static const OutputOpts relations[] = {
+ OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
+ };
+ xf86OutputPtr output = config->output[o];
+ xf86OutputPtr relative;
+ char *relative_name;
+ char *position;
+ OutputOpts relation;
+ int r;
+
+ if (output->initial_x != POSITION_UNSET)
+ continue;
+ position = xf86GetOptValString (output->options,
+ OPTION_POSITION);
+ /*
+ * Absolute position wins
+ */
+ if (position)
+ {
+ int x, y;
+ if (sscanf (position, "%d %d", &x, &y) == 2)
+ {
+ output->initial_x = x;
+ output->initial_y = y;
+ }
+ else
+ {
+ xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
+ "Output %s position not of form \"x y\"\n",
+ output->name);
+ output->initial_x = output->initial_y = 0;
+ }
+ any_set = TRUE;
+ continue;
+ }
+ /*
+ * Next comes relative positions
+ */
+ relation = 0;
+ relative_name = NULL;
+ for (r = 0; r < 4; r++)
+ {
+ relation = relations[r];
+ relative_name = xf86GetOptValString (output->options,
+ relation);
+ if (relative_name)
+ break;
+ }
+ if (relative_name)
+ {
+ int or;
+ relative = NULL;
+ for (or = 0; or < config->num_output; or++)
+ {
+ xf86OutputPtr out_rel = config->output[or];
+ XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor;
+ char *name;
+
+ if (rel_mon)
+ name = rel_mon->mon_identifier;
+ else
+ name = out_rel->name;
+ if (!strcmp (relative_name, name))
+ {
+ relative = config->output[or];
+ break;
+ }
+ }
+ if (!relative)
+ {
+ xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
+ "Cannot position output %s relative to unknown output %s\n",
+ output->name, relative_name);
+ output->initial_x = 0;
+ output->initial_y = 0;
+ any_set = TRUE;
+ continue;
+ }
+ if (relative->initial_x == POSITION_UNSET)
+ {
+ keep_going = TRUE;
+ continue;
+ }
+ output->initial_x = relative->initial_x;
+ output->initial_y = relative->initial_y;
+ switch (relation) {
+ case OPTION_BELOW:
+ output->initial_y += modes[or]->VDisplay;
+ break;
+ case OPTION_RIGHT_OF:
+ output->initial_x += modes[or]->HDisplay;
+ break;
+ case OPTION_ABOVE:
+ output->initial_y -= modes[o]->VDisplay;
+ break;
+ case OPTION_LEFT_OF:
+ output->initial_x -= modes[o]->HDisplay;
+ break;
+ default:
+ break;
+ }
+ any_set = TRUE;
+ continue;
+ }
+
+ /* Nothing set, just stick them at 0,0 */
+ output->initial_x = 0;
+ output->initial_y = 0;
+ any_set = TRUE;
+ }
+ if (!keep_going)
+ break;
+ if (!any_set)
+ {
+ for (o = 0; o < config->num_output; o++)
+ {
+ xf86OutputPtr output = config->output[o];
+ if (output->initial_x == POSITION_UNSET)
+ {
+ xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
+ "Output position loop. Moving %s to 0,0\n",
+ output->name);
+ output->initial_x = output->initial_y = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * normalize positions
+ */
+ min_x = 1000000;
+ min_y = 1000000;
+ for (o = 0; o < config->num_output; o++)
+ {
+ xf86OutputPtr output = config->output[o];
+
+ if (output->initial_x < min_x)
+ min_x = output->initial_x;
+ if (output->initial_y < min_y)
+ min_y = output->initial_y;
+ }
+
+ for (o = 0; o < config->num_output; o++)
+ {
+ xf86OutputPtr output = config->output[o];
+
+ output->initial_x -= min_x;
+ output->initial_y -= min_y;
+ }
+ return TRUE;
+}
+
/*
* XXX walk the monitor mode list and prune out duplicates that
* are inserted by xf86DDCMonitorSet. In an ideal world, that
@@ -440,39 +711,270 @@ xf86PruneDuplicateMonitorModes (MonPtr Monitor)
{
next = clone->next;
if (xf86ModesEqual (master, clone))
+ {
+ if (Monitor->Last == clone)
+ Monitor->Last = clone->prev;
xf86DeleteMode (&Monitor->Modes, clone);
+ }
+ }
+ }
+}
+
+/** Return - 0 + if a should be earlier, same or later than b in list
+ */
+static int
+i830xf86ModeCompare (DisplayModePtr a, DisplayModePtr b)
+{
+ int diff;
+
+ diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0);
+ if (diff)
+ return diff;
+ diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay;
+ if (diff)
+ return diff;
+ diff = b->Clock - a->Clock;
+ return diff;
+}
+
+/**
+ * Insertion sort input in-place and return the resulting head
+ */
+static DisplayModePtr
+i830xf86SortModes (DisplayModePtr input)
+{
+ DisplayModePtr output = NULL, i, o, n, *op, prev;
+
+ /* sort by preferred status and pixel area */
+ while (input)
+ {
+ i = input;
+ input = input->next;
+ for (op = &output; (o = *op); op = &o->next)
+ if (i830xf86ModeCompare (o, i) > 0)
+ break;
+ i->next = *op;
+ *op = i;
+ }
+ /* prune identical modes */
+ for (o = output; o && (n = o->next); o = n)
+ {
+ if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n))
+ {
+ o->next = n->next;
+ xfree (n->name);
+ xfree (n);
+ n = o;
}
}
+ /* hook up backward links */
+ prev = NULL;
+ for (o = output; o; o = o->next)
+ {
+ o->prev = prev;
+ prev = o;
+ }
+ return output;
}
+#define DEBUG_REPROBE 1
+
void
-xf86ProbeOutputModes (ScrnInfoPtr pScrn)
+xf86ProbeOutputModes (ScrnInfoPtr pScrn, int maxX, int maxY)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
- Bool properties_set = FALSE;
int o;
+ if (maxX == 0 || maxY == 0)
+ xf86RandR12GetOriginalVirtualSize (pScrn, &maxX, &maxY);
+
/* Elide duplicate modes before defaulting code uses them */
xf86PruneDuplicateMonitorModes (pScrn->monitor);
/* Probe the list of modes for each output. */
for (o = 0; o < config->num_output; o++)
{
- xf86OutputPtr output = config->output[o];
- DisplayModePtr mode;
-
+ xf86OutputPtr output = config->output[o];
+ DisplayModePtr mode;
+ DisplayModePtr config_modes = NULL, output_modes, default_modes;
+ char *preferred_mode;
+ xf86MonPtr edid_monitor;
+ XF86ConfMonitorPtr conf_monitor;
+ MonRec mon_rec;
+ int min_clock = 0;
+ int max_clock = 0;
+ double clock;
+ enum { sync_config, sync_edid, sync_default } sync_source = sync_default;
+
while (output->probed_modes != NULL)
xf86DeleteMode(&output->probed_modes, output->probed_modes);
- output->probed_modes = (*output->funcs->get_modes) (output);
+ /*
+ * Check connection status
+ */
+ output->status = (*output->funcs->detect)(output);
- /* Set the DDC properties to whatever first output has DDC information.
+ if (output->status == XF86OutputStatusDisconnected)
+ continue;
+
+ memset (&mon_rec, '\0', sizeof (mon_rec));
+
+ conf_monitor = output->conf_monitor;
+
+ if (conf_monitor)
+ {
+ int i;
+
+ for (i = 0; i < conf_monitor->mon_n_hsync; i++)
+ {
+ mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo;
+ mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi;
+ mon_rec.nHsync++;
+ sync_source = sync_config;
+ }
+ for (i = 0; i < conf_monitor->mon_n_vrefresh; i++)
+ {
+ mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo;
+ mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi;
+ mon_rec.nVrefresh++;
+ sync_source = sync_config;
+ }
+ config_modes = i830xf86GetMonitorModes (pScrn, conf_monitor);
+ }
+
+ output_modes = (*output->funcs->get_modes) (output);
+
+ edid_monitor = output->MonInfo;
+
+ if (edid_monitor)
+ {
+ int i;
+ Bool set_hsync = mon_rec.nHsync == 0;
+ Bool set_vrefresh = mon_rec.nVrefresh == 0;
+
+ for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++)
+ {
+ if (edid_monitor->det_mon[i].type == DS_RANGES)
+ {
+ struct monitor_ranges *ranges = &edid_monitor->det_mon[i].section.ranges;
+ if (set_hsync && ranges->max_h)
+ {
+ mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h;
+ mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h;
+ mon_rec.nHsync++;
+ if (sync_source == sync_default)
+ sync_source = sync_edid;
+ }
+ if (set_vrefresh && ranges->max_v)
+ {
+ mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v;
+ mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v;
+ mon_rec.nVrefresh++;
+ if (sync_source == sync_default)
+ sync_source = sync_edid;
+ }
+ if (ranges->max_clock > max_clock)
+ max_clock = ranges->max_clock;
+ }
+ }
+ }
+
+ if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK,
+ OPTUNITS_KHZ, &clock))
+ min_clock = (int) clock;
+ if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK,
+ OPTUNITS_KHZ, &clock))
+ max_clock = (int) clock;
+
+ /*
+ * These limits will end up setting a 1024x768@60Hz mode by default,
+ * which seems like a fairly good mode to use when nothing else is
+ * specified
*/
- if (output->MonInfo != NULL && !properties_set) {
- xf86SetDDCproperties(pScrn, output->MonInfo);
- properties_set = TRUE;
+ if (mon_rec.nHsync == 0)
+ {
+ mon_rec.hsync[0].lo = 31.0;
+ mon_rec.hsync[0].hi = 55.0;
+ mon_rec.nHsync = 1;
+ }
+ if (mon_rec.nVrefresh == 0)
+ {
+ mon_rec.vrefresh[0].lo = 58.0;
+ mon_rec.vrefresh[0].hi = 62.0;
+ mon_rec.nVrefresh = 1;
}
+ default_modes = RADEONxf86GetDefaultModes (output->interlaceAllowed,
+ output->doubleScanAllowed);
+
+ if (sync_source == sync_config)
+ {
+ /*
+ * Check output and config modes against sync range from config file
+ */
+ RADEONxf86ValidateModesSync (pScrn, output_modes, &mon_rec);
+ RADEONxf86ValidateModesSync (pScrn, config_modes, &mon_rec);
+ }
+ /*
+ * Check default modes against sync range
+ */
+ RADEONxf86ValidateModesSync (pScrn, default_modes, &mon_rec);
+ /*
+ * Check default modes against monitor max clock
+ */
+ if (max_clock)
+ RADEONxf86ValidateModesClocks(pScrn, default_modes,
+ &min_clock, &max_clock, 1);
+
+ output->probed_modes = NULL;
+ output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes);
+ output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes);
+ output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes);
+
+ /*
+ * Check all modes against max size
+ */
+ if (maxX && maxY)
+ RADEONxf86ValidateModesSize (pScrn, output->probed_modes,
+ maxX, maxY, 0);
+
+ /*
+ * Check all modes against output
+ */
+ for (mode = output->probed_modes; mode != NULL; mode = mode->next)
+ if (mode->status == MODE_OK)
+ mode->status = (*output->funcs->mode_valid)(output, mode);
+
+ RADEONxf86PruneInvalidModes(pScrn, &output->probed_modes, TRUE);
+
+ output->probed_modes = i830xf86SortModes (output->probed_modes);
+
+ /* Check for a configured preference for a particular mode */
+ preferred_mode = xf86GetOptValString (output->options,
+ OPTION_PREFERRED_MODE);
+ if (preferred_mode)
+ {
+ for (mode = output->probed_modes; mode; mode = mode->next)
+ {
+ if (!strcmp (preferred_mode, mode->name))
+ {
+ if (mode != output->probed_modes)
+ {
+ if (mode->prev)
+ mode->prev->next = mode->next;
+ if (mode->next)
+ mode->next->prev = mode->prev;
+ mode->next = output->probed_modes;
+ output->probed_modes->prev = mode;
+ mode->prev = NULL;
+ output->probed_modes = mode;
+ }
+ mode->type |= M_T_PREFERRED;
+ break;
+ }
+ }
+ }
+
#ifdef DEBUG_REPROBE
if (output->probed_modes != NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -515,7 +1017,6 @@ xf86SetScrnInfoModes (ScrnInfoPtr pScrn)
xf86OutputPtr output;
xf86CrtcPtr crtc;
DisplayModePtr last, mode;
- int originalVirtualX, originalVirtualY;
output = config->output[config->compat_output];
if (!output->crtc)
@@ -543,31 +1044,23 @@ xf86SetScrnInfoModes (ScrnInfoPtr pScrn)
/* Set pScrn->modes to the mode list for the 'compat' output */
pScrn->modes = xf86DuplicateModes(pScrn, output->probed_modes);
- xf86RandR12GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY);
-
- /* Disable modes in the XFree86 DDX list that are larger than the current
- * virtual size.
- */
- RADEONxf86ValidateModesSize(pScrn, pScrn->modes,
- originalVirtualX, originalVirtualY,
- pScrn->displayWidth);
-
- /* Strip out anything that we threw out for virtualX/Y. */
- RADEONxf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE);
-
for (mode = pScrn->modes; mode; mode = mode->next)
if (xf86ModesEqual (mode, &crtc->desiredMode))
break;
-
- /* For some reason, pScrn->modes is circular, unlike the other mode lists.
- * How great is that?
- */
- for (last = pScrn->modes; last && last->next; last = last->next);
- last->next = pScrn->modes;
- pScrn->modes->prev = last;
- if (mode)
- while (pScrn->modes != mode)
- pScrn->modes = pScrn->modes->next;
+
+ if (pScrn->modes != NULL) {
+ /* For some reason, pScrn->modes is circular, unlike the other mode
+ * lists. How great is that?
+ */
+ for (last = pScrn->modes; last && last->next; last = last->next)
+ ;
+ last->next = pScrn->modes;
+ pScrn->modes->prev = last;
+ if (mode) {
+ while (pScrn->modes != mode)
+ pScrn->modes = pScrn->modes->next;
+ }
+ }
pScrn->currentMode = pScrn->modes;
}
@@ -586,35 +1079,33 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn)
DisplayModePtr target_mode = NULL;
xf86CrtcPtr *crtcs;
DisplayModePtr *modes;
- int width, height;
+ Bool *enabled;
+ int width;
+ int height;
- xf86ProbeOutputModes (pScrn);
-
- if (pScrn->display->virtualX == 0)
- {
- /*
- * Expand virtual size to cover potential mode switches
- */
- xf86DefaultScreenLimits (pScrn, &width, &height);
-
- pScrn->display->virtualX = width;
- pScrn->display->virtualY = height;
- }
- else
- {
+ if (pScrn->display->virtualX)
width = pScrn->display->virtualX;
+ else
+ width = config->maxWidth;
+ if (pScrn->display->virtualY)
height = pScrn->display->virtualY;
- }
- if (width > pScrn->virtualX)
- pScrn->virtualX = width;
- if (height > pScrn->virtualY)
- pScrn->virtualY = height;
-
+ else
+ height = config->maxHeight;
+
+ xf86ProbeOutputModes (pScrn, width, height);
+
crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr));
modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr));
+ enabled = xnfcalloc (config->num_output, sizeof (Bool));
for (o = 0; o < config->num_output; o++)
+ {
+ xf86OutputPtr output = config->output[o];
+
modes[o] = NULL;
+ enabled[o] = (xf86OutputEnabled (output) &&
+ output->status != XF86OutputStatusDisconnected);
+ }
/*
* Let outputs with preferred modes drive screen size
@@ -623,7 +1114,7 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn)
{
xf86OutputPtr output = config->output[o];
- if (output->status != XF86OutputStatusDisconnected &&
+ if (enabled[o] &&
xf86OutputHasPreferredMode (output, width, height))
{
target_mode = xf86DefaultMode (output, width, height);
@@ -640,7 +1131,7 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn)
for (o = 0; o < config->num_output; o++)
{
xf86OutputPtr output = config->output[o];
- if (output->status != XF86OutputStatusDisconnected)
+ if (enabled[o])
{
target_mode = xf86DefaultMode (output, width, height);
if (target_mode)
@@ -656,10 +1147,23 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn)
{
xf86OutputPtr output = config->output[o];
- if (output->status != XF86OutputStatusDisconnected && !modes[o])
+ if (enabled[o] && !modes[o])
modes[o] = xf86ClosestMode (output, target_mode, width, height);
}
+ /*
+ * Set the position of each output
+ */
+ if (!xf86InitialOutputPositions (pScrn, modes))
+ {
+ xfree (crtcs);
+ xfree (modes);
+ return FALSE;
+ }
+
+ /*
+ * Assign CRTCs to fit output configuration
+ */
if (!xf86PickCrtcs (pScrn, crtcs, modes, 0, width, height))
{
xfree (crtcs);
@@ -679,7 +1183,7 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn)
crtc->enabled = FALSE;
memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode));
}
-
+
/*
* Set initial configuration
*/
@@ -693,13 +1197,28 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn)
{
crtc->desiredMode = *mode;
crtc->enabled = TRUE;
- crtc->x = 0;
- crtc->y = 0;
+ crtc->x = output->initial_x;
+ crtc->y = output->initial_y;
output->crtc = crtc;
- /* XXX set position; for now, we clone */
}
}
+ if (pScrn->display->virtualX == 0)
+ {
+ /*
+ * Expand virtual size to cover potential mode switches
+ */
+ xf86DefaultScreenLimits (pScrn, &width, &height);
+
+ pScrn->display->virtualX = width;
+ pScrn->display->virtualY = height;
+ }
+
+ if (width > pScrn->virtualX)
+ pScrn->virtualX = width;
+ if (height > pScrn->virtualY)
+ pScrn->virtualY = height;
+
/* Mirror output modes to pScrn mode list */
xf86SetScrnInfoModes (pScrn);
@@ -742,3 +1261,115 @@ xf86DPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
}
}
}
+
+#ifdef RANDR_12_INTERFACE
+
+#define EDID_ATOM_NAME "EDID_DATA"
+
+/**
+ * Set the RandR EDID property
+ */
+static void
+xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len)
+{
+ Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME), TRUE);
+
+ /* This may get called before the RandR resources have been created */
+ if (output->randr_output == NULL)
+ return;
+
+ if (data_len != 0) {
+ RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8,
+ PropModeReplace, data_len, data, FALSE);
+ } else {
+ RRDeleteOutputProperty(output->randr_output, edid_atom);
+ }
+}
+
+#endif
+
+/**
+ * Set the EDID information for the specified output
+ */
+void
+i830_xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
+#ifdef RANDR_12_INTERFACE
+ int size;
+#endif
+
+ if (output->MonInfo != NULL)
+ xfree(output->MonInfo);
+
+ output->MonInfo = edid_mon;
+
+ /* Debug info for now, at least */
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID for output %s\n", output->name);
+ xf86PrintEDID(edid_mon);
+
+ /* Set the DDC properties for the 'compat' output */
+ if (output == config->output[config->compat_output])
+ xf86SetDDCproperties(pScrn, edid_mon);
+
+#ifdef RANDR_12_INTERFACE
+ /* Set the RandR output properties */
+ size = 0;
+ if (edid_mon)
+ {
+ if (edid_mon->ver.version == 1)
+ size = 128;
+ else if (edid_mon->ver.version == 2)
+ size = 256;
+ }
+ xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size);
+#endif
+
+ if (edid_mon)
+ {
+ /* Pull out a phyiscal size from a detailed timing if available. */
+ for (i = 0; i < 4; i++) {
+ if (edid_mon->det_mon[i].type == DT &&
+ edid_mon->det_mon[i].section.d_timings.h_size != 0 &&
+ edid_mon->det_mon[i].section.d_timings.v_size != 0)
+ {
+ output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size;
+ output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size;
+ break;
+ }
+ }
+
+ /* if no mm size is available from a detailed timing, check the max size field */
+ if ((!output->mm_width || !output->mm_height) &&
+ (edid_mon->features.hsize && edid_mon->features.vsize))
+ {
+ output->mm_width = edid_mon->features.hsize * 10;
+ output->mm_height = edid_mon->features.vsize * 10;
+ }
+ }
+}
+
+/**
+ * Return the list of modes supported by the EDID information
+ * stored in 'output'
+ */
+DisplayModePtr
+i830_xf86OutputGetEDIDModes (xf86OutputPtr output)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ xf86MonPtr edid_mon = output->MonInfo;
+
+ if (!edid_mon)
+ return NULL;
+ return xf86DDCGetModes(pScrn->scrnIndex, edid_mon);
+}
+
+xf86MonPtr
+i830_xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+
+ return xf86DoEDID_DDC2 (pScrn->scrnIndex, pDDCBus);
+}