From patchwork Tue Mar 26 20:44:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Paul X-Patchwork-Id: 10872171 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 782FB17E6 for ; Tue, 26 Mar 2019 20:45:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5D8CC28AD3 for ; Tue, 26 Mar 2019 20:45:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4D96528CC0; Tue, 26 Mar 2019 20:45:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D7F0528AD3 for ; Tue, 26 Mar 2019 20:45:15 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 76AE66E057; Tue, 26 Mar 2019 20:45:14 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-qt1-x841.google.com (mail-qt1-x841.google.com [IPv6:2607:f8b0:4864:20::841]) by gabe.freedesktop.org (Postfix) with ESMTPS id 921486E057 for ; Tue, 26 Mar 2019 20:45:12 +0000 (UTC) Received: by mail-qt1-x841.google.com with SMTP id t28so16338391qte.6 for ; Tue, 26 Mar 2019 13:45:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=IdgQ9UJ5SdSiJGi/xXR+llVk/SrOT4hFP6+sNuUNrXg=; b=exdMHwIyedXOlaQhPcG8opDeDDemqxCEiYm1vOKTdtiPbnlJ+zP/OoItywGxMc+XTg nkUUSxfCKBWeP/DWLnXEYiG39uJijZxcR9SoBzkWdo5eu/FGHn5+CLzMGCcTsHQwdpLQ S05fp64VA/8I2FDz86tsXnKcNcuYMMy/ryjPXw9/IW/d/9XCSV7Z6A4YuxKFd9KiGDgh GdmInuEusNhPT/NN3Bn17WoXjSvw/WGJNshI2LkPgtrWBFjxX1BA/ws1Xr1YfBmBcvmr SMiNcnJy27ib7UMpBuQWNhgap35gPD+fqRMFuRRM+kE8LCN2Ogv2+FJ2cBqjPJU5JHTz tUvw== X-Gm-Message-State: APjAAAW5UGVBoJvQSgHelM8EcT7z6a+7fK4Om0zAzq/FOVelNTCpeoiP gtL9xToxK79vAOB1OY3ep+LJdr0Mv68= X-Google-Smtp-Source: APXvYqyzw6pCzJFqv9AJ5zpiipJ5ZJ9xLnZPGyD0xWHN3Pn48ZGs1+Jhv1Q7rGm2Vnvq6Bp2AU2GKg== X-Received: by 2002:ac8:7647:: with SMTP id i7mr26230389qtr.38.1553633111336; Tue, 26 Mar 2019 13:45:11 -0700 (PDT) Received: from rosewood.cam.corp.google.com ([2620:0:1013:11:89c6:2139:5435:371d]) by smtp.gmail.com with ESMTPSA id i11sm9405810qkg.33.2019.03.26.13.45.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 26 Mar 2019 13:45:10 -0700 (PDT) From: Sean Paul To: dri-devel@lists.freedesktop.org Subject: [PATCH v2 1/5] drm: Add helpers to kick off self refresh mode in drivers Date: Tue, 26 Mar 2019 16:44:54 -0400 Message-Id: <20190326204509.96515-1-sean@poorly.run> X-Mailer: git-send-email 2.21.0.392.gf8f6787159e-goog MIME-Version: 1.0 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=poorly.run; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=IdgQ9UJ5SdSiJGi/xXR+llVk/SrOT4hFP6+sNuUNrXg=; b=VsskmdRIc7ZYJV0u5dcaXKCauV7xW3NA2zgkyk9yYKRhTYn9ZU9ILH9dYQFuTVKysu OEoTHPEze4WnzZSkmCYSk9X84Bb2oCe1gVZ7FgWinO/rWTRxszVm63ruNkAdvok1nC+F jO5X036ycRRSub8/pq/PIzFWXNi1cSGPls9oiT5svEhXkM2ZxKkBArNvmThTFWgmebgG th4gxyvnrV7LTyaYt1hyG4ARoE03A6Kly6ArZZxH2Q4N7vOz2caiQ1UgcSpnd/hd+vuP 4l8vQnRSAKTTzAycNBpmGYF6uyYdx6h40s9/04lEPn4Zg9YK/tB+Ph1/2caoIZo2kQYv zU1Q== X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Zain Wang , David Airlie , Jose Souza , Tomasz Figa , Maxime Ripard , Sean Paul , Sean Paul Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Sean Paul 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. 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 Cc: Jose Souza Cc: Zain Wang Cc: Tomasz Figa Signed-off-by: Sean Paul --- 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 #include #include +#include #include #include #include @@ -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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * 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 + */ +#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