@@ -408,6 +408,7 @@ extern void intel_mode_remove_fb(intel_screen_private *intel);
extern void intel_mode_close(intel_screen_private *intel);
extern void intel_mode_fini(intel_screen_private *intel);
extern int intel_mode_read_drm_events(intel_screen_private *intel);
+extern void intel_mode_hotplug(intel_screen_private *intel);
typedef void (*intel_drm_handler_proc)(ScrnInfoPtr scrn,
xf86CrtcPtr crtc,
@@ -94,6 +94,8 @@ struct intel_mode {
void *pageflip_data;
intel_pageflip_handler_proc pageflip_handler;
intel_pageflip_abort_proc pageflip_abort;
+
+ Bool delete_dp_12_displays;
};
struct intel_pageflip {
@@ -130,7 +132,7 @@ struct intel_output {
struct intel_mode *mode;
int output_id;
drmModeConnectorPtr mode_output;
- drmModeEncoderPtr mode_encoder;
+ drmModeEncoderPtr *mode_encoders;
drmModePropertyBlobPtr edid_blob;
int num_props;
struct intel_property *props;
@@ -145,6 +147,8 @@ struct intel_output {
int backlight_active_level;
xf86OutputPtr output;
struct list link;
+ int enc_mask;
+ int enc_clone_mask;
};
static void
@@ -331,6 +335,9 @@ intel_crtc_apply(xf86CrtcPtr crtc)
continue;
intel_output = output->driver_private;
+ if (!intel_output->mode_output)
+ return FALSE;
+
output_ids[output_count] =
intel_output->mode_output->connector_id;
output_count++;
@@ -808,6 +815,11 @@ intel_output_attach_edid(xf86OutputPtr output)
xf86MonPtr mon = NULL;
int i;
+ if (!koutput) {
+ xf86OutputSetEDID(output, mon);
+ return;
+ }
+
/* look for an EDID property */
for (i = 0; i < koutput->count_props; i++) {
drmModePropertyPtr props;
@@ -897,6 +909,9 @@ intel_output_get_modes(xf86OutputPtr output)
intel_output_attach_edid(output);
+ if (!koutput)
+ return Modes;
+
/* modes should already be available */
for (i = 0; i < koutput->count_modes; i++) {
DisplayModePtr Mode;
@@ -949,7 +964,10 @@ intel_output_destroy(xf86OutputPtr output)
free(intel_output->props[i].atoms);
}
free(intel_output->props);
-
+ for (i = 0; i < intel_output->mode_output->count_encoders; i++) {
+ drmModeFreeEncoder(intel_output->mode_encoders[i]);
+ }
+ free(intel_output->mode_encoders);
drmModeFreeConnector(intel_output->mode_output);
intel_output->mode_output = NULL;
@@ -989,6 +1007,9 @@ intel_output_dpms(xf86OutputPtr output, int dpms)
struct intel_mode *mode = intel_output->mode;
int i;
+ if (!koutput)
+ return;
+
for (i = 0; i < koutput->count_props; i++) {
drmModePropertyPtr props;
@@ -1338,51 +1359,158 @@ static const char *output_names[] = {
"eDP",
};
+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];
+ struct intel_output *intel_output;
+
+ intel_output = output->driver_private;
+ if (intel_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] = '\0';
+ id = strtoul(conn_id, NULL, 10);
+
+ *conn_base_id = id;
+
+ *path = conn + 1;
+ return 0;
+}
+
static void
-intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res, int num)
+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 >= 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
+intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res, int num, int dynamic)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86OutputPtr output;
drmModeConnectorPtr koutput;
- drmModeEncoderPtr kencoder;
+ drmModeEncoderPtr *kencoders = NULL;
struct intel_output *intel_output;
- const char *output_name;
char name[32];
+ drmModePropertyPtr props;
+ drmModePropertyBlobPtr path_blob = NULL;
+ int i;
koutput = drmModeGetConnector(mode->fd,
mode_res->connectors[num]);
if (!koutput)
return;
+ for (i = 0; i < koutput->count_props; i++) {
+ props = drmModeGetProperty(mode->fd, koutput->props[i]);
+ if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
+ if (!strcmp(props->name, "PATH")) {
+ path_blob = drmModeGetPropertyBlob(mode->fd, koutput->prop_values[i]);
- kencoder = drmModeGetEncoder(mode->fd, koutput->encoders[0]);
- if (!kencoder) {
- drmModeFreeConnector(koutput);
- return;
+ drmModeFreeProperty(props);
+ break;
+ }
+ drmModeFreeProperty(props);
+ }
}
- if (koutput->connector_type < ARRAY_SIZE(output_names))
- output_name = output_names[koutput->connector_type];
- else
- output_name = "UNKNOWN";
- snprintf(name, 32, "%s%d", output_name, koutput->connector_type_id);
+ drmmode_create_name(scrn, 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;
+
+ intel_output = output->driver_private;
+ intel_output->output_id = mode_res->connectors[num];
+ intel_output->mode_output = koutput;
+ return;
+ }
+ }
+ kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
+ if (!kencoders) {
+ goto out_free_encoders;
+ }
+
+ for (i = 0; i < koutput->count_encoders; i++) {
+ kencoders[i] = drmModeGetEncoder(mode->fd, koutput->encoders[i]);
+ if (!kencoders[i])
+ goto out_free_encoders;
+ }
output = xf86OutputCreate (scrn, &intel_output_funcs, name);
if (!output) {
- drmModeFreeEncoder(kencoder);
- drmModeFreeConnector(koutput);
- return;
+ goto out_free_encoders;
}
intel_output = calloc(sizeof(struct intel_output), 1);
if (!intel_output) {
xf86OutputDestroy(output);
- drmModeFreeConnector(koutput);
- drmModeFreeEncoder(kencoder);
- return;
+ goto out_free_encoders;
}
intel_output->output_id = mode_res->connectors[num];
intel_output->mode_output = koutput;
- intel_output->mode_encoder = kencoder;
+ intel_output->mode_encoders = kencoders;
intel_output->mode = mode;
output->mm_width = koutput->mmWidth;
@@ -1394,11 +1522,22 @@ intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_
if (is_panel(koutput->connector_type))
intel_output_backlight_init(output);
- output->possible_crtcs = kencoder->possible_crtcs;
+ output->possible_crtcs = 0x7f;
+ for (i = 0; i < koutput->count_encoders; i++) {
+ output->possible_crtcs &= kencoders[i]->possible_crtcs;
+ }
output->interlaceAllowed = TRUE;
intel_output->output = output;
list_add(&intel_output->link, &mode->outputs);
+ return;
+out_free_encoders:
+ if (kencoders) {
+ for (i = 0; i < koutput->count_encoders; i++)
+ drmModeFreeEncoder(kencoders[i]);
+ free(kencoders);
+ }
+ drmModeFreeConnector(koutput);
}
static Bool
@@ -1962,57 +2101,63 @@ intel_mode_read_drm_events(struct intel_screen_private *intel)
return drmHandleEvent(mode->fd, &mode->event_context);
}
-static drmModeEncoderPtr
-intel_get_kencoder(struct intel_mode *mode, drmModeResPtr mode_res, int num)
-{
- struct intel_output *iterator;
- int id = mode_res->encoders[num];
-
- list_for_each_entry(iterator, &mode->outputs, link)
- if (iterator->mode_encoder->encoder_id == id)
- return iterator->mode_encoder;
-
- return NULL;
-}
-
/*
* Libdrm's possible_clones is a mask of encoders, Xorg's possible_clones is a
* mask of outputs. This function sets Xorg's possible_clones based on the
* values read from libdrm.
*/
-static void
-intel_compute_possible_clones(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res)
+static uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
{
- xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
- struct intel_output *intel_output, *clone;
- drmModeEncoderPtr cloned_encoder;
- uint32_t mask;
- int i, j, k;
- CARD32 possible_clones;
+ struct intel_output *intel_output = output->driver_private, *clone_drmout;
+ int i;
+ xf86OutputPtr clone_output;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int index_mask = 0;
- for (i = 0; i < config->num_output; i++) {
- possible_clones = 0;
- intel_output = config->output[i]->driver_private;
+ if (intel_output->enc_clone_mask == 0)
+ return index_mask;
- mask = intel_output->mode_encoder->possible_clones;
- for (j = 0; mask != 0; j++, mask >>= 1) {
+ for (i = 0; i < xf86_config->num_output; i++) {
+ clone_output = xf86_config->output[i];
+ clone_drmout = clone_output->driver_private;
+ if (output == clone_output)
+ continue;
- if ((mask & 1) == 0)
- continue;
+ if (clone_drmout->enc_mask == 0)
+ continue;
+ if (intel_output->enc_clone_mask == clone_drmout->enc_mask)
+ index_mask |= (1 << i);
+ }
+ return index_mask;
+}
+static void
+intel_compute_possible_clones(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res)
+{
+ int i, j;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
- cloned_encoder = intel_get_kencoder(mode, mode_res, j);
- if (!cloned_encoder)
- continue;
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ struct intel_output *intel_output;
- for (k = 0; k < config->num_output; k++) {
- clone = config->output[k]->driver_private;
- if (clone->mode_encoder->encoder_id ==
- cloned_encoder->encoder_id)
- possible_clones |= (1 << k);
+ intel_output = output->driver_private;
+ intel_output->enc_clone_mask = 0xff;
+ /* and all the possible encoder clones for this output together */
+ for (j = 0; j < intel_output->mode_output->count_encoders; j++)
+ {
+ int k;
+ for (k = 0; k < mode_res->count_encoders; k++) {
+ if (mode_res->encoders[k] == intel_output->mode_encoders[j]->encoder_id)
+ intel_output->enc_mask |= (1 << k);
}
+
+ intel_output->enc_clone_mask &= intel_output->mode_encoders[j]->possible_clones;
}
+ }
- config->output[i]->possible_clones = possible_clones;
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ output->possible_clones = find_clones(scrn, output);
}
}
@@ -2051,7 +2196,7 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
intel_crtc_init(scrn, mode, mode_res, i);
for (i = 0; i < mode_res->count_connectors; i++)
- intel_output_init(scrn, mode, mode_res, i);
+ intel_output_init(scrn, mode, mode_res, i, 0);
intel_compute_possible_clones(scrn, mode, mode_res);
@@ -2080,6 +2225,10 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
intel->use_pageflipping = TRUE;
}
+ if (xf86ReturnOptValBool(intel->Options, OPTION_DELETE_DP12, FALSE)) {
+ mode->delete_dp_12_displays = TRUE;
+ }
+
intel->modes = mode;
drmModeFreeResources(mode_res);
return TRUE;
@@ -2332,3 +2481,79 @@ cleanup_dst:
cleanup_src:
(*pScreen->DestroyPixmap)(src);
}
+
+void
+intel_mode_hotplug(struct intel_screen_private *intel)
+{
+ ScrnInfoPtr scrn = intel->scrn;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ drmModeResPtr mode_res;
+ int i, j;
+ Bool found;
+ Bool changed = FALSE;
+ struct intel_mode *mode = intel->modes;
+ mode_res = drmModeGetResources(intel->drmSubFD);
+ if (!mode_res)
+ goto out;
+
+restart_destroy:
+ for (i = 0; i < config->num_output; i++) {
+ xf86OutputPtr output = config->output[i];
+ struct intel_output *intel_output;
+
+ intel_output = output->driver_private;
+ found = FALSE;
+ for (j = 0; j < mode_res->count_connectors; j++) {
+ if (mode_res->connectors[j] == intel_output->output_id) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ drmModeFreeConnector(intel_output->mode_output);
+ intel_output->mode_output = NULL;
+ intel_output->output_id = -1;
+
+ changed = TRUE;
+ if (mode->delete_dp_12_displays) {
+ ErrorF("destroying id %d\n", intel_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;
+
+ for (j = 0; j < config->num_output; j++) {
+ xf86OutputPtr output = config->output[j];
+ struct intel_output *intel_output;
+
+ intel_output = output->driver_private;
+ if (mode_res->connectors[i] == intel_output->output_id) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ changed = TRUE;
+ ErrorF("adding id %d\n", mode_res->connectors[i]);
+ intel_output_init(scrn, intel->modes, mode_res, i, 1);
+
+ }
+
+ if (changed) {
+ RRSetChanged(xf86ScrnToScreen(scrn));
+ RRTellChanged(xf86ScrnToScreen(scrn));
+ }
+
+ drmModeFreeResources(mode_res);
+out:
+ RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
+}
@@ -779,7 +779,9 @@ I830HandleUEvents(int fd, void *closure)
if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
hotplug && atoi(hotplug) == 1)
- RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
+ {
+ intel_mode_hotplug(intel);
+ }
udev_device_unref(dev);
}