[PATCH v2 1/5] drm: Add helpers to kick off self refresh mode in drivers

Daniel Vetter daniel at ffwll.ch
Tue Apr 2 09:50:04 UTC 2019


On Tue, Apr 2, 2019 at 11:45 AM Neil Armstrong <narmstrong at baylibre.com> wrote:
>
> On 02/04/2019 11:08, Daniel Vetter wrote:
> > On Tue, Apr 02, 2019 at 10:55:24AM +0200, Neil Armstrong wrote:
> >> Hi Sean,
> >>
> >> On 26/03/2019 21:44, Sean Paul wrote:
> >>> From: Sean Paul <seanpaul at chromium.org>
> >>>
> >>> This patch adds a new drm helper library to help drivers implement
> >>> self refresh. Drivers choosing to use it will register crtcs and
> >>> will receive callbacks when it's time to enter or exit self refresh
> >>> mode.
> >>>
> >>> In its current form, it has a timer which will trigger after a
> >>> driver-specified amount of inactivity. When the timer triggers, the
> >>> helpers will submit a new atomic commit to shut the refreshing pipe
> >>> off. On the next atomic commit, the drm core will revert the self
> >>> refresh state and bring everything back up to be actively driven.
> >>>
> >>> From the driver's perspective, this works like a regular disable/enable
> >>> cycle. The driver need only check the 'self_refresh_active' and/or
> >>> 'self_refresh_changed' state in crtc_state and connector_state. It
> >>> should initiate self refresh mode on the panel and enter an off or
> >>> low-power state.
> >>
> >> It may be a stupid question, but can't this make use of PM runtime ?
> >
> > tbh no idea what you have in mind ... Can you pls explain a bit more?
>
> PM runtime is done to handle these inactivity periods, and act accordingly
> in PM runtime callbacks.
> Maybe Sean needs a more CRTC-centric PM runtime, to put a particular memory
> in self-refresh, maybe a driver-wide inactivity tracking is too big.

I guess the actual implementation uses runtime pm (or at least can).
The trouble with self-refresh is that the display actually is in use,
and we need to keep pretending to userspace that it is in use. That
semantic lie needs a bit of work in frameworks to make it all pan out.
Part of my motiviation with repurposing the existing enable/disable
callbacks is that those will already do runtime pm (or something
equivalent), so less code. But there's a few corner cases.
-Daniel

>
> Neil
>
> > -Daniel
> >
> >>
> >> Neil
> >>
> >>>
> >>> Changes in v2:
> >>> - s/psr/self_refresh/ (Daniel)
> >>> - integrated the psr exit into the commit that wakes it up (Jose/Daniel)
> >>> - made the psr state per-crtc (Jose/Daniel)
> >>>
> >>> Link to v1: https://patchwork.freedesktop.org/patch/msgid/20190228210939.83386-2-sean@poorly.run
> >>>
> >>> Cc: Daniel Vetter <daniel at ffwll.ch>
> >>> Cc: Jose Souza <jose.souza at intel.com>
> >>> Cc: Zain Wang <wzz at rock-chips.com>
> >>> Cc: Tomasz Figa <tfiga at chromium.org>
> >>> Signed-off-by: Sean Paul <seanpaul at chromium.org>
> >>> ---
> >>>  Documentation/gpu/drm-kms-helpers.rst     |   9 +
> >>>  drivers/gpu/drm/Makefile                  |   3 +-
> >>>  drivers/gpu/drm/drm_atomic.c              |   4 +
> >>>  drivers/gpu/drm/drm_atomic_helper.c       |  36 +++-
> >>>  drivers/gpu/drm/drm_atomic_state_helper.c |   8 +
> >>>  drivers/gpu/drm/drm_atomic_uapi.c         |   5 +-
> >>>  drivers/gpu/drm/drm_self_refresh_helper.c | 212 ++++++++++++++++++++++
> >>>  include/drm/drm_atomic.h                  |  15 ++
> >>>  include/drm/drm_connector.h               |  31 ++++
> >>>  include/drm/drm_crtc.h                    |  19 ++
> >>>  include/drm/drm_self_refresh_helper.h     |  23 +++
> >>>  11 files changed, 360 insertions(+), 5 deletions(-)
> >>>  create mode 100644 drivers/gpu/drm/drm_self_refresh_helper.c
> >>>  create mode 100644 include/drm/drm_self_refresh_helper.h
> >>>
> >>> diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
> >>> index 58b375e47615..b0b71f73829f 100644
> >>> --- a/Documentation/gpu/drm-kms-helpers.rst
> >>> +++ b/Documentation/gpu/drm-kms-helpers.rst
> >>> @@ -107,6 +107,15 @@ fbdev Helper Functions Reference
> >>>  .. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c
> >>>     :export:
> >>>
> >>> +Panel Self Refresh Helper Reference
> >>> +===================================
> >>> +
> >>> +.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
> >>> +   :doc: overview
> >>> +
> >>> +.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
> >>> +   :export:
> >>> +
> >>>  Framebuffer CMA Helper Functions Reference
> >>>  ==========================================
> >>>
> >>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> >>> index e630eccb951c..5b3a1e26ec94 100644
> >>> --- a/drivers/gpu/drm/Makefile
> >>> +++ b/drivers/gpu/drm/Makefile
> >>> @@ -38,7 +38,8 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
> >>>             drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
> >>>             drm_simple_kms_helper.o drm_modeset_helper.o \
> >>>             drm_scdc_helper.o drm_gem_framebuffer_helper.o \
> >>> -           drm_atomic_state_helper.o drm_damage_helper.o
> >>> +           drm_atomic_state_helper.o drm_damage_helper.o \
> >>> +           drm_self_refresh_helper.o
> >>>
> >>>  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
> >>>  drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
> >>> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >>> index 5eb40130fafb..a06fe55b5ebf 100644
> >>> --- a/drivers/gpu/drm/drm_atomic.c
> >>> +++ b/drivers/gpu/drm/drm_atomic.c
> >>> @@ -379,6 +379,7 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
> >>>     drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
> >>>     drm_printf(p, "\tenable=%d\n", state->enable);
> >>>     drm_printf(p, "\tactive=%d\n", state->active);
> >>> +   drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
> >>>     drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed);
> >>>     drm_printf(p, "\tmode_changed=%d\n", state->mode_changed);
> >>>     drm_printf(p, "\tactive_changed=%d\n", state->active_changed);
> >>> @@ -881,6 +882,9 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
> >>>
> >>>     drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
> >>>     drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
> >>> +   drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
> >>> +   drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
> >>> +   drm_printf(p, "\tself_refresh_changed=%d\n", state->self_refresh_changed);
> >>>
> >>>     if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
> >>>             if (state->writeback_job && state->writeback_job->fb)
> >>> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> >>> index 2453678d1186..c659db105133 100644
> >>> --- a/drivers/gpu/drm/drm_atomic_helper.c
> >>> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> >>> @@ -30,6 +30,7 @@
> >>>  #include <drm/drm_atomic_uapi.h>
> >>>  #include <drm/drm_plane_helper.h>
> >>>  #include <drm/drm_atomic_helper.h>
> >>> +#include <drm/drm_self_refresh_helper.h>
> >>>  #include <drm/drm_writeback.h>
> >>>  #include <drm/drm_damage_helper.h>
> >>>  #include <linux/dma-fence.h>
> >>> @@ -950,10 +951,33 @@ int drm_atomic_helper_check(struct drm_device *dev,
> >>>     if (state->legacy_cursor_update)
> >>>             state->async_update = !drm_atomic_helper_async_check(dev, state);
> >>>
> >>> +   drm_self_refresh_helper_alter_state(state);
> >>> +
> >>>     return ret;
> >>>  }
> >>>  EXPORT_SYMBOL(drm_atomic_helper_check);
> >>>
> >>> +static bool
> >>> +crtc_needs_disable(struct drm_crtc_state *old_state,
> >>> +              struct drm_crtc_state *new_state)
> >>> +{
> >>> +   /*
> >>> +    * No new_state means the crtc is off, so the only criteria is whether
> >>> +    * it's currently active or in self refresh mode.
> >>> +    */
> >>> +   if (!new_state)
> >>> +           return drm_atomic_crtc_effectively_active(old_state);
> >>> +
> >>> +   /*
> >>> +    * We need to run through the crtc_funcs->disable() function if the crtc
> >>> +    * is currently on, if it's transitioning to self refresh mode, or if
> >>> +    * it's in self refresh mode and needs to be fully disabled.
> >>> +    */
> >>> +   return old_state->active ||
> >>> +          (old_state->self_refresh_active && !new_state->enable) ||
> >>> +          new_state->self_refresh_active;
> >>> +}
> >>> +
> >>>  static void
> >>>  disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> >>>  {
> >>> @@ -974,7 +998,14 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> >>>
> >>>             old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
> >>>
> >>> -           if (!old_crtc_state->active ||
> >>> +           if (new_conn_state->crtc)
> >>> +                   new_crtc_state = drm_atomic_get_new_crtc_state(
> >>> +                                           old_state,
> >>> +                                           new_conn_state->crtc);
> >>> +           else
> >>> +                   new_crtc_state = NULL;
> >>> +
> >>> +           if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
> >>>                 !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
> >>>                     continue;
> >>>
> >>> @@ -1018,7 +1049,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> >>>             if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
> >>>                     continue;
> >>>
> >>> -           if (!old_crtc_state->active)
> >>> +           if (!crtc_needs_disable(old_crtc_state, new_crtc_state))
> >>>                     continue;
> >>>
> >>>             funcs = crtc->helper_private;
> >>> @@ -2948,6 +2979,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
> >>>             return -ENOMEM;
> >>>
> >>>     state->acquire_ctx = ctx;
> >>> +
> >>>     ret = __drm_atomic_helper_set_config(set, state);
> >>>     if (ret != 0)
> >>>             goto fail;
> >>> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
> >>> index 4985384e51f6..ec90c527deed 100644
> >>> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> >>> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> >>> @@ -105,6 +105,10 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
> >>>     state->commit = NULL;
> >>>     state->event = NULL;
> >>>     state->pageflip_flags = 0;
> >>> +
> >>> +   /* Self refresh should be canceled when a new update is available */
> >>> +   state->active = drm_atomic_crtc_effectively_active(state);
> >>> +   state->self_refresh_active = false;
> >>>  }
> >>>  EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
> >>>
> >>> @@ -370,6 +374,10 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
> >>>
> >>>     /* Don't copy over a writeback job, they are used only once */
> >>>     state->writeback_job = NULL;
> >>> +
> >>> +   /* Self refresh should be canceled when a new update is available */
> >>> +   state->self_refresh_changed = state->self_refresh_active;
> >>> +   state->self_refresh_active = false;
> >>>  }
> >>>  EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
> >>>
> >>> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> >>> index 4eb81f10bc54..d2085332172b 100644
> >>> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> >>> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> >>> @@ -490,7 +490,7 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
> >>>     struct drm_mode_config *config = &dev->mode_config;
> >>>
> >>>     if (property == config->prop_active)
> >>> -           *val = state->active;
> >>> +           *val = drm_atomic_crtc_effectively_active(state);
> >>>     else if (property == config->prop_mode_id)
> >>>             *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
> >>>     else if (property == config->prop_vrr_enabled)
> >>> @@ -785,7 +785,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> >>>     if (property == config->prop_crtc_id) {
> >>>             *val = (state->crtc) ? state->crtc->base.id : 0;
> >>>     } else if (property == config->dpms_property) {
> >>> -           *val = connector->dpms;
> >>> +           *val = state->self_refresh_active ? DRM_MODE_DPMS_ON :
> >>> +                   connector->dpms;
> >>>     } else if (property == config->tv_select_subconnector_property) {
> >>>             *val = state->tv.subconnector;
> >>>     } else if (property == config->tv_left_margin_property) {
> >>> diff --git a/drivers/gpu/drm/drm_self_refresh_helper.c b/drivers/gpu/drm/drm_self_refresh_helper.c
> >>> new file mode 100644
> >>> index 000000000000..a3afa031480e
> >>> --- /dev/null
> >>> +++ b/drivers/gpu/drm/drm_self_refresh_helper.c
> >>> @@ -0,0 +1,212 @@
> >>> +/* SPDX-License-Identifier: MIT */
> >>> +/*
> >>> + * Copyright (C) 2019 Google, Inc.
> >>> + *
> >>> + * Authors:
> >>> + * Sean Paul <seanpaul at chromium.org>
> >>> + */
> >>> +#include <drm/drm_atomic.h>
> >>> +#include <drm/drm_atomic_helper.h>
> >>> +#include <drm/drm_connector.h>
> >>> +#include <drm/drm_crtc.h>
> >>> +#include <drm/drm_device.h>
> >>> +#include <drm/drm_mode_config.h>
> >>> +#include <drm/drm_modeset_lock.h>
> >>> +#include <drm/drm_print.h>
> >>> +#include <drm/drm_self_refresh_helper.h>
> >>> +#include <linux/bitops.h>
> >>> +#include <linux/slab.h>
> >>> +#include <linux/workqueue.h>
> >>> +
> >>> +/**
> >>> + * DOC: overview
> >>> + *
> >>> + * This helper library provides an easy way for drivers to leverage the atomic
> >>> + * framework to implement panel self refresh (SR) support. Drivers are
> >>> + * responsible for registering and unregistering the SR helpers on load/unload.
> >>> + *
> >>> + * Once a crtc has enabled SR, the helpers will monitor activity and
> >>> + * call back into the driver to enable/disable SR as appropriate. The best way
> >>> + * to think about this is that it's a DPMS on/off request with a flag set in
> >>> + * state that tells you to disable/enable SR on the panel instead of power-
> >>> + * cycling it.
> >>> + *
> >>> + * Drivers may choose to fully disable their crtc/encoder/bridge hardware, or
> >>> + * they can use the "self_refresh_active" and "self_refresh_changed" flags in
> >>> + * object state if they want to enter low power mode without full disable (in
> >>> + * case full disable/enable is too slow).
> >>> + *
> >>> + * SR will be deactivated if there are any atomic updates affecting the
> >>> + * pipe that is in SR mode. If a crtc is driving multiple connectors, all
> >>> + * connectors must be SR aware and all will enter SR mode.
> >>> + */
> >>> +
> >>> +struct drm_self_refresh_state {
> >>> +   struct drm_crtc *crtc;
> >>> +   struct delayed_work entry_work;
> >>> +   struct drm_atomic_state *save_state;
> >>> +   unsigned int entry_delay_ms;
> >>> +};
> >>> +
> >>> +static void drm_self_refresh_helper_entry_work(struct work_struct *work)
> >>> +{
> >>> +   struct drm_self_refresh_state *sr_state = container_of(
> >>> +                           to_delayed_work(work),
> >>> +                           struct drm_self_refresh_state, entry_work);
> >>> +   struct drm_crtc *crtc = sr_state->crtc;
> >>> +   struct drm_device *dev = crtc->dev;
> >>> +   struct drm_modeset_acquire_ctx ctx;
> >>> +   struct drm_atomic_state *state;
> >>> +   struct drm_connector *conn;
> >>> +   struct drm_connector_state *conn_state;
> >>> +   struct drm_crtc_state *crtc_state;
> >>> +   int i, ret;
> >>> +
> >>> +   drm_modeset_acquire_init(&ctx, 0);
> >>> +
> >>> +   state = drm_atomic_state_alloc(dev);
> >>> +   if (!state) {
> >>> +           ret = -ENOMEM;
> >>> +           goto out;
> >>> +   }
> >>> +
> >>> +retry:
> >>> +   state->acquire_ctx = &ctx;
> >>> +
> >>> +   crtc_state = drm_atomic_get_crtc_state(state, crtc);
> >>> +   if (IS_ERR(crtc_state)) {
> >>> +           ret = PTR_ERR(crtc_state);
> >>> +           goto out;
> >>> +   }
> >>> +
> >>> +   if (!crtc_state->enable)
> >>> +           goto out;
> >>> +
> >>> +   ret = drm_atomic_add_affected_connectors(state, crtc);
> >>> +   if (ret)
> >>> +           goto out;
> >>> +
> >>> +   crtc_state->active = false;
> >>> +   crtc_state->self_refresh_active = true;
> >>> +
> >>> +   for_each_new_connector_in_state(state, conn, conn_state, i) {
> >>> +           if (!conn_state->self_refresh_aware)
> >>> +                   goto out;
> >>> +
> >>> +           conn_state->self_refresh_changed = true;
> >>> +           conn_state->self_refresh_active = true;
> >>> +   }
> >>> +
> >>> +   ret = drm_atomic_commit(state);
> >>> +   if (ret)
> >>> +           goto out;
> >>> +
> >>> +out:
> >>> +   if (ret == -EDEADLK) {
> >>> +           drm_atomic_state_clear(state);
> >>> +           ret = drm_modeset_backoff(&ctx);
> >>> +           if (!ret)
> >>> +                   goto retry;
> >>> +   }
> >>> +
> >>> +   drm_atomic_state_put(state);
> >>> +   drm_modeset_drop_locks(&ctx);
> >>> +   drm_modeset_acquire_fini(&ctx);
> >>> +}
> >>> +
> >>> +/**
> >>> + * drm_self_refresh_helper_alter_state - Alters the atomic state for SR exit
> >>> + * @state: the state currently being checked
> >>> + *
> >>> + * Called at the end of atomic check. This function checks the state for flags
> >>> + * incompatible with self refresh exit and changes them. This is a bit
> >>> + * disingenuous since userspace is expecting one thing and we're giving it
> >>> + * another. However in order to keep self refresh entirely hidden from
> >>> + * userspace, this is required.
> >>> + *
> >>> + * At the end, we queue up the self refresh entry work so we can enter PSR after
> >>> + * the desired delay.
> >>> + */
> >>> +void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state)
> >>> +{
> >>> +   struct drm_crtc *crtc;
> >>> +   struct drm_crtc_state *crtc_state;
> >>> +   int i;
> >>> +
> >>> +   if (state->async_update) {
> >>> +           for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
> >>> +                   if (crtc_state->self_refresh_active) {
> >>> +                           state->async_update = false;
> >>> +                           break;
> >>> +                   }
> >>> +           }
> >>> +   }
> >>> +   if (!state->allow_modeset) {
> >>> +           for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
> >>> +                   if (crtc_state->self_refresh_active) {
> >>> +                           state->allow_modeset = true;
> >>> +                           break;
> >>> +                   }
> >>> +           }
> >>> +   }
> >>> +
> >>> +   for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> >>> +           struct drm_self_refresh_state *sr_state;
> >>> +
> >>> +           /* Don't trigger the entry timer when we're already in SR */
> >>> +           if (crtc_state->self_refresh_active)
> >>> +                   continue;
> >>> +
> >>> +           sr_state = crtc->self_refresh_state;
> >>> +           mod_delayed_work(system_wq, &sr_state->entry_work,
> >>> +                    msecs_to_jiffies(sr_state->entry_delay_ms));
> >>> +   }
> >>> +}
> >>> +EXPORT_SYMBOL(drm_self_refresh_helper_alter_state);
> >>> +
> >>> +/**
> >>> + * drm_self_refresh_helper_register - Registers self refresh helpers for a crtc
> >>> + * @crtc: the crtc which supports self refresh supported displays
> >>> + * @entry_delay_ms: amount of inactivity to wait before entering self refresh
> >>> + */
> >>> +int drm_self_refresh_helper_register(struct drm_crtc *crtc,
> >>> +                                unsigned int entry_delay_ms)
> >>> +{
> >>> +   struct drm_self_refresh_state *sr_state = crtc->self_refresh_state;
> >>> +
> >>> +   /* Helper is already registered */
> >>> +   if (WARN_ON(sr_state))
> >>> +           return -EINVAL;
> >>> +
> >>> +   sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
> >>> +   if (!sr_state)
> >>> +           return -ENOMEM;
> >>> +
> >>> +   INIT_DELAYED_WORK(&sr_state->entry_work,
> >>> +                     drm_self_refresh_helper_entry_work);
> >>> +   sr_state->entry_delay_ms = entry_delay_ms;
> >>> +   sr_state->crtc = crtc;
> >>> +
> >>> +   crtc->self_refresh_state = sr_state;
> >>> +   return 0;
> >>> +}
> >>> +EXPORT_SYMBOL(drm_self_refresh_helper_register);
> >>> +
> >>> +/**
> >>> + * drm_self_refresh_helper_unregister - Unregisters self refresh helpers
> >>> + * @crtc: the crtc to unregister
> >>> + */
> >>> +void drm_self_refresh_helper_unregister(struct drm_crtc *crtc)
> >>> +{
> >>> +   struct drm_self_refresh_state *sr_state = crtc->self_refresh_state;
> >>> +
> >>> +   /* Helper is already unregistered */
> >>> +   if (sr_state)
> >>> +           return;
> >>> +
> >>> +   crtc->self_refresh_state = NULL;
> >>> +
> >>> +   cancel_delayed_work_sync(&sr_state->entry_work);
> >>> +   kfree(sr_state);
> >>> +}
> >>> +EXPORT_SYMBOL(drm_self_refresh_helper_unregister);
> >>> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> >>> index 824a5ed4e216..1e9cab1da97a 100644
> >>> --- a/include/drm/drm_atomic.h
> >>> +++ b/include/drm/drm_atomic.h
> >>> @@ -944,4 +944,19 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state)
> >>>            state->connectors_changed;
> >>>  }
> >>>
> >>> +/**
> >>> + * drm_atomic_crtc_effectively_active - compute whether crtc is actually active
> >>> + * @state: &drm_crtc_state for the CRTC
> >>> + *
> >>> + * When in self refresh mode, the crtc_state->active value will be false, since
> >>> + * the crtc is off. However in some cases we're interested in whether the crtc
> >>> + * is active, or effectively active (ie: it's connected to an active display).
> >>> + * In these cases, use this function instead of just checking active.
> >>> + */
> >>> +static inline bool
> >>> +drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)
> >>> +{
> >>> +   return state->active || state->self_refresh_active;
> >>> +}
> >>> +
> >>>  #endif /* DRM_ATOMIC_H_ */
> >>> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> >>> index c8061992d6cb..0ae7e812ec62 100644
> >>> --- a/include/drm/drm_connector.h
> >>> +++ b/include/drm/drm_connector.h
> >>> @@ -501,6 +501,37 @@ struct drm_connector_state {
> >>>     /** @tv: TV connector state */
> >>>     struct drm_tv_connector_state tv;
> >>>
> >>> +   /**
> >>> +    * @self_refresh_changed:
> >>> +    *
> >>> +    * Set true when self refresh status has changed. This is useful for
> >>> +    * use in encoder/bridge enable where the old state is unavailable to
> >>> +    * the driver and it needs to know whether the enable transition is a
> >>> +    * full transition, or if it just needs to exit self refresh mode.
> >>> +    */
> >>> +   bool self_refresh_changed;
> >>> +
> >>> +   /**
> >>> +    * @self_refresh_active:
> >>> +    *
> >>> +    * Used by the self refresh (SR) helpers to denote when the display
> >>> +    * should be self refreshing. If your connector is SR-capable, check
> >>> +    * this flag in .disable(). If it is true, instead of shutting off the
> >>> +    * panel, put it into self refreshing mode.
> >>> +    */
> >>> +   bool self_refresh_active;
> >>> +
> >>> +   /**
> >>> +    * @self_refresh_aware:
> >>> +    *
> >>> +    * This tracks whether a connector is aware of the self refresh state.
> >>> +    * It should be set to true for those connector implementations which
> >>> +    * understand the self refresh state. This is needed since the crtc
> >>> +    * registers the self refresh helpers and it doesn't know if the
> >>> +    * connectors downstream have implemented self refresh entry/exit.
> >>> +    */
> >>> +   bool self_refresh_aware;
> >>> +
> >>>     /**
> >>>      * @picture_aspect_ratio: Connector property to control the
> >>>      * HDMI infoframe aspect ratio setting.
> >>> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> >>> index f7c3022dbdf4..208d68129b4c 100644
> >>> --- a/include/drm/drm_crtc.h
> >>> +++ b/include/drm/drm_crtc.h
> >>> @@ -53,6 +53,7 @@ struct drm_mode_set;
> >>>  struct drm_file;
> >>>  struct drm_clip_rect;
> >>>  struct drm_printer;
> >>> +struct drm_self_refresh_state;
> >>>  struct device_node;
> >>>  struct dma_fence;
> >>>  struct edid;
> >>> @@ -299,6 +300,17 @@ struct drm_crtc_state {
> >>>      */
> >>>     bool vrr_enabled;
> >>>
> >>> +   /**
> >>> +    * @self_refresh_active:
> >>> +    *
> >>> +    * Used by the self refresh helpers to denote when a self refresh
> >>> +    * transition is occuring. This will be set on enable/disable callbacks
> >>> +    * when self refresh is being enabled or disabled. In some cases, it may
> >>> +    * not be desirable to fully shut off the crtc during self refresh.
> >>> +    * CRTC's can inspect this flag and determine the best course of action.
> >>> +    */
> >>> +   bool self_refresh_active;
> >>> +
> >>>     /**
> >>>      * @event:
> >>>      *
> >>> @@ -1087,6 +1099,13 @@ struct drm_crtc {
> >>>      * The name of the CRTC's fence timeline.
> >>>      */
> >>>     char timeline_name[32];
> >>> +
> >>> +   /**
> >>> +    * @self_refresh_state: Holds the state for the self refresh helpers
> >>> +    *
> >>> +    * Initialized via drm_self_refresh_helper_register().
> >>> +    */
> >>> +   struct drm_self_refresh_state *self_refresh_state;
> >>>  };
> >>>
> >>>  /**
> >>> diff --git a/include/drm/drm_self_refresh_helper.h b/include/drm/drm_self_refresh_helper.h
> >>> new file mode 100644
> >>> index 000000000000..015dacb8a807
> >>> --- /dev/null
> >>> +++ b/include/drm/drm_self_refresh_helper.h
> >>> @@ -0,0 +1,23 @@
> >>> +/* SPDX-License-Identifier: MIT */
> >>> +/*
> >>> + * Copyright (C) 2019 Google, Inc.
> >>> + *
> >>> + * Authors:
> >>> + * Sean Paul <seanpaul at chromium.org>
> >>> + */
> >>> +#ifndef DRM_SELF_REFRESH_HELPER_H_
> >>> +#define DRM_SELF_REFRESH_HELPER_H_
> >>> +
> >>> +struct drm_atomic_state;
> >>> +struct drm_connector;
> >>> +struct drm_device;
> >>> +struct drm_self_refresh_state;
> >>> +struct drm_modeset_acquire_ctx;
> >>> +
> >>> +void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state);
> >>> +
> >>> +int drm_self_refresh_helper_register(struct drm_crtc *crtc,
> >>> +                                unsigned int entry_delay_ms);
> >>> +
> >>> +void drm_self_refresh_helper_unregister(struct drm_crtc *crtc);
> >>> +#endif
> >>>
> >>
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel at lists.freedesktop.org
> >> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
>


-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch


More information about the dri-devel mailing list