Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752635AbdHQDmq (ORCPT ); Wed, 16 Aug 2017 23:42:46 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:45288 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751620AbdHQDmo (ORCPT ); Wed, 16 Aug 2017 23:42:44 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 0CF976072C Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=architt@codeaurora.org Subject: Re: [PATCH v6 3/5] drm/vc4: Set up the DSI host at pdev probe time, not component bind. To: Eric Anholt , dri-devel@lists.freedesktop.org, Andrzej Hajda , Laurent Pinchart , Thierry Reding Cc: linux-kernel@vger.kernel.org References: <20170815234722.20700-1-eric@anholt.net> <20170815234722.20700-3-eric@anholt.net> From: Archit Taneja Message-ID: <7ed4979e-5822-1dda-a93e-dd70f6f08bfc@codeaurora.org> Date: Thu, 17 Aug 2017 09:12:35 +0530 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.1.1 MIME-Version: 1.0 In-Reply-To: <20170815234722.20700-3-eric@anholt.net> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6729 Lines: 217 On 08/16/2017 05:17 AM, Eric Anholt wrote: > 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. Reviewed-by: Archit Taneja > > Signed-off-by: Eric Anholt > --- > drivers/gpu/drm/vc4/vc4_dsi.c | 97 +++++++++++++++++++++++++------------------ > 1 file changed, 57 insertions(+), 40 deletions(-) > > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c > index 2516cd3a1d87..ec1d646b3151 100644 > --- a/drivers/gpu/drm/vc4/vc4_dsi.c > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c > @@ -33,6 +33,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -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; > > @@ -1289,7 +1289,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; > @@ -1324,34 +1323,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; > } > > @@ -1493,16 +1470,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; > @@ -1517,7 +1491,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); > @@ -1598,6 +1571,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) { > @@ -1616,12 +1601,11 @@ 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); > + return ret; > + } > > pm_runtime_enable(dev); > > @@ -1639,8 +1623,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; > } > @@ -1652,12 +1634,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; > } > > -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project