* [PATCH 0/2] Add panel driver for Novatek NT37703
@ 2026-08-11 5:52 Esteban Urrutia via B4 Relay
2026-08-11 5:52 ` [PATCH 1/2] dt-bindings: display: panel: Add bindings " Esteban Urrutia via B4 Relay
2026-08-11 5:52 ` [PATCH 2/2] drm/panel: Add driver for Novatek NT37703 based panels Esteban Urrutia via B4 Relay
0 siblings, 2 replies; 5+ messages in thread
From: Esteban Urrutia via B4 Relay @ 2026-08-11 5:52 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: dri-devel, devicetree, linux-kernel, phone-devel, Esteban Urrutia
This series adds a driver and bindings for panels based on this display
driver IC.
Initial support is added for the Tianma "v2" panel found in the Motorola
ThinkPhone by motorola.
This panel has no model number and is only identified with versions.
There seem to exist three versions of Tianma panels: v0 (no version), v1
and v2.
Only v2 has been able to be tested.
The added driver should in theory make it fairly easy to add new panels
in the future.
I tried to be as careful as possible with that.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
Esteban Urrutia (2):
dt-bindings: display: panel: Add bindings for Novatek NT37703
drm/panel: Add driver for Novatek NT37703 based panels
.../bindings/display/panel/novatek,nt37703.yaml | 78 ++++
MAINTAINERS | 6 +
drivers/gpu/drm/panel/Kconfig | 13 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-novatek-nt37703.c | 467 +++++++++++++++++++++
5 files changed, 565 insertions(+)
---
base-commit: 3d08ff75a47a3e7e2ab45a3bcab6723b4d906422
change-id: 20260726-nt37703-bup-8abbb7396c6e
Best regards,
--
Esteban Urrutia <esteuwu@proton.me>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] dt-bindings: display: panel: Add bindings for Novatek NT37703
2026-08-11 5:52 [PATCH 0/2] Add panel driver for Novatek NT37703 Esteban Urrutia via B4 Relay
@ 2026-08-11 5:52 ` Esteban Urrutia via B4 Relay
2026-08-11 13:05 ` David Heidelberg
2026-08-11 5:52 ` [PATCH 2/2] drm/panel: Add driver for Novatek NT37703 based panels Esteban Urrutia via B4 Relay
1 sibling, 1 reply; 5+ messages in thread
From: Esteban Urrutia via B4 Relay @ 2026-08-11 5:52 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: dri-devel, devicetree, linux-kernel, phone-devel, Esteban Urrutia
From: Esteban Urrutia <esteuwu@proton.me>
Add bindings for this display driver IC which is used to drive MIPI DSI
panels.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
.../bindings/display/panel/novatek,nt37703.yaml | 78 ++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt37703.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt37703.yaml
new file mode 100644
index 000000000000..e1aeed5b978e
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/novatek,nt37703.yaml
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/novatek,nt37703.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Novatek NT37703 display driver IC based panels
+
+maintainers:
+ - Esteban Urrutia <esteuwu@proton.me>
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - motorola,bronco-tianma-v2-nt37703
+ - const: novatek,nt37703
+
+ reg:
+ maxItems: 1
+
+ avdd-supply:
+ description: Analog power supply for panel
+
+ elvdd-supply:
+ description: Positive electroluminiscent (EL) power supply for panel
+
+ elvss-supply:
+ description: Negative electroluminiscent (EL) power supply for panel
+
+ vci-supply:
+ description: Analog power supply for DDIC
+
+ vdd-supply:
+ description: Digital power supply for DDIC
+
+ vddi-supply:
+ description: Digital I/O power supply for DDIC
+
+ reset-gpios:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+
+allOf:
+ - $ref: panel-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "motorola,bronco-tianma-v2-nt37703", "novatek,nt37703";
+ reg = <0>;
+
+ vci-supply = <&vreg_l13c_3p0>;
+ vdd-supply = <&vreg_l1d_1p25>;
+ vddi-supply = <&vreg_l12c_1p8>;
+ reset-gpios = <&tlmm 0 GPIO_ACTIVE_LOW>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+ };
+ };
+
+...
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] drm/panel: Add driver for Novatek NT37703 based panels
2026-08-11 5:52 [PATCH 0/2] Add panel driver for Novatek NT37703 Esteban Urrutia via B4 Relay
2026-08-11 5:52 ` [PATCH 1/2] dt-bindings: display: panel: Add bindings " Esteban Urrutia via B4 Relay
@ 2026-08-11 5:52 ` Esteban Urrutia via B4 Relay
2026-08-11 14:28 ` Uwe Kleine-König
1 sibling, 1 reply; 5+ messages in thread
From: Esteban Urrutia via B4 Relay @ 2026-08-11 5:52 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: dri-devel, devicetree, linux-kernel, phone-devel, Esteban Urrutia
From: Esteban Urrutia <esteuwu@proton.me>
Add driver for panels based on this DDIC.
Initial support is added for the Tianma "v2" panel (no panel model) found
in the Motorola ThinkPhone by motorola.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
MAINTAINERS | 6 +
drivers/gpu/drm/panel/Kconfig | 13 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-novatek-nt37703.c | 467 ++++++++++++++++++++++++++
4 files changed, 487 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index da14a58df9e8..e2bb50a8b1af 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8339,6 +8339,12 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/panel/novatek,nt36672a.yaml
F: drivers/gpu/drm/panel/panel-novatek-nt36672a.c
+DRM DRIVER FOR NOVATEK NT37703 PANELS
+M: Esteban Urrutia <esteuwu@proton.me>
+S: Maintained
+F: Documentation/devicetree/bindings/display/panel/novatek,nt37703.yaml
+F: drivers/gpu/drm/panel/panel-novatek-nt37703.c
+
DRM DRIVER FOR NOVATEK NT37801 PANELS
M: Krzysztof Kozlowski <krzk@kernel.org>
S: Maintained
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index cbdf7b8f7f7a..9cd74ceef44e 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -706,6 +706,19 @@ config DRM_PANEL_NOVATEK_NT37700F
Say Y here if you want to enable support for Novatek NT37700F DSI
panel module. The panel has a resolution of 1080x2160.
+config DRM_PANEL_NOVATEK_NT37703
+ tristate "Novatek NT37703 DSI panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_DSC_HELPER
+ select DRM_DISPLAY_HELPER
+ help
+ Say Y or M here if you want to enable support for panels based
+ on the Novatek NT37703 display driver IC, such as Tianma
+ panels found in some units of the Motorola ThinkPhone by
+ motorola.
+
config DRM_PANEL_NOVATEK_NT37801
tristate "Novatek NT37801/NT37810 AMOLED DSI panel"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 3b523cf37833..4a69b2657c5b 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -68,6 +68,7 @@ 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
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37700F) += panel-novatek-nt37700f.o
+obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37703) += panel-novatek-nt37703.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37801) += panel-novatek-nt37801.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37703.c b/drivers/gpu/drm/panel/panel-novatek-nt37703.c
new file mode 100644
index 000000000000..5858bf12a310
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-novatek-nt37703.c
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Novatek NT37703 based MIPI DSI panels
+ *
+ * Multiple panel support based on Novatek NT36523 driver
+ * Per panel DSC support based on Ilitek ILI9882T driver
+ *
+ * Copyright (c) 2026 Esteban Urrutia <esteuwu@proton.me>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.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>
+
+#define DSC_BPG_OFFSET(x) ((u8) ((x) & DSC_RANGE_BPG_OFFSET_MASK))
+#define NT37703_DCS_SWITCH_PAGE 0xf0
+
+#define nt37703_cmd_test_on(ctx) mipi_dsi_dcs_write_seq_multi((ctx), 0xff, 0xaa, 0x55, \
+ 0xa5, 0x80)
+#define nt37703_switch_page(ctx, page) mipi_dsi_dcs_write_seq_multi((ctx), \
+ NT37703_DCS_SWITCH_PAGE, \
+ 0x55, 0xaa, 0x52, 0x08, (page))
+
+struct panel_info {
+ struct drm_panel panel;
+ const struct panel_desc *desc;
+ struct mipi_dsi_device *dsi;
+ struct drm_dsc_config dsc;
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+};
+
+struct panel_desc {
+ unsigned int width_mm;
+ unsigned int height_mm;
+
+ unsigned int lanes;
+ unsigned long mode_flags;
+ enum mipi_dsi_pixel_format format;
+
+ const struct drm_display_mode *modes;
+ unsigned int num_modes;
+ int (*init_sequence)(struct panel_info *pinfo);
+ const struct drm_dsc_config *dsc;
+};
+
+/*
+ * These parameters are applied when using DSC 1.1 and when the DSC configuration specifies 10 b.p.c
+ * and 8 b.p.p
+ */
+static const struct drm_dsc_rc_range_parameters nt37703_rc_range_params[DSC_NUM_BUF_RANGES] = {
+ { 0, 8, DSC_BPG_OFFSET(2) },
+ { 4, 8, DSC_BPG_OFFSET(0) },
+ { 5, 9, DSC_BPG_OFFSET(0) },
+ { 5, 10, DSC_BPG_OFFSET(-2) },
+ { 7, 11, DSC_BPG_OFFSET(-4) },
+ { 7, 11, DSC_BPG_OFFSET(-6) },
+ { 7, 11, DSC_BPG_OFFSET(-8) },
+ { 7, 12, DSC_BPG_OFFSET(-8) },
+ { 7, 13, DSC_BPG_OFFSET(-8) },
+ { 8, 14, DSC_BPG_OFFSET(-10) },
+ { 9, 14, DSC_BPG_OFFSET(-10) },
+ { 9, 15, DSC_BPG_OFFSET(-10) },
+ { 9, 15, DSC_BPG_OFFSET(-12) },
+ { 12, 16, DSC_BPG_OFFSET(-12) },
+ { 16, 17, DSC_BPG_OFFSET(-12) },
+};
+
+static const struct regulator_bulk_data nt37703_supplies[] = {
+ { .supply = "avdd" },
+ { .supply = "elvdd" },
+ { .supply = "elvss" },
+ { .supply = "vci" },
+ { .supply = "vdd" },
+ { .supply = "vddi" },
+};
+
+static inline struct panel_info *to_panel_info(struct drm_panel *panel)
+{
+ return container_of_const(panel, struct panel_info, panel);
+}
+
+static void nt37703_reset(struct panel_info *pinfo)
+{
+ gpiod_set_value_cansleep(pinfo->reset_gpio, 0);
+ usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(pinfo->reset_gpio, 1);
+ usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(pinfo->reset_gpio, 0);
+ usleep_range(10000, 11000);
+}
+
+static int nt37703_off(struct panel_info *pinfo)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = pinfo->dsi };
+
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+
+ return dsi_ctx.accum_err;
+}
+
+static int nt37703_prepare(struct drm_panel *panel)
+{
+ struct panel_info *pinfo = to_panel_info(panel);
+ struct device *dev = &pinfo->dsi->dev;
+ struct drm_dsc_picture_parameter_set pps;
+ int ret;
+ int i;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(nt37703_supplies), pinfo->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ nt37703_reset(pinfo);
+
+ ret = pinfo->desc->init_sequence(pinfo);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize panel: %d\n", ret);
+ gpiod_set_value_cansleep(pinfo->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(nt37703_supplies), pinfo->supplies);
+ return ret;
+ }
+
+ /*
+ * For some reason this DDIC uses different parameters for the RC ranges under certain DSC
+ * configurations.
+ * Not applying them results in heavy visual glitches, so do so if all conditions are met.
+ */
+ if (pinfo->dsc.dsc_version_major == 1 && pinfo->dsc.dsc_version_minor == 1 &&
+ pinfo->dsc.bits_per_component == 10 && pinfo->dsc.bits_per_pixel == 8 << 4) {
+ for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+ pinfo->dsc.rc_range_params[i].range_min_qp =
+ nt37703_rc_range_params[i].range_min_qp;
+ pinfo->dsc.rc_range_params[i].range_max_qp =
+ nt37703_rc_range_params[i].range_max_qp;
+ pinfo->dsc.rc_range_params[i].range_bpg_offset =
+ nt37703_rc_range_params[i].range_bpg_offset;
+ }
+ }
+
+ /*
+ * Given drm_dsc_setup_rc_params() inconditionally overrides certain members in pinfo->dsc
+ * that may have been set in pinfo->desc->dsc, override these members once more with what's
+ * found in pinfo->desc->dsc.
+ */
+ if (pinfo->desc->dsc->first_line_bpg_offset)
+ pinfo->dsc.first_line_bpg_offset = pinfo->desc->dsc->first_line_bpg_offset;
+
+ drm_dsc_pps_payload_pack(&pps, &pinfo->dsc);
+
+ ret = mipi_dsi_picture_parameter_set(pinfo->dsi, &pps);
+ if (ret < 0) {
+ dev_err(panel->dev, "Failed to transmit PPS: %d\n", ret);
+ return ret;
+ }
+
+ ret = mipi_dsi_compression_mode(pinfo->dsi, true);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable compression mode: %d\n", ret);
+ return ret;
+ }
+
+ msleep(28);
+
+ return 0;
+}
+
+static int nt37703_unprepare(struct drm_panel *panel)
+{
+ struct panel_info *pinfo = to_panel_info(panel);
+ struct device *dev = &pinfo->dsi->dev;
+ int ret;
+
+ ret = nt37703_off(pinfo);
+ if (ret < 0)
+ dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
+
+ gpiod_set_value_cansleep(pinfo->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(nt37703_supplies), pinfo->supplies);
+
+ return 0;
+}
+
+static int nt37703_get_modes(struct drm_panel *panel, struct drm_connector *connector)
+{
+ struct panel_info *pinfo = to_panel_info(panel);
+ int i;
+
+ for (i = 0; i < pinfo->desc->num_modes; i++) {
+ const struct drm_display_mode *m = &pinfo->desc->modes[i];
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, m);
+ if (!mode) {
+ dev_err(panel->dev, "Failed to add mode %ux%u@%u\n", m->hdisplay,
+ m->vdisplay, drm_mode_vrefresh(m));
+ return -ENOMEM;
+ }
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ if (i == 0)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ }
+
+ connector->display_info.width_mm = pinfo->desc->width_mm;
+ connector->display_info.height_mm = pinfo->desc->height_mm;
+
+ return pinfo->desc->num_modes;
+}
+
+static const struct drm_panel_funcs nt37703_panel_funcs = {
+ .prepare = nt37703_prepare,
+ .unprepare = nt37703_unprepare,
+ .get_modes = nt37703_get_modes,
+};
+
+static int nt37703_bl_update_status(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ u16 brightness = backlight_get_brightness(bl);
+ int ret;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
+ if (ret < 0)
+ return ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ return 0;
+}
+
+static int nt37703_bl_get_brightness(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ u16 brightness;
+ int ret;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
+ if (ret < 0)
+ return ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ return brightness;
+}
+
+static const struct backlight_ops nt37703_bl_ops = {
+ .update_status = nt37703_bl_update_status,
+ .get_brightness = nt37703_bl_get_brightness,
+};
+
+static struct backlight_device *nt37703_create_backlight(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct backlight_properties props = {
+ .type = BACKLIGHT_RAW,
+ .brightness = 2047,
+ .max_brightness = 4095,
+ };
+
+ return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, &nt37703_bl_ops,
+ &props);
+}
+
+static const struct drm_display_mode bronco_tianma_modes[] = {
+ {
+ .clock = (1080 + 16 + 4 + 16) * (2400 + 44 + 2 + 14) * 144 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 16,
+ .hsync_end = 1080 + 16 + 4,
+ .htotal = 1080 + 16 + 4 + 16,
+ .vdisplay = 2400,
+ .vsync_start = 2400 + 44,
+ .vsync_end = 2400 + 44 + 2,
+ .vtotal = 2400 + 44 + 2 + 14,
+ },
+};
+
+static int bronco_tianma_v2_init_sequence(struct panel_info *pinfo)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = pinfo->dsi };
+
+ nt37703_switch_page(&dsi_ctx, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x06);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x29);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x2b, 0x1b, 0x00, 0x32);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x88, 0x01, 0x02, 0x1b, 0x08, 0x77);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x20);
+ mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0, 1080 - 1);
+ mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0, 2400 - 1);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x03, 0x03);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
+ nt37703_cmd_test_on(&dsi_ctx);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x15);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x01, 0xe1);
+ nt37703_cmd_test_on(&dsi_ctx);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x17);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x13);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf9, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x3c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x81);
+ mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+ mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x00);
+ nt37703_switch_page(&dsi_ctx, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x03);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc7, 0x47);
+ nt37703_switch_page(&dsi_ctx, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0xc4);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x09, 0x84, 0x09, 0x84, 0x09, 0x84, 0x16,
+ 0xd6);
+ nt37703_switch_page(&dsi_ctx, 0x03);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x33);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc6, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00,
+ 0x18);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x83);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8b, 0x00, 0x00);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+
+ return dsi_ctx.accum_err;
+}
+
+static const struct drm_dsc_config bronco_tianma_dsc = {
+ .dsc_version_major = 1,
+ .dsc_version_minor = 1,
+ .slice_height = 20,
+ .slice_width = 540,
+ .slice_count = 2, /* 1080 / slice_width */
+ .bits_per_component = 10,
+ .bits_per_pixel = 8 << 4, /* 4 fractional bits */
+ .block_pred_enable = true,
+ .first_line_bpg_offset = 13,
+};
+
+static const struct panel_desc bronco_tianma_v2_desc = {
+ .modes = bronco_tianma_modes,
+ .num_modes = ARRAY_SIZE(bronco_tianma_modes),
+ .width_mm = 68,
+ .height_mm = 152,
+ .lanes = 4,
+ .format = MIPI_DSI_FMT_RGB101010,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM |
+ MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT;
+ .init_sequence = bronco_tianma_v2_init_sequence,
+ .dsc = &bronco_tianma_dsc,
+};
+
+static int nt37703_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct panel_info *pinfo;
+ int ret;
+
+ pinfo = devm_drm_panel_alloc(dev, struct panel_info, panel, &nt37703_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(pinfo))
+ return PTR_ERR(pinfo);
+
+ pinfo->desc = of_device_get_match_data(dev);
+ if (IS_ERR(pinfo->desc))
+ return PTR_ERR(pinfo->desc);
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(nt37703_supplies), nt37703_supplies,
+ &pinfo->supplies);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ pinfo->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(pinfo->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(pinfo->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ pinfo->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, pinfo);
+
+ dsi->lanes = pinfo->desc->lanes;
+ dsi->format = pinfo->desc->format;
+ dsi->mode_flags = pinfo->desc->mode_flags;
+
+ pinfo->panel.prepare_prev_first = true;
+
+ pinfo->panel.backlight = nt37703_create_backlight(dsi);
+ if (IS_ERR(pinfo->panel.backlight))
+ return dev_err_probe(dev, PTR_ERR(pinfo->panel.backlight),
+ "Failed to create backlight\n");
+
+ drm_panel_add(&pinfo->panel);
+
+ /* This panel only supports DSC; unconditionally enable it */
+ pinfo->dsc = *(pinfo->desc->dsc);
+ dsi->dsc = &pinfo->dsc;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ drm_panel_remove(&pinfo->panel);
+ return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+ }
+
+ return 0;
+}
+
+static void nt37703_remove(struct mipi_dsi_device *dsi)
+{
+ struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&pinfo->panel);
+}
+
+static const struct of_device_id nt37703_of_match[] = {
+ {
+ .compatible = "motorola,bronco-tianma-v2-nt37703",
+ .data = &bronco_tianma_v2_desc,
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, nt37703_of_match);
+
+static struct mipi_dsi_driver nt37703_driver = {
+ .probe = nt37703_probe,
+ .remove = nt37703_remove,
+ .driver = {
+ .name = "panel-novatek-nt37703",
+ .of_match_table = nt37703_of_match,
+ },
+};
+module_mipi_dsi_driver(nt37703_driver);
+
+MODULE_AUTHOR("Esteban Urrutia <esteuwu@proton.me>");
+MODULE_DESCRIPTION("DRM driver for Novatek NT37703 based MIPI DSI panels");
+MODULE_LICENSE("GPL");
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] dt-bindings: display: panel: Add bindings for Novatek NT37703
2026-08-11 5:52 ` [PATCH 1/2] dt-bindings: display: panel: Add bindings " Esteban Urrutia via B4 Relay
@ 2026-08-11 13:05 ` David Heidelberg
0 siblings, 0 replies; 5+ messages in thread
From: David Heidelberg @ 2026-08-11 13:05 UTC (permalink / raw)
To: esteuwu, Neil Armstrong, Jessica Zhang, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, phone-devel
On 11/08/2026 07:52, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> Add bindings for this display driver IC which is used to drive MIPI DSI
> panels.
>
> Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
> ---
> .../bindings/display/panel/novatek,nt37703.yaml | 78 ++++++++++++++++++++++
> 1 file changed, 78 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt37703.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt37703.yaml
> new file mode 100644
> index 000000000000..e1aeed5b978e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt37703.yaml
> @@ -0,0 +1,78 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/panel/novatek,nt37703.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Novatek NT37703 display driver IC based panels
> +
> +maintainers:
> + - Esteban Urrutia <esteuwu@proton.me>
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - motorola,bronco-tianma-v2-nt37703
> + - const: novatek,nt37703
Hi Esteban,
Usually the used pattern is vendor,ddic+panel-model
novatek,nt37703-motorola-bronco
...but motorola bronco isn't the model of the panel.
My recommendation - look at some video of screen replacement, stop at moment
when FLEX cable from panel is visible and that's where the panel model usually is.
> +
> + reg:
> + maxItems: 1
> +
> + avdd-supply:
> + description: Analog power supply for panel
> +
> + elvdd-supply:
> + description: Positive electroluminiscent (EL) power supply for panel
> +
> + elvss-supply:
> + description: Negative electroluminiscent (EL) power supply for panel
> +
> + vci-supply:
> + description: Analog power supply for DDIC
> +
> + vdd-supply:
> + description: Digital power supply for DDIC
> +
> + vddi-supply:
> + description: Digital I/O power supply for DDIC
> +
> + reset-gpios:
> + maxItems: 1
> +
> +required:
> + - compatible
> + - reg
> + - reset-gpios
> +
> +allOf:
> + - $ref: panel-common.yaml#
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> +
> + dsi {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + panel@0 {
> + compatible = "motorola,bronco-tianma-v2-nt37703", "novatek,nt37703";
> + reg = <0>;
> +
> + vci-supply = <&vreg_l13c_3p0>;
> + vdd-supply = <&vreg_l1d_1p25>;
> + vddi-supply = <&vreg_l12c_1p8>;
> + reset-gpios = <&tlmm 0 GPIO_ACTIVE_LOW>;
> +
> + port {
> + panel_in: endpoint {
> + remote-endpoint = <&dsi0_out>;
> + };
> + };
> + };
> + };
> +
> +...
>
--
David Heidelberg
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] drm/panel: Add driver for Novatek NT37703 based panels
2026-08-11 5:52 ` [PATCH 2/2] drm/panel: Add driver for Novatek NT37703 based panels Esteban Urrutia via B4 Relay
@ 2026-08-11 14:28 ` Uwe Kleine-König
0 siblings, 0 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2026-08-11 14:28 UTC (permalink / raw)
To: Esteban Urrutia
Cc: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, dri-devel, devicetree,
linux-kernel, phone-devel
[-- Attachment #1: Type: text/plain, Size: 1304 bytes --]
Hello,
On Tue, Aug 11, 2026 at 01:52:34AM -0400, Esteban Urrutia wrote:
> diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37703.c b/drivers/gpu/drm/panel/panel-novatek-nt37703.c
> new file mode 100644
> index 000000000000..5858bf12a310
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-novatek-nt37703.c
> @@ -0,0 +1,467 @@
> [...]
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/of.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>
Please rely on <drm/drm_mipi_dsi.h> to provide the definition of
of_device_id and drop explicit inclusion of <linux/mod_devicetable.h> as
this will go away soon.
> [...]
> +static const struct of_device_id nt37703_of_match[] = {
> + {
> + .compatible = "motorola,bronco-tianma-v2-nt37703",
> + .data = &bronco_tianma_v2_desc,
> + },
> + { /* sentinel */ },
No trailing comma after the list terminator please.
> +};
> +MODULE_DEVICE_TABLE(of, nt37703_of_match);
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-11 14:28 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-11 5:52 [PATCH 0/2] Add panel driver for Novatek NT37703 Esteban Urrutia via B4 Relay
2026-08-11 5:52 ` [PATCH 1/2] dt-bindings: display: panel: Add bindings " Esteban Urrutia via B4 Relay
2026-08-11 13:05 ` David Heidelberg
2026-08-11 5:52 ` [PATCH 2/2] drm/panel: Add driver for Novatek NT37703 based panels Esteban Urrutia via B4 Relay
2026-08-11 14:28 ` Uwe Kleine-König
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox