Commit 9c012700 authored by Thierry Reding's avatar Thierry Reding

drm/tegra: dc: Add powergate support

Both display controllers are in their own power partition. Currently the
driver relies on the assumption that these partitions are on (which is
the hardware default). However some bootloaders may disable them, so the
driver must make sure to turn them back on to avoid hangs.
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent b298e98e
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <soc/tegra/pmc.h>
#include "dc.h" #include "dc.h"
#include "drm.h" #include "drm.h"
#include "gem.h" #include "gem.h"
...@@ -20,6 +22,7 @@ struct tegra_dc_soc_info { ...@@ -20,6 +22,7 @@ struct tegra_dc_soc_info {
bool supports_cursor; bool supports_cursor;
bool supports_block_linear; bool supports_block_linear;
unsigned int pitch_align; unsigned int pitch_align;
bool has_powergate;
}; };
struct tegra_plane { struct tegra_plane {
...@@ -1357,6 +1360,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { ...@@ -1357,6 +1360,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
.supports_cursor = false, .supports_cursor = false,
.supports_block_linear = false, .supports_block_linear = false,
.pitch_align = 8, .pitch_align = 8,
.has_powergate = false,
}; };
static const struct tegra_dc_soc_info tegra30_dc_soc_info = { static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
...@@ -1364,6 +1368,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = { ...@@ -1364,6 +1368,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
.supports_cursor = false, .supports_cursor = false,
.supports_block_linear = false, .supports_block_linear = false,
.pitch_align = 8, .pitch_align = 8,
.has_powergate = false,
}; };
static const struct tegra_dc_soc_info tegra114_dc_soc_info = { static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
...@@ -1371,6 +1376,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = { ...@@ -1371,6 +1376,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
.supports_cursor = false, .supports_cursor = false,
.supports_block_linear = false, .supports_block_linear = false,
.pitch_align = 64, .pitch_align = 64,
.has_powergate = true,
}; };
static const struct tegra_dc_soc_info tegra124_dc_soc_info = { static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
...@@ -1378,12 +1384,16 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = { ...@@ -1378,12 +1384,16 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
.supports_cursor = true, .supports_cursor = true,
.supports_block_linear = true, .supports_block_linear = true,
.pitch_align = 64, .pitch_align = 64,
.has_powergate = true,
}; };
static const struct of_device_id tegra_dc_of_match[] = { static const struct of_device_id tegra_dc_of_match[] = {
{ {
.compatible = "nvidia,tegra124-dc", .compatible = "nvidia,tegra124-dc",
.data = &tegra124_dc_soc_info, .data = &tegra124_dc_soc_info,
}, {
.compatible = "nvidia,tegra114-dc",
.data = &tegra114_dc_soc_info,
}, { }, {
.compatible = "nvidia,tegra30-dc", .compatible = "nvidia,tegra30-dc",
.data = &tegra30_dc_soc_info, .data = &tegra30_dc_soc_info,
...@@ -1467,9 +1477,34 @@ static int tegra_dc_probe(struct platform_device *pdev) ...@@ -1467,9 +1477,34 @@ static int tegra_dc_probe(struct platform_device *pdev)
return PTR_ERR(dc->rst); return PTR_ERR(dc->rst);
} }
if (dc->soc->has_powergate) {
if (dc->pipe == 0)
dc->powergate = TEGRA_POWERGATE_DIS;
else
dc->powergate = TEGRA_POWERGATE_DISB;
err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
dc->rst);
if (err < 0) {
dev_err(&pdev->dev, "failed to power partition: %d\n",
err);
return err;
}
} else {
err = clk_prepare_enable(dc->clk); err = clk_prepare_enable(dc->clk);
if (err < 0) if (err < 0) {
dev_err(&pdev->dev, "failed to enable clock: %d\n",
err);
return err;
}
err = reset_control_deassert(dc->rst);
if (err < 0) {
dev_err(&pdev->dev, "failed to deassert reset: %d\n",
err);
return err; return err;
}
}
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dc->regs = devm_ioremap_resource(&pdev->dev, regs); dc->regs = devm_ioremap_resource(&pdev->dev, regs);
...@@ -1523,6 +1558,10 @@ static int tegra_dc_remove(struct platform_device *pdev) ...@@ -1523,6 +1558,10 @@ static int tegra_dc_remove(struct platform_device *pdev)
} }
reset_control_assert(dc->rst); reset_control_assert(dc->rst);
if (dc->soc->has_powergate)
tegra_powergate_power_off(dc->powergate);
clk_disable_unprepare(dc->clk); clk_disable_unprepare(dc->clk);
return 0; return 0;
......
...@@ -101,6 +101,7 @@ struct tegra_dc { ...@@ -101,6 +101,7 @@ struct tegra_dc {
spinlock_t lock; spinlock_t lock;
struct drm_crtc base; struct drm_crtc base;
int powergate;
int pipe; int pipe;
struct clk *clk; struct clk *clk;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment