From: Rob Clark Date: Tue, 4 Nov 2014 18:33:14 +0000 (-0500) Subject: drm/msm/hdmi: refactor bind/init X-Git-Tag: v3.19-rc1~73^2~55^2~17 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=067fef372c7356f64e4d307218df0fae49f9c88e;p=karo-tx-linux.git drm/msm/hdmi: refactor bind/init 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 --- diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 9d00dcba6959..90077619029d 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -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 -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 = { diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c index f408b69486a8..eeed006eed13 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c @@ -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; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index ac204720429e..a62109e4ae0d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -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; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index f2b985bc2adf..812c59bbaf7f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -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; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 31a2c6331a1d..ce0308124a72 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -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; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 5bf340dd0f00..c91101d5ac0f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -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) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 67f9d0a2332c..a0398b72ea21 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -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);