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 <yubing.zhang@rock-chips.com>
This commit is contained in:
Zhang Yubing
2024-05-08 17:08:28 +08:00
committed by Tao Huang
parent bf2d6a4286
commit 1eab7dd4f8

View File

@@ -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 |