diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 50689a190c2c..55c465053f0a 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -3775,9 +3775,10 @@ static void dw_hdmi_qp_unregister_platform_device(void *pdev) platform_device_unregister(pdev); } -static int dw_hdmi_qp_register_hdcp(struct device *dev, - struct dw_hdmi_qp *hdmi) +int dw_hdmi_qp_register_hdcp(struct dw_hdmi_qp *hdmi) { + int ret = 0; + struct dw_qp_hdcp hdmi_hdcp = { .hdmi = hdmi, .write = hdmi_writel, @@ -3785,8 +3786,9 @@ static int dw_hdmi_qp_register_hdcp(struct device *dev, .regs = hdmi->regs, .get_mem = dw_hdmi_qp_hdcp14_get_mem, }; + struct platform_device_info hdcp_device_info = { - .parent = dev, + .parent = hdmi->dev, .id = PLATFORM_DEVID_AUTO, .res = NULL, .num_res = 0, @@ -3795,16 +3797,23 @@ static int dw_hdmi_qp_register_hdcp(struct device *dev, .size_data = sizeof(hdmi_hdcp), .dma_mask = DMA_BIT_MASK(32), }; - hdmi->hdcp_dev = platform_device_register_full(&hdcp_device_info); - if (IS_ERR(hdmi->hdcp_dev)) { - dev_err(dev, "failed to register hdcp!\n"); - return -ENOMEM; + + if (hdmi->hdcp14_mem) { + hdmi->hdcp_dev = platform_device_register_full(&hdcp_device_info); + if (IS_ERR(hdmi->hdcp_dev)) { + dev_err(hdmi->dev, "Failed to register hdcp device!\n"); + ret = PTR_ERR(hdmi->hdcp_dev); + } else { + hdmi->hdcp = hdmi->hdcp_dev->dev.platform_data; + ret = devm_add_action_or_reset(hdmi->dev, + dw_hdmi_qp_unregister_platform_device, + hdmi->hdcp_dev); + } } - hdmi->hdcp = hdmi->hdcp_dev->dev.platform_data; - - return 0; + return ret; } +EXPORT_SYMBOL_GPL(dw_hdmi_qp_register_hdcp); int dw_hdmi_qp_register_audio(struct dw_hdmi_qp *hdmi) { @@ -4097,12 +4106,9 @@ static struct dw_hdmi_qp *dw_hdmi_qp_probe(struct platform_device *pdev, if (IS_ERR(hdmi->hdcp14_mem)) { ret = PTR_ERR(hdmi->hdcp14_mem); + hdmi->hdcp14_mem = NULL; goto err_ddc; } - - ret = dw_hdmi_qp_register_hdcp(dev, hdmi); - if (ret) - goto err_ddc; } return hdmi; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index d3cc51f316e8..0100065d0362 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -3454,6 +3454,15 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun .mode_set = dw_hdmi_rockchip_encoder_mode_set, }; +/* + * Register child devices like audio/cec/hdcp at late_register stage + * to avoid register these devie at probe/bind(which may cause + * infinite loop of .probe() if a component is always defer) + * + * As these devices are not that critical, so we don't check + * the register results here, just give warning in it's register + * function if it failed, let the drm bringup. + */ static int dw_hdmi_encoder_late_register(struct drm_encoder *encoder) { struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); @@ -3461,6 +3470,7 @@ static int dw_hdmi_encoder_late_register(struct drm_encoder *encoder) if (hdmi->is_hdmi_qp) { dw_hdmi_qp_register_audio(hdmi->hdmi_qp); dw_hdmi_qp_register_cec(hdmi->hdmi_qp); + dw_hdmi_qp_register_hdcp(hdmi->hdmi_qp); } return 0; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 0bd76c26c4f6..64ccc38300a9 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -362,5 +362,6 @@ void dw_hdmi_cec_wake_ops_register(struct dw_hdmi *hdmi, const struct dw_hdmi_cec_wake_ops *cec_ops); int dw_hdmi_qp_register_audio(struct dw_hdmi_qp *hdmi); int dw_hdmi_qp_register_cec(struct dw_hdmi_qp *hdmi); +int dw_hdmi_qp_register_hdcp(struct dw_hdmi_qp *hdmi); #endif /* __IMX_HDMI_H__ */