Merge tag 'lsk-v4.4-16.07-android'
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / panel / panel-simple.c
index 49b101e4899ed3cd6dd29abde0740057a127e829..51fd0abd13cebea1ac52a30f619ff2a11495642e 100644 (file)
@@ -34,6 +34,7 @@
 #include <drm/drm_panel.h>
 
 #include <video/display_timing.h>
+#include <video/of_display_timing.h>
 #include <video/videomode.h>
 
 struct panel_desc {
@@ -75,6 +76,7 @@ struct panel_simple {
        bool prepared;
        bool enabled;
 
+       struct device *dev;
        const struct panel_desc *desc;
 
        struct backlight_device *backlight;
@@ -144,6 +146,32 @@ 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;
+       int ret;
+
+       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 +184,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;
@@ -172,11 +200,11 @@ static int panel_simple_unprepare(struct drm_panel *panel)
                return 0;
 
        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,9 +227,9 @@ 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);
 
        p->prepared = true;
@@ -216,7 +244,7 @@ static int panel_simple_enable(struct drm_panel *panel)
        if (p->enabled)
                return 0;
 
-       if (p->desc->delay.enable)
+       if (p->desc && p->desc->delay.enable)
                msleep(p->desc->delay.enable);
 
        if (p->backlight) {
@@ -247,6 +275,9 @@ static int panel_simple_get_modes(struct drm_panel *panel)
        /* add hard-coded panel modes */
        num += panel_simple_get_fixed_modes(p);
 
+       /* add device node plane modes */
+       num += panel_simple_of_get_native_mode(p);
+
        return num;
 }
 
@@ -257,6 +288,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;
 
@@ -289,13 +323,13 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
        panel->enabled = false;
        panel->prepared = false;
        panel->desc = 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);
@@ -440,6 +474,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,
@@ -566,6 +623,29 @@ static const struct panel_desc avic_tm070ddh03 = {
        },
 };
 
+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,
@@ -926,6 +1006,29 @@ static const struct panel_desc lg_lb070wv8 = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
 };
 
+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,
+       },
+};
+
 static const struct drm_display_mode lg_lp097qx1_spa1_mode = {
        .clock = 205210,
        .hdisplay = 2048,
@@ -1142,6 +1245,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,
        }, {
@@ -1150,6 +1256,9 @@ 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,
@@ -1165,6 +1274,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "avic,tm070ddh03",
                .data = &avic_tm070ddh03,
+       }, {
+               .compatible = "chunghwa,claa070wp03xg",
+               .data = &chunghwa_claa070wp03xg,
        }, {
                .compatible = "chunghwa,claa101wa01a",
                .data = &chunghwa_claa101wa01a
@@ -1213,6 +1325,9 @@ 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,
@@ -1431,6 +1546,9 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
 
 static const struct of_device_id dsi_of_match[] = {
        {
+               .compatible = "simple-panel-dsi",
+               .data = NULL
+       }, {
                .compatible = "auo,b080uan01",
                .data = &auo_b080uan01
        }, {
@@ -1455,6 +1573,8 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
 {
        const struct panel_desc_dsi *desc;
        const struct of_device_id *id;
+       const struct panel_desc *pdesc;
+       u32 val;
        int err;
 
        id = of_match_node(dsi_of_match, dsi->dev.of_node);
@@ -1463,13 +1583,27 @@ 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;
+       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;
 
        return mipi_dsi_attach(dsi);
 }