Hi, On Sun, Feb 11, 2018 at 03:07:44PM +0200, Laurent Pinchart wrote: > There's no reason to delay initialization of most of the driver (such as > mapping memory I/O, getting clocks or enabling runtime PM) to the > component master bind handler. > > This additionally fixes a real PM issue caused enabling runtime PM in > the bind handler. > > The bind handler performs the following sequence of PM operations: > > pm_runtime_enable(dev); > pm_runtime_get_sync(dev); > > ... (access the hardware to read the device revision) ... > > pm_runtime_put_sync(dev); > > If a failure occurs at this point, the error path calls > pm_runtime_disable() to balance the pm_runtime_enable() call. > > To understand the problem, it should be noted that the bind handler is > called when one of the component registers itself, which happens in the > component's probe handler. Furthermore, as the components are children > of the DSS, the device core calls pm_runtime_get_sync() on the DSS > platform device before calling the component's probe handler. This > increases the DSS power usage count but doesn't runtime resume the > device, as runtime PM is disabled at that point. > > The bind handler is thus called with runtime PM disabled, with the > device runtime suspended, but with the power usage count larger than 0. > The pm_runtime_get_sync() call will thus further increase the power > usage count and runtime resume the device. The pm_runtime_put_sync() > handler will decrease the power usage count to a non-zero value and will > thus not suspend the device. Finally, the pm_runtime_disable() call will > disable runtime PM, preventing the pm_runtime_put() call in the device > core from runtime suspending the device. The DSS device is thus left > powered on. > > To fix this, move the initialization code from the bind handler to the > probe handler. > > Signed-off-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> > --- Reviewed-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxxxx> -- Sebastian > drivers/gpu/drm/omapdrm/dss/dss.c | 193 ++++++++++++++++++++------------------ > 1 file changed, 104 insertions(+), 89 deletions(-) > > diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c > index f1c7ef3a2ec3..d086189263ef 100644 > --- a/drivers/gpu/drm/omapdrm/dss/dss.c > +++ b/drivers/gpu/drm/omapdrm/dss/dss.c > @@ -1300,88 +1300,18 @@ static const struct soc_device_attribute dss_soc_devices[] = { > > static int dss_bind(struct device *dev) > { > - struct platform_device *pdev = to_platform_device(dev); > - struct resource *dss_mem; > - u32 rev; > int r; > > - dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); > - dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); > - if (IS_ERR(dss.base)) > - return PTR_ERR(dss.base); > - > - r = dss_get_clocks(); > + r = component_bind_all(dev, NULL); > if (r) > return r; > > - r = dss_setup_default_clock(); > - if (r) > - goto err_setup_clocks; > - > - r = dss_video_pll_probe(pdev); > - if (r) > - goto err_pll_init; > - > - r = dss_init_ports(pdev); > - if (r) > - goto err_init_ports; > - > - pm_runtime_enable(&pdev->dev); > - > - r = dss_runtime_get(); > - if (r) > - goto err_runtime_get; > - > - dss.dss_clk_rate = clk_get_rate(dss.dss_clk); > - > - /* Select DPLL */ > - REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); > - > - dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); > - > -#ifdef CONFIG_OMAP2_DSS_VENC > - REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ > - REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ > - REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ > -#endif > - dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; > - dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; > - dss.dispc_clk_source = DSS_CLK_SRC_FCK; > - dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; > - dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; > - > - rev = dss_read_reg(DSS_REVISION); > - pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); > - > - dss_runtime_put(); > - > - r = component_bind_all(&pdev->dev, NULL); > - if (r) > - goto err_component; > - > - dss_debugfs_create_file("dss", dss_dump_regs); > - > pm_set_vt_switch(0); > > omapdss_gather_components(dev); > omapdss_set_is_initialized(true); > > return 0; > - > -err_component: > -err_runtime_get: > - pm_runtime_disable(&pdev->dev); > - dss_uninit_ports(pdev); > -err_init_ports: > - if (dss.video1_pll) > - dss_video_pll_uninit(dss.video1_pll); > - > - if (dss.video2_pll) > - dss_video_pll_uninit(dss.video2_pll); > -err_pll_init: > -err_setup_clocks: > - dss_put_clocks(); > - return r; > } > > static void dss_unbind(struct device *dev) > @@ -1391,18 +1321,6 @@ static void dss_unbind(struct device *dev) > omapdss_set_is_initialized(false); > > component_unbind_all(&pdev->dev, NULL); > - > - if (dss.video1_pll) > - dss_video_pll_uninit(dss.video1_pll); > - > - if (dss.video2_pll) > - dss_video_pll_uninit(dss.video2_pll); > - > - dss_uninit_ports(pdev); > - > - pm_runtime_disable(&pdev->dev); > - > - dss_put_clocks(); > } > > static const struct component_master_ops dss_component_ops = { > @@ -1434,10 +1352,46 @@ static int dss_add_child_component(struct device *dev, void *data) > return 0; > } > > +static int dss_probe_hardware(void) > +{ > + u32 rev; > + int r; > + > + r = dss_runtime_get(); > + if (r) > + return r; > + > + dss.dss_clk_rate = clk_get_rate(dss.dss_clk); > + > + /* Select DPLL */ > + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); > + > + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); > + > +#ifdef CONFIG_OMAP2_DSS_VENC > + REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ > + REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ > + REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ > +#endif > + dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; > + dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; > + dss.dispc_clk_source = DSS_CLK_SRC_FCK; > + dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; > + dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; > + > + rev = dss_read_reg(DSS_REVISION); > + pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); > + > + dss_runtime_put(); > + > + return 0; > +} > + > static int dss_probe(struct platform_device *pdev) > { > const struct soc_device_attribute *soc; > struct component_match *match = NULL; > + struct resource *dss_mem; > int r; > > dss.pdev = pdev; > @@ -1458,20 +1412,69 @@ static int dss_probe(struct platform_device *pdev) > else > dss.feat = of_match_device(dss_of_match, &pdev->dev)->data; > > - r = dss_initialize_debugfs(); > + /* Map I/O registers, get and setup clocks. */ > + dss_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); > + if (IS_ERR(dss.base)) > + return PTR_ERR(dss.base); > + > + r = dss_get_clocks(); > if (r) > return r; > > - /* add all the child devices as components */ > + r = dss_setup_default_clock(); > + if (r) > + goto err_put_clocks; > + > + /* Setup the video PLLs and the DPI and SDI ports. */ > + r = dss_video_pll_probe(pdev); > + if (r) > + goto err_put_clocks; > + > + r = dss_init_ports(pdev); > + if (r) > + goto err_uninit_plls; > + > + /* Enable runtime PM and probe the hardware. */ > + pm_runtime_enable(&pdev->dev); > + > + r = dss_probe_hardware(); > + if (r) > + goto err_pm_runtime_disable; > + > + /* Initialize debugfs. */ > + r = dss_initialize_debugfs(); > + if (r) > + goto err_pm_runtime_disable; > + > + dss_debugfs_create_file("dss", dss_dump_regs); > + > + /* Add all the child devices as components. */ > device_for_each_child(&pdev->dev, &match, dss_add_child_component); > > r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); > - if (r) { > - dss_uninitialize_debugfs(); > - return r; > - } > + if (r) > + goto err_uninit_debugfs; > > return 0; > + > +err_uninit_debugfs: > + dss_uninitialize_debugfs(); > + > +err_pm_runtime_disable: > + pm_runtime_disable(&pdev->dev); > + dss_uninit_ports(pdev); > + > +err_uninit_plls: > + if (dss.video1_pll) > + dss_video_pll_uninit(dss.video1_pll); > + if (dss.video2_pll) > + dss_video_pll_uninit(dss.video2_pll); > + > +err_put_clocks: > + dss_put_clocks(); > + > + return r; > } > > static int dss_remove(struct platform_device *pdev) > @@ -1480,6 +1483,18 @@ static int dss_remove(struct platform_device *pdev) > > dss_uninitialize_debugfs(); > > + pm_runtime_disable(&pdev->dev); > + > + dss_uninit_ports(pdev); > + > + if (dss.video1_pll) > + dss_video_pll_uninit(dss.video1_pll); > + > + if (dss.video2_pll) > + dss_video_pll_uninit(dss.video2_pll); > + > + dss_put_clocks(); > + > return 0; > } > > -- > Regards, > > Laurent Pinchart > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/dri-devel
Attachment:
signature.asc
Description: PGP signature
_______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel