From 1eab7dd4f8bbae5c6c875c44a7b0c8ce483c4198 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Wed, 8 May 2024 17:08:28 +0800 Subject: [PATCH] drm/rockchip: dw-dp: init audio when register encoder According to Documentation/driver-api/driver-model/driver.rst, a warning as follow: -EPROBE_DEFER must not be returned if probe() has already created child devices, even if those child devices are removed again in a cleanup path. If -EPROBE_DEFER is returned after a child device has been registered, it may result in an infinite loop of .probe() calls to the same driver. To avoid this issue, we do the audio init work when register encoder. Change-Id: I2f527f29a32ca8cb28a0044b3689933845b7108a Signed-off-by: Zhang Yubing --- drivers/gpu/drm/rockchip/dw-dp.c | 218 ++++++++++++++++++------------- 1 file changed, 128 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index c18d54ad04d7..ba1c710efdcb 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -5128,6 +5128,128 @@ static void dw_dp_unregister_audio_driver(void *data) } } +static int dw_dp_single_audio_init(struct dw_dp *dp, struct dw_dp_audio *audio) +{ + int ret; + + audio->extcon = devm_extcon_dev_allocate(dp->dev, dw_dp_cable); + if (IS_ERR(audio->extcon)) + return dev_err_probe(dp->dev, PTR_ERR(audio->extcon), + "failed to allocate extcon device\n"); + + ret = devm_extcon_dev_register(dp->dev, audio->extcon); + if (ret) + return dev_err_probe(dp->dev, ret, "failed to register extcon device\n"); + + ret = dw_dp_register_audio_driver(dp, audio); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dp->dev, dw_dp_unregister_audio_driver, audio); + if (ret) + return ret; + + return 0; +} + +static int dw_dp_audio_init(struct dw_dp *dp) +{ + struct dw_dp_audio *audio; + int i, ret; + + audio = dp->audio; + ret = dw_dp_single_audio_init(dp, audio); + if (ret) + return ret; + + if (!dp->support_mst) + return 0; + + for (i = 1; i < dp->mst_port_num; i++) { + if (!of_device_is_available(dp->mst_enc[i].port_node)) + continue; + + audio = dp->mst_enc[i].audio; + ret = dw_dp_single_audio_init(dp, audio); + if (ret) + return ret; + } + + return 0; +} + +static int dw_dp_get_audio_clk(struct dw_dp *dp) +{ + struct dw_dp_audio *audio; + char clk_name[10]; + int i; + + audio = devm_kzalloc(dp->dev, sizeof(*audio), GFP_KERNEL); + if (!audio) + return -ENOMEM; + + audio->id = 0; + dp->audio = audio; + + audio->i2s_clk = devm_clk_get_optional(dp->dev, "i2s"); + if (IS_ERR(audio->i2s_clk)) + return dev_err_probe(dp->dev, PTR_ERR(audio->i2s_clk), + "failed to get i2s clock\n"); + + audio->spdif_clk = devm_clk_get_optional(dp->dev, "spdif"); + if (IS_ERR(audio->spdif_clk)) + return dev_err_probe(dp->dev, PTR_ERR(audio->spdif_clk), + "failed to get spdif clock\n"); + + if (!dp->support_mst) + return 0; + + dp->mst_enc[0].audio = audio; + + for (i = 1; i < dp->mst_port_num; i++) { + if (!of_device_is_available(dp->mst_enc[i].port_node)) + continue; + + audio = devm_kzalloc(dp->dev, sizeof(*audio), GFP_KERNEL); + if (!audio) + return -ENOMEM; + + audio->id = i; + + snprintf(clk_name, sizeof(clk_name), "i2s%d", i); + audio->i2s_clk = devm_clk_get_optional(dp->dev, clk_name); + if (IS_ERR(audio->i2s_clk)) + return dev_err_probe(dp->dev, PTR_ERR(audio->i2s_clk), + "failed to get i2s clock\n"); + + snprintf(clk_name, sizeof(clk_name), "spdif%d", i); + audio->spdif_clk = devm_clk_get_optional(dp->dev, clk_name); + if (IS_ERR(audio->spdif_clk)) + return dev_err_probe(dp->dev, PTR_ERR(audio->spdif_clk), + "failed to get spdif clock\n"); + dp->mst_enc[i].audio = audio; + } + + return 0; +} + +static int dw_dp_encoder_late_register(struct drm_encoder *encoder) +{ + struct dw_dp *dp = encoder_to_dp(encoder); + int ret; + + ret = dw_dp_audio_init(dp); + if (ret) + dev_warn(dp->dev, "audio init failed\n"); + + return 0; +} + +static const struct drm_encoder_funcs dw_dp_encoder_funcs = { + .destroy = drm_encoder_cleanup, + .late_register = dw_dp_encoder_late_register, +}; + static int dw_dp_bind(struct device *dev, struct device *master, void *data) { struct dw_dp *dp = dev_get_drvdata(dev); @@ -5151,7 +5273,8 @@ static int dw_dp_bind(struct device *dev, struct device *master, void *data) port_node = dp->mst_enc[0].port_node; else port_node = dev->of_node; - drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS); + drm_encoder_init(drm_dev, encoder, &dw_dp_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); drm_encoder_helper_add(encoder, &dw_dp_encoder_helper_funcs); encoder->possible_crtcs = @@ -5325,91 +5448,6 @@ static int dw_dp_get_port_node(struct dw_dp *dp) return 0; } -static int dw_dp_single_audio_init(struct dw_dp *dp, struct dw_dp_audio *audio) -{ - int ret; - - audio->extcon = devm_extcon_dev_allocate(dp->dev, dw_dp_cable); - if (IS_ERR(audio->extcon)) - return dev_err_probe(dp->dev, PTR_ERR(audio->extcon), - "failed to allocate extcon device\n"); - - ret = devm_extcon_dev_register(dp->dev, audio->extcon); - if (ret) - return dev_err_probe(dp->dev, ret, "failed to register extcon device\n"); - - ret = dw_dp_register_audio_driver(dp, audio); - if (ret) - return ret; - - ret = devm_add_action_or_reset(dp->dev, dw_dp_unregister_audio_driver, audio); - if (ret) - return ret; - - return 0; -} - -static int dw_dp_audio_init(struct dw_dp *dp) -{ - struct dw_dp_audio *audio; - char clk_name[10]; - int i, ret; - - audio = devm_kzalloc(dp->dev, sizeof(*audio), GFP_KERNEL); - if (!audio) - return -ENOMEM; - - audio->id = 0; - ret = dw_dp_single_audio_init(dp, audio); - if (ret) - return ret; - dp->audio = audio; - - audio->i2s_clk = devm_clk_get_optional(dp->dev, "i2s"); - if (IS_ERR(audio->i2s_clk)) - return dev_err_probe(dp->dev, PTR_ERR(audio->i2s_clk), - "failed to get i2s clock\n"); - - audio->spdif_clk = devm_clk_get_optional(dp->dev, "spdif"); - if (IS_ERR(audio->spdif_clk)) - return dev_err_probe(dp->dev, PTR_ERR(audio->spdif_clk), - "failed to get spdif clock\n"); - - if (!dp->support_mst) - return 0; - - dp->mst_enc[0].audio = audio; - - for (i = 1; i < dp->mst_port_num; i++) { - if (!of_device_is_available(dp->mst_enc[i].port_node)) - continue; - - audio = devm_kzalloc(dp->dev, sizeof(*audio), GFP_KERNEL); - if (!audio) - return -ENOMEM; - - audio->id = i; - ret = dw_dp_single_audio_init(dp, audio); - if (ret) - return ret; - - snprintf(clk_name, sizeof(clk_name), "i2s%d", i); - audio->i2s_clk = devm_clk_get_optional(dp->dev, clk_name); - if (IS_ERR(audio->i2s_clk)) - return dev_err_probe(dp->dev, PTR_ERR(audio->i2s_clk), - "failed to get i2s clock\n"); - - snprintf(clk_name, sizeof(clk_name), "spdif%d", i); - audio->spdif_clk = devm_clk_get_optional(dp->dev, clk_name); - if (IS_ERR(audio->spdif_clk)) - return dev_err_probe(dp->dev, PTR_ERR(audio->spdif_clk), - "failed to get spdif clock\n"); - dp->mst_enc[i].audio = audio; - } - - return 0; -} - static int dw_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -5527,6 +5565,10 @@ static int dw_dp_probe(struct platform_device *pdev) } } + ret = dw_dp_get_audio_clk(dp); + if (ret) + return ret; + dp->irq = platform_get_irq(pdev, 0); if (dp->irq < 0) return dp->irq; @@ -5539,10 +5581,6 @@ static int dw_dp_probe(struct platform_device *pdev) return ret; } - ret = dw_dp_audio_init(dp); - if (ret) - return ret; - dp->bridge.of_node = dp->support_mst ? dp->mst_enc[0].port_node : dev->of_node; dp->bridge.funcs = &dw_dp_bridge_funcs; dp->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |