From ca915b108a39081edff1206ec00ecdb4136408ac Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 8 Dec 2014 16:14:45 +0100 Subject: [PATCH] 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 --- drivers/gpu/drm/tegra/dc.c | 71 +++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/tegra/drm.h | 4 +++ 2 files changed, 72 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 ©->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; diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index bf1c47ec46b6..3db719de312f 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -180,6 +180,10 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); void tegra_dc_commit(struct tegra_dc *dc); int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent, unsigned long pclk, unsigned int div); +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_output { struct device_node *of_node; -- 2.30.2