Re: [PATCH v2 12/15] drm: omapdrm: dss: Move initialization code from component bind to probe

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux