summaryrefslogtreecommitdiff
path: root/samsung/panel/panel-samsung-drv.c
diff options
context:
space:
mode:
authorRobin Peng <robinpeng@google.com>2021-12-20 18:40:25 +0800
committerRobin Peng <robinpeng@google.com>2021-12-21 10:02:23 +0800
commit3f0b1425e21c985b3d818fec8504a851578e0270 (patch)
treed728827b929884279f2e1a16d8519e6d6d1d3f8c /samsung/panel/panel-samsung-drv.c
parent1cd1a7fee8ff1e887ae51db10efb84c1719c0409 (diff)
parentf00e446e328a1958a0a99c1e1a6d5c40f25f1040 (diff)
downloaddisplay-3f0b1425e21c985b3d818fec8504a851578e0270.tar.gz
Merge android12-gs-pixel-5.10-sc-v2 into android13-gs-pixel-5.10
Bug: 199698959 Signed-off-by: Robin Peng <robinpeng@google.com> Change-Id: Ie45d9105e4d9061dc46202dfbdfa7e371ca6ff70
Diffstat (limited to 'samsung/panel/panel-samsung-drv.c')
-rw-r--r--samsung/panel/panel-samsung-drv.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/samsung/panel/panel-samsung-drv.c b/samsung/panel/panel-samsung-drv.c
index ac4fa59..a9389a5 100644
--- a/samsung/panel/panel-samsung-drv.c
+++ b/samsung/panel/panel-samsung-drv.c
@@ -1098,6 +1098,25 @@ static ssize_t te2_lp_timing_show(struct device *dev,
return ret;
}
+static bool panel_idle_queue_delayed_work(struct exynos_panel *ctx)
+{
+ const ktime_t now = ktime_get();
+ const unsigned int delta_ms = ktime_to_ms(ktime_sub(now, ctx->last_mode_set_ts));
+
+ if (delta_ms < ctx->idle_delay_ms) {
+ const unsigned int delay_ms = ctx->idle_delay_ms - delta_ms;
+
+ dev_dbg(ctx->dev, "%s: last mode %ums ago, schedule idle in %ums\n",
+ __func__, delta_ms, delay_ms);
+
+ mod_delayed_work(system_highpri_wq, &ctx->idle_work,
+ msecs_to_jiffies(delay_ms));
+ return true;
+ }
+
+ return false;
+}
+
static void panel_update_idle_mode_locked(struct exynos_panel *ctx)
{
const struct exynos_panel_funcs *funcs = ctx->desc->exynos_panel_func;
@@ -1110,10 +1129,29 @@ static void panel_update_idle_mode_locked(struct exynos_panel *ctx)
if (!is_panel_active(ctx) || !funcs->set_self_refresh)
return;
+ if (ctx->idle_delay_ms && ctx->self_refresh_active && panel_idle_queue_delayed_work(ctx))
+ return;
+
+ if (delayed_work_pending(&ctx->idle_work)) {
+ dev_dbg(ctx->dev, "%s: cancelling delayed idle work\n", __func__);
+ cancel_delayed_work(&ctx->idle_work);
+ }
+
if (funcs->set_self_refresh(ctx, ctx->self_refresh_active))
exynos_panel_update_te2(ctx);
}
+static void panel_idle_work(struct work_struct *work)
+{
+ struct exynos_panel *ctx = container_of(work, struct exynos_panel, idle_work.work);
+
+ dev_dbg(ctx->dev, "%s\n", __func__);
+
+ mutex_lock(&ctx->mode_lock);
+ panel_update_idle_mode_locked(ctx);
+ mutex_unlock(&ctx->mode_lock);
+}
+
static ssize_t panel_idle_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -1146,6 +1184,66 @@ static ssize_t panel_idle_show(struct device *dev, struct device_attribute *attr
return scnprintf(buf, PAGE_SIZE, "%d\n", ctx->panel_idle_enabled);
}
+static ssize_t min_vrefresh_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ const struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+ struct exynos_panel *ctx = mipi_dsi_get_drvdata(dsi);
+ int min_vrefresh;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &min_vrefresh);
+ if (ret) {
+ dev_err(dev, "invalid min vrefresh value\n");
+ return ret;
+ }
+
+ mutex_lock(&ctx->mode_lock);
+ ctx->min_vrefresh = min_vrefresh;
+ panel_update_idle_mode_locked(ctx);
+ mutex_unlock(&ctx->mode_lock);
+
+ return count;
+}
+
+static ssize_t min_vrefresh_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ const struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+ struct exynos_panel *ctx = mipi_dsi_get_drvdata(dsi);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ctx->min_vrefresh);
+}
+
+static ssize_t idle_delay_ms_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ const struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+ struct exynos_panel *ctx = mipi_dsi_get_drvdata(dsi);
+ u32 idle_delay_ms;
+ int ret;
+
+ ret = kstrtou32(buf, 0, &idle_delay_ms);
+ if (ret) {
+ dev_err(dev, "invalid idle delay ms\n");
+ return ret;
+ }
+
+ mutex_lock(&ctx->mode_lock);
+ ctx->idle_delay_ms = idle_delay_ms;
+ panel_update_idle_mode_locked(ctx);
+ mutex_unlock(&ctx->mode_lock);
+
+ return count;
+}
+
+static ssize_t idle_delay_ms_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ const struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+ struct exynos_panel *ctx = mipi_dsi_get_drvdata(dsi);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ctx->idle_delay_ms);
+}
+
static DEVICE_ATTR_RO(serial_number);
static DEVICE_ATTR_RO(panel_extinfo);
static DEVICE_ATTR_RO(panel_name);
@@ -1153,6 +1251,8 @@ static DEVICE_ATTR_WO(gamma);
static DEVICE_ATTR_RW(te2_timing);
static DEVICE_ATTR_RW(te2_lp_timing);
static DEVICE_ATTR_RW(panel_idle);
+static DEVICE_ATTR_RW(min_vrefresh);
+static DEVICE_ATTR_RW(idle_delay_ms);
static const struct attribute *panel_attrs[] = {
&dev_attr_serial_number.attr,
@@ -1162,6 +1262,8 @@ static const struct attribute *panel_attrs[] = {
&dev_attr_te2_timing.attr,
&dev_attr_te2_lp_timing.attr,
&dev_attr_panel_idle.attr,
+ &dev_attr_min_vrefresh.attr,
+ &dev_attr_idle_delay_ms.attr,
NULL
};
@@ -1182,6 +1284,7 @@ static void exynos_panel_connector_print_state(struct drm_printer *p,
drm_printf(p, "\tidle: %s (%s)\n",
ctx->panel_idle_vrefresh ? "active" : "inactive",
ctx->panel_idle_enabled ? "enabled" : "disabled");
+
if (ctx->current_mode) {
const struct drm_display_mode *m = &ctx->current_mode->mode;
@@ -2969,6 +3072,7 @@ static void exynos_panel_bridge_mode_set(struct drm_bridge *bridge,
pmode->mode.hdisplay, pmode->mode.vdisplay, drm_mode_vrefresh(&pmode->mode));
dsi->mode_flags = pmode->exynos_mode.mode_flags;
+ ctx->last_mode_set_ts = ktime_get();
DPU_ATRACE_BEGIN(__func__);
if (funcs) {
@@ -3290,6 +3394,7 @@ int exynos_panel_common_init(struct mipi_dsi_device *dsi,
ctx->bl_notifier.ranges[i] = ctx->desc->bl_range[i];
}
ctx->panel_idle_enabled = exynos_panel_func && exynos_panel_func->set_self_refresh != NULL;
+ INIT_DELAYED_WORK(&ctx->idle_work, panel_idle_work);
mutex_init(&ctx->mode_lock);
mutex_init(&ctx->bl_state_lock);