Message ID | 20191113222952.9231-1-manasi.d.navare@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [CI,v2] drm/fbdev: Fallback to non tiled mode if all tiles not present | expand |
Pushed tod rm-misc-next, thanks a lot Dave all the feedback and reviews. Regards Manasi On Wed, Nov 13, 2019 at 02:29:52PM -0800, Manasi Navare wrote: > 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> > --- > drivers/gpu/drm/drm_client_modeset.c | 70 ++++++++++++++++++++++++++++ > 1 file changed, 70 insertions(+) > > diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c > index 895b73f23079..f2150a0bac4c 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,14 @@ 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) > + num_tiled_conns++; > + } > + > retry: > for (i = 0; i < connector_count; i++) { > connector = connectors[i]; > @@ -399,6 +432,28 @@ static bool drm_client_target_preferred(struct drm_connector **connectors, > 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); > @@ -515,6 +570,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)) > @@ -532,6 +588,10 @@ 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) > + num_tiled_conns++; > + } > retry: > conn_seq = conn_configured; > for (i = 0; i < count; i++) { > @@ -631,6 +691,16 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, > 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.19.1 >
diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index 895b73f23079..f2150a0bac4c 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,14 @@ 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) + num_tiled_conns++; + } + retry: for (i = 0; i < connector_count; i++) { connector = connectors[i]; @@ -399,6 +432,28 @@ static bool drm_client_target_preferred(struct drm_connector **connectors, 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); @@ -515,6 +570,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)) @@ -532,6 +588,10 @@ 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) + num_tiled_conns++; + } retry: conn_seq = conn_configured; for (i = 0; i < count; i++) { @@ -631,6 +691,16 @@ static bool drm_client_firmware_config(struct drm_client_dev *client, 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",