drm/msm/hdmi: refactor bind/init
authorRob Clark <robdclark@gmail.com>
Tue, 4 Nov 2014 18:33:14 +0000 (13:33 -0500)
committerRob Clark <robdclark@gmail.com>
Sun, 16 Nov 2014 19:22:42 +0000 (14:22 -0500)
Split up hdmi_init() into hdmi_init() (done at hdmi sub-device
bind/probe time) and hdmi_modeset_init() done from master driver's
modeset_init().

Anything that can fail due to dependencies on other drivers which
may be missing or not probed yet should go in hdmi_init(), so that
devm error/cleanup paths work properly.

Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
drivers/gpu/drm/msm/msm_drv.h

index 9d00dcba695950873c77baa761dea89e4b86aeac..90077619029de28c2c2b479c109bcc5cacd6bbe8 100644 (file)
@@ -68,24 +68,17 @@ void hdmi_destroy(struct kref *kref)
        platform_set_drvdata(hdmi->pdev, NULL);
 }
 
-/* initialize connector */
-struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
+/* construct hdmi at bind/probe time, grab all the resources.  If
+ * we are to EPROBE_DEFER we want to do it here, rather than later
+ * at modeset_init() time
+ */
+static struct hdmi *hdmi_init(struct platform_device *pdev)
 {
+       struct hdmi_platform_config *config = pdev->dev.platform_data;
        struct hdmi *hdmi = NULL;
-       struct msm_drm_private *priv = dev->dev_private;
-       struct platform_device *pdev = priv->hdmi_pdev;
-       struct hdmi_platform_config *config;
        int i, ret;
 
-       if (!pdev) {
-               dev_err(dev->dev, "no hdmi device\n");
-               ret = -ENXIO;
-               goto fail;
-       }
-
-       config = pdev->dev.platform_data;
-
-       hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
+       hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
        if (!hdmi) {
                ret = -ENOMEM;
                goto fail;
@@ -93,12 +86,8 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 
        kref_init(&hdmi->refcount);
 
-       hdmi->dev = dev;
        hdmi->pdev = pdev;
        hdmi->config = config;
-       hdmi->encoder = encoder;
-
-       hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
 
        /* not sure about which phy maps to which msm.. probably I miss some */
        if (config->phy_init)
@@ -108,7 +97,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 
        if (IS_ERR(hdmi->phy)) {
                ret = PTR_ERR(hdmi->phy);
-               dev_err(dev->dev, "failed to load phy: %d\n", ret);
+               dev_err(&pdev->dev, "failed to load phy: %d\n", ret);
                hdmi->phy = NULL;
                goto fail;
        }
@@ -127,7 +116,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                                config->hpd_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
-                       dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get hpd regulator: %s (%d)\n",
                                        config->hpd_reg_names[i], ret);
                        goto fail;
                }
@@ -143,7 +132,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                                config->pwr_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
-                       dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get pwr regulator: %s (%d)\n",
                                        config->pwr_reg_names[i], ret);
                        goto fail;
                }
@@ -158,7 +147,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get hpd clk: %s (%d)\n",
                                        config->hpd_clk_names[i], ret);
                        goto fail;
                }
@@ -173,7 +162,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get pwr clk: %s (%d)\n",
                                        config->pwr_clk_names[i], ret);
                        goto fail;
                }
@@ -184,11 +173,41 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        hdmi->i2c = hdmi_i2c_init(hdmi);
        if (IS_ERR(hdmi->i2c)) {
                ret = PTR_ERR(hdmi->i2c);
-               dev_err(dev->dev, "failed to get i2c: %d\n", ret);
+               dev_err(&pdev->dev, "failed to get i2c: %d\n", ret);
                hdmi->i2c = NULL;
                goto fail;
        }
 
+       return hdmi;
+
+fail:
+       if (hdmi)
+               hdmi_destroy(&hdmi->refcount);
+
+       return ERR_PTR(ret);
+}
+
+/* Second part of initialization, the drm/kms level modeset_init,
+ * constructs/initializes mode objects, etc, is called from master
+ * driver (not hdmi sub-device's probe/bind!)
+ *
+ * Any resource (regulator/clk/etc) which could be missing at boot
+ * should be handled in hdmi_init() so that failure happens from
+ * hdmi sub-device's probe.
+ */
+int hdmi_modeset_init(struct hdmi *hdmi,
+               struct drm_device *dev, struct drm_encoder *encoder)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       struct platform_device *pdev = hdmi->pdev;
+       struct hdmi_platform_config *config = pdev->dev.platform_data;
+       int ret;
+
+       hdmi->dev = dev;
+       hdmi->encoder = encoder;
+
+       hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
+
        hdmi->bridge = hdmi_bridge_init(hdmi);
        if (IS_ERR(hdmi->bridge)) {
                ret = PTR_ERR(hdmi->bridge);
@@ -230,19 +249,20 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 
        platform_set_drvdata(pdev, hdmi);
 
-       return hdmi;
+       return 0;
 
 fail:
-       if (hdmi) {
-               /* bridge/connector are normally destroyed by drm: */
-               if (hdmi->bridge)
-                       hdmi->bridge->funcs->destroy(hdmi->bridge);
-               if (hdmi->connector)
-                       hdmi->connector->funcs->destroy(hdmi->connector);
-               hdmi_destroy(&hdmi->refcount);
+       /* bridge/connector are normally destroyed by drm: */
+       if (hdmi->bridge) {
+               hdmi->bridge->funcs->destroy(hdmi->bridge);
+               hdmi->bridge = NULL;
+       }
+       if (hdmi->connector) {
+               hdmi->connector->funcs->destroy(hdmi->connector);
+               hdmi->connector = NULL;
        }
 
-       return ERR_PTR(ret);
+       return ret;
 }
 
 /*
@@ -251,11 +271,10 @@ fail:
 
 #include <linux/of_gpio.h>
 
-static void set_hdmi_pdev(struct drm_device *dev,
-               struct platform_device *pdev)
+static void set_hdmi(struct drm_device *dev, struct hdmi *hdmi)
 {
        struct msm_drm_private *priv = dev->dev_private;
-       priv->hdmi_pdev = pdev;
+       priv->hdmi = hdmi;
 }
 
 #ifdef CONFIG_OF
@@ -279,6 +298,7 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char
 static int hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        static struct hdmi_platform_config config = {};
+       struct hdmi *hdmi;
 #ifdef CONFIG_OF
        struct device_node *of_node = dev->of_node;
 
@@ -369,14 +389,17 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
        }
 #endif
        dev->platform_data = &config;
-       set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev));
+       hdmi = hdmi_init(to_platform_device(dev));
+       if (IS_ERR(hdmi))
+               return PTR_ERR(hdmi);
+       set_hdmi(dev_get_drvdata(master), hdmi);
        return 0;
 }
 
 static void hdmi_unbind(struct device *dev, struct device *master,
                void *data)
 {
-       set_hdmi_pdev(dev_get_drvdata(master), NULL);
+       set_hdmi(dev_get_drvdata(master), NULL);
 }
 
 static const struct component_ops hdmi_ops = {
index f408b69486a8eb83d299abc636356187d2d467bb..eeed006eed1337a6c07c62e0cc62d944b95fce83 100644 (file)
@@ -510,7 +510,7 @@ struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi)
 
 #ifdef CONFIG_COMMON_CLK
        phy_8960->pll_hw.init = &pll_init;
-       phy_8960->pll = devm_clk_register(hdmi->dev->dev, &phy_8960->pll_hw);
+       phy_8960->pll = devm_clk_register(&hdmi->pdev->dev, &phy_8960->pll_hw);
        if (IS_ERR(phy_8960->pll)) {
                ret = PTR_ERR(phy_8960->pll);
                phy_8960->pll = NULL;
index ac204720429e9d4f363feb9b2b2165ade05dc6cc..a62109e4ae0d3603822fdf91fe99523f58c7b6e4 100644 (file)
@@ -228,7 +228,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        struct drm_encoder *encoder;
        struct drm_connector *connector;
        struct drm_panel *panel;
-       struct hdmi *hdmi;
        int ret;
 
        /* construct non-private planes: */
@@ -326,11 +325,13 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        priv->crtcs[priv->num_crtcs++] = crtc;
        priv->encoders[priv->num_encoders++] = encoder;
 
-       hdmi = hdmi_init(dev, encoder);
-       if (IS_ERR(hdmi)) {
-               ret = PTR_ERR(hdmi);
-               dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
-               goto fail;
+       if (priv->hdmi) {
+               /* Construct bridge/connector for HDMI: */
+               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+               if (ret) {
+                       dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+                       goto fail;
+               }
        }
 
        return 0;
index f2b985bc2adf41f8330dd4bfb8dcafdb30b43c53..812c59bbaf7f80fd98c3fec975013ec5a9cd0206 100644 (file)
@@ -82,6 +82,7 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
 {
        struct mdp_kms *mdp_kms = to_mdp_kms(kms);
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
+       struct msm_drm_private *priv = mdp5_kms->dev->dev_private;
        uint32_t intr;
 
        intr = mdp5_read(mdp5_kms, REG_MDP5_HW_INTR_STATUS);
@@ -92,7 +93,7 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
                mdp5_irq_mdp(mdp_kms);
 
        if (intr & MDP5_HW_INTR_STATUS_INTR_HDMI)
-               hdmi_irq(0, mdp5_kms->hdmi);
+               hdmi_irq(0, priv->hdmi);
 
        return IRQ_HANDLED;
 }
index 31a2c6331a1d5a47c57bb36e1a30482b67615e50..ce0308124a722222709a09ec363b97ef620cc6bb 100644 (file)
@@ -324,11 +324,12 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        priv->encoders[priv->num_encoders++] = encoder;
 
        /* Construct bridge/connector for HDMI: */
-       mdp5_kms->hdmi = hdmi_init(dev, encoder);
-       if (IS_ERR(mdp5_kms->hdmi)) {
-               ret = PTR_ERR(mdp5_kms->hdmi);
-               dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
-               goto fail;
+       if (priv->hdmi) {
+               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+               if (ret) {
+                       dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+                       goto fail;
+               }
        }
 
        return 0;
index 5bf340dd0f00afc05300fa0e68346acb005e59c4..c91101d5ac0f3a4776ba6fa720ff840aa3bd7a34 100644 (file)
@@ -71,8 +71,6 @@ struct mdp5_kms {
        struct clk *lut_clk;
        struct clk *vsync_clk;
 
-       struct hdmi *hdmi;
-
        struct mdp_irq error_handler;
 };
 #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base)
index 67f9d0a2332c28b9983d7fe29000f907ffcd87f5..a0398b72ea21628a01c25bbc3647119696212072 100644 (file)
@@ -75,7 +75,12 @@ struct msm_drm_private {
        struct msm_kms *kms;
 
        /* subordinate devices, if present: */
-       struct platform_device *hdmi_pdev, *gpu_pdev;
+       struct platform_device *gpu_pdev;
+
+       /* possibly this should be in the kms component, but it is
+        * shared by both mdp4 and mdp5..
+        */
+       struct hdmi *hdmi;
 
        /* when we have more than one 'msm_gpu' these need to be an array: */
        struct msm_gpu *gpu;
@@ -202,7 +207,8 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
 struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
 
 struct hdmi;
-struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
+int hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,
+               struct drm_encoder *encoder);
 irqreturn_t hdmi_irq(int irq, void *dev_id);
 void __init hdmi_register(void);
 void __exit hdmi_unregister(void);