devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Add driver for Samsung S6E8AA5X01 panel controller
@ 2025-06-12 14:52 Kaustabh Chakraborty
  2025-06-12 14:52 ` [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver Kaustabh Chakraborty
  2025-06-12 14:52 ` [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller Kaustabh Chakraborty
  0 siblings, 2 replies; 9+ messages in thread
From: Kaustabh Chakraborty @ 2025-06-12 14:52 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang
  Cc: dri-devel, devicetree, linux-kernel, Kaustabh Chakraborty

This patch series introduces a driver for Samsung S6E8AA5X01, which is
an AMOLED MIPI DSI panel controller. This panel is found in several
(mostly Samsung) phones, in at least two different sizes - 720x1280 and
720x1480.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
Kaustabh Chakraborty (2):
      dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver
      drm: panel: add support for Samsung S6E8AA5X01 panel controller

 .../bindings/display/panel/samsung,s6e8aa5x01.yaml |  80 ++
 drivers/gpu/drm/panel/Kconfig                      |  11 +
 drivers/gpu/drm/panel/Makefile                     |   1 +
 drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c   | 922 +++++++++++++++++++++
 4 files changed, 1014 insertions(+)
---
base-commit: 0bb71d301869446810a0b13d3da290bd455d7c78
change-id: 20250523-panel-samsung-s6e8aa5x01-ea2496eafeda

Best regards,
-- 
Kaustabh Chakraborty <kauschluss@disroot.org>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver
  2025-06-12 14:52 [PATCH 0/2] Add driver for Samsung S6E8AA5X01 panel controller Kaustabh Chakraborty
@ 2025-06-12 14:52 ` Kaustabh Chakraborty
  2025-06-12 15:30   ` Conor Dooley
  2025-06-12 14:52 ` [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller Kaustabh Chakraborty
  1 sibling, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2025-06-12 14:52 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang
  Cc: dri-devel, devicetree, linux-kernel, Kaustabh Chakraborty

Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Document the
compatible and devicetree properties of this panel driver. Timings are
provided through the devicetree node as panels are available in
different sizes.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 .../bindings/display/panel/samsung,s6e8aa5x01.yaml | 80 ++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa5x01.yaml b/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa5x01.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..909f43a49434af94c90ee64a3171d44645cd9dc9
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa5x01.yaml
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/samsung,s6e8aa0.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S6E8AA5X01 display panel controller
+
+maintainers:
+  - Kaustabh Chakraborty <kauschluss@disroot.org>
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    const: samsung,s6e8aa5x01
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    maxItems: 1
+    description: core voltage supply
+
+  vci-supply:
+    maxItems: 1
+    description: voltage supply for analog circuits
+
+  reset-gpios: true
+  width-mm: true
+  height-mm: true
+  panel-timing: true
+
+required:
+  - compatible
+  - reg
+  - width-mm
+  - height-mm
+  - panel-timing
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel@0 {
+            compatible = "samsung,s6e8aa5x01";
+            reg = <0>;
+
+            vdd-supply = <&panel_vdd_reg>;
+            vci-supply = <&panel_vci_reg>;
+
+            reset-gpios = <&gpd3 4 GPIO_ACTIVE_HIGH>;
+
+            width-mm = <62>;
+            height-mm = <128>;
+
+            panel-timing {
+                clock-frequency = <73094400>;
+
+                hactive = <720>;
+                hsync-len = <2>;
+                hfront-porch = <62>;
+                hback-porch = <26>;
+
+                vactive = <1480>;
+                vsync-len = <2>;
+                vfront-porch = <12>;
+                vback-porch = <10>;
+            };
+        };
+    };
+
+...

-- 
2.49.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller
  2025-06-12 14:52 [PATCH 0/2] Add driver for Samsung S6E8AA5X01 panel controller Kaustabh Chakraborty
  2025-06-12 14:52 ` [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver Kaustabh Chakraborty
@ 2025-06-12 14:52 ` Kaustabh Chakraborty
  2025-06-13  9:39   ` Thomas Zimmermann
  1 sibling, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2025-06-12 14:52 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang
  Cc: dri-devel, devicetree, linux-kernel, Kaustabh Chakraborty

Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Implement
a basic panel driver for such panels.

The driver also initializes a backlight device, which works by changing
the panel's gamma values and aid brightness levels appropriately, with
the help of look-up tables acquired from downstream kernel sources.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
 drivers/gpu/drm/panel/Kconfig                    |  11 +
 drivers/gpu/drm/panel/Makefile                   |   1 +
 drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c | 922 +++++++++++++++++++++++
 3 files changed, 934 insertions(+)

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d5aa1c95c6a45b2fea9b1d7a9e8a39fe617b860c..3d92ec3d7a1e85bf099e50e78b666fa38267d05c 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -833,6 +833,17 @@ config DRM_PANEL_SAMSUNG_S6E8AA0
 	select DRM_MIPI_DSI
 	select VIDEOMODE_HELPERS
 
+config DRM_PANEL_SAMSUNG_S6E8AA5X01
+	tristate "Samsung S6E8AA5X01 panel"
+	depends on GPIOLIB && OF && REGULATOR
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here if you want to enable support for Samsung S6E8AA5X01 panel
+	  controller. The controller is driven by the MIPI DSI protocol with 4
+	  lanes. Panels are available in multiple sizes by vendors, such as in
+	  720x1280@60Hz or 720x1480@60Hz.
+
 config DRM_PANEL_SAMSUNG_SOFEF00
 	tristate "Samsung sofef00/s6e3fc2x01 OnePlus 6/6T DSI cmd mode panels"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 73a39bc726045f3ce52fdeef8c0ec762a4a378c7..995cf2b22427897313f806280b0bc9a67a7b4879 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24) += panel-samsung-s6e88a0-ams427ap24.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA5X01) += panel-samsung-s6e8aa5x01.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF00) += panel-samsung-sofef00.o
 obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c
