summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMidas Chien <midaschieh@google.com>2024-01-05 11:40:53 +0000
committerMidas Chien <midaschieh@google.com>2024-01-17 06:23:57 +0000
commitd460f686f4ff55f3cb38a417fa78380c0bee1be7 (patch)
tree27ff833183d3e6e6c429c09277b06de37a9d90ce
parenta51d2acbe6bd7dc96a3f04b968283a35b02992cc (diff)
downloaddisplay-android-gs-bluejay-5.10-android14-qpr3-beta.tar.gz
While sysfs_notify initiates updates for state monitors upon state changes, timely data updates can be hindered if user space processes are frozen during notification. Support a mechanism to awaken the system during notification if it need to ensure timely updates. Bug: 311495944 Test: check refresh rate indicator is correct Change-Id: I86d1f6e2e72bb54c10d394bd2634ce51147189e4 Signed-off-by: Midas Chien <midaschieh@google.com> (cherry picked from commit 5cdb5034e2360b17e8cad80e7d5b5902c8ccfba3)
-rw-r--r--samsung/panel/Documentation/ABI/testing/sysfs-devices-platform-exynos-drm10
-rw-r--r--samsung/panel/panel-boe-nt37290.c4
-rw-r--r--samsung/panel/panel-samsung-drv.c56
-rw-r--r--samsung/panel/panel-samsung-drv.h15
-rw-r--r--samsung/panel/panel-samsung-s6e3hc3-c10.c2
-rw-r--r--samsung/panel/panel-samsung-s6e3hc3.c6
-rw-r--r--samsung/panel/panel-samsung-s6e3hc4.c4
7 files changed, 80 insertions, 17 deletions
diff --git a/samsung/panel/Documentation/ABI/testing/sysfs-devices-platform-exynos-drm b/samsung/panel/Documentation/ABI/testing/sysfs-devices-platform-exynos-drm
index b9d7b13..3485a4a 100644
--- a/samsung/panel/Documentation/ABI/testing/sysfs-devices-platform-exynos-drm
+++ b/samsung/panel/Documentation/ABI/testing/sysfs-devices-platform-exynos-drm
@@ -15,3 +15,13 @@ Description:
The file provides the available display stats state.
Valid panels are 'primary-panel' or 'secondary-panel'.
+
+What: /sys/class/backlight/<panel>-backlight/allow_wakeup_by_state_change
+Date: January 2024
+KernelVersion: 5.10
+Contact: "Midas Chien" <midaschieh@google.com>
+Description:
+ The file specifies whether the system can be awakened to receive
+ notifications regarding backlight state changes.
+
+ Valid panels are 'panel0' or 'panel1'.
diff --git a/samsung/panel/panel-boe-nt37290.c b/samsung/panel/panel-boe-nt37290.c
index 17e6b8e..1dfdce5 100644
--- a/samsung/panel/panel-boe-nt37290.c
+++ b/samsung/panel/panel-boe-nt37290.c
@@ -730,7 +730,7 @@ static bool nt37290_change_frequency(struct exynos_panel *ctx,
ctx->panel_idle_vrefresh = ctx->self_refresh_active ? spanel->hw_idle_vrefresh : 0;
if (updated) {
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
te2_state_changed(ctx->bl);
dev_dbg(ctx->dev, "change to %dHz, idle %s, was_lp_mode %d\n",
vrefresh, idle_active ? "active" : "deactive", was_lp_mode);
@@ -771,7 +771,7 @@ static bool nt37290_set_self_refresh(struct exynos_panel *ctx, bool enable)
if (pmode->exynos_mode.is_lp_mode) {
/* set 10Hz while self refresh is active, otherwise clear it */
ctx->panel_idle_vrefresh = enable ? 10 : 0;
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, true);
return false;
}
diff --git a/samsung/panel/panel-samsung-drv.c b/samsung/panel/panel-samsung-drv.c
index 60cfaec..968c844 100644
--- a/samsung/panel/panel-samsung-drv.c
+++ b/samsung/panel/panel-samsung-drv.c
@@ -2024,7 +2024,7 @@ static void exynos_panel_pre_commit_properties(
DPU_ATRACE_BEGIN("set_hbm");
mutex_lock(&ctx->mode_lock);
exynos_panel_func->set_hbm_mode(ctx, conn_state->global_hbm_mode);
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
mutex_unlock(&ctx->mode_lock);
DPU_ATRACE_END("set_hbm");
ghbm_updated = true;
@@ -2824,7 +2824,7 @@ static ssize_t hbm_mode_store(struct device *dev,
if (hbm_mode != ctx->hbm_mode) {
funcs->set_hbm_mode(ctx, hbm_mode);
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
}
unlock:
@@ -3253,6 +3253,34 @@ static ssize_t als_table_show(struct device *dev,
static DEVICE_ATTR_RW(als_table);
+static ssize_t allow_wakeup_by_state_change_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct backlight_device *bd = to_backlight_device(dev);
+ struct exynos_panel *ctx = bl_get_data(bd);
+ int ret;
+
+ ret = kstrtobool(buf, &ctx->allow_wakeup_by_state_change);
+ if (ret) {
+ dev_err(ctx->dev, "invalid allow wakeup by state change value\n");
+ return ret;
+ }
+
+ return count;
+}
+
+static ssize_t allow_wakeup_by_state_change_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct backlight_device *bd = to_backlight_device(dev);
+ struct exynos_panel *ctx = bl_get_data(bd);
+
+ return sysfs_emit_at(buf, 0, "%d\n", ctx->allow_wakeup_by_state_change);
+}
+
+static DEVICE_ATTR_RW(allow_wakeup_by_state_change);
+
static struct attribute *bl_device_attrs[] = {
&dev_attr_hbm_mode.attr,
&dev_attr_dimming_on.attr,
@@ -3263,6 +3291,7 @@ static struct attribute *bl_device_attrs[] = {
&dev_attr_lp_state.attr,
&dev_attr_te2_state.attr,
&dev_attr_als_table.attr,
+ &dev_attr_allow_wakeup_by_state_change.attr,
NULL,
};
ATTRIBUTE_GROUPS(bl_device);
@@ -3331,7 +3360,7 @@ static void exynos_panel_set_backlight_state(struct exynos_panel *ctx,
mutex_unlock(&ctx->bl_state_lock);
if (state_changed) {
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
dev_info(ctx->dev, "panel: %s | bl: brightness@%u, state@0x%x\n",
exynos_panel_get_state_str(panel_state), bl->props.brightness,
bl->props.state);
@@ -4143,7 +4172,7 @@ static void exynos_panel_bridge_mode_set(struct drm_bridge *bridge,
exynos_panel_set_backlight_state(
ctx, is_active ? PANEL_STATE_NORMAL : PANEL_STATE_OFF);
else if (ctx->bl)
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
if (!is_lp_mode)
exynos_panel_update_te2(ctx);
@@ -4615,10 +4644,20 @@ static int disp_stats_update_state(struct exynos_panel *ctx)
static void notify_panel_mode_changed_worker(struct work_struct *work)
{
+ struct notify_state_change *notify_state_change =
+ container_of(work, struct notify_state_change, work);
struct exynos_panel *ctx =
- container_of(work, struct exynos_panel, notify_panel_mode_changed_work);
+ container_of(notify_state_change, struct exynos_panel, notify_panel_mode_changed);
disp_stats_update_state(ctx);
+
+ if (ctx->allow_wakeup_by_state_change && notify_state_change->abort_suspend) {
+ if (unlikely(!notify_state_change->ws))
+ dev_warn(ctx->dev, "wakeup source creation was unsuccessful\n");
+ else
+ pm_wakeup_ws_event(notify_state_change->ws, 0, true);
+ }
+
sysfs_notify(&ctx->bl->dev.kobj, NULL, "state");
}
@@ -4653,6 +4692,11 @@ int exynos_panel_common_init(struct mipi_dsi_device *dsi,
dev_err(ctx->dev, "failed to register backlight device\n");
return PTR_ERR(ctx->bl);
}
+
+ ctx->notify_panel_mode_changed.ws = wakeup_source_register(dev, name);
+ if (!ctx->notify_panel_mode_changed.ws)
+ dev_warn(ctx->dev, "failed to register `%s` wakeup source\n", name);
+
ctx->bl->props.max_brightness = ctx->desc->max_brightness;
ctx->bl->props.brightness = ctx->desc->dft_brightness;
@@ -4688,7 +4732,7 @@ int exynos_panel_common_init(struct mipi_dsi_device *dsi,
ctx->panel_idle_enabled = exynos_panel_func && exynos_panel_func->set_self_refresh != NULL;
INIT_DELAYED_WORK(&ctx->idle_work, panel_idle_work);
- INIT_WORK(&ctx->notify_panel_mode_changed_work, notify_panel_mode_changed_worker);
+ INIT_WORK(&ctx->notify_panel_mode_changed.work, notify_panel_mode_changed_worker);
mutex_init(&ctx->mode_lock);
mutex_init(&ctx->bl_state_lock);
diff --git a/samsung/panel/panel-samsung-drv.h b/samsung/panel/panel-samsung-drv.h
index e10d521..4f29db7 100644
--- a/samsung/panel/panel-samsung-drv.h
+++ b/samsung/panel/panel-samsung-drv.h
@@ -613,6 +613,12 @@ struct display_stats {
bool initialized;
};
+struct notify_state_change {
+ struct work_struct work;
+ struct wakeup_source *ws;
+ bool abort_suspend;
+};
+
struct exynos_panel {
struct device *dev;
struct drm_panel panel;
@@ -705,7 +711,9 @@ struct exynos_panel {
enum exynos_cabc_mode current_cabc_mode;
/* use for notify state changed */
- struct work_struct notify_panel_mode_changed_work;
+ bool allow_wakeup_by_state_change;
+ struct notify_state_change notify_panel_mode_changed;
+ struct work_struct notify_brightness_changed_work;
/* use for display stats residence */
struct display_stats disp_stats;
@@ -852,9 +860,10 @@ static inline void te2_state_changed(struct backlight_device *bl)
sysfs_notify(&bl->dev.kobj, NULL, "te2_state");
}
-static inline void notify_panel_mode_changed(struct exynos_panel *ctx)
+static inline void notify_panel_mode_changed(struct exynos_panel *ctx, bool abort_suspend)
{
- schedule_work(&ctx->notify_panel_mode_changed_work);
+ ctx->notify_panel_mode_changed.abort_suspend = abort_suspend;
+ schedule_work(&ctx->notify_panel_mode_changed.work);
}
static inline u32 get_current_frame_duration_us(struct exynos_panel *ctx)
diff --git a/samsung/panel/panel-samsung-s6e3hc3-c10.c b/samsung/panel/panel-samsung-s6e3hc3-c10.c
index b0c6ff6..94cc9e1 100644
--- a/samsung/panel/panel-samsung-s6e3hc3-c10.c
+++ b/samsung/panel/panel-samsung-s6e3hc3-c10.c
@@ -491,7 +491,7 @@ static void s6e3hc3_c10_update_refresh_mode(struct exynos_panel *ctx,
ctx->panel_idle_vrefresh = idle_vrefresh;
s6e3hc3_c10_update_panel_feat(ctx, pmode, false);
te2_state_changed(ctx->bl);
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
}
static void s6e3hc3_c10_change_frequency(struct exynos_panel *ctx,
diff --git a/samsung/panel/panel-samsung-s6e3hc3.c b/samsung/panel/panel-samsung-s6e3hc3.c
index 13c974a..30d8a5f 100644
--- a/samsung/panel/panel-samsung-s6e3hc3.c
+++ b/samsung/panel/panel-samsung-s6e3hc3.c
@@ -536,7 +536,7 @@ static bool s6e3hc3_set_self_refresh(struct exynos_panel *ctx, bool enable)
if (pmode->exynos_mode.is_lp_mode) {
/* set 10Hz while self refresh is active, otherwise clear it */
ctx->panel_idle_vrefresh = enable ? 10 : 0;
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, true);
return false;
}
@@ -550,7 +550,7 @@ static bool s6e3hc3_set_self_refresh(struct exynos_panel *ctx, bool enable)
if (pmode->idle_mode == IDLE_MODE_ON_INACTIVITY) {
/* simply update idle vrefresh follow by self refresh */
ctx->panel_idle_vrefresh = enable ? idle_vrefresh : 0;
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
if (spanel->auto_mode_vrefresh != idle_vrefresh) {
dev_dbg(ctx->dev,
"early exit update needed for mode: %s (idle_vrefresh: %d)\n",
@@ -593,7 +593,7 @@ static bool s6e3hc3_set_self_refresh(struct exynos_panel *ctx, bool enable)
}
EXYNOS_DCS_WRITE_TABLE(ctx, lock_cmd_f0);
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
DPU_ATRACE_END(__func__);
diff --git a/samsung/panel/panel-samsung-s6e3hc4.c b/samsung/panel/panel-samsung-s6e3hc4.c
index 4340a89..6c68515 100644
--- a/samsung/panel/panel-samsung-s6e3hc4.c
+++ b/samsung/panel/panel-samsung-s6e3hc4.c
@@ -549,7 +549,7 @@ static void s6e3hc4_update_refresh_mode(struct exynos_panel *ctx,
ctx->panel_idle_vrefresh = idle_vrefresh;
s6e3hc4_update_panel_feat(ctx, vrefresh, false);
te2_state_changed(ctx->bl);
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, false);
}
static void s6e3hc4_change_frequency(struct exynos_panel *ctx,
@@ -605,7 +605,7 @@ static bool s6e3hc4_set_self_refresh(struct exynos_panel *ctx, bool enable)
if (pmode->exynos_mode.is_lp_mode) {
/* set 10Hz while self refresh is active, otherwise clear it */
ctx->panel_idle_vrefresh = enable ? 10 : 0;
- notify_panel_mode_changed(ctx);
+ notify_panel_mode_changed(ctx, true);
return false;
}