[v3,9/9] drm/mediatek: dp: Add support for embedded DisplayPort aux-bus
Commit Message
For the eDP case we can support using aux-bus on MediaTek DP: this
gives us the possibility to declare our panel as generic "panel-edp"
which will automatically configure the timings and available modes
via the EDID that we read from it.
To do this, move the panel parsing at the end of the probe function
so that the hardware is initialized beforehand and also initialize
the DPTX AUX block and power both on as, when we populate the
aux-bus, the panel driver will trigger an EDID read to perform
panel detection.
Last but not least, since now the AUX transfers can happen in the
separated aux-bus, it was necessary to add an exclusion for the
cable_plugged_in check in `mtk_dp_aux_transfer()` and the easiest
way to do this is to simply ignore checking that when the bridge
type is eDP.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_dp.c | 61 ++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 10 deletions(-)
Comments
On Tue, Apr 04, 2023 at 12:48:00PM +0200, AngeloGioacchino Del Regno wrote:
> For the eDP case we can support using aux-bus on MediaTek DP: this
> gives us the possibility to declare our panel as generic "panel-edp"
> which will automatically configure the timings and available modes
> via the EDID that we read from it.
>
> To do this, move the panel parsing at the end of the probe function
> so that the hardware is initialized beforehand and also initialize
> the DPTX AUX block and power both on as, when we populate the
> aux-bus, the panel driver will trigger an EDID read to perform
> panel detection.
>
> Last but not least, since now the AUX transfers can happen in the
> separated aux-bus, it was necessary to add an exclusion for the
> cable_plugged_in check in `mtk_dp_aux_transfer()` and the easiest
> way to do this is to simply ignore checking that when the bridge
> type is eDP.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> drivers/gpu/drm/mediatek/mtk_dp.c | 61 ++++++++++++++++++++++++++-----
> 1 file changed, 51 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index a67143c22024..8109f5b4392b 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[..]
> @@ -2571,6 +2585,33 @@ static int mtk_dp_probe(struct platform_device *pdev)
> mtk_dp->need_debounce = true;
> timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0);
>
> + if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
> + /* Initialize, reset and poweron the DPTX AUX block */
> + mtk_dp_initialize_aux_settings(mtk_dp);
> + mtk_dp_power_enable(mtk_dp);
> +
> + /* Power on the panel to allow EDID read from aux-bus */
> + mtk_dp_aux_panel_poweron(mtk_dp, true);
> +
> + ret = devm_of_dp_aux_populate_bus(&mtk_dp->aux, NULL);
This patch causes
.../bin/aarch64-none-linux-gnu-ld: Unexpected GOT/PLT entries detected!
.../bin/aarch64-none-linux-gnu-ld: Unexpected run-time procedure linkages detected!
.../bin/aarch64-none-linux-gnu-ld: drivers/gpu/drm/mediatek/mtk_dp.o: in function `mtk_dp_probe':
.../drivers/gpu/drm/mediatek/mtk_dp.c:2595: undefined reference to `devm_of_dp_aux_populate_bus'
You need
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
index b451dee64d34..76cab28e010c 100644
--- a/drivers/gpu/drm/mediatek/Kconfig
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -26,6 +26,7 @@ config DRM_MEDIATEK_DP
select PHY_MTK_DP
select DRM_DISPLAY_HELPER
select DRM_DISPLAY_DP_HELPER
+ select DRM_DP_AUX_BUS
help
DRM/KMS Display Port driver for MediaTek SoCs.
Thanks,
Nícolas
On Tue, Apr 04, 2023 at 12:48:00PM +0200, AngeloGioacchino Del Regno wrote:
> For the eDP case we can support using aux-bus on MediaTek DP: this
> gives us the possibility to declare our panel as generic "panel-edp"
> which will automatically configure the timings and available modes
> via the EDID that we read from it.
>
> To do this, move the panel parsing at the end of the probe function
> so that the hardware is initialized beforehand and also initialize
> the DPTX AUX block and power both on as, when we populate the
> aux-bus, the panel driver will trigger an EDID read to perform
> panel detection.
>
> Last but not least, since now the AUX transfers can happen in the
> separated aux-bus, it was necessary to add an exclusion for the
> cable_plugged_in check in `mtk_dp_aux_transfer()` and the easiest
> way to do this is to simply ignore checking that when the bridge
> type is eDP.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> drivers/gpu/drm/mediatek/mtk_dp.c | 61 ++++++++++++++++++++++++++-----
> 1 file changed, 51 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
> index a67143c22024..8109f5b4392b 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dp.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dp.c
[..]
> @@ -2571,6 +2585,33 @@ static int mtk_dp_probe(struct platform_device *pdev)
> mtk_dp->need_debounce = true;
> timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0);
>
> + if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
> + /* Initialize, reset and poweron the DPTX AUX block */
> + mtk_dp_initialize_aux_settings(mtk_dp);
> + mtk_dp_power_enable(mtk_dp);
> +
> + /* Power on the panel to allow EDID read from aux-bus */
> + mtk_dp_aux_panel_poweron(mtk_dp, true);
> +
> + ret = devm_of_dp_aux_populate_bus(&mtk_dp->aux, NULL);
> +
> + /* If the panel is present, detection is done: power off! */
> + mtk_dp_aux_panel_poweron(mtk_dp, false);
> + mtk_dp_power_disable(mtk_dp);
> +
> + /* We ignore -ENODEV error, as the panel may not be on aux-bus */
> + if (ret && ret != -ENODEV)
> + return ret;
> +
> + /*
> + * Here we don't ignore any error, as if there's no panel to
> + * link, eDP is not configured correctly and will be unusable.
> + */
> + ret = mtk_dp_edp_link_panel(&mtk_dp->aux);
This call might return EDEFER_PROBE if the panel hasn't probed yet. That's a
problem, because during this probe you register a device for the dp-phy, so
you'll be retriggering defer probes every time you probe until the panel probes.
But if this driver was builtin and the panel a module, then this loop will go on
forever.
You should make use of the done_probing callback in
devm_of_dp_aux_populate_bus() and do the panel linking there. This way you can
exit successfully from this probe and avoid the loop. I had to do the same thing
for anx7625.c [1].
Thanks,
Nícolas
[1] https://lore.kernel.org/all/20230518193902.891121-1-nfraprado@collabora.com/
@@ -4,6 +4,7 @@
* Copyright (c) 2022 BayLibre
*/
+#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_dp.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic_helper.h>
@@ -2042,7 +2043,8 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
- if (!mtk_dp->train_info.cable_plugged_in) {
+ if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP &&
+ !mtk_dp->train_info.cable_plugged_in) {
ret = -EAGAIN;
goto err;
}
@@ -2154,6 +2156,11 @@ static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
enable_irq(mtk_dp->irq);
mtk_dp_hwirq_enable(mtk_dp, true);
+ if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
+ mtk_dp->train_info.cable_plugged_in = true;
+ drm_helper_hpd_irq_event(mtk_dp->drm_dev);
+ }
+
return 0;
err_bridge_attach:
@@ -2483,6 +2490,20 @@ static int mtk_dp_register_audio_driver(struct device *dev)
return PTR_ERR_OR_ZERO(mtk_dp->audio_pdev);
}
+static int mtk_dp_edp_link_panel(struct drm_dp_aux *mtk_aux)
+{
+ struct mtk_dp *mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
+ struct device *dev = mtk_aux->dev;
+ struct drm_bridge *panel_aux_bridge;
+
+ panel_aux_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+ if (IS_ERR(panel_aux_bridge))
+ return PTR_ERR(panel_aux_bridge);
+
+ mtk_dp->next_bridge = panel_aux_bridge;
+ return 0;
+}
+
static int mtk_dp_probe(struct platform_device *pdev)
{
struct mtk_dp *mtk_dp;
@@ -2501,21 +2522,14 @@ static int mtk_dp_probe(struct platform_device *pdev)
return dev_err_probe(dev, mtk_dp->irq,
"failed to request dp irq resource\n");
- mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
- if (IS_ERR(mtk_dp->next_bridge) &&
- PTR_ERR(mtk_dp->next_bridge) == -ENODEV)
- mtk_dp->next_bridge = NULL;
- else if (IS_ERR(mtk_dp->next_bridge))
- return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge),
- "Failed to get bridge\n");
-
ret = mtk_dp_dt_parse(mtk_dp, pdev);
if (ret)
return dev_err_probe(dev, ret, "Failed to parse dt\n");
- drm_dp_aux_init(&mtk_dp->aux);
mtk_dp->aux.name = "aux_mtk_dp";
+ mtk_dp->aux.dev = dev;
mtk_dp->aux.transfer = mtk_dp_aux_transfer;
+ drm_dp_aux_init(&mtk_dp->aux);
spin_lock_init(&mtk_dp->irq_thread_lock);
@@ -2571,6 +2585,33 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->need_debounce = true;
timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0);
+ if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
+ /* Initialize, reset and poweron the DPTX AUX block */
+ mtk_dp_initialize_aux_settings(mtk_dp);
+ mtk_dp_power_enable(mtk_dp);
+
+ /* Power on the panel to allow EDID read from aux-bus */
+ mtk_dp_aux_panel_poweron(mtk_dp, true);
+
+ ret = devm_of_dp_aux_populate_bus(&mtk_dp->aux, NULL);
+
+ /* If the panel is present, detection is done: power off! */
+ mtk_dp_aux_panel_poweron(mtk_dp, false);
+ mtk_dp_power_disable(mtk_dp);
+
+ /* We ignore -ENODEV error, as the panel may not be on aux-bus */
+ if (ret && ret != -ENODEV)
+ return ret;
+
+ /*
+ * Here we don't ignore any error, as if there's no panel to
+ * link, eDP is not configured correctly and will be unusable.
+ */
+ ret = mtk_dp_edp_link_panel(&mtk_dp->aux);
+ if (ret)
+ return ret;
+ }
+
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);