diff options
-rw-r--r-- | src/intel_display.c | 57 | ||||
-rw-r--r-- | src/sna/sna_display.c | 32 |
2 files changed, 88 insertions, 1 deletions
diff --git a/src/intel_display.c b/src/intel_display.c index b2a5904f..d58e6e0b 100644 --- a/src/intel_display.c +++ b/src/intel_display.c @@ -1435,7 +1435,6 @@ intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num) intel_output_backlight_init(output); output->possible_crtcs = kencoder->possible_crtcs; - output->possible_clones = kencoder->possible_clones; output->interlaceAllowed = TRUE; intel_output->output = output; @@ -1680,6 +1679,60 @@ drm_wakeup_handler(pointer data, int err, pointer p) drmHandleEvent(mode->fd, &mode->event_context); } +static drmModeEncoderPtr +intel_get_kencoder(struct intel_mode *mode, int num) +{ + struct intel_output *iterator; + int id = mode->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) +{ + 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; + + for (i = 0; i < config->num_output; i++) { + possible_clones = 0; + intel_output = config->output[i]->driver_private; + + mask = intel_output->mode_encoder->possible_clones; + for (j = 0; mask != 0; j++, mask >>= 1) { + + if ((mask & 1) == 0) + continue; + + cloned_encoder = intel_get_kencoder(mode, j); + if (!cloned_encoder) + continue; + + 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); + } + } + + config->output[i]->possible_clones = possible_clones; + } +} + Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp) { intel_screen_private *intel = intel_get_screen_private(scrn); @@ -1716,6 +1769,8 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp) for (i = 0; i < mode->mode_res->count_connectors; i++) intel_output_init(scrn, mode, i); + intel_compute_possible_clones(scrn, mode); + #ifdef INTEL_PIXMAP_SHARING xf86ProviderSetup(scrn, NULL, "Intel"); #endif diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index fc5cbfc5..ed323755 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -2291,6 +2291,35 @@ cleanup_connector: drmModeFreeConnector(koutput); } +/* The kernel reports possible encoder clones, whereas X uses a list of + * possible connector clones. This is works when we have a 1:1 mapping + * between encoders and connectors, but breaks for Haswell which has a pair + * of DP/HDMI connectors hanging off a single encoder. + */ +static void +sna_mode_compute_possible_clones(ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + unsigned clones[32] = { 0 }; + int i, j; + + assert(config->num_output <= 32); + + /* Convert from encoder numbering to output numbering */ + for (i = 0; i < config->num_output; i++) { + unsigned mask = config->output[i]->possible_clones; + for (j = 0; mask != 0; j++, mask >>= 1) { + if ((mask & 1) == 0) + continue; + + clones[j] |= 1 << i; + } + } + + for (i = 0; i < config->num_output; i++) + config->output[i]->possible_clones = clones[i]; +} + struct sna_visit_set_pixmap_window { PixmapPtr old, new; }; @@ -2574,6 +2603,9 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna) for (i = 0; i < mode->kmode->count_connectors; i++) sna_output_init(scrn, mode, i); + if (!xf86IsEntityShared(scrn->entityList[0])) + sna_mode_compute_possible_clones(scrn); + #if HAS_PIXMAP_SHARING xf86ProviderSetup(scrn, NULL, "Intel"); #endif |