devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] Support Kingdisplay kd101ne3 and Starry er88577 MIPI-DSI panel
@ 2024-06-01  8:45 Zhaoxiong Lv
  2024-06-01  8:45 ` [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support Zhaoxiong Lv
                   ` (3 more replies)
  0 siblings, 4 replies; 21+ messages in thread
From: Zhaoxiong Lv @ 2024-06-01  8:45 UTC (permalink / raw)
  To: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel, Zhaoxiong Lv

Kingdisplay kd101ne3 and Starry er88577 both 10.1" WXGA TFT LCD panel,
And the two panels have the same timing, so add compatible for Kingdisplay 
kd101ne3 and Starry er88577 in dt-bindings and drivers.

Changes in v2:
- PATCH 1/4: Delete some unnecessary information.
- PATCH 2/4: Use the new mipi_dsi_dcs_write_seq_multi() function, deleted some unnecessary functions.
- PATCH 3/4: Add compatible for Starry-er88577.
- PATCH 4/4: Add starry panel configuration in panel-kingdisplay-kd101ne3 driver.
- Link to v1: https://lore.kernel.org/all/20240418081548.12160-1-lvzhaoxiong@huaqin.corp-partner.google.com/

Zhaoxiong Lv (4):
  dt-bindings: display: panel: Add KD101NE3-40TI support
  drm/panel: kd101ne3: add new panel driver
  dt-bindings: display: panel: Add compatible for Starry-er88577
  drm/panel: starry: add new panel driver

 .../panel/kingdisplay,kd101ne3-40ti.yaml      |  60 ++
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-kingdisplay-kd101ne3.c    | 625 ++++++++++++++++++
 4 files changed, 695 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
 create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c

-- 
2.17.1


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

* [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support
  2024-06-01  8:45 [PATCH v2 0/4] Support Kingdisplay kd101ne3 and Starry er88577 MIPI-DSI panel Zhaoxiong Lv
@ 2024-06-01  8:45 ` Zhaoxiong Lv
  2024-06-01 15:40   ` Krzysztof Kozlowski
  2024-06-01 16:27   ` Dmitry Baryshkov
  2024-06-01  8:45 ` [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver Zhaoxiong Lv
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 21+ messages in thread
From: Zhaoxiong Lv @ 2024-06-01  8:45 UTC (permalink / raw)
  To: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel, Zhaoxiong Lv

Create a new dt-scheam for the kd101ne3-40ti.
The bias IC of this kindisplay-kd101ne3 panel is placed
on the panel side, so when the panel is powered on,
there is no need to control AVDD and AVEE in the driver.

Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
---

Chage since V2:

-  Drop some properties that have already been defined in panel-common.
-  The header file 'dt-bindings/gpio/gpio.h' is not used, delete it

V1: https://lore.kernel.org/all/20240418081548.12160-2-lvzhaoxiong@huaqin.corp-partner.google.com/

---
 .../panel/kingdisplay,kd101ne3-40ti.yaml      | 59 +++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml

diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
new file mode 100644
index 000000000000..b0cf12bb727d
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/kingdisplay,kd101ne3-40ti.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Kingdisplay KD101NE3-40TI based MIPI-DSI panels
+
+maintainers:
+  - Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - kingdisplay,kd101ne3-40ti
+
+  reg:
+    description: the virtual channel number of a DSI peripheral
+
+  pp3300-supply:
+    description: core voltage supply
+
+required:
+  - compatible
+  - reg
+  - pp3300-supply
+  - enable-gpios
+  - backlight
+  - port
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        panel: panel@0 {
+            compatible = "kingdisplay,kd101ne3-40ti";
+            reg = <0>;
+            enable-gpios = <&pio 98 0>;
+            pinctrl-names = "default";
+            pinctrl-0 = <&panel_pins_default>;
+            pp3300-supply = <&en_pp6000_mipi_disp>;
+            backlight = <&backlight_lcd0>;
+            rotation = <90>;
+            port {
+                panel_in: endpoint {
+                    remote-endpoint = <&dsi_out>;
+                };
+            };
+        };
+    };
+
+...
-- 
2.17.1


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

* [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-01  8:45 [PATCH v2 0/4] Support Kingdisplay kd101ne3 and Starry er88577 MIPI-DSI panel Zhaoxiong Lv
  2024-06-01  8:45 ` [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support Zhaoxiong Lv
@ 2024-06-01  8:45 ` Zhaoxiong Lv
  2024-06-01 16:23   ` Dmitry Baryshkov
  2024-06-02  5:07   ` Alex Bee
  2024-06-01  8:45 ` [PATCH v2 3/4] dt-bindings: display: panel: Add compatible for Starry-er88577 Zhaoxiong Lv
  2024-06-01  8:45 ` [PATCH v2 4/4] drm/panel: starry: add new panel driver Zhaoxiong Lv
  3 siblings, 2 replies; 21+ messages in thread
From: Zhaoxiong Lv @ 2024-06-01  8:45 UTC (permalink / raw)
  To: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel, Zhaoxiong Lv

The bias IC of this kindisplay-kd101ne3 panel is placed
on the panel side, so when the panel is powered on,
there is no need to control AVDD and AVEE in the driver,
only 3.3v and reset are needed.

Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
---

Chage since V2:

-  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
-  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
-  and drop kingdisplay_panel_enter_sleep_mode().
-  3. If prepare fails, disable GPIO before regulators.
-  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
-  5. Drop ".shutdown = kingdisplay_panel_shutdown".

---
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
 3 files changed, 543 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index e54f6f5604ed..71669e990e8e 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
 	  24 bit RGB per pixel. It provides a MIPI DSI interface to
 	  the host and has a built-in LED backlight.
 
+config DRM_PANEL_KINGDISPLAY_KD101NE3
+	tristate "Kingdisplay kd101ne3 panel"
+	depends on OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here if you want to enable support for the kingdisplay kd101ne3
+	  4-lane 800x1280 MIPI DSI panel.
+
 config DRM_PANEL_LEADTEK_LTK050H3146W
 	tristate "Leadtek LTK050H3146W panel"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index f0203f6e02f4..4576c9fe33d9 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
 obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
 obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
 obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
+obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
 obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
 obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
 obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
new file mode 100644
index 000000000000..8994a1c9afb5
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Panels based on the JD9365DA display controller.
+ * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+struct kingdisplay_panel;
+
+struct panel_desc {
+	const struct drm_display_mode *modes;
+	unsigned int bpc;
+
+	/**
+	 * @width_mm: width of the panel's active display area
+	 * @height_mm: height of the panel's active display area
+	 */
+	struct {
+		unsigned int width_mm;
+		unsigned int height_mm;
+	} size;
+
+	unsigned long mode_flags;
+	enum mipi_dsi_pixel_format format;
+	const struct panel_init_cmd *init_cmds;
+	int (*init)(struct kingdisplay_panel *kingdisplay);
+	unsigned int lanes;
+	bool discharge_on_disable;
+	bool lp11_before_reset;
+};
+
+struct kingdisplay_panel {
+	struct drm_panel base;
+	struct mipi_dsi_device *dsi;
+
+	const struct panel_desc *desc;
+
+	enum drm_panel_orientation orientation;
+	struct regulator *pp3300;
+	struct gpio_desc *enable_gpio;
+};
+
+static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
+{
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
+
+	/* T5:HWreset to init_code >= 50ms */
+	msleep(50);
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
+	if (dsi_ctx.accum_err)
+		return dsi_ctx.accum_err;
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+	if (dsi_ctx.accum_err)
+		return dsi_ctx.accum_err;
+
+	msleep(120);
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
+	if (dsi_ctx.accum_err)
+		return dsi_ctx.accum_err;
+
+	msleep(20);
+
+	return 0;
+};
+
+static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
+{
+	return container_of(panel, struct kingdisplay_panel, base);
+}
+
+static int kingdisplay_panel_disable(struct drm_panel *panel)
+{
+	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+	int err;
+
+	kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+	msleep(100);
+
+	err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
+	if (err < 0)
+		dev_err(panel->dev, "failed to set display off: %d\n", err);
+
+	msleep(50);
+
+	err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
+	if (err < 0) {
+		dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
+		return err;
+	}
+
+	msleep(120);
+
+	return 0;
+}
+
+static int kingdisplay_panel_unprepare(struct drm_panel *panel)
+{
+	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+	int err;
+
+	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
+
+	/* T15: 2ms */
+	usleep_range(1000, 2000);
+
+	err = regulator_disable(kingdisplay->pp3300);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int kingdisplay_panel_prepare(struct drm_panel *panel)
+{
+	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+	int err;
+
+	gpiod_set_value(kingdisplay->enable_gpio, 0);
+
+	err = regulator_enable(kingdisplay->pp3300);
+	if (err < 0)
+		return err;
+
+	/* T1:Vdd to mipi_lp >= 0ms */
+	usleep_range(5000, 6000);
+
+	if (kingdisplay->desc->lp11_before_reset) {
+		err = mipi_dsi_dcs_nop(kingdisplay->dsi);
+		if (err < 0)
+			goto poweroff;
+
+		usleep_range(1000, 2000);
+	}
+
+	/* T2: 10ms, T1 + T2 > 60ms */
+	msleep(60);
+
+	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
+
+	err = kingdisplay->desc->init(kingdisplay);
+	if (err < 0)
+		goto poweroff;
+
+	return 0;
+
+poweroff:
+	gpiod_set_value(kingdisplay->enable_gpio, 0);
+		/* T6: 2ms */
+	usleep_range(1000, 2000);
+	regulator_disable(kingdisplay->pp3300);
+
+	return err;
+}
+
+static int kingdisplay_panel_enable(struct drm_panel *panel)
+{
+	msleep(130);
+	return 0;
+}
+
+static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
+	.clock = 70595,
+	.hdisplay = 800,
+	.hsync_start = 800 + 30,
+	.hsync_end = 800 + 30 + 30,
+	.htotal = 800 + 30 + 30 + 30,
+	.vdisplay = 1280,
+	.vsync_start = 1280 + 30,
+	.vsync_end = 1280 + 30 + 4,
+	.vtotal = 1280 + 30 + 4 + 8,
+	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
+	.modes = &kingdisplay_kd101ne3_40ti_default_mode,
+	.bpc = 8,
+	.size = {
+		.width_mm = 135,
+		.height_mm = 216,
+	},
+	.lanes = 4,
+	.format = MIPI_DSI_FMT_RGB888,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+		      MIPI_DSI_MODE_LPM,
+	.init = kingdisplay_kd101ne3_init,
+	.lp11_before_reset = true,
+};
+
+static int kingdisplay_panel_get_modes(struct drm_panel *panel,
+			       struct drm_connector *connector)
+{
+	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+	const struct drm_display_mode *m = kingdisplay->desc->modes;
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev, m);
+	if (!mode) {
+		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+			m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
+		return -ENOMEM;
+	}
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_set_name(mode);
+	drm_mode_probed_add(connector, mode);
+
+	connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
+	connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
+	connector->display_info.bpc = kingdisplay->desc->bpc;
+
+	return 1;
+}
+
+static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
+{
+	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
+
+	return kingdisplay->orientation;
+}
+
+static const struct drm_panel_funcs kingdisplay_panel_funcs = {
+	.disable = kingdisplay_panel_disable,
+	.unprepare = kingdisplay_panel_unprepare,
+	.prepare = kingdisplay_panel_prepare,
+	.enable = kingdisplay_panel_enable,
+	.get_modes = kingdisplay_panel_get_modes,
+	.get_orientation = kingdisplay_panel_get_orientation,
+};
+
+static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
+{
+	struct device *dev = &kingdisplay->dsi->dev;
+	int err;
+
+	kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
+	if (IS_ERR(kingdisplay->pp3300))
+		return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
+				     "Cannot get pp3300\n");
+
+	kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+	if (IS_ERR(kingdisplay->enable_gpio))
+		return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
+				     "Cannot get enable GPIO\n");
+
+	drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
+
+	err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
+	if (err < 0) {
+		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
+		return err;
+	}
+
+	err = drm_panel_of_backlight(&kingdisplay->base);
+	if (err)
+		return err;
+
+	kingdisplay->base.funcs = &kingdisplay_panel_funcs;
+	kingdisplay->base.dev = &kingdisplay->dsi->dev;
+
+	drm_panel_add(&kingdisplay->base);
+
+	return 0;
+}
+
+static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
+{
+	struct kingdisplay_panel *kingdisplay;
+	int ret;
+	const struct panel_desc *desc;
+
+	kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
+	if (!kingdisplay)
+		return -ENOMEM;
+
+	desc = of_device_get_match_data(&dsi->dev);
+	dsi->lanes = desc->lanes;
+	dsi->format = desc->format;
+	dsi->mode_flags = desc->mode_flags;
+	kingdisplay->desc = desc;
+	kingdisplay->dsi = dsi;
+	ret = kingdisplay_panel_add(kingdisplay);
+	if (ret < 0)
+		return ret;
+
+	mipi_dsi_set_drvdata(dsi, kingdisplay);
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret)
+		drm_panel_remove(&kingdisplay->base);
+
+	return ret;
+}
+
+static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
+{
+	struct kingdisplay_panel *kingdisplay = 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);
+
+	if (kingdisplay->base.dev)
+		drm_panel_remove(&kingdisplay->base);
+}
+
+static const struct of_device_id kingdisplay_of_match[] = {
+	{ .compatible = "kingdisplay,kd101ne3-40ti",
+	  .data = &kingdisplay_kd101ne3_40ti_desc
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
+
+static struct mipi_dsi_driver kingdisplay_panel_driver = {
+	.driver = {
+		.name = "panel-kingdisplay-kd101ne3",
+		.of_match_table = kingdisplay_of_match,
+	},
+	.probe = kingdisplay_panel_probe,
+	.remove = kingdisplay_panel_remove,
+};
+module_mipi_dsi_driver(kingdisplay_panel_driver);
+
+MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
+MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1


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

* [PATCH v2 3/4] dt-bindings: display: panel: Add compatible for Starry-er88577
  2024-06-01  8:45 [PATCH v2 0/4] Support Kingdisplay kd101ne3 and Starry er88577 MIPI-DSI panel Zhaoxiong Lv
  2024-06-01  8:45 ` [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support Zhaoxiong Lv
  2024-06-01  8:45 ` [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver Zhaoxiong Lv
@ 2024-06-01  8:45 ` Zhaoxiong Lv
  2024-06-01 15:41   ` Krzysztof Kozlowski
  2024-06-01  8:45 ` [PATCH v2 4/4] drm/panel: starry: add new panel driver Zhaoxiong Lv
  3 siblings, 1 reply; 21+ messages in thread
From: Zhaoxiong Lv @ 2024-06-01  8:45 UTC (permalink / raw)
  To: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel, Zhaoxiong Lv

The Starry-er88577 is a 10.1" WXGA TFT-LCD panel, which fits
in nicely with the existing panel-kingdisplay-kd101ne3 driver.
Hence, we add a new compatible with panel specific config.

Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
---

Chage since V2:

-  Add compatible for Starry er88577 in Kingdisplay kd101ne3 dt-bindings.

---
 .../bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
index b0cf12bb727d..68c43d2d21a6 100644
--- a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
+++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
@@ -17,6 +17,7 @@ properties:
     items:
       - enum:
           - kingdisplay,kd101ne3-40ti
+          - starry,er88577
 
   reg:
     description: the virtual channel number of a DSI peripheral
-- 
2.17.1


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

* [PATCH v2 4/4] drm/panel: starry: add new panel driver
  2024-06-01  8:45 [PATCH v2 0/4] Support Kingdisplay kd101ne3 and Starry er88577 MIPI-DSI panel Zhaoxiong Lv
                   ` (2 preceding siblings ...)
  2024-06-01  8:45 ` [PATCH v2 3/4] dt-bindings: display: panel: Add compatible for Starry-er88577 Zhaoxiong Lv
@ 2024-06-01  8:45 ` Zhaoxiong Lv
  2024-06-01 16:26   ` Dmitry Baryshkov
  3 siblings, 1 reply; 21+ messages in thread
From: Zhaoxiong Lv @ 2024-06-01  8:45 UTC (permalink / raw)
  To: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel, Zhaoxiong Lv

This Starry panel has the same timing as the Kingdisplay panel,
so add starry configuration in the Kingdisplay driver.

Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
---

Chage since V2:

-  Add compatible for Starry er88577 in panel-kingdisplay-kd101ne3 drivers.

---
 .../drm/panel/panel-kingdisplay-kd101ne3.c    | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
index 8994a1c9afb5..b614d28475a6 100644
--- a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
+++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
@@ -267,6 +267,67 @@ static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
 	return 0;
 };
 
+static int starry_er88577_init(struct kingdisplay_panel *kingdisplay)
+{
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
+
+	/* T5:HWreset to init_code >= 120ms */
+	msleep(120);
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xab, 0xba);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0xba, 0xab);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x10, 0x01, 0x47, 0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x0c, 0x14, 0x04, 0x50, 0x50, 0x14);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x56, 0x53, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x33, 0x30, 0x04);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x05, 0x12, 0x29, 0x49, 0x40);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31,
+				     0x1a, 0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38, 0x34, 0x26,
+				     0x0e, 0x06, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31, 0x1a,
+				     0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38, 0x34, 0x26, 0x0e,
+				     0x06);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xcc, 0x76, 0x12, 0x34, 0x44, 0x44, 0x44,
+				     0x44, 0x98, 0x04, 0x98, 0x04, 0x0f, 0x00, 0x00, 0xc1);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x54, 0x94, 0x02, 0x85, 0x9f, 0x00, 0x6f,
+				     0x00, 0x54, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, 0x22,
+				     0x20, 0x44, 0xff, 0x18, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x87, 0x47, 0x05, 0x05, 0x1c, 0x1c, 0x1d,
+				     0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f, 0x0f, 0x0f, 0x0d, 0x0d,
+				     0x13, 0x13, 0x11, 0x11, 0x24);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x06, 0x06, 0x04, 0x04, 0x1c, 0x1c, 0x1d,
+				     0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f, 0x0e, 0x0e, 0x0c, 0x0c,
+				     0x12, 0x12, 0x10, 0x10, 0x24);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0xcb, 0x43);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x0e, 0x4b, 0x4b, 0x20, 0x19, 0x6b, 0x06,
+				     0xb3);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0xe3, 0x2b, 0x38, 0x08);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x00, 0x01, 0x00, 0x0e, 0x04, 0x44, 0x08,
+				     0x10, 0x00, 0x00, 0x00);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x80, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x12, 0x03, 0x20, 0x00, 0xff);
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x00);
+	if (dsi_ctx.accum_err)
+		return dsi_ctx.accum_err;
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+	if (dsi_ctx.accum_err)
+		return dsi_ctx.accum_err;
+
+	msleep(120);
+
+	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
+	if (dsi_ctx.accum_err)
+		return dsi_ctx.accum_err;
+
+	msleep(20);
+
+	return 0;
+};
+
 static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
 {
 	return container_of(panel, struct kingdisplay_panel, base);
@@ -391,6 +452,34 @@ static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
 	.lp11_before_reset = true,
 };
 
+static const struct drm_display_mode starry_er88577_default_mode = {
+	.clock = 77380,
+	.hdisplay = 800,
+	.hsync_start = 800 + 80,
+	.hsync_end = 800 + 80 + 20,
+	.htotal = 800 + 80 + 20 + 80,
+	.vdisplay = 1280,
+	.vsync_start = 1280 + 20,
+	.vsync_end = 1280 + 20 + 4,
+	.vtotal = 1280 + 20 + 4 + 12,
+	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct panel_desc starry_er88577_desc = {
+	.modes = &starry_er88577_default_mode,
+	.bpc = 8,
+	.size = {
+		.width_mm = 135,
+		.height_mm = 216,
+	},
+	.lanes = 4,
+	.format = MIPI_DSI_FMT_RGB888,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+		      MIPI_DSI_MODE_LPM,
+	.init = starry_er88577_init,
+	.lp11_before_reset = true,
+};
+
 static int kingdisplay_panel_get_modes(struct drm_panel *panel,
 			       struct drm_connector *connector)
 {
@@ -514,6 +603,9 @@ static const struct of_device_id kingdisplay_of_match[] = {
 	{ .compatible = "kingdisplay,kd101ne3-40ti",
 	  .data = &kingdisplay_kd101ne3_40ti_desc
 	},
+	{ .compatible = "starry,er88577",
+	  .data = &starry_er88577_desc
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
-- 
2.17.1


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

* Re: [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support
  2024-06-01  8:45 ` [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support Zhaoxiong Lv
@ 2024-06-01 15:40   ` Krzysztof Kozlowski
  2024-06-01 16:27   ` Dmitry Baryshkov
  1 sibling, 0 replies; 21+ messages in thread
From: Krzysztof Kozlowski @ 2024-06-01 15:40 UTC (permalink / raw)
  To: Zhaoxiong Lv, dmitry.torokhov, robh, krzysztof.kozlowski+dt,
	conor+dt, jikos, benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel

On 01/06/2024 10:45, Zhaoxiong Lv wrote:
> Create a new dt-scheam for the kd101ne3-40ti.
> The bias IC of this kindisplay-kd101ne3 panel is placed
> on the panel side, so when the panel is powered on,
> there is no need to control AVDD and AVEE in the driver.

> +
> +  reg:
> +    description: the virtual channel number of a DSI peripheral
> +
> +  pp3300-supply:
> +    description: core voltage supply
> +
> +required:
> +  - compatible
> +  - reg
> +  - pp3300-supply
> +  - enable-gpios
> +  - backlight
> +  - port
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    dsi {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        panel: panel@0 {
> +            compatible = "kingdisplay,kd101ne3-40ti";
> +            reg = <0>;
> +            enable-gpios = <&pio 98 0>;

Please use the define, not drop the header.

Best regards,
Krzysztof


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

* Re: [PATCH v2 3/4] dt-bindings: display: panel: Add compatible for Starry-er88577
  2024-06-01  8:45 ` [PATCH v2 3/4] dt-bindings: display: panel: Add compatible for Starry-er88577 Zhaoxiong Lv
@ 2024-06-01 15:41   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 21+ messages in thread
From: Krzysztof Kozlowski @ 2024-06-01 15:41 UTC (permalink / raw)
  To: Zhaoxiong Lv, dmitry.torokhov, robh, krzysztof.kozlowski+dt,
	conor+dt, jikos, benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel

On 01/06/2024 10:45, Zhaoxiong Lv wrote:
> The Starry-er88577 is a 10.1" WXGA TFT-LCD panel, which fits
> in nicely with the existing panel-kingdisplay-kd101ne3 driver.
> Hence, we add a new compatible with panel specific config.
> 
> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> ---
> 
> Chage since V2:
> 

Squash it with first patch. Logically this is one change: adding new
binding for these devices.

Best regards,
Krzysztof


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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-01  8:45 ` [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver Zhaoxiong Lv
@ 2024-06-01 16:23   ` Dmitry Baryshkov
  2024-06-02  5:07   ` Alex Bee
  1 sibling, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2024-06-01 16:23 UTC (permalink / raw)
  To: Zhaoxiong Lv
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

On Sat, Jun 01, 2024 at 04:45:26PM +0800, Zhaoxiong Lv wrote:
> The bias IC of this kindisplay-kd101ne3 panel is placed
> on the panel side, so when the panel is powered on,
> there is no need to control AVDD and AVEE in the driver,
> only 3.3v and reset are needed.
> 
> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> ---
> 
> Chage since V2:
> 
> -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
> -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
> -  and drop kingdisplay_panel_enter_sleep_mode().
> -  3. If prepare fails, disable GPIO before regulators.
> -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
> -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
> 
> ---
>  drivers/gpu/drm/panel/Kconfig                 |   9 +
>  drivers/gpu/drm/panel/Makefile                |   1 +
>  .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
>  3 files changed, 543 insertions(+)
>  create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> 
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index e54f6f5604ed..71669e990e8e 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
>  	  24 bit RGB per pixel. It provides a MIPI DSI interface to
>  	  the host and has a built-in LED backlight.
>  
> +config DRM_PANEL_KINGDISPLAY_KD101NE3
> +	tristate "Kingdisplay kd101ne3 panel"
> +	depends on OF
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	help
> +	  Say Y here if you want to enable support for the kingdisplay kd101ne3
> +	  4-lane 800x1280 MIPI DSI panel.
> +
>  config DRM_PANEL_LEADTEK_LTK050H3146W
>  	tristate "Leadtek LTK050H3146W panel"
>  	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index f0203f6e02f4..4576c9fe33d9 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
>  obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
>  obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
>  obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
> +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
>  obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
>  obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
>  obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> new file mode 100644
> index 000000000000..8994a1c9afb5
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> @@ -0,0 +1,533 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Panels based on the JD9365DA display controller.
> + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_connector.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_panel.h>
> +
> +#include <video/mipi_display.h>
> +
> +struct kingdisplay_panel;
> +
> +struct panel_desc {
> +	const struct drm_display_mode *modes;
> +	unsigned int bpc;
> +
> +	/**
> +	 * @width_mm: width of the panel's active display area
> +	 * @height_mm: height of the panel's active display area
> +	 */
> +	struct {
> +		unsigned int width_mm;
> +		unsigned int height_mm;
> +	} size;
> +
> +	unsigned long mode_flags;
> +	enum mipi_dsi_pixel_format format;
> +	const struct panel_init_cmd *init_cmds;
> +	int (*init)(struct kingdisplay_panel *kingdisplay);
> +	unsigned int lanes;
> +	bool discharge_on_disable;
> +	bool lp11_before_reset;
> +};
> +
> +struct kingdisplay_panel {
> +	struct drm_panel base;
> +	struct mipi_dsi_device *dsi;
> +
> +	const struct panel_desc *desc;
> +
> +	enum drm_panel_orientation orientation;
> +	struct regulator *pp3300;
> +	struct gpio_desc *enable_gpio;
> +};
> +
> +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> +{
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> +
> +	/* T5:HWreset to init_code >= 50ms */
> +	msleep(50);
> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;

No need to, the execution can continue.

> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);

mipi_dsi_dcs_exit_sleep_mode_multi()

> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;

No need to

> +
> +	msleep(120);

mipi_dsi_msleep

> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);

mipi_dsi_dcs_set_display_on_multi

> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;

No need to

> +
> +	msleep(20);

mipi_dsi_msleep
> +
> +	return 0;
> +};
> +
> +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct kingdisplay_panel, base);
> +}
> +
> +static int kingdisplay_panel_disable(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	int err;
> +
> +	kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> +	msleep(100);
> +
> +	err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);

You might want to use context / mipi_dsi_*_multi here too.

> +	if (err < 0)
> +		dev_err(panel->dev, "failed to set display off: %d\n", err);
> +
> +	msleep(50);
> +
> +	err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
> +	if (err < 0) {
> +		dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
> +		return err;
> +	}
> +
> +	msleep(120);
> +
> +	return 0;
> +}
> +
> +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	int err;
> +
> +	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
> +
> +	/* T15: 2ms */
> +	usleep_range(1000, 2000);
> +
> +	err = regulator_disable(kingdisplay->pp3300);
> +	if (err < 0)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static int kingdisplay_panel_prepare(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	int err;
> +
> +	gpiod_set_value(kingdisplay->enable_gpio, 0);
> +
> +	err = regulator_enable(kingdisplay->pp3300);
> +	if (err < 0)
> +		return err;
> +
> +	/* T1:Vdd to mipi_lp >= 0ms */
> +	usleep_range(5000, 6000);
> +
> +	if (kingdisplay->desc->lp11_before_reset) {
> +		err = mipi_dsi_dcs_nop(kingdisplay->dsi);
> +		if (err < 0)
> +			goto poweroff;
> +
> +		usleep_range(1000, 2000);
> +	}
> +
> +	/* T2: 10ms, T1 + T2 > 60ms */
> +	msleep(60);
> +
> +	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
> +
> +	err = kingdisplay->desc->init(kingdisplay);
> +	if (err < 0)
> +		goto poweroff;
> +
> +	return 0;
> +
> +poweroff:
> +	gpiod_set_value(kingdisplay->enable_gpio, 0);
> +		/* T6: 2ms */
> +	usleep_range(1000, 2000);
> +	regulator_disable(kingdisplay->pp3300);
> +
> +	return err;
> +}
> +
> +static int kingdisplay_panel_enable(struct drm_panel *panel)
> +{
> +	msleep(130);

This happens after enabling the DSI video signal. What is the point of sleeping here?

> +	return 0;
> +}
> +
> +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
> +	.clock = 70595,
> +	.hdisplay = 800,
> +	.hsync_start = 800 + 30,
> +	.hsync_end = 800 + 30 + 30,
> +	.htotal = 800 + 30 + 30 + 30,
> +	.vdisplay = 1280,
> +	.vsync_start = 1280 + 30,
> +	.vsync_end = 1280 + 30 + 4,
> +	.vtotal = 1280 + 30 + 4 + 8,
> +	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> +};
> +
> +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> +	.modes = &kingdisplay_kd101ne3_40ti_default_mode,
> +	.bpc = 8,
> +	.size = {
> +		.width_mm = 135,
> +		.height_mm = 216,
> +	},
> +	.lanes = 4,
> +	.format = MIPI_DSI_FMT_RGB888,
> +	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> +		      MIPI_DSI_MODE_LPM,
> +	.init = kingdisplay_kd101ne3_init,
> +	.lp11_before_reset = true,
> +};
> +
> +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> +			       struct drm_connector *connector)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	const struct drm_display_mode *m = kingdisplay->desc->modes;
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_duplicate(connector->dev, m);
> +	if (!mode) {
> +		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
> +			m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
> +		return -ENOMEM;
> +	}
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +	drm_mode_set_name(mode);
> +	drm_mode_probed_add(connector, mode);
> +
> +	connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
> +	connector->display_info.height_mm = kingdisplay->desc->size.height_mm;

Please move dimensions to the mode and use drm_connector_helper_get_modes_fixed()

> +	connector->display_info.bpc = kingdisplay->desc->bpc;
> +
> +	return 1;
> +}
> +
> +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +
> +	return kingdisplay->orientation;
> +}
> +
> +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
> +	.disable = kingdisplay_panel_disable,
> +	.unprepare = kingdisplay_panel_unprepare,
> +	.prepare = kingdisplay_panel_prepare,
> +	.enable = kingdisplay_panel_enable,
> +	.get_modes = kingdisplay_panel_get_modes,
> +	.get_orientation = kingdisplay_panel_get_orientation,
> +};
> +
> +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
> +{
> +	struct device *dev = &kingdisplay->dsi->dev;
> +	int err;
> +
> +	kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
> +	if (IS_ERR(kingdisplay->pp3300))
> +		return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
> +				     "Cannot get pp3300\n");
> +
> +	kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> +	if (IS_ERR(kingdisplay->enable_gpio))
> +		return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
> +				     "Cannot get enable GPIO\n");
> +
> +	drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
> +		       DRM_MODE_CONNECTOR_DSI);
> +
> +	err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
> +	if (err < 0) {
> +		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
> +		return err;
> +	}
> +
> +	err = drm_panel_of_backlight(&kingdisplay->base);
> +	if (err)
> +		return err;
> +
> +	kingdisplay->base.funcs = &kingdisplay_panel_funcs;
> +	kingdisplay->base.dev = &kingdisplay->dsi->dev;
> +
> +	drm_panel_add(&kingdisplay->base);
> +
> +	return 0;
> +}
> +
> +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct kingdisplay_panel *kingdisplay;
> +	int ret;
> +	const struct panel_desc *desc;
> +
> +	kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
> +	if (!kingdisplay)
> +		return -ENOMEM;
> +
> +	desc = of_device_get_match_data(&dsi->dev);
> +	dsi->lanes = desc->lanes;
> +	dsi->format = desc->format;
> +	dsi->mode_flags = desc->mode_flags;
> +	kingdisplay->desc = desc;
> +	kingdisplay->dsi = dsi;
> +	ret = kingdisplay_panel_add(kingdisplay);
> +	if (ret < 0)
> +		return ret;
> +
> +	mipi_dsi_set_drvdata(dsi, kingdisplay);
> +
> +	ret = mipi_dsi_attach(dsi);
> +	if (ret)
> +		drm_panel_remove(&kingdisplay->base);
> +
> +	return ret;
> +}
> +
> +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
> +{
> +	struct kingdisplay_panel *kingdisplay = 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);
> +
> +	if (kingdisplay->base.dev)
> +		drm_panel_remove(&kingdisplay->base);
> +}
> +
> +static const struct of_device_id kingdisplay_of_match[] = {
> +	{ .compatible = "kingdisplay,kd101ne3-40ti",
> +	  .data = &kingdisplay_kd101ne3_40ti_desc
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> +
> +static struct mipi_dsi_driver kingdisplay_panel_driver = {
> +	.driver = {
> +		.name = "panel-kingdisplay-kd101ne3",
> +		.of_match_table = kingdisplay_of_match,
> +	},
> +	.probe = kingdisplay_panel_probe,
> +	.remove = kingdisplay_panel_remove,
> +};
> +module_mipi_dsi_driver(kingdisplay_panel_driver);
> +
> +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
> +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.17.1
> 

-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 4/4] drm/panel: starry: add new panel driver
  2024-06-01  8:45 ` [PATCH v2 4/4] drm/panel: starry: add new panel driver Zhaoxiong Lv
@ 2024-06-01 16:26   ` Dmitry Baryshkov
  2024-06-07 11:51     ` zhaoxiong lv
  0 siblings, 1 reply; 21+ messages in thread
From: Dmitry Baryshkov @ 2024-06-01 16:26 UTC (permalink / raw)
  To: Zhaoxiong Lv
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

On Sat, Jun 01, 2024 at 04:45:28PM +0800, Zhaoxiong Lv wrote:
> This Starry panel has the same timing as the Kingdisplay panel,
> so add starry configuration in the Kingdisplay driver.

Do these two panels share the same driver IC? Programming sequences do
not seem common, so it might be better to have a separate driver for
this panel.

> 
> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> ---
> 
> Chage since V2:
> 
> -  Add compatible for Starry er88577 in panel-kingdisplay-kd101ne3 drivers.
> 
> ---
>  .../drm/panel/panel-kingdisplay-kd101ne3.c    | 92 +++++++++++++++++++
>  1 file changed, 92 insertions(+)
> 
> diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> index 8994a1c9afb5..b614d28475a6 100644
> --- a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> @@ -267,6 +267,67 @@ static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
>  	return 0;
>  };
>  
> +static int starry_er88577_init(struct kingdisplay_panel *kingdisplay)
> +{
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> +
> +	/* T5:HWreset to init_code >= 120ms */
> +	msleep(120);
> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xab, 0xba);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0xba, 0xab);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x10, 0x01, 0x47, 0xff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x0c, 0x14, 0x04, 0x50, 0x50, 0x14);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x56, 0x53, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x33, 0x30, 0x04);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x05, 0x12, 0x29, 0x49, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31,
> +				     0x1a, 0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38, 0x34, 0x26,
> +				     0x0e, 0x06, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31, 0x1a,
> +				     0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38, 0x34, 0x26, 0x0e,
> +				     0x06);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xcc, 0x76, 0x12, 0x34, 0x44, 0x44, 0x44,
> +				     0x44, 0x98, 0x04, 0x98, 0x04, 0x0f, 0x00, 0x00, 0xc1);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x54, 0x94, 0x02, 0x85, 0x9f, 0x00, 0x6f,
> +				     0x00, 0x54, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, 0x22,
> +				     0x20, 0x44, 0xff, 0x18, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x87, 0x47, 0x05, 0x05, 0x1c, 0x1c, 0x1d,
> +				     0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f, 0x0f, 0x0f, 0x0d, 0x0d,
> +				     0x13, 0x13, 0x11, 0x11, 0x24);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x06, 0x06, 0x04, 0x04, 0x1c, 0x1c, 0x1d,
> +				     0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f, 0x0e, 0x0e, 0x0c, 0x0c,
> +				     0x12, 0x12, 0x10, 0x10, 0x24);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0xcb, 0x43);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x0e, 0x4b, 0x4b, 0x20, 0x19, 0x6b, 0x06,
> +				     0xb3);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0xe3, 0x2b, 0x38, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x00, 0x01, 0x00, 0x0e, 0x04, 0x44, 0x08,
> +				     0x10, 0x00, 0x00, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x80, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff,
> +				     0xff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x12, 0x03, 0x20, 0x00, 0xff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x00);
> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;
> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;
> +
> +	msleep(120);
> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;
> +
> +	msleep(20);

Most of the comments from the patch 2 apply:
- drop conditions
- use mipi_dsi_dcs_set_display_on_multi(),
  mipi_dsi_dcs_exit_sleep_mode_multi() and mipi_dsi_msleep().

> +
> +	return 0;
> +};
> +
>  static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
>  {
>  	return container_of(panel, struct kingdisplay_panel, base);
> @@ -391,6 +452,34 @@ static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
>  	.lp11_before_reset = true,
>  };
>  
> +static const struct drm_display_mode starry_er88577_default_mode = {
> +	.clock = 77380,
> +	.hdisplay = 800,
> +	.hsync_start = 800 + 80,
> +	.hsync_end = 800 + 80 + 20,
> +	.htotal = 800 + 80 + 20 + 80,
> +	.vdisplay = 1280,
> +	.vsync_start = 1280 + 20,
> +	.vsync_end = 1280 + 20 + 4,
> +	.vtotal = 1280 + 20 + 4 + 12,
> +	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> +};
> +
> +static const struct panel_desc starry_er88577_desc = {
> +	.modes = &starry_er88577_default_mode,
> +	.bpc = 8,
> +	.size = {
> +		.width_mm = 135,
> +		.height_mm = 216,
> +	},
> +	.lanes = 4,
> +	.format = MIPI_DSI_FMT_RGB888,
> +	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> +		      MIPI_DSI_MODE_LPM,
> +	.init = starry_er88577_init,
> +	.lp11_before_reset = true,
> +};
> +
>  static int kingdisplay_panel_get_modes(struct drm_panel *panel,
>  			       struct drm_connector *connector)
>  {
> @@ -514,6 +603,9 @@ static const struct of_device_id kingdisplay_of_match[] = {
>  	{ .compatible = "kingdisplay,kd101ne3-40ti",
>  	  .data = &kingdisplay_kd101ne3_40ti_desc
>  	},
> +	{ .compatible = "starry,er88577",
> +	  .data = &starry_er88577_desc
> +	},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> -- 
> 2.17.1
> 

-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support
  2024-06-01  8:45 ` [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support Zhaoxiong Lv
  2024-06-01 15:40   ` Krzysztof Kozlowski
@ 2024-06-01 16:27   ` Dmitry Baryshkov
  2024-06-07 11:38     ` zhaoxiong lv
  1 sibling, 1 reply; 21+ messages in thread
From: Dmitry Baryshkov @ 2024-06-01 16:27 UTC (permalink / raw)
  To: Zhaoxiong Lv
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

On Sat, Jun 01, 2024 at 04:45:25PM +0800, Zhaoxiong Lv wrote:
> Create a new dt-scheam for the kd101ne3-40ti.
> The bias IC of this kindisplay-kd101ne3 panel is placed
> on the panel side, so when the panel is powered on,
> there is no need to control AVDD and AVEE in the driver.
> 
> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> ---
> 
> Chage since V2:
> 
> -  Drop some properties that have already been defined in panel-common.
> -  The header file 'dt-bindings/gpio/gpio.h' is not used, delete it
> 
> V1: https://lore.kernel.org/all/20240418081548.12160-2-lvzhaoxiong@huaqin.corp-partner.google.com/
> 
> ---
>  .../panel/kingdisplay,kd101ne3-40ti.yaml      | 59 +++++++++++++++++++
>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> new file mode 100644
> index 000000000000..b0cf12bb727d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> @@ -0,0 +1,59 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/panel/kingdisplay,kd101ne3-40ti.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Kingdisplay KD101NE3-40TI based MIPI-DSI panels
> +
> +maintainers:
> +  - Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>

Any reason for using a separate bindings instead of extending
panel-simple-dsi.yaml ?

> +
> +allOf:
> +  - $ref: panel-common.yaml#
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - kingdisplay,kd101ne3-40ti
> +
> +  reg:
> +    description: the virtual channel number of a DSI peripheral
> +
> +  pp3300-supply:
> +    description: core voltage supply
> +
> +required:
> +  - compatible
> +  - reg
> +  - pp3300-supply
> +  - enable-gpios
> +  - backlight
> +  - port
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    dsi {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        panel: panel@0 {
> +            compatible = "kingdisplay,kd101ne3-40ti";
> +            reg = <0>;
> +            enable-gpios = <&pio 98 0>;
> +            pinctrl-names = "default";
> +            pinctrl-0 = <&panel_pins_default>;
> +            pp3300-supply = <&en_pp6000_mipi_disp>;
> +            backlight = <&backlight_lcd0>;
> +            rotation = <90>;
> +            port {
> +                panel_in: endpoint {
> +                    remote-endpoint = <&dsi_out>;
> +                };
> +            };
> +        };
> +    };
> +
> +...
> -- 
> 2.17.1
> 

-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-01  8:45 ` [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver Zhaoxiong Lv
  2024-06-01 16:23   ` Dmitry Baryshkov
@ 2024-06-02  5:07   ` Alex Bee
  2024-06-07 11:44     ` zhaoxiong lv
  1 sibling, 1 reply; 21+ messages in thread
From: Alex Bee @ 2024-06-02  5:07 UTC (permalink / raw)
  To: Zhaoxiong Lv, dmitry.torokhov, robh, krzysztof.kozlowski+dt,
	conor+dt, jikos, benjamin.tissoires, dianders, hsinyi
  Cc: dri-devel, devicetree, linux-kernel

Am 01.06.24 um 10:45 schrieb Zhaoxiong Lv:

Hi Zhaoxiong,

> The bias IC of this kindisplay-kd101ne3 panel is placed
> on the panel side, so when the panel is powered on,
> there is no need to control AVDD and AVEE in the driver,
> only 3.3v and reset are needed.
> 
> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> ---
> 
> Chage since V2:
> 
> -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
> -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
> -  and drop kingdisplay_panel_enter_sleep_mode().
> -  3. If prepare fails, disable GPIO before regulators.
> -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
> -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
> 
> ---
>   drivers/gpu/drm/panel/Kconfig                 |   9 +
>   drivers/gpu/drm/panel/Makefile                |   1 +
>   .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
>   3 files changed, 543 insertions(+)
>   create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> 
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index e54f6f5604ed..71669e990e8e 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
>   	  24 bit RGB per pixel. It provides a MIPI DSI interface to
>   	  the host and has a built-in LED backlight.
>   
> +config DRM_PANEL_KINGDISPLAY_KD101NE3
> +	tristate "Kingdisplay kd101ne3 panel"
> +	depends on OF
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	help
> +	  Say Y here if you want to enable support for the kingdisplay kd101ne3
> +	  4-lane 800x1280 MIPI DSI panel.
> +
>   config DRM_PANEL_LEADTEK_LTK050H3146W
>   	tristate "Leadtek LTK050H3146W panel"
>   	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index f0203f6e02f4..4576c9fe33d9 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
>   obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
>   obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
>   obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
> +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
>   obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
>   obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
>   obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> new file mode 100644
> index 000000000000..8994a1c9afb5
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> @@ -0,0 +1,533 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Panels based on the JD9365DA display controller.
> + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_connector.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_panel.h>
> +
> +#include <video/mipi_display.h>
> +
> +struct kingdisplay_panel;
> +
> +struct panel_desc {
> +	const struct drm_display_mode *modes;
> +	unsigned int bpc;
> +
> +	/**
> +	 * @width_mm: width of the panel's active display area
> +	 * @height_mm: height of the panel's active display area
> +	 */
> +	struct {
> +		unsigned int width_mm;
> +		unsigned int height_mm;
> +	} size;
> +
> +	unsigned long mode_flags;
> +	enum mipi_dsi_pixel_format format;
> +	const struct panel_init_cmd *init_cmds;
> +	int (*init)(struct kingdisplay_panel *kingdisplay);
> +	unsigned int lanes;
> +	bool discharge_on_disable;
> +	bool lp11_before_reset;
> +};
> +
> +struct kingdisplay_panel {
> +	struct drm_panel base;
> +	struct mipi_dsi_device *dsi;
> +
> +	const struct panel_desc *desc;
> +
> +	enum drm_panel_orientation orientation;
> +	struct regulator *pp3300;
> +	struct gpio_desc *enable_gpio;
> +};
> +
> +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> +{
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> +
> +	/* T5:HWreset to init_code >= 50ms */
> +	msleep(50);
> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
Looking at the init sequence, I'm pretty confident this panel uses a 
Jadard JD 9365 driver IC. It's probably worth adding it to 
panel-jadard-jd9365da instead of adding a completly new driver.

Alex
> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;
> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;
> +
> +	msleep(120);
> +
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> +	if (dsi_ctx.accum_err)
> +		return dsi_ctx.accum_err;
> +
> +	msleep(20);
> +
> +	return 0;
> +};
> +
> +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct kingdisplay_panel, base);
> +}
> +
> +static int kingdisplay_panel_disable(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	int err;
> +
> +	kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> +	msleep(100);
> +
> +	err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
> +	if (err < 0)
> +		dev_err(panel->dev, "failed to set display off: %d\n", err);
> +
> +	msleep(50);
> +
> +	err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
> +	if (err < 0) {
> +		dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
> +		return err;
> +	}
> +
> +	msleep(120);
> +
> +	return 0;
> +}
> +
> +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	int err;
> +
> +	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
> +
> +	/* T15: 2ms */
> +	usleep_range(1000, 2000);
> +
> +	err = regulator_disable(kingdisplay->pp3300);
> +	if (err < 0)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static int kingdisplay_panel_prepare(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	int err;
> +
> +	gpiod_set_value(kingdisplay->enable_gpio, 0);
> +
> +	err = regulator_enable(kingdisplay->pp3300);
> +	if (err < 0)
> +		return err;
> +
> +	/* T1:Vdd to mipi_lp >= 0ms */
> +	usleep_range(5000, 6000);
> +
> +	if (kingdisplay->desc->lp11_before_reset) {
> +		err = mipi_dsi_dcs_nop(kingdisplay->dsi);
> +		if (err < 0)
> +			goto poweroff;
> +
> +		usleep_range(1000, 2000);
> +	}
> +
> +	/* T2: 10ms, T1 + T2 > 60ms */
> +	msleep(60);
> +
> +	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
> +
> +	err = kingdisplay->desc->init(kingdisplay);
> +	if (err < 0)
> +		goto poweroff;
> +
> +	return 0;
> +
> +poweroff:
> +	gpiod_set_value(kingdisplay->enable_gpio, 0);
> +		/* T6: 2ms */
> +	usleep_range(1000, 2000);
> +	regulator_disable(kingdisplay->pp3300);
> +
> +	return err;
> +}
> +
> +static int kingdisplay_panel_enable(struct drm_panel *panel)
> +{
> +	msleep(130);
> +	return 0;
> +}
> +
> +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
> +	.clock = 70595,
> +	.hdisplay = 800,
> +	.hsync_start = 800 + 30,
> +	.hsync_end = 800 + 30 + 30,
> +	.htotal = 800 + 30 + 30 + 30,
> +	.vdisplay = 1280,
> +	.vsync_start = 1280 + 30,
> +	.vsync_end = 1280 + 30 + 4,
> +	.vtotal = 1280 + 30 + 4 + 8,
> +	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> +};
> +
> +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> +	.modes = &kingdisplay_kd101ne3_40ti_default_mode,
> +	.bpc = 8,
> +	.size = {
> +		.width_mm = 135,
> +		.height_mm = 216,
> +	},
> +	.lanes = 4,
> +	.format = MIPI_DSI_FMT_RGB888,
> +	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> +		      MIPI_DSI_MODE_LPM,
> +	.init = kingdisplay_kd101ne3_init,
> +	.lp11_before_reset = true,
> +};
> +
> +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> +			       struct drm_connector *connector)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +	const struct drm_display_mode *m = kingdisplay->desc->modes;
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_duplicate(connector->dev, m);
> +	if (!mode) {
> +		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
> +			m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
> +		return -ENOMEM;
> +	}
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +	drm_mode_set_name(mode);
> +	drm_mode_probed_add(connector, mode);
> +
> +	connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
> +	connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
> +	connector->display_info.bpc = kingdisplay->desc->bpc;
> +
> +	return 1;
> +}
> +
> +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
> +{
> +	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> +
> +	return kingdisplay->orientation;
> +}
> +
> +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
> +	.disable = kingdisplay_panel_disable,
> +	.unprepare = kingdisplay_panel_unprepare,
> +	.prepare = kingdisplay_panel_prepare,
> +	.enable = kingdisplay_panel_enable,
> +	.get_modes = kingdisplay_panel_get_modes,
> +	.get_orientation = kingdisplay_panel_get_orientation,
> +};
> +
> +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
> +{
> +	struct device *dev = &kingdisplay->dsi->dev;
> +	int err;
> +
> +	kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
> +	if (IS_ERR(kingdisplay->pp3300))
> +		return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
> +				     "Cannot get pp3300\n");
> +
> +	kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> +	if (IS_ERR(kingdisplay->enable_gpio))
> +		return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
> +				     "Cannot get enable GPIO\n");
> +
> +	drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
> +		       DRM_MODE_CONNECTOR_DSI);
> +
> +	err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
> +	if (err < 0) {
> +		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
> +		return err;
> +	}
> +
> +	err = drm_panel_of_backlight(&kingdisplay->base);
> +	if (err)
> +		return err;
> +
> +	kingdisplay->base.funcs = &kingdisplay_panel_funcs;
> +	kingdisplay->base.dev = &kingdisplay->dsi->dev;
> +
> +	drm_panel_add(&kingdisplay->base);
> +
> +	return 0;
> +}
> +
> +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct kingdisplay_panel *kingdisplay;
> +	int ret;
> +	const struct panel_desc *desc;
> +
> +	kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
> +	if (!kingdisplay)
> +		return -ENOMEM;
> +
> +	desc = of_device_get_match_data(&dsi->dev);
> +	dsi->lanes = desc->lanes;
> +	dsi->format = desc->format;
> +	dsi->mode_flags = desc->mode_flags;
> +	kingdisplay->desc = desc;
> +	kingdisplay->dsi = dsi;
> +	ret = kingdisplay_panel_add(kingdisplay);
> +	if (ret < 0)
> +		return ret;
> +
> +	mipi_dsi_set_drvdata(dsi, kingdisplay);
> +
> +	ret = mipi_dsi_attach(dsi);
> +	if (ret)
> +		drm_panel_remove(&kingdisplay->base);
> +
> +	return ret;
> +}
> +
> +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
> +{
> +	struct kingdisplay_panel *kingdisplay = 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);
> +
> +	if (kingdisplay->base.dev)
> +		drm_panel_remove(&kingdisplay->base);
> +}
> +
> +static const struct of_device_id kingdisplay_of_match[] = {
> +	{ .compatible = "kingdisplay,kd101ne3-40ti",
> +	  .data = &kingdisplay_kd101ne3_40ti_desc
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> +
> +static struct mipi_dsi_driver kingdisplay_panel_driver = {
> +	.driver = {
> +		.name = "panel-kingdisplay-kd101ne3",
> +		.of_match_table = kingdisplay_of_match,
> +	},
> +	.probe = kingdisplay_panel_probe,
> +	.remove = kingdisplay_panel_remove,
> +};
> +module_mipi_dsi_driver(kingdisplay_panel_driver);
> +
> +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
> +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
> +MODULE_LICENSE("GPL v2");


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

* Re: [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support
  2024-06-01 16:27   ` Dmitry Baryshkov
@ 2024-06-07 11:38     ` zhaoxiong lv
  2024-06-07 11:48       ` Dmitry Baryshkov
  0 siblings, 1 reply; 21+ messages in thread
From: zhaoxiong lv @ 2024-06-07 11:38 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

hi Dmitry Baryshkov

Because this is a separate mipi dsi driver, I did not put it in
panel-sample-dsi.yaml.


On Sun, Jun 2, 2024 at 12:28 AM Dmitry Baryshkov
<dmitry.baryshkov@linaro.org> wrote:
>
> On Sat, Jun 01, 2024 at 04:45:25PM +0800, Zhaoxiong Lv wrote:
> > Create a new dt-scheam for the kd101ne3-40ti.
> > The bias IC of this kindisplay-kd101ne3 panel is placed
> > on the panel side, so when the panel is powered on,
> > there is no need to control AVDD and AVEE in the driver.
> >
> > Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > ---
> >
> > Chage since V2:
> >
> > -  Drop some properties that have already been defined in panel-common.
> > -  The header file 'dt-bindings/gpio/gpio.h' is not used, delete it
> >
> > V1: https://lore.kernel.org/all/20240418081548.12160-2-lvzhaoxiong@huaqin.corp-partner.google.com/
> >
> > ---
> >  .../panel/kingdisplay,kd101ne3-40ti.yaml      | 59 +++++++++++++++++++
> >  1 file changed, 59 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> > new file mode 100644
> > index 000000000000..b0cf12bb727d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> > @@ -0,0 +1,59 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/display/panel/kingdisplay,kd101ne3-40ti.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Kingdisplay KD101NE3-40TI based MIPI-DSI panels
> > +
> > +maintainers:
> > +  - Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
>
> Any reason for using a separate bindings instead of extending
> panel-simple-dsi.yaml ?
>
> > +
> > +allOf:
> > +  - $ref: panel-common.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - kingdisplay,kd101ne3-40ti
> > +
> > +  reg:
> > +    description: the virtual channel number of a DSI peripheral
> > +
> > +  pp3300-supply:
> > +    description: core voltage supply
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - pp3300-supply
> > +  - enable-gpios
> > +  - backlight
> > +  - port
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > +  - |
> > +    dsi {
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +        panel: panel@0 {
> > +            compatible = "kingdisplay,kd101ne3-40ti";
> > +            reg = <0>;
> > +            enable-gpios = <&pio 98 0>;
> > +            pinctrl-names = "default";
> > +            pinctrl-0 = <&panel_pins_default>;
> > +            pp3300-supply = <&en_pp6000_mipi_disp>;
> > +            backlight = <&backlight_lcd0>;
> > +            rotation = <90>;
> > +            port {
> > +                panel_in: endpoint {
> > +                    remote-endpoint = <&dsi_out>;
> > +                };
> > +            };
> > +        };
> > +    };
> > +
> > +...
> > --
> > 2.17.1
> >
>
> --
> With best wishes
> Dmitry

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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-02  5:07   ` Alex Bee
@ 2024-06-07 11:44     ` zhaoxiong lv
  2024-06-07 12:01       ` Dmitry Baryshkov
  0 siblings, 1 reply; 21+ messages in thread
From: zhaoxiong lv @ 2024-06-07 11:44 UTC (permalink / raw)
  To: Alex Bee
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

hi Alex Bee

I compared these two drivers. Although the control IC is the same, the
panel is different, and the init_cmd and timing are also slightly
different, so I added a separate driver.

thanks

On Sun, Jun 2, 2024 at 1:07 PM Alex Bee <knaerzche@gmail.com> wrote:
>
> Am 01.06.24 um 10:45 schrieb Zhaoxiong Lv:
>
> Hi Zhaoxiong,
>
> > The bias IC of this kindisplay-kd101ne3 panel is placed
> > on the panel side, so when the panel is powered on,
> > there is no need to control AVDD and AVEE in the driver,
> > only 3.3v and reset are needed.
> >
> > Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > ---
> >
> > Chage since V2:
> >
> > -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
> > -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
> > -  and drop kingdisplay_panel_enter_sleep_mode().
> > -  3. If prepare fails, disable GPIO before regulators.
> > -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
> > -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
> >
> > ---
> >   drivers/gpu/drm/panel/Kconfig                 |   9 +
> >   drivers/gpu/drm/panel/Makefile                |   1 +
> >   .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
> >   3 files changed, 543 insertions(+)
> >   create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> >
> > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> > index e54f6f5604ed..71669e990e8e 100644
> > --- a/drivers/gpu/drm/panel/Kconfig
> > +++ b/drivers/gpu/drm/panel/Kconfig
> > @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
> >         24 bit RGB per pixel. It provides a MIPI DSI interface to
> >         the host and has a built-in LED backlight.
> >
> > +config DRM_PANEL_KINGDISPLAY_KD101NE3
> > +     tristate "Kingdisplay kd101ne3 panel"
> > +     depends on OF
> > +     depends on DRM_MIPI_DSI
> > +     depends on BACKLIGHT_CLASS_DEVICE
> > +     help
> > +       Say Y here if you want to enable support for the kingdisplay kd101ne3
> > +       4-lane 800x1280 MIPI DSI panel.
> > +
> >   config DRM_PANEL_LEADTEK_LTK050H3146W
> >       tristate "Leadtek LTK050H3146W panel"
> >       depends on OF
> > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> > index f0203f6e02f4..4576c9fe33d9 100644
> > --- a/drivers/gpu/drm/panel/Makefile
> > +++ b/drivers/gpu/drm/panel/Makefile
> > @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
> >   obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
> >   obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
> >   obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
> > +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
> >   obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
> >   obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
> >   obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> > diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > new file mode 100644
> > index 000000000000..8994a1c9afb5
> > --- /dev/null
> > +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > @@ -0,0 +1,533 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/* Panels based on the JD9365DA display controller.
> > + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/regulator/consumer.h>
> > +
> > +#include <drm/drm_connector.h>
> > +#include <drm/drm_crtc.h>
> > +#include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_panel.h>
> > +
> > +#include <video/mipi_display.h>
> > +
> > +struct kingdisplay_panel;
> > +
> > +struct panel_desc {
> > +     const struct drm_display_mode *modes;
> > +     unsigned int bpc;
> > +
> > +     /**
> > +      * @width_mm: width of the panel's active display area
> > +      * @height_mm: height of the panel's active display area
> > +      */
> > +     struct {
> > +             unsigned int width_mm;
> > +             unsigned int height_mm;
> > +     } size;
> > +
> > +     unsigned long mode_flags;
> > +     enum mipi_dsi_pixel_format format;
> > +     const struct panel_init_cmd *init_cmds;
> > +     int (*init)(struct kingdisplay_panel *kingdisplay);
> > +     unsigned int lanes;
> > +     bool discharge_on_disable;
> > +     bool lp11_before_reset;
> > +};
> > +
> > +struct kingdisplay_panel {
> > +     struct drm_panel base;
> > +     struct mipi_dsi_device *dsi;
> > +
> > +     const struct panel_desc *desc;
> > +
> > +     enum drm_panel_orientation orientation;
> > +     struct regulator *pp3300;
> > +     struct gpio_desc *enable_gpio;
> > +};
> > +
> > +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> > +{
> > +     struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> > +
> > +     /* T5:HWreset to init_code >= 50ms */
> > +     msleep(50);
> > +
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> Looking at the init sequence, I'm pretty confident this panel uses a
> Jadard JD 9365 driver IC. It's probably worth adding it to
> panel-jadard-jd9365da instead of adding a completly new driver.
>
> Alex
> > +     if (dsi_ctx.accum_err)
> > +             return dsi_ctx.accum_err;
> > +
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> > +     if (dsi_ctx.accum_err)
> > +             return dsi_ctx.accum_err;
> > +
> > +     msleep(120);
> > +
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> > +     if (dsi_ctx.accum_err)
> > +             return dsi_ctx.accum_err;
> > +
> > +     msleep(20);
> > +
> > +     return 0;
> > +};
> > +
> > +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> > +{
> > +     return container_of(panel, struct kingdisplay_panel, base);
> > +}
> > +
> > +static int kingdisplay_panel_disable(struct drm_panel *panel)
> > +{
> > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > +     int err;
> > +
> > +     kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> > +
> > +     msleep(100);
> > +
> > +     err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
> > +     if (err < 0)
> > +             dev_err(panel->dev, "failed to set display off: %d\n", err);
> > +
> > +     msleep(50);
> > +
> > +     err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
> > +     if (err < 0) {
> > +             dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
> > +             return err;
> > +     }
> > +
> > +     msleep(120);
> > +
> > +     return 0;
> > +}
> > +
> > +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
> > +{
> > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > +     int err;
> > +
> > +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
> > +
> > +     /* T15: 2ms */
> > +     usleep_range(1000, 2000);
> > +
> > +     err = regulator_disable(kingdisplay->pp3300);
> > +     if (err < 0)
> > +             return err;
> > +
> > +     return 0;
> > +}
> > +
> > +static int kingdisplay_panel_prepare(struct drm_panel *panel)
> > +{
> > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > +     int err;
> > +
> > +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > +
> > +     err = regulator_enable(kingdisplay->pp3300);
> > +     if (err < 0)
> > +             return err;
> > +
> > +     /* T1:Vdd to mipi_lp >= 0ms */
> > +     usleep_range(5000, 6000);
> > +
> > +     if (kingdisplay->desc->lp11_before_reset) {
> > +             err = mipi_dsi_dcs_nop(kingdisplay->dsi);
> > +             if (err < 0)
> > +                     goto poweroff;
> > +
> > +             usleep_range(1000, 2000);
> > +     }
> > +
> > +     /* T2: 10ms, T1 + T2 > 60ms */
> > +     msleep(60);
> > +
> > +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
> > +
> > +     err = kingdisplay->desc->init(kingdisplay);
> > +     if (err < 0)
> > +             goto poweroff;
> > +
> > +     return 0;
> > +
> > +poweroff:
> > +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > +             /* T6: 2ms */
> > +     usleep_range(1000, 2000);
> > +     regulator_disable(kingdisplay->pp3300);
> > +
> > +     return err;
> > +}
> > +
> > +static int kingdisplay_panel_enable(struct drm_panel *panel)
> > +{
> > +     msleep(130);
> > +     return 0;
> > +}
> > +
> > +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
> > +     .clock = 70595,
> > +     .hdisplay = 800,
> > +     .hsync_start = 800 + 30,
> > +     .hsync_end = 800 + 30 + 30,
> > +     .htotal = 800 + 30 + 30 + 30,
> > +     .vdisplay = 1280,
> > +     .vsync_start = 1280 + 30,
> > +     .vsync_end = 1280 + 30 + 4,
> > +     .vtotal = 1280 + 30 + 4 + 8,
> > +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> > +};
> > +
> > +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> > +     .modes = &kingdisplay_kd101ne3_40ti_default_mode,
> > +     .bpc = 8,
> > +     .size = {
> > +             .width_mm = 135,
> > +             .height_mm = 216,
> > +     },
> > +     .lanes = 4,
> > +     .format = MIPI_DSI_FMT_RGB888,
> > +     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> > +                   MIPI_DSI_MODE_LPM,
> > +     .init = kingdisplay_kd101ne3_init,
> > +     .lp11_before_reset = true,
> > +};
> > +
> > +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> > +                            struct drm_connector *connector)
> > +{
> > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > +     const struct drm_display_mode *m = kingdisplay->desc->modes;
> > +     struct drm_display_mode *mode;
> > +
> > +     mode = drm_mode_duplicate(connector->dev, m);
> > +     if (!mode) {
> > +             dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
> > +                     m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
> > +             return -ENOMEM;
> > +     }
> > +
> > +     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> > +     drm_mode_set_name(mode);
> > +     drm_mode_probed_add(connector, mode);
> > +
> > +     connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
> > +     connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
> > +     connector->display_info.bpc = kingdisplay->desc->bpc;
> > +
> > +     return 1;
> > +}
> > +
> > +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
> > +{
> > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > +
> > +     return kingdisplay->orientation;
> > +}
> > +
> > +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
> > +     .disable = kingdisplay_panel_disable,
> > +     .unprepare = kingdisplay_panel_unprepare,
> > +     .prepare = kingdisplay_panel_prepare,
> > +     .enable = kingdisplay_panel_enable,
> > +     .get_modes = kingdisplay_panel_get_modes,
> > +     .get_orientation = kingdisplay_panel_get_orientation,
> > +};
> > +
> > +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
> > +{
> > +     struct device *dev = &kingdisplay->dsi->dev;
> > +     int err;
> > +
> > +     kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
> > +     if (IS_ERR(kingdisplay->pp3300))
> > +             return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
> > +                                  "Cannot get pp3300\n");
> > +
> > +     kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> > +     if (IS_ERR(kingdisplay->enable_gpio))
> > +             return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
> > +                                  "Cannot get enable GPIO\n");
> > +
> > +     drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
> > +                    DRM_MODE_CONNECTOR_DSI);
> > +
> > +     err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
> > +     if (err < 0) {
> > +             dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
> > +             return err;
> > +     }
> > +
> > +     err = drm_panel_of_backlight(&kingdisplay->base);
> > +     if (err)
> > +             return err;
> > +
> > +     kingdisplay->base.funcs = &kingdisplay_panel_funcs;
> > +     kingdisplay->base.dev = &kingdisplay->dsi->dev;
> > +
> > +     drm_panel_add(&kingdisplay->base);
> > +
> > +     return 0;
> > +}
> > +
> > +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
> > +{
> > +     struct kingdisplay_panel *kingdisplay;
> > +     int ret;
> > +     const struct panel_desc *desc;
> > +
> > +     kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
> > +     if (!kingdisplay)
> > +             return -ENOMEM;
> > +
> > +     desc = of_device_get_match_data(&dsi->dev);
> > +     dsi->lanes = desc->lanes;
> > +     dsi->format = desc->format;
> > +     dsi->mode_flags = desc->mode_flags;
> > +     kingdisplay->desc = desc;
> > +     kingdisplay->dsi = dsi;
> > +     ret = kingdisplay_panel_add(kingdisplay);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     mipi_dsi_set_drvdata(dsi, kingdisplay);
> > +
> > +     ret = mipi_dsi_attach(dsi);
> > +     if (ret)
> > +             drm_panel_remove(&kingdisplay->base);
> > +
> > +     return ret;
> > +}
> > +
> > +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
> > +{
> > +     struct kingdisplay_panel *kingdisplay = 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);
> > +
> > +     if (kingdisplay->base.dev)
> > +             drm_panel_remove(&kingdisplay->base);
> > +}
> > +
> > +static const struct of_device_id kingdisplay_of_match[] = {
> > +     { .compatible = "kingdisplay,kd101ne3-40ti",
> > +       .data = &kingdisplay_kd101ne3_40ti_desc
> > +     },
> > +     { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> > +
> > +static struct mipi_dsi_driver kingdisplay_panel_driver = {
> > +     .driver = {
> > +             .name = "panel-kingdisplay-kd101ne3",
> > +             .of_match_table = kingdisplay_of_match,
> > +     },
> > +     .probe = kingdisplay_panel_probe,
> > +     .remove = kingdisplay_panel_remove,
> > +};
> > +module_mipi_dsi_driver(kingdisplay_panel_driver);
> > +
> > +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
> > +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
> > +MODULE_LICENSE("GPL v2");
>

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

* Re: [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support
  2024-06-07 11:38     ` zhaoxiong lv
@ 2024-06-07 11:48       ` Dmitry Baryshkov
  0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2024-06-07 11:48 UTC (permalink / raw)
  To: zhaoxiong lv
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

On Fri, 7 Jun 2024 at 14:38, zhaoxiong lv
<lvzhaoxiong@huaqin.corp-partner.google.com> wrote:
>
> hi Dmitry Baryshkov
>
> Because this is a separate mipi dsi driver, I did not put it in
> panel-sample-dsi.yaml.

Driver and bindings are two separate things. Bindings describe the
hardware. If there is no other reason to have a separate bindings
document, please use panel-simple-dsi.yaml.

Also please don't top-post in public mailing lists.

>
>
> On Sun, Jun 2, 2024 at 12:28 AM Dmitry Baryshkov
> <dmitry.baryshkov@linaro.org> wrote:
> >
> > On Sat, Jun 01, 2024 at 04:45:25PM +0800, Zhaoxiong Lv wrote:
> > > Create a new dt-scheam for the kd101ne3-40ti.
> > > The bias IC of this kindisplay-kd101ne3 panel is placed
> > > on the panel side, so when the panel is powered on,
> > > there is no need to control AVDD and AVEE in the driver.
> > >
> > > Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > > ---
> > >
> > > Chage since V2:
> > >
> > > -  Drop some properties that have already been defined in panel-common.
> > > -  The header file 'dt-bindings/gpio/gpio.h' is not used, delete it
> > >
> > > V1: https://lore.kernel.org/all/20240418081548.12160-2-lvzhaoxiong@huaqin.corp-partner.google.com/
> > >
> > > ---
> > >  .../panel/kingdisplay,kd101ne3-40ti.yaml      | 59 +++++++++++++++++++
> > >  1 file changed, 59 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> > > new file mode 100644
> > > index 000000000000..b0cf12bb727d
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd101ne3-40ti.yaml
> > > @@ -0,0 +1,59 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/display/panel/kingdisplay,kd101ne3-40ti.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Kingdisplay KD101NE3-40TI based MIPI-DSI panels
> > > +
> > > +maintainers:
> > > +  - Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> >
> > Any reason for using a separate bindings instead of extending
> > panel-simple-dsi.yaml ?
> >
> > > +
> > > +allOf:
> > > +  - $ref: panel-common.yaml#
> > > +
> > > +properties:
> > > +  compatible:
> > > +    items:
> > > +      - enum:
> > > +          - kingdisplay,kd101ne3-40ti
> > > +
> > > +  reg:
> > > +    description: the virtual channel number of a DSI peripheral
> > > +
> > > +  pp3300-supply:
> > > +    description: core voltage supply
> > > +
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +  - pp3300-supply
> > > +  - enable-gpios
> > > +  - backlight
> > > +  - port
> > > +
> > > +unevaluatedProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    dsi {
> > > +        #address-cells = <1>;
> > > +        #size-cells = <0>;
> > > +        panel: panel@0 {
> > > +            compatible = "kingdisplay,kd101ne3-40ti";
> > > +            reg = <0>;
> > > +            enable-gpios = <&pio 98 0>;
> > > +            pinctrl-names = "default";
> > > +            pinctrl-0 = <&panel_pins_default>;
> > > +            pp3300-supply = <&en_pp6000_mipi_disp>;
> > > +            backlight = <&backlight_lcd0>;
> > > +            rotation = <90>;
> > > +            port {
> > > +                panel_in: endpoint {
> > > +                    remote-endpoint = <&dsi_out>;
> > > +                };
> > > +            };
> > > +        };
> > > +    };
> > > +
> > > +...
> > > --
> > > 2.17.1
> > >
> >
> > --
> > With best wishes
> > Dmitry



-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 4/4] drm/panel: starry: add new panel driver
  2024-06-01 16:26   ` Dmitry Baryshkov
@ 2024-06-07 11:51     ` zhaoxiong lv
  2024-06-07 12:04       ` Dmitry Baryshkov
  0 siblings, 1 reply; 21+ messages in thread
From: zhaoxiong lv @ 2024-06-07 11:51 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

hi Dmitry

These two panels are not the same IC but their timing is the same,
only the init cmd and panel parameters are different, so I made it
compatible on the kingdisplay driver.

Similar to this driver:  panel-boe-tv101wum-nl6.c

thanks

On Sun, Jun 2, 2024 at 12:26 AM Dmitry Baryshkov
<dmitry.baryshkov@linaro.org> wrote:
>
> On Sat, Jun 01, 2024 at 04:45:28PM +0800, Zhaoxiong Lv wrote:
> > This Starry panel has the same timing as the Kingdisplay panel,
> > so add starry configuration in the Kingdisplay driver.
>
> Do these two panels share the same driver IC? Programming sequences do
> not seem common, so it might be better to have a separate driver for
> this panel.
>
> >
> > Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > ---
> >
> > Chage since V2:
> >
> > -  Add compatible for Starry er88577 in panel-kingdisplay-kd101ne3 drivers.
> >
> > ---
> >  .../drm/panel/panel-kingdisplay-kd101ne3.c    | 92 +++++++++++++++++++
> >  1 file changed, 92 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > index 8994a1c9afb5..b614d28475a6 100644
> > --- a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > @@ -267,6 +267,67 @@ static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> >       return 0;
> >  };
> >
> > +static int starry_er88577_init(struct kingdisplay_panel *kingdisplay)
> > +{
> > +     struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> > +
> > +     /* T5:HWreset to init_code >= 120ms */
> > +     msleep(120);
> > +
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xab, 0xba);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0xba, 0xab);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x10, 0x01, 0x47, 0xff);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x0c, 0x14, 0x04, 0x50, 0x50, 0x14);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x56, 0x53, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x33, 0x30, 0x04);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x05, 0x12, 0x29, 0x49, 0x40);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31,
> > +                                  0x1a, 0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38, 0x34, 0x26,
> > +                                  0x0e, 0x06, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31, 0x1a,
> > +                                  0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38, 0x34, 0x26, 0x0e,
> > +                                  0x06);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xcc, 0x76, 0x12, 0x34, 0x44, 0x44, 0x44,
> > +                                  0x44, 0x98, 0x04, 0x98, 0x04, 0x0f, 0x00, 0x00, 0xc1);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x54, 0x94, 0x02, 0x85, 0x9f, 0x00, 0x6f,
> > +                                  0x00, 0x54, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, 0x22,
> > +                                  0x20, 0x44, 0xff, 0x18, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x87, 0x47, 0x05, 0x05, 0x1c, 0x1c, 0x1d,
> > +                                  0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f, 0x0f, 0x0f, 0x0d, 0x0d,
> > +                                  0x13, 0x13, 0x11, 0x11, 0x24);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x06, 0x06, 0x04, 0x04, 0x1c, 0x1c, 0x1d,
> > +                                  0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f, 0x0e, 0x0e, 0x0c, 0x0c,
> > +                                  0x12, 0x12, 0x10, 0x10, 0x24);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0xcb, 0x43);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x0e, 0x4b, 0x4b, 0x20, 0x19, 0x6b, 0x06,
> > +                                  0xb3);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0xe3, 0x2b, 0x38, 0x08);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x00, 0x01, 0x00, 0x0e, 0x04, 0x44, 0x08,
> > +                                  0x10, 0x00, 0x00, 0x00);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x80, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff,
> > +                                  0xff);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x12, 0x03, 0x20, 0x00, 0xff);
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x00);
> > +     if (dsi_ctx.accum_err)
> > +             return dsi_ctx.accum_err;
> > +
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> > +     if (dsi_ctx.accum_err)
> > +             return dsi_ctx.accum_err;
> > +
> > +     msleep(120);
> > +
> > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> > +     if (dsi_ctx.accum_err)
> > +             return dsi_ctx.accum_err;
> > +
> > +     msleep(20);
>
> Most of the comments from the patch 2 apply:
> - drop conditions
> - use mipi_dsi_dcs_set_display_on_multi(),
>   mipi_dsi_dcs_exit_sleep_mode_multi() and mipi_dsi_msleep().
>
> > +
> > +     return 0;
> > +};
> > +
> >  static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> >  {
> >       return container_of(panel, struct kingdisplay_panel, base);
> > @@ -391,6 +452,34 @@ static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> >       .lp11_before_reset = true,
> >  };
> >
> > +static const struct drm_display_mode starry_er88577_default_mode = {
> > +     .clock = 77380,
> > +     .hdisplay = 800,
> > +     .hsync_start = 800 + 80,
> > +     .hsync_end = 800 + 80 + 20,
> > +     .htotal = 800 + 80 + 20 + 80,
> > +     .vdisplay = 1280,
> > +     .vsync_start = 1280 + 20,
> > +     .vsync_end = 1280 + 20 + 4,
> > +     .vtotal = 1280 + 20 + 4 + 12,
> > +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> > +};
> > +
> > +static const struct panel_desc starry_er88577_desc = {
> > +     .modes = &starry_er88577_default_mode,
> > +     .bpc = 8,
> > +     .size = {
> > +             .width_mm = 135,
> > +             .height_mm = 216,
> > +     },
> > +     .lanes = 4,
> > +     .format = MIPI_DSI_FMT_RGB888,
> > +     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> > +                   MIPI_DSI_MODE_LPM,
> > +     .init = starry_er88577_init,
> > +     .lp11_before_reset = true,
> > +};
> > +
> >  static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> >                              struct drm_connector *connector)
> >  {
> > @@ -514,6 +603,9 @@ static const struct of_device_id kingdisplay_of_match[] = {
> >       { .compatible = "kingdisplay,kd101ne3-40ti",
> >         .data = &kingdisplay_kd101ne3_40ti_desc
> >       },
> > +     { .compatible = "starry,er88577",
> > +       .data = &starry_er88577_desc
> > +     },
> >       { /* sentinel */ }
> >  };
> >  MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> > --
> > 2.17.1
> >
>
> --
> With best wishes
> Dmitry

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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-07 11:44     ` zhaoxiong lv
@ 2024-06-07 12:01       ` Dmitry Baryshkov
  2024-06-07 12:41         ` Alex Bee
  0 siblings, 1 reply; 21+ messages in thread
From: Dmitry Baryshkov @ 2024-06-07 12:01 UTC (permalink / raw)
  To: zhaoxiong lv
  Cc: Alex Bee, dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt,
	jikos, benjamin.tissoires, dianders, hsinyi, dri-devel,
	devicetree, linux-kernel

On Fri, Jun 07, 2024 at 07:44:33PM +0800, zhaoxiong lv wrote:
> hi Alex Bee
> 
> I compared these two drivers. Although the control IC is the same, the
> panel is different, and the init_cmd and timing are also slightly
> different, so I added a separate driver.

But it obviously uses the same structure as the panel-jadard. Please
use existing driver instead of creating a completely new one (which you
happily overload with an unrelated panel).

> 
> thanks
> 
> On Sun, Jun 2, 2024 at 1:07 PM Alex Bee <knaerzche@gmail.com> wrote:
> >
> > Am 01.06.24 um 10:45 schrieb Zhaoxiong Lv:
> >
> > Hi Zhaoxiong,
> >
> > > The bias IC of this kindisplay-kd101ne3 panel is placed
> > > on the panel side, so when the panel is powered on,
> > > there is no need to control AVDD and AVEE in the driver,
> > > only 3.3v and reset are needed.
> > >
> > > Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > > ---
> > >
> > > Chage since V2:
> > >
> > > -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
> > > -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
> > > -  and drop kingdisplay_panel_enter_sleep_mode().
> > > -  3. If prepare fails, disable GPIO before regulators.
> > > -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
> > > -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
> > >
> > > ---
> > >   drivers/gpu/drm/panel/Kconfig                 |   9 +
> > >   drivers/gpu/drm/panel/Makefile                |   1 +
> > >   .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
> > >   3 files changed, 543 insertions(+)
> > >   create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > >
> > > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> > > index e54f6f5604ed..71669e990e8e 100644
> > > --- a/drivers/gpu/drm/panel/Kconfig
> > > +++ b/drivers/gpu/drm/panel/Kconfig
> > > @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
> > >         24 bit RGB per pixel. It provides a MIPI DSI interface to
> > >         the host and has a built-in LED backlight.
> > >
> > > +config DRM_PANEL_KINGDISPLAY_KD101NE3
> > > +     tristate "Kingdisplay kd101ne3 panel"
> > > +     depends on OF
> > > +     depends on DRM_MIPI_DSI
> > > +     depends on BACKLIGHT_CLASS_DEVICE
> > > +     help
> > > +       Say Y here if you want to enable support for the kingdisplay kd101ne3
> > > +       4-lane 800x1280 MIPI DSI panel.
> > > +
> > >   config DRM_PANEL_LEADTEK_LTK050H3146W
> > >       tristate "Leadtek LTK050H3146W panel"
> > >       depends on OF
> > > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> > > index f0203f6e02f4..4576c9fe33d9 100644
> > > --- a/drivers/gpu/drm/panel/Makefile
> > > +++ b/drivers/gpu/drm/panel/Makefile
> > > @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
> > >   obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
> > >   obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
> > >   obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
> > > +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
> > >   obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
> > >   obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
> > >   obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> > > diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > > new file mode 100644
> > > index 000000000000..8994a1c9afb5
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > > @@ -0,0 +1,533 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/* Panels based on the JD9365DA display controller.
> > > + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > > + */
> > > +
> > > +#include <linux/delay.h>
> > > +#include <linux/gpio/consumer.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/regulator/consumer.h>
> > > +
> > > +#include <drm/drm_connector.h>
> > > +#include <drm/drm_crtc.h>
> > > +#include <drm/drm_mipi_dsi.h>
> > > +#include <drm/drm_panel.h>
> > > +
> > > +#include <video/mipi_display.h>
> > > +
> > > +struct kingdisplay_panel;
> > > +
> > > +struct panel_desc {
> > > +     const struct drm_display_mode *modes;
> > > +     unsigned int bpc;
> > > +
> > > +     /**
> > > +      * @width_mm: width of the panel's active display area
> > > +      * @height_mm: height of the panel's active display area
> > > +      */
> > > +     struct {
> > > +             unsigned int width_mm;
> > > +             unsigned int height_mm;
> > > +     } size;
> > > +
> > > +     unsigned long mode_flags;
> > > +     enum mipi_dsi_pixel_format format;
> > > +     const struct panel_init_cmd *init_cmds;
> > > +     int (*init)(struct kingdisplay_panel *kingdisplay);
> > > +     unsigned int lanes;
> > > +     bool discharge_on_disable;
> > > +     bool lp11_before_reset;
> > > +};
> > > +
> > > +struct kingdisplay_panel {
> > > +     struct drm_panel base;
> > > +     struct mipi_dsi_device *dsi;
> > > +
> > > +     const struct panel_desc *desc;
> > > +
> > > +     enum drm_panel_orientation orientation;
> > > +     struct regulator *pp3300;
> > > +     struct gpio_desc *enable_gpio;
> > > +};
> > > +
> > > +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> > > +{
> > > +     struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> > > +
> > > +     /* T5:HWreset to init_code >= 50ms */
> > > +     msleep(50);
> > > +
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> > Looking at the init sequence, I'm pretty confident this panel uses a
> > Jadard JD 9365 driver IC. It's probably worth adding it to
> > panel-jadard-jd9365da instead of adding a completly new driver.
> >
> > Alex
> > > +     if (dsi_ctx.accum_err)
> > > +             return dsi_ctx.accum_err;
> > > +
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> > > +     if (dsi_ctx.accum_err)
> > > +             return dsi_ctx.accum_err;
> > > +
> > > +     msleep(120);
> > > +
> > > +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> > > +     if (dsi_ctx.accum_err)
> > > +             return dsi_ctx.accum_err;
> > > +
> > > +     msleep(20);
> > > +
> > > +     return 0;
> > > +};
> > > +
> > > +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> > > +{
> > > +     return container_of(panel, struct kingdisplay_panel, base);
> > > +}
> > > +
> > > +static int kingdisplay_panel_disable(struct drm_panel *panel)
> > > +{
> > > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > > +     int err;
> > > +
> > > +     kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> > > +
> > > +     msleep(100);
> > > +
> > > +     err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
> > > +     if (err < 0)
> > > +             dev_err(panel->dev, "failed to set display off: %d\n", err);
> > > +
> > > +     msleep(50);
> > > +
> > > +     err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
> > > +     if (err < 0) {
> > > +             dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
> > > +             return err;
> > > +     }
> > > +
> > > +     msleep(120);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
> > > +{
> > > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > > +     int err;
> > > +
> > > +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
> > > +
> > > +     /* T15: 2ms */
> > > +     usleep_range(1000, 2000);
> > > +
> > > +     err = regulator_disable(kingdisplay->pp3300);
> > > +     if (err < 0)
> > > +             return err;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int kingdisplay_panel_prepare(struct drm_panel *panel)
> > > +{
> > > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > > +     int err;
> > > +
> > > +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > > +
> > > +     err = regulator_enable(kingdisplay->pp3300);
> > > +     if (err < 0)
> > > +             return err;
> > > +
> > > +     /* T1:Vdd to mipi_lp >= 0ms */
> > > +     usleep_range(5000, 6000);
> > > +
> > > +     if (kingdisplay->desc->lp11_before_reset) {
> > > +             err = mipi_dsi_dcs_nop(kingdisplay->dsi);
> > > +             if (err < 0)
> > > +                     goto poweroff;
> > > +
> > > +             usleep_range(1000, 2000);
> > > +     }
> > > +
> > > +     /* T2: 10ms, T1 + T2 > 60ms */
> > > +     msleep(60);
> > > +
> > > +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
> > > +
> > > +     err = kingdisplay->desc->init(kingdisplay);
> > > +     if (err < 0)
> > > +             goto poweroff;
> > > +
> > > +     return 0;
> > > +
> > > +poweroff:
> > > +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > > +             /* T6: 2ms */
> > > +     usleep_range(1000, 2000);
> > > +     regulator_disable(kingdisplay->pp3300);
> > > +
> > > +     return err;
> > > +}
> > > +
> > > +static int kingdisplay_panel_enable(struct drm_panel *panel)
> > > +{
> > > +     msleep(130);
> > > +     return 0;
> > > +}
> > > +
> > > +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
> > > +     .clock = 70595,
> > > +     .hdisplay = 800,
> > > +     .hsync_start = 800 + 30,
> > > +     .hsync_end = 800 + 30 + 30,
> > > +     .htotal = 800 + 30 + 30 + 30,
> > > +     .vdisplay = 1280,
> > > +     .vsync_start = 1280 + 30,
> > > +     .vsync_end = 1280 + 30 + 4,
> > > +     .vtotal = 1280 + 30 + 4 + 8,
> > > +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> > > +};
> > > +
> > > +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> > > +     .modes = &kingdisplay_kd101ne3_40ti_default_mode,
> > > +     .bpc = 8,
> > > +     .size = {
> > > +             .width_mm = 135,
> > > +             .height_mm = 216,
> > > +     },
> > > +     .lanes = 4,
> > > +     .format = MIPI_DSI_FMT_RGB888,
> > > +     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> > > +                   MIPI_DSI_MODE_LPM,
> > > +     .init = kingdisplay_kd101ne3_init,
> > > +     .lp11_before_reset = true,
> > > +};
> > > +
> > > +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> > > +                            struct drm_connector *connector)
> > > +{
> > > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > > +     const struct drm_display_mode *m = kingdisplay->desc->modes;
> > > +     struct drm_display_mode *mode;
> > > +
> > > +     mode = drm_mode_duplicate(connector->dev, m);
> > > +     if (!mode) {
> > > +             dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
> > > +                     m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
> > > +             return -ENOMEM;
> > > +     }
> > > +
> > > +     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> > > +     drm_mode_set_name(mode);
> > > +     drm_mode_probed_add(connector, mode);
> > > +
> > > +     connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
> > > +     connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
> > > +     connector->display_info.bpc = kingdisplay->desc->bpc;
> > > +
> > > +     return 1;
> > > +}
> > > +
> > > +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
> > > +{
> > > +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > > +
> > > +     return kingdisplay->orientation;
> > > +}
> > > +
> > > +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
> > > +     .disable = kingdisplay_panel_disable,
> > > +     .unprepare = kingdisplay_panel_unprepare,
> > > +     .prepare = kingdisplay_panel_prepare,
> > > +     .enable = kingdisplay_panel_enable,
> > > +     .get_modes = kingdisplay_panel_get_modes,
> > > +     .get_orientation = kingdisplay_panel_get_orientation,
> > > +};
> > > +
> > > +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
> > > +{
> > > +     struct device *dev = &kingdisplay->dsi->dev;
> > > +     int err;
> > > +
> > > +     kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
> > > +     if (IS_ERR(kingdisplay->pp3300))
> > > +             return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
> > > +                                  "Cannot get pp3300\n");
> > > +
> > > +     kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> > > +     if (IS_ERR(kingdisplay->enable_gpio))
> > > +             return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
> > > +                                  "Cannot get enable GPIO\n");
> > > +
> > > +     drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
> > > +                    DRM_MODE_CONNECTOR_DSI);
> > > +
> > > +     err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
> > > +     if (err < 0) {
> > > +             dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
> > > +             return err;
> > > +     }
> > > +
> > > +     err = drm_panel_of_backlight(&kingdisplay->base);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     kingdisplay->base.funcs = &kingdisplay_panel_funcs;
> > > +     kingdisplay->base.dev = &kingdisplay->dsi->dev;
> > > +
> > > +     drm_panel_add(&kingdisplay->base);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
> > > +{
> > > +     struct kingdisplay_panel *kingdisplay;
> > > +     int ret;
> > > +     const struct panel_desc *desc;
> > > +
> > > +     kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
> > > +     if (!kingdisplay)
> > > +             return -ENOMEM;
> > > +
> > > +     desc = of_device_get_match_data(&dsi->dev);
> > > +     dsi->lanes = desc->lanes;
> > > +     dsi->format = desc->format;
> > > +     dsi->mode_flags = desc->mode_flags;
> > > +     kingdisplay->desc = desc;
> > > +     kingdisplay->dsi = dsi;
> > > +     ret = kingdisplay_panel_add(kingdisplay);
> > > +     if (ret < 0)
> > > +             return ret;
> > > +
> > > +     mipi_dsi_set_drvdata(dsi, kingdisplay);
> > > +
> > > +     ret = mipi_dsi_attach(dsi);
> > > +     if (ret)
> > > +             drm_panel_remove(&kingdisplay->base);
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
> > > +{
> > > +     struct kingdisplay_panel *kingdisplay = 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);
> > > +
> > > +     if (kingdisplay->base.dev)
> > > +             drm_panel_remove(&kingdisplay->base);
> > > +}
> > > +
> > > +static const struct of_device_id kingdisplay_of_match[] = {
> > > +     { .compatible = "kingdisplay,kd101ne3-40ti",
> > > +       .data = &kingdisplay_kd101ne3_40ti_desc
> > > +     },
> > > +     { /* sentinel */ }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> > > +
> > > +static struct mipi_dsi_driver kingdisplay_panel_driver = {
> > > +     .driver = {
> > > +             .name = "panel-kingdisplay-kd101ne3",
> > > +             .of_match_table = kingdisplay_of_match,
> > > +     },
> > > +     .probe = kingdisplay_panel_probe,
> > > +     .remove = kingdisplay_panel_remove,
> > > +};
> > > +module_mipi_dsi_driver(kingdisplay_panel_driver);
> > > +
> > > +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
> > > +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
> > > +MODULE_LICENSE("GPL v2");
> >

-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 4/4] drm/panel: starry: add new panel driver
  2024-06-07 11:51     ` zhaoxiong lv
@ 2024-06-07 12:04       ` Dmitry Baryshkov
  0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2024-06-07 12:04 UTC (permalink / raw)
  To: zhaoxiong lv
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel

On Fri, 7 Jun 2024 at 14:51, zhaoxiong lv
<lvzhaoxiong@huaqin.corp-partner.google.com> wrote:
>
> hi Dmitry
>
> These two panels are not the same IC but their timing is the same,
> only the init cmd and panel parameters are different, so I made it
> compatible on the kingdisplay driver.

We usually merge drivers by the driver IC, not by the timings.

Please stop top-posting.

>
> Similar to this driver:  panel-boe-tv101wum-nl6.c
>
> thanks
>
> On Sun, Jun 2, 2024 at 12:26 AM Dmitry Baryshkov
> <dmitry.baryshkov@linaro.org> wrote:
> >
> > On Sat, Jun 01, 2024 at 04:45:28PM +0800, Zhaoxiong Lv wrote:
> > > This Starry panel has the same timing as the Kingdisplay panel,
> > > so add starry configuration in the Kingdisplay driver.
> >
> > Do these two panels share the same driver IC? Programming sequences do
> > not seem common, so it might be better to have a separate driver for
> > this panel.


-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-07 12:01       ` Dmitry Baryshkov
@ 2024-06-07 12:41         ` Alex Bee
  2024-06-12 11:35           ` zhaoxiong lv
  0 siblings, 1 reply; 21+ messages in thread
From: Alex Bee @ 2024-06-07 12:41 UTC (permalink / raw)
  To: Dmitry Baryshkov, zhaoxiong lv
  Cc: dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt, jikos,
	benjamin.tissoires, dianders, hsinyi, dri-devel, devicetree,
	linux-kernel


Am 07.06.24 um 14:01 schrieb Dmitry Baryshkov:
> On Fri, Jun 07, 2024 at 07:44:33PM +0800, zhaoxiong lv wrote:
>> hi Alex Bee
>>
>> I compared these two drivers. Although the control IC is the same, the
>> panel is different, and the init_cmd and timing are also slightly
>> different, so I added a separate driver.
> But it obviously uses the same structure as the panel-jadard. Please
> use existing driver instead of creating a completely new one (which you
> happily overload with an unrelated panel).
>
+1

panel-jadard already supports different panels with different
init-sequences and they can be set per panel-type (compatible). If you need
different reset-/enable timings (what I doubt) you'll have to extend struct
jadard_panel_desc. In any case you'll have to put dsi->mode_flags in there
as your panel uses MIPI_DSI_MODE_LPM what the currently supported don't
need.

Alex.

>> thanks
>>
>> On Sun, Jun 2, 2024 at 1:07 PM Alex Bee <knaerzche@gmail.com> wrote:
>>> Am 01.06.24 um 10:45 schrieb Zhaoxiong Lv:
>>>
>>> Hi Zhaoxiong,
>>>
>>>> The bias IC of this kindisplay-kd101ne3 panel is placed
>>>> on the panel side, so when the panel is powered on,
>>>> there is no need to control AVDD and AVEE in the driver,
>>>> only 3.3v and reset are needed.
>>>>
>>>> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
>>>> ---
>>>>
>>>> Chage since V2:
>>>>
>>>> -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
>>>> -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
>>>> -  and drop kingdisplay_panel_enter_sleep_mode().
>>>> -  3. If prepare fails, disable GPIO before regulators.
>>>> -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
>>>> -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
>>>>
>>>> ---
>>>>    drivers/gpu/drm/panel/Kconfig                 |   9 +
>>>>    drivers/gpu/drm/panel/Makefile                |   1 +
>>>>    .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
>>>>    3 files changed, 543 insertions(+)
>>>>    create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
>>>>
>>>> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
>>>> index e54f6f5604ed..71669e990e8e 100644
>>>> --- a/drivers/gpu/drm/panel/Kconfig
>>>> +++ b/drivers/gpu/drm/panel/Kconfig
>>>> @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
>>>>          24 bit RGB per pixel. It provides a MIPI DSI interface to
>>>>          the host and has a built-in LED backlight.
>>>>
>>>> +config DRM_PANEL_KINGDISPLAY_KD101NE3
>>>> +     tristate "Kingdisplay kd101ne3 panel"
>>>> +     depends on OF
>>>> +     depends on DRM_MIPI_DSI
>>>> +     depends on BACKLIGHT_CLASS_DEVICE
>>>> +     help
>>>> +       Say Y here if you want to enable support for the kingdisplay kd101ne3
>>>> +       4-lane 800x1280 MIPI DSI panel.
>>>> +
>>>>    config DRM_PANEL_LEADTEK_LTK050H3146W
>>>>        tristate "Leadtek LTK050H3146W panel"
>>>>        depends on OF
>>>> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
>>>> index f0203f6e02f4..4576c9fe33d9 100644
>>>> --- a/drivers/gpu/drm/panel/Makefile
>>>> +++ b/drivers/gpu/drm/panel/Makefile
>>>> @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
>>>>    obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
>>>>    obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
>>>>    obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
>>>> +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
>>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
>>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
>>>>    obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
>>>> diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
>>>> new file mode 100644
>>>> index 000000000000..8994a1c9afb5
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
>>>> @@ -0,0 +1,533 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/* Panels based on the JD9365DA display controller.
>>>> + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
>>>> + */
>>>> +
>>>> +#include <linux/delay.h>
>>>> +#include <linux/gpio/consumer.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +
>>>> +#include <drm/drm_connector.h>
>>>> +#include <drm/drm_crtc.h>
>>>> +#include <drm/drm_mipi_dsi.h>
>>>> +#include <drm/drm_panel.h>
>>>> +
>>>> +#include <video/mipi_display.h>
>>>> +
>>>> +struct kingdisplay_panel;
>>>> +
>>>> +struct panel_desc {
>>>> +     const struct drm_display_mode *modes;
>>>> +     unsigned int bpc;
>>>> +
>>>> +     /**
>>>> +      * @width_mm: width of the panel's active display area
>>>> +      * @height_mm: height of the panel's active display area
>>>> +      */
>>>> +     struct {
>>>> +             unsigned int width_mm;
>>>> +             unsigned int height_mm;
>>>> +     } size;
>>>> +
>>>> +     unsigned long mode_flags;
>>>> +     enum mipi_dsi_pixel_format format;
>>>> +     const struct panel_init_cmd *init_cmds;
>>>> +     int (*init)(struct kingdisplay_panel *kingdisplay);
>>>> +     unsigned int lanes;
>>>> +     bool discharge_on_disable;
>>>> +     bool lp11_before_reset;
>>>> +};
>>>> +
>>>> +struct kingdisplay_panel {
>>>> +     struct drm_panel base;
>>>> +     struct mipi_dsi_device *dsi;
>>>> +
>>>> +     const struct panel_desc *desc;
>>>> +
>>>> +     enum drm_panel_orientation orientation;
>>>> +     struct regulator *pp3300;
>>>> +     struct gpio_desc *enable_gpio;
>>>> +};
>>>> +
>>>> +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
>>>> +{
>>>> +     struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
>>>> +
>>>> +     /* T5:HWreset to init_code >= 50ms */
>>>> +     msleep(50);
>>>> +
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
>>> Looking at the init sequence, I'm pretty confident this panel uses a
>>> Jadard JD 9365 driver IC. It's probably worth adding it to
>>> panel-jadard-jd9365da instead of adding a completly new driver.
>>>
>>> Alex
>>>> +     if (dsi_ctx.accum_err)
>>>> +             return dsi_ctx.accum_err;
>>>> +
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
>>>> +     if (dsi_ctx.accum_err)
>>>> +             return dsi_ctx.accum_err;
>>>> +
>>>> +     msleep(120);
>>>> +
>>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
>>>> +     if (dsi_ctx.accum_err)
>>>> +             return dsi_ctx.accum_err;
>>>> +
>>>> +     msleep(20);
>>>> +
>>>> +     return 0;
>>>> +};
>>>> +
>>>> +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
>>>> +{
>>>> +     return container_of(panel, struct kingdisplay_panel, base);
>>>> +}
>>>> +
>>>> +static int kingdisplay_panel_disable(struct drm_panel *panel)
>>>> +{
>>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
>>>> +     int err;
>>>> +
>>>> +     kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
>>>> +
>>>> +     msleep(100);
>>>> +
>>>> +     err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
>>>> +     if (err < 0)
>>>> +             dev_err(panel->dev, "failed to set display off: %d\n", err);
>>>> +
>>>> +     msleep(50);
>>>> +
>>>> +     err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
>>>> +     if (err < 0) {
>>>> +             dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
>>>> +             return err;
>>>> +     }
>>>> +
>>>> +     msleep(120);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
>>>> +{
>>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
>>>> +     int err;
>>>> +
>>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
>>>> +
>>>> +     /* T15: 2ms */
>>>> +     usleep_range(1000, 2000);
>>>> +
>>>> +     err = regulator_disable(kingdisplay->pp3300);
>>>> +     if (err < 0)
>>>> +             return err;
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int kingdisplay_panel_prepare(struct drm_panel *panel)
>>>> +{
>>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
>>>> +     int err;
>>>> +
>>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
>>>> +
>>>> +     err = regulator_enable(kingdisplay->pp3300);
>>>> +     if (err < 0)
>>>> +             return err;
>>>> +
>>>> +     /* T1:Vdd to mipi_lp >= 0ms */
>>>> +     usleep_range(5000, 6000);
>>>> +
>>>> +     if (kingdisplay->desc->lp11_before_reset) {
>>>> +             err = mipi_dsi_dcs_nop(kingdisplay->dsi);
>>>> +             if (err < 0)
>>>> +                     goto poweroff;
>>>> +
>>>> +             usleep_range(1000, 2000);
>>>> +     }
>>>> +
>>>> +     /* T2: 10ms, T1 + T2 > 60ms */
>>>> +     msleep(60);
>>>> +
>>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
>>>> +
>>>> +     err = kingdisplay->desc->init(kingdisplay);
>>>> +     if (err < 0)
>>>> +             goto poweroff;
>>>> +
>>>> +     return 0;
>>>> +
>>>> +poweroff:
>>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
>>>> +             /* T6: 2ms */
>>>> +     usleep_range(1000, 2000);
>>>> +     regulator_disable(kingdisplay->pp3300);
>>>> +
>>>> +     return err;
>>>> +}
>>>> +
>>>> +static int kingdisplay_panel_enable(struct drm_panel *panel)
>>>> +{
>>>> +     msleep(130);
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
>>>> +     .clock = 70595,
>>>> +     .hdisplay = 800,
>>>> +     .hsync_start = 800 + 30,
>>>> +     .hsync_end = 800 + 30 + 30,
>>>> +     .htotal = 800 + 30 + 30 + 30,
>>>> +     .vdisplay = 1280,
>>>> +     .vsync_start = 1280 + 30,
>>>> +     .vsync_end = 1280 + 30 + 4,
>>>> +     .vtotal = 1280 + 30 + 4 + 8,
>>>> +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
>>>> +};
>>>> +
>>>> +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
>>>> +     .modes = &kingdisplay_kd101ne3_40ti_default_mode,
>>>> +     .bpc = 8,
>>>> +     .size = {
>>>> +             .width_mm = 135,
>>>> +             .height_mm = 216,
>>>> +     },
>>>> +     .lanes = 4,
>>>> +     .format = MIPI_DSI_FMT_RGB888,
>>>> +     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
>>>> +                   MIPI_DSI_MODE_LPM,
>>>> +     .init = kingdisplay_kd101ne3_init,
>>>> +     .lp11_before_reset = true,
>>>> +};
>>>> +
>>>> +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
>>>> +                            struct drm_connector *connector)
>>>> +{
>>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
>>>> +     const struct drm_display_mode *m = kingdisplay->desc->modes;
>>>> +     struct drm_display_mode *mode;
>>>> +
>>>> +     mode = drm_mode_duplicate(connector->dev, m);
>>>> +     if (!mode) {
>>>> +             dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
>>>> +                     m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
>>>> +             return -ENOMEM;
>>>> +     }
>>>> +
>>>> +     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
>>>> +     drm_mode_set_name(mode);
>>>> +     drm_mode_probed_add(connector, mode);
>>>> +
>>>> +     connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
>>>> +     connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
>>>> +     connector->display_info.bpc = kingdisplay->desc->bpc;
>>>> +
>>>> +     return 1;
>>>> +}
>>>> +
>>>> +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
>>>> +{
>>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
>>>> +
>>>> +     return kingdisplay->orientation;
>>>> +}
>>>> +
>>>> +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
>>>> +     .disable = kingdisplay_panel_disable,
>>>> +     .unprepare = kingdisplay_panel_unprepare,
>>>> +     .prepare = kingdisplay_panel_prepare,
>>>> +     .enable = kingdisplay_panel_enable,
>>>> +     .get_modes = kingdisplay_panel_get_modes,
>>>> +     .get_orientation = kingdisplay_panel_get_orientation,
>>>> +};
>>>> +
>>>> +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
>>>> +{
>>>> +     struct device *dev = &kingdisplay->dsi->dev;
>>>> +     int err;
>>>> +
>>>> +     kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
>>>> +     if (IS_ERR(kingdisplay->pp3300))
>>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
>>>> +                                  "Cannot get pp3300\n");
>>>> +
>>>> +     kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
>>>> +     if (IS_ERR(kingdisplay->enable_gpio))
>>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
>>>> +                                  "Cannot get enable GPIO\n");
>>>> +
>>>> +     drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
>>>> +                    DRM_MODE_CONNECTOR_DSI);
>>>> +
>>>> +     err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
>>>> +     if (err < 0) {
>>>> +             dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
>>>> +             return err;
>>>> +     }
>>>> +
>>>> +     err = drm_panel_of_backlight(&kingdisplay->base);
>>>> +     if (err)
>>>> +             return err;
>>>> +
>>>> +     kingdisplay->base.funcs = &kingdisplay_panel_funcs;
>>>> +     kingdisplay->base.dev = &kingdisplay->dsi->dev;
>>>> +
>>>> +     drm_panel_add(&kingdisplay->base);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
>>>> +{
>>>> +     struct kingdisplay_panel *kingdisplay;
>>>> +     int ret;
>>>> +     const struct panel_desc *desc;
>>>> +
>>>> +     kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
>>>> +     if (!kingdisplay)
>>>> +             return -ENOMEM;
>>>> +
>>>> +     desc = of_device_get_match_data(&dsi->dev);
>>>> +     dsi->lanes = desc->lanes;
>>>> +     dsi->format = desc->format;
>>>> +     dsi->mode_flags = desc->mode_flags;
>>>> +     kingdisplay->desc = desc;
>>>> +     kingdisplay->dsi = dsi;
>>>> +     ret = kingdisplay_panel_add(kingdisplay);
>>>> +     if (ret < 0)
>>>> +             return ret;
>>>> +
>>>> +     mipi_dsi_set_drvdata(dsi, kingdisplay);
>>>> +
>>>> +     ret = mipi_dsi_attach(dsi);
>>>> +     if (ret)
>>>> +             drm_panel_remove(&kingdisplay->base);
>>>> +
>>>> +     return ret;
>>>> +}
>>>> +
>>>> +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
>>>> +{
>>>> +     struct kingdisplay_panel *kingdisplay = 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);
>>>> +
>>>> +     if (kingdisplay->base.dev)
>>>> +             drm_panel_remove(&kingdisplay->base);
>>>> +}
>>>> +
>>>> +static const struct of_device_id kingdisplay_of_match[] = {
>>>> +     { .compatible = "kingdisplay,kd101ne3-40ti",
>>>> +       .data = &kingdisplay_kd101ne3_40ti_desc
>>>> +     },
>>>> +     { /* sentinel */ }
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
>>>> +
>>>> +static struct mipi_dsi_driver kingdisplay_panel_driver = {
>>>> +     .driver = {
>>>> +             .name = "panel-kingdisplay-kd101ne3",
>>>> +             .of_match_table = kingdisplay_of_match,
>>>> +     },
>>>> +     .probe = kingdisplay_panel_probe,
>>>> +     .remove = kingdisplay_panel_remove,
>>>> +};
>>>> +module_mipi_dsi_driver(kingdisplay_panel_driver);
>>>> +
>>>> +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
>>>> +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
>>>> +MODULE_LICENSE("GPL v2");

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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-07 12:41         ` Alex Bee
@ 2024-06-12 11:35           ` zhaoxiong lv
  2024-06-12 11:39             ` zhaoxiong lv
  2024-06-12 13:01             ` Dmitry Baryshkov
  0 siblings, 2 replies; 21+ messages in thread
From: zhaoxiong lv @ 2024-06-12 11:35 UTC (permalink / raw)
  To: Alex Bee
  Cc: Dmitry Baryshkov, dmitry.torokhov, robh, krzysztof.kozlowski+dt,
	conor+dt, jikos, benjamin.tissoires, dianders, hsinyi, dri-devel,
	devicetree, linux-kernel

On Fri, Jun 7, 2024 at 8:41 PM Alex Bee <knaerzche@gmail.com> wrote:
>
>
> Am 07.06.24 um 14:01 schrieb Dmitry Baryshkov:
> > On Fri, Jun 07, 2024 at 07:44:33PM +0800, zhaoxiong lv wrote:
> >> hi Alex Bee
> >>
> >> I compared these two drivers. Although the control IC is the same, the
> >> panel is different, and the init_cmd and timing are also slightly
> >> different, so I added a separate driver.
> > But it obviously uses the same structure as the panel-jadard. Please
> > use existing driver instead of creating a completely new one (which you
> > happily overload with an unrelated panel).
> >
> +1
>
> panel-jadard already supports different panels with different
> init-sequences and they can be set per panel-type (compatible). If you need
> different reset-/enable timings (what I doubt) you'll have to extend struct
> jadard_panel_desc. In any case you'll have to put dsi->mode_flags in there
> as your panel uses MIPI_DSI_MODE_LPM what the currently supported don't
> need.

 hi Alex Bee/Dmitry Baryshkov

We found that when using the panel-kingdisplay-kd101ne3 driver to send
init code, it takes about 3.5s to complete the sending, but using the
new API (mipi_dsi_dcs_write_seq_multi) will not have this phenomenon,
which seems to affect the user experience.
I would like to ask how I can deal with this?

thanks

>
> Alex.
>
> >> thanks
> >>
> >> On Sun, Jun 2, 2024 at 1:07 PM Alex Bee <knaerzche@gmail.com> wrote:
> >>> Am 01.06.24 um 10:45 schrieb Zhaoxiong Lv:
> >>>
> >>> Hi Zhaoxiong,
> >>>
> >>>> The bias IC of this kindisplay-kd101ne3 panel is placed
> >>>> on the panel side, so when the panel is powered on,
> >>>> there is no need to control AVDD and AVEE in the driver,
> >>>> only 3.3v and reset are needed.
> >>>>
> >>>> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> >>>> ---
> >>>>
> >>>> Chage since V2:
> >>>>
> >>>> -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
> >>>> -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
> >>>> -  and drop kingdisplay_panel_enter_sleep_mode().
> >>>> -  3. If prepare fails, disable GPIO before regulators.
> >>>> -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
> >>>> -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
> >>>>
> >>>> ---
> >>>>    drivers/gpu/drm/panel/Kconfig                 |   9 +
> >>>>    drivers/gpu/drm/panel/Makefile                |   1 +
> >>>>    .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
> >>>>    3 files changed, 543 insertions(+)
> >>>>    create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> >>>>
> >>>> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> >>>> index e54f6f5604ed..71669e990e8e 100644
> >>>> --- a/drivers/gpu/drm/panel/Kconfig
> >>>> +++ b/drivers/gpu/drm/panel/Kconfig
> >>>> @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
> >>>>          24 bit RGB per pixel. It provides a MIPI DSI interface to
> >>>>          the host and has a built-in LED backlight.
> >>>>
> >>>> +config DRM_PANEL_KINGDISPLAY_KD101NE3
> >>>> +     tristate "Kingdisplay kd101ne3 panel"
> >>>> +     depends on OF
> >>>> +     depends on DRM_MIPI_DSI
> >>>> +     depends on BACKLIGHT_CLASS_DEVICE
> >>>> +     help
> >>>> +       Say Y here if you want to enable support for the kingdisplay kd101ne3
> >>>> +       4-lane 800x1280 MIPI DSI panel.
> >>>> +
> >>>>    config DRM_PANEL_LEADTEK_LTK050H3146W
> >>>>        tristate "Leadtek LTK050H3146W panel"
> >>>>        depends on OF
> >>>> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> >>>> index f0203f6e02f4..4576c9fe33d9 100644
> >>>> --- a/drivers/gpu/drm/panel/Makefile
> >>>> +++ b/drivers/gpu/drm/panel/Makefile
> >>>> @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
> >>>>    obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
> >>>>    obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
> >>>>    obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
> >>>> +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
> >>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
> >>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
> >>>>    obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> >>>> diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> >>>> new file mode 100644
> >>>> index 000000000000..8994a1c9afb5
> >>>> --- /dev/null
> >>>> +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> >>>> @@ -0,0 +1,533 @@
> >>>> +// SPDX-License-Identifier: GPL-2.0
> >>>> +/* Panels based on the JD9365DA display controller.
> >>>> + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> >>>> + */
> >>>> +
> >>>> +#include <linux/delay.h>
> >>>> +#include <linux/gpio/consumer.h>
> >>>> +#include <linux/module.h>
> >>>> +#include <linux/of.h>
> >>>> +#include <linux/regulator/consumer.h>
> >>>> +
> >>>> +#include <drm/drm_connector.h>
> >>>> +#include <drm/drm_crtc.h>
> >>>> +#include <drm/drm_mipi_dsi.h>
> >>>> +#include <drm/drm_panel.h>
> >>>> +
> >>>> +#include <video/mipi_display.h>
> >>>> +
> >>>> +struct kingdisplay_panel;
> >>>> +
> >>>> +struct panel_desc {
> >>>> +     const struct drm_display_mode *modes;
> >>>> +     unsigned int bpc;
> >>>> +
> >>>> +     /**
> >>>> +      * @width_mm: width of the panel's active display area
> >>>> +      * @height_mm: height of the panel's active display area
> >>>> +      */
> >>>> +     struct {
> >>>> +             unsigned int width_mm;
> >>>> +             unsigned int height_mm;
> >>>> +     } size;
> >>>> +
> >>>> +     unsigned long mode_flags;
> >>>> +     enum mipi_dsi_pixel_format format;
> >>>> +     const struct panel_init_cmd *init_cmds;
> >>>> +     int (*init)(struct kingdisplay_panel *kingdisplay);
> >>>> +     unsigned int lanes;
> >>>> +     bool discharge_on_disable;
> >>>> +     bool lp11_before_reset;
> >>>> +};
> >>>> +
> >>>> +struct kingdisplay_panel {
> >>>> +     struct drm_panel base;
> >>>> +     struct mipi_dsi_device *dsi;
> >>>> +
> >>>> +     const struct panel_desc *desc;
> >>>> +
> >>>> +     enum drm_panel_orientation orientation;
> >>>> +     struct regulator *pp3300;
> >>>> +     struct gpio_desc *enable_gpio;
> >>>> +};
> >>>> +
> >>>> +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> >>>> +{
> >>>> +     struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> >>>> +
> >>>> +     /* T5:HWreset to init_code >= 50ms */
> >>>> +     msleep(50);
> >>>> +
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> >>> Looking at the init sequence, I'm pretty confident this panel uses a
> >>> Jadard JD 9365 driver IC. It's probably worth adding it to
> >>> panel-jadard-jd9365da instead of adding a completly new driver.
> >>>
> >>> Alex
> >>>> +     if (dsi_ctx.accum_err)
> >>>> +             return dsi_ctx.accum_err;
> >>>> +
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> >>>> +     if (dsi_ctx.accum_err)
> >>>> +             return dsi_ctx.accum_err;
> >>>> +
> >>>> +     msleep(120);
> >>>> +
> >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> >>>> +     if (dsi_ctx.accum_err)
> >>>> +             return dsi_ctx.accum_err;
> >>>> +
> >>>> +     msleep(20);
> >>>> +
> >>>> +     return 0;
> >>>> +};
> >>>> +
> >>>> +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> >>>> +{
> >>>> +     return container_of(panel, struct kingdisplay_panel, base);
> >>>> +}
> >>>> +
> >>>> +static int kingdisplay_panel_disable(struct drm_panel *panel)
> >>>> +{
> >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> >>>> +     int err;
> >>>> +
> >>>> +     kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> >>>> +
> >>>> +     msleep(100);
> >>>> +
> >>>> +     err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
> >>>> +     if (err < 0)
> >>>> +             dev_err(panel->dev, "failed to set display off: %d\n", err);
> >>>> +
> >>>> +     msleep(50);
> >>>> +
> >>>> +     err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
> >>>> +     if (err < 0) {
> >>>> +             dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
> >>>> +             return err;
> >>>> +     }
> >>>> +
> >>>> +     msleep(120);
> >>>> +
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
> >>>> +{
> >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> >>>> +     int err;
> >>>> +
> >>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
> >>>> +
> >>>> +     /* T15: 2ms */
> >>>> +     usleep_range(1000, 2000);
> >>>> +
> >>>> +     err = regulator_disable(kingdisplay->pp3300);
> >>>> +     if (err < 0)
> >>>> +             return err;
> >>>> +
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static int kingdisplay_panel_prepare(struct drm_panel *panel)
> >>>> +{
> >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> >>>> +     int err;
> >>>> +
> >>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> >>>> +
> >>>> +     err = regulator_enable(kingdisplay->pp3300);
> >>>> +     if (err < 0)
> >>>> +             return err;
> >>>> +
> >>>> +     /* T1:Vdd to mipi_lp >= 0ms */
> >>>> +     usleep_range(5000, 6000);
> >>>> +
> >>>> +     if (kingdisplay->desc->lp11_before_reset) {
> >>>> +             err = mipi_dsi_dcs_nop(kingdisplay->dsi);
> >>>> +             if (err < 0)
> >>>> +                     goto poweroff;
> >>>> +
> >>>> +             usleep_range(1000, 2000);
> >>>> +     }
> >>>> +
> >>>> +     /* T2: 10ms, T1 + T2 > 60ms */
> >>>> +     msleep(60);
> >>>> +
> >>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
> >>>> +
> >>>> +     err = kingdisplay->desc->init(kingdisplay);
> >>>> +     if (err < 0)
> >>>> +             goto poweroff;
> >>>> +
> >>>> +     return 0;
> >>>> +
> >>>> +poweroff:
> >>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> >>>> +             /* T6: 2ms */
> >>>> +     usleep_range(1000, 2000);
> >>>> +     regulator_disable(kingdisplay->pp3300);
> >>>> +
> >>>> +     return err;
> >>>> +}
> >>>> +
> >>>> +static int kingdisplay_panel_enable(struct drm_panel *panel)
> >>>> +{
> >>>> +     msleep(130);
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
> >>>> +     .clock = 70595,
> >>>> +     .hdisplay = 800,
> >>>> +     .hsync_start = 800 + 30,
> >>>> +     .hsync_end = 800 + 30 + 30,
> >>>> +     .htotal = 800 + 30 + 30 + 30,
> >>>> +     .vdisplay = 1280,
> >>>> +     .vsync_start = 1280 + 30,
> >>>> +     .vsync_end = 1280 + 30 + 4,
> >>>> +     .vtotal = 1280 + 30 + 4 + 8,
> >>>> +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> >>>> +};
> >>>> +
> >>>> +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> >>>> +     .modes = &kingdisplay_kd101ne3_40ti_default_mode,
> >>>> +     .bpc = 8,
> >>>> +     .size = {
> >>>> +             .width_mm = 135,
> >>>> +             .height_mm = 216,
> >>>> +     },
> >>>> +     .lanes = 4,
> >>>> +     .format = MIPI_DSI_FMT_RGB888,
> >>>> +     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> >>>> +                   MIPI_DSI_MODE_LPM,
> >>>> +     .init = kingdisplay_kd101ne3_init,
> >>>> +     .lp11_before_reset = true,
> >>>> +};
> >>>> +
> >>>> +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> >>>> +                            struct drm_connector *connector)
> >>>> +{
> >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> >>>> +     const struct drm_display_mode *m = kingdisplay->desc->modes;
> >>>> +     struct drm_display_mode *mode;
> >>>> +
> >>>> +     mode = drm_mode_duplicate(connector->dev, m);
> >>>> +     if (!mode) {
> >>>> +             dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
> >>>> +                     m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
> >>>> +             return -ENOMEM;
> >>>> +     }
> >>>> +
> >>>> +     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> >>>> +     drm_mode_set_name(mode);
> >>>> +     drm_mode_probed_add(connector, mode);
> >>>> +
> >>>> +     connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
> >>>> +     connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
> >>>> +     connector->display_info.bpc = kingdisplay->desc->bpc;
> >>>> +
> >>>> +     return 1;
> >>>> +}
> >>>> +
> >>>> +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
> >>>> +{
> >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> >>>> +
> >>>> +     return kingdisplay->orientation;
> >>>> +}
> >>>> +
> >>>> +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
> >>>> +     .disable = kingdisplay_panel_disable,
> >>>> +     .unprepare = kingdisplay_panel_unprepare,
> >>>> +     .prepare = kingdisplay_panel_prepare,
> >>>> +     .enable = kingdisplay_panel_enable,
> >>>> +     .get_modes = kingdisplay_panel_get_modes,
> >>>> +     .get_orientation = kingdisplay_panel_get_orientation,
> >>>> +};
> >>>> +
> >>>> +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
> >>>> +{
> >>>> +     struct device *dev = &kingdisplay->dsi->dev;
> >>>> +     int err;
> >>>> +
> >>>> +     kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
> >>>> +     if (IS_ERR(kingdisplay->pp3300))
> >>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
> >>>> +                                  "Cannot get pp3300\n");
> >>>> +
> >>>> +     kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> >>>> +     if (IS_ERR(kingdisplay->enable_gpio))
> >>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
> >>>> +                                  "Cannot get enable GPIO\n");
> >>>> +
> >>>> +     drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
> >>>> +                    DRM_MODE_CONNECTOR_DSI);
> >>>> +
> >>>> +     err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
> >>>> +     if (err < 0) {
> >>>> +             dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
> >>>> +             return err;
> >>>> +     }
> >>>> +
> >>>> +     err = drm_panel_of_backlight(&kingdisplay->base);
> >>>> +     if (err)
> >>>> +             return err;
> >>>> +
> >>>> +     kingdisplay->base.funcs = &kingdisplay_panel_funcs;
> >>>> +     kingdisplay->base.dev = &kingdisplay->dsi->dev;
> >>>> +
> >>>> +     drm_panel_add(&kingdisplay->base);
> >>>> +
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
> >>>> +{
> >>>> +     struct kingdisplay_panel *kingdisplay;
> >>>> +     int ret;
> >>>> +     const struct panel_desc *desc;
> >>>> +
> >>>> +     kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
> >>>> +     if (!kingdisplay)
> >>>> +             return -ENOMEM;
> >>>> +
> >>>> +     desc = of_device_get_match_data(&dsi->dev);
> >>>> +     dsi->lanes = desc->lanes;
> >>>> +     dsi->format = desc->format;
> >>>> +     dsi->mode_flags = desc->mode_flags;
> >>>> +     kingdisplay->desc = desc;
> >>>> +     kingdisplay->dsi = dsi;
> >>>> +     ret = kingdisplay_panel_add(kingdisplay);
> >>>> +     if (ret < 0)
> >>>> +             return ret;
> >>>> +
> >>>> +     mipi_dsi_set_drvdata(dsi, kingdisplay);
> >>>> +
> >>>> +     ret = mipi_dsi_attach(dsi);
> >>>> +     if (ret)
> >>>> +             drm_panel_remove(&kingdisplay->base);
> >>>> +
> >>>> +     return ret;
> >>>> +}
> >>>> +
> >>>> +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
> >>>> +{
> >>>> +     struct kingdisplay_panel *kingdisplay = 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);
> >>>> +
> >>>> +     if (kingdisplay->base.dev)
> >>>> +             drm_panel_remove(&kingdisplay->base);
> >>>> +}
> >>>> +
> >>>> +static const struct of_device_id kingdisplay_of_match[] = {
> >>>> +     { .compatible = "kingdisplay,kd101ne3-40ti",
> >>>> +       .data = &kingdisplay_kd101ne3_40ti_desc
> >>>> +     },
> >>>> +     { /* sentinel */ }
> >>>> +};
> >>>> +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> >>>> +
> >>>> +static struct mipi_dsi_driver kingdisplay_panel_driver = {
> >>>> +     .driver = {
> >>>> +             .name = "panel-kingdisplay-kd101ne3",
> >>>> +             .of_match_table = kingdisplay_of_match,
> >>>> +     },
> >>>> +     .probe = kingdisplay_panel_probe,
> >>>> +     .remove = kingdisplay_panel_remove,
> >>>> +};
> >>>> +module_mipi_dsi_driver(kingdisplay_panel_driver);
> >>>> +
> >>>> +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
> >>>> +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
> >>>> +MODULE_LICENSE("GPL v2");

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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-12 11:35           ` zhaoxiong lv
@ 2024-06-12 11:39             ` zhaoxiong lv
  2024-06-12 13:01             ` Dmitry Baryshkov
  1 sibling, 0 replies; 21+ messages in thread
From: zhaoxiong lv @ 2024-06-12 11:39 UTC (permalink / raw)
  To: Alex Bee
  Cc: Dmitry Baryshkov, dmitry.torokhov, robh, krzysztof.kozlowski+dt,
	conor+dt, jikos, benjamin.tissoires, dianders, hsinyi, dri-devel,
	devicetree, linux-kernel

On Wed, Jun 12, 2024 at 7:35 PM zhaoxiong lv
<lvzhaoxiong@huaqin.corp-partner.google.com> wrote:
>
> On Fri, Jun 7, 2024 at 8:41 PM Alex Bee <knaerzche@gmail.com> wrote:
> >
> >
> > Am 07.06.24 um 14:01 schrieb Dmitry Baryshkov:
> > > On Fri, Jun 07, 2024 at 07:44:33PM +0800, zhaoxiong lv wrote:
> > >> hi Alex Bee
> > >>
> > >> I compared these two drivers. Although the control IC is the same, the
> > >> panel is different, and the init_cmd and timing are also slightly
> > >> different, so I added a separate driver.
> > > But it obviously uses the same structure as the panel-jadard. Please
> > > use existing driver instead of creating a completely new one (which you
> > > happily overload with an unrelated panel).
> > >
> > +1
> >
> > panel-jadard already supports different panels with different
> > init-sequences and they can be set per panel-type (compatible). If you need
> > different reset-/enable timings (what I doubt) you'll have to extend struct
> > jadard_panel_desc. In any case you'll have to put dsi->mode_flags in there
> > as your panel uses MIPI_DSI_MODE_LPM what the currently supported don't
> > need.
>
>  hi Alex Bee/Dmitry Baryshkov
>
> We found that when using the panel-kingdisplay-kd101ne3 driver to send
> init code, it takes about 3.5s to complete the sending, but using the
> new API (mipi_dsi_dcs_write_seq_multi) will not have this phenomenon,
> which seems to affect the user experience.
> I would like to ask how I can deal with this?
>
> thanks
>

Sorry, it should be that this driver(panel-jadard-jd9365da-h3.c) takes 3.5S.


> >
> > Alex.
> >
> > >> thanks
> > >>
> > >> On Sun, Jun 2, 2024 at 1:07 PM Alex Bee <knaerzche@gmail.com> wrote:
> > >>> Am 01.06.24 um 10:45 schrieb Zhaoxiong Lv:
> > >>>
> > >>> Hi Zhaoxiong,
> > >>>
> > >>>> The bias IC of this kindisplay-kd101ne3 panel is placed
> > >>>> on the panel side, so when the panel is powered on,
> > >>>> there is no need to control AVDD and AVEE in the driver,
> > >>>> only 3.3v and reset are needed.
> > >>>>
> > >>>> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > >>>> ---
> > >>>>
> > >>>> Chage since V2:
> > >>>>
> > >>>> -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
> > >>>> -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
> > >>>> -  and drop kingdisplay_panel_enter_sleep_mode().
> > >>>> -  3. If prepare fails, disable GPIO before regulators.
> > >>>> -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
> > >>>> -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
> > >>>>
> > >>>> ---
> > >>>>    drivers/gpu/drm/panel/Kconfig                 |   9 +
> > >>>>    drivers/gpu/drm/panel/Makefile                |   1 +
> > >>>>    .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
> > >>>>    3 files changed, 543 insertions(+)
> > >>>>    create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > >>>>
> > >>>> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> > >>>> index e54f6f5604ed..71669e990e8e 100644
> > >>>> --- a/drivers/gpu/drm/panel/Kconfig
> > >>>> +++ b/drivers/gpu/drm/panel/Kconfig
> > >>>> @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
> > >>>>          24 bit RGB per pixel. It provides a MIPI DSI interface to
> > >>>>          the host and has a built-in LED backlight.
> > >>>>
> > >>>> +config DRM_PANEL_KINGDISPLAY_KD101NE3
> > >>>> +     tristate "Kingdisplay kd101ne3 panel"
> > >>>> +     depends on OF
> > >>>> +     depends on DRM_MIPI_DSI
> > >>>> +     depends on BACKLIGHT_CLASS_DEVICE
> > >>>> +     help
> > >>>> +       Say Y here if you want to enable support for the kingdisplay kd101ne3
> > >>>> +       4-lane 800x1280 MIPI DSI panel.
> > >>>> +
> > >>>>    config DRM_PANEL_LEADTEK_LTK050H3146W
> > >>>>        tristate "Leadtek LTK050H3146W panel"
> > >>>>        depends on OF
> > >>>> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> > >>>> index f0203f6e02f4..4576c9fe33d9 100644
> > >>>> --- a/drivers/gpu/drm/panel/Makefile
> > >>>> +++ b/drivers/gpu/drm/panel/Makefile
> > >>>> @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
> > >>>> +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> > >>>> diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > >>>> new file mode 100644
> > >>>> index 000000000000..8994a1c9afb5
> > >>>> --- /dev/null
> > >>>> +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > >>>> @@ -0,0 +1,533 @@
> > >>>> +// SPDX-License-Identifier: GPL-2.0
> > >>>> +/* Panels based on the JD9365DA display controller.
> > >>>> + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > >>>> + */
> > >>>> +
> > >>>> +#include <linux/delay.h>
> > >>>> +#include <linux/gpio/consumer.h>
> > >>>> +#include <linux/module.h>
> > >>>> +#include <linux/of.h>
> > >>>> +#include <linux/regulator/consumer.h>
> > >>>> +
> > >>>> +#include <drm/drm_connector.h>
> > >>>> +#include <drm/drm_crtc.h>
> > >>>> +#include <drm/drm_mipi_dsi.h>
> > >>>> +#include <drm/drm_panel.h>
> > >>>> +
> > >>>> +#include <video/mipi_display.h>
> > >>>> +
> > >>>> +struct kingdisplay_panel;
> > >>>> +
> > >>>> +struct panel_desc {
> > >>>> +     const struct drm_display_mode *modes;
> > >>>> +     unsigned int bpc;
> > >>>> +
> > >>>> +     /**
> > >>>> +      * @width_mm: width of the panel's active display area
> > >>>> +      * @height_mm: height of the panel's active display area
> > >>>> +      */
> > >>>> +     struct {
> > >>>> +             unsigned int width_mm;
> > >>>> +             unsigned int height_mm;
> > >>>> +     } size;
> > >>>> +
> > >>>> +     unsigned long mode_flags;
> > >>>> +     enum mipi_dsi_pixel_format format;
> > >>>> +     const struct panel_init_cmd *init_cmds;
> > >>>> +     int (*init)(struct kingdisplay_panel *kingdisplay);
> > >>>> +     unsigned int lanes;
> > >>>> +     bool discharge_on_disable;
> > >>>> +     bool lp11_before_reset;
> > >>>> +};
> > >>>> +
> > >>>> +struct kingdisplay_panel {
> > >>>> +     struct drm_panel base;
> > >>>> +     struct mipi_dsi_device *dsi;
> > >>>> +
> > >>>> +     const struct panel_desc *desc;
> > >>>> +
> > >>>> +     enum drm_panel_orientation orientation;
> > >>>> +     struct regulator *pp3300;
> > >>>> +     struct gpio_desc *enable_gpio;
> > >>>> +};
> > >>>> +
> > >>>> +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> > >>>> +{
> > >>>> +     struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> > >>>> +
> > >>>> +     /* T5:HWreset to init_code >= 50ms */
> > >>>> +     msleep(50);
> > >>>> +
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> > >>> Looking at the init sequence, I'm pretty confident this panel uses a
> > >>> Jadard JD 9365 driver IC. It's probably worth adding it to
> > >>> panel-jadard-jd9365da instead of adding a completly new driver.
> > >>>
> > >>> Alex
> > >>>> +     if (dsi_ctx.accum_err)
> > >>>> +             return dsi_ctx.accum_err;
> > >>>> +
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> > >>>> +     if (dsi_ctx.accum_err)
> > >>>> +             return dsi_ctx.accum_err;
> > >>>> +
> > >>>> +     msleep(120);
> > >>>> +
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> > >>>> +     if (dsi_ctx.accum_err)
> > >>>> +             return dsi_ctx.accum_err;
> > >>>> +
> > >>>> +     msleep(20);
> > >>>> +
> > >>>> +     return 0;
> > >>>> +};
> > >>>> +
> > >>>> +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     return container_of(panel, struct kingdisplay_panel, base);
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_disable(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     int err;
> > >>>> +
> > >>>> +     kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> > >>>> +
> > >>>> +     msleep(100);
> > >>>> +
> > >>>> +     err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
> > >>>> +     if (err < 0)
> > >>>> +             dev_err(panel->dev, "failed to set display off: %d\n", err);
> > >>>> +
> > >>>> +     msleep(50);
> > >>>> +
> > >>>> +     err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
> > >>>> +     if (err < 0) {
> > >>>> +             dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
> > >>>> +             return err;
> > >>>> +     }
> > >>>> +
> > >>>> +     msleep(120);
> > >>>> +
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     int err;
> > >>>> +
> > >>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
> > >>>> +
> > >>>> +     /* T15: 2ms */
> > >>>> +     usleep_range(1000, 2000);
> > >>>> +
> > >>>> +     err = regulator_disable(kingdisplay->pp3300);
> > >>>> +     if (err < 0)
> > >>>> +             return err;
> > >>>> +
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_prepare(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     int err;
> > >>>> +
> > >>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > >>>> +
> > >>>> +     err = regulator_enable(kingdisplay->pp3300);
> > >>>> +     if (err < 0)
> > >>>> +             return err;
> > >>>> +
> > >>>> +     /* T1:Vdd to mipi_lp >= 0ms */
> > >>>> +     usleep_range(5000, 6000);
> > >>>> +
> > >>>> +     if (kingdisplay->desc->lp11_before_reset) {
> > >>>> +             err = mipi_dsi_dcs_nop(kingdisplay->dsi);
> > >>>> +             if (err < 0)
> > >>>> +                     goto poweroff;
> > >>>> +
> > >>>> +             usleep_range(1000, 2000);
> > >>>> +     }
> > >>>> +
> > >>>> +     /* T2: 10ms, T1 + T2 > 60ms */
> > >>>> +     msleep(60);
> > >>>> +
> > >>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
> > >>>> +
> > >>>> +     err = kingdisplay->desc->init(kingdisplay);
> > >>>> +     if (err < 0)
> > >>>> +             goto poweroff;
> > >>>> +
> > >>>> +     return 0;
> > >>>> +
> > >>>> +poweroff:
> > >>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > >>>> +             /* T6: 2ms */
> > >>>> +     usleep_range(1000, 2000);
> > >>>> +     regulator_disable(kingdisplay->pp3300);
> > >>>> +
> > >>>> +     return err;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_enable(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     msleep(130);
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
> > >>>> +     .clock = 70595,
> > >>>> +     .hdisplay = 800,
> > >>>> +     .hsync_start = 800 + 30,
> > >>>> +     .hsync_end = 800 + 30 + 30,
> > >>>> +     .htotal = 800 + 30 + 30 + 30,
> > >>>> +     .vdisplay = 1280,
> > >>>> +     .vsync_start = 1280 + 30,
> > >>>> +     .vsync_end = 1280 + 30 + 4,
> > >>>> +     .vtotal = 1280 + 30 + 4 + 8,
> > >>>> +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> > >>>> +};
> > >>>> +
> > >>>> +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> > >>>> +     .modes = &kingdisplay_kd101ne3_40ti_default_mode,
> > >>>> +     .bpc = 8,
> > >>>> +     .size = {
> > >>>> +             .width_mm = 135,
> > >>>> +             .height_mm = 216,
> > >>>> +     },
> > >>>> +     .lanes = 4,
> > >>>> +     .format = MIPI_DSI_FMT_RGB888,
> > >>>> +     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> > >>>> +                   MIPI_DSI_MODE_LPM,
> > >>>> +     .init = kingdisplay_kd101ne3_init,
> > >>>> +     .lp11_before_reset = true,
> > >>>> +};
> > >>>> +
> > >>>> +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> > >>>> +                            struct drm_connector *connector)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     const struct drm_display_mode *m = kingdisplay->desc->modes;
> > >>>> +     struct drm_display_mode *mode;
> > >>>> +
> > >>>> +     mode = drm_mode_duplicate(connector->dev, m);
> > >>>> +     if (!mode) {
> > >>>> +             dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
> > >>>> +                     m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
> > >>>> +             return -ENOMEM;
> > >>>> +     }
> > >>>> +
> > >>>> +     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> > >>>> +     drm_mode_set_name(mode);
> > >>>> +     drm_mode_probed_add(connector, mode);
> > >>>> +
> > >>>> +     connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
> > >>>> +     connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
> > >>>> +     connector->display_info.bpc = kingdisplay->desc->bpc;
> > >>>> +
> > >>>> +     return 1;
> > >>>> +}
> > >>>> +
> > >>>> +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +
> > >>>> +     return kingdisplay->orientation;
> > >>>> +}
> > >>>> +
> > >>>> +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
> > >>>> +     .disable = kingdisplay_panel_disable,
> > >>>> +     .unprepare = kingdisplay_panel_unprepare,
> > >>>> +     .prepare = kingdisplay_panel_prepare,
> > >>>> +     .enable = kingdisplay_panel_enable,
> > >>>> +     .get_modes = kingdisplay_panel_get_modes,
> > >>>> +     .get_orientation = kingdisplay_panel_get_orientation,
> > >>>> +};
> > >>>> +
> > >>>> +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
> > >>>> +{
> > >>>> +     struct device *dev = &kingdisplay->dsi->dev;
> > >>>> +     int err;
> > >>>> +
> > >>>> +     kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
> > >>>> +     if (IS_ERR(kingdisplay->pp3300))
> > >>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
> > >>>> +                                  "Cannot get pp3300\n");
> > >>>> +
> > >>>> +     kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> > >>>> +     if (IS_ERR(kingdisplay->enable_gpio))
> > >>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
> > >>>> +                                  "Cannot get enable GPIO\n");
> > >>>> +
> > >>>> +     drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
> > >>>> +                    DRM_MODE_CONNECTOR_DSI);
> > >>>> +
> > >>>> +     err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
> > >>>> +     if (err < 0) {
> > >>>> +             dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
> > >>>> +             return err;
> > >>>> +     }
> > >>>> +
> > >>>> +     err = drm_panel_of_backlight(&kingdisplay->base);
> > >>>> +     if (err)
> > >>>> +             return err;
> > >>>> +
> > >>>> +     kingdisplay->base.funcs = &kingdisplay_panel_funcs;
> > >>>> +     kingdisplay->base.dev = &kingdisplay->dsi->dev;
> > >>>> +
> > >>>> +     drm_panel_add(&kingdisplay->base);
> > >>>> +
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay;
> > >>>> +     int ret;
> > >>>> +     const struct panel_desc *desc;
> > >>>> +
> > >>>> +     kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
> > >>>> +     if (!kingdisplay)
> > >>>> +             return -ENOMEM;
> > >>>> +
> > >>>> +     desc = of_device_get_match_data(&dsi->dev);
> > >>>> +     dsi->lanes = desc->lanes;
> > >>>> +     dsi->format = desc->format;
> > >>>> +     dsi->mode_flags = desc->mode_flags;
> > >>>> +     kingdisplay->desc = desc;
> > >>>> +     kingdisplay->dsi = dsi;
> > >>>> +     ret = kingdisplay_panel_add(kingdisplay);
> > >>>> +     if (ret < 0)
> > >>>> +             return ret;
> > >>>> +
> > >>>> +     mipi_dsi_set_drvdata(dsi, kingdisplay);
> > >>>> +
> > >>>> +     ret = mipi_dsi_attach(dsi);
> > >>>> +     if (ret)
> > >>>> +             drm_panel_remove(&kingdisplay->base);
> > >>>> +
> > >>>> +     return ret;
> > >>>> +}
> > >>>> +
> > >>>> +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = 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);
> > >>>> +
> > >>>> +     if (kingdisplay->base.dev)
> > >>>> +             drm_panel_remove(&kingdisplay->base);
> > >>>> +}
> > >>>> +
> > >>>> +static const struct of_device_id kingdisplay_of_match[] = {
> > >>>> +     { .compatible = "kingdisplay,kd101ne3-40ti",
> > >>>> +       .data = &kingdisplay_kd101ne3_40ti_desc
> > >>>> +     },
> > >>>> +     { /* sentinel */ }
> > >>>> +};
> > >>>> +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> > >>>> +
> > >>>> +static struct mipi_dsi_driver kingdisplay_panel_driver = {
> > >>>> +     .driver = {
> > >>>> +             .name = "panel-kingdisplay-kd101ne3",
> > >>>> +             .of_match_table = kingdisplay_of_match,
> > >>>> +     },
> > >>>> +     .probe = kingdisplay_panel_probe,
> > >>>> +     .remove = kingdisplay_panel_remove,
> > >>>> +};
> > >>>> +module_mipi_dsi_driver(kingdisplay_panel_driver);
> > >>>> +
> > >>>> +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
> > >>>> +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
> > >>>> +MODULE_LICENSE("GPL v2");

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

* Re: [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver
  2024-06-12 11:35           ` zhaoxiong lv
  2024-06-12 11:39             ` zhaoxiong lv
@ 2024-06-12 13:01             ` Dmitry Baryshkov
  1 sibling, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2024-06-12 13:01 UTC (permalink / raw)
  To: zhaoxiong lv
  Cc: Alex Bee, dmitry.torokhov, robh, krzysztof.kozlowski+dt, conor+dt,
	jikos, benjamin.tissoires, dianders, hsinyi, dri-devel,
	devicetree, linux-kernel

On Wed, 12 Jun 2024 at 14:35, zhaoxiong lv
<lvzhaoxiong@huaqin.corp-partner.google.com> wrote:
>
> On Fri, Jun 7, 2024 at 8:41 PM Alex Bee <knaerzche@gmail.com> wrote:
> >
> >
> > Am 07.06.24 um 14:01 schrieb Dmitry Baryshkov:
> > > On Fri, Jun 07, 2024 at 07:44:33PM +0800, zhaoxiong lv wrote:
> > >> hi Alex Bee
> > >>
> > >> I compared these two drivers. Although the control IC is the same, the
> > >> panel is different, and the init_cmd and timing are also slightly
> > >> different, so I added a separate driver.
> > > But it obviously uses the same structure as the panel-jadard. Please
> > > use existing driver instead of creating a completely new one (which you
> > > happily overload with an unrelated panel).
> > >
> > +1
> >
> > panel-jadard already supports different panels with different
> > init-sequences and they can be set per panel-type (compatible). If you need
> > different reset-/enable timings (what I doubt) you'll have to extend struct
> > jadard_panel_desc. In any case you'll have to put dsi->mode_flags in there
> > as your panel uses MIPI_DSI_MODE_LPM what the currently supported don't
> > need.
>
>  hi Alex Bee/Dmitry Baryshkov
>
> We found that when using the panel-kingdisplay-kd101ne3 driver to send
> init code, it takes about 3.5s to complete the sending, but using the
> new API (mipi_dsi_dcs_write_seq_multi) will not have this phenomenon,
> which seems to affect the user experience.
> I would like to ask how I can deal with this?

As usual, update panel-jadard to use _multi.

>
> thanks
>
> >
> > Alex.
> >
> > >> thanks
> > >>
> > >> On Sun, Jun 2, 2024 at 1:07 PM Alex Bee <knaerzche@gmail.com> wrote:
> > >>> Am 01.06.24 um 10:45 schrieb Zhaoxiong Lv:
> > >>>
> > >>> Hi Zhaoxiong,
> > >>>
> > >>>> The bias IC of this kindisplay-kd101ne3 panel is placed
> > >>>> on the panel side, so when the panel is powered on,
> > >>>> there is no need to control AVDD and AVEE in the driver,
> > >>>> only 3.3v and reset are needed.
> > >>>>
> > >>>> Signed-off-by: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > >>>> ---
> > >>>>
> > >>>> Chage since V2:
> > >>>>
> > >>>> -  1. Use the new mipi_dsi_dcs_write_seq_multi() function.
> > >>>> -  2. Modify Move mipi_dsi_dcs_set_display_off() and mipi_dsi_dcs_enter_sleep_mode() to disable(),
> > >>>> -  and drop kingdisplay_panel_enter_sleep_mode().
> > >>>> -  3. If prepare fails, disable GPIO before regulators.
> > >>>> -  4. This function drm_connector_set_panel_orientation() is no longer used. Delete it.
> > >>>> -  5. Drop ".shutdown = kingdisplay_panel_shutdown".
> > >>>>
> > >>>> ---
> > >>>>    drivers/gpu/drm/panel/Kconfig                 |   9 +
> > >>>>    drivers/gpu/drm/panel/Makefile                |   1 +
> > >>>>    .../drm/panel/panel-kingdisplay-kd101ne3.c    | 533 ++++++++++++++++++
> > >>>>    3 files changed, 543 insertions(+)
> > >>>>    create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > >>>>
> > >>>> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> > >>>> index e54f6f5604ed..71669e990e8e 100644
> > >>>> --- a/drivers/gpu/drm/panel/Kconfig
> > >>>> +++ b/drivers/gpu/drm/panel/Kconfig
> > >>>> @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
> > >>>>          24 bit RGB per pixel. It provides a MIPI DSI interface to
> > >>>>          the host and has a built-in LED backlight.
> > >>>>
> > >>>> +config DRM_PANEL_KINGDISPLAY_KD101NE3
> > >>>> +     tristate "Kingdisplay kd101ne3 panel"
> > >>>> +     depends on OF
> > >>>> +     depends on DRM_MIPI_DSI
> > >>>> +     depends on BACKLIGHT_CLASS_DEVICE
> > >>>> +     help
> > >>>> +       Say Y here if you want to enable support for the kingdisplay kd101ne3
> > >>>> +       4-lane 800x1280 MIPI DSI panel.
> > >>>> +
> > >>>>    config DRM_PANEL_LEADTEK_LTK050H3146W
> > >>>>        tristate "Leadtek LTK050H3146W panel"
> > >>>>        depends on OF
> > >>>> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> > >>>> index f0203f6e02f4..4576c9fe33d9 100644
> > >>>> --- a/drivers/gpu/drm/panel/Makefile
> > >>>> +++ b/drivers/gpu/drm/panel/Makefile
> > >>>> @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
> > >>>> +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += panel-kingdisplay-kd101ne3.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
> > >>>>    obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> > >>>> diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > >>>> new file mode 100644
> > >>>> index 000000000000..8994a1c9afb5
> > >>>> --- /dev/null
> > >>>> +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > >>>> @@ -0,0 +1,533 @@
> > >>>> +// SPDX-License-Identifier: GPL-2.0
> > >>>> +/* Panels based on the JD9365DA display controller.
> > >>>> + * Author: Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>
> > >>>> + */
> > >>>> +
> > >>>> +#include <linux/delay.h>
> > >>>> +#include <linux/gpio/consumer.h>
> > >>>> +#include <linux/module.h>
> > >>>> +#include <linux/of.h>
> > >>>> +#include <linux/regulator/consumer.h>
> > >>>> +
> > >>>> +#include <drm/drm_connector.h>
> > >>>> +#include <drm/drm_crtc.h>
> > >>>> +#include <drm/drm_mipi_dsi.h>
> > >>>> +#include <drm/drm_panel.h>
> > >>>> +
> > >>>> +#include <video/mipi_display.h>
> > >>>> +
> > >>>> +struct kingdisplay_panel;
> > >>>> +
> > >>>> +struct panel_desc {
> > >>>> +     const struct drm_display_mode *modes;
> > >>>> +     unsigned int bpc;
> > >>>> +
> > >>>> +     /**
> > >>>> +      * @width_mm: width of the panel's active display area
> > >>>> +      * @height_mm: height of the panel's active display area
> > >>>> +      */
> > >>>> +     struct {
> > >>>> +             unsigned int width_mm;
> > >>>> +             unsigned int height_mm;
> > >>>> +     } size;
> > >>>> +
> > >>>> +     unsigned long mode_flags;
> > >>>> +     enum mipi_dsi_pixel_format format;
> > >>>> +     const struct panel_init_cmd *init_cmds;
> > >>>> +     int (*init)(struct kingdisplay_panel *kingdisplay);
> > >>>> +     unsigned int lanes;
> > >>>> +     bool discharge_on_disable;
> > >>>> +     bool lp11_before_reset;
> > >>>> +};
> > >>>> +
> > >>>> +struct kingdisplay_panel {
> > >>>> +     struct drm_panel base;
> > >>>> +     struct mipi_dsi_device *dsi;
> > >>>> +
> > >>>> +     const struct panel_desc *desc;
> > >>>> +
> > >>>> +     enum drm_panel_orientation orientation;
> > >>>> +     struct regulator *pp3300;
> > >>>> +     struct gpio_desc *enable_gpio;
> > >>>> +};
> > >>>> +
> > >>>> +static int kingdisplay_kd101ne3_init(struct kingdisplay_panel *kingdisplay)
> > >>>> +{
> > >>>> +     struct mipi_dsi_multi_context dsi_ctx = { .dsi = kingdisplay->dsi };
> > >>>> +
> > >>>> +     /* T5:HWreset to init_code >= 50ms */
> > >>>> +     msleep(50);
> > >>>> +
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0x93);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, 0x65);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe3, 0xf8);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x03);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xc7);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xc7);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x7e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x61);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x50);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x43);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x32);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x35);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x38);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x54);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x42);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x39);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x34);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x26);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x61);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x50);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x43);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x32);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x35);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x38);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x36);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x54);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x42);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x39);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x34);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x26);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x02);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x04);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0x00);
> > >>> Looking at the init sequence, I'm pretty confident this panel uses a
> > >>> Jadard JD 9365 driver IC. It's probably worth adding it to
> > >>> panel-jadard-jd9365da instead of adding a completly new driver.
> > >>>
> > >>> Alex
> > >>>> +     if (dsi_ctx.accum_err)
> > >>>> +             return dsi_ctx.accum_err;
> > >>>> +
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
> > >>>> +     if (dsi_ctx.accum_err)
> > >>>> +             return dsi_ctx.accum_err;
> > >>>> +
> > >>>> +     msleep(120);
> > >>>> +
> > >>>> +     mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
> > >>>> +     if (dsi_ctx.accum_err)
> > >>>> +             return dsi_ctx.accum_err;
> > >>>> +
> > >>>> +     msleep(20);
> > >>>> +
> > >>>> +     return 0;
> > >>>> +};
> > >>>> +
> > >>>> +static inline struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     return container_of(panel, struct kingdisplay_panel, base);
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_disable(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     int err;
> > >>>> +
> > >>>> +     kingdisplay->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> > >>>> +
> > >>>> +     msleep(100);
> > >>>> +
> > >>>> +     err = mipi_dsi_dcs_set_display_off(kingdisplay->dsi);
> > >>>> +     if (err < 0)
> > >>>> +             dev_err(panel->dev, "failed to set display off: %d\n", err);
> > >>>> +
> > >>>> +     msleep(50);
> > >>>> +
> > >>>> +     err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->dsi);
> > >>>> +     if (err < 0) {
> > >>>> +             dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
> > >>>> +             return err;
> > >>>> +     }
> > >>>> +
> > >>>> +     msleep(120);
> > >>>> +
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_unprepare(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     int err;
> > >>>> +
> > >>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
> > >>>> +
> > >>>> +     /* T15: 2ms */
> > >>>> +     usleep_range(1000, 2000);
> > >>>> +
> > >>>> +     err = regulator_disable(kingdisplay->pp3300);
> > >>>> +     if (err < 0)
> > >>>> +             return err;
> > >>>> +
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_prepare(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     int err;
> > >>>> +
> > >>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > >>>> +
> > >>>> +     err = regulator_enable(kingdisplay->pp3300);
> > >>>> +     if (err < 0)
> > >>>> +             return err;
> > >>>> +
> > >>>> +     /* T1:Vdd to mipi_lp >= 0ms */
> > >>>> +     usleep_range(5000, 6000);
> > >>>> +
> > >>>> +     if (kingdisplay->desc->lp11_before_reset) {
> > >>>> +             err = mipi_dsi_dcs_nop(kingdisplay->dsi);
> > >>>> +             if (err < 0)
> > >>>> +                     goto poweroff;
> > >>>> +
> > >>>> +             usleep_range(1000, 2000);
> > >>>> +     }
> > >>>> +
> > >>>> +     /* T2: 10ms, T1 + T2 > 60ms */
> > >>>> +     msleep(60);
> > >>>> +
> > >>>> +     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
> > >>>> +
> > >>>> +     err = kingdisplay->desc->init(kingdisplay);
> > >>>> +     if (err < 0)
> > >>>> +             goto poweroff;
> > >>>> +
> > >>>> +     return 0;
> > >>>> +
> > >>>> +poweroff:
> > >>>> +     gpiod_set_value(kingdisplay->enable_gpio, 0);
> > >>>> +             /* T6: 2ms */
> > >>>> +     usleep_range(1000, 2000);
> > >>>> +     regulator_disable(kingdisplay->pp3300);
> > >>>> +
> > >>>> +     return err;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_enable(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     msleep(130);
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static const struct drm_display_mode kingdisplay_kd101ne3_40ti_default_mode = {
> > >>>> +     .clock = 70595,
> > >>>> +     .hdisplay = 800,
> > >>>> +     .hsync_start = 800 + 30,
> > >>>> +     .hsync_end = 800 + 30 + 30,
> > >>>> +     .htotal = 800 + 30 + 30 + 30,
> > >>>> +     .vdisplay = 1280,
> > >>>> +     .vsync_start = 1280 + 30,
> > >>>> +     .vsync_end = 1280 + 30 + 4,
> > >>>> +     .vtotal = 1280 + 30 + 4 + 8,
> > >>>> +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> > >>>> +};
> > >>>> +
> > >>>> +static const struct panel_desc kingdisplay_kd101ne3_40ti_desc = {
> > >>>> +     .modes = &kingdisplay_kd101ne3_40ti_default_mode,
> > >>>> +     .bpc = 8,
> > >>>> +     .size = {
> > >>>> +             .width_mm = 135,
> > >>>> +             .height_mm = 216,
> > >>>> +     },
> > >>>> +     .lanes = 4,
> > >>>> +     .format = MIPI_DSI_FMT_RGB888,
> > >>>> +     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> > >>>> +                   MIPI_DSI_MODE_LPM,
> > >>>> +     .init = kingdisplay_kd101ne3_init,
> > >>>> +     .lp11_before_reset = true,
> > >>>> +};
> > >>>> +
> > >>>> +static int kingdisplay_panel_get_modes(struct drm_panel *panel,
> > >>>> +                            struct drm_connector *connector)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +     const struct drm_display_mode *m = kingdisplay->desc->modes;
> > >>>> +     struct drm_display_mode *mode;
> > >>>> +
> > >>>> +     mode = drm_mode_duplicate(connector->dev, m);
> > >>>> +     if (!mode) {
> > >>>> +             dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
> > >>>> +                     m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
> > >>>> +             return -ENOMEM;
> > >>>> +     }
> > >>>> +
> > >>>> +     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> > >>>> +     drm_mode_set_name(mode);
> > >>>> +     drm_mode_probed_add(connector, mode);
> > >>>> +
> > >>>> +     connector->display_info.width_mm = kingdisplay->desc->size.width_mm;
> > >>>> +     connector->display_info.height_mm = kingdisplay->desc->size.height_mm;
> > >>>> +     connector->display_info.bpc = kingdisplay->desc->bpc;
> > >>>> +
> > >>>> +     return 1;
> > >>>> +}
> > >>>> +
> > >>>> +static enum drm_panel_orientation kingdisplay_panel_get_orientation(struct drm_panel *panel)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
> > >>>> +
> > >>>> +     return kingdisplay->orientation;
> > >>>> +}
> > >>>> +
> > >>>> +static const struct drm_panel_funcs kingdisplay_panel_funcs = {
> > >>>> +     .disable = kingdisplay_panel_disable,
> > >>>> +     .unprepare = kingdisplay_panel_unprepare,
> > >>>> +     .prepare = kingdisplay_panel_prepare,
> > >>>> +     .enable = kingdisplay_panel_enable,
> > >>>> +     .get_modes = kingdisplay_panel_get_modes,
> > >>>> +     .get_orientation = kingdisplay_panel_get_orientation,
> > >>>> +};
> > >>>> +
> > >>>> +static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
> > >>>> +{
> > >>>> +     struct device *dev = &kingdisplay->dsi->dev;
> > >>>> +     int err;
> > >>>> +
> > >>>> +     kingdisplay->pp3300 = devm_regulator_get(dev, "pp3300");
> > >>>> +     if (IS_ERR(kingdisplay->pp3300))
> > >>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->pp3300),
> > >>>> +                                  "Cannot get pp3300\n");
> > >>>> +
> > >>>> +     kingdisplay->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> > >>>> +     if (IS_ERR(kingdisplay->enable_gpio))
> > >>>> +             return dev_err_probe(dev, PTR_ERR(kingdisplay->enable_gpio),
> > >>>> +                                  "Cannot get enable GPIO\n");
> > >>>> +
> > >>>> +     drm_panel_init(&kingdisplay->base, dev, &kingdisplay_panel_funcs,
> > >>>> +                    DRM_MODE_CONNECTOR_DSI);
> > >>>> +
> > >>>> +     err = of_drm_get_panel_orientation(dev->of_node, &kingdisplay->orientation);
> > >>>> +     if (err < 0) {
> > >>>> +             dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
> > >>>> +             return err;
> > >>>> +     }
> > >>>> +
> > >>>> +     err = drm_panel_of_backlight(&kingdisplay->base);
> > >>>> +     if (err)
> > >>>> +             return err;
> > >>>> +
> > >>>> +     kingdisplay->base.funcs = &kingdisplay_panel_funcs;
> > >>>> +     kingdisplay->base.dev = &kingdisplay->dsi->dev;
> > >>>> +
> > >>>> +     drm_panel_add(&kingdisplay->base);
> > >>>> +
> > >>>> +     return 0;
> > >>>> +}
> > >>>> +
> > >>>> +static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay;
> > >>>> +     int ret;
> > >>>> +     const struct panel_desc *desc;
> > >>>> +
> > >>>> +     kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
> > >>>> +     if (!kingdisplay)
> > >>>> +             return -ENOMEM;
> > >>>> +
> > >>>> +     desc = of_device_get_match_data(&dsi->dev);
> > >>>> +     dsi->lanes = desc->lanes;
> > >>>> +     dsi->format = desc->format;
> > >>>> +     dsi->mode_flags = desc->mode_flags;
> > >>>> +     kingdisplay->desc = desc;
> > >>>> +     kingdisplay->dsi = dsi;
> > >>>> +     ret = kingdisplay_panel_add(kingdisplay);
> > >>>> +     if (ret < 0)
> > >>>> +             return ret;
> > >>>> +
> > >>>> +     mipi_dsi_set_drvdata(dsi, kingdisplay);
> > >>>> +
> > >>>> +     ret = mipi_dsi_attach(dsi);
> > >>>> +     if (ret)
> > >>>> +             drm_panel_remove(&kingdisplay->base);
> > >>>> +
> > >>>> +     return ret;
> > >>>> +}
> > >>>> +
> > >>>> +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
> > >>>> +{
> > >>>> +     struct kingdisplay_panel *kingdisplay = 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);
> > >>>> +
> > >>>> +     if (kingdisplay->base.dev)
> > >>>> +             drm_panel_remove(&kingdisplay->base);
> > >>>> +}
> > >>>> +
> > >>>> +static const struct of_device_id kingdisplay_of_match[] = {
> > >>>> +     { .compatible = "kingdisplay,kd101ne3-40ti",
> > >>>> +       .data = &kingdisplay_kd101ne3_40ti_desc
> > >>>> +     },
> > >>>> +     { /* sentinel */ }
> > >>>> +};
> > >>>> +MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
> > >>>> +
> > >>>> +static struct mipi_dsi_driver kingdisplay_panel_driver = {
> > >>>> +     .driver = {
> > >>>> +             .name = "panel-kingdisplay-kd101ne3",
> > >>>> +             .of_match_table = kingdisplay_of_match,
> > >>>> +     },
> > >>>> +     .probe = kingdisplay_panel_probe,
> > >>>> +     .remove = kingdisplay_panel_remove,
> > >>>> +};
> > >>>> +module_mipi_dsi_driver(kingdisplay_panel_driver);
> > >>>> +
> > >>>> +MODULE_AUTHOR("Zhaoxiong Lv <lvzhaoxiong@huaqin.corp-partner.google.com>");
> > >>>> +MODULE_DESCRIPTION("kingdisplay kd101ne3-40ti 800x1280 video mode panel driver");
> > >>>> +MODULE_LICENSE("GPL v2");



-- 
With best wishes
Dmitry

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

end of thread, other threads:[~2024-06-12 13:02 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-01  8:45 [PATCH v2 0/4] Support Kingdisplay kd101ne3 and Starry er88577 MIPI-DSI panel Zhaoxiong Lv
2024-06-01  8:45 ` [PATCH v2 1/4] dt-bindings: display: panel: Add KD101NE3-40TI support Zhaoxiong Lv
2024-06-01 15:40   ` Krzysztof Kozlowski
2024-06-01 16:27   ` Dmitry Baryshkov
2024-06-07 11:38     ` zhaoxiong lv
2024-06-07 11:48       ` Dmitry Baryshkov
2024-06-01  8:45 ` [PATCH v2 2/4] drm/panel: kd101ne3: add new panel driver Zhaoxiong Lv
2024-06-01 16:23   ` Dmitry Baryshkov
2024-06-02  5:07   ` Alex Bee
2024-06-07 11:44     ` zhaoxiong lv
2024-06-07 12:01       ` Dmitry Baryshkov
2024-06-07 12:41         ` Alex Bee
2024-06-12 11:35           ` zhaoxiong lv
2024-06-12 11:39             ` zhaoxiong lv
2024-06-12 13:01             ` Dmitry Baryshkov
2024-06-01  8:45 ` [PATCH v2 3/4] dt-bindings: display: panel: Add compatible for Starry-er88577 Zhaoxiong Lv
2024-06-01 15:41   ` Krzysztof Kozlowski
2024-06-01  8:45 ` [PATCH v2 4/4] drm/panel: starry: add new panel driver Zhaoxiong Lv
2024-06-01 16:26   ` Dmitry Baryshkov
2024-06-07 11:51     ` zhaoxiong lv
2024-06-07 12:04       ` Dmitry Baryshkov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).