new file mode 100644
index 0000000000000000000000000000000000000000..1804d82ed2d1fb8af0492f4a5bf07ba661f600fb
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c
@@ -0,0 +1,922 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Samsung S6E8AA5X01 display panel driver.
+ *
+ * Copyright (C) 2025 Kaustabh Chakraborty <kauschluss@disroot.org>
+ */
+
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+/* Manufacturer Command Set */
+#define MCS_AIDCTL		0xb2
+#define MCS_ADAPTIVECTL		0xb5
+#define MCS_ELVSS		0xb6
+#define MCS_TEMPERCTL		0xb8
+#define MCS_PENTILE		0xc0
+#define MCS_GAMMACTL		0xca
+#define MCS_LTPSCTL		0xcb
+#define MCS_PCD			0xcc
+#define MCS_ERRFLAG		0xe7
+#define MCS_ACCESSPROT		0xf0
+#define MCS_DISPCTL		0xf2
+#define MCS_GAMMAUPD		0xf7
+
+#define GAMMA_CMD_LEN	34
+#define AID_CMD_LEN	3
+
+static const struct {
+	u8 gamma[GAMMA_CMD_LEN];
+	u8 aid[AID_CMD_LEN];
+} s6e8aa5x01_cmds[] = {
+	{
+		/* 5 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x94,
+		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
+		  0x8d, 0x8c, 0x8d, 0x89, 0x8c, 0x8e,
+		  0x8e, 0x8f, 0x90, 0xa3, 0xa2, 0x9a,
+		  0xcf, 0xca, 0x9f, 0xe6, 0xff, 0xb4,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0xa5 },
+	}, {
+		/* 6 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x95,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x8c, 0x8a, 0x8c, 0x85, 0x88, 0x8c,
+		  0x8b, 0x8c, 0x8e, 0xa2, 0xa2, 0x9a,
+		  0xd0, 0xcc, 0xa2, 0xed, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x95 },
+	}, {
+		/* 7 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x95,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x8c, 0x8a, 0x8c, 0x85, 0x88, 0x8c,
+		  0x8b, 0x8c, 0x8e, 0xa2, 0xa2, 0x99,
+		  0xc8, 0xc4, 0x9d, 0xed, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x89 },
+	}, {
+		/* 8 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
+		  0x8a, 0x88, 0x8b, 0x83, 0x86, 0x8b,
+		  0x8c, 0x8b, 0x8d, 0x9d, 0x9f, 0x97,
+		  0xc7, 0xc3, 0x9c, 0xf5, 0xff, 0xbb,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x7e },
+	}, {
+		/* 9 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x8a, 0x82, 0x84, 0x88,
+		  0x90, 0x8f, 0x91, 0x95, 0x97, 0x94,
+		  0xc6, 0xc2, 0x9d, 0xf5, 0xff, 0xbb,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x73 },
+	}, {
+		/* 10 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x8a, 0x82, 0x84, 0x88,
+		  0x90, 0x8f, 0x91, 0x94, 0x97, 0x93,
+		  0xc6, 0xc2, 0x9e, 0xec, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x67 },
+	}, {
+		/* 11 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x8a, 0x82, 0x84, 0x88,
+		  0x8b, 0x8b, 0x8d, 0x90, 0x93, 0x92,
+		  0xc5, 0xc1, 0x9c, 0xf5, 0xff, 0xbb,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x56 },
+	}, {
+		/* 12 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
+		  0x87, 0x86, 0x8a, 0x8c, 0x90, 0x8f,
+		  0xcd, 0xc9, 0xa1, 0xec, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x4a },
+	}, {
+		/* 13 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
+		  0x87, 0x86, 0x8a, 0x8c, 0x90, 0x8e,
+		  0xc4, 0xbf, 0x9c, 0xf5, 0xff, 0xbb,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x3b },
+	}, {
+		/* 14 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
+		  0x87, 0x86, 0x89, 0x8c, 0x90, 0x8f,
+		  0xc2, 0xbf, 0x9c, 0xec, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x35 },
+	}, {
+		/* 15 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
+		  0x87, 0x86, 0x89, 0x8c, 0x90, 0x8f,
+		  0xb7, 0xb6, 0x96, 0xec, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x25 },
+	}, {
+		/* 16 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
+		  0x88, 0x86, 0x89, 0x8c, 0x90, 0x8f,
+		  0xb7, 0xb6, 0x96, 0xec, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x20 },
+	}, {
+		/* 17 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x7f, 0x80, 0x86,
+		  0x86, 0x85, 0x89, 0x88, 0x8c, 0x8e,
+		  0xbf, 0xbe, 0x9c, 0xec, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x05, 0x11 },
+	}, {
+		/* 19 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x7f, 0x80, 0x86,
+		  0x87, 0x85, 0x89, 0x88, 0x8c, 0x8e,
+		  0xb3, 0xb4, 0x97, 0xeb, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0xf2 },
+	}, {
+		/* 20 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x95,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x89, 0x86, 0x89, 0x7f, 0x80, 0x86,
+		  0x87, 0x85, 0x89, 0x89, 0x8c, 0x8e,
+		  0xb3, 0xb4, 0x97, 0xeb, 0xff, 0xb7,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0xe4 },
+	}, {
+		/* 21 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x8a, 0x88, 0x8b, 0x7d, 0x7e, 0x84,
+		  0x8c, 0x8a, 0x8c, 0x8e, 0x90, 0x8f,
+		  0xb6, 0xb6, 0x97, 0xe3, 0xff, 0xb3,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0xd5 },
+	}, {
+		/* 22 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x97,
+		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
+		  0x8a, 0x88, 0x8b, 0x81, 0x82, 0x86,
+		  0x87, 0x86, 0x88, 0x8e, 0x90, 0x8f,
+		  0xb6, 0xb6, 0x95, 0xe3, 0xff, 0xb3,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0xc5 },
+	}, {
+		/* 24 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x97,
+		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
+		  0x87, 0x86, 0x88, 0x8e, 0x90, 0x8f,
+		  0xb6, 0xb6, 0x94, 0xe3, 0xff, 0xb3,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0xa7 },
+	}, {
+		/* 25 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x98,
+		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
+		  0x87, 0x86, 0x87, 0x8e, 0x90, 0x8f,
+		  0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0x95 },
+	}, {
+		/* 27 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x99,
+		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8a, 0x83, 0x86, 0x8a,
+		  0x88, 0x87, 0x87, 0x88, 0x8b, 0x8c,
+		  0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0x76 },
+	}, {
+		/* 29 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x99,
+		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x83, 0x86, 0x89,
+		  0x88, 0x87, 0x88, 0x88, 0x8b, 0x8b,
+		  0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0x54 },
+	}, {
+		/* 30 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9a,
+		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8a, 0x84, 0x86, 0x8a,
+		  0x87, 0x87, 0x87, 0x88, 0x8b, 0x8b,
+		  0xbf, 0xbf, 0x99, 0xda, 0xfa, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0x44 },
+	}, {
+		/* 32 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9a,
+		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
+		  0x89, 0x87, 0x8a, 0x84, 0x86, 0x8a,
+		  0x87, 0x87, 0x87, 0x89, 0x8b, 0x8b,
+		  0xbf, 0xbf, 0x98, 0xd2, 0xf2, 0xac,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x04, 0x1f },
+	}, {
+		/* 34 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
+		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8b, 0x87, 0x8b, 0x83, 0x86, 0x89,
+		  0x87, 0x87, 0x88, 0x88, 0x8b, 0x8a,
+		  0xbf, 0xbf, 0x98, 0xd2, 0xf2, 0xac,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x03, 0xff },
+	}, {
+		/* 37 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
+		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
+		  0x86, 0x86, 0x86, 0x8d, 0x90, 0x8d,
+		  0xc0, 0xbf, 0x9a, 0xd2, 0xf2, 0xac,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x03, 0xd3 },
+	}, {
+		/* 39 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
+		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
+		  0x87, 0x86, 0x87, 0x8d, 0x90, 0x8d,
+		  0xb6, 0xb6, 0x93, 0xda, 0xf9, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x03, 0xb3 },
+	}, {
+		/* 41 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
+		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x85,
+		  0x87, 0x86, 0x87, 0x8d, 0x90, 0x8d,
+		  0xb6, 0xb6, 0x94, 0xda, 0xf9, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x03, 0x93 },
+	}, {
+		/* 44 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
+		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
+		  0x87, 0x86, 0x86, 0x85, 0x87, 0x8a,
+		  0xbe, 0xbe, 0x99, 0xda, 0xf9, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x03, 0x66 },
+	}, {
+		/* 47 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
+		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
+		  0x88, 0x86, 0x87, 0x84, 0x87, 0x89,
+		  0xb4, 0xb4, 0x94, 0xe2, 0xff, 0xb3,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x03, 0x40 },
+	}, {
+		/* 50 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
+		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
+		  0x88, 0x86, 0x87, 0x84, 0x87, 0x89,
+		  0xb4, 0xb4, 0x95, 0xe2, 0xff, 0xb3,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x03, 0x0e },
+	}, {
+		/* 53 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
+		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
+		  0x88, 0x86, 0x87, 0x85, 0x87, 0x8a,
+		  0xb4, 0xb4, 0x96, 0xe2, 0xff, 0xb3,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0xe2 },
+	}, {
+		/* 56 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
+		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
+		  0x88, 0x86, 0x87, 0x85, 0x87, 0x8a,
+		  0xab, 0xab, 0x90, 0xdd, 0xf7, 0xaf,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0xb5 },
+	}, {
+		/* 60 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
+		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x82, 0x82, 0x87,
+		  0x83, 0x81, 0x84, 0x81, 0x84, 0x88,
+		  0xb3, 0xb3, 0x96, 0xcf, 0xe5, 0xa8,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x77 },
+	}, {
+		/* 64 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
+		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
+		  0x8a, 0x87, 0x8b, 0x82, 0x82, 0x87,
+		  0x83, 0x81, 0x84, 0x82, 0x84, 0x88,
+		  0xb2, 0xb3, 0x97, 0xcf, 0xe5, 0xa8,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x36 },
+	}, {
+		/* 68 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x9b, 0x00, 0xa6, 0x00, 0x9d,
+		  0x88, 0x88, 0x89, 0x89, 0x89, 0x8b,
+		  0x8a, 0x88, 0x8b, 0x7f, 0x80, 0x86,
+		  0x88, 0x86, 0x87, 0x7d, 0x7f, 0x85,
+		  0xb2, 0xb3, 0x97, 0xcf, 0xe5, 0xa8,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 72 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0x9c, 0x00, 0xa9, 0x00, 0xa0,
+		  0x88, 0x88, 0x89, 0x88, 0x88, 0x8a,
+		  0x8c, 0x8a, 0x8d, 0x7f, 0x81, 0x85,
+		  0x84, 0x82, 0x84, 0x85, 0x87, 0x8a,
+		  0xaa, 0xab, 0x93, 0xcf, 0xe5, 0xa8,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 77 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xa1, 0x00, 0xad, 0x00, 0xa5,
+		  0x89, 0x89, 0x8a, 0x88, 0x87, 0x89,
+		  0x8c, 0x89, 0x8d, 0x7f, 0x81, 0x85,
+		  0x84, 0x83, 0x84, 0x81, 0x83, 0x86,
+		  0xaa, 0xab, 0x93, 0xc0, 0xd3, 0xa1,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 82 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xa5, 0x00, 0xb0, 0x00, 0xa9,
+		  0x88, 0x89, 0x89, 0x85, 0x86, 0x89,
+		  0x8a, 0x88, 0x8b, 0x82, 0x82, 0x87,
+		  0x81, 0x80, 0x82, 0x89, 0x8b, 0x8b,
+		  0xa2, 0xa3, 0x8e, 0xc0, 0xd3, 0xa1,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 87 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xab, 0x00, 0xb4, 0x00, 0xad,
+		  0x88, 0x89, 0x8a, 0x84, 0x86, 0x88,
+		  0x8a, 0x88, 0x8b, 0x7f, 0x7f, 0x84,
+		  0x86, 0x84, 0x85, 0x85, 0x86, 0x88,
+		  0xa2, 0xa3, 0x8f, 0xc0, 0xd3, 0xa1,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 93 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xaf, 0x00, 0xb9, 0x00, 0xb1,
+		  0x88, 0x89, 0x8a, 0x84, 0x85, 0x87,
+		  0x8a, 0x89, 0x8b, 0x7e, 0x7e, 0x83,
+		  0x87, 0x86, 0x86, 0x88, 0x8a, 0x89,
+		  0x9c, 0x9c, 0x8b, 0xc0, 0xd3, 0xa1,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 98 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xb3, 0x00, 0xbc, 0x00, 0xb5,
+		  0x88, 0x88, 0x88, 0x84, 0x84, 0x86,
+		  0x8a, 0x88, 0x8a, 0x7f, 0x7f, 0x84,
+		  0x84, 0x83, 0x84, 0x88, 0x8a, 0x89,
+		  0x9c, 0x9c, 0x8b, 0xc0, 0xd3, 0xa1,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 105 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xb7, 0x00, 0xc0, 0x00, 0xba,
+		  0x87, 0x87, 0x88, 0x85, 0x85, 0x87,
+		  0x89, 0x88, 0x89, 0x7f, 0x7f, 0x83,
+		  0x81, 0x80, 0x82, 0x88, 0x8a, 0x89,
+		  0x9c, 0x9c, 0x8c, 0xb2, 0xc2, 0x9a,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 111 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xbb, 0x00, 0xc3, 0x00, 0xbe,
+		  0x87, 0x87, 0x88, 0x85, 0x85, 0x88,
+		  0x88, 0x87, 0x89, 0x80, 0x80, 0x84,
+		  0x81, 0x81, 0x82, 0x85, 0x86, 0x87,
+		  0x9c, 0x9c, 0x8b, 0xb2, 0xc2, 0x9a,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x15 },
+	}, {
+		/* 119 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4,
+		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
+		  0x87, 0x85, 0x87, 0x82, 0x81, 0x84,
+		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
+		  0x9c, 0x9c, 0x8c, 0xb2, 0xc2, 0x9a,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x02, 0x14 },
+	}, {
+		/* 126 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4,
+		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
+		  0x87, 0x85, 0x87, 0x82, 0x81, 0x84,
+		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
+		  0x9c, 0x9c, 0x8d, 0xb2, 0xc2, 0x9a,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x01, 0xde },
+	}, {
+		/* 134 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4,
+		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
+		  0x87, 0x85, 0x87, 0x82, 0x81, 0x84,
+		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
+		  0x9c, 0x9c, 0x8d, 0xa4, 0xb0, 0x92,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x01, 0x94 },
+	}, {
+		/* 143 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
+		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
+		  0x87, 0x85, 0x87, 0x82, 0x81, 0x85,
+		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
+		  0x92, 0x92, 0x89, 0xab, 0xb6, 0x96,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x01, 0x46 },
+	}, {
+		/* 152 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
+		  0x87, 0x87, 0x88, 0x83, 0x84, 0x86,
+		  0x87, 0x85, 0x87, 0x81, 0x81, 0x85,
+		  0x84, 0x82, 0x83, 0x80, 0x81, 0x83,
+		  0x92, 0x92, 0x8b, 0xab, 0xb6, 0x96,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0xfa },
+	}, {
+		/* 162 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
+		  0x87, 0x87, 0x88, 0x83, 0x84, 0x86,
+		  0x87, 0x85, 0x87, 0x81, 0x81, 0x84,
+		  0x84, 0x82, 0x84, 0x80, 0x81, 0x83,
+		  0x92, 0x92, 0x8b, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0xac },
+	}, {
+		/* 172 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
+		  0x87, 0x87, 0x88, 0x83, 0x84, 0x86,
+		  0x87, 0x85, 0x87, 0x81, 0x81, 0x84,
+		  0x84, 0x82, 0x83, 0x80, 0x81, 0x84,
+		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x57 },
+	}, {
+		/* 183 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc2, 0x00, 0xca, 0x00, 0xc5,
+		  0x86, 0x86, 0x87, 0x85, 0x84, 0x87,
+		  0x87, 0x86, 0x88, 0x7e, 0x80, 0x83,
+		  0x84, 0x82, 0x83, 0x80, 0x81, 0x83,
+		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 195 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xc7, 0x00, 0xce, 0x00, 0xc9,
+		  0x86, 0x87, 0x86, 0x83, 0x83, 0x85,
+		  0x85, 0x84, 0x86, 0x82, 0x82, 0x85,
+		  0x80, 0x80, 0x81, 0x81, 0x81, 0x84,
+		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 207 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xcc, 0x00, 0xd2, 0x00, 0xce,
+		  0x86, 0x86, 0x87, 0x81, 0x83, 0x84,
+		  0x84, 0x82, 0x84, 0x83, 0x83, 0x85,
+		  0x81, 0x81, 0x82, 0x7c, 0x7d, 0x81,
+		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 220 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xd1, 0x00, 0xd6, 0x00, 0xd3,
+		  0x86, 0x86, 0x86, 0x81, 0x83, 0x84,
+		  0x84, 0x82, 0x84, 0x80, 0x80, 0x83,
+		  0x81, 0x81, 0x82, 0x7c, 0x7d, 0x81,
+		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 234 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xd6, 0x00, 0xdb, 0x00, 0xd8,
+		  0x85, 0x85, 0x85, 0x81, 0x83, 0x84,
+		  0x83, 0x82, 0x83, 0x80, 0x80, 0x82,
+		  0x84, 0x82, 0x83, 0x79, 0x79, 0x7e,
+		  0x93, 0x92, 0x8d, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 249 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xdc, 0x00, 0xe0, 0x00, 0xdd,
+		  0x84, 0x84, 0x84, 0x81, 0x82, 0x83,
+		  0x84, 0x82, 0x84, 0x7f, 0x7f, 0x82,
+		  0x81, 0x80, 0x81, 0x80, 0x81, 0x82,
+		  0x8c, 0x8c, 0x86, 0x9d, 0xa4, 0x8e,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 265 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xe2, 0x00, 0xe5, 0x00, 0xe3,
+		  0x83, 0x83, 0x83, 0x81, 0x82, 0x83,
+		  0x82, 0x82, 0x83, 0x82, 0x81, 0x83,
+		  0x7f, 0x7e, 0x80, 0x7c, 0x7d, 0x80,
+		  0x8c, 0x8c, 0x86, 0x8e, 0x92, 0x87,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 282 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xe8, 0x00, 0xea, 0x00, 0xe9,
+		  0x83, 0x83, 0x83, 0x80, 0x82, 0x82,
+		  0x81, 0x82, 0x82, 0x82, 0x81, 0x82,
+		  0x81, 0x80, 0x81, 0x80, 0x80, 0x81,
+		  0x85, 0x85, 0x83, 0x8e, 0x92, 0x87,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 300 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xed, 0x00, 0xef, 0x00, 0xed,
+		  0x81, 0x82, 0x81, 0x81, 0x81, 0x82,
+		  0x82, 0x82, 0x83, 0x80, 0x80, 0x81,
+		  0x81, 0x81, 0x82, 0x83, 0x83, 0x83,
+		  0x80, 0x80, 0x7f, 0x8e, 0x92, 0x87,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 316 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf3,
+		  0x80, 0x81, 0x80, 0x81, 0x81, 0x81,
+		  0x82, 0x82, 0x82, 0x81, 0x80, 0x81,
+		  0x82, 0x82, 0x83, 0x80, 0x80, 0x80,
+		  0x80, 0x80, 0x7f, 0x80, 0x80, 0x80,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 333 nits */
+		{ MCS_GAMMACTL,
+		  0x00, 0xf8, 0x00, 0xf8, 0x00, 0xf8,
+		  0x80, 0x81, 0x80, 0x81, 0x80, 0x81,
+		  0x81, 0x82, 0x82, 0x81, 0x80, 0x81,
+		  0x83, 0x83, 0x83, 0x7e, 0x7d, 0x7e,
+		  0x80, 0x80, 0x7f, 0x80, 0x80, 0x80,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	}, {
+		/* 360 nits */
+		{ MCS_GAMMACTL,
+		  0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+		  0x00, 0x00, 0x00, },
+		{ MCS_AIDCTL, 0x00, 0x10 },
+	},
+};
+
+struct s6e8aa5x01_ctx {
+	struct drm_panel panel;
+	struct mipi_dsi_device *dsi;
+	struct drm_display_mode mode;
+	struct backlight_device *backlight;
+	struct regulator_bulk_data supplies[2];
+	struct gpio_desc *reset_gpio;
+	struct mutex mcs_mutex;
+	u32 bus_flags;
+	u32 width;
+	u32 height;
+};
+
+static inline struct s6e8aa5x01_ctx *to_s6e8aa5x01_ctx(struct drm_panel *panel)
+{
+	return container_of(panel, struct s6e8aa5x01_ctx, panel);
+}
+
+static void s6e8aa5x01_mcs_protect(struct mipi_dsi_multi_context *dsi,
+				   struct s6e8aa5x01_ctx *ctx, bool protect)
+{
+	if (protect) {
+		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0xa5, 0xa5);
+		mutex_unlock(&ctx->mcs_mutex);
+	} else {
+		mutex_lock(&ctx->mcs_mutex);
+		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0x5a, 0x5a);
+	}
+}
+
+static int s6e8aa5x01_update_brightness(struct backlight_device *backlight)
+{
+	struct mipi_dsi_multi_context dsi = { .dsi = bl_get_data(backlight) };
+	struct s6e8aa5x01_ctx *ctx = mipi_dsi_get_drvdata(dsi.dsi);
+	u16 lvl = backlight->props.brightness;
+
+	s6e8aa5x01_mcs_protect(&dsi, ctx, false);
+
+	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].gamma, GAMMA_CMD_LEN);
+	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].aid, AID_CMD_LEN);
+	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_GAMMAUPD, 0x03);
+
+	s6e8aa5x01_mcs_protect(&dsi, ctx, true);
+
+	return dsi.accum_err;
+}
+
+static int s6e8aa5x01_prepare(struct drm_panel *panel)
+{
+	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
+	struct device *dev = &ctx->dsi->dev;
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	usleep_range(5000, 6000);
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	usleep_range(5000, 6000);
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	usleep_range(10000, 11000);
+
+	return 0;
+}
+
+static int s6e8aa5x01_unprepare(struct drm_panel *panel)
+{
+	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	usleep_range(5000, 6000);
+
+	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+
+	return 0;
+}
+
+static int s6e8aa5x01_enable(struct drm_panel *panel)
+{
+	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
+	struct mipi_dsi_multi_context dsi = { .dsi = ctx->dsi };
+	u16 lvl = ctx->backlight->props.brightness;
+
+	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi);
+	mipi_dsi_msleep(&dsi, 100);
+
+	s6e8aa5x01_mcs_protect(&dsi, ctx, false);
+
+	/* general panel settings */
+	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_PENTILE, 0xd8, 0xd8, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_PCD, 0x5c);
+	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_ERRFLAG, 0xed, 0xc7, 0x23, 0x67);
+	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_DISPCTL, 0x0c, 0x0c, 0xb9, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_LTPSCTL,
+				0x00, 0x45, 0x10, 0x10, 0x08, 0x32, 0x54, 0x00,
+				0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x48, 0x5e, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x03, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00,
+				0x08, 0x05, 0x2a, 0x54, 0x03, 0xcc, 0x00, 0xff,
+				0xfb, 0x03, 0x0d, 0x00, 0x11, 0x0f, 0x02, 0x03,
+				0x0b, 0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+				0x13, 0x13, 0x13, 0x13, 0x00, 0x02, 0x03, 0x0b,
+				0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+				0x13, 0x13);
+
+	/* sync the panel with the backlight's brightness level */
+	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].gamma, GAMMA_CMD_LEN);
+	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].aid, AID_CMD_LEN);
+	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_GAMMAUPD, 0x03);
+
+	s6e8aa5x01_mcs_protect(&dsi, ctx, true);
+
+	mipi_dsi_dcs_set_display_on_multi(&dsi);
+
+	return dsi.accum_err;
+}
+
+static int s6e8aa5x01_disable(struct drm_panel *panel)
+{
+	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
+	struct mipi_dsi_multi_context dsi = { .dsi = ctx->dsi };
+
+	mipi_dsi_dcs_set_display_off_multi(&dsi);
+	mipi_dsi_msleep(&dsi, 100);
+
+	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi);
+	mipi_dsi_msleep(&dsi, 150);
+
+	return dsi.accum_err;
+}
+
+static int s6e8aa5x01_get_modes(struct drm_panel *panel,
+				struct drm_connector *connector)
+{
+	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev, &ctx->mode);
+	if (!mode)
+		return -ENOMEM;
+
+	mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(connector, mode);
+	drm_mode_set_name(mode);
+
+	connector->display_info.width_mm = mode->width_mm;
+	connector->display_info.height_mm = mode->height_mm;
+	connector->display_info.bus_flags = ctx->bus_flags;
+
+	return 1;
+}
+
+static const struct backlight_ops s6e8aa5x01_bl_ops = {
+	.update_status = s6e8aa5x01_update_brightness,
+};
+
+static const struct drm_panel_funcs s6e8aa5x01_panel_funcs = {
+	.prepare = s6e8aa5x01_prepare,
+	.unprepare = s6e8aa5x01_unprepare,
+	.enable = s6e8aa5x01_enable,
+	.disable = s6e8aa5x01_disable,
+	.get_modes = s6e8aa5x01_get_modes,
+};
+
+static int s6e8aa5x01_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct s6e8aa5x01_ctx *ctx;
+	int ret;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->dsi = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	ctx->supplies[0].supply = "vdd";
+	ctx->supplies[1].supply = "vci";
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+				      ctx->supplies);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
+	if (IS_ERR(ctx->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+				     "Failed to get reset-gpios\n");
+
+	ret = devm_mutex_init(dev, &ctx->mcs_mutex);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to initialize mutex object\n");
+
+	ret = of_get_drm_panel_display_mode(dev->of_node, &ctx->mode,
+					    &ctx->bus_flags);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get panel timings\n");
+
+	ctx->backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
+							dsi, &s6e8aa5x01_bl_ops,
+							NULL);
+	if (IS_ERR(ctx->backlight))
+		return dev_err_probe(dev, PTR_ERR(ctx->backlight),
+				     "Failed to register backlight device\n");
+
+	ctx->backlight->props.type = BACKLIGHT_PLATFORM;
+	ctx->backlight->props.brightness = ARRAY_SIZE(s6e8aa5x01_cmds) - 1;
+	ctx->backlight->props.max_brightness = ARRAY_SIZE(s6e8aa5x01_cmds) - 1;
+
+	dsi->lanes = 4;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+			  MIPI_DSI_MODE_VIDEO_NO_HFP;
+
+	drm_panel_init(&ctx->panel, dev, &s6e8aa5x01_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
+	ctx->panel.prepare_prev_first = true;
+
+	drm_panel_add(&ctx->panel);
+
+	ret = devm_mipi_dsi_attach(dev, dsi);
+	if (ret < 0) {
+		drm_panel_remove(&ctx->panel);
+		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+	}
+
+	return 0;
+}
+
+static void s6e8aa5x01_remove(struct mipi_dsi_device *dsi)
+{
+	struct s6e8aa5x01_ctx *ctx = mipi_dsi_get_drvdata(dsi);
+
+	drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id s6e8aa5x01_of_device_id[] = {
+	{ .compatible = "samsung,s6e8aa5x01" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, s6e8aa5x01_of_device_id);
+
+static struct mipi_dsi_driver s6e8aa5x01_dsi_driver = {
+	.probe = s6e8aa5x01_probe,
+	.remove = s6e8aa5x01_remove,
+	.driver = {
+		.name = "panel-samsung-s6e8aa5x01",
+		.of_match_table = s6e8aa5x01_of_device_id,
+	},
+};
+module_mipi_dsi_driver(s6e8aa5x01_dsi_driver);
+
+MODULE_AUTHOR("Kaustabh Chakraborty <kauschluss@disroot.org>");
+MODULE_DESCRIPTION("Samsung S6E8AA5X01 Display Panel Driver");
+MODULE_LICENSE("GPL");

-- 
2.49.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver
  2025-06-12 14:52 ` [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver Kaustabh Chakraborty
@ 2025-06-12 15:30   ` Conor Dooley
  2025-06-12 17:10     ` Kaustabh Chakraborty
  0 siblings, 1 reply; 9+ messages in thread
From: Conor Dooley @ 2025-06-12 15:30 UTC (permalink / raw)
  To: Kaustabh Chakraborty
  Cc: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang, dri-devel,
	devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 430 bytes --]

On Thu, Jun 12, 2025 at 08:22:41PM +0530, Kaustabh Chakraborty wrote:
> Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Document the
> compatible and devicetree properties of this panel driver. Timings are
> provided through the devicetree node as panels are available in
> different sizes.
> 
> Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>

Acked-by: Conor Dooley <conor.dooley@microchip.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver
  2025-06-12 15:30   ` Conor Dooley
@ 2025-06-12 17:10     ` Kaustabh Chakraborty
  2025-06-12 17:48       ` Conor Dooley
  0 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2025-06-12 17:10 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang, dri-devel,
	devicetree, linux-kernel

On 2025-06-12 15:30, Conor Dooley wrote:
> On Thu, Jun 12, 2025 at 08:22:41PM +0530, Kaustabh Chakraborty wrote:
>> Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Document the
>> compatible and devicetree properties of this panel driver. Timings are
>> provided through the devicetree node as panels are available in
>> different sizes.
>> 
>> Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
> 
> Acked-by: Conor Dooley <conor.dooley@microchip.com>

Okay no, even this one has the ID wrong, ugh :(

>> +$id: http://devicetree.org/schemas/display/panel/samsung,s6e8aa0.yaml#

Will apply tag after fixing it.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver
  2025-06-12 17:10     ` Kaustabh Chakraborty
@ 2025-06-12 17:48       ` Conor Dooley
  0 siblings, 0 replies; 9+ messages in thread
From: Conor Dooley @ 2025-06-12 17:48 UTC (permalink / raw)
  To: Kaustabh Chakraborty
  Cc: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang, dri-devel,
	devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 792 bytes --]

On Thu, Jun 12, 2025 at 05:10:23PM +0000, Kaustabh Chakraborty wrote:
> On 2025-06-12 15:30, Conor Dooley wrote:
> > On Thu, Jun 12, 2025 at 08:22:41PM +0530, Kaustabh Chakraborty wrote:
> >> Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Document the
> >> compatible and devicetree properties of this panel driver. Timings are
> >> provided through the devicetree node as panels are available in
> >> different sizes.
> >> 
> >> Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
> > 
> > Acked-by: Conor Dooley <conor.dooley@microchip.com>
> 
> Okay no, even this one has the ID wrong, ugh :(
> 
> >> +$id: http://devicetree.org/schemas/display/panel/samsung,s6e8aa0.yaml#
> 
> Will apply tag after fixing it.

Thanks, I didn't spot it here either.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller
  2025-06-12 14:52 ` [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller Kaustabh Chakraborty
@ 2025-06-13  9:39   ` Thomas Zimmermann
  2025-06-13 11:03     ` Kaustabh Chakraborty
  0 siblings, 1 reply; 9+ messages in thread
From: Thomas Zimmermann @ 2025-06-13  9:39 UTC (permalink / raw)
  To: Kaustabh Chakraborty, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang
  Cc: dri-devel, devicetree, linux-kernel

Hi

Am 12.06.25 um 16:52 schrieb Kaustabh Chakraborty:
> Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Implement
> a basic panel driver for such panels.
>
> The driver also initializes a backlight device, which works by changing
> the panel's gamma values and aid brightness levels appropriately, with
> the help of look-up tables acquired from downstream kernel sources.
>
> Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
> ---
>   drivers/gpu/drm/panel/Kconfig                    |  11 +
>   drivers/gpu/drm/panel/Makefile                   |   1 +
>   drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c | 922 +++++++++++++++++++++++
>   3 files changed, 934 insertions(+)
>
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index d5aa1c95c6a45b2fea9b1d7a9e8a39fe617b860c..3d92ec3d7a1e85bf099e50e78b666fa38267d05c 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -833,6 +833,17 @@ config DRM_PANEL_SAMSUNG_S6E8AA0
>   	select DRM_MIPI_DSI
>   	select VIDEOMODE_HELPERS
>   
> +config DRM_PANEL_SAMSUNG_S6E8AA5X01
> +	tristate "Samsung S6E8AA5X01 panel"
> +	depends on GPIOLIB && OF && REGULATOR
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	help
> +	  Say Y here if you want to enable support for Samsung S6E8AA5X01 panel
> +	  controller. The controller is driven by the MIPI DSI protocol with 4
> +	  lanes. Panels are available in multiple sizes by vendors, such as in
> +	  720x1280@60Hz or 720x1480@60Hz.
> +
>   config DRM_PANEL_SAMSUNG_SOFEF00
>   	tristate "Samsung sofef00/s6e3fc2x01 OnePlus 6/6T DSI cmd mode panels"
>   	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index 73a39bc726045f3ce52fdeef8c0ec762a4a378c7..995cf2b22427897313f806280b0bc9a67a7b4879 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -86,6 +86,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24) += panel-samsung-s6e88a0-ams427ap24.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
> +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA5X01) += panel-samsung-s6e8aa5x01.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF00) += panel-samsung-sofef00.o
>   obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
>   obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..1804d82ed2d1fb8af0492f4a5bf07ba661f600fb
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01.c
> @@ -0,0 +1,922 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Samsung S6E8AA5X01 display panel driver.
> + *
> + * Copyright (C) 2025 Kaustabh Chakraborty <kauschluss@disroot.org>
> + */
> +
> +#include <linux/backlight.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_modes.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_probe_helper.h>
> +
> +/* Manufacturer Command Set */
> +#define MCS_AIDCTL		0xb2
> +#define MCS_ADAPTIVECTL		0xb5
> +#define MCS_ELVSS		0xb6
> +#define MCS_TEMPERCTL		0xb8
> +#define MCS_PENTILE		0xc0
> +#define MCS_GAMMACTL		0xca
> +#define MCS_LTPSCTL		0xcb
> +#define MCS_PCD			0xcc
> +#define MCS_ERRFLAG		0xe7
> +#define MCS_ACCESSPROT		0xf0
> +#define MCS_DISPCTL		0xf2
> +#define MCS_GAMMAUPD		0xf7
> +
> +#define GAMMA_CMD_LEN	34
> +#define AID_CMD_LEN	3
> +
> +static const struct {
> +	u8 gamma[GAMMA_CMD_LEN];
> +	u8 aid[AID_CMD_LEN];
> +} s6e8aa5x01_cmds[] = {
> +	{
> +		/* 5 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x94,
> +		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
> +		  0x8d, 0x8c, 0x8d, 0x89, 0x8c, 0x8e,
> +		  0x8e, 0x8f, 0x90, 0xa3, 0xa2, 0x9a,
> +		  0xcf, 0xca, 0x9f, 0xe6, 0xff, 0xb4,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0xa5 },
> +	}, {
> +		/* 6 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x95,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x8c, 0x8a, 0x8c, 0x85, 0x88, 0x8c,
> +		  0x8b, 0x8c, 0x8e, 0xa2, 0xa2, 0x9a,
> +		  0xd0, 0xcc, 0xa2, 0xed, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x95 },
> +	}, {
> +		/* 7 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x95,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x8c, 0x8a, 0x8c, 0x85, 0x88, 0x8c,
> +		  0x8b, 0x8c, 0x8e, 0xa2, 0xa2, 0x99,
> +		  0xc8, 0xc4, 0x9d, 0xed, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x89 },
> +	}, {
> +		/* 8 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
> +		  0x8a, 0x88, 0x8b, 0x83, 0x86, 0x8b,
> +		  0x8c, 0x8b, 0x8d, 0x9d, 0x9f, 0x97,
> +		  0xc7, 0xc3, 0x9c, 0xf5, 0xff, 0xbb,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x7e },
> +	}, {
> +		/* 9 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x8a, 0x82, 0x84, 0x88,
> +		  0x90, 0x8f, 0x91, 0x95, 0x97, 0x94,
> +		  0xc6, 0xc2, 0x9d, 0xf5, 0xff, 0xbb,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x73 },
> +	}, {
> +		/* 10 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x8a, 0x82, 0x84, 0x88,
> +		  0x90, 0x8f, 0x91, 0x94, 0x97, 0x93,
> +		  0xc6, 0xc2, 0x9e, 0xec, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x67 },
> +	}, {
> +		/* 11 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8a, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x8a, 0x82, 0x84, 0x88,
> +		  0x8b, 0x8b, 0x8d, 0x90, 0x93, 0x92,
> +		  0xc5, 0xc1, 0x9c, 0xf5, 0xff, 0xbb,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x56 },
> +	}, {
> +		/* 12 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
> +		  0x87, 0x86, 0x8a, 0x8c, 0x90, 0x8f,
> +		  0xcd, 0xc9, 0xa1, 0xec, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x4a },
> +	}, {
> +		/* 13 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
> +		  0x87, 0x86, 0x8a, 0x8c, 0x90, 0x8e,
> +		  0xc4, 0xbf, 0x9c, 0xf5, 0xff, 0xbb,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x3b },
> +	}, {
> +		/* 14 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
> +		  0x87, 0x86, 0x89, 0x8c, 0x90, 0x8f,
> +		  0xc2, 0xbf, 0x9c, 0xec, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x35 },
> +	}, {
> +		/* 15 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
> +		  0x87, 0x86, 0x89, 0x8c, 0x90, 0x8f,
> +		  0xb7, 0xb6, 0x96, 0xec, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x25 },
> +	}, {
> +		/* 16 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x82, 0x84, 0x88,
> +		  0x88, 0x86, 0x89, 0x8c, 0x90, 0x8f,
> +		  0xb7, 0xb6, 0x96, 0xec, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x20 },
> +	}, {
> +		/* 17 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x7f, 0x80, 0x86,
> +		  0x86, 0x85, 0x89, 0x88, 0x8c, 0x8e,
> +		  0xbf, 0xbe, 0x9c, 0xec, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x05, 0x11 },
> +	}, {
> +		/* 19 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x7f, 0x80, 0x86,
> +		  0x87, 0x85, 0x89, 0x88, 0x8c, 0x8e,
> +		  0xb3, 0xb4, 0x97, 0xeb, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0xf2 },
> +	}, {
> +		/* 20 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x95,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x89, 0x86, 0x89, 0x7f, 0x80, 0x86,
> +		  0x87, 0x85, 0x89, 0x89, 0x8c, 0x8e,
> +		  0xb3, 0xb4, 0x97, 0xeb, 0xff, 0xb7,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0xe4 },
> +	}, {
> +		/* 21 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x96,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x8a, 0x88, 0x8b, 0x7d, 0x7e, 0x84,
> +		  0x8c, 0x8a, 0x8c, 0x8e, 0x90, 0x8f,
> +		  0xb6, 0xb6, 0x97, 0xe3, 0xff, 0xb3,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0xd5 },
> +	}, {
> +		/* 22 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x97,
> +		  0x88, 0x89, 0x8b, 0x87, 0x87, 0x89,
> +		  0x8a, 0x88, 0x8b, 0x81, 0x82, 0x86,
> +		  0x87, 0x86, 0x88, 0x8e, 0x90, 0x8f,
> +		  0xb6, 0xb6, 0x95, 0xe3, 0xff, 0xb3,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0xc5 },
> +	}, {
> +		/* 24 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x97,
> +		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
> +		  0x87, 0x86, 0x88, 0x8e, 0x90, 0x8f,
> +		  0xb6, 0xb6, 0x94, 0xe3, 0xff, 0xb3,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0xa7 },
> +	}, {
> +		/* 25 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x98,
> +		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
> +		  0x87, 0x86, 0x87, 0x8e, 0x90, 0x8f,
> +		  0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0x95 },
> +	}, {
> +		/* 27 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x99,
> +		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8a, 0x83, 0x86, 0x8a,
> +		  0x88, 0x87, 0x87, 0x88, 0x8b, 0x8c,
> +		  0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0x76 },
> +	}, {
> +		/* 29 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x99,
> +		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x83, 0x86, 0x89,
> +		  0x88, 0x87, 0x88, 0x88, 0x8b, 0x8b,
> +		  0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0x54 },
> +	}, {
> +		/* 30 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9a,
> +		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8a, 0x84, 0x86, 0x8a,
> +		  0x87, 0x87, 0x87, 0x88, 0x8b, 0x8b,
> +		  0xbf, 0xbf, 0x99, 0xda, 0xfa, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0x44 },
> +	}, {
> +		/* 32 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9a,
> +		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
> +		  0x89, 0x87, 0x8a, 0x84, 0x86, 0x8a,
> +		  0x87, 0x87, 0x87, 0x89, 0x8b, 0x8b,
> +		  0xbf, 0xbf, 0x98, 0xd2, 0xf2, 0xac,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x04, 0x1f },
> +	}, {
> +		/* 34 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
> +		  0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8b, 0x87, 0x8b, 0x83, 0x86, 0x89,
> +		  0x87, 0x87, 0x88, 0x88, 0x8b, 0x8a,
> +		  0xbf, 0xbf, 0x98, 0xd2, 0xf2, 0xac,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x03, 0xff },
> +	}, {
> +		/* 37 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
> +		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
> +		  0x86, 0x86, 0x86, 0x8d, 0x90, 0x8d,
> +		  0xc0, 0xbf, 0x9a, 0xd2, 0xf2, 0xac,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x03, 0xd3 },
> +	}, {
> +		/* 39 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
> +		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86,
> +		  0x87, 0x86, 0x87, 0x8d, 0x90, 0x8d,
> +		  0xb6, 0xb6, 0x93, 0xda, 0xf9, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x03, 0xb3 },
> +	}, {
> +		/* 41 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
> +		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x85,
> +		  0x87, 0x86, 0x87, 0x8d, 0x90, 0x8d,
> +		  0xb6, 0xb6, 0x94, 0xda, 0xf9, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x03, 0x93 },
> +	}, {
> +		/* 44 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
> +		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
> +		  0x87, 0x86, 0x86, 0x85, 0x87, 0x8a,
> +		  0xbe, 0xbe, 0x99, 0xda, 0xf9, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x03, 0x66 },
> +	}, {
> +		/* 47 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b,
> +		  0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
> +		  0x88, 0x86, 0x87, 0x84, 0x87, 0x89,
> +		  0xb4, 0xb4, 0x94, 0xe2, 0xff, 0xb3,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x03, 0x40 },
> +	}, {
> +		/* 50 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
> +		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
> +		  0x88, 0x86, 0x87, 0x84, 0x87, 0x89,
> +		  0xb4, 0xb4, 0x95, 0xe2, 0xff, 0xb3,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x03, 0x0e },
> +	}, {
> +		/* 53 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
> +		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
> +		  0x88, 0x86, 0x87, 0x85, 0x87, 0x8a,
> +		  0xb4, 0xb4, 0x96, 0xe2, 0xff, 0xb3,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0xe2 },
> +	}, {
> +		/* 56 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
> +		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86,
> +		  0x88, 0x86, 0x87, 0x85, 0x87, 0x8a,
> +		  0xab, 0xab, 0x90, 0xdd, 0xf7, 0xaf,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0xb5 },
> +	}, {
> +		/* 60 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
> +		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x82, 0x82, 0x87,
> +		  0x83, 0x81, 0x84, 0x81, 0x84, 0x88,
> +		  0xb3, 0xb3, 0x96, 0xcf, 0xe5, 0xa8,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x77 },
> +	}, {
> +		/* 64 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c,
> +		  0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a,
> +		  0x8a, 0x87, 0x8b, 0x82, 0x82, 0x87,
> +		  0x83, 0x81, 0x84, 0x82, 0x84, 0x88,
> +		  0xb2, 0xb3, 0x97, 0xcf, 0xe5, 0xa8,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x36 },
> +	}, {
> +		/* 68 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x9b, 0x00, 0xa6, 0x00, 0x9d,
> +		  0x88, 0x88, 0x89, 0x89, 0x89, 0x8b,
> +		  0x8a, 0x88, 0x8b, 0x7f, 0x80, 0x86,
> +		  0x88, 0x86, 0x87, 0x7d, 0x7f, 0x85,
> +		  0xb2, 0xb3, 0x97, 0xcf, 0xe5, 0xa8,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 72 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0x9c, 0x00, 0xa9, 0x00, 0xa0,
> +		  0x88, 0x88, 0x89, 0x88, 0x88, 0x8a,
> +		  0x8c, 0x8a, 0x8d, 0x7f, 0x81, 0x85,
> +		  0x84, 0x82, 0x84, 0x85, 0x87, 0x8a,
> +		  0xaa, 0xab, 0x93, 0xcf, 0xe5, 0xa8,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 77 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xa1, 0x00, 0xad, 0x00, 0xa5,
> +		  0x89, 0x89, 0x8a, 0x88, 0x87, 0x89,
> +		  0x8c, 0x89, 0x8d, 0x7f, 0x81, 0x85,
> +		  0x84, 0x83, 0x84, 0x81, 0x83, 0x86,
> +		  0xaa, 0xab, 0x93, 0xc0, 0xd3, 0xa1,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 82 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xa5, 0x00, 0xb0, 0x00, 0xa9,
> +		  0x88, 0x89, 0x89, 0x85, 0x86, 0x89,
> +		  0x8a, 0x88, 0x8b, 0x82, 0x82, 0x87,
> +		  0x81, 0x80, 0x82, 0x89, 0x8b, 0x8b,
> +		  0xa2, 0xa3, 0x8e, 0xc0, 0xd3, 0xa1,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 87 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xab, 0x00, 0xb4, 0x00, 0xad,
> +		  0x88, 0x89, 0x8a, 0x84, 0x86, 0x88,
> +		  0x8a, 0x88, 0x8b, 0x7f, 0x7f, 0x84,
> +		  0x86, 0x84, 0x85, 0x85, 0x86, 0x88,
> +		  0xa2, 0xa3, 0x8f, 0xc0, 0xd3, 0xa1,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 93 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xaf, 0x00, 0xb9, 0x00, 0xb1,
> +		  0x88, 0x89, 0x8a, 0x84, 0x85, 0x87,
> +		  0x8a, 0x89, 0x8b, 0x7e, 0x7e, 0x83,
> +		  0x87, 0x86, 0x86, 0x88, 0x8a, 0x89,
> +		  0x9c, 0x9c, 0x8b, 0xc0, 0xd3, 0xa1,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 98 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xb3, 0x00, 0xbc, 0x00, 0xb5,
> +		  0x88, 0x88, 0x88, 0x84, 0x84, 0x86,
> +		  0x8a, 0x88, 0x8a, 0x7f, 0x7f, 0x84,
> +		  0x84, 0x83, 0x84, 0x88, 0x8a, 0x89,
> +		  0x9c, 0x9c, 0x8b, 0xc0, 0xd3, 0xa1,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 105 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xb7, 0x00, 0xc0, 0x00, 0xba,
> +		  0x87, 0x87, 0x88, 0x85, 0x85, 0x87,
> +		  0x89, 0x88, 0x89, 0x7f, 0x7f, 0x83,
> +		  0x81, 0x80, 0x82, 0x88, 0x8a, 0x89,
> +		  0x9c, 0x9c, 0x8c, 0xb2, 0xc2, 0x9a,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 111 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xbb, 0x00, 0xc3, 0x00, 0xbe,
> +		  0x87, 0x87, 0x88, 0x85, 0x85, 0x88,
> +		  0x88, 0x87, 0x89, 0x80, 0x80, 0x84,
> +		  0x81, 0x81, 0x82, 0x85, 0x86, 0x87,
> +		  0x9c, 0x9c, 0x8b, 0xb2, 0xc2, 0x9a,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x15 },
> +	}, {
> +		/* 119 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4,
> +		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
> +		  0x87, 0x85, 0x87, 0x82, 0x81, 0x84,
> +		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
> +		  0x9c, 0x9c, 0x8c, 0xb2, 0xc2, 0x9a,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x02, 0x14 },
> +	}, {
> +		/* 126 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4,
> +		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
> +		  0x87, 0x85, 0x87, 0x82, 0x81, 0x84,
> +		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
> +		  0x9c, 0x9c, 0x8d, 0xb2, 0xc2, 0x9a,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x01, 0xde },
> +	}, {
> +		/* 134 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4,
> +		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
> +		  0x87, 0x85, 0x87, 0x82, 0x81, 0x84,
> +		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
> +		  0x9c, 0x9c, 0x8d, 0xa4, 0xb0, 0x92,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x01, 0x94 },
> +	}, {
> +		/* 143 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
> +		  0x87, 0x87, 0x88, 0x82, 0x84, 0x86,
> +		  0x87, 0x85, 0x87, 0x82, 0x81, 0x85,
> +		  0x83, 0x82, 0x83, 0x80, 0x81, 0x84,
> +		  0x92, 0x92, 0x89, 0xab, 0xb6, 0x96,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x01, 0x46 },
> +	}, {
> +		/* 152 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
> +		  0x87, 0x87, 0x88, 0x83, 0x84, 0x86,
> +		  0x87, 0x85, 0x87, 0x81, 0x81, 0x85,
> +		  0x84, 0x82, 0x83, 0x80, 0x81, 0x83,
> +		  0x92, 0x92, 0x8b, 0xab, 0xb6, 0x96,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0xfa },
> +	}, {
> +		/* 162 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
> +		  0x87, 0x87, 0x88, 0x83, 0x84, 0x86,
> +		  0x87, 0x85, 0x87, 0x81, 0x81, 0x84,
> +		  0x84, 0x82, 0x84, 0x80, 0x81, 0x83,
> +		  0x92, 0x92, 0x8b, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0xac },
> +	}, {
> +		/* 172 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3,
> +		  0x87, 0x87, 0x88, 0x83, 0x84, 0x86,
> +		  0x87, 0x85, 0x87, 0x81, 0x81, 0x84,
> +		  0x84, 0x82, 0x83, 0x80, 0x81, 0x84,
> +		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x57 },
> +	}, {
> +		/* 183 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc2, 0x00, 0xca, 0x00, 0xc5,
> +		  0x86, 0x86, 0x87, 0x85, 0x84, 0x87,
> +		  0x87, 0x86, 0x88, 0x7e, 0x80, 0x83,
> +		  0x84, 0x82, 0x83, 0x80, 0x81, 0x83,
> +		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 195 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xc7, 0x00, 0xce, 0x00, 0xc9,
> +		  0x86, 0x87, 0x86, 0x83, 0x83, 0x85,
> +		  0x85, 0x84, 0x86, 0x82, 0x82, 0x85,
> +		  0x80, 0x80, 0x81, 0x81, 0x81, 0x84,
> +		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 207 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xcc, 0x00, 0xd2, 0x00, 0xce,
> +		  0x86, 0x86, 0x87, 0x81, 0x83, 0x84,
> +		  0x84, 0x82, 0x84, 0x83, 0x83, 0x85,
> +		  0x81, 0x81, 0x82, 0x7c, 0x7d, 0x81,
> +		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 220 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xd1, 0x00, 0xd6, 0x00, 0xd3,
> +		  0x86, 0x86, 0x86, 0x81, 0x83, 0x84,
> +		  0x84, 0x82, 0x84, 0x80, 0x80, 0x83,
> +		  0x81, 0x81, 0x82, 0x7c, 0x7d, 0x81,
> +		  0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 234 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xd6, 0x00, 0xdb, 0x00, 0xd8,
> +		  0x85, 0x85, 0x85, 0x81, 0x83, 0x84,
> +		  0x83, 0x82, 0x83, 0x80, 0x80, 0x82,
> +		  0x84, 0x82, 0x83, 0x79, 0x79, 0x7e,
> +		  0x93, 0x92, 0x8d, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 249 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xdc, 0x00, 0xe0, 0x00, 0xdd,
> +		  0x84, 0x84, 0x84, 0x81, 0x82, 0x83,
> +		  0x84, 0x82, 0x84, 0x7f, 0x7f, 0x82,
> +		  0x81, 0x80, 0x81, 0x80, 0x81, 0x82,
> +		  0x8c, 0x8c, 0x86, 0x9d, 0xa4, 0x8e,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 265 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xe2, 0x00, 0xe5, 0x00, 0xe3,
> +		  0x83, 0x83, 0x83, 0x81, 0x82, 0x83,
> +		  0x82, 0x82, 0x83, 0x82, 0x81, 0x83,
> +		  0x7f, 0x7e, 0x80, 0x7c, 0x7d, 0x80,
> +		  0x8c, 0x8c, 0x86, 0x8e, 0x92, 0x87,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 282 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xe8, 0x00, 0xea, 0x00, 0xe9,
> +		  0x83, 0x83, 0x83, 0x80, 0x82, 0x82,
> +		  0x81, 0x82, 0x82, 0x82, 0x81, 0x82,
> +		  0x81, 0x80, 0x81, 0x80, 0x80, 0x81,
> +		  0x85, 0x85, 0x83, 0x8e, 0x92, 0x87,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 300 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xed, 0x00, 0xef, 0x00, 0xed,
> +		  0x81, 0x82, 0x81, 0x81, 0x81, 0x82,
> +		  0x82, 0x82, 0x83, 0x80, 0x80, 0x81,
> +		  0x81, 0x81, 0x82, 0x83, 0x83, 0x83,
> +		  0x80, 0x80, 0x7f, 0x8e, 0x92, 0x87,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 316 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf3,
> +		  0x80, 0x81, 0x80, 0x81, 0x81, 0x81,
> +		  0x82, 0x82, 0x82, 0x81, 0x80, 0x81,
> +		  0x82, 0x82, 0x83, 0x80, 0x80, 0x80,
> +		  0x80, 0x80, 0x7f, 0x80, 0x80, 0x80,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 333 nits */
> +		{ MCS_GAMMACTL,
> +		  0x00, 0xf8, 0x00, 0xf8, 0x00, 0xf8,
> +		  0x80, 0x81, 0x80, 0x81, 0x80, 0x81,
> +		  0x81, 0x82, 0x82, 0x81, 0x80, 0x81,
> +		  0x83, 0x83, 0x83, 0x7e, 0x7d, 0x7e,
> +		  0x80, 0x80, 0x7f, 0x80, 0x80, 0x80,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	}, {
> +		/* 360 nits */
> +		{ MCS_GAMMACTL,
> +		  0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
> +		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
> +		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
> +		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
> +		  0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
> +		  0x00, 0x00, 0x00, },
> +		{ MCS_AIDCTL, 0x00, 0x10 },
> +	},
> +};
> +
> +struct s6e8aa5x01_ctx {
> +	struct drm_panel panel;
> +	struct mipi_dsi_device *dsi;
> +	struct drm_display_mode mode;
> +	struct backlight_device *backlight;
> +	struct regulator_bulk_data supplies[2];
> +	struct gpio_desc *reset_gpio;
> +	struct mutex mcs_mutex;
> +	u32 bus_flags;
> +	u32 width;
> +	u32 height;
> +};
> +
> +static inline struct s6e8aa5x01_ctx *to_s6e8aa5x01_ctx(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct s6e8aa5x01_ctx, panel);
> +}
> +
> +static void s6e8aa5x01_mcs_protect(struct mipi_dsi_multi_context *dsi,
> +				   struct s6e8aa5x01_ctx *ctx, bool protect)

I found this interface confusing. Rather split it up into .  It also 
does two different things AFAICT.

- The mcs_mutex protects against concurrent access from update_status 
and enable

- MSC_ACCESSPROT enable access to hardware state.

Maybe try this:

- Move msc_mutex into the callers, so that ->update_status and ->enable 
acquire and release the lock.

- Move MCS_ACCESSPROT into ->enable and ->disable and leave it 
accessible, if the hardware allows that.
> +{
> +	if (protect) {
> +		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0xa5, 0xa5);
> +		mutex_unlock(&ctx->mcs_mutex);
> +	} else {
> +		mutex_lock(&ctx->mcs_mutex);
> +		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0x5a, 0x5a);
> +	}
> +}
> +
> +static int s6e8aa5x01_update_brightness(struct backlight_device *backlight)#

Maybe call this function s6e8aa5x01_update_status() to match the callback.

> +{
> +	struct mipi_dsi_multi_context dsi = { .dsi = bl_get_data(backlight) };
> +	struct s6e8aa5x01_ctx *ctx = mipi_dsi_get_drvdata(dsi.dsi);
> +	u16 lvl = backlight->props.brightness;

backlight_get_brightness() here ?


I think you should also check panel->enabled and return if false. AFAIU 
there will be no gamma changes on disabled hardware anyway.

> +
> +	s6e8aa5x01_mcs_protect(&dsi, ctx, false);
> +
> +	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].gamma, GAMMA_CMD_LEN);
> +	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].aid, AID_CMD_LEN);
> +	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_GAMMAUPD, 0x03);
> +
> +	s6e8aa5x01_mcs_protect(&dsi, ctx, true);
> +
> +	return dsi.accum_err;
> +}
> +
> +static int s6e8aa5x01_prepare(struct drm_panel *panel)
> +{
> +	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
> +	struct device *dev = &ctx->dsi->dev;
> +	int ret;
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to enable regulators: %d\n", ret);
> +		return ret;
> +	}
> +
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
> +	usleep_range(5000, 6000);
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +	usleep_range(5000, 6000);
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
> +	usleep_range(10000, 11000);
> +
> +	return 0;
> +}
> +
> +static int s6e8aa5x01_unprepare(struct drm_panel *panel)
> +{
> +	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
> +
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +	usleep_range(5000, 6000);
> +
> +	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> +
> +	return 0;
> +}
> +
> +static int s6e8aa5x01_enable(struct drm_panel *panel)
> +{
> +	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
> +	struct mipi_dsi_multi_context dsi = { .dsi = ctx->dsi };
> +	u16 lvl = ctx->backlight->props.brightness;

backlight_get_brightness() here ?

> +
> +	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi);
> +	mipi_dsi_msleep(&dsi, 100);
> +
> +	s6e8aa5x01_mcs_protect(&dsi, ctx, false);
> +
> +	/* general panel settings */
> +	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_PENTILE, 0xd8, 0xd8, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_PCD, 0x5c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_ERRFLAG, 0xed, 0xc7, 0x23, 0x67);
> +	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_DISPCTL, 0x0c, 0x0c, 0xb9, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_LTPSCTL,
> +				0x00, 0x45, 0x10, 0x10, 0x08, 0x32, 0x54, 0x00,
> +				0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00,
> +				0x00, 0x00, 0x48, 0x5e, 0x00, 0x00, 0x00, 0x00,
> +				0x00, 0x03, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00,
> +				0x08, 0x05, 0x2a, 0x54, 0x03, 0xcc, 0x00, 0xff,
> +				0xfb, 0x03, 0x0d, 0x00, 0x11, 0x0f, 0x02, 0x03,
> +				0x0b, 0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
> +				0x13, 0x13, 0x13, 0x13, 0x00, 0x02, 0x03, 0x0b,
> +				0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
> +				0x13, 0x13);
> +
> +	/* sync the panel with the backlight's brightness level */
> +	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].gamma, GAMMA_CMD_LEN);
> +	mipi_dsi_dcs_write_buffer_multi(&dsi, s6e8aa5x01_cmds[lvl].aid, AID_CMD_LEN);
> +	mipi_dsi_dcs_write_seq_multi(&dsi, MCS_GAMMAUPD, 0x03);
> +
> +	s6e8aa5x01_mcs_protect(&dsi, ctx, true);
> +
> +	mipi_dsi_dcs_set_display_on_multi(&dsi);
> +
> +	return dsi.accum_err;
> +}
> +
> +static int s6e8aa5x01_disable(struct drm_panel *panel)
> +{
> +	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
> +	struct mipi_dsi_multi_context dsi = { .dsi = ctx->dsi };
> +
> +	mipi_dsi_dcs_set_display_off_multi(&dsi);
> +	mipi_dsi_msleep(&dsi, 100);
> +
> +	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi);
> +	mipi_dsi_msleep(&dsi, 150);
> +
> +	return dsi.accum_err;
> +}
> +
> +static int s6e8aa5x01_get_modes(struct drm_panel *panel,
> +				struct drm_connector *connector)
> +{
> +	struct s6e8aa5x01_ctx *ctx = to_s6e8aa5x01_ctx(panel);
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_duplicate(connector->dev, &ctx->mode);
> +	if (!mode)
> +		return -ENOMEM;
> +
> +	mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +	drm_mode_probed_add(connector, mode);
> +	drm_mode_set_name(mode);
> +
> +	connector->display_info.width_mm = mode->width_mm;
> +	connector->display_info.height_mm = mode->height_mm;
> +	connector->display_info.bus_flags = ctx->bus_flags;
> +
> +	return 1;
> +}
> +
> +static const struct backlight_ops s6e8aa5x01_bl_ops = {
> +	.update_status = s6e8aa5x01_update_brightness,
> +};
> +
> +static const struct drm_panel_funcs s6e8aa5x01_panel_funcs = {
> +	.prepare = s6e8aa5x01_prepare,
> +	.unprepare = s6e8aa5x01_unprepare,
> +	.enable = s6e8aa5x01_enable,
> +	.disable = s6e8aa5x01_disable,
> +	.get_modes = s6e8aa5x01_get_modes,
> +};
> +
> +static int s6e8aa5x01_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct device *dev = &dsi->dev;
> +	struct s6e8aa5x01_ctx *ctx;
> +	int ret;
> +
> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);

You're possibly using the instance after the hardware device has been 
removed. Alloc with drmm_kzalloc() or you might end up with UAF errors.

> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	ctx->dsi = dsi;
> +	mipi_dsi_set_drvdata(dsi, ctx);
> +
> +	ctx->supplies[0].supply = "vdd";
> +	ctx->supplies[1].supply = "vci";
> +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
> +				      ctx->supplies);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to get regulators\n");
> +
> +	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
> +	if (IS_ERR(ctx->reset_gpio))
> +		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
> +				     "Failed to get reset-gpios\n");
> +
> +	ret = devm_mutex_init(dev, &ctx->mcs_mutex);

You're taking this mutex in DRM code, so rather use drmm_mutex_init() here.

Best regards
Thomas


> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to initialize mutex object\n");
> +
> +	ret = of_get_drm_panel_display_mode(dev->of_node, &ctx->mode,
> +					    &ctx->bus_flags);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to get panel timings\n");
> +
> +	ctx->backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
> +							dsi, &s6e8aa5x01_bl_ops,
> +							NULL);
> +	if (IS_ERR(ctx->backlight))
> +		return dev_err_probe(dev, PTR_ERR(ctx->backlight),
> +				     "Failed to register backlight device\n");
> +
> +	ctx->backlight->props.type = BACKLIGHT_PLATFORM;
> +	ctx->backlight->props.brightness = ARRAY_SIZE(s6e8aa5x01_cmds) - 1;
> +	ctx->backlight->props.max_brightness = ARRAY_SIZE(s6e8aa5x01_cmds) - 1;
> +
> +	dsi->lanes = 4;
> +	dsi->format = MIPI_DSI_FMT_RGB888;
> +	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> +			  MIPI_DSI_MODE_VIDEO_NO_HFP;
> +
> +	drm_panel_init(&ctx->panel, dev, &s6e8aa5x01_panel_funcs,
> +		       DRM_MODE_CONNECTOR_DSI);
> +	ctx->panel.prepare_prev_first = true;
> +
> +	drm_panel_add(&ctx->panel);
> +
> +	ret = devm_mipi_dsi_attach(dev, dsi);
> +	if (ret < 0) {
> +		drm_panel_remove(&ctx->panel);
> +		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static void s6e8aa5x01_remove(struct mipi_dsi_device *dsi)
> +{
> +	struct s6e8aa5x01_ctx *ctx = mipi_dsi_get_drvdata(dsi);
> +
> +	drm_panel_remove(&ctx->panel);
> +}
> +
> +static const struct of_device_id s6e8aa5x01_of_device_id[] = {
> +	{ .compatible = "samsung,s6e8aa5x01" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, s6e8aa5x01_of_device_id);
> +
> +static struct mipi_dsi_driver s6e8aa5x01_dsi_driver = {
> +	.probe = s6e8aa5x01_probe,
> +	.remove = s6e8aa5x01_remove,
> +	.driver = {
> +		.name = "panel-samsung-s6e8aa5x01",
> +		.of_match_table = s6e8aa5x01_of_device_id,
> +	},
> +};
> +module_mipi_dsi_driver(s6e8aa5x01_dsi_driver);
> +
> +MODULE_AUTHOR("Kaustabh Chakraborty <kauschluss@disroot.org>");
> +MODULE_DESCRIPTION("Samsung S6E8AA5X01 Display Panel Driver");
> +MODULE_LICENSE("GPL");
>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller
  2025-06-13  9:39   ` Thomas Zimmermann
@ 2025-06-13 11:03     ` Kaustabh Chakraborty
  2025-06-13 11:40       ` Thomas Zimmermann
  0 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2025-06-13 11:03 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang, dri-devel,
	devicetree, linux-kernel

On 2025-06-13 09:39, Thomas Zimmermann wrote:
> Hi
> 
> Am 12.06.25 um 16:52 schrieb Kaustabh Chakraborty:
>> Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Implement
>> a basic panel driver for such panels.
>>
>> The driver also initializes a backlight device, which works by changing
>> the panel's gamma values and aid brightness levels appropriately, with
>> the help of look-up tables acquired from downstream kernel sources.
>>
>> Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>

[...]

>> +
>> +static void s6e8aa5x01_mcs_protect(struct mipi_dsi_multi_context *dsi,
>> +				   struct s6e8aa5x01_ctx *ctx, bool protect)
> 
> I found this interface confusing. Rather split it up into .  It also does two different things AFAICT.
> 
> - The mcs_mutex protects against concurrent access from update_status and enable

mcs_mutex is meant to prevent any early access protection of the MCS commands.
Suppose there are two functions, A and B, accessing MCS.

ENTRY: A()
(access protection disabled)
...

ENTRY: B()
(access protection disabled)
...
(access protection enabled)
EXIT: B()

[!] cannot access MCS commands here anymore
(access protection enabled)
EXIT: A()

And to avoid such errors a mutex is provided.

> 
> - MSC_ACCESSPROT enable access to hardware state.
> 
> Maybe try this:
> 
> - Move msc_mutex into the callers, so that ->update_status and ->enable acquire and release the lock.
> 
> - Move MCS_ACCESSPROT into ->enable and ->disable and leave it accessible, if the hardware allows that.

Yeah this is a good idea, I'll try it.

>> +{
>> +	if (protect) {
>> +		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0xa5, 0xa5);
>> +		mutex_unlock(&ctx->mcs_mutex);
>> +	} else {
>> +		mutex_lock(&ctx->mcs_mutex);
>> +		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0x5a, 0x5a);
>> +	}
>> +}
>> +
>> +static int s6e8aa5x01_update_brightness(struct backlight_device *backlight)#
> 
> Maybe call this function s6e8aa5x01_update_status() to match the callback.
> 
>> +{
>> +	struct mipi_dsi_multi_context dsi = { .dsi = bl_get_data(backlight) };
>> +	struct s6e8aa5x01_ctx *ctx = mipi_dsi_get_drvdata(dsi.dsi);
>> +	u16 lvl = backlight->props.brightness;
> 
> backlight_get_brightness() here ?
> 
> 
> I think you should also check panel->enabled and return if false. AFAIU there will be no gamma changes on disabled hardware anyway.
>

The enable function is never executed when the panel is disabled. This is
because flag checking is done by drm_panel anyway. See drm_panel_enable()
in drivers/gpu/drm/drm_panel.c [1]

>> +
>> +static int s6e8aa5x01_probe(struct mipi_dsi_device *dsi)
>> +{
>> +	struct device *dev = &dsi->dev;
>> +	struct s6e8aa5x01_ctx *ctx;
>> +	int ret;
>> +
>> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> 
> You're possibly using the instance after the hardware device has been removed. Alloc with drmm_kzalloc() or you might end up with UAF errors.

Hmm, none of the panel drivers are using drmm_kzalloc(), or even any
drmm_*(). Are you sure I must use it?

>> +	ret = devm_mutex_init(dev, &ctx->mcs_mutex);
> 
> You're taking this mutex in DRM code, so rather use drmm_mutex_init() here.

(The comment by me above applies here too)

> 
> Best regards
> Thomas

[1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/gpu/drm/drm_panel.c#n209

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller
  2025-06-13 11:03     ` Kaustabh Chakraborty
@ 2025-06-13 11:40       ` Thomas Zimmermann
  0 siblings, 0 replies; 9+ messages in thread
From: Thomas Zimmermann @ 2025-06-13 11:40 UTC (permalink / raw)
  To: Kaustabh Chakraborty
  Cc: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jessica Zhang, dri-devel,
	devicetree, linux-kernel

Hi

Am 13.06.25 um 13:03 schrieb Kaustabh Chakraborty:
> On 2025-06-13 09:39, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 12.06.25 um 16:52 schrieb Kaustabh Chakraborty:
>>> Samsung S6E8AA5X01 is an AMOLED MIPI DSI panel controller. Implement
>>> a basic panel driver for such panels.
>>>
>>> The driver also initializes a backlight device, which works by changing
>>> the panel's gamma values and aid brightness levels appropriately, with
>>> the help of look-up tables acquired from downstream kernel sources.
>>>
>>> Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
> [...]
>
>>> +
>>> +static void s6e8aa5x01_mcs_protect(struct mipi_dsi_multi_context *dsi,
>>> +				   struct s6e8aa5x01_ctx *ctx, bool protect)
>> I found this interface confusing. Rather split it up into .  It also does two different things AFAICT.
>>
>> - The mcs_mutex protects against concurrent access from update_status and enable
> mcs_mutex is meant to prevent any early access protection of the MCS commands.
> Suppose there are two functions, A and B, accessing MCS.
>
> ENTRY: A()
> (access protection disabled)
> ...
>
> ENTRY: B()
> (access protection disabled)
> ...
> (access protection enabled)
> EXIT: B()
>
> [!] cannot access MCS commands here anymore
> (access protection enabled)
> EXIT: A()
>
> And to avoid such errors a mutex is provided.

This mutex protects a lot more than just the access flags. It prevents 
backlight and enable code to concurrently set gamma on the device. Even 
if you move the MCS_ACCESSPROT to enable/disable helpers, you'll likely 
need the mutex around the gamma updates.

But there's maybe an easy fix. See that the panel code already calls the 
backlight helpers in its enable/disable [1][2] functions. They will 
invoke ->update_status with the proper locking. [3] This means that you 
shouldn't program gamma in the ->enable callback. Leave everything in 
->update_status and let your panel helpers deal with it. No need for 
mcs_mutex at all.

[1] 
https://elixir.bootlin.com/linux/v6.15.1/source/drivers/gpu/drm/drm_panel.c#L235
[2] 
https://elixir.bootlin.com/linux/v6.15.1/source/drivers/gpu/drm/drm_panel.c#L275
[3] 
https://elixir.bootlin.com/linux/v6.15.1/source/include/linux/backlight.h#L318

>
>> - MSC_ACCESSPROT enable access to hardware state.
>>
>> Maybe try this:
>>
>> - Move msc_mutex into the callers, so that ->update_status and ->enable acquire and release the lock.
>>
>> - Move MCS_ACCESSPROT into ->enable and ->disable and leave it accessible, if the hardware allows that.
> Yeah this is a good idea, I'll try it.
>
>>> +{
>>> +	if (protect) {
>>> +		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0xa5, 0xa5);
>>> +		mutex_unlock(&ctx->mcs_mutex);
>>> +	} else {
>>> +		mutex_lock(&ctx->mcs_mutex);
>>> +		mipi_dsi_dcs_write_seq_multi(dsi, MCS_ACCESSPROT, 0x5a, 0x5a);
>>> +	}
>>> +}
>>> +
>>> +static int s6e8aa5x01_update_brightness(struct backlight_device *backlight)#
>> Maybe call this function s6e8aa5x01_update_status() to match the callback.
>>
>>> +{
>>> +	struct mipi_dsi_multi_context dsi = { .dsi = bl_get_data(backlight) };
>>> +	struct s6e8aa5x01_ctx *ctx = mipi_dsi_get_drvdata(dsi.dsi);
>>> +	u16 lvl = backlight->props.brightness;
>> backlight_get_brightness() here ?
>>
>>
>> I think you should also check panel->enabled and return if false. AFAIU there will be no gamma changes on disabled hardware anyway.
>>
> The enable function is never executed when the panel is disabled. This is
> because flag checking is done by drm_panel anyway. See drm_panel_enable()
> in drivers/gpu/drm/drm_panel.c [1]

What I mean is: the drm_panel.enabled flag is set at [4] and cleared at 
[5]. It tells you that the panel is running. If someone tries to update 
the backlight brightness while the panel is not enabled, you likely what 
to return here without touching hardware.

[4] 
https://elixir.bootlin.com/linux/v6.15.1/source/drivers/gpu/drm/drm_panel.c#L285
[5] 
https://elixir.bootlin.com/linux/v6.15.1/source/drivers/gpu/drm/drm_panel.c#L233

>
>>> +
>>> +static int s6e8aa5x01_probe(struct mipi_dsi_device *dsi)
>>> +{
>>> +	struct device *dev = &dsi->dev;
>>> +	struct s6e8aa5x01_ctx *ctx;
>>> +	int ret;
>>> +
>>> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>> You're possibly using the instance after the hardware device has been removed. Alloc with drmm_kzalloc() or you might end up with UAF errors.
> Hmm, none of the panel drivers are using drmm_kzalloc(), or even any
> drmm_*(). Are you sure I must use it?

Then leave it as it is. Maybe one of the panel maintainers can confirm.

I still don't trust it to not possibly blow up. devm_ is released when 
the hardware device goes away.

Best regards
Thomas

>
>>> +	ret = devm_mutex_init(dev, &ctx->mcs_mutex);
>> You're taking this mutex in DRM code, so rather use drmm_mutex_init() here.
> (The comment by me above applies here too)
>
>> Best regards
>> Thomas
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/gpu/drm/drm_panel.c#n209

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-06-13 11:40 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-12 14:52 [PATCH 0/2] Add driver for Samsung S6E8AA5X01 panel controller Kaustabh Chakraborty
2025-06-12 14:52 ` [PATCH 1/2] dt-bindings: display: panel: document Samsung S6E8AA5X01 panel driver Kaustabh Chakraborty
2025-06-12 15:30   ` Conor Dooley
2025-06-12 17:10     ` Kaustabh Chakraborty
2025-06-12 17:48       ` Conor Dooley
2025-06-12 14:52 ` [PATCH 2/2] drm: panel: add support for Samsung S6E8AA5X01 panel controller Kaustabh Chakraborty
2025-06-13  9:39   ` Thomas Zimmermann
2025-06-13 11:03     ` Kaustabh Chakraborty
2025-06-13 11:40       ` Thomas Zimmermann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).