From patchwork Mon Nov 10 02:16:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Airlie X-Patchwork-Id: 5263791 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 6EAB49F3ED for ; Mon, 10 Nov 2014 02:16:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 288842016C for ; Mon, 10 Nov 2014 02:16:32 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id EAAF1200CC for ; Mon, 10 Nov 2014 02:16:30 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 133A76EEED; Sun, 9 Nov 2014 18:16:28 -0800 (PST) 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 B09B76EEED; Sun, 9 Nov 2014 18:16:26 -0800 (PST) Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sAA2GQ28016344 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Sun, 9 Nov 2014 21:16:26 -0500 Received: from tyrion-bne-redhat-com.bne.redhat.com (dhcp-40-110.bne.redhat.com [10.64.40.110]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sAA2GHBu004574; Sun, 9 Nov 2014 21:16:25 -0500 From: Dave Airlie To: dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org Date: Mon, 10 Nov 2014 12:16:16 +1000 Message-Id: <1415585776-31415-7-git-send-email-airlied@gmail.com> In-Reply-To: <1415585776-31415-1-git-send-email-airlied@gmail.com> References: <1415585776-31415-1-git-send-email-airlied@gmail.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Subject: [Intel-gfx] [PATCH 6/6] drm/fb: add support for tiled monitor configurations. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 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=-4.8 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 fbdev/con support for tiled monitors, so that we only set a mode on the correct half of the monitor, or span the two halves if needed. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 122 +++++++++++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_fbdev.c | 25 +++++++- include/drm/drm_fb_helper.h | 6 ++ 3 files changed, 130 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3144db9..095f9d5 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1042,19 +1042,21 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, crtc_count = 0; for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_display_mode *desired_mode; + int x, y; desired_mode = fb_helper->crtc_info[i].desired_mode; - + x = fb_helper->crtc_info[i].x; + y = fb_helper->crtc_info[i].y; if (desired_mode) { if (gamma_size == 0) gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; - if (desired_mode->hdisplay < sizes.fb_width) - sizes.fb_width = desired_mode->hdisplay; - if (desired_mode->vdisplay < sizes.fb_height) - sizes.fb_height = desired_mode->vdisplay; - if (desired_mode->hdisplay > sizes.surface_width) - sizes.surface_width = desired_mode->hdisplay; - if (desired_mode->vdisplay > sizes.surface_height) - sizes.surface_height = desired_mode->vdisplay; + if (desired_mode->hdisplay + x < sizes.fb_width) + sizes.fb_width = desired_mode->hdisplay + x; + if (desired_mode->vdisplay + y < sizes.fb_height) + sizes.fb_height = desired_mode->vdisplay + y; + if (desired_mode->hdisplay + x > sizes.surface_width) + sizes.surface_width = desired_mode->hdisplay + x; + if (desired_mode->vdisplay + y > sizes.surface_height) + sizes.surface_height = desired_mode->vdisplay + y; crtc_count++; } } @@ -1356,6 +1358,7 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper, static bool drm_target_cloned(struct drm_fb_helper *fb_helper, struct drm_display_mode **modes, + struct drm_fb_offset *offsets, bool *enabled, int width, int height) { int count, i, j; @@ -1427,27 +1430,88 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper, return false; } +static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper, + struct drm_display_mode **modes, + struct drm_fb_offset *offsets, + int idx, + int h_idx, int v_idx) +{ + struct drm_fb_helper_connector *fb_helper_conn; + int i; + int hoffset = 0, voffset = 0; + + for (i = 0; i < fb_helper->connector_count; i++) { + fb_helper_conn = fb_helper->connector_info[i]; + if (!fb_helper_conn->connector->has_tile) + continue; + + if (!modes[i] && (h_idx || v_idx)) { + DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, + fb_helper_conn->connector->base.id); + continue; + } + if (fb_helper_conn->connector->tile_h_loc < h_idx) + hoffset += modes[i]->hdisplay; + + if (fb_helper_conn->connector->tile_v_loc < v_idx) + voffset += modes[i]->vdisplay; + } + offsets[idx].x = hoffset; + offsets[idx].y = voffset; + DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx); + return 0; +} + static bool drm_target_preferred(struct drm_fb_helper *fb_helper, struct drm_display_mode **modes, + struct drm_fb_offset *offsets, bool *enabled, int width, int height) { struct drm_fb_helper_connector *fb_helper_conn; int i; - + uint64_t conn_configured = 0, mask; + int tile_pass = 0; + mask = (1 << fb_helper->connector_count) - 1; +retry: for (i = 0; i < fb_helper->connector_count; i++) { fb_helper_conn = fb_helper->connector_info[i]; - if (enabled[i] == false) + if (conn_configured & (1 << i)) + continue; + + if (enabled[i] == false) { + conn_configured |= (1 << i); + continue; + } + + /* first pass over all the untiled connectors */ + if (tile_pass == 0 && fb_helper_conn->connector->has_tile) continue; + if (tile_pass == 1) { + if (fb_helper_conn->connector->tile_h_loc != 0 || + fb_helper_conn->connector->tile_v_loc != 0) + continue; + + } else { + if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 && + fb_helper_conn->connector->tile_v_loc != tile_pass - 1) + /* if this tile_pass doesn't cover any of the tiles - keep going */ + continue; + + /* find the tile offsets for this pass - need + to find all tiles left and above */ + drm_get_tile_offsets(fb_helper, modes, offsets, + i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc); + } DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", fb_helper_conn->connector->base.id); /* got for command line mode first */ modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); if (!modes[i]) { - DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", - fb_helper_conn->connector->base.id); + DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n", + fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0); modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); } /* No preferred modes, pick one off the list */ @@ -1457,6 +1521,13 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper, } DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : "none"); + conn_configured |= (1 << i); + } + + if ((conn_configured & mask) != mask) { + DRM_ERROR("not all connectors configured %d %llx %llx\n", tile_pass, conn_configured, mask); + tile_pass++; + goto retry; } return true; } @@ -1546,6 +1617,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) struct drm_device *dev = fb_helper->dev; struct drm_fb_helper_crtc **crtcs; struct drm_display_mode **modes; + struct drm_fb_offset *offsets; struct drm_mode_set *modeset; bool *enabled; int width, height; @@ -1560,9 +1632,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); modes = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_display_mode *), GFP_KERNEL); + offsets = kcalloc(dev->mode_config.num_connector, + sizeof(struct drm_fb_offset), GFP_KERNEL); enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), GFP_KERNEL); - if (!crtcs || !modes || !enabled) { + if (!crtcs || !modes || !enabled | !offsets) { DRM_ERROR("Memory allocation failed\n"); goto out; } @@ -1572,14 +1646,16 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) if (!(fb_helper->funcs->initial_config && fb_helper->funcs->initial_config(fb_helper, crtcs, modes, + offsets, enabled, width, height))) { memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); + memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0])); - if (!drm_target_cloned(fb_helper, - modes, enabled, width, height) && - !drm_target_preferred(fb_helper, - modes, enabled, width, height)) + if (!drm_target_cloned(fb_helper, modes, offsets, + enabled, width, height) && + !drm_target_preferred(fb_helper, modes, offsets, + enabled, width, height)) DRM_ERROR("Unable to find initial modes\n"); DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", @@ -1599,18 +1675,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) for (i = 0; i < fb_helper->connector_count; i++) { struct drm_display_mode *mode = modes[i]; struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; + struct drm_fb_offset *offset = &offsets[i]; modeset = &fb_crtc->mode_set; if (mode && fb_crtc) { - DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", - mode->name, fb_crtc->mode_set.crtc->base.id); + DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", + mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); fb_crtc->desired_mode = mode; + fb_crtc->x = offset->x; + fb_crtc->y = offset->y; if (modeset->mode) drm_mode_destroy(dev, modeset->mode); modeset->mode = drm_mode_duplicate(dev, fb_crtc->desired_mode); modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; modeset->fb = fb_helper->fb; + modeset->x = offset->x; + modeset->y = offset->y; } } @@ -1628,6 +1709,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) out: kfree(crtcs); kfree(modes); + kfree(offsets); kfree(enabled); } diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index f475414..73faf85 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -322,6 +322,7 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, struct drm_fb_helper_crtc **crtcs, struct drm_display_mode **modes, + struct drm_fb_offset *offsets, bool *enabled, int width, int height) { struct drm_device *dev = fb_helper->dev; @@ -330,6 +331,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, bool fallback = true; int num_connectors_enabled = 0; int num_connectors_detected = 0; + uint64_t conn_configured = 0, mask; + int pass = 0; /* * If the user specified any force options, just bail here @@ -355,7 +358,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, return false; memcpy(save_enabled, enabled, dev->mode_config.num_connector); - + mask = (1 << fb_helper->connector_count) - 1; +retry: for (i = 0; i < fb_helper->connector_count; i++) { struct drm_fb_helper_connector *fb_conn; struct drm_connector *connector; @@ -365,12 +369,19 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, fb_conn = fb_helper->connector_info[i]; connector = fb_conn->connector; + if (conn_configured & (1 << i)) + continue; + + if (pass == 0 && !connector->has_tile) + continue; + if (connector->status == connector_status_connected) num_connectors_detected++; if (!enabled[i]) { DRM_DEBUG_KMS("connector %s not enabled, skipping\n", connector->name); + conn_configured |= (1 << i); continue; } @@ -379,6 +390,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", connector->name); enabled[i] = false; + conn_configured |= (1 << i); continue; } @@ -407,8 +419,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, /* try for preferred next */ if (!modes[i]) { - DRM_DEBUG_KMS("looking for preferred mode on connector %s\n", - connector->name); + DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n", + connector->name, connector->has_tile); modes[i] = drm_has_preferred_mode(fb_conn, width, height); } @@ -451,6 +463,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); fallback = false; + conn_configured |= (1 << i); + } + + if ((conn_configured & mask) != mask) { + DRM_ERROR("not all connectors configured %d %llx %llx\n", pass, conn_configured, mask); + pass++; + goto retry; } /* diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index bfd329d..7fcb1e7 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -34,9 +34,14 @@ struct drm_fb_helper; #include +struct drm_fb_offset { + int x, y; +}; + struct drm_fb_helper_crtc { struct drm_mode_set mode_set; struct drm_display_mode *desired_mode; + int x, y; }; struct drm_fb_helper_surface_size { @@ -72,6 +77,7 @@ struct drm_fb_helper_funcs { bool (*initial_config)(struct drm_fb_helper *fb_helper, struct drm_fb_helper_crtc **crtcs, struct drm_display_mode **modes, + struct drm_fb_offset *offsets, bool *enabled, int width, int height); };