On Thu, 2019-02-28 at 16:09 -0500, Sean Paul wrote: > From: Sean Paul <seanp...@chromium.org> > > This patch adds a new drm helper library to help drivers implement > PSR. Drivers choosing to use it will register connectors with > PSR-capable displays connected and will receive callbacks when it's > time > to enter or exit PSR.
This helpers should target connector not the entire driver, a modification in any sink would cause a PSR exit in all PSR panels. Also do atomic commit in drm_psr_helper_flush() that is called from another atomic commit sounds wrong. During the atomic checks it should probably just set enable and active states of drm_crtc_state and the CRTC would be active when committing changes. > > 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 save the current atomic state and issue a new state > which > has the PSR-enabled pipes turned off. On the next update, the drm > core > will poke the PSR helpers to restore the saved state to the driver > before > servicing said update. > > From the driver's perspective, this works like a regular > disable/enable > cycle. The driver need only check the 'psr_transition' state in > connector_state and keep the panel turned on when in .disable(), > while > everything else will cycle off as normal. If drivers want more > control, > they can use the psr_transition state to enter a low-power state to > minimize PSR exit time. > > While this carries the PSR moniker, it is not specific to the > DisplayPort technology. This can be used for power savings with other > types of self refresh, such as MIPI command mode. > > Cc: Zain Wang <w...@rock-chips.com> > Cc: Tomasz Figa <tf...@chromium.org> > Signed-off-by: Sean Paul <seanp...@chromium.org> > --- > Documentation/gpu/drm-kms-helpers.rst | 9 + > drivers/gpu/drm/Makefile | 2 +- > drivers/gpu/drm/drm_atomic_helper.c | 34 +++ > drivers/gpu/drm/drm_atomic_uapi.c | 5 + > drivers/gpu/drm/drm_fb_helper.c | 9 + > drivers/gpu/drm/drm_framebuffer.c | 18 ++ > drivers/gpu/drm/drm_psr_helper.c | 343 > ++++++++++++++++++++++++++ > include/drm/drm_connector.h | 22 ++ > include/drm/drm_crtc.h | 11 + > include/drm/drm_mode_config.h | 6 + > include/drm/drm_psr_helper.h | 24 ++ > 11 files changed, 482 insertions(+), 1 deletion(-) > create mode 100644 drivers/gpu/drm/drm_psr_helper.c > create mode 100644 include/drm/drm_psr_helper.h > > diff --git a/Documentation/gpu/drm-kms-helpers.rst > b/Documentation/gpu/drm-kms-helpers.rst > index 17ca7f8bf3d3..d218a113bd52 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_psr_helper.c > + :doc: overview > + > +.. kernel-doc:: drivers/gpu/drm/drm_psr_helper.c > + :export: > + > Framebuffer CMA Helper Functions Reference > ========================================== > > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile > index 1ac55c65eac0..bff80fb946c7 100644 > --- a/drivers/gpu/drm/Makefile > +++ b/drivers/gpu/drm/Makefile > @@ -19,7 +19,7 @@ drm-y := drm_auth.o drm_bufs.o > drm_cache.o \ > drm_plane.o drm_color_mgmt.o drm_print.o \ > drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ > drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o > \ > - drm_atomic_uapi.o > + drm_atomic_uapi.o drm_psr_helper.o > > drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o > drm-$(CONFIG_DRM_VM) += drm_vm.o > diff --git a/drivers/gpu/drm/drm_atomic_helper.c > b/drivers/gpu/drm/drm_atomic_helper.c > index c53ecbd9abdd..f5284d55f170 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_psr_helper.h> > #include <drm/drm_writeback.h> > #include <drm/drm_damage_helper.h> > #include <linux/dma-fence.h> > @@ -2746,6 +2747,10 @@ int drm_atomic_helper_update_plane(struct > drm_plane *plane, > struct drm_plane_state *plane_state; > int ret = 0; > > + ret = drm_psr_helper_flush(plane->dev, ctx); > + if (ret) > + return ret; > + > state = drm_atomic_state_alloc(plane->dev); > if (!state) > return -ENOMEM; > @@ -2797,6 +2802,10 @@ int drm_atomic_helper_disable_plane(struct > drm_plane *plane, > struct drm_plane_state *plane_state; > int ret = 0; > > + ret = drm_psr_helper_flush(plane->dev, ctx); > + if (ret) > + return ret; > + > state = drm_atomic_state_alloc(plane->dev); > if (!state) > return -ENOMEM; > @@ -2934,11 +2943,16 @@ int drm_atomic_helper_set_config(struct > drm_mode_set *set, > struct drm_crtc *crtc = set->crtc; > int ret = 0; > > + ret = drm_psr_helper_flush(crtc->dev, ctx); > + if (ret) > + return ret; > + > state = drm_atomic_state_alloc(crtc->dev); > if (!state) > return -ENOMEM; > > state->acquire_ctx = ctx; > + > ret = __drm_atomic_helper_set_config(set, state); > if (ret != 0) > goto fail; > @@ -3139,6 +3153,10 @@ void drm_atomic_helper_shutdown(struct > drm_device *dev) > > DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); > > + ret = drm_psr_helper_flush(dev, &ctx); > + if (ret) > + DRM_ERROR("PSR flush during shutdown failed with %i\n", > ret); > + > ret = __drm_atomic_helper_disable_all(dev, &ctx, true); > if (ret) > DRM_ERROR("Disabling all crtc's during unload failed > with %i\n", ret); > @@ -3271,6 +3289,10 @@ struct drm_atomic_state > *drm_atomic_helper_suspend(struct drm_device *dev) > > DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); > > + err = drm_psr_helper_flush(dev, &ctx); > + if (err) > + goto unlock; > + > state = drm_atomic_helper_duplicate_state(dev, &ctx); > if (IS_ERR(state)) > goto unlock; > @@ -3436,6 +3458,10 @@ int drm_atomic_helper_page_flip(struct > drm_crtc *crtc, > struct drm_atomic_state *state; > int ret = 0; > > + ret = drm_psr_helper_flush(crtc->dev, ctx); > + if (ret) > + return ret; > + > state = drm_atomic_state_alloc(plane->dev); > if (!state) > return -ENOMEM; > @@ -3481,6 +3507,10 @@ int drm_atomic_helper_page_flip_target(struct > drm_crtc *crtc, > struct drm_crtc_state *crtc_state; > int ret = 0; > > + ret = drm_psr_helper_flush(plane->dev, ctx); > + if (ret) > + return ret; > + > state = drm_atomic_state_alloc(plane->dev); > if (!state) > return -ENOMEM; > @@ -3532,6 +3562,10 @@ int drm_atomic_helper_legacy_gamma_set(struct > drm_crtc *crtc, > int i, ret = 0; > bool replaced; > > + ret = drm_psr_helper_flush(dev, ctx); > + if (ret) > + return ret; > + > state = drm_atomic_state_alloc(crtc->dev); > if (!state) > return -ENOMEM; > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c > b/drivers/gpu/drm/drm_atomic_uapi.c > index 4eb81f10bc54..21d7771d6ec7 100644 > --- a/drivers/gpu/drm/drm_atomic_uapi.c > +++ b/drivers/gpu/drm/drm_atomic_uapi.c > @@ -29,6 +29,7 @@ > #include <drm/drm_atomic_uapi.h> > #include <drm/drm_atomic.h> > #include <drm/drm_print.h> > +#include <drm/drm_psr_helper.h> > #include <drm/drm_drv.h> > #include <drm/drm_writeback.h> > #include <drm/drm_vblank.h> > @@ -1314,6 +1315,10 @@ int drm_mode_atomic_ioctl(struct drm_device > *dev, > fence_state = NULL; > num_fences = 0; > > + ret = drm_psr_helper_flush(dev, state->acquire_ctx); > + if (ret) > + goto out; > + > for (i = 0; i < arg->count_objs; i++) { > uint32_t obj_id, count_props; > struct drm_mode_object *obj; > diff --git a/drivers/gpu/drm/drm_fb_helper.c > b/drivers/gpu/drm/drm_fb_helper.c > index 04d23cb430bf..a56ae2acda90 100644 > --- a/drivers/gpu/drm/drm_fb_helper.c > +++ b/drivers/gpu/drm/drm_fb_helper.c > @@ -41,6 +41,7 @@ > #include <drm/drm_crtc_helper.h> > #include <drm/drm_atomic.h> > #include <drm/drm_atomic_helper.h> > +#include <drm/drm_psr_helper.h> > > #include "drm_crtc_internal.h" > #include "drm_crtc_helper_internal.h" > @@ -406,6 +407,10 @@ static int restore_fbdev_mode_atomic(struct > drm_fb_helper *fb_helper, bool activ > > state->acquire_ctx = &ctx; > retry: > + ret = drm_psr_helper_flush(dev, state->acquire_ctx); > + if (ret) > + goto out_state; > + > drm_for_each_plane(plane, dev) { > plane_state = drm_atomic_get_plane_state(state, plane); > if (IS_ERR(plane_state)) { > @@ -1442,6 +1447,10 @@ static int setcmap_atomic(struct fb_cmap > *cmap, struct fb_info *info) > > state->acquire_ctx = &ctx; > retry: > + ret = drm_psr_helper_flush(dev, &ctx); > + if (ret) > + goto out_state; > + > for (i = 0; i < fb_helper->crtc_count; i++) { > crtc = fb_helper->crtc_info[i].mode_set.crtc; > > diff --git a/drivers/gpu/drm/drm_framebuffer.c > b/drivers/gpu/drm/drm_framebuffer.c > index d8d75e25f6fb..43b029a88578 100644 > --- a/drivers/gpu/drm/drm_framebuffer.c > +++ b/drivers/gpu/drm/drm_framebuffer.c > @@ -27,6 +27,7 @@ > #include <drm/drm_atomic.h> > #include <drm/drm_atomic_uapi.h> > #include <drm/drm_print.h> > +#include <drm/drm_psr_helper.h> > #include <drm/drm_util.h> > > #include "drm_internal.h" > @@ -572,6 +573,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device > *dev, > struct drm_clip_rect __user *clips_ptr; > struct drm_clip_rect *clips = NULL; > struct drm_mode_fb_dirty_cmd *r = data; > + struct drm_modeset_acquire_ctx ctx; > struct drm_framebuffer *fb; > unsigned flags; > int num_clips; > @@ -580,10 +582,24 @@ int drm_mode_dirtyfb_ioctl(struct drm_device > *dev, > if (!drm_core_check_feature(dev, DRIVER_MODESET)) > return -EOPNOTSUPP; > > + drm_modeset_acquire_init(&ctx, 0); > + > fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id); > if (!fb) > return -ENOENT; > > +retry: > + ret = drm_psr_helper_flush(fb->dev, &ctx); > + if (ret) { > + if (ret == -EDEADLK) { > + ret = drm_modeset_backoff(&ctx); > + if (!ret) > + goto retry; > + } else { > + goto out_err1; > + } > + } > + > num_clips = r->num_clips; > clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r- > >clips_ptr; > > @@ -630,6 +646,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device > *dev, > kfree(clips); > out_err1: > drm_framebuffer_put(fb); > + drm_modeset_drop_locks(&ctx); > + drm_modeset_acquire_fini(&ctx); > > return ret; > } > diff --git a/drivers/gpu/drm/drm_psr_helper.c > b/drivers/gpu/drm/drm_psr_helper.c > new file mode 100644 > index 000000000000..0b57a2a53075 > --- /dev/null > +++ b/drivers/gpu/drm/drm_psr_helper.c > @@ -0,0 +1,343 @@ > +/* SPDX-License-Identifier: MIT */ > +/* > + * Copyright (C) 2019 Google, Inc. > + * > + * Authors: > + * Sean Paul <seanp...@chromium.org> > + */ > +#include <drm/drm_atomic.h> > +#include <drm/drm_atomic_helper.h> > +#include <drm/drm_connector.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_psr_helper.h> > +#include <linux/bitops.h> > +#include <linux/mutex.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 (PSR) support. Drivers > are > + * responsible for intializing and cleaning up the PSR helpers on > load/unload. > + * When drivers identify a display that supports self refreshing > (eDP or MIPI > + * command mode), it should register the affected connector with the > PSR > + * helpers. > + * > + * Once a connector is registered, the PSR helpers will monitor > activity and > + * call back into the driver to enable/disable PSR 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 PSR on the panel instead > of power- > + * cycling it. > + * > + * Drivers may choose to fully disable their crtc/encoder/bridge > hardware, or > + * they can use the "psr_transition" flag in crtc and connector > state if they > + * want to enter low power mode without full disable (in case full > + * disable/enable is too slow). > + * > + * PSR will be deactivated if there are any atomic updates, even > updates that do > + * not affect the connectors which are self refreshing. Supporting > this is > + * possible but non-trivial due to sharing of hardware resources. > Similarly, if > + * a crtc is driving multiple connectors, PSR will not be initiated > on any of > + * those connectors. > + */ > + > +struct drm_psr_state { > + struct drm_device *dev; > + struct drm_modeset_lock mutex; > + struct delayed_work entry_work; > + struct drm_atomic_state *save_state; > + unsigned int entry_delay_ms; > +}; > + > +static void drm_psr_helper_entry_work(struct work_struct *work) > +{ > + struct drm_psr_state *psr_state = > container_of(to_delayed_work(work), > + struct > drm_psr_state, > + entry_work); > + struct drm_atomic_state *save_state; > + struct drm_device *dev = psr_state->dev; > + struct drm_modeset_acquire_ctx ctx; > + struct drm_atomic_state *state; > + struct drm_connector *conn; > + struct drm_connector_list_iter conn_iter; > + struct drm_connector_state *conn_state; > + struct drm_crtc *crtc; > + struct drm_crtc_state *crtc_state; > + bool commit = false; > + int ret, i; > + > + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); > + > + ret = drm_modeset_lock(&psr_state->mutex, &ctx); > + if (ret) > + goto out; > + > + /* > + * The only way this can happen is if we schedule the worker > while it's > + * already running and that timeout subsequently elapses. Since > we hold > + * the psr_state->mutex when scheduling, we also know where the > worker > + * is sitting in its execution (hint: look up). In this case, > it's > + * possible for the entry worker to run twice for the same > commit. Since > + * the hardware hasn't changed since the last save state, just > kick out. > + */ > + if (psr_state->save_state) > + goto out; > + > + state = drm_atomic_state_alloc(dev); > + if (!state) { > + ret = -ENOMEM; > + goto out; > + } > + > + save_state = drm_atomic_helper_duplicate_state(dev, &ctx); > + > + /* > + * Now that we have the current the HW state saved, we have to > flip the > + * psr_transition bit so we know what type of enable we're > dealing with > + * when coming back on. > + * > + * NOTE: We don't check conn->capable here since that could > change out > + * from under us. We'll trust the atomic core to only call > enable if > + * necessary (ie: only for those connectors/crtcs that > currently have > + * psr enabled). > + */ > + if (IS_ERR(save_state)) { > + ret = PTR_ERR(save_state); > + goto out; > + } > + for_each_new_connector_in_state(save_state, conn, conn_state, > i) { > + if (!conn_state->crtc) > + continue; > + conn_state->psr_transition = true; > + } > + for_each_new_crtc_in_state(save_state, crtc, crtc_state, i) { > + if (!crtc_state->active) > + continue; > + crtc_state->psr_transition = true; > + } > + > + state->acquire_ctx = &ctx; > + drm_connector_list_iter_begin(psr_state->dev, &conn_iter); > + drm_for_each_connector_iter(conn, &conn_iter) { > + if (!conn->psr_capable) > + continue; > + > + conn_state = drm_atomic_get_connector_state(state, > conn); > + if (IS_ERR(conn_state)) { > + ret = PTR_ERR(conn_state); > + drm_connector_list_iter_end(&conn_iter); > + goto out_free_state; > + } > + > + if (!conn_state->crtc) > + continue; > + > + crtc_state = drm_atomic_get_crtc_state(state, > conn_state->crtc); > + if (IS_ERR(crtc_state)) { > + ret = PTR_ERR(crtc_state); > + drm_connector_list_iter_end(&conn_iter); > + goto out_free_state; > + } > + > + /* Don't use PSR if the crtc is driving multiple > connectors */ > + if (hweight_long(crtc_state->connector_mask) > 1) > + continue; > + > + commit = true; > + crtc_state->active = false; > + crtc_state->psr_transition = true; > + conn_state->psr_transition = true; > + } > + drm_connector_list_iter_end(&conn_iter); > + > + /* Nothing to commit, so just exit */ > + if (!commit) > + goto out_free_state; > + > + ret = drm_atomic_commit(state); > + if (ret) > + goto out_free_state; > + > + psr_state->save_state = save_state; > + goto out; > + > +out_free_state: > + drm_atomic_state_put(save_state); > + drm_atomic_state_put(state); > +out: > + DRM_MODESET_LOCK_ALL_END(ctx, ret); > +} > + > +static int > +drm_psr_helper_acquire_modeset_locks(struct drm_atomic_state *state, > + struct drm_modeset_acquire_ctx > *ctx) > +{ > + struct drm_mode_config *config = &state->dev->mode_config; > + struct drm_crtc *crtc; > + struct drm_crtc_state *new_crtc_state; > + struct drm_plane *plane; > + struct drm_plane_state *new_plane_state; > + int ret, i; > + > + ret = drm_modeset_lock(&config->connection_mutex, ctx); > + if (ret) > + return ret; > + > + for_each_new_plane_in_state(state, plane, new_plane_state, i) { > + ret = drm_modeset_lock(&plane->mutex, ctx); > + if (ret) > + return ret; > + } > + > + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { > + ret = drm_modeset_lock(&crtc->mutex, ctx); > + if (ret) > + return ret; > + } > + return 0; > +} > + > +/** > + * drm_psr_helper_flush - Restore the hardware to pre-PSR state > + * @dev: DRM device > + * @ctx: An acquire context to use for restoring the state > + * > + * This function should be called before every drm_atomic_commit to > ensure any > + * connectors that are currently self-refreshing revert back to > being bus > + * driven. Drivers may call this function outside of the atomic > hooks if > + * they wish to disable PSR pre-emptively (such as upon an input > event or when > + * GPU becomes active). > + * > + * If everything is successful, this function will schedule the PSR > entry worker > + * to enable PSR after the driver-specified timeout. > + * > + * If the PSR helper is not being used, this is a no-op. > + */ > +int drm_psr_helper_flush(struct drm_device *dev, > + struct drm_modeset_acquire_ctx *ctx) > +{ > + struct drm_mode_config *config = &dev->mode_config; > + struct drm_psr_state *psr_state = config->psr_state; > + int ret; > + > + if (!psr_state) > + return 0; > + > + ret = drm_modeset_lock(&psr_state->mutex, ctx); > + if (ret) > + return ret; > + > + if (!psr_state->save_state) > + goto out; > + > + ret = drm_psr_helper_acquire_modeset_locks(psr_state- > >save_state, ctx); > + if (ret) > + goto out; > + > + ret = drm_atomic_helper_commit_duplicated_state(psr_state- > >save_state, > + ctx); > + > +out: > + psr_state->save_state = NULL; > + if (!ret) { > + mod_delayed_work(system_wq, &psr_state->entry_work, > + msecs_to_jiffies(psr_state- > >entry_delay_ms)); > + } > + return ret; > +} > +EXPORT_SYMBOL(drm_psr_helper_flush); > + > +/** > + * drm_psr_helper_register - Registers a connector with the PSR > helpers > + * @connector: the connector which has a PSR-supported display > attached > + * > + * Note that this can be called once on initialization for fixed > panels, or > + * during enable/hotplug. > + */ > +int drm_psr_helper_register(struct drm_connector *connector) > +{ > + struct drm_mode_config *config = &connector->dev->mode_config; > + struct drm_psr_state *psr_state = config->psr_state; > + > + /* PSR helpers are uninitialized */ > + if (WARN_ON(!psr_state)) > + return -EINVAL; > + > + /* Acquired via psr_helper_flush */ > + if (!drm_modeset_is_locked(&psr_state->mutex)) > + return -EINVAL; > + > + connector->psr_capable = true; > + return 0; > +} > +EXPORT_SYMBOL(drm_psr_helper_register); > + > +/** > + * drm_psr_helper_unregister - Unregisters a connector with the PSR > helpers > + * @connector: the connector to unregister > + */ > +int drm_psr_helper_unregister(struct drm_connector *connector) > +{ > + struct drm_mode_config *config = &connector->dev->mode_config; > + struct drm_psr_state *psr_state = config->psr_state; > + > + /* PSR helpers are uninitialized */ > + if (WARN_ON(!psr_state)) > + return -EINVAL; > + > + /* Acquired via psr_helper_flush */ > + if (!drm_modeset_is_locked(&psr_state->mutex)) > + return -EINVAL; > + > + connector->psr_capable = false; > + return 0; > +} > +EXPORT_SYMBOL(drm_psr_helper_unregister); > + > +/** > + * drm_psr_helper_init - Initializes the PSR helpers > + * @dev: DRM device > + * @entry_delay_ms: The amount of time to wait after an atomic > commit before > + * activating PSR > + * > + * Drivers using the PSR helpers must call this some time after > mode_config > + * is initialized in order to make use of the PSR helpers. Typically > + * entry_delay_ms is a function of how quickly the hardware can > enter/exit PSR. > + */ > +int drm_psr_helper_init(struct drm_device *dev, unsigned int > entry_delay_ms) > +{ > + struct drm_mode_config *config = &dev->mode_config; > + struct drm_psr_state *psr_state; > + > + psr_state = kzalloc(sizeof(*psr_state), GFP_KERNEL); > + if (!psr_state) > + return -ENOMEM; > + > + INIT_DELAYED_WORK(&psr_state->entry_work, > drm_psr_helper_entry_work); > + drm_modeset_lock_init(&psr_state->mutex); > + psr_state->dev = dev; > + psr_state->entry_delay_ms = entry_delay_ms; > + > + config->psr_state = psr_state; > + return 0; > +} > +EXPORT_SYMBOL(drm_psr_helper_init); > + > +/** > + * drm_psr_helper_cleanup - De-initializes the PSR helpers > + * @dev: DRM device > + */ > +void drm_psr_helper_cleanup(struct drm_device *dev) > +{ > + struct drm_mode_config *config = &dev->mode_config; > + > + cancel_delayed_work_sync(&config->psr_state->entry_work); > + kfree(config->psr_state); > + config->psr_state = NULL; > +} > +EXPORT_SYMBOL(drm_psr_helper_cleanup); > diff --git a/include/drm/drm_connector.h > b/include/drm/drm_connector.h > index c8061992d6cb..9612b3d56f30 100644 > --- a/include/drm/drm_connector.h > +++ b/include/drm/drm_connector.h > @@ -501,6 +501,17 @@ struct drm_connector_state { > /** @tv: TV connector state */ > struct drm_tv_connector_state tv; > > + /** > + * @psr_transition: > + * > + * Used by the PSR helpers to denote when a PSR transition is > occuring. > + * If your connector is PSR-capable, register it with the > helpers and > + * check this flag in .enable() and .disable(). If it is true, > instead > + * of shutting off the panel, put it in or take it out of self > + * refreshing mode. > + */ > + bool psr_transition; > + > /** > * @picture_aspect_ratio: Connector property to control the > * HDMI infoframe aspect ratio setting. > @@ -993,6 +1004,17 @@ struct drm_connector { > */ > struct drm_display_info display_info; > > + /** > + * @psr_capable: > + * > + * Set by the driver via drm_psr_helper_register(). Signals > that this > + * connector (and associated pipe) is PSR capable and should be > put in > + * low-power mode when it is inactive. > + * > + * Protected by &drm_mode_config.psr_state.mutex > + */ > + bool psr_capable; > + > /** @funcs: connector control functions */ > const struct drm_connector_funcs *funcs; > > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h > index f7c3022dbdf4..10acd4fc0991 100644 > --- a/include/drm/drm_crtc.h > +++ b/include/drm/drm_crtc.h > @@ -299,6 +299,17 @@ struct drm_crtc_state { > */ > bool vrr_enabled; > > + /** > + * @psr_transition: > + * > + * Used by the PSR helpers to denote when a PSR transition is > occuring. > + * This will be set on enable/disable callbacks when PSR is > being > + * enabled or disabled. In some cases, it may not be desirable > to fully > + * shut off the crtc during PSR. CRTC's can inspect this flag > and > + * determine the best course of action. > + */ > + bool psr_transition; > + > /** > * @event: > * > diff --git a/include/drm/drm_mode_config.h > b/include/drm/drm_mode_config.h > index 7f60e8eb269a..371b80d090ab 100644 > --- a/include/drm/drm_mode_config.h > +++ b/include/drm/drm_mode_config.h > @@ -37,6 +37,7 @@ struct drm_atomic_state; > struct drm_mode_fb_cmd2; > struct drm_format_info; > struct drm_display_mode; > +struct drm_psr_state; > > /** > * struct drm_mode_config_funcs - basic driver provided mode setting > functions > @@ -900,6 +901,11 @@ struct drm_mode_config { > */ > struct drm_atomic_state *suspend_state; > > + /** > + * @psr_state: Holds the state for the psr helper > + */ > + struct drm_psr_state *psr_state; > + > const struct drm_mode_config_helper_funcs *helper_private; > }; > > diff --git a/include/drm/drm_psr_helper.h > b/include/drm/drm_psr_helper.h > new file mode 100644 > index 000000000000..972c4ec98d05 > --- /dev/null > +++ b/include/drm/drm_psr_helper.h > @@ -0,0 +1,24 @@ > +/* SPDX-License-Identifier: MIT */ > +/* > + * Copyright (C) 2019 Google, Inc. > + * > + * Authors: > + * Sean Paul <seanp...@chromium.org> > + */ > +#ifndef DRM_PSR_HELPER_H_ > +#define DRM_PSR_HELPER_H_ > + > +struct drm_connector; > +struct drm_device; > +struct drm_psr_state; > +struct drm_modeset_acquire_ctx; > + > +int drm_psr_helper_flush(struct drm_device *dev, > + struct drm_modeset_acquire_ctx *ctx); > + > +int drm_psr_helper_register(struct drm_connector *connector); > +int drm_psr_helper_unregister(struct drm_connector *connector); > + > +int drm_psr_helper_init(struct drm_device *dev, unsigned int > entry_delay_ms); > +void drm_psr_helper_cleanup(struct drm_device *dev); > +#endif
signature.asc
Description: This is a digitally signed message part
_______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel