From: Dave Airlie <[email protected]>

This adds MST support to the UXA paths in the driver.

Signed-off-by: Dave Airlie <[email protected]>
---
 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
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to