All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dave Airlie <airlied@gmail.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH 2/2] intel/uxa: add MST support.
Date: Wed,  3 Sep 2014 10:43:21 +1000	[thread overview]
Message-ID: <1409705001-972-2-git-send-email-airlied@gmail.com> (raw)
In-Reply-To: <1409705001-972-1-git-send-email-airlied@gmail.com>

From: Dave Airlie <airlied@redhat.com>

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

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 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

  reply	other threads:[~2014-09-03  0:43 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-03  0:43 [PATCH 1/2] intel/uxa/display: drop mode_res caching Dave Airlie
2014-09-03  0:43 ` Dave Airlie [this message]
2014-09-03  7:28   ` [PATCH 2/2] intel/uxa: add MST support Chris Wilson
2014-09-07 17:48   ` Chris Wilson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1409705001-972-2-git-send-email-airlied@gmail.com \
    --to=airlied@gmail.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.