diff mbox

[v5,20/23] modetest: Support pipes with multiple connectors

Message ID 1371244894-27878-21-git-send-email-laurent.pinchart@ideasonboard.com (mailing list archive)
State New, archived
Headers show

Commit Message

Laurent Pinchart June 14, 2013, 9:21 p.m. UTC
The -s argument can now take a list of connectors. Configure all of them
in cloned mode using a single CRTC.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/modetest/modetest.c | 211 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 157 insertions(+), 54 deletions(-)
diff mbox

Patch

diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 6be8c75..945ba84 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -40,6 +40,7 @@ 
 #include "config.h"
 
 #include <assert.h>
+#include <ctype.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -634,6 +635,34 @@  error:
 	return NULL;
 }
 
+static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id)
+{
+	drmModeConnector *connector;
+	int i;
+
+	for (i = 0; i < dev->resources->res->count_connectors; i++) {
+		connector = dev->resources->connectors[i].connector;
+		if (connector && connector->connector_id == id)
+			return connector;
+	}
+
+	return NULL;
+}
+
+static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id)
+{
+	drmModeEncoder *encoder;
+	int i;
+
+	for (i = 0; i < dev->resources->res->count_encoders; i++) {
+		encoder = dev->resources->encoders[i].encoder;
+		if (encoder && encoder->encoder_id == id)
+			return encoder;
+	}
+
+	return NULL;
+}
+
 /* -----------------------------------------------------------------------------
  * Pipes and planes
  */
@@ -646,7 +675,8 @@  error:
  * can bind it with a free crtc.
  */
 struct pipe_arg {
-	uint32_t con_id;
+	uint32_t *con_ids;
+	unsigned int num_cons;
 	uint32_t crtc_id;
 	char mode_str[64];
 	char format_str[5];
@@ -669,69 +699,114 @@  struct plane_arg {
 	unsigned int fourcc;
 };
 
-static void pipe_find_mode(struct device *dev, struct pipe_arg *pipe)
+static drmModeModeInfo *
+connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str)
 {
 	drmModeConnector *connector;
-	drmModeEncoder *encoder;
-	int i, j;
+	drmModeModeInfo *mode;
+	int i;
 
-	/* First, find the connector & mode */
-	pipe->mode = NULL;
-	for (i = 0; i < dev->resources->res->count_connectors; i++) {
-		connector = dev->resources->connectors[i].connector;
+	connector = get_connector_by_id(dev, con_id);
+	if (!connector || !connector->count_modes)
+		return NULL;
+
+	for (i = 0; i < connector->count_modes; i++) {
+		mode = &connector->modes[i];
+		if (!strcmp(mode->name, mode_str))
+			return mode;
+	}
+
+	return NULL;
+}
+
+static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe)
+{
+	uint32_t possible_crtcs = ~0;
+	uint32_t active_crtcs = 0;
+	unsigned int crtc_idx;
+	unsigned int i;
+	int j;
+
+	for (i = 0; i < pipe->num_cons; ++i) {
+		drmModeConnector *connector;
+		drmModeEncoder *encoder;
+
+		connector = get_connector_by_id(dev, pipe->con_ids[i]);
 		if (!connector)
-			continue;
+			return NULL;
 
-		if (!connector->count_modes)
-			continue;
+		encoder = get_encoder_by_id(dev, connector->encoder_id);
+		if (!encoder)
+			return NULL;
 
-		if (connector->connector_id != pipe->con_id)
-			continue;
+		possible_crtcs &= encoder->possible_crtcs;
 
-		for (j = 0; j < connector->count_modes; j++) {
-			pipe->mode = &connector->modes[j];
-			if (!strcmp(pipe->mode->name, pipe->mode_str))
+		for (j = 0; j < dev->resources->res->count_crtcs; ++j) {
+			drmModeCrtc *crtc = dev->resources->crtcs[j].crtc;
+			if (crtc && crtc->crtc_id == encoder->crtc_id) {
+				active_crtcs |= 1 << j;
 				break;
+			}
 		}
-
-		/* Found it, break out */
-		if (pipe->mode)
-			break;
 	}
 
-	if (!pipe->mode) {
-		fprintf(stderr, "failed to find mode \"%s\"\n", pipe->mode_str);
-		return;
+	if (!possible_crtcs)
+		return NULL;
+
+	/* Return the first possible and active CRTC if one exists, or the first
+	 * possible CRTC otherwise.
+	 */
+	if (possible_crtcs & active_crtcs)
+		crtc_idx = ffs(possible_crtcs & active_crtcs);
+	else
+		crtc_idx = ffs(possible_crtcs);
+
+	return &dev->resources->crtcs[crtc_idx - 1];
+}
+
+static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe)
+{
+	drmModeModeInfo *mode;
+	int i;
+
+	pipe->mode = NULL;
+
+	for (i = 0; i < (int)pipe->num_cons; i++) {
+		mode = connector_find_mode(dev, pipe->con_ids[i],
+					   pipe->mode_str);
+		if (mode == NULL) {
+			fprintf(stderr,
+				"failed to find mode \"%s\" for connector %u\n",
+				pipe->mode_str, pipe->con_ids[i]);
+			return -EINVAL;
+		}
 	}
 
 	/* If the CRTC ID was specified, get the corresponding CRTC. Otherwise
-	 * locate a CRTC that can be attached to the connector.
+	 * locate a CRTC that can be attached to all the connectors.
 	 */
-	if (pipe->crtc_id == (uint32_t)-1) {
-		for (i = 0; i < dev->resources->res->count_encoders; i++) {
-			encoder = dev->resources->encoders[i].encoder;
-			if (!encoder)
-				continue;
-
-			if (encoder->encoder_id  == connector->encoder_id) {
-				pipe->crtc_id = encoder->crtc_id;
+	if (pipe->crtc_id != (uint32_t)-1) {
+		for (i = 0; i < dev->resources->res->count_crtcs; i++) {
+			struct crtc *crtc = &dev->resources->crtcs[i];
+
+			if (pipe->crtc_id == crtc->crtc->crtc_id) {
+				pipe->crtc = crtc;
 				break;
 			}
 		}
+	} else {
+		pipe->crtc = pipe_find_crtc(dev, pipe);
 	}
 
-	if (pipe->crtc_id == (uint32_t)-1)
-		return;
+	if (!pipe->crtc) {
+		fprintf(stderr, "failed to find CRTC for pipe\n");
+		return -EINVAL;
+	}
 
-	for (i = 0; i < dev->resources->res->count_crtcs; i++) {
-		struct crtc *crtc = &dev->resources->crtcs[i];
+	pipe->mode = mode;
+	pipe->crtc->mode = mode;
 
-		if (pipe->crtc_id == crtc->crtc->crtc_id) {
-			crtc->mode = pipe->mode;
-			pipe->crtc = crtc;
-			break;
-		}
-	}
+	return 0;
 }
 
 /* -----------------------------------------------------------------------------
@@ -826,7 +901,7 @@  page_flip_handler(int fd, unsigned int frame,
 	else
 		new_fb_id = pipe->fb_id[0];
 
-	drmModePageFlip(fd, pipe->crtc_id, new_fb_id,
+	drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id,
 			DRM_MODE_PAGE_FLIP_EVENT, pipe);
 	pipe->current_fb_id = new_fb_id;
 	pipe->swap_count++;
@@ -929,6 +1004,7 @@  static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
 	unsigned int fb_id;
 	struct kms_bo *bo;
 	unsigned int i;
+	unsigned int j;
 	int ret, x;
 
 	dev->mode.width = 0;
@@ -937,9 +1013,10 @@  static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
 	for (i = 0; i < count; i++) {
 		struct pipe_arg *pipe = &pipes[i];
 
-		pipe_find_mode(dev, pipe);
-		if (pipe->mode == NULL)
+		ret = pipe_find_crtc_and_mode(dev, pipe);
+		if (ret < 0)
 			continue;
+
 		dev->mode.width += pipe->mode->hdisplay;
 		if (dev->mode.height < pipe->mode->vdisplay)
 			dev->mode.height = pipe->mode->vdisplay;
@@ -966,12 +1043,15 @@  static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
 		if (pipe->mode == NULL)
 			continue;
 
-		printf("setting mode %s@%s on connector %d, crtc %d\n",
-		       pipe->mode_str, pipe->format_str, pipe->con_id,
-		       pipe->crtc_id);
+		printf("setting mode %s@%s on connectors ",
+		       pipe->mode_str, pipe->format_str);
+		for (j = 0; j < pipe->num_cons; ++j)
+			printf("%u, ", pipe->con_ids[j]);
+		printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
 
-		ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, fb_id, x, 0,
-				     &pipe->con_id, 1, pipe->mode);
+		ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id,
+				     x, 0, pipe->con_ids, pipe->num_cons,
+				     pipe->mode);
 
 		/* XXX: Actually check if this is needed */
 		drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
@@ -1027,8 +1107,9 @@  static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned
 		if (pipe->mode == NULL)
 			continue;
 
-		ret = drmModePageFlip(dev->fd, pipe->crtc_id, other_fb_id,
-				      DRM_MODE_PAGE_FLIP_EVENT, pipe);
+		ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id,
+				      other_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
+				      pipe);
 		if (ret) {
 			fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
 			return;
@@ -1091,13 +1172,35 @@  static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned
 static int parse_connector(struct pipe_arg *pipe, const char *arg)
 {
 	unsigned int len;
+	unsigned int i;
 	const char *p;
 	char *endp;
 
 	pipe->crtc_id = (uint32_t)-1;
 	strcpy(pipe->format_str, "XR24");
 
-	pipe->con_id = strtoul(arg, &endp, 10);
+	/* Count the number of connectors and allocate them. */
+	pipe->num_cons = 1;
+	for (p = arg; isdigit(*p) || *p == ','; ++p) {
+		if (*p == ',')
+			pipe->num_cons++;
+	}
+
+	pipe->con_ids = malloc(pipe->num_cons * sizeof *pipe->con_ids);
+	if (pipe->con_ids == NULL)
+		return -1;
+
+	/* Parse the connectors. */
+	for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) {
+		pipe->con_ids[i] = strtoul(p, &endp, 10);
+		if (*endp != ',')
+			break;
+	}
+
+	if (i != pipe->num_cons - 1)
+		return -1;
+
+	/* Parse the remaining parameters. */
 	if (*endp == '@') {
 		arg = endp + 1;
 		pipe->crtc_id = strtoul(arg, &endp, 10);
@@ -1195,7 +1298,7 @@  static void usage(char *name)
 
 	fprintf(stderr, "\n Test options:\n\n");
 	fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][@<format>]\tset a plane\n");
-	fprintf(stderr, "\t-s <connector_id>[@<crtc_id>]:<mode>[@<format>]\tset a mode\n");
+	fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[@<format>]\tset a mode\n");
 	fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
 	fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");