[PATCH 06/10] drm/panel: otm8009a: Properly sequence [un]prepare with backlight

Sean Paul seanpaul at chromium.org
Thu Sep 21 17:06:17 UTC 2017


I noticed while removing the enabled flag that backlight update checks
prepared in such a way that could race with hardware turning on/off.
This patch adds a mutex to ensure these races don't happen.

In addition to the lock, this patch also renames prepared to initialized
to better reflect what it means when used in the backlight hook.

Signed-off-by: Sean Paul <seanpaul at chromium.org>
---
 drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 43 ++++++++++++++++--------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
index 0a5898fd4502..d099af3c91df 100644
--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
@@ -11,6 +11,7 @@
 #include <drm/drm_panel.h>
 #include <linux/backlight.h>
 #include <linux/gpio/consumer.h>
+#include <linux/mutex.h>
 #include <video/mipi_display.h>
 
 #define DRV_NAME "orisetech_otm8009a"
@@ -62,7 +63,9 @@ struct otm8009a {
 	struct drm_panel panel;
 	struct backlight_device *bl_dev;
 	struct gpio_desc *reset_gpio;
-	bool prepared;
+
+	struct mutex lock;
+	bool initialized;
 };
 
 static const struct drm_display_mode default_mode = {
@@ -265,26 +268,30 @@ static int otm8009a_unprepare(struct drm_panel *panel)
 {
 	struct otm8009a *ctx = panel_to_otm8009a(panel);
 
-	if (!ctx->prepared)
-		return 0;
+	mutex_lock(&ctx->lock);
+	if (!ctx->initialized)
+		goto out;
 
 	if (ctx->reset_gpio) {
 		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 		msleep(20);
 	}
 
-	ctx->prepared = false;
+	ctx->initialized = false;
 
+out:
+	mutex_unlock(&ctx->lock);
 	return 0;
 }
 
 static int otm8009a_prepare(struct drm_panel *panel)
 {
 	struct otm8009a *ctx = panel_to_otm8009a(panel);
-	int ret;
+	int ret = 0;
 
-	if (ctx->prepared)
-		return 0;
+	mutex_lock(&ctx->lock);
+	if (ctx->initialized)
+		goto out;
 
 	if (ctx->reset_gpio) {
 		gpiod_set_value_cansleep(ctx->reset_gpio, 0);
@@ -296,18 +303,20 @@ static int otm8009a_prepare(struct drm_panel *panel)
 
 	ret = otm8009a_init_sequence(ctx);
 	if (ret)
-		return ret;
+		goto out;
 
-	ctx->prepared = true;
+	ctx->initialized = true;
 
 	/*
 	 * Power on the backlight. Note: end-user still controls brightness
-	 * Note: ctx->prepared must be true before updating the backlight.
+	 * Note: ctx->initialized must be true before updating the backlight.
 	 */
 	ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
 	backlight_update_status(ctx->bl_dev);
 
-	return 0;
+out:
+	mutex_unlock(&ctx->lock);
+	return ret;
 }
 
 static int otm8009a_get_modes(struct drm_panel *panel)
@@ -348,10 +357,13 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd)
 {
 	struct otm8009a *ctx = bl_get_data(bd);
 	u8 data[2];
+	int ret = 0;
 
-	if (!ctx->prepared) {
+	mutex_lock(&ctx->lock);
+	if (!ctx->initialized) {
 		DRM_DEBUG("lcd not ready yet for setting its backlight!\n");
-		return -ENXIO;
+		ret = -ENXIO;
+		goto out;
 	}
 
 	if (bd->props.power <= FB_BLANK_NORMAL) {
@@ -375,7 +387,9 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd)
 	data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY;
 	otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data));
 
-	return 0;
+out:
+	mutex_unlock(&ctx->lock);
+	return ret;
 }
 
 static const struct backlight_ops otm8009a_backlight_ops = {
@@ -401,6 +415,7 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi)
 	mipi_dsi_set_drvdata(dsi, ctx);
 
 	ctx->dev = dev;
+	mutex_init(&ctx->lock);
 
 	dsi->lanes = 2;
 	dsi->format = MIPI_DSI_FMT_RGB888;
-- 
2.14.1.821.g8fa685d3b7-goog



More information about the dri-devel mailing list