drm/panel: Change dlen from u16 to u8
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / panel / panel-simple.c
index f97b73ec4713722ae3af5a05ba048ea95042e4e0..20a4bb6b548c2486f8d85c10d83745145f515ac0 100644 (file)
 #include <drm/drm_panel.h>
 
 #include <video/display_timing.h>
+#include <video/mipi_display.h>
+#include <video/of_display_timing.h>
 #include <video/videomode.h>
 
+struct dsi_ctrl_hdr {
+       u8 dtype;       /* data type */
+       u8 wait;        /* ms */
+       u8 dlen;        /* payload len */
+} __packed;
+
+struct dsi_cmd_desc {
+       struct dsi_ctrl_hdr dchdr;
+       u8 *payload;
+};
+
+struct dsi_panel_cmds {
+       u8 *buf;
+       int blen;
+       struct dsi_cmd_desc *cmds;
+       int cmd_cnt;
+};
+
 struct panel_desc {
        const struct drm_display_mode *modes;
        unsigned int num_modes;
@@ -72,9 +92,11 @@ struct panel_desc {
 
 struct panel_simple {
        struct drm_panel base;
+       struct mipi_dsi_device *dsi;
        bool prepared;
        bool enabled;
 
+       struct device *dev;
        const struct panel_desc *desc;
 
        struct backlight_device *backlight;
@@ -82,6 +104,11 @@ struct panel_simple {
        struct i2c_adapter *ddc;
 
        struct gpio_desc *enable_gpio;
+       struct gpio_desc *reset_gpio;
+       unsigned int reset_delay;
+
+       struct dsi_panel_cmds *on_cmds;
+       struct dsi_panel_cmds *off_cmds;
 };
 
 static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
@@ -89,6 +116,130 @@ static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
        return container_of(panel, struct panel_simple, base);
 }
 
+static void panel_simple_dsi_cmds_cleanup(struct panel_simple *p)
+{
+       if (p->on_cmds) {
+               kfree(p->on_cmds->buf);
+               kfree(p->on_cmds->cmds);
+       }
+
+       if (p->off_cmds) {
+               kfree(p->off_cmds->buf);
+               kfree(p->off_cmds->cmds);
+       }
+}
+
+static int panel_simple_dsi_parse_dcs_cmds(struct device *dev,
+                                          const u8 *data, int blen,
+                                          struct dsi_panel_cmds *pcmds)
+{
+       int len;
+       char *buf, *bp;
+       struct dsi_ctrl_hdr *dchdr;
+       int i, cnt;
+
+       if (!pcmds)
+               return -EINVAL;
+
+       buf = kmemdup(data, blen, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /* scan dcs commands */
+       bp = buf;
+       len = blen;
+       cnt = 0;
+       while (len > sizeof(*dchdr)) {
+               dchdr = (struct dsi_ctrl_hdr *)bp;
+
+               if (dchdr->dlen > len) {
+                       dev_err(dev, "%s: error, len=%d", __func__,
+                               dchdr->dlen);
+                       return -EINVAL;
+               }
+
+               bp += sizeof(*dchdr);
+               len -= sizeof(*dchdr);
+               bp += dchdr->dlen;
+               len -= dchdr->dlen;
+               cnt++;
+       }
+
+       if (len != 0) {
+               dev_err(dev, "%s: dcs_cmd=%x len=%d error!",
+                       __func__, buf[0], blen);
+               kfree(buf);
+               return -EINVAL;
+       }
+
+       pcmds->cmds = kcalloc(cnt, sizeof(struct dsi_cmd_desc), GFP_KERNEL);
+       if (!pcmds->cmds) {
+               kfree(buf);
+               return -ENOMEM;
+       }
+
+       pcmds->cmd_cnt = cnt;
+       pcmds->buf = buf;
+       pcmds->blen = blen;
+
+       bp = buf;
+       len = blen;
+       for (i = 0; i < cnt; i++) {
+               dchdr = (struct dsi_ctrl_hdr *)bp;
+               len -= sizeof(*dchdr);
+               bp += sizeof(*dchdr);
+               pcmds->cmds[i].dchdr = *dchdr;
+               pcmds->cmds[i].payload = bp;
+               bp += dchdr->dlen;
+               len -= dchdr->dlen;
+       }
+
+       dev_info(dev, "%s: dcs_cmd=%x len=%d, cmd_cnt=%d\n", __func__,
+                pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt);
+       return 0;
+}
+
+static int panel_simple_dsi_send_cmds(struct panel_simple *panel,
+                                     struct dsi_panel_cmds *cmds)
+{
+       struct mipi_dsi_device *dsi = panel->dsi;
+       int i, err;
+
+       if (!cmds)
+               return -EINVAL;
+
+       for (i = 0; i < cmds->cmd_cnt; i++) {
+               struct dsi_cmd_desc *cmd = &cmds->cmds[i];
+
+               switch (cmd->dchdr.dtype) {
+               case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+               case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+               case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+               case MIPI_DSI_GENERIC_LONG_WRITE:
+                       err = mipi_dsi_generic_write(dsi, cmd->payload,
+                                                    cmd->dchdr.dlen);
+                       break;
+               case MIPI_DSI_DCS_SHORT_WRITE:
+               case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+               case MIPI_DSI_DCS_LONG_WRITE:
+                       err = mipi_dsi_dcs_write_buffer(dsi, cmd->payload,
+                                                       cmd->dchdr.dlen);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               if (err)
+                       dev_err(panel->dev, "failed to write dcs cmd: %d\n",
+                               err);
+
+               if (cmd->dchdr.wait)
+                       msleep(cmd->dchdr.wait);
+       }
+
+       return 0;
+}
+
 static int panel_simple_get_fixed_modes(struct panel_simple *panel)
 {
        struct drm_connector *connector = panel->base.connector;
@@ -144,6 +295,41 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
        return num;
 }
 
+static int panel_simple_of_get_native_mode(struct panel_simple *panel)
+{
+       struct drm_connector *connector = panel->base.connector;
+       struct drm_device *drm = panel->base.drm;
+       struct drm_display_mode *mode;
+       struct device_node *timings_np;
+       int ret;
+
+       timings_np = of_get_child_by_name(panel->dev->of_node,
+                                         "display-timings");
+       if (!timings_np) {
+               dev_dbg(panel->dev, "failed to find display-timings node\n");
+               return 0;
+       }
+
+       of_node_put(timings_np);
+       mode = drm_mode_create(drm);
+       if (!mode)
+               return 0;
+
+       ret = of_get_drm_display_mode(panel->dev->of_node, mode,
+                                     OF_USE_NATIVE_MODE);
+       if (ret) {
+               dev_dbg(panel->dev, "failed to find dts display timings\n");
+               drm_mode_destroy(drm, mode);
+               return 0;
+       }
+
+       drm_mode_set_name(mode);
+       mode->type |= DRM_MODE_TYPE_PREFERRED;
+       drm_mode_probed_add(connector, mode);
+
+       return 1;
+}
+
 static int panel_simple_disable(struct drm_panel *panel)
 {
        struct panel_simple *p = to_panel_simple(panel);
@@ -156,7 +342,7 @@ static int panel_simple_disable(struct drm_panel *panel)
                backlight_update_status(p->backlight);
        }
 
-       if (p->desc->delay.disable)
+       if (p->desc && p->desc->delay.disable)
                msleep(p->desc->delay.disable);
 
        p->enabled = false;
@@ -167,16 +353,26 @@ static int panel_simple_disable(struct drm_panel *panel)
 static int panel_simple_unprepare(struct drm_panel *panel)
 {
        struct panel_simple *p = to_panel_simple(panel);
+       int err;
 
        if (!p->prepared)
                return 0;
 
+       if (p->off_cmds) {
+               err = panel_simple_dsi_send_cmds(p, p->off_cmds);
+               if (err)
+                       dev_err(p->dev, "failed to send off cmds\n");
+       }
+
+       if (p->reset_gpio)
+               gpiod_direction_output(p->reset_gpio, 1);
+
        if (p->enable_gpio)
-               gpiod_set_value_cansleep(p->enable_gpio, 0);
+               gpiod_direction_output(p->enable_gpio, 0);
 
        regulator_disable(p->supply);
 
-       if (p->desc->delay.unprepare)
+       if (p->desc && p->desc->delay.unprepare)
                msleep(p->desc->delay.unprepare);
 
        p->prepared = false;
@@ -199,11 +395,20 @@ static int panel_simple_prepare(struct drm_panel *panel)
        }
 
        if (p->enable_gpio)
-               gpiod_set_value_cansleep(p->enable_gpio, 1);
+               gpiod_direction_output(p->enable_gpio, 1);
 
-       if (p->desc->delay.prepare)
+       if (p->desc && p->desc->delay.prepare)
                msleep(p->desc->delay.prepare);
 
+       if (p->reset_gpio)
+               gpiod_direction_output(p->reset_gpio, 1);
+
+       if (p->reset_delay)
+               msleep(p->reset_delay);
+
+       if (p->reset_gpio)
+               gpiod_direction_output(p->reset_gpio, 0);
+
        p->prepared = true;
 
        return 0;
@@ -212,11 +417,18 @@ static int panel_simple_prepare(struct drm_panel *panel)
 static int panel_simple_enable(struct drm_panel *panel)
 {
        struct panel_simple *p = to_panel_simple(panel);
+       int err;
 
        if (p->enabled)
                return 0;
 
-       if (p->desc->delay.enable)
+       if (p->on_cmds) {
+               err = panel_simple_dsi_send_cmds(p, p->on_cmds);
+               if (err)
+                       dev_err(p->dev, "failed to send on cmds\n");
+       }
+
+       if (p->desc && p->desc->delay.enable)
                msleep(p->desc->delay.enable);
 
        if (p->backlight) {
@@ -234,6 +446,12 @@ static int panel_simple_get_modes(struct drm_panel *panel)
        struct panel_simple *p = to_panel_simple(panel);
        int num = 0;
 
+       /* add device node plane modes */
+       num += panel_simple_of_get_native_mode(p);
+
+       /* add hard-coded panel modes */
+       num += panel_simple_get_fixed_modes(p);
+
        /* probe EDID if a DDC bus is available */
        if (p->ddc) {
                struct edid *edid = drm_get_edid(panel->connector, p->ddc);
@@ -244,9 +462,6 @@ static int panel_simple_get_modes(struct drm_panel *panel)
                }
        }
 
-       /* add hard-coded panel modes */
-       num += panel_simple_get_fixed_modes(p);
-
        return num;
 }
 
@@ -257,6 +472,9 @@ static int panel_simple_get_timings(struct drm_panel *panel,
        struct panel_simple *p = to_panel_simple(panel);
        unsigned int i;
 
+       if (!p->desc)
+               return 0;
+
        if (p->desc->num_timings < num_timings)
                num_timings = p->desc->num_timings;
 
@@ -280,25 +498,50 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 {
        struct device_node *backlight, *ddc;
        struct panel_simple *panel;
+       struct panel_desc *of_desc;
+       u32 val;
        int err;
 
        panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
        if (!panel)
                return -ENOMEM;
 
+       if (!desc)
+               of_desc = devm_kzalloc(dev, sizeof(*of_desc), GFP_KERNEL);
+       else
+               of_desc = devm_kmemdup(dev, desc, sizeof(*of_desc), GFP_KERNEL);
+
+       if (!of_property_read_u32(dev->of_node, "bus-format", &val))
+               of_desc->bus_format = val;
+       if (!of_property_read_u32(dev->of_node, "delay,prepare", &val))
+               of_desc->delay.prepare = val;
+       if (!of_property_read_u32(dev->of_node, "delay,enable", &val))
+               of_desc->delay.enable = val;
+       if (!of_property_read_u32(dev->of_node, "delay,disable", &val))
+               of_desc->delay.disable = val;
+       if (!of_property_read_u32(dev->of_node, "delay,unprepare", &val))
+               of_desc->delay.unprepare = val;
+
        panel->enabled = false;
        panel->prepared = false;
-       panel->desc = desc;
+       panel->desc = of_desc;
+       panel->dev = dev;
 
        panel->supply = devm_regulator_get(dev, "power");
        if (IS_ERR(panel->supply))
                return PTR_ERR(panel->supply);
 
-       panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
-                                                    GPIOD_OUT_LOW);
+       panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", 0);
        if (IS_ERR(panel->enable_gpio)) {
                err = PTR_ERR(panel->enable_gpio);
-               dev_err(dev, "failed to request GPIO: %d\n", err);
+               dev_err(dev, "failed to request enable GPIO: %d\n", err);
+               return err;
+       }
+
+       panel->reset_gpio = devm_gpiod_get_optional(dev, "reset", 0);
+       if (IS_ERR(panel->reset_gpio)) {
+               err = PTR_ERR(panel->reset_gpio);
+               dev_err(dev, "failed to request reset GPIO: %d\n", err);
                return err;
        }
 
@@ -359,6 +602,8 @@ static int panel_simple_remove(struct device *dev)
        if (panel->backlight)
                put_device(&panel->backlight->dev);
 
+       panel_simple_dsi_cmds_cleanup(panel);
+
        return 0;
 }
 
@@ -440,6 +685,29 @@ static const struct panel_desc auo_b101ean01 = {
        },
 };
 
+static const struct drm_display_mode auo_b101ew05_mode = {
+       .clock = 71000,
+       .hdisplay = 1280,
+       .hsync_start = 1280 + 18,
+       .hsync_end = 1280 + 18 + 10,
+       .htotal = 1280 + 18 + 10 + 100,
+       .vdisplay = 800,
+       .vsync_start = 800 + 6,
+       .vsync_end = 800 + 6 + 2,
+       .vtotal = 800 + 6 + 2 + 8,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_b101ew05 = {
+       .modes = &auo_b101ew05_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 217,
+               .height = 136,
+       },
+};
+
 static const struct drm_display_mode auo_b101xtn01_mode = {
        .clock = 72000,
        .hdisplay = 1366,
@@ -487,6 +755,31 @@ static const struct panel_desc auo_b116xw03 = {
        },
 };
 
+static const struct drm_display_mode auo_b125han03_mode = {
+       .clock = 146900,
+       .hdisplay = 1920,
+       .hsync_start = 1920 + 48,
+       .hsync_end = 1920 + 48 + 32,
+       .htotal = 1920 + 48 + 32 + 140,
+       .vdisplay = 1080,
+       .vsync_start = 1080 + 2,
+       .vsync_end = 1080 + 2 + 5,
+       .vtotal = 1080 + 2 + 5 + 57,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc auo_b125han03 = {
+       .modes = &auo_b125han03_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 276,
+               .height = 156,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct drm_display_mode auo_b133xtn01_mode = {
        .clock = 69500,
        .hdisplay = 1366,
@@ -566,6 +859,57 @@ static const struct panel_desc avic_tm070ddh03 = {
        },
 };
 
+static const struct drm_display_mode boe_nv125fhm_n73_mode = {
+       .clock = 72300,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 80,
+       .hsync_end = 1366 + 80 + 20,
+       .htotal = 1366 + 80 + 20 + 60,
+       .vdisplay = 768,
+       .vsync_start = 768 + 12,
+       .vsync_end = 768 + 12 + 2,
+       .vtotal = 768 + 12 + 2 + 8,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc boe_nv125fhm_n73 = {
+       .modes = &boe_nv125fhm_n73_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 276,
+               .height = 156,
+       },
+       .delay = {
+               .unprepare = 160,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
+static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
+       .clock = 67000,
+       .hdisplay = 800,
+       .hsync_start = 800 + 24,
+       .hsync_end = 800 + 24 + 16,
+       .htotal = 800 + 24 + 16 + 24,
+       .vdisplay = 1280,
+       .vsync_start = 1280 + 2,
+       .vsync_end = 1280 + 2 + 2,
+       .vtotal = 1280 + 2 + 2 + 4,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc chunghwa_claa070wp03xg = {
+       .modes = &chunghwa_claa070wp03xg_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 94,
+               .height = 151,
+       },
+};
+
 static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
        .clock = 72070,
        .hdisplay = 1366,
@@ -856,6 +1200,35 @@ static const struct panel_desc innolux_n116bge = {
        },
 };
 
+static const struct drm_display_mode innolux_n125hce_mode = {
+       .clock = 138780,
+       .hdisplay = 1920,
+       .hsync_start = 1920 + 80,
+       .hsync_end = 1920 + 80 + 30,
+       .htotal = 1920 + 80 + 30 + 50,
+       .vdisplay = 1080,
+       .vsync_start = 1080 + 12,
+       .vsync_end = 1080 + 12 + 4,
+       .vtotal = 1080 + 12 + 4 + 16,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc innolux_n125hce = {
+       .modes = &innolux_n125hce_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 283,
+               .height = 168,
+       },
+       .delay = {
+               .unprepare = 600,
+               .enable = 100,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct drm_display_mode innolux_n156bge_l21_mode = {
        .clock = 69300,
        .hdisplay = 1366,
@@ -926,6 +1299,77 @@ static const struct panel_desc lg_lb070wv8 = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
 };
 
+static const struct drm_display_mode sharp_lcd_f402_mode = {
+       .clock = 205000,
+       .hdisplay = 1536,
+       .hsync_start = 1536 + 12,
+       .hsync_end = 1536 + 12 + 48,
+       .htotal = 1536 + 12 + 48 + 16,
+       .vdisplay = 2048,
+       .vsync_start = 2048 + 8,
+       .vsync_end = 2048 + 8 + 8,
+       .vtotal = 2048 + 8 + 8 + 4,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc sharp_lcd_f402 = {
+       .modes = &sharp_lcd_f402_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 95,
+               .height = 54,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
+static const struct drm_display_mode lg_lp079qx1_sp0v_mode = {
+       .clock = 200000,
+       .hdisplay = 1536,
+       .hsync_start = 1536 + 12,
+       .hsync_end = 1536 + 12 + 16,
+       .htotal = 1536 + 12 + 16 + 48,
+       .vdisplay = 2048,
+       .vsync_start = 2048 + 8,
+       .vsync_end = 2048 + 8 + 4,
+       .vtotal = 2048 + 8 + 4 + 8,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc lg_lp079qx1_sp0v = {
+       .modes = &lg_lp079qx1_sp0v_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 129,
+               .height = 171,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
+static const struct drm_display_mode lg_lp097qx1_spa1_mode = {
+       .clock = 205210,
+       .hdisplay = 2048,
+       .hsync_start = 2048 + 150,
+       .hsync_end = 2048 + 150 + 5,
+       .htotal = 2048 + 150 + 5 + 5,
+       .vdisplay = 1536,
+       .vsync_start = 1536 + 3,
+       .vsync_end = 1536 + 3 + 1,
+       .vtotal = 1536 + 3 + 1 + 9,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc lg_lp097qx1_spa1 = {
+       .modes = &lg_lp097qx1_spa1_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 320,
+               .height = 187,
+       },
+};
+
 static const struct drm_display_mode lg_lp129qe_mode = {
        .clock = 285250,
        .hdisplay = 2560,
@@ -1027,6 +1471,28 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
+static const struct drm_display_mode samsung_lsn122dl01_c01_mode = {
+       .clock = 271560,
+       .hdisplay = 2560,
+       .hsync_start = 2560 + 48,
+       .hsync_end = 2560 + 48 + 32,
+       .htotal = 2560 + 48 + 32 + 80,
+       .vdisplay = 1600,
+       .vsync_start = 1600 + 2,
+       .vsync_end = 1600 + 2 + 5,
+       .vtotal = 1600 + 2 + 5 + 57,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc samsung_lsn122dl01_c01 = {
+       .modes = &samsung_lsn122dl01_c01_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 2560,
+               .height = 1600,
+       },
+};
+
 static const struct drm_display_mode samsung_ltn101nt05_mode = {
        .clock = 54030,
        .hdisplay = 1024,
@@ -1098,6 +1564,9 @@ static const struct panel_desc shelly_sca07010_bfn_lnn = {
 
 static const struct of_device_id platform_of_match[] = {
        {
+               .compatible = "simple-panel",
+               .data = NULL,
+       }, {
                .compatible = "ampire,am800480r3tmqwa1h",
                .data = &ampire_am800480r3tmqwa1h,
        }, {
@@ -1106,12 +1575,18 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "auo,b101ean01",
                .data = &auo_b101ean01,
+       }, {
+               .compatible = "auo,b101ew05",
+               .data = &auo_b101ew05,
        }, {
                .compatible = "auo,b101xtn01",
                .data = &auo_b101xtn01,
        }, {
                .compatible = "auo,b116xw03",
                .data = &auo_b116xw03,
+       }, {
+               .compatible = "auo,b125han03",
+               .data = &auo_b125han03,
        }, {
                .compatible = "auo,b133htn01",
                .data = &auo_b133htn01,
@@ -1121,6 +1596,12 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "avic,tm070ddh03",
                .data = &avic_tm070ddh03,
+       }, {
+               .compatible = "boe,nv125fhm-n73",
+               .data = &boe_nv125fhm_n73,
+       }, {
+               .compatible = "chunghwa,claa070wp03xg",
+               .data = &chunghwa_claa070wp03xg,
        }, {
                .compatible = "chunghwa,claa101wa01a",
                .data = &chunghwa_claa101wa01a
@@ -1160,6 +1641,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "innolux,n116bge",
                .data = &innolux_n116bge,
+       }, {
+               .compatible = "innolux,n125hce",
+               .data = &innolux_n125hce,
        }, {
                .compatible = "innolux,n156bge-l21",
                .data = &innolux_n156bge_l21,
@@ -1169,6 +1653,12 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "lg,lb070wv8",
                .data = &lg_lb070wv8,
+       }, {
+               .compatible = "lg,lp079qx1-sp0v",
+               .data = &lg_lp079qx1_sp0v,
+       }, {
+               .compatible = "lg,lp097qx1-spa1",
+               .data = &lg_lp097qx1_spa1,
        }, {
                .compatible = "lg,lp129qe",
                .data = &lg_lp129qe,
@@ -1181,12 +1671,18 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "ortustech,com43h4m85ulc",
                .data = &ortustech_com43h4m85ulc,
+       }, {
+               .compatible = "samsung,lsn122dl01-c01",
+               .data = &samsung_lsn122dl01_c01,
        }, {
                .compatible = "samsung,ltn101nt05",
                .data = &samsung_ltn101nt05,
        }, {
                .compatible = "samsung,ltn140at29-301",
                .data = &samsung_ltn140at29_301,
+       }, {
+               .compatible = "sharp,lcd-f402",
+               .data = &sharp_lcd_f402,
        }, {
                .compatible = "shelly,sca07010-bfn-lnn",
                .data = &shelly_sca07010_bfn_lnn,
@@ -1263,6 +1759,36 @@ static const struct panel_desc_dsi auo_b080uan01 = {
        .lanes = 4,
 };
 
+static const struct drm_display_mode boe_tv080wum_nl0_mode = {
+       .clock = 160000,
+       .hdisplay = 1200,
+       .hsync_start = 1200 + 120,
+       .hsync_end = 1200 + 120 + 20,
+       .htotal = 1200 + 120 + 20 + 21,
+       .vdisplay = 1920,
+       .vsync_start = 1920 + 21,
+       .vsync_end = 1920 + 21 + 3,
+       .vtotal = 1920 + 21 + 3 + 18,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc_dsi boe_tv080wum_nl0 = {
+       .desc = {
+               .modes = &boe_tv080wum_nl0_mode,
+               .num_modes = 1,
+               .size = {
+                       .width = 107,
+                       .height = 172,
+               },
+       },
+       .flags = MIPI_DSI_MODE_VIDEO |
+                MIPI_DSI_MODE_VIDEO_BURST |
+                MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+};
+
 static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
        .clock = 71000,
        .hdisplay = 800,
@@ -1348,10 +1874,17 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
        .lanes = 4,
 };
 
+
 static const struct of_device_id dsi_of_match[] = {
        {
+               .compatible = "simple-panel-dsi",
+               .data = NULL
+       }, {
                .compatible = "auo,b080uan01",
                .data = &auo_b080uan01
+       }, {
+               .compatible = "boe,tv080wum-nl0",
+               .data = &boe_tv080wum_nl0
        }, {
                .compatible = "lg,ld070wx3-sl01",
                .data = &lg_ld070wx3_sl01
@@ -1369,8 +1902,13 @@ MODULE_DEVICE_TABLE(of, dsi_of_match);
 
 static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
 {
+       struct panel_simple *panel;
        const struct panel_desc_dsi *desc;
        const struct of_device_id *id;
+       const struct panel_desc *pdesc;
+       const void *data;
+       int len;
+       u32 val;
        int err;
 
        id = of_match_node(dsi_of_match, dsi->dev.of_node);
@@ -1379,13 +1917,65 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
 
        desc = id->data;
 
-       err = panel_simple_probe(&dsi->dev, &desc->desc);
+       if (desc) {
+               dsi->mode_flags = desc->flags;
+               dsi->format = desc->format;
+               dsi->lanes = desc->lanes;
+               pdesc = &desc->desc;
+       } else {
+               pdesc = NULL;
+       }
+
+       err = panel_simple_probe(&dsi->dev, pdesc);
        if (err < 0)
                return err;
 
-       dsi->mode_flags = desc->flags;
-       dsi->format = desc->format;
-       dsi->lanes = desc->lanes;
+       panel = dev_get_drvdata(&dsi->dev);
+       panel->dsi = dsi;
+
+       if (!of_property_read_u32(dsi->dev.of_node, "dsi,flags", &val))
+               dsi->mode_flags = val;
+
+       if (!of_property_read_u32(dsi->dev.of_node, "dsi,format", &val))
+               dsi->format = val;
+
+       if (!of_property_read_u32(dsi->dev.of_node, "dsi,lanes", &val))
+               dsi->lanes = val;
+
+       if (!of_property_read_u32(dsi->dev.of_node, "reset-delay-ms", &val))
+               panel->reset_delay = val;
+
+       data = of_get_property(dsi->dev.of_node, "panel-init-sequence", &len);
+       if (data) {
+               panel->on_cmds = devm_kzalloc(&dsi->dev,
+                                             sizeof(*panel->on_cmds),
+                                             GFP_KERNEL);
+               if (!panel->on_cmds)
+                       return -ENOMEM;
+
+               err = panel_simple_dsi_parse_dcs_cmds(&dsi->dev, data, len,
+                                                     panel->on_cmds);
+               if (err) {
+                       dev_err(&dsi->dev, "failed to parse panel init sequence\n");
+                       return err;
+               }
+       }
+
+       data = of_get_property(dsi->dev.of_node, "panel-exit-sequence", &len);
+       if (data) {
+               panel->off_cmds = devm_kzalloc(&dsi->dev,
+                                              sizeof(*panel->off_cmds),
+                                              GFP_KERNEL);
+               if (!panel->off_cmds)
+                       return -ENOMEM;
+
+               err = panel_simple_dsi_parse_dcs_cmds(&dsi->dev, data, len,
+                                                     panel->off_cmds);
+               if (err) {
+                       dev_err(&dsi->dev, "failed to parse panel exit sequence\n");
+                       return err;
+               }
+       }
 
        return mipi_dsi_attach(dsi);
 }