diff mbox

[igt,3/5] lib: add kmstest_get_connector_config

Message ID 1369992192-957-3-git-send-email-imre.deak@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Imre Deak May 31, 2013, 9:23 a.m. UTC
This is used by multiple test cases, so make it shared.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 lib/drmtest.c       | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/drmtest.h       |  14 ++++++
 tests/kms_flip.c    | 115 ++++++++------------------------------------
 tests/testdisplay.c | 134 +++++++++++++++-------------------------------------
 4 files changed, 206 insertions(+), 191 deletions(-)

Comments

Rodrigo Vivi June 5, 2013, 6 p.m. UTC | #1
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>

On Fri, May 31, 2013 at 6:23 AM, Imre Deak <imre.deak@intel.com> wrote:
> This is used by multiple test cases, so make it shared.
>
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  lib/drmtest.c       | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/drmtest.h       |  14 ++++++
>  tests/kms_flip.c    | 115 ++++++++------------------------------------
>  tests/testdisplay.c | 134 +++++++++++++++-------------------------------------
>  4 files changed, 206 insertions(+), 191 deletions(-)
>
> diff --git a/lib/drmtest.c b/lib/drmtest.c
> index 3ad77a8..7368077 100644
> --- a/lib/drmtest.c
> +++ b/lib/drmtest.c
> @@ -1317,3 +1317,137 @@ int drmtest_set_vt_graphics_mode(void)
>         return orig_vt_mode < 0 ? -1 : 0;
>  }
>
> +static int get_connector_default_mode(int drm_fd, drmModeConnector *connector,
> +                                     drmModeModeInfo *mode)
> +{
> +       drmModeRes *resources;
> +       int i;
> +
> +       resources = drmModeGetResources(drm_fd);
> +       if (!resources) {
> +               perror("drmModeGetResources failed");
> +
> +               return -1;
> +       }
> +
> +       if (!connector->count_modes) {
> +               fprintf(stderr, "no modes for connector %d\n",
> +                       connector->connector_id);
> +               drmModeFreeResources(resources);
> +
> +               return -1;
> +       }
> +
> +       for (i = 0; i < connector->count_modes; i++) {
> +               if (i == 0 ||
> +                   connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
> +                       *mode = connector->modes[i];
> +                       if (mode->type & DRM_MODE_TYPE_PREFERRED)
> +                               break;
> +               }
> +       }
> +
> +       drmModeFreeResources(resources);
> +
> +       return 0;
> +}
> +
> +int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
> +                                unsigned long crtc_idx_mask,
> +                                struct kmstest_connector_config *config)
> +{
> +       drmModeRes *resources;
> +       drmModeConnector *connector;
> +       drmModeEncoder *encoder;
> +       int i, j;
> +
> +       resources = drmModeGetResources(drm_fd);
> +       if (!resources) {
> +               perror("drmModeGetResources failed");
> +               goto err1;
> +       }
> +
> +       /* First, find the connector & mode */
> +       connector = drmModeGetConnector(drm_fd, connector_id);
> +       if (!connector)
> +               goto err2;
> +
> +       if (connector->connection != DRM_MODE_CONNECTED)
> +               goto err3;
> +
> +       if (!connector->count_modes) {
> +               fprintf(stderr, "connector %d has no modes\n", connector_id);
> +               goto err3;
> +       }
> +
> +       if (connector->connector_id != connector_id) {
> +               fprintf(stderr, "connector id doesn't match (%d != %d)\n",
> +                       connector->connector_id, connector_id);
> +               goto err3;
> +       }
> +
> +       /*
> +        * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
> +        * In both cases find the first compatible encoder and skip the CRTC
> +        * if there is non such.
> +        */
> +       encoder = NULL;         /* suppress GCC warning */
> +       for (i = 0; i < resources->count_crtcs; i++) {
> +               if (!resources->crtcs[i] || !(crtc_idx_mask & (1 << i)))
> +                       continue;
> +
> +               /* Now get a compatible encoder */
> +               for (j = 0; j < connector->count_encoders; j++) {
> +                       encoder = drmModeGetEncoder(drm_fd,
> +                                                   connector->encoders[j]);
> +
> +                       if (!encoder) {
> +                               fprintf(stderr, "could not get encoder %d: %s\n",
> +                                       resources->encoders[j], strerror(errno));
> +
> +                               continue;
> +                       }
> +
> +                       if (encoder->possible_crtcs & (1 << i))
> +                               goto found;
> +
> +                       drmModeFreeEncoder(encoder);
> +               }
> +       }
> +
> +       fprintf(stderr,
> +               "no crtc with a compatible encoder (crtc_idx_mask %08lx)\n",
> +               crtc_idx_mask);
> +       goto err3;
> +
> +found:
> +       if (get_connector_default_mode(drm_fd, connector,
> +                                      &config->default_mode) < 0)
> +               goto err4;
> +
> +       config->connector = connector;
> +       config->encoder = encoder;
> +       config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]);
> +       config->crtc_idx = i;
> +       config->pipe = kmstest_get_pipe_from_crtc_id(drm_fd,
> +                                                    config->crtc->crtc_id);
> +
> +       drmModeFreeResources(resources);
> +
> +       return 0;
> +err4:
> +       drmModeFreeEncoder(encoder);
> +err3:
> +       drmModeFreeConnector(connector);
> +err2:
> +       drmModeFreeResources(resources);
> +err1:
> +       return -1;
> +}
> +
> +void kmstest_free_connector_config(struct kmstest_connector_config *config)
> +{
> +       drmModeFreeCrtc(config->crtc);
> +       drmModeFreeEncoder(config->encoder);
> +       drmModeFreeConnector(config->connector);
> +}
> diff --git a/lib/drmtest.h b/lib/drmtest.h
> index 3c1368d..89ded11 100644
> --- a/lib/drmtest.h
> +++ b/lib/drmtest.h
> @@ -101,6 +101,20 @@ void drmtest_init_aperture_trashers(drm_intel_bufmgr *bufmgr);
>  void drmtest_trash_aperture(void);
>  void drmtest_cleanup_aperture_trashers(void);
>
> +struct kmstest_connector_config {
> +       drmModeCrtc *crtc;
> +       drmModeConnector *connector;
> +       drmModeEncoder *encoder;
> +       drmModeModeInfo default_mode;
> +       int crtc_idx;
> +       int pipe;
> +};
> +
> +int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
> +                                unsigned long crtc_idx_mask,
> +                                struct kmstest_connector_config *config);
> +void kmstest_free_connector_config(struct kmstest_connector_config *config);
> +
>  /* helpers to create nice-looking framebuffers */
>  struct kmstest_fb {
>         uint32_t fb_id;
> diff --git a/tests/kms_flip.c b/tests/kms_flip.c
> index 735b4dd..c9b3d8a 100644
> --- a/tests/kms_flip.c
> +++ b/tests/kms_flip.c
> @@ -825,97 +825,23 @@ static void update_all_state(struct test_output *o,
>                 update_state(&o->vblank_state);
>  }
>
> -static void connector_find_preferred_mode(struct test_output *o, int crtc_id)
> +static void connector_find_preferred_mode(uint32_t connector_id, int crtc_idx,
> +                                         struct test_output *o)
>  {
> -       drmModeConnector *connector;
> -       drmModeEncoder *encoder = NULL;
> -       int i, j;
> -
> -       /* First, find the connector & mode */
> -       o->mode_valid = 0;
> -       o->crtc = 0;
> -       connector = drmModeGetConnector(drm_fd, o->id);
> -       assert(connector);
> -
> -       if (connector->connection != DRM_MODE_CONNECTED) {
> -               drmModeFreeConnector(connector);
> -               return;
> -       }
> -
> -       if (!connector->count_modes) {
> -               fprintf(stderr, "connector %d has no modes\n", o->id);
> -               drmModeFreeConnector(connector);
> -               return;
> -       }
> -
> -       if (connector->connector_id != o->id) {
> -               fprintf(stderr, "connector id doesn't match (%d != %d)\n",
> -                       connector->connector_id, o->id);
> -               drmModeFreeConnector(connector);
> -               return;
> -       }
> -
> -       for (j = 0; j < connector->count_modes; j++) {
> -               o->mode = connector->modes[j];
> -               if (o->mode.type & DRM_MODE_TYPE_PREFERRED) {
> -                       o->mode_valid = 1;
> -                       break;
> -               }
> -       }
> -
> -       if (!o->mode_valid) {
> -               if (connector->count_modes > 0) {
> -                       /* use the first mode as test mode */
> -                       o->mode = connector->modes[0];
> -                       o->mode_valid = 1;
> -               }
> -               else {
> -                       fprintf(stderr, "failed to find any modes on connector %d\n",
> -                               o->id);
> -                       return;
> -               }
> -       }
> +       struct kmstest_connector_config config;
>
> -       /* Now get the encoder */
> -       for (i = 0; i < connector->count_encoders; i++) {
> -               encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
> -
> -               if (!encoder) {
> -                       fprintf(stderr, "could not get encoder %i: %s\n",
> -                               resources->encoders[i], strerror(errno));
> -                       drmModeFreeEncoder(encoder);
> -                       continue;
> -               }
> -
> -               break;
> -       }
> -
> -       o->encoder = encoder;
> -
> -       if (i == resources->count_encoders) {
> -               fprintf(stderr, "failed to find encoder\n");
> -               o->mode_valid = 0;
> -               return;
> -       }
> -
> -       /* Find first CRTC not in use */
> -       for (i = 0; i < resources->count_crtcs; i++) {
> -               if (resources->crtcs[i] != crtc_id)
> -                       continue;
> -               if (resources->crtcs[i] &&
> -                   (o->encoder->possible_crtcs & (1<<i))) {
> -                       o->crtc = resources->crtcs[i];
> -                       break;
> -               }
> -       }
> -
> -       if (!o->crtc) {
> -               fprintf(stderr, "could not find requested crtc %d\n", crtc_id);
> +       if (kmstest_get_connector_config(drm_fd, connector_id, 1 << crtc_idx,
> +                                        &config) < 0) {
>                 o->mode_valid = 0;
>                 return;
>         }
>
> -       o->connector = connector;
> +       o->connector = config.connector;
> +       o->encoder = config.encoder;
> +       o->crtc = config.crtc->crtc_id;
> +       o->pipe = config.pipe;
> +       o->mode = config.default_mode;
> +       o->mode_valid = 1;
>  }
>
>  static void
> @@ -1042,21 +968,21 @@ static unsigned event_loop(struct test_output *o, unsigned duration_sec)
>         return end - start;
>  }
>
> -static void run_test_on_crtc(struct test_output *o, int crtc, int duration)
> +static void run_test_on_crtc(struct test_output *o, int crtc_idx, int duration)
>  {
>         unsigned ellapsed;
>
>         o->bpp = 32;
>         o->depth = 24;
>
> -       connector_find_preferred_mode(o, crtc);
> +       connector_find_preferred_mode(o->id, crtc_idx, o);
>         if (!o->mode_valid)
>                 return;
>
>         last_connector = o->connector;
>
>         fprintf(stdout, "Beginning %s on crtc %d, connector %d\n",
> -               o->test_name, crtc, o->id);
> +               o->test_name, o->crtc, o->id);
>
>         o->fb_width = o->mode.hdisplay;
>         o->fb_height = o->mode.vdisplay;
> @@ -1116,7 +1042,7 @@ static void run_test_on_crtc(struct test_output *o, int crtc, int duration)
>                 check_final_state(o, &o->vblank_state, ellapsed);
>
>         fprintf(stdout, "\n%s on crtc %d, connector %d: PASSED\n\n",
> -               o->test_name, crtc, o->id);
> +               o->test_name, o->crtc, o->id);
>
>         kmstest_remove_fb(drm_fd, o->fb_ids[2]);
>         kmstest_remove_fb(drm_fd, o->fb_ids[1]);
> @@ -1131,7 +1057,8 @@ static void run_test_on_crtc(struct test_output *o, int crtc, int duration)
>  static int run_test(int duration, int flags, const char *test_name)
>  {
>         struct test_output o;
> -       int c, i;
> +       int c;
> +       int crtc_idx;
>
>         resources = drmModeGetResources(drm_fd);
>         if (!resources) {
> @@ -1142,19 +1069,15 @@ static int run_test(int duration, int flags, const char *test_name)
>
>         /* Find any connected displays */
>         for (c = 0; c < resources->count_connectors; c++) {
> -               for (i = 0; i < resources->count_crtcs; i++) {
> -                       int crtc;
> -
> +               for (crtc_idx = 0; crtc_idx < resources->count_crtcs; crtc_idx++) {
>                         memset(&o, 0, sizeof(o));
>                         o.test_name = test_name;
>                         o.id = resources->connectors[c];
>                         o.flags = flags;
>                         o.flip_state.name = "flip";
>                         o.vblank_state.name = "vblank";
> -                       crtc = resources->crtcs[i];
> -                       o.pipe = kmstest_get_pipe_from_crtc_id(drm_fd, crtc);
>
> -                       run_test_on_crtc(&o, crtc, duration);
> +                       run_test_on_crtc(&o, crtc_idx, duration);
>                 }
>         }
>
> diff --git a/tests/testdisplay.c b/tests/testdisplay.c
> index b10c3b9..4470339 100644
> --- a/tests/testdisplay.c
> +++ b/tests/testdisplay.c
> @@ -102,6 +102,7 @@ struct connector {
>         drmModeEncoder *encoder;
>         drmModeConnector *connector;
>         int crtc;
> +       int crtc_idx;
>         int pipe;
>  };
>
> @@ -185,101 +186,31 @@ static void dump_crtcs_fd(int drmfd)
>         drmModeFreeResources(mode_resources);
>  }
>
> -static void connector_find_preferred_mode(struct connector *c)
> +static void connector_find_preferred_mode(uint32_t connector_id,
> +                                         unsigned long crtc_idx_mask,
> +                                         int mode_num, struct connector *c)
>  {
> -       drmModeConnector *connector;
> -       drmModeEncoder *encoder = NULL;
> -       int i, j;
> -
> -       /* First, find the connector & mode */
> -       c->mode_valid = 0;
> -       connector = drmModeGetConnector(drm_fd, c->id);
> -       if (!connector) {
> -               fprintf(stderr, "could not get connector %d: %s\n",
> -                       c->id, strerror(errno));
> -               drmModeFreeConnector(connector);
> -               return;
> -       }
> -
> -       if (connector->connection != DRM_MODE_CONNECTED) {
> -               drmModeFreeConnector(connector);
> -               return;
> -       }
> -
> -       if (!connector->count_modes) {
> -               fprintf(stderr, "connector %d has no modes\n", c->id);
> -               drmModeFreeConnector(connector);
> -               return;
> -       }
> -
> -       if (connector->connector_id != c->id) {
> -               fprintf(stderr, "connector id doesn't match (%d != %d)\n",
> -                       connector->connector_id, c->id);
> -               drmModeFreeConnector(connector);
> -               return;
> -       }
> -
> -       for (j = 0; j < connector->count_modes; j++) {
> -               c->mode = connector->modes[j];
> -               if (c->mode.type & DRM_MODE_TYPE_PREFERRED) {
> -                       c->mode_valid = 1;
> -                       break;
> -               }
> -       }
> -
> -       if ( specified_mode_num != -1 ){
> -               c->mode = connector->modes[specified_mode_num];
> -               if (c->mode.type & DRM_MODE_TYPE_PREFERRED)
> -                       c->mode_valid = 1;
> -       }
> -
> -       if (!c->mode_valid) {
> -               if (connector->count_modes > 0) {
> -                       /* use the first mode as test mode */
> -                       c->mode = connector->modes[0];
> -                       c->mode_valid = 1;
> -               }
> -               else {
> -                       fprintf(stderr, "failed to find any modes on connector %d\n",
> -                               c->id);
> -                       return;
> -               }
> -       }
> -
> -       /* Now get the encoder */
> -       for (i = 0; i < connector->count_encoders; i++) {
> -               encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
> -
> -               if (!encoder) {
> -                       fprintf(stderr, "could not get encoder %i: %s\n",
> -                               resources->encoders[i], strerror(errno));
> -                       drmModeFreeEncoder(encoder);
> -                       continue;
> -               }
> -
> -               break;
> -       }
> -
> -       c->encoder = encoder;
> +       struct kmstest_connector_config config;
>
> -       if (i == resources->count_encoders) {
> -               fprintf(stderr, "failed to find encoder\n");
> +       if (kmstest_get_connector_config(drm_fd, connector_id, crtc_idx_mask,
> +                                        &config) < 0) {
>                 c->mode_valid = 0;
>                 return;
>         }
>
> -       /* Find first CRTC not in use */
> -       for (i = 0; i < resources->count_crtcs; i++) {
> -               if (resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i)))
> -                       break;
> +       c->connector = config.connector;
> +       c->encoder = config.encoder;
> +       c->crtc = config.crtc->crtc_id;
> +       c->crtc_idx = config.crtc_idx;
> +       c->pipe = config.pipe;
> +
> +       if (mode_num != -1) {
> +               assert(mode_num < config.connector->count_modes);
> +               c->mode = config.connector->modes[mode_num];
> +       } else {
> +               c->mode = config.default_mode;
>         }
> -       c->crtc = resources->crtcs[i];
> -       c->pipe = i;
> -
> -       if(test_preferred_mode || force_mode || specified_mode_num != -1)
> -               resources->crtcs[i] = 0;
> -
> -       c->connector = connector;
> +       c->mode_valid = 1;
>  }
>
>  static void
> @@ -409,10 +340,6 @@ set_mode(struct connector *c)
>         else if (depth > 16 && depth <= 32)
>                 bpp = 32;
>
> -       connector_find_preferred_mode(c);
> -       if (!c->mode_valid)
> -               return;
> -
>         test_mode_num = 1;
>         if (force_mode){
>                 memcpy( &c->mode, &force_timing, sizeof(force_timing));
> @@ -506,13 +433,30 @@ int update_display(void)
>         }
>
>         if (test_preferred_mode || test_all_modes || force_mode || specified_disp_id != -1) {
> +               unsigned long crtc_idx_mask = -1UL;
> +
>                 /* Find any connected displays */
>                 for (c = 0; c < resources->count_connectors; c++) {
> -                       connectors[c].id = resources->connectors[c];
> -                       if ( specified_disp_id != -1 && connectors[c].id != specified_disp_id )
> +                       struct connector *connector = &connectors[c];
> +
> +                       connector->id = resources->connectors[c];
> +                       if (specified_disp_id != -1 &&
> +                           connector->id != specified_disp_id)
> +                               continue;
> +
> +                       connector_find_preferred_mode(connector->id,
> +                                                     crtc_idx_mask,
> +                                                     specified_mode_num,
> +                                                     connector);
> +                       if (!connector->mode_valid)
>                                 continue;
>
> -                       set_mode(&connectors[c]);
> +                       set_mode(connector);
> +
> +                       if (test_preferred_mode || force_mode ||
> +                           specified_mode_num != -1)
> +                               crtc_idx_mask &= ~(1 << connector->crtc_idx);
> +
>                 }
>         }
>         drmModeFreeResources(resources);
> --
> 1.8.1.2
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff mbox

Patch

diff --git a/lib/drmtest.c b/lib/drmtest.c
index 3ad77a8..7368077 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -1317,3 +1317,137 @@  int drmtest_set_vt_graphics_mode(void)
 	return orig_vt_mode < 0 ? -1 : 0;
 }
 
+static int get_connector_default_mode(int drm_fd, drmModeConnector *connector,
+				      drmModeModeInfo *mode)
+{
+	drmModeRes *resources;
+	int i;
+
+	resources = drmModeGetResources(drm_fd);
+	if (!resources) {
+		perror("drmModeGetResources failed");
+
+		return -1;
+	}
+
+	if (!connector->count_modes) {
+		fprintf(stderr, "no modes for connector %d\n",
+			connector->connector_id);
+		drmModeFreeResources(resources);
+
+		return -1;
+	}
+
+	for (i = 0; i < connector->count_modes; i++) {
+		if (i == 0 ||
+		    connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
+			*mode = connector->modes[i];
+			if (mode->type & DRM_MODE_TYPE_PREFERRED)
+				break;
+		}
+	}
+
+	drmModeFreeResources(resources);
+
+	return 0;
+}
+
+int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
+				 unsigned long crtc_idx_mask,
+				 struct kmstest_connector_config *config)
+{
+	drmModeRes *resources;
+	drmModeConnector *connector;
+	drmModeEncoder *encoder;
+	int i, j;
+
+	resources = drmModeGetResources(drm_fd);
+	if (!resources) {
+		perror("drmModeGetResources failed");
+		goto err1;
+	}
+
+	/* First, find the connector & mode */
+	connector = drmModeGetConnector(drm_fd, connector_id);
+	if (!connector)
+		goto err2;
+
+	if (connector->connection != DRM_MODE_CONNECTED)
+		goto err3;
+
+	if (!connector->count_modes) {
+		fprintf(stderr, "connector %d has no modes\n", connector_id);
+		goto err3;
+	}
+
+	if (connector->connector_id != connector_id) {
+		fprintf(stderr, "connector id doesn't match (%d != %d)\n",
+			connector->connector_id, connector_id);
+		goto err3;
+	}
+
+	/*
+	 * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
+	 * In both cases find the first compatible encoder and skip the CRTC
+	 * if there is non such.
+	 */
+	encoder = NULL;		/* suppress GCC warning */
+	for (i = 0; i < resources->count_crtcs; i++) {
+		if (!resources->crtcs[i] || !(crtc_idx_mask & (1 << i)))
+			continue;
+
+		/* Now get a compatible encoder */
+		for (j = 0; j < connector->count_encoders; j++) {
+			encoder = drmModeGetEncoder(drm_fd,
+						    connector->encoders[j]);
+
+			if (!encoder) {
+				fprintf(stderr, "could not get encoder %d: %s\n",
+					resources->encoders[j], strerror(errno));
+
+				continue;
+			}
+
+			if (encoder->possible_crtcs & (1 << i))
+				goto found;
+
+			drmModeFreeEncoder(encoder);
+		}
+	}
+
+	fprintf(stderr,
+		"no crtc with a compatible encoder (crtc_idx_mask %08lx)\n",
+		crtc_idx_mask);
+	goto err3;
+
+found:
+	if (get_connector_default_mode(drm_fd, connector,
+				       &config->default_mode) < 0)
+		goto err4;
+
+	config->connector = connector;
+	config->encoder = encoder;
+	config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]);
+	config->crtc_idx = i;
+	config->pipe = kmstest_get_pipe_from_crtc_id(drm_fd,
+						     config->crtc->crtc_id);
+
+	drmModeFreeResources(resources);
+
+	return 0;
+err4:
+	drmModeFreeEncoder(encoder);
+err3:
+	drmModeFreeConnector(connector);
+err2:
+	drmModeFreeResources(resources);
+err1:
+	return -1;
+}
+
+void kmstest_free_connector_config(struct kmstest_connector_config *config)
+{
+	drmModeFreeCrtc(config->crtc);
+	drmModeFreeEncoder(config->encoder);
+	drmModeFreeConnector(config->connector);
+}
diff --git a/lib/drmtest.h b/lib/drmtest.h
index 3c1368d..89ded11 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -101,6 +101,20 @@  void drmtest_init_aperture_trashers(drm_intel_bufmgr *bufmgr);
 void drmtest_trash_aperture(void);
 void drmtest_cleanup_aperture_trashers(void);
 
+struct kmstest_connector_config {
+	drmModeCrtc *crtc;
+	drmModeConnector *connector;
+	drmModeEncoder *encoder;
+	drmModeModeInfo default_mode;
+	int crtc_idx;
+	int pipe;
+};
+
+int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
+				 unsigned long crtc_idx_mask,
+				 struct kmstest_connector_config *config);
+void kmstest_free_connector_config(struct kmstest_connector_config *config);
+
 /* helpers to create nice-looking framebuffers */
 struct kmstest_fb {
 	uint32_t fb_id;
diff --git a/tests/kms_flip.c b/tests/kms_flip.c
index 735b4dd..c9b3d8a 100644
--- a/tests/kms_flip.c
+++ b/tests/kms_flip.c
@@ -825,97 +825,23 @@  static void update_all_state(struct test_output *o,
 		update_state(&o->vblank_state);
 }
 
-static void connector_find_preferred_mode(struct test_output *o, int crtc_id)
+static void connector_find_preferred_mode(uint32_t connector_id, int crtc_idx,
+					  struct test_output *o)
 {
-	drmModeConnector *connector;
-	drmModeEncoder *encoder = NULL;
-	int i, j;
-
-	/* First, find the connector & mode */
-	o->mode_valid = 0;
-	o->crtc = 0;
-	connector = drmModeGetConnector(drm_fd, o->id);
-	assert(connector);
-
-	if (connector->connection != DRM_MODE_CONNECTED) {
-		drmModeFreeConnector(connector);
-		return;
-	}
-
-	if (!connector->count_modes) {
-		fprintf(stderr, "connector %d has no modes\n", o->id);
-		drmModeFreeConnector(connector);
-		return;
-	}
-
-	if (connector->connector_id != o->id) {
-		fprintf(stderr, "connector id doesn't match (%d != %d)\n",
-			connector->connector_id, o->id);
-		drmModeFreeConnector(connector);
-		return;
-	}
-
-	for (j = 0; j < connector->count_modes; j++) {
-		o->mode = connector->modes[j];
-		if (o->mode.type & DRM_MODE_TYPE_PREFERRED) {
-			o->mode_valid = 1;
-			break;
-		}
-	}
-
-	if (!o->mode_valid) {
-		if (connector->count_modes > 0) {
-			/* use the first mode as test mode */
-			o->mode = connector->modes[0];
-			o->mode_valid = 1;
-		}
-		else {
-			fprintf(stderr, "failed to find any modes on connector %d\n",
-				o->id);
-			return;
-		}
-	}
+	struct kmstest_connector_config config;
 
-	/* Now get the encoder */
-	for (i = 0; i < connector->count_encoders; i++) {
-		encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
-
-		if (!encoder) {
-			fprintf(stderr, "could not get encoder %i: %s\n",
-				resources->encoders[i], strerror(errno));
-			drmModeFreeEncoder(encoder);
-			continue;
-		}
-
-		break;
-	}
-
-	o->encoder = encoder;
-
-	if (i == resources->count_encoders) {
-		fprintf(stderr, "failed to find encoder\n");
-		o->mode_valid = 0;
-		return;
-	}
-
-	/* Find first CRTC not in use */
-	for (i = 0; i < resources->count_crtcs; i++) {
-		if (resources->crtcs[i] != crtc_id)
-			continue;
-		if (resources->crtcs[i] &&
-		    (o->encoder->possible_crtcs & (1<<i))) {
-			o->crtc = resources->crtcs[i];
-			break;
-		}
-	}
-
-	if (!o->crtc) {
-		fprintf(stderr, "could not find requested crtc %d\n", crtc_id);
+	if (kmstest_get_connector_config(drm_fd, connector_id, 1 << crtc_idx,
+					 &config) < 0) {
 		o->mode_valid = 0;
 		return;
 	}
 
-	o->connector = connector;
+	o->connector = config.connector;
+	o->encoder = config.encoder;
+	o->crtc = config.crtc->crtc_id;
+	o->pipe = config.pipe;
+	o->mode = config.default_mode;
+	o->mode_valid = 1;
 }
 
 static void
@@ -1042,21 +968,21 @@  static unsigned event_loop(struct test_output *o, unsigned duration_sec)
 	return end - start;
 }
 
-static void run_test_on_crtc(struct test_output *o, int crtc, int duration)
+static void run_test_on_crtc(struct test_output *o, int crtc_idx, int duration)
 {
 	unsigned ellapsed;
 
 	o->bpp = 32;
 	o->depth = 24;
 
-	connector_find_preferred_mode(o, crtc);
+	connector_find_preferred_mode(o->id, crtc_idx, o);
 	if (!o->mode_valid)
 		return;
 
 	last_connector = o->connector;
 
 	fprintf(stdout, "Beginning %s on crtc %d, connector %d\n",
-		o->test_name, crtc, o->id);
+		o->test_name, o->crtc, o->id);
 
 	o->fb_width = o->mode.hdisplay;
 	o->fb_height = o->mode.vdisplay;
@@ -1116,7 +1042,7 @@  static void run_test_on_crtc(struct test_output *o, int crtc, int duration)
 		check_final_state(o, &o->vblank_state, ellapsed);
 
 	fprintf(stdout, "\n%s on crtc %d, connector %d: PASSED\n\n",
-		o->test_name, crtc, o->id);
+		o->test_name, o->crtc, o->id);
 
 	kmstest_remove_fb(drm_fd, o->fb_ids[2]);
 	kmstest_remove_fb(drm_fd, o->fb_ids[1]);
@@ -1131,7 +1057,8 @@  static void run_test_on_crtc(struct test_output *o, int crtc, int duration)
 static int run_test(int duration, int flags, const char *test_name)
 {
 	struct test_output o;
-	int c, i;
+	int c;
+	int crtc_idx;
 
 	resources = drmModeGetResources(drm_fd);
 	if (!resources) {
@@ -1142,19 +1069,15 @@  static int run_test(int duration, int flags, const char *test_name)
 
 	/* Find any connected displays */
 	for (c = 0; c < resources->count_connectors; c++) {
-		for (i = 0; i < resources->count_crtcs; i++) {
-			int crtc;
-
+		for (crtc_idx = 0; crtc_idx < resources->count_crtcs; crtc_idx++) {
 			memset(&o, 0, sizeof(o));
 			o.test_name = test_name;
 			o.id = resources->connectors[c];
 			o.flags = flags;
 			o.flip_state.name = "flip";
 			o.vblank_state.name = "vblank";
-			crtc = resources->crtcs[i];
-			o.pipe = kmstest_get_pipe_from_crtc_id(drm_fd, crtc);
 
-			run_test_on_crtc(&o, crtc, duration);
+			run_test_on_crtc(&o, crtc_idx, duration);
 		}
 	}
 
diff --git a/tests/testdisplay.c b/tests/testdisplay.c
index b10c3b9..4470339 100644
--- a/tests/testdisplay.c
+++ b/tests/testdisplay.c
@@ -102,6 +102,7 @@  struct connector {
 	drmModeEncoder *encoder;
 	drmModeConnector *connector;
 	int crtc;
+	int crtc_idx;
 	int pipe;
 };
 
@@ -185,101 +186,31 @@  static void dump_crtcs_fd(int drmfd)
 	drmModeFreeResources(mode_resources);
 }
 
-static void connector_find_preferred_mode(struct connector *c)
+static void connector_find_preferred_mode(uint32_t connector_id,
+					  unsigned long crtc_idx_mask,
+					  int mode_num, struct connector *c)
 {
-	drmModeConnector *connector;
-	drmModeEncoder *encoder = NULL;
-	int i, j;
-
-	/* First, find the connector & mode */
-	c->mode_valid = 0;
-	connector = drmModeGetConnector(drm_fd, c->id);
-	if (!connector) {
-		fprintf(stderr, "could not get connector %d: %s\n",
-			c->id, strerror(errno));
-		drmModeFreeConnector(connector);
-		return;
-	}
-
-	if (connector->connection != DRM_MODE_CONNECTED) {
-		drmModeFreeConnector(connector);
-		return;
-	}
-
-	if (!connector->count_modes) {
-		fprintf(stderr, "connector %d has no modes\n", c->id);
-		drmModeFreeConnector(connector);
-		return;
-	}
-
-	if (connector->connector_id != c->id) {
-		fprintf(stderr, "connector id doesn't match (%d != %d)\n",
-			connector->connector_id, c->id);
-		drmModeFreeConnector(connector);
-		return;
-	}
-
-	for (j = 0; j < connector->count_modes; j++) {
-		c->mode = connector->modes[j];
-		if (c->mode.type & DRM_MODE_TYPE_PREFERRED) {
-			c->mode_valid = 1;
-			break;
-		}
-	}
-
-	if ( specified_mode_num != -1 ){
-		c->mode = connector->modes[specified_mode_num];
-		if (c->mode.type & DRM_MODE_TYPE_PREFERRED)
-			c->mode_valid = 1;
-	}
-
-	if (!c->mode_valid) {
-		if (connector->count_modes > 0) {
-			/* use the first mode as test mode */
-			c->mode = connector->modes[0];
-			c->mode_valid = 1;
-		}
-		else {
-			fprintf(stderr, "failed to find any modes on connector %d\n",
-				c->id);
-			return;
-		}
-	}
-
-	/* Now get the encoder */
-	for (i = 0; i < connector->count_encoders; i++) {
-		encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
-
-		if (!encoder) {
-			fprintf(stderr, "could not get encoder %i: %s\n",
-				resources->encoders[i], strerror(errno));
-			drmModeFreeEncoder(encoder);
-			continue;
-		}
-
-		break;
-	}
-
-	c->encoder = encoder;
+	struct kmstest_connector_config config;
 
-	if (i == resources->count_encoders) {
-		fprintf(stderr, "failed to find encoder\n");
+	if (kmstest_get_connector_config(drm_fd, connector_id, crtc_idx_mask,
+					 &config) < 0) {
 		c->mode_valid = 0;
 		return;
 	}
 
-	/* Find first CRTC not in use */
-	for (i = 0; i < resources->count_crtcs; i++) {
-		if (resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i)))
-			break;
+	c->connector = config.connector;
+	c->encoder = config.encoder;
+	c->crtc = config.crtc->crtc_id;
+	c->crtc_idx = config.crtc_idx;
+	c->pipe = config.pipe;
+
+	if (mode_num != -1) {
+		assert(mode_num < config.connector->count_modes);
+		c->mode = config.connector->modes[mode_num];
+	} else {
+		c->mode = config.default_mode;
 	}
-	c->crtc = resources->crtcs[i];
-	c->pipe = i;
-
-	if(test_preferred_mode || force_mode || specified_mode_num != -1)
-		resources->crtcs[i] = 0;
-
-	c->connector = connector;
+	c->mode_valid = 1;
 }
 
 static void
@@ -409,10 +340,6 @@  set_mode(struct connector *c)
 	else if (depth > 16 && depth <= 32)
 		bpp = 32;
 
-	connector_find_preferred_mode(c);
-	if (!c->mode_valid)
-		return;
-
 	test_mode_num = 1;
 	if (force_mode){
 		memcpy( &c->mode, &force_timing, sizeof(force_timing));
@@ -506,13 +433,30 @@  int update_display(void)
 	}
 
 	if (test_preferred_mode || test_all_modes || force_mode || specified_disp_id != -1) {
+		unsigned long crtc_idx_mask = -1UL;
+
 		/* Find any connected displays */
 		for (c = 0; c < resources->count_connectors; c++) {
-			connectors[c].id = resources->connectors[c];
-			if ( specified_disp_id != -1 && connectors[c].id != specified_disp_id )
+			struct connector *connector = &connectors[c];
+
+			connector->id = resources->connectors[c];
+			if (specified_disp_id != -1 &&
+			    connector->id != specified_disp_id)
+				continue;
+
+			connector_find_preferred_mode(connector->id,
+						      crtc_idx_mask,
+						      specified_mode_num,
+						      connector);
+			if (!connector->mode_valid)
 				continue;
 
-			set_mode(&connectors[c]);
+			set_mode(connector);
+
+			if (test_preferred_mode || force_mode ||
+			    specified_mode_num != -1)
+				crtc_idx_mask &= ~(1 << connector->crtc_idx);
+
 		}
 	}
 	drmModeFreeResources(resources);