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 <robdclark@gmail.com>
This commit is contained in:
		
							parent
							
								
									bc00ae02e4
								
							
						
					
					
						commit
						067fef372c
					
				| @ -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 = { | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user