summaryrefslogtreecommitdiffstats
path: root/meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0003-drm-vc4-Set-up-the-DSI-host-at-pdev-probe-time-not-c.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0003-drm-vc4-Set-up-the-DSI-host-at-pdev-probe-time-not-c.patch')
-rw-r--r--meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0003-drm-vc4-Set-up-the-DSI-host-at-pdev-probe-time-not-c.patch217
1 files changed, 217 insertions, 0 deletions
diff --git a/meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0003-drm-vc4-Set-up-the-DSI-host-at-pdev-probe-time-not-c.patch b/meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0003-drm-vc4-Set-up-the-DSI-host-at-pdev-probe-time-not-c.patch
new file mode 100644
index 000000000..0e6e068fe
--- /dev/null
+++ b/meta-agl-bsp/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi/dsi/0003-drm-vc4-Set-up-the-DSI-host-at-pdev-probe-time-not-c.patch
@@ -0,0 +1,217 @@
+From 2ccd080392adfb1f077f2f4d289651b6b15e0951 Mon Sep 17 00:00:00 2001
+From: Kevin Quigley <kevin@kquigley.co.uk>
+Date: Mon, 24 Sep 2018 18:09:52 +0000
+Subject: [PATCH 3/4] drm/vc4: Set up the DSI host at pdev probe time, not
+ component bind. bring https://patchwork.kernel.org/patch/9902623/ to Linux
+ 4.14.y
+
+We need the following things to happen in sequence:
+
+DSI host creation
+DSI device creation in the panel driver (needs DSI host)
+DSI device attach from panel to host.
+DSI drm_panel_add()
+DSI encoder creation
+DSI encoder's DRM panel/bridge attach
+
+Unless we allow device creation while the host isn't up yet, we need
+to break the -EPROBE_DEFER deadlock between the panel driver looking
+up the host and the host driver looking up the panel. We can do so by
+moving the DSI host creation outside of the component bind loop, and
+the panel/bridge lookup/attach into the component bind process.
+---
+ drivers/gpu/drm/vc4/vc4_dsi.c | 93 ++++++++++++++++++++---------------
+ 1 file changed, 53 insertions(+), 40 deletions(-)
+
+diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
+index 3fa2db18d70f..faf38f17ec26 100644
+--- a/drivers/gpu/drm/vc4/vc4_dsi.c
++++ b/drivers/gpu/drm/vc4/vc4_dsi.c
+@@ -33,6 +33,7 @@
+ #include <drm/drm_crtc_helper.h>
+ #include <drm/drm_edid.h>
+ #include <drm/drm_mipi_dsi.h>
++#include <drm/drm_of.h>
+ #include <drm/drm_panel.h>
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
+@@ -504,7 +505,6 @@ struct vc4_dsi {
+ struct mipi_dsi_host dsi_host;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+- bool is_panel_bridge;
+
+ void __iomem *regs;
+
+@@ -1300,7 +1300,6 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+ {
+ struct vc4_dsi *dsi = host_to_dsi(host);
+- int ret = 0;
+
+ dsi->lanes = device->lanes;
+ dsi->channel = device->channel;
+@@ -1335,33 +1334,12 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
+ return 0;
+ }
+
+- dsi->bridge = of_drm_find_bridge(device->dev.of_node);
+- if (!dsi->bridge) {
+- struct drm_panel *panel =
+- of_drm_find_panel(device->dev.of_node);
+-
+- dsi->bridge = drm_panel_bridge_add(panel,
+- DRM_MODE_CONNECTOR_DSI);
+- if (IS_ERR(dsi->bridge)) {
+- ret = PTR_ERR(dsi->bridge);
+- dsi->bridge = NULL;
+- return ret;
+- }
+- dsi->is_panel_bridge = true;
+- }
+-
+- return drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
++ return 0;
+ }
+
+ static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+ {
+- struct vc4_dsi *dsi = host_to_dsi(host);
+-
+- if (dsi->is_panel_bridge) {
+- drm_panel_bridge_remove(dsi->bridge);
+- dsi->bridge = NULL;
+- }
+
+ return 0;
+ }
+@@ -1525,16 +1503,13 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+- struct vc4_dsi *dsi;
++ struct vc4_dsi *dsi = dev_get_drvdata(dev);
+ struct vc4_dsi_encoder *vc4_dsi_encoder;
++ struct drm_panel *panel;
+ const struct of_device_id *match;
+ dma_cap_mask_t dma_mask;
+ int ret;
+
+- dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+- if (!dsi)
+- return -ENOMEM;
+-
+ match = of_match_device(vc4_dsi_dt_match, dev);
+ if (!match)
+ return -ENODEV;
+@@ -1549,7 +1524,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
+ vc4_dsi_encoder->dsi = dsi;
+ dsi->encoder = &vc4_dsi_encoder->base.base;
+
+- dsi->pdev = pdev;
+ dsi->regs = vc4_ioremap_regs(pdev, 0);
+ if (IS_ERR(dsi->regs))
+ return PTR_ERR(dsi->regs);
+@@ -1637,6 +1611,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
+ return ret;
+ }
+
++ ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
++ &panel, &dsi->bridge);
++ if (ret)
++ return ret;
++
++ if (panel) {
++ dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
++ DRM_MODE_CONNECTOR_DSI);
++ if (IS_ERR(dsi->bridge))
++ return PTR_ERR(dsi->bridge);
++ }
++
+ /* The esc clock rate is supposed to always be 100Mhz. */
+ ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
+ if (ret) {
+@@ -1655,13 +1641,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
+ DRM_MODE_ENCODER_DSI, NULL);
+ drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
+
+- dsi->dsi_host.ops = &vc4_dsi_host_ops;
+- dsi->dsi_host.dev = dev;
+-
+- mipi_dsi_host_register(&dsi->dsi_host);
+-
+- dev_set_drvdata(dev, dsi);
+-
+ ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
+ if (ret) {
+ dev_err(dev, "bridge attach failed: %d\n", ret);
+@@ -1672,6 +1651,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
+ * from our driver, since we need to sequence them within the
+ * encoder's enable/disable paths.
+ */
++
+ dsi->encoder->bridge = NULL;
+
+ pm_runtime_enable(dev);
+@@ -1690,8 +1670,6 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
+
+ vc4_dsi_encoder_destroy(dsi->encoder);
+
+- mipi_dsi_host_unregister(&dsi->dsi_host);
+-
+ if (dsi->port == 1)
+ vc4->dsi1 = NULL;
+ }
+@@ -1703,12 +1681,47 @@ static const struct component_ops vc4_dsi_ops = {
+
+ static int vc4_dsi_dev_probe(struct platform_device *pdev)
+ {
+- return component_add(&pdev->dev, &vc4_dsi_ops);
++ struct device *dev = &pdev->dev;
++ struct vc4_dsi *dsi;
++ int ret;
++
++ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
++ if (!dsi)
++ return -ENOMEM;
++ dev_set_drvdata(dev, dsi);
++
++ dsi->pdev = pdev;
++
++ /* Note, the initialization sequence for DSI and panels is
++ * tricky. The component bind above won't get past its
++ * -EPROBE_DEFER until the panel/bridge probes. The
++ * panel/bridge will return -EPROBE_DEFER until it has a
++ * mipi_dsi_host to register its device to. So, we register
++ * the host during pdev probe time, so vc4 as a whole can then
++ * -EPROBE_DEFER its component bind process until the panel
++ * successfully attaches.
++ */
++ dsi->dsi_host.ops = &vc4_dsi_host_ops;
++ dsi->dsi_host.dev = dev;
++ mipi_dsi_host_register(&dsi->dsi_host);
++
++ ret = component_add(&pdev->dev, &vc4_dsi_ops);
++ if (ret) {
++ mipi_dsi_host_unregister(&dsi->dsi_host);
++ return ret;
++ }
++
++ return 0;
+ }
+
+ static int vc4_dsi_dev_remove(struct platform_device *pdev)
+ {
++ struct device *dev = &pdev->dev;
++ struct vc4_dsi *dsi = dev_get_drvdata(dev);
++
+ component_del(&pdev->dev, &vc4_dsi_ops);
++ mipi_dsi_host_unregister(&dsi->dsi_host);
++
+ return 0;
+ }
+
+--
+2.21.0
+