aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/dc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r--drivers/gpu/drm/tegra/dc.c92
1 files changed, 63 insertions, 29 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 95b373f739f2..c875f11786b9 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -30,6 +30,7 @@ struct tegra_dc_soc_info {
bool supports_block_linear;
unsigned int pitch_align;
bool has_powergate;
+ bool broken_reset;
};
struct tegra_plane {
@@ -485,12 +486,25 @@ static int tegra_plane_state_add(struct tegra_plane *plane,
{
struct drm_crtc_state *crtc_state;
struct tegra_dc_state *tegra;
+ struct drm_rect clip;
+ int err;
/* Propagate errors from allocation or locking failures. */
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc_state->mode.hdisplay;
+ clip.y2 = crtc_state->mode.vdisplay;
+
+ /* Check plane state for visibility and calculate clipping bounds */
+ err = drm_plane_helper_check_state(state, &clip, 0, INT_MAX,
+ true, true);
+ if (err < 0)
+ return err;
+
tegra = to_dc_state(crtc_state);
tegra->planes |= WIN_A_ACT_REQ << plane->index;
@@ -545,6 +559,23 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
return 0;
}
+static void tegra_dc_disable_window(struct tegra_dc *dc, int index)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&dc->lock, flags);
+
+ value = WINDOW_A_SELECT << index;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
+
+ value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+ value &= ~WIN_ENABLE;
+ tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+
+ spin_unlock_irqrestore(&dc->lock, flags);
+}
+
static void tegra_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@@ -559,15 +590,18 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
if (!plane->state->crtc || !plane->state->fb)
return;
+ if (!plane->state->visible)
+ return tegra_dc_disable_window(dc, p->index);
+
memset(&window, 0, sizeof(window));
- window.src.x = plane->state->src_x >> 16;
- window.src.y = plane->state->src_y >> 16;
- window.src.w = plane->state->src_w >> 16;
- window.src.h = plane->state->src_h >> 16;
- window.dst.x = plane->state->crtc_x;
- window.dst.y = plane->state->crtc_y;
- window.dst.w = plane->state->crtc_w;
- window.dst.h = plane->state->crtc_h;
+ window.src.x = plane->state->src.x1 >> 16;
+ window.src.y = plane->state->src.y1 >> 16;
+ window.src.w = drm_rect_width(&plane->state->src) >> 16;
+ window.src.h = drm_rect_height(&plane->state->src) >> 16;
+ window.dst.x = plane->state->dst.x1;
+ window.dst.y = plane->state->dst.y1;
+ window.dst.w = drm_rect_width(&plane->state->dst);
+ window.dst.h = drm_rect_height(&plane->state->dst);
window.bits_per_pixel = fb->format->cpp[0] * 8;
window.bottom_up = tegra_fb_is_bottom_up(fb);
@@ -598,8 +632,6 @@ static void tegra_plane_atomic_disable(struct drm_plane *plane,
{
struct tegra_plane *p = to_tegra_plane(plane);
struct tegra_dc *dc;
- unsigned long flags;
- u32 value;
/* rien ne va plus */
if (!old_state || !old_state->crtc)
@@ -607,16 +639,7 @@ static void tegra_plane_atomic_disable(struct drm_plane *plane,
dc = to_tegra_dc(old_state->crtc);
- spin_lock_irqsave(&dc->lock, flags);
-
- value = WINDOW_A_SELECT << p->index;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
-
- value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
- value &= ~WIN_ENABLE;
- tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-
- spin_unlock_irqrestore(&dc->lock, flags);
+ tegra_dc_disable_window(dc, p->index);
}
static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
@@ -1856,6 +1879,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
.supports_block_linear = false,
.pitch_align = 8,
.has_powergate = false,
+ .broken_reset = true,
};
static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
@@ -1865,6 +1889,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
.supports_block_linear = false,
.pitch_align = 8,
.has_powergate = false,
+ .broken_reset = false,
};
static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
@@ -1874,6 +1899,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
.supports_block_linear = false,
.pitch_align = 64,
.has_powergate = true,
+ .broken_reset = false,
};
static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
@@ -1883,6 +1909,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
.supports_block_linear = true,
.pitch_align = 64,
.has_powergate = true,
+ .broken_reset = false,
};
static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
@@ -1892,6 +1919,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
.supports_block_linear = true,
.pitch_align = 64,
.has_powergate = true,
+ .broken_reset = false,
};
static const struct of_device_id tegra_dc_of_match[] = {
@@ -1989,7 +2017,8 @@ static int tegra_dc_probe(struct platform_device *pdev)
return PTR_ERR(dc->rst);
}
- reset_control_assert(dc->rst);
+ if (!dc->soc->broken_reset)
+ reset_control_assert(dc->rst);
if (dc->soc->has_powergate) {
if (dc->pipe == 0)
@@ -2063,10 +2092,12 @@ 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->broken_reset) {
+ 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)
@@ -2096,10 +2127,13 @@ static int tegra_dc_resume(struct device *dev)
return err;
}
- err = reset_control_deassert(dc->rst);
- if (err < 0) {
- dev_err(dev, "failed to deassert reset: %d\n", err);
- return err;
+ if (!dc->soc->broken_reset) {
+ err = reset_control_deassert(dc->rst);
+ if (err < 0) {
+ dev_err(dev,
+ "failed to deassert reset: %d\n", err);
+ return err;
+ }
}
}