Commit 0281c414 authored by Thierry Reding's avatar Thierry Reding

drm/tegra: hub: Use private object for global state

Rather than subclass the global atomic state to store the hub display
clock and rate, create a private object and store this data in its
state.
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 4ae4b5c0
...@@ -1736,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, ...@@ -1736,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
drm_crtc_vblank_on(crtc); drm_crtc_vblank_on(crtc);
} }
static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
struct tegra_atomic_state *s = to_tegra_atomic_state(state->state);
struct tegra_dc_state *tegra = to_dc_state(state);
/*
* The display hub display clock needs to be fed by the display clock
* with the highest frequency to ensure proper functioning of all the
* displays.
*
* Note that this isn't used before Tegra186, but it doesn't hurt and
* conditionalizing it would make the code less clean.
*/
if (state->active) {
if (!s->clk_disp || tegra->pclk > s->rate) {
s->dc = to_tegra_dc(crtc);
s->clk_disp = s->dc->clk;
s->rate = tegra->pclk;
}
}
return 0;
}
static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state) struct drm_crtc_state *old_crtc_state)
{ {
...@@ -1797,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -1797,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
} }
static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
.atomic_check = tegra_crtc_atomic_check,
.atomic_begin = tegra_crtc_atomic_begin, .atomic_begin = tegra_crtc_atomic_begin,
.atomic_flush = tegra_crtc_atomic_flush, .atomic_flush = tegra_crtc_atomic_flush,
.atomic_enable = tegra_crtc_atomic_enable, .atomic_enable = tegra_crtc_atomic_enable,
......
...@@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm, ...@@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm,
if (err < 0) if (err < 0)
return err; return err;
err = tegra_display_hub_atomic_check(drm, state);
if (err < 0)
return err;
err = drm_atomic_normalize_zpos(drm, state); err = drm_atomic_normalize_zpos(drm, state);
if (err < 0) if (err < 0)
return err; return err;
...@@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm, ...@@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm,
return 0; return 0;
} }
static struct drm_atomic_state *
tegra_atomic_state_alloc(struct drm_device *drm)
{
struct tegra_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state || drm_atomic_state_init(drm, &state->base) < 0) {
kfree(state);
return NULL;
}
return &state->base;
}
static void tegra_atomic_state_clear(struct drm_atomic_state *state)
{
struct tegra_atomic_state *tegra = to_tegra_atomic_state(state);
drm_atomic_state_default_clear(state);
tegra->clk_disp = NULL;
tegra->dc = NULL;
tegra->rate = 0;
}
static void tegra_atomic_state_free(struct drm_atomic_state *state)
{
drm_atomic_state_default_release(state);
kfree(state);
}
static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
.fb_create = tegra_fb_create, .fb_create = tegra_fb_create,
#ifdef CONFIG_DRM_FBDEV_EMULATION #ifdef CONFIG_DRM_FBDEV_EMULATION
...@@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { ...@@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
#endif #endif
.atomic_check = tegra_atomic_check, .atomic_check = tegra_atomic_check,
.atomic_commit = drm_atomic_helper_commit, .atomic_commit = drm_atomic_helper_commit,
.atomic_state_alloc = tegra_atomic_state_alloc,
.atomic_state_clear = tegra_atomic_state_clear,
.atomic_state_free = tegra_atomic_state_free,
}; };
static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state) static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state)
......
...@@ -42,20 +42,6 @@ struct tegra_fbdev { ...@@ -42,20 +42,6 @@ struct tegra_fbdev {
}; };
#endif #endif
struct tegra_atomic_state {
struct drm_atomic_state base;
struct clk *clk_disp;
struct tegra_dc *dc;
unsigned long rate;
};
static inline struct tegra_atomic_state *
to_tegra_atomic_state(struct drm_atomic_state *state)
{
return container_of(state, struct tegra_atomic_state, base);
}
struct tegra_drm { struct tegra_drm {
struct drm_device *drm; struct drm_device *drm;
......
...@@ -573,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, ...@@ -573,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
return p; return p;
} }
static struct drm_private_state *
tegra_display_hub_duplicate_state(struct drm_private_obj *obj)
{
struct tegra_display_hub_state *state;
state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
return &state->base;
}
static void tegra_display_hub_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct tegra_display_hub_state *hub_state =
to_tegra_display_hub_state(state);
kfree(hub_state);
}
static const struct drm_private_state_funcs tegra_display_hub_state_funcs = {
.atomic_duplicate_state = tegra_display_hub_duplicate_state,
.atomic_destroy_state = tegra_display_hub_destroy_state,
};
static struct tegra_display_hub_state *
tegra_display_hub_get_state(struct tegra_display_hub *hub,
struct drm_atomic_state *state)
{
struct drm_device *drm = dev_get_drvdata(hub->client.parent);
struct drm_private_state *priv;
WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex));
priv = drm_atomic_get_private_obj_state(state, &hub->base);
if (IS_ERR(priv))
return ERR_CAST(priv);
return to_tegra_display_hub_state(priv);
}
int tegra_display_hub_atomic_check(struct drm_device *drm,
struct drm_atomic_state *state)
{
struct tegra_drm *tegra = drm->dev_private;
struct tegra_display_hub_state *hub_state;
struct drm_crtc_state *old, *new;
struct drm_crtc *crtc;
unsigned int i;
if (!tegra->hub)
return 0;
hub_state = tegra_display_hub_get_state(tegra->hub, state);
if (IS_ERR(hub_state))
return PTR_ERR(hub_state);
/*
* The display hub display clock needs to be fed by the display clock
* with the highest frequency to ensure proper functioning of all the
* displays.
*
* Note that this isn't used before Tegra186, but it doesn't hurt and
* conditionalizing it would make the code less clean.
*/
for_each_oldnew_crtc_in_state(state, crtc, old, new, i) {
struct tegra_dc_state *dc = to_dc_state(new);
if (new->active) {
if (!hub_state->clk || dc->pclk > hub_state->rate) {
hub_state->dc = to_tegra_dc(dc->base.crtc);
hub_state->clk = hub_state->dc->clk;
hub_state->rate = dc->pclk;
}
}
}
return 0;
}
static void tegra_display_hub_update(struct tegra_dc *dc) static void tegra_display_hub_update(struct tegra_dc *dc)
{ {
u32 value; u32 value;
...@@ -598,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc) ...@@ -598,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc)
void tegra_display_hub_atomic_commit(struct drm_device *drm, void tegra_display_hub_atomic_commit(struct drm_device *drm,
struct drm_atomic_state *state) struct drm_atomic_state *state)
{ {
struct tegra_atomic_state *s = to_tegra_atomic_state(state);
struct tegra_drm *tegra = drm->dev_private; struct tegra_drm *tegra = drm->dev_private;
struct tegra_display_hub *hub = tegra->hub; struct tegra_display_hub *hub = tegra->hub;
struct tegra_display_hub_state *hub_state;
struct device *dev = hub->client.dev; struct device *dev = hub->client.dev;
int err; int err;
if (s->clk_disp) { hub_state = tegra_display_hub_get_state(hub, state);
err = clk_set_rate(s->clk_disp, s->rate);
if (hub_state->clk) {
err = clk_set_rate(hub_state->clk, hub_state->rate);
if (err < 0) if (err < 0)
dev_err(dev, "failed to set rate of %pC to %lu Hz\n", dev_err(dev, "failed to set rate of %pC to %lu Hz\n",
s->clk_disp, s->rate); hub_state->clk, hub_state->rate);
err = clk_set_parent(hub->clk_disp, s->clk_disp); err = clk_set_parent(hub->clk_disp, hub_state->clk);
if (err < 0) if (err < 0)
dev_err(dev, "failed to set parent of %pC to %pC: %d\n", dev_err(dev, "failed to set parent of %pC to %pC: %d\n",
hub->clk_disp, s->clk_disp, err); hub->clk_disp, hub_state->clk, err);
} }
if (s->dc) if (hub_state->dc)
tegra_display_hub_update(s->dc); tegra_display_hub_update(hub_state->dc);
} }
static int tegra_display_hub_init(struct host1x_client *client) static int tegra_display_hub_init(struct host1x_client *client)
...@@ -625,6 +710,14 @@ static int tegra_display_hub_init(struct host1x_client *client) ...@@ -625,6 +710,14 @@ static int tegra_display_hub_init(struct host1x_client *client)
struct tegra_display_hub *hub = to_tegra_display_hub(client); struct tegra_display_hub *hub = to_tegra_display_hub(client);
struct drm_device *drm = dev_get_drvdata(client->parent); struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private; struct tegra_drm *tegra = drm->dev_private;
struct tegra_display_hub_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
drm_atomic_private_obj_init(&hub->base, &state->base,
&tegra_display_hub_state_funcs);
tegra->hub = hub; tegra->hub = hub;
...@@ -636,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client) ...@@ -636,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client)
struct drm_device *drm = dev_get_drvdata(client->parent); struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private; struct tegra_drm *tegra = drm->dev_private;
drm_atomic_private_obj_fini(&tegra->hub->base);
tegra->hub = NULL; tegra->hub = NULL;
return 0; return 0;
......
...@@ -41,6 +41,7 @@ struct tegra_display_hub_soc { ...@@ -41,6 +41,7 @@ struct tegra_display_hub_soc {
}; };
struct tegra_display_hub { struct tegra_display_hub {
struct drm_private_obj base;
struct host1x_client client; struct host1x_client client;
struct clk *clk_disp; struct clk *clk_disp;
struct clk *clk_dsc; struct clk *clk_dsc;
...@@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client) ...@@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client)
return container_of(client, struct tegra_display_hub, client); return container_of(client, struct tegra_display_hub, client);
} }
struct tegra_display_hub_state {
struct drm_private_state base;
struct tegra_dc *dc;
unsigned long rate;
struct clk *clk;
};
static inline struct tegra_display_hub_state *
to_tegra_display_hub_state(struct drm_private_state *priv)
{
return container_of(priv, struct tegra_display_hub_state, base);
}
struct tegra_dc; struct tegra_dc;
struct tegra_plane; struct tegra_plane;
...@@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, ...@@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
unsigned int wgrp, unsigned int wgrp,
unsigned int index); unsigned int index);
int tegra_display_hub_atomic_check(struct drm_device *drm,
struct drm_atomic_state *state);
void tegra_display_hub_atomic_commit(struct drm_device *drm, void tegra_display_hub_atomic_commit(struct drm_device *drm,
struct drm_atomic_state *state); struct drm_atomic_state *state);
......
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