devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] drm/panel: Add support for Novatek NT36532 panel
@ 2026-07-29 16:08 Junjie Cao
  2026-07-29 16:08 ` [PATCH v2 1/2] dt-bindings: display: panel: Add Novatek NT36532 Junjie Cao
  2026-07-29 16:08 ` [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver Junjie Cao
  0 siblings, 2 replies; 5+ messages in thread
From: Junjie Cao @ 2026-07-29 16:08 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: Junjie Cao, Dmitry Baryshkov, Konrad Dybcio, Pengyu Luo,
	dri-devel, devicetree, linux-arm-msm, linux-kernel

This series adds support for panels using the Novatek NT36532 Display
Driver IC, a dual-DSI, dual-DSC controller that requires DPU support
for MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT.

The first user is the CSOT PPC100HB1-1 panel found in the OnePlus Pad 2
(OnePlus Pad Pro in China) tablet: 3000x2120, dual-DSI in bonded mode,
DSC 1.2 with two slices per line.

This has been tested on the OnePlus Pad 2: the panel comes up in its
native 3000x2120 mode at 120Hz over dual-DSI in bonded mode with DSC,
and displays a stable image.

Changes in v2:
- Rebase onto next-20260727.
- Update to the new DRM APIs: devm_drm_panel_alloc(), devm_drm_panel_add().
- Drop the driver-private 'dsc_slice_per_pkt' plumbing and rely on
  MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT instead.
- Send DCS commands through the second DSI link in dual-DSI mode.
- Change the refresh rate control register 0xb3 value from 0x41 to 0x40.
- Drop the of_node assignment when registering the secondary DSI device,
  matching panel-novatek-nt36523.
- Update author email to junjie.cao@linux.dev.
- Pick up Conor's Acked-by on the binding.
- Link to v1: https://lore.kernel.org/all/20251001135914.13754-1-caojunjie650@gmail.com

Junjie Cao (2):
  dt-bindings: display: panel: Add Novatek NT36532
  drm/panel: Add Novatek NT36532 panel driver

 .../display/panel/novatek,nt36532.yaml        |  83 ++++
 MAINTAINERS                                   |   7 +
 drivers/gpu/drm/panel/Kconfig                 |  10 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-novatek-nt36532.c | 430 ++++++++++++++++++
 5 files changed, 531 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/novatek,nt36532.yaml
 create mode 100644 drivers/gpu/drm/panel/panel-novatek-nt36532.c


base-commit: 0d33d21e47d9dc66f91e44da3fc9220c74d93df7
-- 
2.43.0


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

* [PATCH v2 1/2] dt-bindings: display: panel: Add Novatek NT36532
  2026-07-29 16:08 [PATCH v2 0/2] drm/panel: Add support for Novatek NT36532 panel Junjie Cao
@ 2026-07-29 16:08 ` Junjie Cao
  2026-07-29 16:08 ` [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver Junjie Cao
  1 sibling, 0 replies; 5+ messages in thread
From: Junjie Cao @ 2026-07-29 16:08 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: Junjie Cao, Dmitry Baryshkov, Konrad Dybcio, Pengyu Luo,
	dri-devel, devicetree, linux-arm-msm, linux-kernel, Conor Dooley

NT36532 is a driver IC used to drive MIPI-DSI panels. It is found
in OnePlus Pad 2 tablets with CSOT panels.

Signed-off-by: Junjie Cao <junjie.cao@linux.dev>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
 .../display/panel/novatek,nt36532.yaml        | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/novatek,nt36532.yaml

diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt36532.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt36532.yaml
new file mode 100644
index 000000000000..c1ab793dd718
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/novatek,nt36532.yaml
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/novatek,nt36532.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Novatek NT36532 based DSI display Panels
+
+maintainers:
+  - Junjie Cao <junjie.cao@linux.dev>
+
+description: |
+  The NT36532 IC from Novatek is a Driver IC used to drive MIPI-DSI panels.
+
+allOf:
+  - $ref: panel-common-dual.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - csot,ppc100hb1-1
+      - const: novatek,nt36532
+
+  reg:
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+    description: phandle of gpio for reset line - This should be 8mA
+
+  vddio-supply:
+    description: regulator that supplies the I/O voltage
+
+  ports: true
+
+required:
+  - compatible
+  - reg
+  - vddio-supply
+  - reset-gpios
+  - ports
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel@0 {
+            compatible = "csot,ppc100hb1-1", "novatek,nt36532";
+            reg = <0>;
+
+            reset-gpios = <&tlmm 133 GPIO_ACTIVE_LOW>;
+
+            vddio-supply = <&vreg_l12b_1p8>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    panel_in_0: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    panel_in_1: endpoint {
+                        remote-endpoint = <&dsi1_out>;
+                    };
+                };
+            };
+        };
+    };
+
+...

base-commit: 0d33d21e47d9dc66f91e44da3fc9220c74d93df7
-- 
2.43.0


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

* [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver
  2026-07-29 16:08 [PATCH v2 0/2] drm/panel: Add support for Novatek NT36532 panel Junjie Cao
  2026-07-29 16:08 ` [PATCH v2 1/2] dt-bindings: display: panel: Add Novatek NT36532 Junjie Cao
@ 2026-07-29 16:08 ` Junjie Cao
  2026-07-29 16:28   ` sashiko-bot
  1 sibling, 1 reply; 5+ messages in thread
From: Junjie Cao @ 2026-07-29 16:08 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: Junjie Cao, Dmitry Baryshkov, Konrad Dybcio, Pengyu Luo,
	dri-devel, devicetree, linux-arm-msm, linux-kernel

Add a driver for panels using the Novatek NT36532 Display Driver IC,
including support for the CSOT PPC100HB1-1, found in the OnePlus Pad 2
tablets.

It has been tested on the OnePlus Pad 2: the panel comes up in its native
3000x2120 mode at 120Hz over dual-DSI in bonded mode with DSC, and
displays a stable image.

Signed-off-by: Junjie Cao <junjie.cao@linux.dev>
---
 MAINTAINERS                                   |   7 +
 drivers/gpu/drm/panel/Kconfig                 |  10 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-novatek-nt36532.c | 430 ++++++++++++++++++
 4 files changed, 448 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-novatek-nt36532.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 92a2167f1eb8..bcbdd38981be 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8324,6 +8324,13 @@ T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
 F:	Documentation/devicetree/bindings/display/panel/novatek,nt36523.yaml
 F:	drivers/gpu/drm/panel/panel-novatek-nt36523.c
 
+DRM DRIVER FOR NOVATEK NT36532 PANELS
+M:	Junjie Cao <junjie.cao@linux.dev>
+S:	Maintained
+T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F:	Documentation/devicetree/bindings/display/panel/novatek,nt36532.yaml
+F:	drivers/gpu/drm/panel/panel-novatek-nt36532.c
+
 DRM DRIVER FOR NOVATEK NT36672A PANELS
 M:	Sumit Semwal <sumit.semwal@linaro.org>
 S:	Maintained
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index cbdf7b8f7f7a..e88211e6859d 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -664,6 +664,16 @@ config DRM_PANEL_NOVATEK_NT36523
 	  around the Novatek NT36523 display controller, such as some
 	  Boe panels used in Xiaomi Mi Pad 5 and 5 Pro tablets.
 
+config DRM_PANEL_NOVATEK_NT36532
+	tristate "Novatek NT36532-based MIPI-DSI panels"
+	depends on OF
+	depends on DRM_MIPI_DSI
+	help
+	  Say Y here if you want to enable support for the panels built
+	  around the Novatek NT36532 display controller, such as some
+	  CSOT panels used in OnePlus Pad 2 tablets. These panels are
+	  typically dual-DSI and may use DSC (Display Stream Compression).
+
 config DRM_PANEL_NOVATEK_NT36536
 	tristate "Novatek NT36536 panel driver"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 3b523cf37833..0f920cff7c2a 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35532) += panel-novatek-nt35532.o
 obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o
 obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o
 obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o
+obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36532) += panel-novatek-nt36532.o
 obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36536) += panel-novatek-nt36536.o
 obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o
 obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36532.c b/drivers/gpu/drm/panel/panel-novatek-nt36532.c
new file mode 100644
index 000000000000..03f9a1b6aa5a
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-novatek-nt36532.c
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Novatek NT36532 DriverIC panels driver
+ * Based on the template generated by linux-mdss-dsi-panel-driver-generator
+ *
+ * Copyright (c) 2025, 2026 Junjie Cao <junjie.cao@linux.dev>
+ */
+
+#include <linux/delay.h>
+#include <linux/device-id/of.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/display/drm_dsc.h>
+#include <drm/display/drm_dsc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+struct nt36532 {
+	struct drm_panel panel;
+	struct mipi_dsi_device *dsi[2];
+	const struct panel_info *panel_info;
+	struct gpio_desc *reset_gpio;
+	struct regulator_bulk_data *supplies;
+};
+
+struct panel_info {
+	unsigned int width_mm;
+	unsigned int height_mm;
+
+	unsigned int lanes;
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+
+	const struct drm_display_mode display_mode;
+
+	struct drm_dsc_config * const dsc_cfg;
+
+	int (*init_sequence)(struct nt36532 *ctx);
+
+	bool is_dual_dsi;
+};
+
+static const struct regulator_bulk_data nt36532_supplies[] = {
+	{ .supply = "vddio" }, /* 1.8v */
+};
+
+static inline struct nt36532 *to_nt36532(struct drm_panel *panel)
+{
+	return container_of(panel, struct nt36532, panel);
+}
+
+static inline struct mipi_dsi_device *to_primary_dsi(struct nt36532 *ctx)
+{
+	/* Sync on DSI1 for dual dsi */
+	return ctx->panel_info->is_dual_dsi ? ctx->dsi[1] : ctx->dsi[0];
+}
+
+static void nt36532_reset(struct nt36532 *ctx)
+{
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	usleep_range(10000, 10100);
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	usleep_range(5000, 5100);
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	usleep_range(15000, 15100);
+}
+
+static int nt36532_prepare(struct drm_panel *panel)
+{
+	struct nt36532 *ctx = to_nt36532(panel);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(nt36532_supplies),
+				    ctx->supplies);
+	if (ret < 0)
+		return ret;
+
+	nt36532_reset(ctx);
+
+	ret = ctx->panel_info->init_sequence(ctx);
+	if (ret < 0) {
+		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+		regulator_bulk_disable(ARRAY_SIZE(nt36532_supplies),
+				       ctx->supplies);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int nt36532_off(struct nt36532 *ctx)
+{
+	struct mipi_dsi_device *dsi = to_primary_dsi(ctx);
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+
+	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+	mipi_dsi_usleep_range(&dsi_ctx, 10000, 10100);
+	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, 65);
+
+	return dsi_ctx.accum_err;
+}
+
+static int nt36532_unprepare(struct drm_panel *panel)
+{
+	struct nt36532 *ctx = to_nt36532(panel);
+	struct device *dev = &ctx->dsi[0]->dev;
+	int ret;
+
+	ret = nt36532_off(ctx);
+	if (ret < 0)
+		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	regulator_bulk_disable(ARRAY_SIZE(nt36532_supplies), ctx->supplies);
+
+	return 0;
+}
+
+static int nt36532_get_modes(struct drm_panel *panel,
+			     struct drm_connector *connector)
+{
+	struct nt36532 *ctx = to_nt36532(panel);
+	const struct panel_info *panel_info = ctx->panel_info;
+
+	return drm_connector_helper_get_modes_fixed(connector,
+						    &panel_info->display_mode);
+}
+
+static const struct drm_panel_funcs nt36532_panel_funcs = {
+	.prepare = nt36532_prepare,
+	.unprepare = nt36532_unprepare,
+	.get_modes = nt36532_get_modes,
+};
+
+static int csot_init_sequence(struct nt36532 *ctx)
+{
+	struct mipi_dsi_device *dsi = to_primary_dsi(ctx);
+	struct drm_dsc_picture_parameter_set pps;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x22);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_LUT, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x24);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbc,
+				     0x00, 0x00, 0x03, 0x22, 0x00, 0x41);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x23);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x60);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x20);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x0c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x03);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0xe1);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0xa9);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x16);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x8e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x8e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x8e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x04);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x08);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x0c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x10);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x14);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x18);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x1c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x20);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x24);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x28);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x2c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x30);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x34);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x38);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x3c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x20);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x20);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_ROWS, 0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_COLUMNS,
+				     0xfd);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0xfc);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0xfa);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0xf8);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0xf6);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_ADDRESS_MODE, 0xf4);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0xf2);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0xf0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0xee);
+	mipi_dsi_dcs_set_pixel_format_multi(&dsi_ctx, 0xec);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0xea);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_3D_CONTROL, 0xe9);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0xe8);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_VSYNC_TIMING, 0xe7);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xe6);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_GET_SCANLINE, 0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0xf9);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0xf6);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0xf2);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0xf0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0xec);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0xe8);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0xe4);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0xe0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0xde);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0xd9);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0xd6);
+	mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x00d4);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0xc2);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
+				     0xd0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0xcd);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0xf6);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0xf0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0xeb);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0xe8);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0xe5);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS,
+				     0xe3);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0xe0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0xde);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0xda);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0xd7);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0xd4);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0xd2);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0xd0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0xcc);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xc8);
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x27);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_ROWS, 0xf0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_PARTIAL_COLUMNS,
+				     0x2a, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd0, 0x31);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd1, 0x54);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xde, 0x40);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x02);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x2a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x02);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xf0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x05);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x16);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x23);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, 0xaa, 0x2a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, 0xa0, 0x2a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x27);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x8c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x10);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+	mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0xff07);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
+				     0x2c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x02);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b,
+				     0x03, 0xd2, 0x1a, 0x04, 0x04, 0x00);
+
+	/* Enable DSC */
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x03);
+	drm_dsc_pps_payload_pack(&pps, ctx->panel_info->dsc_cfg);
+	mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9d, 0x01);
+
+	/* Program refresh rate control registers */
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x91);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x40);
+
+	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, 120);
+
+	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+	mipi_dsi_usleep_range(&dsi_ctx, 10000, 10100);
+
+	return dsi_ctx.accum_err;
+}
+
+static const struct drm_display_mode csot_display_mode = {
+	/* 120Hz, the typical value */
+	.clock = (1500 + 118 + 20 + 100) * 2 * (2120 + 26 + 2 + 208) * 120 / 1000,
+	.hdisplay = 1500 * 2,
+	.hsync_start = (1500 + 118) * 2,
+	.hsync_end = (1500 + 118 + 20) * 2,
+	.htotal = (1500 + 118 + 20 + 100) * 2,
+	.vdisplay = 2120,
+	.vsync_start = 2120 + 26,
+	.vsync_end = 2120 + 26 + 2,
+	.vtotal = 2120 + 26 + 2 + 208,
+};
+
+static struct drm_dsc_config csot_dsc_cfg = {
+	.dsc_version_major = 1,
+	.dsc_version_minor = 2,
+	.slice_height = 20,
+	.slice_width = 750,
+	.slice_count = 2,
+	.bits_per_component = 8,
+	.bits_per_pixel = 8 << 4,
+	.block_pred_enable = true,
+};
+
+static int nt36532_probe(struct mipi_dsi_device *dsi)
+{
+	struct mipi_dsi_device_info dsi_info = {"nt36532-secondary", 0, NULL};
+	const struct panel_info *panel_info;
+	struct mipi_dsi_host *dsi1_host;
+	struct device *dev = &dsi->dev;
+	struct device_node *dsi1;
+	struct nt36532 *ctx;
+	int num_dsi = 1;
+	int ret, i;
+
+	ctx = devm_drm_panel_alloc(dev, struct nt36532, panel,
+				   &nt36532_panel_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ret = devm_regulator_bulk_get_const(&dsi->dev,
+					    ARRAY_SIZE(nt36532_supplies),
+					    nt36532_supplies, &ctx->supplies);
+	if (ret < 0)
+		return ret;
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+				     "Failed to get reset-gpios\n");
+
+	ctx->panel_info = of_device_get_match_data(dev);
+	panel_info = ctx->panel_info;
+	if (!panel_info)
+		return -ENODEV;
+
+	if (panel_info->is_dual_dsi) {
+		num_dsi = 2;
+		dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
+		if (!dsi1) {
+			dev_err(dev, "cannot get secondary DSI node.\n");
+			return -ENODEV;
+		}
+
+		dsi1_host = of_find_mipi_dsi_host_by_node(dsi1);
+		of_node_put(dsi1);
+		if (!dsi1_host)
+			return dev_err_probe(dev, -EPROBE_DEFER,
+					     "cannot get secondary DSI host\n");
+
+		ctx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi1_host,
+								 &dsi_info);
+		if (IS_ERR(ctx->dsi[1])) {
+			dev_err(dev, "cannot get secondary DSI device\n");
+			return PTR_ERR(ctx->dsi[1]);
+		}
+
+		mipi_dsi_set_drvdata(ctx->dsi[1], ctx);
+	}
+
+	ctx->dsi[0] = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	ctx->panel.prepare_prev_first = true;
+
+	ret = devm_drm_panel_add(dev, &ctx->panel);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to add panel\n");
+
+	for (i = 0; i < num_dsi; i++) {
+		ctx->dsi[i]->lanes = panel_info->lanes;
+		ctx->dsi[i]->format = panel_info->format;
+		ctx->dsi[i]->mode_flags = panel_info->mode_flags;
+		ctx->dsi[i]->dsc = panel_info->dsc_cfg;
+		ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]);
+		if (ret < 0) {
+			return dev_err_probe(dev, ret,
+					     "Failed to attach to DSI host\n");
+		}
+	}
+
+	return 0;
+}
+
+static const struct panel_info csot_panel_info = {
+	.width_mm = 250,
+	.height_mm = 177,
+	.lanes = 4,
+	.format = MIPI_DSI_FMT_RGB888,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS |
+		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT,
+	.display_mode = csot_display_mode,
+	.dsc_cfg = &csot_dsc_cfg,
+	.init_sequence = csot_init_sequence,
+	.is_dual_dsi = true,
+};
+
+static const struct of_device_id nt36532_of_match[] = {
+	{ .compatible = "csot,ppc100hb1-1", .data = &csot_panel_info },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nt36532_of_match);
+
+static struct mipi_dsi_driver nt36532_driver = {
+	.probe = nt36532_probe,
+	.driver = {
+		.name = "panel-novatek-nt36532",
+		.of_match_table = nt36532_of_match,
+	},
+};
+module_mipi_dsi_driver(nt36532_driver);
+
+MODULE_AUTHOR("Junjie Cao <junjie.cao@linux.dev>");
+MODULE_DESCRIPTION("DRM driver for Novatek NT36532 based MIPI DSI panels");
+MODULE_LICENSE("GPL");
-- 
2.43.0


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

* Re: [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver
  2026-07-29 16:08 ` [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver Junjie Cao
@ 2026-07-29 16:28   ` sashiko-bot
  2026-08-03 14:49     ` Junjie Cao
  0 siblings, 1 reply; 5+ messages in thread
From: sashiko-bot @ 2026-07-29 16:28 UTC (permalink / raw)
  To: Junjie Cao; +Cc: conor+dt, dri-devel, robh, devicetree

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Missing Kconfig dependency for DRM_DISPLAY_DSC_HELPER leads to linker errors.
- [High] Improper use of DCS brightness helper inside a vendor sequence corrupts the initialization payload.
- [Medium] Global static DSC configuration structure is assigned to device context and mutated by host drivers.
- [Medium] Missing DRM backlight device registration and OF backlight mapping.
- [Low] Panel physical dimensions are defined but not reported to DRM userspace.
--

--- Patch [2]: [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver ---
commit 5fca5767ad8caef139f4cb6c683a24fe7d77f970
Author: Junjie Cao <junjie.cao@linux.dev>
Subject: drm/panel: Add Novatek NT36532 panel driver

This commit adds a driver for panels using the Novatek NT36532 Display
Driver IC, specifically the CSOT PPC100HB1-1 found in the OnePlus Pad 2
tablets.

> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index cbdf7b8f7f7af..e88211e6859d7 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -664,6 +664,16 @@ config DRM_PANEL_NOVATEK_NT36523
>  	  around the Novatek NT36523 display controller, such as some
>  	  Boe panels used in Xiaomi Mi Pad 5 and 5 Pro tablets.
>  
> +config DRM_PANEL_NOVATEK_NT36532
> +	tristate "Novatek NT36532-based MIPI-DSI panels"
> +	depends on OF
> +	depends on DRM_MIPI_DSI
> +	help
> +	  Say Y here if you want to enable support for the panels built
> +	  around the Novatek NT36532 display controller, such as some
> +	  CSOT panels used in OnePlus Pad 2 tablets. These panels are
> +	  typically dual-DSI and may use DSC (Display Stream Compression).
> +

[Severity: High]
Since the driver's csot_init_sequence() calls drm_dsc_pps_payload_pack(),
does this Kconfig entry need to select DRM_DISPLAY_DSC_HELPER? Building
this as a module without other DSC drivers enabled might result in
linker errors for the missing symbol.

> diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36532.c b/drivers/gpu/drm/panel/panel-novatek-nt36532.c
> new file mode 100644
> index 0000000000000..03f9a1b6aa5a4
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-novatek-nt36532.c

[ ... ]

> +static int nt36532_get_modes(struct drm_panel *panel,
> +			     struct drm_connector *connector)
> +{
> +	struct nt36532 *ctx = to_nt36532(panel);
> +	const struct panel_info *panel_info = ctx->panel_info;
> +
> +	return drm_connector_helper_get_modes_fixed(connector,
> +						    &panel_info->display_mode);
> +}

[Severity: Low]
The function drm_connector_helper_get_modes_fixed() relies on the width_mm
and height_mm properties of the drm_display_mode passed to it. Since
csot_display_mode does not set these fields, the dimensions will remain 0x0.

Should nt36532_get_modes() manually set connector->display_info.width_mm
and height_mm using the physical dimensions defined in csot_panel_info?

[ ... ]

> +static int csot_init_sequence(struct nt36532 *ctx)
> +{
> +	struct mipi_dsi_device *dsi = to_primary_dsi(ctx);
> +	struct drm_dsc_picture_parameter_set pps;
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };

[ ... ]

> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0xde);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0xd9);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0xd6);
> +	mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x00d4);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0xc2);

[Severity: High]
The surrounding sequence appears to use 1-byte payload writes to sequential
registers. The mipi_dsi_dcs_set_display_brightness_multi() helper transmits
a 2-byte payload. 

Could this extra byte shift subsequent commands out of alignment and cause
parsing errors in the display IC firmware? Should this just be a standard
1-byte mipi_dsi_dcs_write_seq_multi() call for register 0x51?

[ ... ]

> +static struct drm_dsc_config csot_dsc_cfg = {
> +	.dsc_version_major = 1,
> +	.dsc_version_minor = 2,
> +	.slice_height = 20,
> +	.slice_width = 750,
> +	.slice_count = 2,
> +	.bits_per_component = 8,
> +	.bits_per_pixel = 8 << 4,
> +	.block_pred_enable = true,
> +};

[ ... ]

> +static int nt36532_probe(struct mipi_dsi_device *dsi)
> +{

[ ... ]

> +	for (i = 0; i < num_dsi; i++) {
> +		ctx->dsi[i]->lanes = panel_info->lanes;
> +		ctx->dsi[i]->format = panel_info->format;
> +		ctx->dsi[i]->mode_flags = panel_info->mode_flags;
> +		ctx->dsi[i]->dsc = panel_info->dsc_cfg;

[Severity: Medium]
This assigns a pointer to the global static structure csot_dsc_cfg directly
to the device context.

Because DSI host drivers (like the MSM DPU driver) actively mutate the
DSC parameters at runtime by calling drm_dsc_compute_rc_parameters(),
can this cause concurrent mutation of global state, especially on dual-DSI
setups?

[ ... ]

> +	ctx->panel.prepare_prev_first = true;
> +
> +	ret = devm_drm_panel_add(dev, &ctx->panel);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "failed to add panel\n");

[Severity: Medium]
Is a call to drm_panel_of_backlight() or devm_backlight_device_register()
missing here? Without it, userspace might be unable to change the screen
brightness, or an external backlight might fail to turn on when the
panel is enabled.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260729160804.912826-1-junjie.cao@linux.dev?part=2

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

* Re: [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver
  2026-07-29 16:28   ` sashiko-bot
@ 2026-08-03 14:49     ` Junjie Cao
  0 siblings, 0 replies; 5+ messages in thread
From: Junjie Cao @ 2026-08-03 14:49 UTC (permalink / raw)
  To: sashiko-reviews
  Cc: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dmitry Baryshkov,
	Konrad Dybcio, Pengyu Luo, dri-devel, devicetree, linux-arm-msm,
	linux-kernel

On Wed, 29 Jul 2026 16:28:47 +0000, sashiko-bot@kernel.org wrote:
> - [High] Missing Kconfig dependency for DRM_DISPLAY_DSC_HELPER leads
>   to linker errors.
> - [High] Improper use of DCS brightness helper inside a vendor
>   sequence corrupts the initialization payload.
> - [Medium] Global static DSC configuration structure is assigned to
>   device context and mutated by host drivers.
> - [Medium] Missing DRM backlight device registration and OF backlight
>   mapping.
> - [Low] Panel physical dimensions are defined but not reported to DRM
>   userspace.

Thanks for the report. What I'll fix in v3 first, then the two claims
I disagree with.

Will fix in v3:

1) Kconfig: add select DRM_DISPLAY_DSC_HELPER + DRM_DISPLAY_HELPER (for
   drm_dsc_pps_payload_pack()) and DRM_KMS_HELPER (for
   drm_connector_helper_get_modes_fixed()), plus depends on
   BACKLIGHT_CLASS_DEVICE, like the other DSC panels. Verified on
   arm64: disable DRM_MSM/amdgpu and the other DSC panels and Kconfig
   happily gives you NT36532=m with the DSC helper off, leaving
   drm_dsc_pps_payload_pack without a provider. Most DSI hosts and all
   the DSI bridges select DRM_MIPI_DSI but not the DSC helper, so this
   is easy to hit. Good catch.

2) The set_display_brightness_multi(0x00d4) call sits in the page 0x23
   vendor dimming table (0x4e..0x52, one byte each); 0x51 there is a
   table entry, not the DCS brightness command. The stock OnePlus
   Pad 2 firmware DT sends it as an 0x15 short write (51 d4), while
   the helper emits a long write with a trailing 0x00. Will switch to
   a plain one-byte write. The "51 07 ff" after switching to page 0x10
   is the real brightness command and stays; I'll write it as
   MIPI_DCS_SET_DISPLAY_BRIGHTNESS with an explicit 07 ff payload
   instead of the byte-swapped 0xff07 (same bytes on the wire), and
   drop the other accidental MIPI_DCS_* macro names in the vendor pages
   (SET_GAMMA_CURVE, SET_ADDRESS_MODE, set_pixel_format, ...).

3) Make the DSC template const and copy it into the instance at probe
   time (ctx->dsc = *panel_info->dsc_cfg), like panel-novatek-nt36536 does,
   so the module-global struct is never written.

4) Call drm_panel_of_backlight(). Brightness on this device comes from
   a separate KTZ8866 backlight controller via the standard
   'backlight' property (already allowed through panel-common-dual.yaml,
   so no binding change). Without the hookup the backlight stays on
   after a panel DPMS off; reproducible on the device here.

5) Move width_mm/height_mm into csot_display_mode; modetest currently
   reports the connector as 0x0 mm.

Won't change:

a) "extra byte could shift subsequent commands out of alignment" - no.
   Each DCS write is its own DSI packet with its own payload length; a
   longer packet can't corrupt the ones after it. The 0x51 change
   above is about matching the vendor sequence, not corruption - the
   panel comes up fine as is.

b) The two DSI devices keep sharing one drm_dsc_config; only its
   storage moves, per 3). Both links of a bonded panel must run
   identical DSC parameters, and the host derives the rc parameters
   deterministically from the same seed values while the pair is
   brought up sequentially in one thread, so there is nothing to race.
   Per-link copies would just be two structs that must never diverge.

Thanks,
Junjie

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

end of thread, other threads:[~2026-08-04  4:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 16:08 [PATCH v2 0/2] drm/panel: Add support for Novatek NT36532 panel Junjie Cao
2026-07-29 16:08 ` [PATCH v2 1/2] dt-bindings: display: panel: Add Novatek NT36532 Junjie Cao
2026-07-29 16:08 ` [PATCH v2 2/2] drm/panel: Add Novatek NT36532 panel driver Junjie Cao
2026-07-29 16:28   ` sashiko-bot
2026-08-03 14:49     ` Junjie Cao

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).