sna: Allow pipes to be manually assigned to ZaphodHeads

Assigning pipes to a driver instance is hard as not only do we have a
limited number (so choosing which instances should share CRTCs requires
user intervention) but also some pipes are limited by hardware to
certain outputs and certain modes (and we do not have the full knowledge
of the future configuration to be able to determine where to assign the
CRTC). As usual, when there is no clear answer, punt it to the user.

This expands the ZaphodHeads option to include an optional
comma-separated pipe list followed by a colon before the output list,
e.g.

Section "Device"
        Identifier "Device0"
        Driver "intel"
        Option "ZaphodHeads" "1:LVDS"
        BusID "PCI:0:2:0"
        Screen 0
EndSection

Section "Device"
        Identifier "Device1"
        Driver "intel"
        Option "ZaphodHeads" "0,2:HDMI1,HDMI2,HDMI3"
        BusID "PCI:0:2:0"
        Screen 1
EndSection

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2015-10-30 18:07:37 +00:00
parent d78200e53e
commit 94d271b239
2 changed files with 113 additions and 58 deletions

View File

@ -344,12 +344,28 @@ Default: 0
.IP
Specify the randr output(s) to use with zaphod mode for a particular driver
instance. If you set this option you must use it with all instances of the
driver
driver. By default, each head is assigned only one CRTC (which limits
using multiple outputs with that head to cloned mode). CRTC can be manually
assigned to individual heads by preceding the output names with a comma
delimited list of pipe numbers followed by a colon. Note that different pipes
may be limited in their functionality and some outputs may only work with
different pipes.
.br
For example:
.RS
.B
Option \*qZaphodHeads\*q \*qLVDS1,VGA1\*q
will assign xrandr outputs LVDS1 and VGA1 to this instance of the driver.
.RE
.RS
.B
Option \*qZaphodHeads\*q \*q0,2:HDMI1,DP2\*q
will assign xrandr outputs HDMI1 and DP2 and CRTCs 0 and 2 to this instance of the driver.
.RE
.SH OUTPUT CONFIGURATION
On 830M and better chipsets, the driver supports runtime configuration of

View File

@ -272,6 +272,81 @@ static bool is_zaphod(ScrnInfoPtr scrn)
return xf86IsEntityShared(scrn->entityList[0]);
}
static bool
sna_zaphod_match(struct sna *sna, const char *output)
{
const char *s, *colon;
char t[20];
unsigned int i = 0;
s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
if (s == NULL)
return false;
colon = strchr(s, ':');
if (colon) /* Skip over the ZaphodPipes */
s = colon + 1;
do {
/* match any outputs in a comma list, stopping at whitespace */
switch (*s) {
case '\0':
t[i] = '\0';
return strcmp(t, output) == 0;
case ',':
t[i] ='\0';
if (strcmp(t, output) == 0)
return TRUE;
i = 0;
break;
case ' ':
case '\t':
case '\n':
case '\r':
break;
default:
t[i++] = *s;
break;
}
s++;
} while (i < sizeof(t));
return false;
}
static unsigned
get_zaphod_crtcs(struct sna *sna)
{
const char *str, *colon;
unsigned crtcs = 0;
str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
if (str == NULL || (colon = strchr(str, ':')) == NULL) {
DBG(("%s: no zaphod pipes, using screen number: %x\n",
__FUNCTION__,
sna->scrn->confScreen->device->screen));
return 1 << sna->scrn->confScreen->device->screen;
}
DBG(("%s: ZaphodHeads='%s'\n", __FUNCTION__, str));
while (str < colon) {
char *end;
unsigned crtc = strtoul(str, &end, 0);
if (end == str)
break;
DBG(("%s: adding CRTC %d to zaphod pipes\n",
__FUNCTION__, crtc));
crtcs |= 1 << crtc;
str = end + 1;
}
DBG(("%s: ZaphodPipes=%x\n", __FUNCTION__, crtcs));
return crtcs;
}
inline static unsigned count_to_mask(int x)
{
return (1 << x) - 1;
@ -3027,7 +3102,7 @@ sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
struct sna_crtc *sna_crtc;
struct drm_i915_get_pipe_from_crtc_id get_pipe;
DBG(("%s(%d)\n", __FUNCTION__, id));
DBG(("%s(%d): is-zaphod? %d\n", __FUNCTION__, id, is_zaphod(scrn)));
sna_crtc = calloc(sizeof(struct sna_crtc), 1);
if (sna_crtc == NULL)
@ -3049,7 +3124,7 @@ sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
sna_crtc->flags |= get_pipe.pipe << 8;
if (is_zaphod(scrn) &&
scrn->confScreen->device->screen != get_pipe.pipe) {
(get_zaphod_crtcs(sna) & (1 << get_pipe.pipe)) == 0) {
free(sna_crtc);
return true;
}
@ -4111,43 +4186,6 @@ static const char * const output_names[] = {
/* DRM_MODE_CONNECTOR_DSI */ "DSI"
};
static bool
sna_zaphod_match(const char *s, const char *output)
{
char t[20];
unsigned int i = 0;
do {
/* match any outputs in a comma list, stopping at whitespace */
switch (*s) {
case '\0':
t[i] = '\0';
return strcmp(t, output) == 0;
case ',':
t[i] ='\0';
if (strcmp(t, output) == 0)
return TRUE;
i = 0;
break;
case ' ':
case '\t':
case '\n':
case '\r':
break;
default:
t[i++] = *s;
break;
}
s++;
} while (i < sizeof(t));
return false;
}
static bool
output_ignored(ScrnInfoPtr scrn, const char *name)
{
@ -4541,25 +4579,26 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
}
if (is_zaphod(scrn)) {
const char *str;
unsigned zaphod_crtcs;
str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
if (str && !sna_zaphod_match(str, name)) {
DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
if (!sna_zaphod_match(sna, name)) {
DBG(("%s: zaphod mismatch, want %s, have %s\n",
__FUNCTION__,
xf86GetOptValString(sna->Options, OPTION_ZAPHOD),
name));
return 0;
}
if ((possible_crtcs & (1 << scrn->confScreen->device->screen)) == 0) {
if (str) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"%s is an invalid output for screen (pipe) %d\n",
name, scrn->confScreen->device->screen);
return -1;
} else
return 0;
zaphod_crtcs = get_zaphod_crtcs(sna);
possible_crtcs &= zaphod_crtcs;
if (possible_crtcs == 0) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"%s is an invalid output for screen %d\n",
name, scrn->confScreen->device->screen);
return -1;
}
possible_crtcs = 1;
possible_crtcs >>= ffs(zaphod_crtcs) - 1;
}
sna_output = calloc(sizeof(struct sna_output), 1);
@ -4599,16 +4638,16 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
/* Construct name from topology, and recheck if output is acceptable */
path = name_from_path(sna, sna_output, name);
if (path) {
const char *str;
if (output_ignored(scrn, name)) {
len = 0;
goto skip;
}
str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
if (str && !sna_zaphod_match(str, name)) {
DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
if (!sna_zaphod_match(sna, name)) {
DBG(("%s: zaphod mismatch, want %s, have %s\n",
__FUNCTION__,
xf86GetOptValString(sna->Options, OPTION_ZAPHOD),
name));
len = 0;
goto skip;
}