| From 61913166a612c878673fcb8727b8c5ee05d03778 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 11 Dec 2019 13:24:33 -0800 |
| Subject: drm/fbdev: Fallback to non tiled mode if all tiles not present |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Manasi Navare <manasi.d.navare@intel.com> |
| |
| [ Upstream commit f25c7a006cd1c07254780e3406e45cee4842b933 ] |
| |
| In case of tiled displays, if we hotplug just one connector, |
| fbcon currently just selects the preferred mode and if it is |
| tiled mode then that becomes a problem if rest of the tiles are |
| not present. |
| So in the fbdev driver on hotplug when we probe the client modeset, |
| if we dont find all the connectors for all tiles, then on a connector |
| with one tile, just fallback to the first available non tiled mode |
| to display over a single connector. |
| On the hotplug of the consecutive tiled connectors, if the tiled mode |
| no longer exists because of fbcon size limitation, then return |
| no modes for consecutive tiles but retain the non tiled mode |
| on the 0th tile. |
| Use the same logic in case of connected boot case as well. |
| This has been tested with Dell UP328K tiled monitor. |
| |
| v2: |
| * Set the modes on consecutive hotplugged tiles to no mode |
| if tiled mode is pruned (Dave) |
| v1: |
| * Just handle the 1st connector hotplug case |
| * v1 Reviewed-by: Dave Airlie <airlied@redhat.com> |
| |
| Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> |
| Suggested-by: Dave Airlie <airlied@redhat.com> |
| Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> |
| Cc: Dave Airlie <airlied@redhat.com> |
| Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> |
| Reviewed-by: Dave Airlie <airlied@redhat.com> |
| Link: https://patchwork.freedesktop.org/patch/msgid/20191113222952.9231-1-manasi.d.navare@intel.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/gpu/drm/drm_client_modeset.c | 72 ++++++++++++++++++++++++++++ |
| 1 file changed, 72 insertions(+) |
| |
| diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c |
| index c8922b7cac091..12e748b202d6f 100644 |
| --- a/drivers/gpu/drm/drm_client_modeset.c |
| +++ b/drivers/gpu/drm/drm_client_modeset.c |
| @@ -114,6 +114,33 @@ drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc) |
| return NULL; |
| } |
| |
| +static struct drm_display_mode * |
| +drm_connector_get_tiled_mode(struct drm_connector *connector) |
| +{ |
| + struct drm_display_mode *mode; |
| + |
| + list_for_each_entry(mode, &connector->modes, head) { |
| + if (mode->hdisplay == connector->tile_h_size && |
| + mode->vdisplay == connector->tile_v_size) |
| + return mode; |
| + } |
| + return NULL; |
| +} |
| + |
| +static struct drm_display_mode * |
| +drm_connector_fallback_non_tiled_mode(struct drm_connector *connector) |
| +{ |
| + struct drm_display_mode *mode; |
| + |
| + list_for_each_entry(mode, &connector->modes, head) { |
| + if (mode->hdisplay == connector->tile_h_size && |
| + mode->vdisplay == connector->tile_v_size) |
| + continue; |
| + return mode; |
| + } |
| + return NULL; |
| +} |
| + |
| static struct drm_display_mode * |
| drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height) |
| { |
| @@ -348,8 +375,15 @@ static bool drm_client_target_preferred(struct drm_connector **connectors, |
| struct drm_connector *connector; |
| u64 conn_configured = 0; |
| int tile_pass = 0; |
| + int num_tiled_conns = 0; |
| int i; |
| |
| + for (i = 0; i < connector_count; i++) { |
| + if (connectors[i]->has_tile && |
| + connectors[i]->status == connector_status_connected) |
| + num_tiled_conns++; |
| + } |
| + |
| retry: |
| for (i = 0; i < connector_count; i++) { |
| connector = connectors[i]; |
| @@ -399,6 +433,28 @@ retry: |
| list_for_each_entry(modes[i], &connector->modes, head) |
| break; |
| } |
| + /* |
| + * In case of tiled mode if all tiles not present fallback to |
| + * first available non tiled mode. |
| + * After all tiles are present, try to find the tiled mode |
| + * for all and if tiled mode not present due to fbcon size |
| + * limitations, use first non tiled mode only for |
| + * tile 0,0 and set to no mode for all other tiles. |
| + */ |
| + if (connector->has_tile) { |
| + if (num_tiled_conns < |
| + connector->num_h_tile * connector->num_v_tile || |
| + (connector->tile_h_loc == 0 && |
| + connector->tile_v_loc == 0 && |
| + !drm_connector_get_tiled_mode(connector))) { |
| + DRM_DEBUG_KMS("Falling back to non tiled mode on Connector %d\n", |
| + connector->base.id); |
| + modes[i] = drm_connector_fallback_non_tiled_mode(connector); |
| + } else { |
| + modes[i] = drm_connector_get_tiled_mode(connector); |
| + } |
| + } |
| + |
| DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
| "none"); |
| conn_configured |= BIT_ULL(i); |
| @@ -516,6 +572,7 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, |
| bool fallback = true, ret = true; |
| int num_connectors_enabled = 0; |
| int num_connectors_detected = 0; |
| + int num_tiled_conns = 0; |
| struct drm_modeset_acquire_ctx ctx; |
| |
| if (!drm_drv_uses_atomic_modeset(dev)) |
| @@ -533,6 +590,11 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, |
| memcpy(save_enabled, enabled, count); |
| mask = GENMASK(count - 1, 0); |
| conn_configured = 0; |
| + for (i = 0; i < count; i++) { |
| + if (connectors[i]->has_tile && |
| + connectors[i]->status == connector_status_connected) |
| + num_tiled_conns++; |
| + } |
| retry: |
| conn_seq = conn_configured; |
| for (i = 0; i < count; i++) { |
| @@ -632,6 +694,16 @@ retry: |
| connector->name); |
| modes[i] = &connector->state->crtc->mode; |
| } |
| + /* |
| + * In case of tiled modes, if all tiles are not present |
| + * then fallback to a non tiled mode. |
| + */ |
| + if (connector->has_tile && |
| + num_tiled_conns < connector->num_h_tile * connector->num_v_tile) { |
| + DRM_DEBUG_KMS("Falling back to non tiled mode on Connector %d\n", |
| + connector->base.id); |
| + modes[i] = drm_connector_fallback_non_tiled_mode(connector); |
| + } |
| crtcs[i] = new_crtc; |
| |
| DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n", |
| -- |
| 2.20.1 |
| |