These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / msm / dsi / dsi.c
index ad50b80..6edcd6f 100644 (file)
 
 struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
 {
-       if (!msm_dsi || !msm_dsi->panel)
+       if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
                return NULL;
 
-       return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
+       return (msm_dsi->device_flags & MIPI_DSI_MODE_VIDEO) ?
                msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
                msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
 }
 
+static int dsi_get_phy(struct msm_dsi *msm_dsi)
+{
+       struct platform_device *pdev = msm_dsi->pdev;
+       struct platform_device *phy_pdev;
+       struct device_node *phy_node;
+
+       phy_node = of_parse_phandle(pdev->dev.of_node, "qcom,dsi-phy", 0);
+       if (!phy_node) {
+               dev_err(&pdev->dev, "cannot find phy device\n");
+               return -ENXIO;
+       }
+
+       phy_pdev = of_find_device_by_node(phy_node);
+       if (phy_pdev)
+               msm_dsi->phy = platform_get_drvdata(phy_pdev);
+
+       of_node_put(phy_node);
+
+       if (!phy_pdev || !msm_dsi->phy) {
+               dev_err(&pdev->dev, "%s: phy driver is not ready\n", __func__);
+               return -EPROBE_DEFER;
+       }
+
+       msm_dsi->phy_dev = get_device(&phy_pdev->dev);
+
+       return 0;
+}
+
 static void dsi_destroy(struct msm_dsi *msm_dsi)
 {
        if (!msm_dsi)
                return;
 
        msm_dsi_manager_unregister(msm_dsi);
+
+       if (msm_dsi->phy_dev) {
+               put_device(msm_dsi->phy_dev);
+               msm_dsi->phy = NULL;
+               msm_dsi->phy_dev = NULL;
+       }
+
        if (msm_dsi->host) {
                msm_dsi_host_destroy(msm_dsi->host);
                msm_dsi->host = NULL;
@@ -39,20 +74,15 @@ static void dsi_destroy(struct msm_dsi *msm_dsi)
 
 static struct msm_dsi *dsi_init(struct platform_device *pdev)
 {
-       struct msm_dsi *msm_dsi = NULL;
+       struct msm_dsi *msm_dsi;
        int ret;
 
-       if (!pdev) {
-               dev_err(&pdev->dev, "no dsi device\n");
-               ret = -ENXIO;
-               goto fail;
-       }
+       if (!pdev)
+               return ERR_PTR(-ENXIO);
 
        msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
-       if (!msm_dsi) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       if (!msm_dsi)
+               return ERR_PTR(-ENOMEM);
        DBG("dsi probed=%p", msm_dsi);
 
        msm_dsi->pdev = pdev;
@@ -61,19 +91,22 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev)
        /* Init dsi host */
        ret = msm_dsi_host_init(msm_dsi);
        if (ret)
-               goto fail;
+               goto destroy_dsi;
+
+       /* GET dsi PHY */
+       ret = dsi_get_phy(msm_dsi);
+       if (ret)
+               goto destroy_dsi;
 
        /* Register to dsi manager */
        ret = msm_dsi_manager_register(msm_dsi);
        if (ret)
-               goto fail;
+               goto destroy_dsi;
 
        return msm_dsi;
 
-fail:
-       if (msm_dsi)
-               dsi_destroy(msm_dsi);
-
+destroy_dsi:
+       dsi_destroy(msm_dsi);
        return ERR_PTR(ret);
 }
 
@@ -142,12 +175,14 @@ static struct platform_driver dsi_driver = {
 void __init msm_dsi_register(void)
 {
        DBG("");
+       msm_dsi_phy_driver_register();
        platform_driver_register(&dsi_driver);
 }
 
 void __exit msm_dsi_unregister(void)
 {
        DBG("");
+       msm_dsi_phy_driver_unregister();
        platform_driver_unregister(&dsi_driver);
 }
 
@@ -155,6 +190,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
                struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
 {
        struct msm_drm_private *priv = dev->dev_private;
+       struct drm_bridge *ext_bridge;
        int ret, i;
 
        if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
@@ -182,10 +218,25 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
                msm_dsi->encoders[i] = encoders[i];
        }
 
-       msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
+       /*
+        * check if the dsi encoder output is connected to a panel or an
+        * external bridge. We create a connector only if we're connected to a
+        * drm_panel device. When we're connected to an external bridge, we
+        * assume that the drm_bridge driver will create the connector itself.
+        */
+       ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host);
+
+       if (ext_bridge)
+               msm_dsi->connector =
+                       msm_dsi_manager_ext_bridge_init(msm_dsi->id);
+       else
+               msm_dsi->connector =
+                       msm_dsi_manager_connector_init(msm_dsi->id);
+
        if (IS_ERR(msm_dsi->connector)) {
                ret = PTR_ERR(msm_dsi->connector);
-               dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
+               dev_err(dev->dev,
+                       "failed to create dsi connector: %d\n", ret);
                msm_dsi->connector = NULL;
                goto fail;
        }
@@ -201,10 +252,12 @@ fail:
                        msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
                        msm_dsi->bridge = NULL;
                }
-               if (msm_dsi->connector) {
+
+               /* don't destroy connector if we didn't make it */
+               if (msm_dsi->connector && !msm_dsi->external_bridge)
                        msm_dsi->connector->funcs->destroy(msm_dsi->connector);
-                       msm_dsi->connector = NULL;
-               }
+
+               msm_dsi->connector = NULL;
        }
 
        return ret;