drm/msm/mdp4: Initialize LCDC encoder even if panel driver isn't available
authorArchit Taneja <architt@codeaurora.org>
Wed, 18 Nov 2015 11:45:50 +0000 (17:15 +0530)
committerRob Clark <robdclark@gmail.com>
Mon, 14 Dec 2015 15:39:36 +0000 (10:39 -0500)
Currently, the driver defers if it doesn't find a drm_panel. This forces
us to have a drm_panel, if not, the driver isn't usable.

Make the lcdc encoder initialization independent of the availability of
the drm panel. We only check if there is a panel node specified in DT. If
it isn't, then we don't initialize the encoder at all. The panel node is
passed to the lcdc encoder and lvds connector drivers.

The connector driver takes the responsibility to retrieve the drm_panel
from the panel node, and update the status on whether the panel is
connected or not. This makes the panel usable even if the drm_panel
driver is inserted as a module later on.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c

index 379b4352185354c146b938c3562dd3e979b952af..6c9dd2848e5f373341076df444e9b192ba1503e6 100644 (file)
@@ -240,18 +240,18 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
        return 0;
 }
 
-static struct drm_panel *detect_panel(struct drm_device *dev)
+static struct device_node *mdp4_detect_lcdc_panel(struct drm_device *dev)
 {
        struct device_node *endpoint, *panel_node;
        struct device_node *np = dev->dev->of_node;
-       struct drm_panel *panel = NULL;
 
        endpoint = of_graph_get_next_endpoint(np, NULL);
        if (!endpoint) {
-               dev_err(dev->dev, "no valid endpoint\n");
-               return ERR_PTR(-ENODEV);
+               DBG("no endpoint in MDP4 to fetch LVDS panel\n");
+               return NULL;
        }
 
+       /* don't proceed if we have an endpoint but no panel_node tied to it */
        panel_node = of_graph_get_remote_port_parent(endpoint);
        if (!panel_node) {
                dev_err(dev->dev, "no valid panel node\n");
@@ -261,13 +261,7 @@ static struct drm_panel *detect_panel(struct drm_device *dev)
 
        of_node_put(endpoint);
 
-       panel = of_drm_find_panel(panel_node);
-       if (!panel) {
-               of_node_put(panel_node);
-               return ERR_PTR(-EPROBE_DEFER);
-       }
-
-       return panel;
+       return panel_node;
 }
 
 static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
@@ -277,18 +271,22 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
        struct msm_drm_private *priv = dev->dev_private;
        struct drm_encoder *encoder;
        struct drm_connector *connector;
-       struct drm_panel *panel;
+       struct device_node *panel_node;
        int ret;
 
        switch (intf_type) {
        case DRM_MODE_ENCODER_LVDS:
-               panel = detect_panel(dev);
-               if (IS_ERR(panel)) {
-                       dev_err(dev->dev, "failed to detect LVDS panel\n");
-                       return PTR_ERR(panel);
-               }
-
-               encoder = mdp4_lcdc_encoder_init(dev, panel);
+               /*
+                * bail out early if:
+                * - there is no panel node (no need to initialize lcdc
+                *   encoder and lvds connector), or
+                * - panel node is a bad pointer
+                */
+               panel_node = mdp4_detect_lcdc_panel(dev);
+               if (IS_ERR_OR_NULL(panel_node))
+                       return PTR_ERR(panel_node);
+
+               encoder = mdp4_lcdc_encoder_init(dev, panel_node);
                if (IS_ERR(encoder)) {
                        dev_err(dev->dev, "failed to construct LCDC encoder\n");
                        return PTR_ERR(encoder);
@@ -297,7 +295,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
                /* LCDC can be hooked to DMA_P (TODO: Add DMA_S later?) */
                encoder->possible_crtcs = 1 << DMA_P;
 
-               connector = mdp4_lvds_connector_init(dev, panel, encoder);
+               connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
                if (IS_ERR(connector)) {
                        dev_err(dev->dev, "failed to initialize LVDS connector\n");
                        return PTR_ERR(connector);
index 8a7f6e1e2bca9dd0ba3205995a374516c2d53350..7d03585424f7de5e00794d99dadb582507d86e94 100644 (file)
@@ -212,10 +212,10 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
 
 long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
 struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
-               struct drm_panel *panel);
+               struct device_node *panel_node);
 
 struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
-               struct drm_panel *panel, struct drm_encoder *encoder);
+               struct device_node *panel_node, struct drm_encoder *encoder);
 
 #ifdef CONFIG_COMMON_CLK
 struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
