* [PATCH v3 0/4] Add Novatek NT37705 panel driver for Fairphone (Gen. 6)
@ 2026-10-02 14:21 Luca Weiss
2026-10-02 14:21 ` [PATCH v3 1/4] dt-bindings: display: panel: Add Novatek NT37705 Luca Weiss
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Luca Weiss @ 2026-10-02 14:21 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: ~postmarketos/upstreaming, phone-devel, dri-devel, devicetree,
linux-kernel, linux-arm-msm, Luca Weiss, Krzysztof Kozlowski,
Dmitry Baryshkov, Konrad Dybcio
Add bindings and a panel driver for the NT37705, and then enable display
on the Fairphone (Gen. 6).
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
Changes in v3:
- dt-bindings: don't use 'contains' (Sashiko)
- driver: Use devm_drm_panel_add & devm_mipi_dsi_attach
- driver: Replace linux/mod_devicetable.h with linux/device-id/of.h
(Uwe)
- Link to v2: https://patch.msgid.link/20260918-fp6-panel-v2-0-6695c4008920@fairphone.com
Changes in v2:
- Fix kconfig dependencies of panel driver
- Pick up tags
- Link to v1: https://patch.msgid.link/20260501-fp6-panel-v1-0-e09cb05651cc@fairphone.com
---
Luca Weiss (4):
dt-bindings: display: panel: Add Novatek NT37705
drm/panel: Add driver for Novatek NT37705 panel
arm64: defconfig: Enable Novatek NT37705 panel
arm64: dts: qcom: milos-fairphone-fp6: Enable display
.../bindings/display/panel/novatek,nt37705.yaml | 71 ++++
arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 64 ++++
arch/arm64/configs/defconfig | 1 +
drivers/gpu/drm/panel/Kconfig | 12 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-novatek-nt37705.c | 396 +++++++++++++++++++++
6 files changed, 545 insertions(+)
---
base-commit: c2cd463d6ee7d55a3ec0719d93c49ff99022d58f
change-id: 20260501-fp6-panel-3d35c999d894
Best regards,
--
Luca Weiss <luca.weiss@fairphone.com>
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 1/4] dt-bindings: display: panel: Add Novatek NT37705 2026-10-02 14:21 [PATCH v3 0/4] Add Novatek NT37705 panel driver for Fairphone (Gen. 6) Luca Weiss @ 2026-10-02 14:21 ` Luca Weiss 2026-10-02 14:21 ` [PATCH v3 2/4] drm/panel: Add driver for Novatek NT37705 panel Luca Weiss ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: Luca Weiss @ 2026-10-02 14:21 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio Cc: ~postmarketos/upstreaming, phone-devel, dri-devel, devicetree, linux-kernel, linux-arm-msm, Luca Weiss, Krzysztof Kozlowski Novatek NT37705 is a display driver IC used to drive AMOLED DSI panels. Describe it and the panel in the Fairphone (Gen. 6) (BJ631JHM-T71-D900 from BOE) using it. Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> Link: https://lore.kernel.org/r/81a3c207-4d8f-490f-8e2a-6f3f4c2acd35@kernel.org/ Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- .../bindings/display/panel/novatek,nt37705.yaml | 71 ++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt37705.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt37705.yaml new file mode 100644 index 000000000000..850d91e25af5 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt37705.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/novatek,nt37705.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Novatek NT37705-based DSI display panels + +maintainers: + - Luca Weiss <luca.weiss@fairphone.com> + +description: + The Novatek NT37705 is a generic DSI Panel IC used to control AMOLED panels. + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: boe,bj631jhm-t71-d900 + + reg: + maxItems: 1 + + vddio-supply: + description: I/O voltage rail + + dvdd-supply: + description: Digital voltage rail + + vci-supply: + description: Analog voltage rail + +required: + - compatible + - reg + - reset-gpios + - vddio-supply + - dvdd-supply + - vci-supply + - port + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "boe,bj631jhm-t71-d900"; + reg = <0>; + + reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + vci-supply = <&vreg_l19b>; + vddio-supply = <&vreg_l9b>; + dvdd-supply = <&vreg_oled_dvdd_1p2>; + + port { + panel_in_0: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; + +... -- 2.56.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/4] drm/panel: Add driver for Novatek NT37705 panel 2026-10-02 14:21 [PATCH v3 0/4] Add Novatek NT37705 panel driver for Fairphone (Gen. 6) Luca Weiss 2026-10-02 14:21 ` [PATCH v3 1/4] dt-bindings: display: panel: Add Novatek NT37705 Luca Weiss @ 2026-10-02 14:21 ` Luca Weiss 2026-10-03 1:33 ` sashiko-bot 2026-10-02 14:21 ` [PATCH v3 3/4] arm64: defconfig: Enable " Luca Weiss 2026-10-02 14:21 ` [PATCH v3 4/4] arm64: dts: qcom: milos-fairphone-fp6: Enable display Luca Weiss 3 siblings, 1 reply; 6+ messages in thread From: Luca Weiss @ 2026-10-02 14:21 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio Cc: ~postmarketos/upstreaming, phone-devel, dri-devel, devicetree, linux-kernel, linux-arm-msm, Luca Weiss Add support for the 2484x1116 AMOLED panel from BOE (BJ631JHM-T71-D900) bundled with a NT37705 driver IC, as found on the Fairphone (Gen. 6) smartphone. The panel can also be configured in 10-bit (RGB101010) mode, however currently it's configured in 8-bit (RGB888) since there's some issues in the Qualcomm DPU driver when driving this panel in 10-bit. Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- drivers/gpu/drm/panel/Kconfig | 12 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-novatek-nt37705.c | 396 ++++++++++++++++++++++++++ 3 files changed, 409 insertions(+) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index cbdf7b8f7f7a..be2f812bef76 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -706,6 +706,18 @@ 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_NT37705 + tristate "Novatek NT37705-based 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 here if you want to enable support for Novatek NT37705-based + display panels, such as the one found in the Fairphone (Gen. 6) + smartphone. + 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..e1366b5e25fc 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_NT37705) += panel-novatek-nt37705.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-nt37705.c b/drivers/gpu/drm/panel/panel-novatek-nt37705.c new file mode 100644 index 000000000000..3cf092a1f360 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-novatek-nt37705.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2026 Luca Weiss <luca.weiss@fairphone.com> + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/device-id/of.h> +#include <linux/gpio/consumer.h> +#include <linux/module.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 nt37705_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct drm_dsc_config dsc; + struct regulator_bulk_data *supplies; + struct gpio_desc *reset_gpio; +}; + +static const struct regulator_bulk_data nt37705_supplies[] = { + { .supply = "vddio" }, + { .supply = "dvdd" }, + { .supply = "vci" }, +}; + +static inline struct nt37705_panel *to_nt37705_panel(struct drm_panel *panel) +{ + return container_of_const(panel, struct nt37705_panel, panel); +} + +static void nt37705_reset(struct nt37705_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +static int nt37705_on(struct nt37705_panel *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, + 0x55, 0xaa, 0x52, 0x08, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, 0x18); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x2c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x05, 0x05, + 0x05, 0x00, 0x05, 0x05, 0x05, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x3c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0b, + 0x0b, 0x00, 0x00, 0x0b, 0x0b, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x4c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x5c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x6c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x0b, + 0x77, 0x77, 0x00, 0x00, 0x0b, 0x00, 0x1d, + 0x00, 0x1d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x7c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x0b, + 0x77, 0x77, 0x00, 0x00, 0x0b, 0x00, 0x1d, + 0x00, 0x1d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x8c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x9c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x11, 0x11, 0x20, 0x02, 0x00, 0x03, 0x00, + 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0xa4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, 0x00, 0xc0, 0x40, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0xa8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, + 0x55, 0xaa, 0x52, 0x08, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x15, 0x15, 0x15, 0xdd); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, + 0x55, 0xaa, 0x52, 0x08, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x32); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, + 0x55, 0xaa, 0x52, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x19); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x55); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x11); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x01, 0x7f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x2d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x01, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x3c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf9, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x0d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x83); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x12); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x41); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x13); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfd, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x20); + mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x045b); + mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x09b3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00); + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0xbb0d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x04); + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0xfe0f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x01, 0x19); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x03, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, + 0x89, 0x28, 0x00, 0x0c, 0xd2, 0x00, 0x02, + 0x2f, 0x01, 0x18, 0x00, 0x07, 0x09, 0x75, + 0x08, 0x34, 0x10, 0xf0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x00); + mipi_dsi_msleep(&dsi_ctx, 120); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x00); + mipi_dsi_msleep(&dsi_ctx, 22); + + return dsi_ctx.accum_err; +} + +static int nt37705_off(struct nt37705_panel *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x00); + mipi_dsi_msleep(&dsi_ctx, 20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x00); + mipi_dsi_msleep(&dsi_ctx, 120); + + return dsi_ctx.accum_err; +} + +static int nt37705_prepare(struct drm_panel *panel) +{ + struct nt37705_panel *ctx = to_nt37705_panel(panel); + struct device *dev = &ctx->dsi->dev; + struct drm_dsc_picture_parameter_set pps; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(nt37705_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + nt37705_reset(ctx); + + ret = nt37705_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(nt37705_supplies), ctx->supplies); + return ret; + } + + drm_dsc_pps_payload_pack(&pps, &ctx->dsc); + + ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps); + if (ret < 0) { + dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); + return ret; + } + + ret = mipi_dsi_compression_mode(ctx->dsi, true); + if (ret < 0) { + dev_err(dev, "failed to enable compression mode: %d\n", ret); + return ret; + } + + msleep(28); /* TODO: Is this panel-dependent? */ + + return 0; +} + +static int nt37705_unprepare(struct drm_panel *panel) +{ + struct nt37705_panel *ctx = to_nt37705_panel(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = nt37705_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(nt37705_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode nt37705_mode = { + .clock = (1116 + 100 + 30 + 100) * (2484 + 70 + 48 + 70) * 120 / 1000, + .hdisplay = 1116, + .hsync_start = 1116 + 100, + .hsync_end = 1116 + 100 + 30, + .htotal = 1116 + 100 + 30 + 100, + .vdisplay = 2484, + .vsync_start = 2484 + 70, + .vsync_end = 2484 + 70 + 48, + .vtotal = 2484 + 70 + 48 + 70, + .width_mm = 66, + .height_mm = 146, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int nt37705_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &nt37705_mode); +} + +static const struct drm_panel_funcs nt37705_panel_funcs = { + .prepare = nt37705_prepare, + .unprepare = nt37705_unprepare, + .get_modes = nt37705_get_modes, +}; + +static int nt37705_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 const struct backlight_ops nt37705_bl_ops = { + .update_status = nt37705_bl_update_status, +}; + +static struct backlight_device * +nt37705_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .scale = BACKLIGHT_SCALE_NON_LINEAR, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &nt37705_bl_ops, &props); +} + +static int nt37705_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct nt37705_panel *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct nt37705_panel, panel, + &nt37705_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(nt37705_supplies), + nt37705_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = nt37705_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + ret = devm_drm_panel_add(dev, &ctx->panel); + if (ret) + return ret; + + /* This panel only supports DSC; unconditionally enable it */ + dsi->dsc = &ctx->dsc; + + ctx->dsc.dsc_version_major = 1; + ctx->dsc.dsc_version_minor = 1; + + /* TODO: Pass slice_per_pkt = 2 */ + ctx->dsc.slice_height = 12; + ctx->dsc.slice_width = 558; + /* + * TODO: hdisplay should be read from the selected mode once + * it is passed back to drm_panel (in prepare?) + */ + WARN_ON(1116 % ctx->dsc.slice_width); + ctx->dsc.slice_count = 1116 / ctx->dsc.slice_width; + ctx->dsc.bits_per_component = 8; + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ + ctx->dsc.block_pred_enable = true; + + return devm_mipi_dsi_attach(dev, dsi); +} + +static const struct of_device_id nt37705_of_match[] = { + { .compatible = "boe,bj631jhm-t71-d900" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, nt37705_of_match); + +static struct mipi_dsi_driver nt37705_driver = { + .probe = nt37705_probe, + .driver = { + .name = "panel-novatek-nt37705", + .of_match_table = nt37705_of_match, + }, +}; +module_mipi_dsi_driver(nt37705_driver); + +MODULE_DESCRIPTION("DRM driver for NT37705-equipped DSI panels"); +MODULE_LICENSE("GPL"); -- 2.56.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/4] drm/panel: Add driver for Novatek NT37705 panel 2026-10-02 14:21 ` [PATCH v3 2/4] drm/panel: Add driver for Novatek NT37705 panel Luca Weiss @ 2026-10-03 1:33 ` sashiko-bot 0 siblings, 0 replies; 6+ messages in thread From: sashiko-bot @ 2026-10-03 1:33 UTC (permalink / raw) To: Luca Weiss; +Cc: conor+dt, robh, dri-devel, devicetree Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] drm/panel: resource leak in nt37705_prepare() error path - [High] drm/panel: unsafe DSI access from backlight sysfs when panel is unpowered - [Medium] drm/panel: race condition and state corruption in backlight sysfs handler - [Medium] drm/panel: DCS protocol violation sending extra parameters - [Medium] drm/panel: premature exposure via devm_drm_panel_add() before DSC init -- commit 512ec900afa4de1ceeb7c942bc90e389f2a7b45d Author: Luca Weiss <luca.weiss@fairphone.com> drm/panel: Add driver for Novatek NT37705 panel Add support for the 2484x1116 AMOLED panel from BOE (BJ631JHM-T71-D900) bundled with a NT37705 driver IC, as found on the Fairphone (Gen. 6) smartphone. The panel can also be configured in 10-bit (RGB101010) mode, however currently it's configured in 8-bit (RGB888) since there's some issues in the Qualcomm DPU driver when driving this panel in 10-bit. > diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37705.c b/drivers/gpu/drm/panel/panel-novatek-nt37705.c > new file mode 100644 > index 0000000000000..3cf092a1f360d > --- /dev/null > +++ b/drivers/gpu/drm/panel/panel-novatek-nt37705.c [ ... ] > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x00); > + mipi_dsi_msleep(&dsi_ctx, 120); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x00); > + mipi_dsi_msleep(&dsi_ctx, 22); > + > + return dsi_ctx.accum_err; > +} [Severity: Medium] Does this code send extra parameters for zero-parameter DCS commands? The DCS specification defines MIPI_DCS_EXIT_SLEEP_MODE (0x11) and MIPI_DCS_SET_DISPLAY_ON (0x29) as zero-parameter commands. By appending a 0x00 argument here, the DSI core will send a DCS Short Write with 1 parameter (Data Type 0x15) instead of a DCS Short Write with 0 parameters (Data Type 0x05). Could this protocol violation cause the panel or DSI host to reject the command? > +static int nt37705_off(struct nt37705_panel *ctx) > +{ > + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; > + > + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; > + > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x00); > + mipi_dsi_msleep(&dsi_ctx, 20); > + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x00); > + mipi_dsi_msleep(&dsi_ctx, 120); [Severity: Medium] Similarly, MIPI_DCS_SET_DISPLAY_OFF (0x28) and MIPI_DCS_ENTER_SLEEP_MODE (0x10) are also zero-parameter commands. Should the trailing 0x00 parameter byte be removed to prevent DCS protocol violations here as well? [ ... ] > + ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps); > + if (ret < 0) { > + dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); > + return ret; > + } > + > + ret = mipi_dsi_compression_mode(ctx->dsi, true); > + if (ret < 0) { > + dev_err(dev, "failed to enable compression mode: %d\n", ret); > + return ret; > + } > + > + msleep(28); /* TODO: Is this panel-dependent? */ > + > + return 0; > +} [Severity: High] Does this code leak the enabled regulators and leave the reset GPIO asserted on these error paths? If either mipi_dsi_picture_parameter_set() or mipi_dsi_compression_mode() fails, the function returns immediately. Since the DRM framework does not invoke unprepare() when prepare() returns an error, this skips the regulator_bulk_disable() cleanup. This could cause a permanent resource leak and leave the hardware powered on in an inconsistent state. [ ... ] > +static int nt37705_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; > +} [Severity: Medium] Are these non-atomic bitwise operations on dsi->mode_flags safe from race conditions? This sysfs handler can execute concurrently with DRM modeset operations (such as nt37705_on()) which also modify dsi->mode_flags, potentially causing a data race and state corruption. Additionally, if mipi_dsi_dcs_set_display_brightness_large() fails, the function returns early without restoring MIPI_DSI_MODE_LPM. Could this permanently corrupt the DSI mode flags for all subsequent sequences? [Severity: High] Is it safe to issue DCS writes here without verifying if the panel is currently powered on? The backlight sysfs node is registered in nt37705_probe() before the DSI device is attached: ctx->panel.backlight = nt37705_create_backlight(dsi); ... return devm_mipi_dsi_attach(dev, dsi); If userspace writes to the brightness node while the screen is off (regulators disabled, reset asserted) or before the driver finishes probing, it forces a DCS write to an unpowered or unattached DSI bus. Could this cause DSI transmission timeouts or wedge the host controller? [ ... ] > + ctx->panel.backlight = nt37705_create_backlight(dsi); > + if (IS_ERR(ctx->panel.backlight)) > + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), > + "Failed to create backlight\n"); > + > + ret = devm_drm_panel_add(dev, &ctx->panel); > + if (ret) > + return ret; > + > + /* This panel only supports DSC; unconditionally enable it */ > + dsi->dsc = &ctx->dsc; > + > + ctx->dsc.dsc_version_major = 1; > + ctx->dsc.dsc_version_minor = 1; > + > + /* TODO: Pass slice_per_pkt = 2 */ > + ctx->dsc.slice_height = 12; > + ctx->dsc.slice_width = 558; [Severity: Medium] Is it safe to publish the panel to the system before its structural setup is complete? devm_drm_panel_add() is called here, immediately exposing the panel to DRM bridge consumers. However, critical DSC configuration fields (like dsi->dsc, slice_height, and slice_width) are initialized after this call. If a consumer binds concurrently, could it acquire the panel and invoke drm_panel_prepare(), triggering drm_dsc_pps_payload_pack() on uninitialized or zeroed DSC parameters, leading to malformed payload generation or division by zero panics? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261002-fp6-panel-v3-0-4b80f83bc936@fairphone.com?part=2 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 3/4] arm64: defconfig: Enable Novatek NT37705 panel 2026-10-02 14:21 [PATCH v3 0/4] Add Novatek NT37705 panel driver for Fairphone (Gen. 6) Luca Weiss 2026-10-02 14:21 ` [PATCH v3 1/4] dt-bindings: display: panel: Add Novatek NT37705 Luca Weiss 2026-10-02 14:21 ` [PATCH v3 2/4] drm/panel: Add driver for Novatek NT37705 panel Luca Weiss @ 2026-10-02 14:21 ` Luca Weiss 2026-10-02 14:21 ` [PATCH v3 4/4] arm64: dts: qcom: milos-fairphone-fp6: Enable display Luca Weiss 3 siblings, 0 replies; 6+ messages in thread From: Luca Weiss @ 2026-10-02 14:21 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio Cc: ~postmarketos/upstreaming, phone-devel, dri-devel, devicetree, linux-kernel, linux-arm-msm, Luca Weiss, Dmitry Baryshkov Enable the NT37705 panel driver which is used on Fairphone (Gen. 6). Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 6ec8d3a69c98..1d4afc733c8a 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1023,6 +1023,7 @@ CONFIG_DRM_PANEL_KHADAS_TS050=m CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m CONFIG_DRM_PANEL_NOVATEK_NT36672A=m CONFIG_DRM_PANEL_NOVATEK_NT36672E=m +CONFIG_DRM_PANEL_NOVATEK_NT37705=m CONFIG_DRM_PANEL_NOVATEK_NT37801=m CONFIG_DRM_PANEL_RAYDIUM_RM67191=m CONFIG_DRM_PANEL_RAYDIUM_RM692E5=m -- 2.56.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 4/4] arm64: dts: qcom: milos-fairphone-fp6: Enable display 2026-10-02 14:21 [PATCH v3 0/4] Add Novatek NT37705 panel driver for Fairphone (Gen. 6) Luca Weiss ` (2 preceding siblings ...) 2026-10-02 14:21 ` [PATCH v3 3/4] arm64: defconfig: Enable " Luca Weiss @ 2026-10-02 14:21 ` Luca Weiss 3 siblings, 0 replies; 6+ messages in thread From: Luca Weiss @ 2026-10-02 14:21 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio Cc: ~postmarketos/upstreaming, phone-devel, dri-devel, devicetree, linux-kernel, linux-arm-msm, Luca Weiss, Dmitry Baryshkov, Konrad Dybcio Configure the MDSS nodes for the phone and add the panel node. Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts index 4e8777162b53..11015c3fa331 100644 --- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts +++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts @@ -709,6 +709,49 @@ &ipa { status = "okay"; }; +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l4b>; + + status = "okay"; + + panel@0 { + compatible = "boe,bj631jhm-t71-d900"; + reg = <0>; + + reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + vci-supply = <&vreg_l19b>; + vddio-supply = <&vreg_l9b>; + dvdd-supply = <&vreg_oled_dvdd_1p2>; + + pinctrl-0 = <&disp_reset_n_active>, <&mdp_vsync>; + pinctrl-1 = <&disp_reset_n_suspend>, <&mdp_vsync>; + pinctrl-names = "default", + "sleep"; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + data-lanes = <0 1 2 3>; + remote-endpoint = <&panel_in>; +}; + +&mdss_dsi0_phy { + vdds-supply = <&vreg_l2b>; + + status = "okay"; +}; + &pm8550vs_c { status = "okay"; }; @@ -872,6 +915,20 @@ &tlmm { <13 1>, /* NC */ <63 2>; /* WLAN UART */ + disp_reset_n_active: disp-reset-n-active-state { + pins = "gpio12"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + disp_reset_n_suspend: disp-reset-n-suspend-state { + pins = "gpio12"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + sdc2_card_det_n: sdc2-card-det-state { pins = "gpio65"; function = "gpio"; @@ -906,6 +963,13 @@ pm8008_int_default: pm8008-int-default-state { drive-strength = <2>; bias-disable; }; + + mdp_vsync: mdp-vsync-state { + pins = "gpio129"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; }; &uart5 { -- 2.56.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-03 1:33 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-02 14:21 [PATCH v3 0/4] Add Novatek NT37705 panel driver for Fairphone (Gen. 6) Luca Weiss 2026-10-02 14:21 ` [PATCH v3 1/4] dt-bindings: display: panel: Add Novatek NT37705 Luca Weiss 2026-10-02 14:21 ` [PATCH v3 2/4] drm/panel: Add driver for Novatek NT37705 panel Luca Weiss 2026-10-03 1:33 ` sashiko-bot 2026-10-02 14:21 ` [PATCH v3 3/4] arm64: defconfig: Enable " Luca Weiss 2026-10-02 14:21 ` [PATCH v3 4/4] arm64: dts: qcom: milos-fairphone-fp6: Enable display Luca Weiss
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.