diff options
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
| -rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 147 | 
1 files changed, 87 insertions, 60 deletions
| diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 714af052fbef..7c70fd31a4c2 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1727,6 +1727,7 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc,  {  	struct tegra_dc *dc = to_tegra_dc(crtc);  	u32 value; +	int err;  	if (!tegra_dc_idle(dc)) {  		tegra_dc_stop(dc); @@ -1773,7 +1774,9 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc,  	spin_unlock_irq(&crtc->dev->event_lock); -	pm_runtime_put_sync(dc->dev); +	err = host1x_client_suspend(&dc->client); +	if (err < 0) +		dev_err(dc->dev, "failed to suspend: %d\n", err);  }  static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, @@ -1783,8 +1786,13 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,  	struct tegra_dc_state *state = to_dc_state(crtc->state);  	struct tegra_dc *dc = to_tegra_dc(crtc);  	u32 value; +	int err; -	pm_runtime_get_sync(dc->dev); +	err = host1x_client_resume(&dc->client); +	if (err < 0) { +		dev_err(dc->dev, "failed to resume: %d\n", err); +		return; +	}  	/* initialize display controller */  	if (dc->syncpt) { @@ -1996,7 +2004,7 @@ static bool tegra_dc_has_window_groups(struct tegra_dc *dc)  static int tegra_dc_init(struct host1x_client *client)  { -	struct drm_device *drm = dev_get_drvdata(client->parent); +	struct drm_device *drm = dev_get_drvdata(client->host);  	unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;  	struct tegra_dc *dc = host1x_client_to_dc(client);  	struct tegra_drm *tegra = drm->dev_private; @@ -2012,6 +2020,15 @@ static int tegra_dc_init(struct host1x_client *client)  	if (!tegra_dc_has_window_groups(dc))  		return 0; +	/* +	 * Set the display hub as the host1x client parent for the display +	 * controller. This is needed for the runtime reference counting that +	 * ensures the display hub is always powered when any of the display +	 * controllers are. +	 */ +	if (dc->soc->has_nvdisplay) +		client->parent = &tegra->hub->client; +  	dc->syncpt = host1x_syncpt_request(client, flags);  	if (!dc->syncpt)  		dev_warn(dc->dev, "failed to allocate syncpoint\n"); @@ -2077,9 +2094,9 @@ static int tegra_dc_init(struct host1x_client *client)  	/*  	 * Inherit the DMA parameters (such as maximum segment size) from the -	 * parent device. +	 * parent host1x device.  	 */ -	client->dev->dma_parms = client->parent->dma_parms; +	client->dev->dma_parms = client->host->dma_parms;  	return 0; @@ -2121,9 +2138,74 @@ static int tegra_dc_exit(struct host1x_client *client)  	return 0;  } +static int tegra_dc_runtime_suspend(struct host1x_client *client) +{ +	struct tegra_dc *dc = host1x_client_to_dc(client); +	struct device *dev = client->dev; +	int err; + +	err = reset_control_assert(dc->rst); +	if (err < 0) { +		dev_err(dev, "failed to assert reset: %d\n", err); +		return err; +	} + +	if (dc->soc->has_powergate) +		tegra_powergate_power_off(dc->powergate); + +	clk_disable_unprepare(dc->clk); +	pm_runtime_put_sync(dev); + +	return 0; +} + +static int tegra_dc_runtime_resume(struct host1x_client *client) +{ +	struct tegra_dc *dc = host1x_client_to_dc(client); +	struct device *dev = client->dev; +	int err; + +	err = pm_runtime_get_sync(dev); +	if (err < 0) { +		dev_err(dev, "failed to get runtime PM: %d\n", err); +		return err; +	} + +	if (dc->soc->has_powergate) { +		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, +							dc->rst); +		if (err < 0) { +			dev_err(dev, "failed to power partition: %d\n", err); +			goto put_rpm; +		} +	} else { +		err = clk_prepare_enable(dc->clk); +		if (err < 0) { +			dev_err(dev, "failed to enable clock: %d\n", err); +			goto put_rpm; +		} + +		err = reset_control_deassert(dc->rst); +		if (err < 0) { +			dev_err(dev, "failed to deassert reset: %d\n", err); +			goto disable_clk; +		} +	} + +	return 0; + +disable_clk: +	clk_disable_unprepare(dc->clk); +put_rpm: +	pm_runtime_put_sync(dev); +	return err; +} +  static const struct host1x_client_ops dc_client_ops = {  	.init = tegra_dc_init,  	.exit = tegra_dc_exit, +	.suspend = tegra_dc_runtime_suspend, +	.resume = tegra_dc_runtime_resume,  };  static const struct tegra_dc_soc_info tegra20_dc_soc_info = { @@ -2535,65 +2617,10 @@ static int tegra_dc_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM -static int tegra_dc_suspend(struct device *dev) -{ -	struct tegra_dc *dc = dev_get_drvdata(dev); -	int err; - -	err = reset_control_assert(dc->rst); -	if (err < 0) { -		dev_err(dev, "failed to assert reset: %d\n", err); -		return err; -	} - -	if (dc->soc->has_powergate) -		tegra_powergate_power_off(dc->powergate); - -	clk_disable_unprepare(dc->clk); - -	return 0; -} - -static int tegra_dc_resume(struct device *dev) -{ -	struct tegra_dc *dc = dev_get_drvdata(dev); -	int err; - -	if (dc->soc->has_powergate) { -		err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, -							dc->rst); -		if (err < 0) { -			dev_err(dev, "failed to power partition: %d\n", err); -			return err; -		} -	} else { -		err = clk_prepare_enable(dc->clk); -		if (err < 0) { -			dev_err(dev, "failed to enable clock: %d\n", err); -			return err; -		} - -		err = reset_control_deassert(dc->rst); -		if (err < 0) { -			dev_err(dev, "failed to deassert reset: %d\n", err); -			return err; -		} -	} - -	return 0; -} -#endif - -static const struct dev_pm_ops tegra_dc_pm_ops = { -	SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL) -}; -  struct platform_driver tegra_dc_driver = {  	.driver = {  		.name = "tegra-dc",  		.of_match_table = tegra_dc_of_match, -		.pm = &tegra_dc_pm_ops,  	},  	.probe = tegra_dc_probe,  	.remove = tegra_dc_remove, | 
