* [PATCH 0/2] drm/panel: Add support for Samsung AMS662ZS01 panel
@ 2026-09-07 11:51 Vsevolod Nevorotov
2026-09-07 11:51 ` [PATCH 1/2] dt-bindings: display: panel: Add Samsung AMS662ZS01 Vsevolod Nevorotov
2026-09-07 11:51 ` [PATCH 2/2] drm/panel: Add Samsung AMS662ZS01 panel driver Vsevolod Nevorotov
0 siblings, 2 replies; 5+ messages in thread
From: Vsevolod Nevorotov @ 2026-09-07 11:51 UTC (permalink / raw)
To: neil.armstrong, robh, krzk+dt
Cc: jesszhan0024, conor+dt, airlied, simona, mripard, tzimmermann,
maarten.lankhorst, dri-devel, devicetree, linux-kernel,
Vsevolod Nevorotov
This series adds Device Tree bindings and a DRM panel driver for the
Samsung AMS662ZS01 FHD+ AMOLED panel found in the OnePlus 9RT (martini).
Vsevolod Nevorotov (2):
dt-bindings: display: panel: Add Samsung AMS662ZS01
drm/panel: Add Samsung AMS662ZS01 panel driver
.../display/panel/samsung,ams662zs01.yaml | 75 ++++
drivers/gpu/drm/panel/Kconfig | 13 +
drivers/gpu/drm/panel/Makefile | 1 +
.../gpu/drm/panel/panel-samsung-ams662zs01.c | 398 ++++++++++++++++++
4 files changed, 487 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml
create mode 100644 drivers/gpu/drm/panel/panel-samsung-ams662zs01.c
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] dt-bindings: display: panel: Add Samsung AMS662ZS01
2026-09-07 11:51 [PATCH 0/2] drm/panel: Add support for Samsung AMS662ZS01 panel Vsevolod Nevorotov
@ 2026-09-07 11:51 ` Vsevolod Nevorotov
2026-09-07 12:01 ` sashiko-bot
2026-09-07 11:51 ` [PATCH 2/2] drm/panel: Add Samsung AMS662ZS01 panel driver Vsevolod Nevorotov
1 sibling, 1 reply; 5+ messages in thread
From: Vsevolod Nevorotov @ 2026-09-07 11:51 UTC (permalink / raw)
To: neil.armstrong, robh, krzk+dt
Cc: jesszhan0024, conor+dt, airlied, simona, mripard, tzimmermann,
maarten.lankhorst, dri-devel, devicetree, linux-kernel,
Vsevolod Nevorotov
Add Device Tree binding documentation for the Samsung AMS662ZS01
FHD+ AMOLED DSI panel found in the OnePlus 9RT smartphone.
Signed-off-by: Vsevolod Nevorotov <sevanevorotov29@gmail.com>
---
.../display/panel/samsung,ams662zs01.yaml | 75 +++++++++++++++++++
1 file changed, 75 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml b/Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml
new file mode 100644
index 00000000000..b2697d140ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/samsung,ams662zs01.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung AMS662ZS01 DSI Display Panel
+
+maintainers:
+ - Vsevolod Nevorotov <sevanevorotov29@gmail.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ const: samsung,ams662zs01
+
+ reg:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ vout-gpios:
+ maxItems: 1
+ description: Panel VOUT enable GPIO line
+
+ vddio-supply:
+ description: 1.8V I/O power supply
+
+ vdd-supply:
+ description: 3.0V core power supply
+
+ port: true
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+ - vddio-supply
+ - vdd-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "samsung,ams662zs01";
+ reg = <0>;
+
+ reset-gpios = <&tlmm 24 GPIO_ACTIVE_LOW>;
+ vout-gpios = <&tlmm 25 GPIO_ACTIVE_HIGH>;
+
+ vddio-supply = <&vreg_l12c_1p8>;
+ vdd-supply = <&vreg_l13c_3p0>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&mdp_vsync_active>;
+ pinctrl-1 = <&mdp_vsync_active>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&mdss_dsi0_out>;
+ };
+ };
+ };
+ };
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] drm/panel: Add Samsung AMS662ZS01 panel driver
2026-09-07 11:51 [PATCH 0/2] drm/panel: Add support for Samsung AMS662ZS01 panel Vsevolod Nevorotov
2026-09-07 11:51 ` [PATCH 1/2] dt-bindings: display: panel: Add Samsung AMS662ZS01 Vsevolod Nevorotov
@ 2026-09-07 11:51 ` Vsevolod Nevorotov
2026-09-07 12:12 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Vsevolod Nevorotov @ 2026-09-07 11:51 UTC (permalink / raw)
To: neil.armstrong, robh, krzk+dt
Cc: jesszhan0024, conor+dt, airlied, simona, mripard, tzimmermann,
maarten.lankhorst, dri-devel, devicetree, linux-kernel,
Vsevolod Nevorotov
Add support for the Samsung AMS662ZS01 AMOLED display panel used in the
OnePlus 9RT (martini) smartphone.
The panel operates in Command Mode with DSC (Display Stream Compression)
enabled at 1080x2400 resolution at 60Hz.
Signed-off-by: Vsevolod Nevorotov <sevanevorotov29@gmail.com>
---
drivers/gpu/drm/panel/Kconfig | 13 +
drivers/gpu/drm/panel/Makefile | 1 +
.../gpu/drm/panel/panel-samsung-ams662zs01.c | 398 ++++++++++++++++++
3 files changed, 412 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-samsung-ams662zs01.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index cbdf7b8f7f7..c94116ca42c 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -904,6 +904,19 @@ config DRM_PANEL_SAMSUNG_AMS639RQ08
Say Y or M here if you want to enable support for the
Samsung AMS639RQ08 FHD Plus (2340x1080@60Hz) CMD mode panel.
+config DRM_PANEL_SAMSUNG_AMS662ZS01
+ tristate "Samsung AMS662ZS01 panel"
+ depends on GPIOLIB && OF && REGULATOR
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_HELPER
+ select DRM_DISPLAY_DSC_HELPER
+ help
+ Say Y or M here if you want to enable support for the
+ Samsung AMS662ZS01 FHD Plus (1080x2400@60Hz) DSC CMD mode panel.
+ This panel is connected via MIPI DSI interface and is
+ primarily found in the OnePlus 9RT smartphone.
+
config DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24
tristate "Samsung AMS427AP24 panel with S6E88A0 controller"
depends on GPIOLIB && OF && REGULATOR
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 3b523cf3783..fc5cfc4dd6b 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_DRM_PANEL_RENESAS_R69328) += panel-renesas-r69328.o
obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_AMS581VF01) += panel-samsung-ams581vf01.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_AMS639RQ08) += panel-samsung-ams639rq08.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_AMS662ZS01) += panel-samsung-ams662zs01.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
diff --git a/drivers/gpu/drm/panel/panel-samsung-ams662zs01.c b/drivers/gpu/drm/panel/panel-samsung-ams662zs01.c
new file mode 100644
index 00000000000..52e7e75c08b
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-ams662zs01.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Samsung AMS662ZS01 6.62" 1080x2400 AMOLED DSI command-mode panel with DSC.
+ *
+ * Found on the OnePlus 9RT (oneplus,martini). Both panel revisions the vendor
+ * tree carries -- "samsung ams662zs01 fhd cmd mode dsc dsi panel" and its
+ * dvt respin, which the martini bootloader hands off as
+ * msm_drm.dsi_display0=qcom,mdss_dsi_samsung_ams662zs01_dvt_dsc_cmd -- share
+ * one initialisation sequence and one set of timings; the revisions differ only
+ * in the HBM/fingerprint brightness tables, which this driver does not use.
+ *
+ * Command sequences and timings transcribed from
+ * arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-samsung_ams662zs01_dvt_dsc_cmd.dtsi
+ * in the vendor kernel (timing0, the 60 Hz mode).
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.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>
+
+#include <video/mipi_display.h>
+
+/*
+ * Samsung DDIC vendor commands. The PPS is written as a DCS long write of the
+ * 128-byte payload rather than as a MIPI PPS (0x0a) packet, and compression is
+ * armed by a DCS register write rather than by a MIPI compression-mode (0x07)
+ * packet -- that is what the vendor sequence does on this DDIC, so it is what
+ * is known to work here.
+ */
+#define AMS662ZS01_DCS_WRITE_PPS 0x9e
+#define AMS662ZS01_DCS_COMPRESSION_MODE 0x9d
+#define AMS662ZS01_DCS_ACCESS_KEY 0xf0
+#define AMS662ZS01_DCS_FREQ_SELECT 0x60
+#define AMS662ZS01_DCS_GAMMA_UPDATE 0xf7
+
+/* Payloads of AMS662ZS01_DCS_FREQ_SELECT, from the per-timing switch commands. */
+#define AMS662ZS01_FREQ_60HZ 0x00
+#define AMS662ZS01_FREQ_120HZ 0x08
+
+struct ams662zs01 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct drm_dsc_config dsc;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *vout_gpio;
+ struct regulator_bulk_data *supplies;
+};
+
+/*
+ * vddio is pm8350c L12C at 1.8 V, vdd is pm8350c L13C at 3.0-3.2 V. The vendor
+ * tree wires both through the DSI controller node (display/lahaina-sde-display.dtsi)
+ * and lists them as the panel's supply entries; lab/ibb are commented out on
+ * oplus builds, so the pm8350b AMOLED AB/IBB regulators are not involved and
+ * need no driver here.
+ */
+static const struct regulator_bulk_data ams662zs01_supplies[] = {
+ { .supply = "vddio" },
+ { .supply = "vdd" },
+};
+
+static inline struct ams662zs01 *to_ams662zs01(struct drm_panel *panel)
+{
+ return container_of(panel, struct ams662zs01, panel);
+}
+
+/*
+ * qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>: the pin idles high,
+ * is pulled low for 10 ms and released. reset-gpios is active-low, so the
+ * logical values run the other way round.
+ */
+static void ams662zs01_reset(struct ams662zs01 *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+}
+
+/* The 0xf0 key gates every vendor register touched below. */
+#define ams662zs01_unlock(dsi_ctx) \
+ mipi_dsi_dcs_write_seq_multi((dsi_ctx), AMS662ZS01_DCS_ACCESS_KEY, 0x5a, 0x5a)
+#define ams662zs01_lock(dsi_ctx) \
+ mipi_dsi_dcs_write_seq_multi((dsi_ctx), AMS662ZS01_DCS_ACCESS_KEY, 0xa5, 0xa5)
+
+/*
+ * The payload is built at run time rather than with
+ * mipi_dsi_dcs_write_seq_multi(): that macro stores its arguments in a
+ * "static const u8" array, so every one of them has to be a compile-time
+ * constant and a variable freq does not compile.
+ */
+static void ams662zs01_set_freq(struct mipi_dsi_multi_context *dsi_ctx, u8 freq)
+{
+ const u8 freq_select[] = { AMS662ZS01_DCS_FREQ_SELECT, freq, 0x00 };
+
+ ams662zs01_unlock(dsi_ctx);
+ mipi_dsi_dcs_write_buffer_multi(dsi_ctx, freq_select, sizeof(freq_select));
+ mipi_dsi_dcs_write_seq_multi(dsi_ctx, AMS662ZS01_DCS_GAMMA_UPDATE, 0x0f);
+ ams662zs01_lock(dsi_ctx);
+}
+
+static void ams662zs01_send_pps(struct mipi_dsi_multi_context *dsi_ctx,
+ const struct drm_dsc_config *dsc)
+{
+ struct drm_dsc_picture_parameter_set pps;
+ u8 buf[1 + sizeof(pps)];
+
+ drm_dsc_pps_payload_pack(&pps, dsc);
+
+ buf[0] = AMS662ZS01_DCS_WRITE_PPS;
+ memcpy(&buf[1], &pps, sizeof(pps));
+
+ mipi_dsi_dcs_write_buffer_multi(dsi_ctx, buf, sizeof(buf));
+}
+
+static int ams662zs01_prepare(struct drm_panel *panel)
+{
+ struct ams662zs01 *ctx = to_ams662zs01(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ dsi_ctx.accum_err = regulator_bulk_enable(ARRAY_SIZE(ams662zs01_supplies),
+ ctx->supplies);
+ if (dsi_ctx.accum_err)
+ return dsi_ctx.accum_err;
+
+ /*
+ * Panel VOUT enable (tlmm 25). The vendor driver raises it right after
+ * the rails and the pinctrl state, and drops it in power-off
+ * (techpack/display/msm/dsi/dsi_panel.c, panel_vout_gpio).
+ */
+ gpiod_set_value_cansleep(ctx->vout_gpio, 1);
+ usleep_range(1000, 2000);
+
+ ams662zs01_reset(ctx);
+
+ /*
+ * ctx->dsc is filled in by the DSI host: dsi_timing_setup() runs
+ * dsi_populate_dsc_params() on the panel's config before the panel is
+ * prepared (panel.prepare_prev_first), so the rate-control parameters
+ * the PPS carries are computed by then.
+ */
+ ams662zs01_send_pps(&dsi_ctx, ctx->dsi->dsc);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x14);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, AMS662ZS01_DCS_COMPRESSION_MODE, 0x01);
+
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 128);
+
+ mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+ mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0, 1080 - 1);
+ mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0, 2400 - 1);
+
+ /* FQ CON: pick the fixed-frequency (non-adaptive) frame rate path. */
+ ams662zs01_unlock(&dsi_ctx);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x27, 0xf2);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf2, 0x00);
+ ams662zs01_lock(&dsi_ctx);
+
+ ams662zs01_set_freq(&dsi_ctx, AMS662ZS01_FREQ_60HZ);
+
+ /* Brightness control on, dimming off. */
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
+
+ if (dsi_ctx.accum_err) {
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ gpiod_set_value_cansleep(ctx->vout_gpio, 0);
+ regulator_bulk_disable(ARRAY_SIZE(ams662zs01_supplies),
+ ctx->supplies);
+ }
+
+ return dsi_ctx.accum_err;
+}
+
+static int ams662zs01_enable(struct drm_panel *panel)
+{
+ struct ams662zs01 *ctx = to_ams662zs01(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+
+ return dsi_ctx.accum_err;
+}
+
+static int ams662zs01_disable(struct drm_panel *panel)
+{
+ struct ams662zs01 *ctx = to_ams662zs01(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ /* Leave AOD, in case the panel was put there behind our back. */
+ ams662zs01_unlock(&dsi_ctx);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
+ ams662zs01_lock(&dsi_ctx);
+
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 11);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 121);
+
+ return dsi_ctx.accum_err;
+}
+
+static int ams662zs01_unprepare(struct drm_panel *panel)
+{
+ struct ams662zs01 *ctx = to_ams662zs01(panel);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ gpiod_set_value_cansleep(ctx->vout_gpio, 0);
+
+ regulator_bulk_disable(ARRAY_SIZE(ams662zs01_supplies), ctx->supplies);
+
+ return 0;
+}
+
+/*
+ * timing0 of the vendor panel node: 60 Hz, hfp 64 / hpw 8 / hbp 48,
+ * vfp 8 / vpw 4 / vbp 12.
+ *
+ * The 120 Hz timing1 (hfp 8 / hpw 24 / hbp 8, vfp 2 / vpw 2 / vbp 8) is
+ * deliberately not advertised. Switching rate on this DDIC needs its
+ * AMS662ZS01_DCS_FREQ_SELECT payload changed to AMS662ZS01_FREQ_120HZ in the
+ * same breath as the CRTC timing, and drm_panel_funcs has no mode_set hook to
+ * hang that off, so a second mode would give DPU 120 Hz timings while the panel
+ * stayed at 60.
+ */
+static const struct drm_display_mode ams662zs01_mode = {
+ .clock = (1080 + 64 + 8 + 48) * (2400 + 8 + 4 + 12) * 60 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 64,
+ .hsync_end = 1080 + 64 + 8,
+ .htotal = 1080 + 64 + 8 + 48,
+ .vdisplay = 2400,
+ .vsync_start = 2400 + 8,
+ .vsync_end = 2400 + 8 + 4,
+ .vtotal = 2400 + 8 + 4 + 12,
+ .width_mm = 70,
+ .height_mm = 153,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int ams662zs01_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ return drm_connector_helper_get_modes_fixed(connector, &ams662zs01_mode);
+}
+
+static const struct drm_panel_funcs ams662zs01_panel_funcs = {
+ .prepare = ams662zs01_prepare,
+ .enable = ams662zs01_enable,
+ .disable = ams662zs01_disable,
+ .unprepare = ams662zs01_unprepare,
+ .get_modes = ams662zs01_get_modes,
+};
+
+static int ams662zs01_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);
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ return ret;
+}
+
+static const struct backlight_ops ams662zs01_bl_ops = {
+ .update_status = ams662zs01_bl_update_status,
+};
+
+/*
+ * qcom,mdss-dsi-bl-max-level = <4095>, default level 1600. The DDIC takes the
+ * 12-bit value as a big-endian 16-bit DCS 0x51 payload, which is what
+ * mipi_dsi_dcs_set_display_brightness_large() emits.
+ */
+static struct backlight_device *ams662zs01_create_backlight(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct backlight_properties props = {
+ .type = BACKLIGHT_RAW,
+ .brightness = 1600,
+ .max_brightness = 4095,
+ };
+
+ return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
+ &ams662zs01_bl_ops, &props);
+}
+
+static int ams662zs01_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct ams662zs01 *ctx;
+ int ret;
+
+ ctx = devm_drm_panel_alloc(dev, struct ams662zs01, panel,
+ &ams662zs01_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(ams662zs01_supplies),
+ ams662zs01_supplies, &ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ ctx->vout_gpio = devm_gpiod_get(dev, "vout", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->vout_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->vout_gpio),
+ "Failed to get vout-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 |
+ MIPI_DSI_MODE_LPM;
+
+ ctx->panel.prepare_prev_first = true;
+
+ ctx->panel.backlight = ams662zs01_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);
+
+ /*
+ * DSC 1.1, two 540x30 slices per line, 8 bpc, 8 bpp -- 3:1 against the
+ * 24 bpp source. The panel has no uncompressed mode.
+ */
+ dsi->dsc = &ctx->dsc;
+ ctx->dsc.dsc_version_major = 1;
+ ctx->dsc.dsc_version_minor = 1;
+ ctx->dsc.slice_height = 30;
+ ctx->dsc.slice_width = 540;
+ ctx->dsc.slice_count = 1080 / 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;
+
+ 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 ams662zs01_remove(struct mipi_dsi_device *dsi)
+{
+ struct ams662zs01 *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 ams662zs01_of_match[] = {
+ { .compatible = "samsung,ams662zs01" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ams662zs01_of_match);
+
+static struct mipi_dsi_driver ams662zs01_driver = {
+ .probe = ams662zs01_probe,
+ .remove = ams662zs01_remove,
+ .driver = {
+ .name = "panel-samsung-ams662zs01",
+ .of_match_table = ams662zs01_of_match,
+ },
+};
+module_mipi_dsi_driver(ams662zs01_driver);
+
+MODULE_DESCRIPTION("DRM driver for the Samsung AMS662ZS01 DSC command-mode panel");
+MODULE_LICENSE("GPL");
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] dt-bindings: display: panel: Add Samsung AMS662ZS01
2026-09-07 11:51 ` [PATCH 1/2] dt-bindings: display: panel: Add Samsung AMS662ZS01 Vsevolod Nevorotov
@ 2026-09-07 12:01 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-07 12:01 UTC (permalink / raw)
To: Vsevolod Nevorotov; +Cc: conor+dt, devicetree, robh, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] The binding introduces a custom `vout-gpios` property instead of using a standard property or a regulator node.
- [Low] The device tree example assigns the exact same active pinctrl state to both the default and sleep states.
--
commit 35f05d4d7ea0faa656ae9f5edd021117b1b534c6
Author: Vsevolod Nevorotov <sevanevorotov29@gmail.com>
dt-bindings: display: panel: Add Samsung AMS662ZS01
Add Device Tree binding documentation for the Samsung AMS662ZS01
FHD+ AMOLED DSI panel found in the OnePlus 9RT smartphone.
> diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml b/Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml
> new file mode 100644
> index 0000000000000..b2697d140edef
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/samsung,ams662zs01.yaml
[ ... ]
> + reset-gpios:
> + maxItems: 1
> +
> + vout-gpios:
> + maxItems: 1
> + description: Panel VOUT enable GPIO line
[Severity: Low]
Is a custom vout-gpios property required here?
Using custom GPIO properties for standard panel functionality like power
enabling fragments the device tree ABI and prevents the use of generic
driver infrastructure.
Could this be modeled with standard paradigms instead, such as
enable-gpios or a regulator-fixed node?
> +
> + vddio-supply:
> + description: 1.8V I/O power supply
[ ... ]
> + vddio-supply = <&vreg_l12c_1p8>;
> + vdd-supply = <&vreg_l13c_3p0>;
> +
> + pinctrl-names = "default", "sleep";
> + pinctrl-0 = <&mdp_vsync_active>;
> + pinctrl-1 = <&mdp_vsync_active>;
[Severity: Low]
Should the sleep state use a different pin configuration?
The example assigns the exact same active pinctrl state (&mdp_vsync_active) to
both the default and sleep states.
Since device tree examples are frequently copied verbatim into production
device trees by developers, using the active pin configuration for the
sleep state defeats power management and can lead to increased power
leakage during system suspend.
> +
> + port {
> + panel_in: endpoint {
> + remote-endpoint = <&mdss_dsi0_out>;
> + };
> + };
> + };
> + };
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907115130.95394-1-sevanevorotov29@gmail.com?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] drm/panel: Add Samsung AMS662ZS01 panel driver
2026-09-07 11:51 ` [PATCH 2/2] drm/panel: Add Samsung AMS662ZS01 panel driver Vsevolod Nevorotov
@ 2026-09-07 12:12 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-07 12:12 UTC (permalink / raw)
To: Vsevolod Nevorotov; +Cc: robh, dri-devel, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Panel reset GPIO is initialized to physical HIGH while regulators are off, causing hardware back-powering.
- [Medium] Data race on shared `dsi->mode_flags` due to non-atomic modification in sysfs backlight update callback.
- [Medium] The backlight sysfs interface issues DSI transfers to an unpowered panel.
--
commit df8bf199977cc597d9cc38caadd2457c9f44d341
Author: Vsevolod Nevorotov <sevanevorotov29@gmail.com>
drm/panel: Add Samsung AMS662ZS01 panel driver
Add support for the Samsung AMS662ZS01 AMOLED display panel used in the
OnePlus 9RT (martini) smartphone.
The panel operates in Command Mode with DSC (Display Stream Compression)
enabled at 1080x2400 resolution at 60Hz.
> diff --git a/drivers/gpu/drm/panel/panel-samsung-ams662zs01.c b/drivers/gpu/drm/panel/panel-samsung-ams662zs01.c
> new file mode 100644
> index 0000000000000..52e7e75c08b13
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-samsung-ams662zs01.c
> [ ... ]
> @@ -267,11 +267,10 @@ static int ams662zs01_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);
> dsi->mode_flags |= MIPI_DSI_MODE_LPM;
[Severity: Medium]
Could this create a data race on dsi->mode_flags?
The backlight subsystem uses bl->update_lock while DRM uses
drm_modeset_lock, providing no mutual exclusion between these paths. A
concurrent sysfs write to the backlight brightness node during
ams662zs01_prepare() could race on dsi->mode_flags. This might cause
display initialization commands to be sent in the wrong power mode.
[Severity: Medium]
Does this function lack a check to ensure the panel is prepared and powered
on before attempting DSI communication?
If userspace writes to the backlight sysfs node while the panel is
unprepared (screen off or system suspended), this unconditionally sends DCS
commands. Attempting a DSI transfer while the panel's regulators are
disabled could cause hardware timeouts, bus errors, or host driver failures.
>
> return ret;
> }
> [ ... ]
> @@ -311,9 +310,10 @@ static int ams662zs01_probe(struct mipi_dsi_device *dsi)
> if (IS_ERR(ctx))
> return PTR_ERR(ctx);
>
> ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(ams662zs01_supplies),
> ams662zs01_supplies, &ctx->supplies);
> if (ret < 0)
> return ret;
>
> ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
[Severity: High]
Does this initialize the active-low reset GPIO to physical HIGH before the
panel's regulators are turned on?
Calling devm_gpiod_get() with GPIOD_OUT_LOW on an active-low GPIO
immediately drives the pin physically HIGH. Driving the reset GPIO high
while the panel's main power rails (VDDIO/VDD) are off could forward-bias
the ESD protection diodes inside the panel driver IC. This back-powers the
IC logic domain, which might cause permanent hardware damage or latch-up
preventing panel initialization.
> if (IS_ERR(ctx->reset_gpio))
> return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
> "Failed to get reset-gpios\n");
> [ ... ]
> @@ -330,9 +330,10 @@ static int ams662zs01_probe(struct mipi_dsi_device *dsi)
> dsi->format = MIPI_DSI_FMT_RGB888;
> dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET |
> MIPI_DSI_CLOCK_NON_CONTINUOUS |
> MIPI_DSI_MODE_LPM;
>
> ctx->panel.prepare_prev_first = true;
>
> ctx->panel.backlight = ams662zs01_create_backlight(dsi);
> if (IS_ERR(ctx->panel.backlight))
> return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
> "Failed to create backlight\n");
[Severity: Medium]
Is it safe to expose the backlight sysfs interface here before the DSI
device is attached to the host?
Because the backlight device is registered here, it is exposed to userspace
while the panel is unprepared and before mipi_dsi_attach() is called. This
makes the unprotected DSI transfers in ams662zs01_bl_update_status()
reachable immediately, even while the panel is suspended.
>
> drm_panel_add(&ctx->panel);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907115130.95394-1-sevanevorotov29@gmail.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-08 7:09 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 11:51 [PATCH 0/2] drm/panel: Add support for Samsung AMS662ZS01 panel Vsevolod Nevorotov
2026-09-07 11:51 ` [PATCH 1/2] dt-bindings: display: panel: Add Samsung AMS662ZS01 Vsevolod Nevorotov
2026-09-07 12:01 ` sashiko-bot
2026-09-07 11:51 ` [PATCH 2/2] drm/panel: Add Samsung AMS662ZS01 panel driver Vsevolod Nevorotov
2026-09-07 12:12 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox