* [PATCH 0/2] Add support for Tianma TA066VVHM03 DSI panel
@ 2026-03-08 6:03 Alexander Koskovich
2026-03-08 6:03 ` [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 Alexander Koskovich
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Alexander Koskovich @ 2026-03-08 6:03 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, Alexander Koskovich
Add dt-binding and driver for the Tianma TA066VVHM03 6.59" 1080x2340
AMOLED DSI panel with DSC compression, found in the ASUS ROG Phone 3.
This panel depends on slice_per_pkt support currently being reviewed:
https://lore.kernel.org/linux-arm-msm/20251001135914.13754-3-caojunjie650@gmail.com
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
Alexander Koskovich (2):
dt-bindings: display: panel: Document Tianma TA066VVHM03
drm/panel: Add support for Tianma TA066VVHM03 panel
.../bindings/display/panel/tianma,ta066vvhm03.yaml | 67 ++++
MAINTAINERS | 6 +
drivers/gpu/drm/panel/Kconfig | 11 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c | 387 +++++++++++++++++++++
5 files changed, 472 insertions(+)
---
base-commit: 11439c4635edd669ae435eec308f4ab8a0804808
change-id: 20260308-tianma-ta066vvhm03-a72bd18f2b3f
Best regards,
--
Alexander Koskovich <akoskovich@pm.me>
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 2026-03-08 6:03 [PATCH 0/2] Add support for Tianma TA066VVHM03 DSI panel Alexander Koskovich @ 2026-03-08 6:03 ` Alexander Koskovich 2026-03-08 8:43 ` Krzysztof Kozlowski 2026-03-08 6:03 ` [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich 2026-03-08 21:59 ` Claude review: Add support for Tianma TA066VVHM03 DSI panel Claude Code Review Bot 2 siblings, 1 reply; 11+ messages in thread From: Alexander Koskovich @ 2026-03-08 6:03 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel, Alexander Koskovich Add bindings for the Tianma TA066VVHM03 6.59" 1080x2340 AMOLED DSI panel with DSC compression, found in the ASUS ROG Phone 3. Signed-off-by: Alexander Koskovich <akoskovich@pm.me> --- .../bindings/display/panel/tianma,ta066vvhm03.yaml | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/tianma,ta066vvhm03.yaml b/Documentation/devicetree/bindings/display/panel/tianma,ta066vvhm03.yaml new file mode 100644 index 000000000000..afcdd203e1b0 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/tianma,ta066vvhm03.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/tianma,ta066vvhm03.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tianma TA066VVHM03 AMOLED DSI Panel + +maintainers: + - Alexander Koskovich <akoskovich@pm.me> + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: tianma,ta066vvhm03 + + reg: + maxItems: 1 + description: DSI virtual channel + + vddio-supply: true + vci-supply: true + vdd-supply: true + port: true + enable-gpios: true + reset-gpios: true + +additionalProperties: false + +required: + - compatible + - reg + - vddio-supply + - vci-supply + - vdd-supply + - reset-gpios + - port + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "tianma,ta066vvhm03"; + reg = <0>; + + enable-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>; + reset-gpios = <&tlmm 75 GPIO_ACTIVE_LOW>; + + vci-supply = <&vreg_l10a>; + vdd-supply = <&vreg_l3c>; + vddio-supply = <&vreg_l14a>; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; + }; +... -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 2026-03-08 6:03 ` [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 Alexander Koskovich @ 2026-03-08 8:43 ` Krzysztof Kozlowski 2026-03-08 21:59 ` Claude review: " Claude Code Review Bot 0 siblings, 1 reply; 11+ messages in thread From: Krzysztof Kozlowski @ 2026-03-08 8:43 UTC (permalink / raw) To: Alexander Koskovich, Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel On 08/03/2026 07:03, Alexander Koskovich wrote: > + > + vddio-supply: true > + vci-supply: true > + vdd-supply: true > + port: true > + enable-gpios: true > + reset-gpios: true > + > +additionalProperties: false This should be placed after "required:" block. Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> > + > +required: > + - compatible > + - reg > + - vddio-supply > + - vci-supply > + - vdd-supply > + - reset-gpios > + - port Best regards, Krzysztof ^ permalink raw reply [flat|nested] 11+ messages in thread
* Claude review: Re: [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 2026-03-08 8:43 ` Krzysztof Kozlowski @ 2026-03-08 21:59 ` Claude Code Review Bot 0 siblings, 0 replies; 11+ messages in thread From: Claude Code Review Bot @ 2026-03-08 21:59 UTC (permalink / raw) To: dri-devel-reviews Patch Review The binding looks reasonable overall but has one issue: **`enable-gpios` is optional in binding but required by the driver:** The binding does not list `enable-gpios` in the `required` section, yet the driver in patch 2 uses `devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW)` which will fail if the GPIO is not specified. Either add `enable-gpios` to the `required` list in the binding, or make the driver use `devm_gpiod_get_optional()`. Since the example DT node includes it and the driver needs it, adding it to `required` seems correct: ```yaml required: - compatible - reg - vddio-supply - vci-supply - vdd-supply - reset-gpios - port ``` Should also include `enable-gpios` here. Otherwise the binding is clean — it uses `panel-common.yaml` reference, has proper `additionalProperties: false`, and includes a complete example. --- --- Generated by Claude Code Patch Reviewer ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-08 6:03 [PATCH 0/2] Add support for Tianma TA066VVHM03 DSI panel Alexander Koskovich 2026-03-08 6:03 ` [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 Alexander Koskovich @ 2026-03-08 6:03 ` Alexander Koskovich 2026-03-08 14:16 ` kernel test robot ` (2 more replies) 2026-03-08 21:59 ` Claude review: Add support for Tianma TA066VVHM03 DSI panel Claude Code Review Bot 2 siblings, 3 replies; 11+ messages in thread From: Alexander Koskovich @ 2026-03-08 6:03 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel, Alexander Koskovich Add driver for the Tianma TA066VVHM03 6.59" 1080x2340 AMOLED DSI panel with DSC compression, found in the ASUS ROG Phone 3. Signed-off-by: Alexander Koskovich <akoskovich@pm.me> --- MAINTAINERS | 6 + drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c | 387 +++++++++++++++++++++++ 4 files changed, 405 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 61bf550fd37c..6b729300daf5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8385,6 +8385,12 @@ F: Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml F: drivers/gpu/drm/bridge/synopsys/dw-dp.c F: include/drm/bridge/dw_dp.h +DRM DRIVER FOR TIANMA TA066VVHM03 PANELS +M: Alexander Koskovich <akoskovich@pm.me> +S: Maintained +F: Documentation/devicetree/bindings/display/panel/tianma,ta066vvhm03.yaml +F: drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c + DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE M: Jagan Teki <jagan@amarulasolutions.com> S: Maintained diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 307152ad7759..c818c701bdf6 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -1122,6 +1122,17 @@ config DRM_PANEL_TDO_TL070WSH30 24 bit RGB per pixel. It provides a MIPI DSI interface to the host, a built-in LED backlight and touch controller. +config DRM_PANEL_TIANMA_TA066VVHM03 + tristate "Tianma TA066VVHM03 panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for the Tianma TA066VVHM03 panel + driver. The panel has a 1080x2340 resolution and uses 24 bit RGB per + pixel. It provides a MIPI DSI interface to the host and has a + built-in touch controller. + config DRM_PANEL_TPO_TD028TTEC1 tristate "Toppoly (TPO) TD028TTEC1 panel driver" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index aeffaa95666d..db257778b9f1 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o obj-$(CONFIG_DRM_PANEL_STARTEK_KD070FHFID015) += panel-startek-kd070fhfid015.o obj-$(CONFIG_DRM_PANEL_TDO_TL070WSH30) += panel-tdo-tl070wsh30.o +obj-$(CONFIG_DRM_PANEL_TIANMA_TA066VVHM03) += panel-tianma-ta066vvhm03.o obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o diff --git a/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c b/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c new file mode 100644 index 000000000000..9bf0f4ab6792 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2026 Alexander Koskovich <akoskovich@pm.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/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 tianma_ta066vvhm03 { + struct regulator_bulk_data *supplies; + struct gpio_desc *enable_gpio; + struct gpio_desc *reset_gpio; + struct mipi_dsi_device *dsi; + struct drm_dsc_config dsc; + struct drm_panel panel; +}; + +static const struct regulator_bulk_data tianma_ta066vvhm03_supplies[] = { + { .supply = "vddio" }, + { .supply = "vci" }, + { .supply = "vdd" }, +}; + +static inline +struct tianma_ta066vvhm03 *to_tianma_ta066vvhm03(struct drm_panel *panel) +{ + return container_of(panel, struct tianma_ta066vvhm03, panel); +} + +static void tianma_ta066vvhm03_reset(struct tianma_ta066vvhm03 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(1000, 2000); + 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 tianma_ta066vvhm03_on(struct tianma_ta066vvhm03 *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, 0xb0, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, + 0x94, 0x42, 0x00, 0x16, 0x05, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x10, 0x00, 0xaa, 0x8a, + 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x3f, + 0x3f, 0x03, 0xff, 0x03, 0xff, 0x23, 0xff, + 0x03, 0xff, 0x23, 0xff, 0x03, 0xff, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x10, 0x01, 0x00, + 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x09, 0x24, 0x0e, 0x00, 0x00, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x2f, 0x00, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, + 0x64, 0x0b, 0x00, 0xc0, 0x02, 0xa6, 0x04, + 0x7f, 0x0b, 0x77, 0x0b, 0x8b, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x00, 0x10, 0x01, 0x68, + 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, 0x01, + 0x68, 0x01, 0x69, 0x03, 0x98, 0x03, 0x70, + 0x03, 0x70, 0x03, 0x70, 0x03, 0x70, 0x00, + 0x10, 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, + 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, 0x03, + 0x98, 0x03, 0x70, 0x03, 0x70, 0x03, 0x70, + 0x03, 0x70, 0x01, 0x42, 0x01, 0x42, 0x01, + 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x42, + 0x01, 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, + 0x42, 0x01, 0x42, 0x01, 0x42, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x00, 0x01, 0x9a, 0x01, 0x9a, + 0x01, 0x9a, 0x05, 0xae, 0x05, 0xae, 0x09, + 0xa4, 0x09, 0xa4, 0x09, 0xa4, 0x09, 0xa4, + 0x09, 0xa4, 0x09, 0xa4, 0x0f, 0xc3, 0x19); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd7, + 0x00, 0xa9, 0x34, 0x00, 0x20, 0x02, 0x00, + 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x40, + 0x09, 0x00, 0x00, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, + 0x00, 0x30, 0x00, 0x30, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x00, 0x2f, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, + 0x59, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0x4a, 0x48, 0x46, 0x44, + 0x42, 0x40, 0x3e, 0x3c, 0x3a, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x04, 0x00, 0x04, 0x04, 0x42, 0x04, + 0x69, 0x5a, 0x00, 0x0a, 0xb0, 0x0f, 0xff, + 0x0f, 0xff, 0x0f, 0xff, 0x14, 0x81, 0xf4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe8, 0x00, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe4, 0x00, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x93); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xde, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x50, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, + 0x50, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x11); + mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, + 0x01, 0x00, 0x00, 0x00, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x00, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x19); + mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x50, 0x42); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x24); + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x0437); + mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0923); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x01); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 100); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + + return dsi_ctx.accum_err; +} + +static int tianma_ta066vvhm03_off(struct tianma_ta066vvhm03 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + 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 tianma_ta066vvhm03_prepare(struct drm_panel *panel) +{ + struct tianma_ta066vvhm03 *ctx = to_tianma_ta066vvhm03(panel); + struct drm_dsc_picture_parameter_set pps; + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(tianma_ta066vvhm03_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ctx->enable_gpio, 1); + + tianma_ta066vvhm03_reset(ctx); + + ret = tianma_ta066vvhm03_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + gpiod_set_value_cansleep(ctx->enable_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(tianma_ta066vvhm03_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; + } + + return 0; +} + +static int tianma_ta066vvhm03_unprepare(struct drm_panel *panel) +{ + struct tianma_ta066vvhm03 *ctx = to_tianma_ta066vvhm03(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = tianma_ta066vvhm03_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->enable_gpio, 0); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(tianma_ta066vvhm03_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode tianma_ta066vvhm03_mode = { + .clock = (1080 + 24 + 4 + 10) * (2340 + 12 + 1 + 4) * 160 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 24, + .hsync_end = 1080 + 24 + 4, + .htotal = 1080 + 24 + 4 + 10, + .vdisplay = 2340, + .vsync_start = 2340 + 12, + .vsync_end = 2340 + 12 + 1, + .vtotal = 2340 + 12 + 1 + 4, + .width_mm = 70, + .height_mm = 152, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int tianma_ta066vvhm03_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &tianma_ta066vvhm03_mode); +} + +static const struct drm_panel_funcs tianma_ta066vvhm03_panel_funcs = { + .prepare = tianma_ta066vvhm03_prepare, + .unprepare = tianma_ta066vvhm03_unprepare, + .get_modes = tianma_ta066vvhm03_get_modes, +}; + +static int tianma_ta066vvhm03_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 tianma_ta066vvhm03_bl_ops = { + .update_status = tianma_ta066vvhm03_bl_update_status, +}; + +static struct backlight_device * +tianma_ta066vvhm03_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &tianma_ta066vvhm03_bl_ops, &props); +} + +static int tianma_ta066vvhm03_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct tianma_ta066vvhm03 *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct tianma_ta066vvhm03, panel, + &tianma_ta066vvhm03_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(tianma_ta066vvhm03_supplies), + tianma_ta066vvhm03_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ctx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), + "Failed to get enable-gpios\n"); + + 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 = tianma_ta066vvhm03_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + /* This panel only supports DSC; unconditionally enable it */ + dsi->dsc = &ctx->dsc; + dsi->dsc_slice_per_pkt = 2; + + ctx->dsc.dsc_version_major = 1; + ctx->dsc.dsc_version_minor = 1; + + ctx->dsc.slice_height = 20; + ctx->dsc.slice_width = 540; + WARN_ON(1080 % ctx->dsc.slice_width); + ctx->dsc.slice_count = 1080 / ctx->dsc.slice_width; + ctx->dsc.bits_per_component = 10; + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ + ctx->dsc.block_pred_enable = true; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void tianma_ta066vvhm03_remove(struct mipi_dsi_device *dsi) +{ + struct tianma_ta066vvhm03 *ctx = 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(&ctx->panel); +} + +static const struct of_device_id tianma_ta066vvhm03_of_match[] = { + { .compatible = "tianma,ta066vvhm03" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tianma_ta066vvhm03_of_match); + +static struct mipi_dsi_driver tianma_ta066vvhm03_driver = { + .probe = tianma_ta066vvhm03_probe, + .remove = tianma_ta066vvhm03_remove, + .driver = { + .name = "panel-tianma-ta066vvhm03", + .of_match_table = tianma_ta066vvhm03_of_match, + }, +}; +module_mipi_dsi_driver(tianma_ta066vvhm03_driver); + +MODULE_AUTHOR("Alexander Koskovich <akoskovich@pm.me>"); +MODULE_DESCRIPTION("DRM driver for Tianma TA066VVHM03-00"); +MODULE_LICENSE("GPL"); -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-08 6:03 ` [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich @ 2026-03-08 14:16 ` kernel test robot 2026-03-08 14:37 ` kernel test robot 2026-03-08 21:59 ` Claude review: " Claude Code Review Bot 2 siblings, 0 replies; 11+ messages in thread From: kernel test robot @ 2026-03-08 14:16 UTC (permalink / raw) To: Alexander Koskovich, Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: llvm, oe-kbuild-all, dri-devel, devicetree, linux-kernel, Alexander Koskovich Hi Alexander, kernel test robot noticed the following build errors: [auto build test ERROR on 11439c4635edd669ae435eec308f4ab8a0804808] url: https://github.com/intel-lab-lkp/linux/commits/Alexander-Koskovich/dt-bindings-display-panel-Document-Tianma-TA066VVHM03/20260308-140525 base: 11439c4635edd669ae435eec308f4ab8a0804808 patch link: https://lore.kernel.org/r/20260308-tianma-ta066vvhm03-v1-2-869fac443b20%40pm.me patch subject: [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20260308/202603082210.FAhPnZOe-lkp@intel.com/config) compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260308/202603082210.FAhPnZOe-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202603082210.FAhPnZOe-lkp@intel.com/ All errors (new ones prefixed by >>): >> drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c:335:7: error: no member named 'dsc_slice_per_pkt' in 'struct mipi_dsi_device' 335 | dsi->dsc_slice_per_pkt = 2; | ~~~ ^ 1 error generated. vim +335 drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c 286 287 static int tianma_ta066vvhm03_probe(struct mipi_dsi_device *dsi) 288 { 289 struct device *dev = &dsi->dev; 290 struct tianma_ta066vvhm03 *ctx; 291 int ret; 292 293 ctx = devm_drm_panel_alloc(dev, struct tianma_ta066vvhm03, panel, 294 &tianma_ta066vvhm03_panel_funcs, 295 DRM_MODE_CONNECTOR_DSI); 296 if (IS_ERR(ctx)) 297 return PTR_ERR(ctx); 298 299 ret = devm_regulator_bulk_get_const(dev, 300 ARRAY_SIZE(tianma_ta066vvhm03_supplies), 301 tianma_ta066vvhm03_supplies, 302 &ctx->supplies); 303 if (ret < 0) 304 return ret; 305 306 ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 307 if (IS_ERR(ctx->enable_gpio)) 308 return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), 309 "Failed to get enable-gpios\n"); 310 311 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 312 if (IS_ERR(ctx->reset_gpio)) 313 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 314 "Failed to get reset-gpios\n"); 315 316 ctx->dsi = dsi; 317 mipi_dsi_set_drvdata(dsi, ctx); 318 319 dsi->lanes = 4; 320 dsi->format = MIPI_DSI_FMT_RGB888; 321 dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET | 322 MIPI_DSI_CLOCK_NON_CONTINUOUS; 323 324 ctx->panel.prepare_prev_first = true; 325 326 ctx->panel.backlight = tianma_ta066vvhm03_create_backlight(dsi); 327 if (IS_ERR(ctx->panel.backlight)) 328 return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), 329 "Failed to create backlight\n"); 330 331 drm_panel_add(&ctx->panel); 332 333 /* This panel only supports DSC; unconditionally enable it */ 334 dsi->dsc = &ctx->dsc; > 335 dsi->dsc_slice_per_pkt = 2; 336 337 ctx->dsc.dsc_version_major = 1; 338 ctx->dsc.dsc_version_minor = 1; 339 340 ctx->dsc.slice_height = 20; 341 ctx->dsc.slice_width = 540; 342 WARN_ON(1080 % ctx->dsc.slice_width); 343 ctx->dsc.slice_count = 1080 / ctx->dsc.slice_width; 344 ctx->dsc.bits_per_component = 10; 345 ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ 346 ctx->dsc.block_pred_enable = true; 347 348 ret = mipi_dsi_attach(dsi); 349 if (ret < 0) { 350 drm_panel_remove(&ctx->panel); 351 return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 352 } 353 354 return 0; 355 } 356 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-08 6:03 ` [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich 2026-03-08 14:16 ` kernel test robot @ 2026-03-08 14:37 ` kernel test robot 2026-03-08 21:59 ` Claude review: " Claude Code Review Bot 2 siblings, 0 replies; 11+ messages in thread From: kernel test robot @ 2026-03-08 14:37 UTC (permalink / raw) To: Alexander Koskovich, Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: oe-kbuild-all, dri-devel, devicetree, linux-kernel, Alexander Koskovich Hi Alexander, kernel test robot noticed the following build errors: [auto build test ERROR on 11439c4635edd669ae435eec308f4ab8a0804808] url: https://github.com/intel-lab-lkp/linux/commits/Alexander-Koskovich/dt-bindings-display-panel-Document-Tianma-TA066VVHM03/20260308-140525 base: 11439c4635edd669ae435eec308f4ab8a0804808 patch link: https://lore.kernel.org/r/20260308-tianma-ta066vvhm03-v1-2-869fac443b20%40pm.me patch subject: [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20260308/202603082223.61KVemAP-lkp@intel.com/config) compiler: alpha-linux-gcc (GCC) 15.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260308/202603082223.61KVemAP-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202603082223.61KVemAP-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c: In function 'tianma_ta066vvhm03_probe': >> drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c:335:12: error: 'struct mipi_dsi_device' has no member named 'dsc_slice_per_pkt' 335 | dsi->dsc_slice_per_pkt = 2; | ^~ vim +335 drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c 286 287 static int tianma_ta066vvhm03_probe(struct mipi_dsi_device *dsi) 288 { 289 struct device *dev = &dsi->dev; 290 struct tianma_ta066vvhm03 *ctx; 291 int ret; 292 293 ctx = devm_drm_panel_alloc(dev, struct tianma_ta066vvhm03, panel, 294 &tianma_ta066vvhm03_panel_funcs, 295 DRM_MODE_CONNECTOR_DSI); 296 if (IS_ERR(ctx)) 297 return PTR_ERR(ctx); 298 299 ret = devm_regulator_bulk_get_const(dev, 300 ARRAY_SIZE(tianma_ta066vvhm03_supplies), 301 tianma_ta066vvhm03_supplies, 302 &ctx->supplies); 303 if (ret < 0) 304 return ret; 305 306 ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 307 if (IS_ERR(ctx->enable_gpio)) 308 return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), 309 "Failed to get enable-gpios\n"); 310 311 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 312 if (IS_ERR(ctx->reset_gpio)) 313 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 314 "Failed to get reset-gpios\n"); 315 316 ctx->dsi = dsi; 317 mipi_dsi_set_drvdata(dsi, ctx); 318 319 dsi->lanes = 4; 320 dsi->format = MIPI_DSI_FMT_RGB888; 321 dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET | 322 MIPI_DSI_CLOCK_NON_CONTINUOUS; 323 324 ctx->panel.prepare_prev_first = true; 325 326 ctx->panel.backlight = tianma_ta066vvhm03_create_backlight(dsi); 327 if (IS_ERR(ctx->panel.backlight)) 328 return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), 329 "Failed to create backlight\n"); 330 331 drm_panel_add(&ctx->panel); 332 333 /* This panel only supports DSC; unconditionally enable it */ 334 dsi->dsc = &ctx->dsc; > 335 dsi->dsc_slice_per_pkt = 2; 336 337 ctx->dsc.dsc_version_major = 1; 338 ctx->dsc.dsc_version_minor = 1; 339 340 ctx->dsc.slice_height = 20; 341 ctx->dsc.slice_width = 540; 342 WARN_ON(1080 % ctx->dsc.slice_width); 343 ctx->dsc.slice_count = 1080 / ctx->dsc.slice_width; 344 ctx->dsc.bits_per_component = 10; 345 ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ 346 ctx->dsc.block_pred_enable = true; 347 348 ret = mipi_dsi_attach(dsi); 349 if (ret < 0) { 350 drm_panel_remove(&ctx->panel); 351 return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 352 } 353 354 return 0; 355 } 356 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 11+ messages in thread
* Claude review: drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-08 6:03 ` [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich 2026-03-08 14:16 ` kernel test robot 2026-03-08 14:37 ` kernel test robot @ 2026-03-08 21:59 ` Claude Code Review Bot 2 siblings, 0 replies; 11+ messages in thread From: Claude Code Review Bot @ 2026-03-08 21:59 UTC (permalink / raw) To: dri-devel-reviews Patch Review **1. Build dependency on unmerged `slice_per_pkt` field (blocking):** The probe function sets: ```c dsi->dsc_slice_per_pkt = 2; ``` This field (`dsc_slice_per_pkt`) does not exist in `struct mipi_dsi_device` in the current kernel tree. The cover letter notes this depends on a patch currently under review. This patch cannot be applied or built until that dependency is merged. The series should either explicitly note this with a `Depends-on:` tag or be resubmitted once the dependency lands. **2. Missing cleanup in `prepare` error paths (bug):** In `tianma_ta066vvhm03_prepare`, the error paths after `mipi_dsi_picture_parameter_set()` and `mipi_dsi_compression_mode()` just return the error without disabling GPIOs or regulators: ```c 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; /* leaks: regulators, enable_gpio, reset_gpio */ } ret = mipi_dsi_compression_mode(ctx->dsi, true); if (ret < 0) { dev_err(dev, "failed to enable compression mode: %d\n", ret); return ret; /* same leak */ } ``` Compare to the earlier error path after `tianma_ta066vvhm03_on()` which correctly cleans up. These later error paths need the same treatment: assert reset, deassert enable, and disable regulators. Consider using a common `goto` label. Also note the inconsistent `dev` pointer usage: the PPS error message uses `panel->dev` while all other messages use the local `dev` variable. Use `dev` consistently. **3. LPM mode toggling in `_off` (questionable):** ```c static int tianma_ta066vvhm03_off(struct tianma_ta066vvhm03 *ctx) { ... ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); ``` This clears LPM, meaning display-off and enter-sleep commands are sent in HS mode. Most panels send shutdown commands in LP mode. This may be correct for this specific panel (vendor DT generated), but it's worth double-checking since it's unusual. Similarly, the backlight callback toggles LPM off for brightness writes then back on: ```c dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); ... dsi->mode_flags |= MIPI_DSI_MODE_LPM; ``` This is a common pattern in generated drivers but is inherently racy if multiple threads could call into the DSI driver simultaneously. **4. Clock/refresh rate:** The pixel clock calculation gives: ```c .clock = (1080 + 24 + 4 + 10) * (2340 + 12 + 1 + 4) * 160 / 1000, ``` This yields ~421 MHz and ~160 Hz refresh rate. For a gaming phone (ROG Phone 3) this seems plausible, but should be verified against hardware documentation. The 160 divisor is the target refresh rate — is 160 Hz confirmed for this panel? **5. MAINTAINERS entry is fine.** Kconfig/Makefile additions are properly sorted alphabetically. **6. Minor:** The `_reset` function uses `GPIOD_OUT_HIGH` at probe (assert reset), then in the reset sequence does 0→1→0. With the active-low polarity from the DT (`GPIO_ACTIVE_LOW`), this means physical low→high→low. This should be verified against the panel datasheet reset timing requirements. --- Generated by Claude Code Patch Reviewer ^ permalink raw reply [flat|nested] 11+ messages in thread
* Claude review: Add support for Tianma TA066VVHM03 DSI panel 2026-03-08 6:03 [PATCH 0/2] Add support for Tianma TA066VVHM03 DSI panel Alexander Koskovich 2026-03-08 6:03 ` [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 Alexander Koskovich 2026-03-08 6:03 ` [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich @ 2026-03-08 21:59 ` Claude Code Review Bot 2 siblings, 0 replies; 11+ messages in thread From: Claude Code Review Bot @ 2026-03-08 21:59 UTC (permalink / raw) To: dri-devel-reviews Overall Series Review Subject: Add support for Tianma TA066VVHM03 DSI panel Author: Alexander Koskovich <AKoskovich@pm.me> Patches: 6 Reviewed: 2026-03-09T07:59:02.650574 --- This is a straightforward 2-patch series adding a new DSI panel driver for the Tianma TA066VVHM03 AMOLED panel (6.59" 1080x2340 with DSC), found in the ASUS ROG Phone 3. The driver was generated with `linux-mdss-dsi-panel-driver-generator`. The series uses modern APIs (`devm_drm_panel_alloc`, `drm_connector_helper_get_modes_fixed`, `mipi_dsi_multi_context`), which is good. However, there are a few issues: 1. **Hard dependency on unmerged `dsc_slice_per_pkt` support** — this series cannot build without that patch being merged first. 2. **Missing error-path cleanup in `prepare`** — after PPS or compression mode fails, GPIOs and regulators are left enabled. 3. **Binding/driver mismatch for `enable-gpios`** — the binding makes it optional but the driver requires it. --- --- Generated by Claude Code Patch Reviewer ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 0/2] Add support for Tianma TA066VVHM03 DSI panel
@ 2026-03-08 21:08 Alexander Koskovich
2026-03-08 21:09 ` [PATCH v2 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich
0 siblings, 1 reply; 11+ messages in thread
From: Alexander Koskovich @ 2026-03-08 21:08 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, Alexander Koskovich,
Krzysztof Kozlowski
Add dt-binding and driver for the Tianma TA066VVHM03 6.59" 1080x2340
AMOLED DSI panel with DSC compression, found in the ASUS ROG Phone 3.
This panel depends on slice_per_pkt support currently being reviewed:
https://lore.kernel.org/linux-arm-msm/20251001135914.13754-3-caojunjie650@gmail.com
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
Changes in v2:
- Move additionalProperties after required block in bindings
- Link to v1: https://lore.kernel.org/r/20260308-tianma-ta066vvhm03-v1-0-869fac443b20@pm.me
---
Alexander Koskovich (2):
dt-bindings: display: panel: Document Tianma TA066VVHM03
drm/panel: Add support for Tianma TA066VVHM03 panel
.../bindings/display/panel/tianma,ta066vvhm03.yaml | 67 ++++
MAINTAINERS | 6 +
drivers/gpu/drm/panel/Kconfig | 11 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c | 387 +++++++++++++++++++++
5 files changed, 472 insertions(+)
---
base-commit: 11439c4635edd669ae435eec308f4ab8a0804808
change-id: 20260308-tianma-ta066vvhm03-a72bd18f2b3f
Best regards,
--
Alexander Koskovich <akoskovich@pm.me>
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v2 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-08 21:08 [PATCH v2 0/2] " Alexander Koskovich @ 2026-03-08 21:09 ` Alexander Koskovich 2026-03-10 2:50 ` Claude review: " Claude Code Review Bot 0 siblings, 1 reply; 11+ messages in thread From: Alexander Koskovich @ 2026-03-08 21:09 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel, Alexander Koskovich Add driver for the Tianma TA066VVHM03 6.59" 1080x2340 AMOLED DSI panel with DSC compression, found in the ASUS ROG Phone 3. Signed-off-by: Alexander Koskovich <akoskovich@pm.me> --- MAINTAINERS | 6 + drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c | 387 +++++++++++++++++++++++ 4 files changed, 405 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 61bf550fd37c..6b729300daf5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8385,6 +8385,12 @@ F: Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml F: drivers/gpu/drm/bridge/synopsys/dw-dp.c F: include/drm/bridge/dw_dp.h +DRM DRIVER FOR TIANMA TA066VVHM03 PANELS +M: Alexander Koskovich <akoskovich@pm.me> +S: Maintained +F: Documentation/devicetree/bindings/display/panel/tianma,ta066vvhm03.yaml +F: drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c + DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE M: Jagan Teki <jagan@amarulasolutions.com> S: Maintained diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 307152ad7759..c818c701bdf6 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -1122,6 +1122,17 @@ config DRM_PANEL_TDO_TL070WSH30 24 bit RGB per pixel. It provides a MIPI DSI interface to the host, a built-in LED backlight and touch controller. +config DRM_PANEL_TIANMA_TA066VVHM03 + tristate "Tianma TA066VVHM03 panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for the Tianma TA066VVHM03 panel + driver. The panel has a 1080x2340 resolution and uses 24 bit RGB per + pixel. It provides a MIPI DSI interface to the host and has a + built-in touch controller. + config DRM_PANEL_TPO_TD028TTEC1 tristate "Toppoly (TPO) TD028TTEC1 panel driver" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index aeffaa95666d..db257778b9f1 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o obj-$(CONFIG_DRM_PANEL_STARTEK_KD070FHFID015) += panel-startek-kd070fhfid015.o obj-$(CONFIG_DRM_PANEL_TDO_TL070WSH30) += panel-tdo-tl070wsh30.o +obj-$(CONFIG_DRM_PANEL_TIANMA_TA066VVHM03) += panel-tianma-ta066vvhm03.o obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o diff --git a/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c b/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c new file mode 100644 index 000000000000..9bf0f4ab6792 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2026 Alexander Koskovich <akoskovich@pm.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/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 tianma_ta066vvhm03 { + struct regulator_bulk_data *supplies; + struct gpio_desc *enable_gpio; + struct gpio_desc *reset_gpio; + struct mipi_dsi_device *dsi; + struct drm_dsc_config dsc; + struct drm_panel panel; +}; + +static const struct regulator_bulk_data tianma_ta066vvhm03_supplies[] = { + { .supply = "vddio" }, + { .supply = "vci" }, + { .supply = "vdd" }, +}; + +static inline +struct tianma_ta066vvhm03 *to_tianma_ta066vvhm03(struct drm_panel *panel) +{ + return container_of(panel, struct tianma_ta066vvhm03, panel); +} + +static void tianma_ta066vvhm03_reset(struct tianma_ta066vvhm03 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(1000, 2000); + 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 tianma_ta066vvhm03_on(struct tianma_ta066vvhm03 *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, 0xb0, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, + 0x94, 0x42, 0x00, 0x16, 0x05, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x10, 0x00, 0xaa, 0x8a, + 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x3f, + 0x3f, 0x03, 0xff, 0x03, 0xff, 0x23, 0xff, + 0x03, 0xff, 0x23, 0xff, 0x03, 0xff, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x10, 0x01, 0x00, + 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x09, 0x24, 0x0e, 0x00, 0x00, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x2f, 0x00, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, + 0x64, 0x0b, 0x00, 0xc0, 0x02, 0xa6, 0x04, + 0x7f, 0x0b, 0x77, 0x0b, 0x8b, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x00, 0x10, 0x01, 0x68, + 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, 0x01, + 0x68, 0x01, 0x69, 0x03, 0x98, 0x03, 0x70, + 0x03, 0x70, 0x03, 0x70, 0x03, 0x70, 0x00, + 0x10, 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, + 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, 0x03, + 0x98, 0x03, 0x70, 0x03, 0x70, 0x03, 0x70, + 0x03, 0x70, 0x01, 0x42, 0x01, 0x42, 0x01, + 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x42, + 0x01, 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, + 0x42, 0x01, 0x42, 0x01, 0x42, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x00, 0x01, 0x9a, 0x01, 0x9a, + 0x01, 0x9a, 0x05, 0xae, 0x05, 0xae, 0x09, + 0xa4, 0x09, 0xa4, 0x09, 0xa4, 0x09, 0xa4, + 0x09, 0xa4, 0x09, 0xa4, 0x0f, 0xc3, 0x19); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd7, + 0x00, 0xa9, 0x34, 0x00, 0x20, 0x02, 0x00, + 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x40, + 0x09, 0x00, 0x00, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, + 0x00, 0x30, 0x00, 0x30, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x00, 0x2f, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, + 0x59, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0x4a, 0x48, 0x46, 0x44, + 0x42, 0x40, 0x3e, 0x3c, 0x3a, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x04, 0x00, 0x04, 0x04, 0x42, 0x04, + 0x69, 0x5a, 0x00, 0x0a, 0xb0, 0x0f, 0xff, + 0x0f, 0xff, 0x0f, 0xff, 0x14, 0x81, 0xf4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe8, 0x00, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe4, 0x00, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x93); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xde, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x50, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, + 0x50, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x11); + mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, + 0x01, 0x00, 0x00, 0x00, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x00, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x19); + mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x50, 0x42); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x24); + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x0437); + mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0923); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x01); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 100); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + + return dsi_ctx.accum_err; +} + +static int tianma_ta066vvhm03_off(struct tianma_ta066vvhm03 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + 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 tianma_ta066vvhm03_prepare(struct drm_panel *panel) +{ + struct tianma_ta066vvhm03 *ctx = to_tianma_ta066vvhm03(panel); + struct drm_dsc_picture_parameter_set pps; + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(tianma_ta066vvhm03_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ctx->enable_gpio, 1); + + tianma_ta066vvhm03_reset(ctx); + + ret = tianma_ta066vvhm03_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + gpiod_set_value_cansleep(ctx->enable_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(tianma_ta066vvhm03_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; + } + + return 0; +} + +static int tianma_ta066vvhm03_unprepare(struct drm_panel *panel) +{ + struct tianma_ta066vvhm03 *ctx = to_tianma_ta066vvhm03(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = tianma_ta066vvhm03_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->enable_gpio, 0); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(tianma_ta066vvhm03_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode tianma_ta066vvhm03_mode = { + .clock = (1080 + 24 + 4 + 10) * (2340 + 12 + 1 + 4) * 160 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 24, + .hsync_end = 1080 + 24 + 4, + .htotal = 1080 + 24 + 4 + 10, + .vdisplay = 2340, + .vsync_start = 2340 + 12, + .vsync_end = 2340 + 12 + 1, + .vtotal = 2340 + 12 + 1 + 4, + .width_mm = 70, + .height_mm = 152, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int tianma_ta066vvhm03_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &tianma_ta066vvhm03_mode); +} + +static const struct drm_panel_funcs tianma_ta066vvhm03_panel_funcs = { + .prepare = tianma_ta066vvhm03_prepare, + .unprepare = tianma_ta066vvhm03_unprepare, + .get_modes = tianma_ta066vvhm03_get_modes, +}; + +static int tianma_ta066vvhm03_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 tianma_ta066vvhm03_bl_ops = { + .update_status = tianma_ta066vvhm03_bl_update_status, +}; + +static struct backlight_device * +tianma_ta066vvhm03_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &tianma_ta066vvhm03_bl_ops, &props); +} + +static int tianma_ta066vvhm03_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct tianma_ta066vvhm03 *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct tianma_ta066vvhm03, panel, + &tianma_ta066vvhm03_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(tianma_ta066vvhm03_supplies), + tianma_ta066vvhm03_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ctx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), + "Failed to get enable-gpios\n"); + + 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 = tianma_ta066vvhm03_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + /* This panel only supports DSC; unconditionally enable it */ + dsi->dsc = &ctx->dsc; + dsi->dsc_slice_per_pkt = 2; + + ctx->dsc.dsc_version_major = 1; + ctx->dsc.dsc_version_minor = 1; + + ctx->dsc.slice_height = 20; + ctx->dsc.slice_width = 540; + WARN_ON(1080 % ctx->dsc.slice_width); + ctx->dsc.slice_count = 1080 / ctx->dsc.slice_width; + ctx->dsc.bits_per_component = 10; + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ + ctx->dsc.block_pred_enable = true; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void tianma_ta066vvhm03_remove(struct mipi_dsi_device *dsi) +{ + struct tianma_ta066vvhm03 *ctx = 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(&ctx->panel); +} + +static const struct of_device_id tianma_ta066vvhm03_of_match[] = { + { .compatible = "tianma,ta066vvhm03" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tianma_ta066vvhm03_of_match); + +static struct mipi_dsi_driver tianma_ta066vvhm03_driver = { + .probe = tianma_ta066vvhm03_probe, + .remove = tianma_ta066vvhm03_remove, + .driver = { + .name = "panel-tianma-ta066vvhm03", + .of_match_table = tianma_ta066vvhm03_of_match, + }, +}; +module_mipi_dsi_driver(tianma_ta066vvhm03_driver); + +MODULE_AUTHOR("Alexander Koskovich <akoskovich@pm.me>"); +MODULE_DESCRIPTION("DRM driver for Tianma TA066VVHM03-00"); +MODULE_LICENSE("GPL"); -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Claude review: drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-08 21:09 ` [PATCH v2 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich @ 2026-03-10 2:50 ` Claude Code Review Bot 0 siblings, 0 replies; 11+ messages in thread From: Claude Code Review Bot @ 2026-03-10 2:50 UTC (permalink / raw) To: dri-devel-reviews Patch Review **Issue 1 (medium): Missing cleanup in `prepare()` error paths after PPS/compression failures.** ```c 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; } ``` Both of these error paths return without disabling regulators, deasserting the enable GPIO, or asserting reset. Compare with the earlier error path after `tianma_ta066vvhm03_on()` which properly cleans up. These should do the same cleanup (or better yet, use `goto` labels for a unified error path). Additionally, note the inconsistency: the `_on()` error path uses `dev` from `&ctx->dsi->dev`, but the PPS error path uses `panel->dev`. Should be consistent — prefer `dev` since it's already a local variable. **Issue 2 (minor): Questionable LPM flag handling in `_off()`.** ```c static int tianma_ta066vvhm03_off(struct tianma_ta066vvhm03 *ctx) { ... ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); ``` This clears LPM mode before sending display-off and enter-sleep DCS commands, meaning they'll be sent in HS mode. This is unusual — most panel drivers send these in LP mode. In `_on()`, LPM is explicitly set. While this may match the vendor downstream driver behavior, it's worth double-checking whether this is intentional and required by the panel. **Issue 3 (minor): `dsc_slice_per_pkt` dependency.** ```c dsi->dsc_slice_per_pkt = 2; ``` As noted in the cover letter, this depends on an out-of-tree patch. This field doesn't exist in mainline `struct mipi_dsi_device`. The driver cannot be merged until that dependency lands. This should be clearly noted (it is in the cover letter, which is fine). **Issue 4 (minor): 160 Hz pixel clock.** ```c .clock = (1080 + 24 + 4 + 10) * (2340 + 12 + 1 + 4) * 160 / 1000, ``` This computes to `(1118 * 2357 * 160) / 1000 = 421,502` (approximately). A 160 Hz refresh rate is unusual for a phone panel — most are 60, 90, or 120 Hz. This may be correct (the ROG Phone 3 could support high refresh rates), but worth confirming this matches the actual panel specification. The `.clock` evaluates to ~421502 kHz. **Issue 5 (nit): Consider using `mipi_dsi_picture_parameter_set_multi` for consistency.** The `_on()` function uses the `_multi` pattern throughout, but `prepare()` switches to non-multi `mipi_dsi_picture_parameter_set()` and `mipi_dsi_compression_mode()`. Some newer DSC panel drivers (e.g., `panel-lg-sw43408.c`) use `mipi_dsi_picture_parameter_set_multi()` to keep the error handling pattern consistent. This would also help with the error path cleanup issue. **Positive observations:** - Correctly uses `devm_drm_panel_alloc()` (modern API). - Uses `mipi_dsi_multi_context` pattern for init sequences — good. - Uses `drm_connector_helper_get_modes_fixed()` — correct for single-mode panels. - Uses `devm_regulator_bulk_get_const()` — correct since the supply array is `const`. - DSC config looks reasonable (DSC 1.1, 10 bpc, 8 bpp, 540px slices). - `prepare_prev_first = true` is set appropriately for DSI panels. - The `WARN_ON(1080 % ctx->dsc.slice_width)` is a nice sanity check. --- Generated by Claude Code Patch Reviewer ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 0/2] Add support for Tianma TA066VVHM03 DSI panel
@ 2026-03-10 4:36 Alexander Koskovich
2026-03-10 4:36 ` [PATCH v3 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich
0 siblings, 1 reply; 11+ messages in thread
From: Alexander Koskovich @ 2026-03-10 4:36 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, Alexander Koskovich,
Krzysztof Kozlowski
Add dt-binding and driver for the Tianma TA066VVHM03 6.59" 1080x2340
AMOLED DSI panel with DSC compression, found in the ASUS ROG Phone 3.
This panel depends on slice_per_pkt support currently being reviewed:
https://lore.kernel.org/linux-arm-msm/20251001135914.13754-3-caojunjie650@gmail.com
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
Changes in v3:
- Fixed From/SoB mismatch
- Link to v2: https://lore.kernel.org/r/20260308-tianma-ta066vvhm03-v2-0-5f2344685133@pm.me
Changes in v2:
- Move additionalProperties after required block in bindings
- Link to v1: https://lore.kernel.org/r/20260308-tianma-ta066vvhm03-v1-0-869fac443b20@pm.me
---
Alexander Koskovich (2):
dt-bindings: display: panel: Document Tianma TA066VVHM03
drm/panel: Add support for Tianma TA066VVHM03 panel
.../bindings/display/panel/tianma,ta066vvhm03.yaml | 67 ++++
MAINTAINERS | 6 +
drivers/gpu/drm/panel/Kconfig | 11 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c | 387 +++++++++++++++++++++
5 files changed, 472 insertions(+)
---
base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
change-id: 20260308-tianma-ta066vvhm03-a72bd18f2b3f
Best regards,
--
Alexander Koskovich <akoskovich@pm.me>
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v3 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-10 4:36 [PATCH v3 0/2] Add support for Tianma TA066VVHM03 DSI panel Alexander Koskovich @ 2026-03-10 4:36 ` Alexander Koskovich 2026-03-11 3:40 ` Claude review: " Claude Code Review Bot 0 siblings, 1 reply; 11+ messages in thread From: Alexander Koskovich @ 2026-03-10 4:36 UTC (permalink / raw) To: Neil Armstrong, Jessica Zhang, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: dri-devel, devicetree, linux-kernel, Alexander Koskovich Add driver for the Tianma TA066VVHM03 6.59" 1080x2340 AMOLED DSI panel with DSC compression, found in the ASUS ROG Phone 3. Signed-off-by: Alexander Koskovich <akoskovich@pm.me> --- MAINTAINERS | 6 + drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c | 387 +++++++++++++++++++++++ 4 files changed, 405 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 77fdfcb55f06..06149cd65f52 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8382,6 +8382,12 @@ F: Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml F: drivers/gpu/drm/bridge/synopsys/dw-dp.c F: include/drm/bridge/dw_dp.h +DRM DRIVER FOR TIANMA TA066VVHM03 PANELS +M: Alexander Koskovich <akoskovich@pm.me> +S: Maintained +F: Documentation/devicetree/bindings/display/panel/tianma,ta066vvhm03.yaml +F: drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c + DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE M: Jagan Teki <jagan@amarulasolutions.com> S: Maintained diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 307152ad7759..c818c701bdf6 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -1122,6 +1122,17 @@ config DRM_PANEL_TDO_TL070WSH30 24 bit RGB per pixel. It provides a MIPI DSI interface to the host, a built-in LED backlight and touch controller. +config DRM_PANEL_TIANMA_TA066VVHM03 + tristate "Tianma TA066VVHM03 panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for the Tianma TA066VVHM03 panel + driver. The panel has a 1080x2340 resolution and uses 24 bit RGB per + pixel. It provides a MIPI DSI interface to the host and has a + built-in touch controller. + config DRM_PANEL_TPO_TD028TTEC1 tristate "Toppoly (TPO) TD028TTEC1 panel driver" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index aeffaa95666d..db257778b9f1 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o obj-$(CONFIG_DRM_PANEL_STARTEK_KD070FHFID015) += panel-startek-kd070fhfid015.o obj-$(CONFIG_DRM_PANEL_TDO_TL070WSH30) += panel-tdo-tl070wsh30.o +obj-$(CONFIG_DRM_PANEL_TIANMA_TA066VVHM03) += panel-tianma-ta066vvhm03.o obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o diff --git a/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c b/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c new file mode 100644 index 000000000000..9bf0f4ab6792 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-tianma-ta066vvhm03.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2026 Alexander Koskovich <akoskovich@pm.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/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 tianma_ta066vvhm03 { + struct regulator_bulk_data *supplies; + struct gpio_desc *enable_gpio; + struct gpio_desc *reset_gpio; + struct mipi_dsi_device *dsi; + struct drm_dsc_config dsc; + struct drm_panel panel; +}; + +static const struct regulator_bulk_data tianma_ta066vvhm03_supplies[] = { + { .supply = "vddio" }, + { .supply = "vci" }, + { .supply = "vdd" }, +}; + +static inline +struct tianma_ta066vvhm03 *to_tianma_ta066vvhm03(struct drm_panel *panel) +{ + return container_of(panel, struct tianma_ta066vvhm03, panel); +} + +static void tianma_ta066vvhm03_reset(struct tianma_ta066vvhm03 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(1000, 2000); + 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 tianma_ta066vvhm03_on(struct tianma_ta066vvhm03 *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, 0xb0, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf1, 0x2a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, + 0x94, 0x42, 0x00, 0x16, 0x05, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x10, 0x00, 0xaa, 0x8a, + 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x3f, + 0x3f, 0x03, 0xff, 0x03, 0xff, 0x23, 0xff, + 0x03, 0xff, 0x23, 0xff, 0x03, 0xff, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x10, 0x01, 0x00, + 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x09, 0x24, 0x0e, 0x00, 0x00, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x2f, 0x00, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, + 0x64, 0x0b, 0x00, 0xc0, 0x02, 0xa6, 0x04, + 0x7f, 0x0b, 0x77, 0x0b, 0x8b, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x00, 0x10, 0x01, 0x68, + 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, 0x01, + 0x68, 0x01, 0x69, 0x03, 0x98, 0x03, 0x70, + 0x03, 0x70, 0x03, 0x70, 0x03, 0x70, 0x00, + 0x10, 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, + 0x01, 0x68, 0x01, 0x68, 0x01, 0x68, 0x03, + 0x98, 0x03, 0x70, 0x03, 0x70, 0x03, 0x70, + 0x03, 0x70, 0x01, 0x42, 0x01, 0x42, 0x01, + 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, 0x42, + 0x01, 0x42, 0x01, 0x42, 0x01, 0x42, 0x01, + 0x42, 0x01, 0x42, 0x01, 0x42, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x00, 0x01, 0x9a, 0x01, 0x9a, + 0x01, 0x9a, 0x05, 0xae, 0x05, 0xae, 0x09, + 0xa4, 0x09, 0xa4, 0x09, 0xa4, 0x09, 0xa4, + 0x09, 0xa4, 0x09, 0xa4, 0x0f, 0xc3, 0x19); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd7, + 0x00, 0xa9, 0x34, 0x00, 0x20, 0x02, 0x00, + 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x40, + 0x09, 0x00, 0x00, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, + 0x00, 0x30, 0x00, 0x30, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x00, 0x2f, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, + 0x59, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0x4a, 0x48, 0x46, 0x44, + 0x42, 0x40, 0x3e, 0x3c, 0x3a, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x04, 0x00, 0x04, 0x04, 0x42, 0x04, + 0x69, 0x5a, 0x00, 0x0a, 0xb0, 0x0f, 0xff, + 0x0f, 0xff, 0x0f, 0xff, 0x14, 0x81, 0xf4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe8, 0x00, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe4, 0x00, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x93); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xde, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x04); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x50, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, + 0x50, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x11); + mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, + 0x01, 0x00, 0x00, 0x00, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x00, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x19); + mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xdf, 0x50, 0x42); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + 0x24); + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x0437); + mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0923); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x01); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 100); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + + return dsi_ctx.accum_err; +} + +static int tianma_ta066vvhm03_off(struct tianma_ta066vvhm03 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + 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 tianma_ta066vvhm03_prepare(struct drm_panel *panel) +{ + struct tianma_ta066vvhm03 *ctx = to_tianma_ta066vvhm03(panel); + struct drm_dsc_picture_parameter_set pps; + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(tianma_ta066vvhm03_supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ctx->enable_gpio, 1); + + tianma_ta066vvhm03_reset(ctx); + + ret = tianma_ta066vvhm03_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + gpiod_set_value_cansleep(ctx->enable_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(tianma_ta066vvhm03_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; + } + + return 0; +} + +static int tianma_ta066vvhm03_unprepare(struct drm_panel *panel) +{ + struct tianma_ta066vvhm03 *ctx = to_tianma_ta066vvhm03(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = tianma_ta066vvhm03_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->enable_gpio, 0); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(tianma_ta066vvhm03_supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode tianma_ta066vvhm03_mode = { + .clock = (1080 + 24 + 4 + 10) * (2340 + 12 + 1 + 4) * 160 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 24, + .hsync_end = 1080 + 24 + 4, + .htotal = 1080 + 24 + 4 + 10, + .vdisplay = 2340, + .vsync_start = 2340 + 12, + .vsync_end = 2340 + 12 + 1, + .vtotal = 2340 + 12 + 1 + 4, + .width_mm = 70, + .height_mm = 152, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int tianma_ta066vvhm03_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &tianma_ta066vvhm03_mode); +} + +static const struct drm_panel_funcs tianma_ta066vvhm03_panel_funcs = { + .prepare = tianma_ta066vvhm03_prepare, + .unprepare = tianma_ta066vvhm03_unprepare, + .get_modes = tianma_ta066vvhm03_get_modes, +}; + +static int tianma_ta066vvhm03_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 tianma_ta066vvhm03_bl_ops = { + .update_status = tianma_ta066vvhm03_bl_update_status, +}; + +static struct backlight_device * +tianma_ta066vvhm03_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &tianma_ta066vvhm03_bl_ops, &props); +} + +static int tianma_ta066vvhm03_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct tianma_ta066vvhm03 *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct tianma_ta066vvhm03, panel, + &tianma_ta066vvhm03_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(tianma_ta066vvhm03_supplies), + tianma_ta066vvhm03_supplies, + &ctx->supplies); + if (ret < 0) + return ret; + + ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(ctx->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), + "Failed to get enable-gpios\n"); + + 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 = tianma_ta066vvhm03_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + /* This panel only supports DSC; unconditionally enable it */ + dsi->dsc = &ctx->dsc; + dsi->dsc_slice_per_pkt = 2; + + ctx->dsc.dsc_version_major = 1; + ctx->dsc.dsc_version_minor = 1; + + ctx->dsc.slice_height = 20; + ctx->dsc.slice_width = 540; + WARN_ON(1080 % ctx->dsc.slice_width); + ctx->dsc.slice_count = 1080 / ctx->dsc.slice_width; + ctx->dsc.bits_per_component = 10; + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ + ctx->dsc.block_pred_enable = true; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void tianma_ta066vvhm03_remove(struct mipi_dsi_device *dsi) +{ + struct tianma_ta066vvhm03 *ctx = 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(&ctx->panel); +} + +static const struct of_device_id tianma_ta066vvhm03_of_match[] = { + { .compatible = "tianma,ta066vvhm03" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tianma_ta066vvhm03_of_match); + +static struct mipi_dsi_driver tianma_ta066vvhm03_driver = { + .probe = tianma_ta066vvhm03_probe, + .remove = tianma_ta066vvhm03_remove, + .driver = { + .name = "panel-tianma-ta066vvhm03", + .of_match_table = tianma_ta066vvhm03_of_match, + }, +}; +module_mipi_dsi_driver(tianma_ta066vvhm03_driver); + +MODULE_AUTHOR("Alexander Koskovich <akoskovich@pm.me>"); +MODULE_DESCRIPTION("DRM driver for Tianma TA066VVHM03-00"); +MODULE_LICENSE("GPL"); -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Claude review: drm/panel: Add support for Tianma TA066VVHM03 panel 2026-03-10 4:36 ` [PATCH v3 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich @ 2026-03-11 3:40 ` Claude Code Review Bot 0 siblings, 0 replies; 11+ messages in thread From: Claude Code Review Bot @ 2026-03-11 3:40 UTC (permalink / raw) To: dri-devel-reviews Patch Review **Issue 1 (bug): Missing cleanup in `prepare()` error paths for PPS/compression failures** When `mipi_dsi_picture_parameter_set()` or `mipi_dsi_compression_mode()` fails, the function returns without undoing the work done by `tianma_ta066vvhm03_on()` (which sends DSI commands to the panel), without deasserting the reset/enable GPIOs, and without disabling regulators. Compare with the error path after `tianma_ta066vvhm03_on()` fails just above, which correctly cleans all of these up. ```c 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; /* <-- leaks regulators, GPIOs, panel state */ } ret = mipi_dsi_compression_mode(ctx->dsi, true); if (ret < 0) { dev_err(dev, "failed to enable compression mode: %d\n", ret); return ret; /* <-- same leak */ } ``` Additionally, the `_multi` variants (`mipi_dsi_picture_parameter_set_multi` and `mipi_dsi_compression_mode_multi`) are available in the current tree. The `prepare()` function could use a multi context throughout to simplify error handling — or at minimum, the error paths need to call the same cleanup as the `_on()` failure path (reset gpio, enable gpio, regulator disable). **Issue 2 (minor): Inconsistent `dev` variable usage in `prepare()` error messages** The PPS error path uses `panel->dev` while all other error paths use the local `dev` variable: ```c dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); ``` vs: ```c dev_err(dev, "failed to enable compression mode: %d\n", ret); ``` Both refer to the same device, but using `panel->dev` here is inconsistent and unexpected. Should use `dev` for consistency. **Issue 3 (dependency): `dsc_slice_per_pkt` field does not exist upstream** ```c dsi->dsc_slice_per_pkt = 2; ``` This field doesn't exist in `struct mipi_dsi_device` in the current tree. The cover letter correctly documents this dependency on a pending patch. This will prevent the driver from compiling until that dependency is merged. This is fine as long as the maintainer is aware and merges them in the right order. **Issue 4 (minor nit): `WARN_ON` for a compile-time-knowable condition** ```c WARN_ON(1080 % ctx->dsc.slice_width); ``` Since `slice_width` is set to 540 just above, this is always false (1080 % 540 == 0). This is a runtime check for what is effectively a compile-time constant. It's harmless and used by other panel drivers (presumably a pattern from the generator), so no action strictly needed. **Observation (style): The driver closely follows the `panel-raydium-rm692e5.c` pattern** The overall structure, probe sequence, backlight handling, DSC setup, and remove function match the established patterns. The use of `devm_drm_panel_alloc`, `devm_regulator_bulk_get_const`, and `drm_connector_helper_get_modes_fixed` are all current best practices. Good. **Summary for Patch 2:** The main issue to fix is the missing cleanup in the `prepare()` error paths after PPS/compression mode failures. Consider using the `_multi` variants for PPS and compression mode to simplify the control flow and ensure consistent error handling. Also fix the `panel->dev` vs `dev` inconsistency. --- Generated by Claude Code Patch Reviewer ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-03-11 3:40 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-08 6:03 [PATCH 0/2] Add support for Tianma TA066VVHM03 DSI panel Alexander Koskovich 2026-03-08 6:03 ` [PATCH 1/2] dt-bindings: display: panel: Document Tianma TA066VVHM03 Alexander Koskovich 2026-03-08 8:43 ` Krzysztof Kozlowski 2026-03-08 21:59 ` Claude review: " Claude Code Review Bot 2026-03-08 6:03 ` [PATCH 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich 2026-03-08 14:16 ` kernel test robot 2026-03-08 14:37 ` kernel test robot 2026-03-08 21:59 ` Claude review: " Claude Code Review Bot 2026-03-08 21:59 ` Claude review: Add support for Tianma TA066VVHM03 DSI panel Claude Code Review Bot -- strict thread matches above, loose matches on Subject: below -- 2026-03-08 21:08 [PATCH v2 0/2] " Alexander Koskovich 2026-03-08 21:09 ` [PATCH v2 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich 2026-03-10 2:50 ` Claude review: " Claude Code Review Bot 2026-03-10 4:36 [PATCH v3 0/2] Add support for Tianma TA066VVHM03 DSI panel Alexander Koskovich 2026-03-10 4:36 ` [PATCH v3 2/2] drm/panel: Add support for Tianma TA066VVHM03 panel Alexander Koskovich 2026-03-11 3:40 ` Claude review: " Claude Code Review Bot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox