Skip to content

Commit 1464e48

Browse files
nfrapradorobertfoss
authored andcommitted
drm/bridge: anx7625: Prevent endless probe loop
During probe, the driver registers i2c dummy devices and populates the aux bus, which registers a device for the panel. After doing that, the driver can still defer probe if needed. This ordering of operations is troublesome however, because the deferred probe work will retry probing all pending devices every time a new device is registered. Therefore, if modules need to be loaded in order to satisfy the dependencies for this driver to complete probe, the kernel will stall, since it'll keep trying to probe the anx7625 driver, but never succeed, given that modules would only be loaded after the deferred probe work completes. Two changes are required to avoid this issue: * Move of_find_mipi_dsi_host_by_node(), which can defer probe, to before anx7625_register_i2c_dummy_clients() and devm_of_dp_aux_populate_ep_devices(), which register devices. * Make use of the done_probing callback when populating the aux bus, so that the bridge registration is only done after the panel is probed. This is required because the panel might need to defer probe, but the aux bus population needs the i2c dummy devices working, so this call couldn't just be moved to an earlier point in probe. One caveat is that if the panel is described outside the aux bus, the probe loop issue can still happen, but we don't have a way to avoid it in that case since there's no callback available. With this patch applied, it's possible to boot on mt8192-asurada-spherion with CONFIG_DRM_ANALOGIX_ANX7625=y CONFIG_MTK_MMSYS=m CONFIG_BACKLIGHT_PWM=y and also with CONFIG_DRM_ANALOGIX_ANX7625=y CONFIG_MTK_MMSYS=y CONFIG_BACKLIGHT_PWM=m Fixes: adca62e ("drm/bridge: anx7625: Support reading edid through aux channel") Fixes: 2693329 ("drm/bridge: anx7625: Return -EPROBE_DEFER if the dsi host was not found") Reported-by: "kernelci.org bot" <bot@kernelci.org> Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com> Reviewed-by: Robert Foss <rfoss@kernel.org> Signed-off-by: Robert Foss <rfoss@kernel.org> Link: https://patchwork.freedesktop.org/patch/msgid/20230518193902.891121-1-nfraprado@collabora.com
1 parent b0c536d commit 1464e48

1 file changed

Lines changed: 88 additions & 40 deletions

File tree

drivers/gpu/drm/bridge/analogix/anx7625.c

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,14 @@ static int anx7625_parse_dt(struct device *dev,
16861686
if (of_property_read_bool(np, "analogix,audio-enable"))
16871687
pdata->audio_en = 1;
16881688

1689+
return 0;
1690+
}
1691+
1692+
static int anx7625_parse_dt_panel(struct device *dev,
1693+
struct anx7625_platform_data *pdata)
1694+
{
1695+
struct device_node *np = dev->of_node;
1696+
16891697
pdata->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0);
16901698
if (IS_ERR(pdata->panel_bridge)) {
16911699
if (PTR_ERR(pdata->panel_bridge) == -ENODEV) {
@@ -2031,7 +2039,7 @@ static int anx7625_register_audio(struct device *dev, struct anx7625_data *ctx)
20312039
return 0;
20322040
}
20332041

2034-
static int anx7625_attach_dsi(struct anx7625_data *ctx)
2042+
static int anx7625_setup_dsi_device(struct anx7625_data *ctx)
20352043
{
20362044
struct mipi_dsi_device *dsi;
20372045
struct device *dev = &ctx->client->dev;
@@ -2041,9 +2049,6 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx)
20412049
.channel = 0,
20422050
.node = NULL,
20432051
};
2044-
int ret;
2045-
2046-
DRM_DEV_DEBUG_DRIVER(dev, "attach dsi\n");
20472052

20482053
host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node);
20492054
if (!host) {
@@ -2064,14 +2069,24 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx)
20642069
MIPI_DSI_MODE_VIDEO_HSE |
20652070
MIPI_DSI_HS_PKT_END_ALIGNED;
20662071

2067-
ret = devm_mipi_dsi_attach(dev, dsi);
2072+
ctx->dsi = dsi;
2073+
2074+
return 0;
2075+
}
2076+
2077+
static int anx7625_attach_dsi(struct anx7625_data *ctx)
2078+
{
2079+
struct device *dev = &ctx->client->dev;
2080+
int ret;
2081+
2082+
DRM_DEV_DEBUG_DRIVER(dev, "attach dsi\n");
2083+
2084+
ret = devm_mipi_dsi_attach(dev, ctx->dsi);
20682085
if (ret) {
20692086
DRM_DEV_ERROR(dev, "fail to attach dsi to host.\n");
20702087
return ret;
20712088
}
20722089

2073-
ctx->dsi = dsi;
2074-
20752090
DRM_DEV_DEBUG_DRIVER(dev, "attach dsi succeeded.\n");
20762091

20772092
return 0;
@@ -2559,6 +2574,40 @@ static void anx7625_runtime_disable(void *data)
25592574
pm_runtime_disable(data);
25602575
}
25612576

2577+
static int anx7625_link_bridge(struct drm_dp_aux *aux)
2578+
{
2579+
struct anx7625_data *platform = container_of(aux, struct anx7625_data, aux);
2580+
struct device *dev = aux->dev;
2581+
int ret;
2582+
2583+
ret = anx7625_parse_dt_panel(dev, &platform->pdata);
2584+
if (ret) {
2585+
DRM_DEV_ERROR(dev, "fail to parse DT for panel : %d\n", ret);
2586+
return ret;
2587+
}
2588+
2589+
platform->bridge.funcs = &anx7625_bridge_funcs;
2590+
platform->bridge.of_node = dev->of_node;
2591+
if (!anx7625_of_panel_on_aux_bus(dev))
2592+
platform->bridge.ops |= DRM_BRIDGE_OP_EDID;
2593+
if (!platform->pdata.panel_bridge)
2594+
platform->bridge.ops |= DRM_BRIDGE_OP_HPD |
2595+
DRM_BRIDGE_OP_DETECT;
2596+
platform->bridge.type = platform->pdata.panel_bridge ?
2597+
DRM_MODE_CONNECTOR_eDP :
2598+
DRM_MODE_CONNECTOR_DisplayPort;
2599+
2600+
drm_bridge_add(&platform->bridge);
2601+
2602+
if (!platform->pdata.is_dpi) {
2603+
ret = anx7625_attach_dsi(platform);
2604+
if (ret)
2605+
drm_bridge_remove(&platform->bridge);
2606+
}
2607+
2608+
return ret;
2609+
}
2610+
25622611
static int anx7625_i2c_probe(struct i2c_client *client)
25632612
{
25642613
struct anx7625_data *platform;
@@ -2633,6 +2682,24 @@ static int anx7625_i2c_probe(struct i2c_client *client)
26332682
platform->aux.wait_hpd_asserted = anx7625_wait_hpd_asserted;
26342683
drm_dp_aux_init(&platform->aux);
26352684

2685+
ret = anx7625_parse_dt(dev, pdata);
2686+
if (ret) {
2687+
if (ret != -EPROBE_DEFER)
2688+
DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret);
2689+
goto free_wq;
2690+
}
2691+
2692+
if (!platform->pdata.is_dpi) {
2693+
ret = anx7625_setup_dsi_device(platform);
2694+
if (ret < 0)
2695+
goto free_wq;
2696+
}
2697+
2698+
/*
2699+
* Registering the i2c devices will retrigger deferred probe, so it
2700+
* needs to be done after calls that might return EPROBE_DEFER,
2701+
* otherwise we can get an infinite loop.
2702+
*/
26362703
if (anx7625_register_i2c_dummy_clients(platform, client) != 0) {
26372704
ret = -ENOMEM;
26382705
DRM_DEV_ERROR(dev, "fail to reserve I2C bus.\n");
@@ -2647,13 +2714,21 @@ static int anx7625_i2c_probe(struct i2c_client *client)
26472714
if (ret)
26482715
goto free_wq;
26492716

2650-
devm_of_dp_aux_populate_ep_devices(&platform->aux);
2651-
2652-
ret = anx7625_parse_dt(dev, pdata);
2717+
/*
2718+
* Populating the aux bus will retrigger deferred probe, so it needs to
2719+
* be done after calls that might return EPROBE_DEFER, otherwise we can
2720+
* get an infinite loop.
2721+
*/
2722+
ret = devm_of_dp_aux_populate_bus(&platform->aux, anx7625_link_bridge);
26532723
if (ret) {
2654-
if (ret != -EPROBE_DEFER)
2655-
DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret);
2656-
goto free_wq;
2724+
if (ret != -ENODEV) {
2725+
DRM_DEV_ERROR(dev, "failed to populate aux bus : %d\n", ret);
2726+
goto free_wq;
2727+
}
2728+
2729+
ret = anx7625_link_bridge(&platform->aux);
2730+
if (ret)
2731+
goto free_wq;
26572732
}
26582733

26592734
if (!platform->pdata.low_power_mode) {
@@ -2666,40 +2741,13 @@ static int anx7625_i2c_probe(struct i2c_client *client)
26662741
if (platform->pdata.intp_irq)
26672742
queue_work(platform->workqueue, &platform->work);
26682743

2669-
platform->bridge.funcs = &anx7625_bridge_funcs;
2670-
platform->bridge.of_node = client->dev.of_node;
2671-
if (!anx7625_of_panel_on_aux_bus(&client->dev))
2672-
platform->bridge.ops |= DRM_BRIDGE_OP_EDID;
2673-
if (!platform->pdata.panel_bridge)
2674-
platform->bridge.ops |= DRM_BRIDGE_OP_HPD |
2675-
DRM_BRIDGE_OP_DETECT;
2676-
platform->bridge.type = platform->pdata.panel_bridge ?
2677-
DRM_MODE_CONNECTOR_eDP :
2678-
DRM_MODE_CONNECTOR_DisplayPort;
2679-
2680-
drm_bridge_add(&platform->bridge);
2681-
2682-
if (!platform->pdata.is_dpi) {
2683-
ret = anx7625_attach_dsi(platform);
2684-
if (ret) {
2685-
DRM_DEV_ERROR(dev, "Fail to attach to dsi : %d\n", ret);
2686-
goto unregister_bridge;
2687-
}
2688-
}
2689-
26902744
if (platform->pdata.audio_en)
26912745
anx7625_register_audio(dev, platform);
26922746

26932747
DRM_DEV_DEBUG_DRIVER(dev, "probe done\n");
26942748

26952749
return 0;
26962750

2697-
unregister_bridge:
2698-
drm_bridge_remove(&platform->bridge);
2699-
2700-
if (!platform->pdata.low_power_mode)
2701-
pm_runtime_put_sync_suspend(&client->dev);
2702-
27032751
free_wq:
27042752
if (platform->workqueue)
27052753
destroy_workqueue(platform->workqueue);

0 commit comments

Comments
 (0)