From: Dave Airlie <airlied@xxxxxxxxxx> This adds MST support to the UXA paths in the driver. Signed-off-by: Dave Airlie <airlied@xxxxxxxxxx> --- src/uxa/intel.h | 1 + src/uxa/intel_display.c | 345 +++++++++++++++++++++++++++++++++++++++--------- src/uxa/intel_driver.c | 4 +- 3 files changed, 289 insertions(+), 61 deletions(-) diff --git a/src/uxa/intel.h b/src/uxa/intel.h index 409635d..eebe08f 100644 --- a/src/uxa/intel.h +++ b/src/uxa/intel.h @@ -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, diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c index 7cdb85f..a3c41f8 100644 --- a/src/uxa/intel_display.c +++ b/src/uxa/intel_display.c @@ -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); +} diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c index a7ca906..7877eb5 100644 --- a/src/uxa/intel_driver.c +++ b/src/uxa/intel_driver.c @@ -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); } -- 1.9.3 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx