Add support for 3 panels used in 2 Xiaomi smartphones, all based on
Qualcomm SDM636/660 SoC:

* Shenchao panel used in Xiaomi Redmi Note 7 (xiaomi-lavender), the
  exact model string is unknown
* Tianma TL063FVMCA01-00 for Xiaomi Redmi Note 7 (xiaomi-lavender)
* Tianma TL063FVMC43-02  for Xiaomi Redmi Note 6 Pro (xiaomi-tulip)

They all are DSI video mode panels using Novatek NT36672A controller,
so they can share almost exactly the same init/off sequences with
minimal differences between variants. This allows to avoid a lot of
code duplication.

Co-developed-by: Richard Acayan <[email protected]>
Signed-off-by: Richard Acayan <[email protected]>
Signed-off-by: Alexey Minnekhanov <[email protected]>
---
 drivers/gpu/drm/panel/panel-novatek-nt36672a.c | 166 +++++++++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c 
b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c
index 237a6a8699aef..e6971ba6ef464 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c
@@ -361,6 +361,90 @@ static void tianma_fhd_video_send_deinit_cmds(struct 
mipi_dsi_multi_context *dsi
        mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x10);
 }
 
+static void lavender_tulip_init_cmds(struct mipi_dsi_multi_context *dsi_ctx)
+{
+       /*
+        * This function supports 3 similar panels with minimal differences
+        * in their init sequences. We assume base to be lavender-tianma
+        * panel, and 2 variations (lavender-shenchao and tulip) are handled as
+        * differences to base.
+        */
+       const struct device_node *node = dev_of_node(&dsi_ctx->dsi->dev);
+       bool is_shenchao = of_device_is_compatible(node, 
"shenchao,fhdplus-video");
+       bool is_tulip = of_device_is_compatible(node, "tianma,tl063fvmc43-02");
+
+       dsi_ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x25);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfb, 0x01);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x18, 0x96);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x05, 0x04);
+
+       if (is_shenchao)
+               mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x27);
+       else
+               mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x20);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfb, 0x01);
+
+       if (is_shenchao)
+               mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x10);
+       else
+               mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x78, 0x01);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x24);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfb, 0x01);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x82, 0x13);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x84, 0x31);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x88, 0x13);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x8a, 0x31);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x8e, 0xe4);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x8f, 0x01);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x90, 0x80);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x26);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfb, 0x01);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xa9, 0x12);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xaa, 0x10);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xae, 0x8a);
+
+       if (is_shenchao)
+               mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x1c, 0xfa);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x10);
+
+       if (is_shenchao)
+               mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb0, 0x01);
+
+       mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
+       mipi_dsi_msleep(dsi_ctx, 80);
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb0, 0x01);
+       mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+
+       if (is_tulip) {
+               mipi_dsi_dcs_set_display_brightness_multi(dsi_ctx, 0x00ff);
+       } else {
+               /* lavender tianma + shenchao specific part */
+               mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x68, 0x03, 0x04);
+               mipi_dsi_dcs_set_display_brightness_multi(dsi_ctx, 0x00b8);
+       }
+
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 
0x2c);
+       mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
+
+       mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
+}
+
+static void lavender_tulip_deinit_cmds(struct mipi_dsi_multi_context *dsi_ctx)
+{
+       dsi_ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+       mipi_dsi_dcs_set_display_off_multi(dsi_ctx);
+       mipi_dsi_msleep(dsi_ctx, 20);
+       mipi_dsi_dcs_enter_sleep_mode_multi(dsi_ctx);
+       mipi_dsi_msleep(dsi_ctx, 120);
+}
+
 static const struct drm_display_mode tianma_fhd_video_panel_default_mode = {
        .clock          = 161331,
 
@@ -393,6 +477,85 @@ static const struct nt36672a_panel_desc 
tianma_fhd_video_panel_desc = {
        .send_deinit_cmds = tianma_fhd_video_send_deinit_cmds,
 };
 
+/* common for both lavender-tianma and lavender-shenchao panels */
+static const struct drm_display_mode lavender_panel_default_mode = {
+       .clock          = (1080 + 90 + 2 + 120) * (2340 + 10 + 3 + 8) * 60 / 
1000,
+
+       .hdisplay       = 1080,
+       .hsync_start    = 1080 + 90,
+       .hsync_end      = 1080 + 90 + 2,
+       .htotal         = 1080 + 90 + 2 + 120,
+
+       .vdisplay       = 2340,
+       .vsync_start    = 2340 + 10,
+       .vsync_end      = 2340 + 10 + 3,
+       .vtotal         = 2340 + 10 + 3 + 8,
+
+       .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct nt36672a_panel_desc shenchao_lavender_panel_desc = {
+       .display_mode = &lavender_panel_default_mode,
+
+       .width_mm = 67,
+       .height_mm = 145,
+
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                       MIPI_DSI_CLOCK_NON_CONTINUOUS,
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+       .send_init_cmds = lavender_tulip_init_cmds,
+       .send_deinit_cmds = lavender_tulip_deinit_cmds,
+};
+
+static const struct nt36672a_panel_desc tianma_lavender_panel_desc = {
+       .display_mode = &lavender_panel_default_mode,
+
+       .width_mm = 67,
+       .height_mm = 145,
+
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                       MIPI_DSI_CLOCK_NON_CONTINUOUS,
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+       .send_init_cmds = lavender_tulip_init_cmds,
+       .send_deinit_cmds = lavender_tulip_deinit_cmds,
+};
+
+static const struct drm_display_mode tianmaplus_e7t_tulip_mode = {
+       .clock          = (1080 + 100 + 28 + 120) * (2280 + 10 + 3 + 8) * 60 / 
1000,
+
+       .hdisplay       = 1080,
+       .hsync_start    = 1080 + 100,
+       .hsync_end      = 1080 + 100 + 28,
+       .htotal         = 1080 + 100 + 28 + 120,
+
+       .vdisplay       = 2280,
+       .vsync_start    = 2280 + 10,
+       .vsync_end      = 2280 + 10 + 3,
+       .vtotal         = 2280 + 10 + 3 + 8,
+
+       .width_mm = 68,
+       .height_mm = 143,
+
+       .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct nt36672a_panel_desc tianmaplus_e7t_tulip_panel_desc = {
+       .display_mode = &tianmaplus_e7t_tulip_mode,
+
+       .width_mm = 68,
+       .height_mm = 143,
+
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                       MIPI_DSI_CLOCK_NON_CONTINUOUS,
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+       /* tulip panel uses almost the same init/deinit sequences as lavender */
+       .send_init_cmds = lavender_tulip_init_cmds,
+       .send_deinit_cmds = lavender_tulip_deinit_cmds,
+};
+
 static int nt36672a_panel_add(struct nt36672a_panel *pinfo)
 {
        struct device *dev = &pinfo->link->dev;
@@ -469,7 +632,10 @@ static void nt36672a_panel_remove(struct mipi_dsi_device 
*dsi)
 }
 
 static const struct of_device_id panel_nt36672a_match[] = {
+       { .compatible = "shenchao,fhdplus-video", .data = 
&shenchao_lavender_panel_desc },
        { .compatible = "tianma,fhd-video", .data = 
&tianma_fhd_video_panel_desc },
+       { .compatible = "tianma,tl063fvmca01-00", .data = 
&tianma_lavender_panel_desc },
+       { .compatible = "tianma,tl063fvmc43-02", .data = 
&tianmaplus_e7t_tulip_panel_desc },
        { },
 };
 MODULE_DEVICE_TABLE(of, panel_nt36672a_match);

-- 
2.55.0

Reply via email to