summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-05-08 11:49:55 +1000
committerDave Airlie <airlied@redhat.com>2014-05-08 11:49:55 +1000
commitef8ae235cf128667a410f9ef4579185be553d192 (patch)
tree3489e9daa01db6c9d1c1c6ee005366b7db442a24
parent78726bccb8bbb9688274ce32101f60e283e65179 (diff)
modesetting: add DP MST supportdp-mst
as per discussions on dri-devel, don't tear down outputs as this can cause randr errors in apps, add an option same as nvidia to allow this behaviour.
-rw-r--r--src/driver.c6
-rw-r--r--src/drmmode_display.c216
-rw-r--r--src/drmmode_display.h1
3 files changed, 175 insertions, 48 deletions
diff --git a/src/driver.c b/src/driver.c
index 21274a9..fab50a3 100644
--- a/src/driver.c
+++ b/src/driver.c
@@ -125,12 +125,14 @@ typedef enum
OPTION_SW_CURSOR,
OPTION_DEVICE_PATH,
OPTION_SHADOW_FB,
+ OPTION_DELETE_DP_12_DISP,
} modesettingOpts;
static const OptionInfoRec Options[] = {
{OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE },
{OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE },
+ {OPTION_DELETE_DP_12_DISP, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
@@ -735,6 +737,10 @@ PreInit(ScrnInfoPtr pScrn, int flags)
ms->drmmode.sw_cursor = TRUE;
}
+ if (xf86ReturnOptValBool(ms->Options, OPTION_DELETE_DP_12_DISP, FALSE)) {
+ ms->drmmode.delete_dp_12_displays = TRUE;
+ }
+
ret = drmGetCap(ms->fd, DRM_CAP_DUMB_PREFER_SHADOW, &value);
if (!ret) {
prefer_shadow = !!value;
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 0cf8c13..f248a2e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -364,6 +364,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
continue;
drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == -1)
+ continue;
output_ids[output_count] = drmmode_output->mode_output->connector_id;
output_count++;
}
@@ -403,10 +405,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
/* go through all the outputs and force DPMS them back on? */
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
if (output->crtc != crtc)
continue;
+ if (drmmode_output->output_id == -1)
+ continue;
output->funcs->dpms(output, DPMSModeOn);
}
}
@@ -620,6 +625,10 @@ drmmode_output_detect(xf86OutputPtr output)
drmmode_output_private_ptr drmmode_output = output->driver_private;
drmmode_ptr drmmode = drmmode_output->drmmode;
xf86OutputStatus status;
+
+ if (drmmode_output->output_id == -1)
+ return XF86OutputStatusDisconnected;
+
drmModeFreeConnector(drmmode_output->mode_output);
drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
@@ -1002,20 +1011,133 @@ static const char * const output_names[] = { "None",
"DSI",
};
+static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output;
+
+ drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == id)
+ return output;
+ }
+ return NULL;
+}
+
+static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
+{
+ char *conn;
+ char conn_id[5];
+ int id, len;
+ char *blob_data;
+
+ if (!path_blob)
+ return -1;
+
+ blob_data = path_blob->data;
+ /* we only handle MST paths for now */
+ if (strncmp(blob_data, "mst:", 4))
+ return -1;
+
+ conn = strchr(blob_data + 4, '-');
+ if (!conn)
+ return -1;
+ len = conn - (blob_data + 4);
+ if (len + 1> 5)
+ return -1;
+ memcpy(conn_id, blob_data + 4, len);
+ conn_id[len + 1] = '\0';
+ id = strtoul(conn_id, NULL, 10);
+
+ *conn_base_id = id;
+
+ *path = conn + 1;
+ return 0;
+}
+
+static void
+drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
+ drmModePropertyBlobPtr path_blob)
+{
+ int ret;
+ char *extra_path;
+ int conn_id;
+ xf86OutputPtr output;
+
+ ret = parse_path_blob(path_blob, &conn_id, &extra_path);
+ if (ret == -1)
+ goto fallback;
+
+ output = find_output(pScrn, conn_id);
+ if (!output)
+ goto fallback;
+
+ snprintf(name, 32, "%s-%s", output->name, extra_path);
+ ErrorF("setting name to %s\n", name);
+ return;
+
+fallback:
+ if (koutput->connector_type >= MS_ARRAY_SIZE(output_names))
+ snprintf(name, 32, "Unknown-%d", koutput->connector_type_id - 1);
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ else if (pScrn->is_gpu)
+ snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1);
+#endif
+ else
+ snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
+}
+
static void
-drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int add_randr)
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int dynamic)
{
xf86OutputPtr output;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
drmModeConnectorPtr koutput;
drmModeEncoderPtr *kencoders = NULL;
drmmode_output_private_ptr drmmode_output;
drmModePropertyPtr props;
char name[32];
int i;
+ drmModePropertyBlobPtr path_blob = NULL;
koutput = drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
if (!koutput)
return;
+ for (i = 0; i < koutput->count_props; i++) {
+ props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+ if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
+ if (!strcmp(props->name, "PATH")) {
+ path_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
+
+ drmModeFreeProperty(props);
+ break;
+ }
+ drmModeFreeProperty(props);
+ }
+ }
+
+ drmmode_create_name(pScrn, koutput, name, path_blob);
+
+ if (path_blob)
+ drmModeFreePropertyBlob(path_blob);
+
+ if (path_blob && dynamic) {
+ /* see if we have an output with this name already
+ and hook stuff up */
+ for (i = 0; i < xf86_config->num_output; i++) {
+ output = xf86_config->output[i];
+
+ if (strncmp(output->name, name, 32))
+ continue;
+
+ drmmode_output = output->driver_private;
+ drmmode_output->output_id = mode_res->connectors[num];
+ drmmode_output->mode_output = koutput;
+ return;
+ }
+ }
kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
if (!kencoders) {
@@ -1029,16 +1151,6 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
}
}
- /* need to do smart conversion here for compat with non-kms ATI driver */
- if (koutput->connector_type >= MS_ARRAY_SIZE(output_names))
- snprintf(name, 32, "Unknown-%d", koutput->connector_type_id - 1);
-#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
- else if (pScrn->is_gpu)
- snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1);
-#endif
- else
- snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
-
output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
if (!output) {
goto out_free_encoders;
@@ -1081,7 +1193,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
}
}
- if (add_randr)
+ if (dynamic)
output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
return;
out_free_encoders:
@@ -1455,7 +1567,9 @@ drmmode_handle_uevents(int fd, void *closure)
drmModeResPtr mode_res;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int i, j;
- ErrorF("got uevent\n");
+ Bool found;
+ Bool changed = FALSE;
+
dev = udev_monitor_receive_device(drmmode->uevent_monitor);
if (!dev) {
ErrorF("failed to get monitor device\n");
@@ -1466,69 +1580,75 @@ drmmode_handle_uevents(int fd, void *closure)
if (!mode_res)
goto out;
- ErrorF("got resourecs %d %d enc %d\n", mode_res->count_crtcs, mode_res->count_connectors, mode_res->count_encoders);
if (mode_res->count_crtcs != config->num_crtc) {
ErrorF("number of CRTCs changed - failed to handle, %d vs %d\n", mode_res->count_crtcs, config->num_crtc);
goto out_free_res;
}
- if (mode_res->count_connectors != config->num_output) {
- Bool found;
- /* figure out if we have gotten rid of any connectors
- traverse old output list looking for outputs */
+ /* figure out if we have gotten rid of any connectors
+ traverse old output list looking for outputs */
restart_destroy:
- for (i = 0; i < config->num_output; i++) {
- xf86OutputPtr output = config->output[i];
- drmmode_output_private_ptr drmmode_output;
+ for (i = 0; i < config->num_output; i++) {
+ xf86OutputPtr output = config->output[i];
+ drmmode_output_private_ptr drmmode_output;
- drmmode_output = output->driver_private;
- found = FALSE;
- for (j = 0; j < mode_res->count_connectors; j++) {
- if (mode_res->connectors[j] == drmmode_output->output_id) {
- found = TRUE;
- break;
- }
+ drmmode_output = output->driver_private;
+ found = FALSE;
+ for (j = 0; j < mode_res->count_connectors; j++) {
+ if (mode_res->connectors[j] == drmmode_output->output_id) {
+ found = TRUE;
+ break;
}
- if (found)
- continue;
+ }
+ if (found)
+ continue;
+
+ drmModeFreeConnector(drmmode_output->mode_output);
+ drmmode_output->mode_output = NULL;
+ drmmode_output->output_id = -1;
+ changed = TRUE;
+ if (drmmode->delete_dp_12_displays) {
ErrorF("destroying id %d\n", drmmode_output->output_id);
RROutputDestroy(output->randr_output);
xf86OutputDestroy(output);
goto restart_destroy;
}
+ }
- /* find new output ids we don't have outputs for */
- for (i = 0; i < mode_res->count_connectors; i++) {
-
- found = FALSE;
+ /* find new output ids we don't have outputs for */
+ for (i = 0; i < mode_res->count_connectors; i++) {
+ found = FALSE;
- for (j = 0; j < config->num_output; j++) {
- xf86OutputPtr output = config->output[j];
- drmmode_output_private_ptr drmmode_output;
+ for (j = 0; j < config->num_output; j++) {
+ xf86OutputPtr output = config->output[j];
+ drmmode_output_private_ptr drmmode_output;
- drmmode_output = output->driver_private;
- if (mode_res->connectors[i] == drmmode_output->output_id) {
- found = TRUE;
- break;
- }
+ drmmode_output = output->driver_private;
+ if (mode_res->connectors[i] == drmmode_output->output_id) {
+ found = TRUE;
+ break;
}
- if (found)
- continue;
+ }
+ if (found)
+ continue;
- ErrorF("adding id %d\n", mode_res->connectors[i]);
- drmmode_output_init(scrn, drmmode, mode_res, i, 1);
+ changed = TRUE;
+ ErrorF("adding id %d\n", mode_res->connectors[i]);
+ drmmode_output_init(scrn, drmmode, mode_res, i, 1);
- }
+ }
+
+ if (changed) {
RRSetChanged(xf86ScrnToScreen(scrn));
RRTellChanged(xf86ScrnToScreen(scrn));
}
+
out_free_res:
drmModeFreeResources(mode_res);
out:
RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
-
udev_device_unref(dev);
}
#endif
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index f90b547..c9996f9 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -70,6 +70,7 @@ typedef struct {
#ifdef HAVE_SCREEN_SPECIFIC_PRIVATE_KEYS
DevPrivateKeyRec pixmapPrivateKeyRec;
#endif
+ Bool delete_dp_12_displays;
} drmmode_rec, *drmmode_ptr;
typedef struct {