index 4cd6e721aa0a3a51f4c206ab8234885d97b8d7e5..1bda2de203347c60e2893f500b1fe2c66f29562e 100644 (file)
@@ -23,6 +23,7 @@
 
 struct mdp4_lcdc_encoder {
        struct drm_encoder base;
+       struct device_node *panel_node;
        struct drm_panel *panel;
        struct clk *lcdc_clk;
        unsigned long int pixclock;
@@ -338,7 +339,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
        struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
                        to_mdp4_lcdc_encoder(encoder);
        struct mdp4_kms *mdp4_kms = get_kms(encoder);
-       struct drm_panel *panel = mdp4_lcdc_encoder->panel;
+       struct drm_panel *panel;
        int i, ret;
 
        if (WARN_ON(!mdp4_lcdc_encoder->enabled))
@@ -346,6 +347,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
 
        mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
 
+       panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
        if (panel) {
                drm_panel_disable(panel);
                drm_panel_unprepare(panel);
@@ -381,7 +383,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
                        to_mdp4_lcdc_encoder(encoder);
        unsigned long pc = mdp4_lcdc_encoder->pixclock;
        struct mdp4_kms *mdp4_kms = get_kms(encoder);
-       struct drm_panel *panel = mdp4_lcdc_encoder->panel;
+       struct drm_panel *panel;
        int i, ret;
 
        if (WARN_ON(mdp4_lcdc_encoder->enabled))
@@ -414,6 +416,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
        if (ret)
                dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
 
+       panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
        if (panel) {
                drm_panel_prepare(panel);
                drm_panel_enable(panel);
@@ -442,7 +445,7 @@ long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
 
 /* initialize encoder */
 struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
-               struct drm_panel *panel)
+               struct device_node *panel_node)
 {
        struct drm_encoder *encoder = NULL;
        struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
@@ -455,7 +458,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
                goto fail;
        }
 
-       mdp4_lcdc_encoder->panel = panel;
+       mdp4_lcdc_encoder->panel_node = panel_node;
 
        encoder = &mdp4_lcdc_encoder->base;
 
index 921185133d38bc7b8237df53acdaa07654e31dc9..e73e1742b25005d85c8620c36e85c9f2a45cdd3a 100644 (file)
@@ -23,6 +23,7 @@
 struct mdp4_lvds_connector {
        struct drm_connector base;
        struct drm_encoder *encoder;
+       struct device_node *panel_node;
        struct drm_panel *panel;
 };
 #define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
@@ -33,6 +34,10 @@ static enum drm_connector_status mdp4_lvds_connector_detect(
        struct mdp4_lvds_connector *mdp4_lvds_connector =
                        to_mdp4_lvds_connector(connector);
 
+       if (!mdp4_lvds_connector->panel)
+               mdp4_lvds_connector->panel =
+                       of_drm_find_panel(mdp4_lvds_connector->panel_node);
+
        return mdp4_lvds_connector->panel ?
                        connector_status_connected :
                        connector_status_disconnected;
@@ -42,10 +47,6 @@ static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
 {
        struct mdp4_lvds_connector *mdp4_lvds_connector =
                        to_mdp4_lvds_connector(connector);
-       struct drm_panel *panel = mdp4_lvds_connector->panel;
-
-       if (panel)
-               drm_panel_detach(panel);
 
        drm_connector_unregister(connector);
        drm_connector_cleanup(connector);
@@ -60,9 +61,14 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
        struct drm_panel *panel = mdp4_lvds_connector->panel;
        int ret = 0;
 
-       if (panel)
+       if (panel) {
+               drm_panel_attach(panel, connector);
+
                ret = panel->funcs->get_modes(panel);
 
+               drm_panel_detach(panel);
+       }
+
        return ret;
 }
 
@@ -111,7 +117,7 @@ static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs
 
 /* initialize connector */
 struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
-               struct drm_panel *panel, struct drm_encoder *encoder)
+               struct device_node *panel_node, struct drm_encoder *encoder)
 {
        struct drm_connector *connector = NULL;
        struct mdp4_lvds_connector *mdp4_lvds_connector;
@@ -124,7 +130,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
        }
 
        mdp4_lvds_connector->encoder = encoder;
-       mdp4_lvds_connector->panel = panel;
+       mdp4_lvds_connector->panel_node = panel_node;
 
        connector = &mdp4_lvds_connector->base;
 
@@ -141,9 +147,6 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
 
        drm_mode_connector_attach_encoder(connector, encoder);
 
-       if (panel)
-               drm_panel_attach(panel, connector);
-
        return connector;
 
 fail: