From patchwork Wed Sep 3 00:43:21 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Airlie X-Patchwork-Id: 4829521 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E18C69F32F for ; Wed, 3 Sep 2014 00:43:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 97A3F201CD for ; Wed, 3 Sep 2014 00:43:28 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2F7AA201E4 for ; Wed, 3 Sep 2014 00:43:27 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6C9836E1BC; Tue, 2 Sep 2014 17:43:26 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by gabe.freedesktop.org (Postfix) with ESMTP id E1F186E1BC for ; Tue, 2 Sep 2014 17:43:24 -0700 (PDT) Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s830hOMG010286 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Tue, 2 Sep 2014 20:43:24 -0400 Received: from dreadlord-bne-redhat-com.bne.redhat.com (dhcp-40-7.bne.redhat.com [10.64.40.7]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s830hLqi030338 for ; Tue, 2 Sep 2014 20:43:23 -0400 From: Dave Airlie To: intel-gfx@lists.freedesktop.org Date: Wed, 3 Sep 2014 10:43:21 +1000 Message-Id: <1409705001-972-2-git-send-email-airlied@gmail.com> In-Reply-To: <1409705001-972-1-git-send-email-airlied@gmail.com> References: <1409705001-972-1-git-send-email-airlied@gmail.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 Subject: [Intel-gfx] [PATCH 2/2] intel/uxa: add MST support. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-5.9 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, FREEMAIL_FROM,RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Dave Airlie This adds MST support to the UXA paths in the driver. Signed-off-by: Dave Airlie --- 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); }