summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tegra/dc.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-12-08 18:14:45 +0300
committerThierry Reding <treding@nvidia.com>2015-01-27 12:14:52 +0300
commitca915b108a39081edff1206ec00ecdb4136408ac (patch)
treebe8c144ee09940e9dd31248e03c3114236e4909e /drivers/gpu/drm/tegra/dc.c
parent07866963b675b358d82baf8df73dba545d967a1d (diff)
downloadlinux-ca915b108a39081edff1206ec00ecdb4136408ac.tar.xz
drm/tegra: dc: Store clock setup in atomic state
This allows the clock setup to be separated from the clock programming and better matches the expectations of the atomic modesetting where no code paths must fail during modeset. Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r--drivers/gpu/drm/tegra/dc.c71
1 files changed, 68 insertions, 3 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 4fb9048b2f65..b905a4e2bdf9 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -41,6 +41,22 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
return container_of(plane, struct tegra_plane, base);
}
+struct tegra_dc_state {
+ struct drm_crtc_state base;
+
+ struct clk *clk;
+ unsigned long pclk;
+ unsigned int div;
+};
+
+static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)
+{
+ if (state)
+ return container_of(state, struct tegra_dc_state, base);
+
+ return NULL;
+}
+
static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index)
{
u32 value = WIN_A_ACT_REQ << index;
@@ -1004,13 +1020,48 @@ static void tegra_dc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
}
+static void tegra_crtc_reset(struct drm_crtc *crtc)
+{
+ struct tegra_dc_state *state;
+
+ kfree(crtc->state);
+ crtc->state = NULL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state)
+ crtc->state = &state->base;
+}
+
+static struct drm_crtc_state *
+tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+ struct tegra_dc_state *state = to_dc_state(crtc->state);
+ struct tegra_dc_state *copy;
+
+ copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+ if (!copy)
+ return NULL;
+
+ copy->base.mode_changed = false;
+ copy->base.planes_changed = false;
+ copy->base.event = NULL;
+
+ return &copy->base;
+}
+
+static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ kfree(state);
+}
+
static const struct drm_crtc_funcs tegra_crtc_funcs = {
.page_flip = tegra_dc_page_flip,
.set_config = drm_crtc_helper_set_config,
.destroy = tegra_dc_destroy,
- .reset = drm_atomic_helper_crtc_reset,
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .reset = tegra_crtc_reset,
+ .atomic_duplicate_state = tegra_crtc_atomic_duplicate_state,
+ .atomic_destroy_state = tegra_crtc_atomic_destroy_state,
};
static void tegra_dc_stop(struct tegra_dc *dc)
@@ -1148,6 +1199,20 @@ int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
return 0;
}
+int tegra_dc_state_setup_clock(struct tegra_dc *dc,
+ struct drm_crtc_state *crtc_state,
+ struct clk *clk, unsigned long pclk,
+ unsigned int div)
+{
+ struct tegra_dc_state *state = to_dc_state(crtc_state);
+
+ state->clk = clk;
+ state->pclk = pclk;
+ state->div = div;
+
+ return 0;
+}
+
static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct drm_display_mode *mode = &crtc->state->adjusted_mode;