[PATCH 1/4] drm/fb-helper: Support deferred setup
Daniel Vetter
daniel at ffwll.ch
Fri Jun 3 18:33:46 UTC 2016
On Fri, Jun 03, 2016 at 06:11:16PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding at nvidia.com>
>
> FB helper code falls back to a 1024x768 mode if no outputs are connected
> or don't report back any modes upon initialization. This can be annoying
> because outputs that are added to FB helper later on can't be used with
> FB helper if they don't support a matching mode.
>
> The fallback is in place because VGA connectors can happen to report an
> unknown connection status even when they are in fact connected.
>
> Some drivers have custom solutions in place to defer FB helper setup
> until at least one output is connected. But the logic behind these
> solutions is always the same and there is nothing driver-specific about
> it, so a better alterative is to fix the FB helper core and add support
> for all drivers automatically.
>
> This patch adds support for deferred FB helper setup. It checks all the
> connectors for their connection status, and if all of them report to be
> disconnected marks the FB helper as needing deferred setup. Whet setup
> is deferred, the FB helper core will automatically retry setup after a
> hotplug event, and it will keep trying until it succeeds.
>
> Signed-off-by: Thierry Reding <treding at nvidia.com>
> ---
> drivers/gpu/drm/drm_fb_helper.c | 36 ++++++++++++++++++++++++++++++++++++
> include/drm/drm_fb_helper.h | 21 +++++++++++++++++++++
> 2 files changed, 57 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 7c2eb75db60f..4f334f9cab28 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -442,6 +442,9 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
> if (!drm_fbdev_emulation)
> return -ENODEV;
>
> + if (fb_helper->deferred_setup)
> + return 0;
> +
> drm_modeset_lock_all(dev);
> ret = restore_fbdev_mode(fb_helper);
>
> @@ -1398,6 +1401,23 @@ unlock:
> }
> EXPORT_SYMBOL(drm_fb_helper_pan_display);
>
> +static bool drm_fb_helper_maybe_connected(struct drm_fb_helper *helper)
> +{
> + bool connected = false;
> + unsigned int i;
> +
> + for (i = 0; i < helper->connector_count; i++) {
> + struct drm_fb_helper_connector *fb = helper->connector_info[i];
> +
> + if (fb->connector->status != connector_status_disconnected) {
> + connected = true;
> + break;
> + }
> + }
> +
> + return connected;
> +}
> +
> /*
> * Allocates the backing storage and sets up the fbdev info structure through
> * the ->fb_probe callback and then registers the fbdev and sets up the panic
> @@ -1499,6 +1519,17 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
> sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
> }
>
> + /*
> + * If everything's disconnected, there's no use in attempting to set
> + * up fbdev.
> + */
> + if (!drm_fb_helper_maybe_connected(fb_helper)) {
> + DRM_INFO("No outputs connected, deferring setup\n");
> + fb_helper->preferred_bpp = preferred_bpp;
> + fb_helper->deferred_setup = true;
> + return 0;
> + }
> +
> if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
> /* hmm everyone went away - assume VGA cable just fell out
> and will come back later. */
> @@ -1539,6 +1570,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>
> list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
>
> + fb_helper->deferred_setup = false;
> return 0;
> }
>
> @@ -2237,6 +2269,10 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
> if (!drm_fbdev_emulation)
> return 0;
>
> + if (fb_helper->deferred_setup)
> + return drm_fb_helper_initial_config(fb_helper,
> + fb_helper->preferred_bpp);
Logic looks all nice, but we need more locking. Extending our abuse of
dev->mode_config.mutex for fb_helper internals won't work since
initial_config already takes some locks at various times, we need a real
fb_helper->mutex now. We want that anyway, to be able to push a bunch of
the modeset locking out of the fbdev code, or at least down a lot.
To make it work we need to make it a top-level lock, surrounding all kms
locks I think. And minimally it needs to wrapt hotplug_event, restore_mode
and the single_add/remove_connector functions.
-Daniel
> +
> mutex_lock(&fb_helper->dev->mode_config.mutex);
> if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
> fb_helper->delayed_hotplug = true;
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 5b4aa35026a3..25446690b2c1 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -214,6 +214,27 @@ struct drm_fb_helper {
> bool delayed_hotplug;
>
> /**
> + * @deferred_setup:
> + *
> + * If no outputs are connected (disconnected or unknown) the FB helper
> + * code will defer setup until at least one of the outputs shows up.
> + * This field keeps track of the status so that setup can be retried
> + * at every hotplug event until it succeeds eventually.
> + */
> + bool deferred_setup;
> +
> + /**
> + * @preferred_bpp:
> + *
> + * Temporary storage for the driver's preferred BPP setting passed to
> + * FB helper initialization. This needs to be tracked so that deferred
> + * FB helper setup can pass this on.
> + *
> + * See also: @deferred_setup
> + */
> + int preferred_bpp;
> +
> + /**
> * @atomic:
> *
> * Use atomic updates for restore_fbdev_mode(), etc. This defaults to
> --
> 2.8.3
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the dri-devel
mailing list