From patchwork Thu Apr 12 16:12:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Noralf_Tr=C3=B8nnes?= X-Patchwork-Id: 10338941 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 518D0600D0 for ; Thu, 12 Apr 2018 16:13:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4103326220 for ; Thu, 12 Apr 2018 16:13:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 356472656B; Thu, 12 Apr 2018 16:13:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C34F326220 for ; Thu, 12 Apr 2018 16:13:07 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E5D426E997; Thu, 12 Apr 2018 16:13:01 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from smtp.domeneshop.no (smtp.domeneshop.no [IPv6:2a01:5b40:0:3005::1]) by gabe.freedesktop.org (Postfix) with ESMTPS id AD1946E992; Thu, 12 Apr 2018 16:12:59 +0000 (UTC) Received: from 211.81-166-168.customer.lyse.net ([81.166.168.211]:54390 helo=localhost.localdomain) by smtp.domeneshop.no with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_CBC_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1f6eqH-0002mh-2E; Thu, 12 Apr 2018 18:12:57 +0200 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= To: dri-devel@lists.freedesktop.org Date: Thu, 12 Apr 2018 18:12:27 +0200 Message-Id: <20180412161237.9314-4-noralf@tronnes.org> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180412161237.9314-1-noralf@tronnes.org> References: <20180412161237.9314-1-noralf@tronnes.org> MIME-Version: 1.0 Subject: [Intel-gfx] [RFC v4 15/25] drm/fb-helper: Move modeset config code to drm_client X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: daniel.vetter@ffwll.ch, intel-gfx@lists.freedesktop.org, =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= , laurent.pinchart@ideasonboard.com, mstaudt@suse.de, dh.herrmann@gmail.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Call the function drm_client_find_display(). No functional change apart from making width/height arguments optional. Some function name/signature changes and whitespace adjustments. Signed-off-by: Noralf Trønnes --- drivers/gpu/drm/drm_client.c | 399 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_fb_helper.c | 371 +------------------------------------ include/drm/drm_client.h | 2 + include/drm/drm_fb_helper.h | 4 - 4 files changed, 403 insertions(+), 373 deletions(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index c85c13568cf9..27818a467b09 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -18,6 +18,10 @@ #include #include +struct drm_client_display_offset { + int x, y; +}; + /** * drm_client_display_create() - Create display structure * @dev: DRM device @@ -359,3 +363,398 @@ void drm_client_display_dpms(struct drm_client_display *display, int mode) drm_client_display_dpms_legacy(display, mode); } EXPORT_SYMBOL(drm_client_display_dpms); + +static int drm_client_probe_connector_modes(struct drm_device *dev, + u32 max_width, u32 max_height) +{ + struct drm_connector_list_iter conn_iter; + struct drm_connector *connector; + int count = 0; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + count += connector->funcs->fill_modes(connector, max_width, max_height); + } + drm_connector_list_iter_end(&conn_iter); + + return count; +} + +static bool drm_target_cloned(struct drm_device *dev, + struct drm_connector **connectors, + unsigned int connector_count, + struct drm_display_mode **modes, + struct drm_client_display_offset *offsets, + bool *enabled, int width, int height) +{ + int count, i, j; + bool can_clone = false; + struct drm_display_mode *dmt_mode, *mode; + + /* only contemplate cloning in the single crtc case */ + if (dev->mode_config.num_crtc > 1) + return false; + + count = 0; + for (i = 0; i < connector_count; i++) { + if (enabled[i]) + count++; + } + + /* only contemplate cloning if more than one connector is enabled */ + if (count <= 1) + return false; + + /* check the command line or if nothing common pick 1024x768 */ + can_clone = true; + for (i = 0; i < connector_count; i++) { + if (!enabled[i]) + continue; + modes[i] = drm_connector_pick_cmdline_mode(connectors[i]); + if (!modes[i]) { + can_clone = false; + break; + } + for (j = 0; j < i; j++) { + if (!enabled[j]) + continue; + if (!drm_mode_equal(modes[j], modes[i])) + can_clone = false; + } + } + + if (can_clone) { + DRM_DEBUG_KMS("can clone using command line\n"); + return true; + } + + /* try and find a 1024x768 mode on each connector */ + can_clone = true; + dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false); + + for (i = 0; i < connector_count; i++) { + if (!enabled[i]) + continue; + + list_for_each_entry(mode, &connectors[i]->modes, head) { + if (drm_mode_equal(mode, dmt_mode)) + modes[i] = mode; + } + if (!modes[i]) + can_clone = false; + } + + if (can_clone) { + DRM_DEBUG_KMS("can clone using 1024x768\n"); + return true; + } + DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); + + return false; +} + +static void drm_get_tile_offsets(struct drm_connector **connectors, + unsigned int connector_count, + struct drm_display_mode **modes, + struct drm_client_display_offset *offsets, + int idx, + int h_idx, int v_idx) +{ + int i; + int hoffset = 0, voffset = 0; + + for (i = 0; i < connector_count; i++) { + struct drm_connector *connector = connectors[i]; + + if (!connector->has_tile) + continue; + + if (!modes[i] && (h_idx || v_idx)) { + DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, + connector->base.id); + continue; + } + if (connector->tile_h_loc < h_idx) + hoffset += modes[i]->hdisplay; + + if (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); +} + +static bool drm_target_preferred(struct drm_connector **connectors, + unsigned int connector_count, + struct drm_display_mode **modes, + struct drm_client_display_offset *offsets, + bool *enabled, int width, int height) +{ + const u64 mask = BIT_ULL(connector_count) - 1; + u64 conn_configured = 0; + int tile_pass = 0; + int i; + +retry: + for (i = 0; i < connector_count; i++) { + struct drm_connector *connector = connectors[i]; + + if (conn_configured & BIT_ULL(i)) + continue; + + if (!enabled[i]) { + conn_configured |= BIT_ULL(i); + continue; + } + + /* first pass over all the untiled connectors */ + if (tile_pass == 0 && connector->has_tile) + continue; + + if (tile_pass == 1) { + if (connector->tile_h_loc != 0 || + connector->tile_v_loc != 0) + continue; + + } else { + if (connector->tile_h_loc != tile_pass - 1 && + 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(connectors, connector_count, modes, offsets, + i, connector->tile_h_loc, connector->tile_v_loc); + } + DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", connector->base.id); + + /* got for command line mode first */ + modes[i] = drm_connector_pick_cmdline_mode(connector); + if (!modes[i]) { + DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n", + connector->base.id, + connector->tile_group ? connector->tile_group->id : 0); + modes[i] = drm_connector_has_preferred_mode(connector, width, height); + } + /* No preferred modes, pick one off the list */ + if (!modes[i]) + modes[i] = list_first_entry_or_null(&connector->modes, + struct drm_display_mode, head); + + DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : "none"); + conn_configured |= BIT_ULL(i); + } + + if ((conn_configured & mask) != mask) { + tile_pass++; + goto retry; + } + return true; +} + +static int drm_pick_crtcs(struct drm_client_display *display, + struct drm_connector **connectors, + unsigned int connector_count, + struct drm_crtc **best_crtcs, + struct drm_display_mode **modes, + int n, int width, int height) +{ + struct drm_device *dev = display->dev; + int o, my_score, best_score, score; + struct drm_connector *connector; + struct drm_mode_set *modeset; + struct drm_encoder *encoder; + struct drm_crtc **crtcs; + + if (n == connector_count) + return 0; + + connector = connectors[n]; + + best_crtcs[n] = NULL; + best_score = drm_pick_crtcs(display, connectors, connector_count, + best_crtcs, modes, n + 1, width, height); + if (!modes[n]) + return best_score; + + crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL); + if (!crtcs) + return best_score; + + my_score = 1; + if (connector->status == connector_status_connected) + my_score++; + if (connector->cmdline_mode.specified) + my_score++; + if (drm_connector_has_preferred_mode(connector, width, height)) + my_score++; + + /* + * If the DRM device implements atomic hooks and ->best_encoder() is + * NULL we fallback to the default drm_atomic_helper_best_encoder() + * helper. + */ + if (drm_drv_uses_atomic_modeset(dev) && + !connector->helper_private->best_encoder) + encoder = drm_atomic_helper_best_encoder(connector); + else + encoder = connector->helper_private->best_encoder(connector); + + if (!encoder) + goto out; + + /* + * select a crtc for this connector and then attempt to configure + * remaining connectors + */ + drm_client_display_for_each_modeset(modeset, display) { + struct drm_crtc *crtc = modeset->crtc; + + if ((encoder->possible_crtcs & drm_crtc_mask(crtc)) == 0) + continue; + + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + + if (o < n) { + /* ignore cloning unless only a single crtc */ + if (dev->mode_config.num_crtc > 1) + continue; + + if (!drm_mode_equal(modes[o], modes[n])) + continue; + } + + crtcs[n] = crtc; + memcpy(crtcs, best_crtcs, n * sizeof(*crtcs)); + score = my_score + drm_pick_crtcs(display, connectors, connector_count, + crtcs, modes, n + 1, width, height); + if (score > best_score) { + best_score = score; + memcpy(best_crtcs, crtcs, + connector_count * sizeof(*crtcs)); + } + } +out: + kfree(crtcs); + + return best_score; +} + +/** + * drm_client_find_display() - Find display + * @dev: DRM device + * @width: Maximum display mode width (optional) + * @height: Maximum display mode height (optional) + * + * This function returns a display the client can use if available. + * + * Free resources by calling drm_client_display_free(). + * + * Returns: + * A &drm_client_display on success, NULL if no connectors are found + * or error pointer on failure. + */ +struct drm_client_display * +drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height) +{ + struct drm_client_display_offset *offsets; + struct drm_client_display *display; + struct drm_connector **connectors; + struct drm_display_mode **modes; + struct drm_crtc **crtcs; + int i, connector_count; + bool *enabled; + + DRM_DEBUG_KMS("\n"); + + if (!width) + width = dev->mode_config.max_width; + if (!height) + height = dev->mode_config.max_height; + + mutex_lock(&dev->mode_config.mutex); + if (!drm_client_probe_connector_modes(dev, width, height)) + DRM_DEBUG_KMS("No connectors reported connected with modes\n"); + + if (dev->driver->initial_client_display) { + display = dev->driver->initial_client_display(dev, width, height); + if (display) { + mutex_unlock(&dev->mode_config.mutex); + return display; + } + } + + connector_count = drm_connector_get_all(dev, &connectors); + if (connector_count < 1) + return NULL; + + enabled = drm_connector_get_enabled_status(connectors, connector_count); + crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL); + modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL); + offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL); + if (!crtcs || !modes || !enabled || !offsets) { + DRM_ERROR("Memory allocation failed\n"); + display = ERR_PTR(-ENOMEM); + goto out; + } + + display = drm_client_display_create(dev); + if (IS_ERR(display)) + goto out; + + if (!drm_target_cloned(dev, connectors, connector_count, + modes, offsets, enabled, width, height) && + !drm_target_preferred(connectors, connector_count, + modes, offsets, enabled, width, height)) + DRM_ERROR("Unable to find initial modes\n"); + + DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); + + drm_pick_crtcs(display, connectors, connector_count, crtcs, modes, 0, width, height); + + /* need to set the modesets up here for use later */ + /* fill out the connector<->crtc mappings into the modesets */ + + for (i = 0; i < connector_count; i++) { + struct drm_client_display_offset *offset = &offsets[i]; + struct drm_connector *connector = connectors[i]; + struct drm_display_mode *mode = modes[i]; + struct drm_crtc *crtc = crtcs[i]; + + if (mode && crtc) { + struct drm_mode_set *modeset; + + modeset = drm_client_display_find_modeset(display, crtc); + if (WARN_ON(!modeset)) { + drm_client_display_free(display); + display = ERR_PTR(-EINVAL); + goto out; + } + + DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", + mode->name, modeset->crtc->base.id, offset->x, offset->y); + + modeset->mode = drm_mode_duplicate(dev, mode); + drm_connector_get(connector); + modeset->connectors[modeset->num_connectors++] = connector; + modeset->x = offset->x; + modeset->y = offset->y; + } + } +out: + mutex_unlock(&dev->mode_config.mutex); + drm_connector_put_all(connectors, connector_count); + kfree(crtcs); + kfree(modes); + kfree(offsets); + kfree(enabled); + + return display; +} +EXPORT_SYMBOL(drm_client_find_display); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 6ee61f195321..01d8840930a3 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1558,386 +1558,19 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe } EXPORT_SYMBOL(drm_fb_helper_fill_var); -static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper, - uint32_t maxX, - uint32_t maxY) -{ - struct drm_connector_list_iter conn_iter; - struct drm_connector *connector; - int count = 0; - - drm_connector_list_iter_begin(fb_helper->dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - count += connector->funcs->fill_modes(connector, maxX, maxY); - } - drm_connector_list_iter_end(&conn_iter); - - return count; -} - -static bool drm_target_cloned(struct drm_fb_helper *fb_helper, - struct drm_connector **connectors, - unsigned int connector_count, - struct drm_display_mode **modes, - struct drm_fb_offset *offsets, - bool *enabled, int width, int height) -{ - int count, i, j; - bool can_clone = false; - struct drm_display_mode *dmt_mode, *mode; - - /* only contemplate cloning in the single crtc case */ - if (fb_helper->dev->mode_config.num_crtc > 1) - return false; - - count = 0; - for (i = 0; i < connector_count; i++) { - if (enabled[i]) - count++; - } - - /* only contemplate cloning if more than one connector is enabled */ - if (count <= 1) - return false; - - /* check the command line or if nothing common pick 1024x768 */ - can_clone = true; - for (i = 0; i < connector_count; i++) { - if (!enabled[i]) - continue; - modes[i] = drm_connector_pick_cmdline_mode(connectors[i]); - if (!modes[i]) { - can_clone = false; - break; - } - for (j = 0; j < i; j++) { - if (!enabled[j]) - continue; - if (!drm_mode_equal(modes[j], modes[i])) - can_clone = false; - } - } - - if (can_clone) { - DRM_DEBUG_KMS("can clone using command line\n"); - return true; - } - - /* try and find a 1024x768 mode on each connector */ - can_clone = true; - dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false); - - for (i = 0; i < connector_count; i++) { - if (!enabled[i]) - continue; - - list_for_each_entry(mode, &connectors[i]->modes, head) { - if (drm_mode_equal(mode, dmt_mode)) - modes[i] = mode; - } - if (!modes[i]) - can_clone = false; - } - - if (can_clone) { - DRM_DEBUG_KMS("can clone using 1024x768\n"); - return true; - } - DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); - return false; -} - -static int drm_get_tile_offsets(struct drm_connector **connectors, - unsigned int connector_count, - struct drm_display_mode **modes, - struct drm_fb_offset *offsets, - int idx, - int h_idx, int v_idx) -{ - int i; - int hoffset = 0, voffset = 0; - - for (i = 0; i < connector_count; i++) { - struct drm_connector *connector = connectors[i]; - - if (!connector->has_tile) - continue; - - if (!modes[i] && (h_idx || v_idx)) { - DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, - connector->base.id); - continue; - } - if (connector->tile_h_loc < h_idx) - hoffset += modes[i]->hdisplay; - - if (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_connector **connectors, - unsigned int connector_count, - struct drm_display_mode **modes, - struct drm_fb_offset *offsets, - bool *enabled, int width, int height) -{ - const u64 mask = BIT_ULL(connector_count) - 1; - u64 conn_configured = 0; - int tile_pass = 0; - int i; - -retry: - for (i = 0; i < connector_count; i++) { - struct drm_connector *connector = connectors[i]; - - if (conn_configured & BIT_ULL(i)) - continue; - - if (enabled[i] == false) { - conn_configured |= BIT_ULL(i); - continue; - } - - /* first pass over all the untiled connectors */ - if (tile_pass == 0 && connector->has_tile) - continue; - - if (tile_pass == 1) { - if (connector->tile_h_loc != 0 || - connector->tile_v_loc != 0) - continue; - - } else { - if (connector->tile_h_loc != tile_pass - 1 && - 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(connectors, connector_count, modes, offsets, - i, connector->tile_h_loc, connector->tile_v_loc); - } - DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", - connector->base.id); - - /* got for command line mode first */ - modes[i] = drm_connector_pick_cmdline_mode(connector); - if (!modes[i]) { - DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n", - connector->base.id, connector->tile_group ? connector->tile_group->id : 0); - modes[i] = drm_connector_has_preferred_mode(connector, width, height); - } - /* No preferred modes, pick one off the list */ - if (!modes[i]) - modes[i] = list_first_entry_or_null(&connector->modes, struct drm_display_mode, head); - - DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : - "none"); - conn_configured |= BIT_ULL(i); - } - - if ((conn_configured & mask) != mask) { - tile_pass++; - goto retry; - } - return true; -} - -static int drm_pick_crtcs(struct drm_client_display *display, - struct drm_connector **connectors, - unsigned int connector_count, - struct drm_crtc **best_crtcs, - struct drm_display_mode **modes, - int n, int width, int height) -{ - struct drm_device *dev = display->dev; - int o, my_score, best_score, score; - struct drm_connector *connector; - const struct drm_connector_helper_funcs *connector_funcs; - struct drm_mode_set *modeset; - struct drm_encoder *encoder; - struct drm_crtc **crtcs; - - if (n == connector_count) - return 0; - - connector = connectors[n]; - - best_crtcs[n] = NULL; - best_score = drm_pick_crtcs(display, connectors, connector_count, - best_crtcs, modes, n + 1, width, height); - if (modes[n] == NULL) - return best_score; - - crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL); - if (!crtcs) - return best_score; - - my_score = 1; - if (connector->status == connector_status_connected) - my_score++; - if (connector->cmdline_mode.specified) - my_score++; - if (drm_connector_has_preferred_mode(connector, width, height)) - my_score++; - - connector_funcs = connector->helper_private; - - /* - * If the DRM device implements atomic hooks and ->best_encoder() is - * NULL we fallback to the default drm_atomic_helper_best_encoder() - * helper. - */ - if (drm_drv_uses_atomic_modeset(dev) && - !connector_funcs->best_encoder) - encoder = drm_atomic_helper_best_encoder(connector); - else - encoder = connector_funcs->best_encoder(connector); - - if (!encoder) - goto out; - - /* - * select a crtc for this connector and then attempt to configure - * remaining connectors - */ - drm_client_display_for_each_modeset(modeset, display) { - struct drm_crtc *crtc = modeset->crtc; - - if ((encoder->possible_crtcs & drm_crtc_mask(crtc)) == 0) - continue; - - for (o = 0; o < n; o++) - if (best_crtcs[o] == crtc) - break; - - if (o < n) { - /* ignore cloning unless only a single crtc */ - if (dev->mode_config.num_crtc > 1) - continue; - - if (!drm_mode_equal(modes[o], modes[n])) - continue; - } - - crtcs[n] = crtc; - memcpy(crtcs, best_crtcs, n * sizeof(*crtcs)); - score = my_score + drm_pick_crtcs(display, connectors, connector_count, - crtcs, modes, n + 1, width, height); - if (score > best_score) { - best_score = score; - memcpy(best_crtcs, crtcs, - connector_count * sizeof(*crtcs)); - } - } -out: - kfree(crtcs); - return best_score; -} - static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, u32 width, u32 height) { - struct drm_device *dev = fb_helper->dev; struct drm_client_display *display; - struct drm_connector **connectors; - struct drm_display_mode **modes; - struct drm_fb_offset *offsets; - struct drm_crtc **crtcs; - int i, connector_count; - bool *enabled; - DRM_DEBUG_KMS("\n"); - /* prevent concurrent modification of connector_count by hotplug */ lockdep_assert_held(&fb_helper->lock); - mutex_lock(&dev->mode_config.mutex); - if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0) - DRM_DEBUG_KMS("No connectors reported connected with modes\n"); - - if (dev->driver->initial_client_display) { - display = dev->driver->initial_client_display(dev, width, height); - if (display) { - drm_client_display_free(fb_helper->display); - fb_helper->display = display; - mutex_unlock(&dev->mode_config.mutex); - return; - } - } - - connector_count = drm_connector_get_all(dev, &connectors); - if (connector_count < 1) + display = drm_client_find_display(fb_helper->dev, width, height); + if (IS_ERR_OR_NULL(display)) return; - enabled = drm_connector_get_enabled_status(connectors, connector_count); - crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL); - modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL); - offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL); - if (!crtcs || !modes || !enabled || !offsets) { - DRM_ERROR("Memory allocation failed\n"); - goto out; - } - - display = drm_client_display_create(dev); - if (IS_ERR(display)) - goto out; - - if (!drm_target_cloned(fb_helper, connectors, connector_count, - modes, offsets, enabled, width, height) && - !drm_target_preferred(connectors, connector_count, - modes, offsets, enabled, width, height)) - DRM_ERROR("Unable to find initial modes\n"); - - DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); - - drm_pick_crtcs(display, connectors, connector_count, crtcs, modes, 0, width, height); - - /* need to set the modesets up here for use later */ - /* fill out the connector<->crtc mappings into the modesets */ - - for (i = 0; i < connector_count; i++) { - struct drm_connector *connector = connectors[i]; - struct drm_display_mode *mode = modes[i]; - struct drm_crtc *crtc = crtcs[i]; - struct drm_fb_offset *offset = &offsets[i]; - - if (mode && crtc) { - struct drm_mode_set *modeset; - - modeset = drm_client_display_find_modeset(display, crtc); - if (WARN_ON(!modeset)) { - drm_client_display_free(display); - goto out; - } - - DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", - mode->name, modeset->crtc->base.id, offset->x, offset->y); - - modeset->mode = drm_mode_duplicate(dev, mode); - drm_connector_get(connector); - modeset->connectors[modeset->num_connectors++] = connector; - modeset->x = offset->x; - modeset->y = offset->y; - } - } - drm_client_display_free(fb_helper->display); fb_helper->display = display; -out: - mutex_unlock(&dev->mode_config.mutex); - drm_connector_put_all(connectors, connector_count); - kfree(crtcs); - kfree(modes); - kfree(offsets); - kfree(enabled); } /* diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index ed028f5877d0..27d2a46cd94a 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -48,5 +48,7 @@ bool drm_client_display_panel_rotation(struct drm_connector *connector, unsigned int *rotation); int drm_client_display_restore(struct drm_client_display *display); void drm_client_display_dpms(struct drm_client_display *display, int mode); +struct drm_client_display * +drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height); #endif diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index a1e1ab1247c5..5f66f253a97b 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -41,10 +41,6 @@ enum mode_set_atomic { ENTER_ATOMIC_MODE_SET, }; -struct drm_fb_offset { - int x, y; -}; - /** * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size * @fb_width: fbdev width