aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/drm.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2017-11-13 11:08:13 +0100
committerThierry Reding <treding@nvidia.com>2017-12-13 14:16:37 +0100
commitc4755fb9064f64083fe559e92a46df817fc5e07b (patch)
tree4e5f79fbdeb8fa7bf9a886a30f5168a25186db14 /drivers/gpu/drm/tegra/drm.c
parentdrm/tegra: Move common plane code to separate file (diff)
downloadlinux-dev-c4755fb9064f64083fe559e92a46df817fc5e07b.tar.xz
linux-dev-c4755fb9064f64083fe559e92a46df817fc5e07b.zip
drm/tegra: Add Tegra186 display hub support
The display architecture has changed in several significant ways with the new Tegra186 SoC. Shared between all display controllers is a set of common resources referred to as the display hub. The hub generates accesses to memory and feeds them into various composition pipelines, each of which being a window that can be assigned to arbitrary heads. Atomic state is subclassed in order to track the global bandwidth requirements and select and adjust the hub clocks appropriately. The plane code is shared to a large degree with earlier SoC generations, except where the programming differs. Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/drm.c')
-rw-r--r--drivers/gpu/drm/tegra/drm.c67
1 files changed, 64 insertions, 3 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 90d876fc6ea7..98a2494b4ed0 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -33,6 +33,35 @@ struct tegra_drm_file {
struct mutex lock;
};
+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 = {
.fb_create = tegra_fb_create,
#ifdef CONFIG_DRM_FBDEV_EMULATION
@@ -40,11 +69,32 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
#endif
.atomic_check = drm_atomic_helper_check,
.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)
+{
+ struct drm_device *drm = old_state->dev;
+ struct tegra_drm *tegra = drm->dev_private;
+
+ if (tegra->hub) {
+ drm_atomic_helper_commit_modeset_disables(drm, old_state);
+ tegra_display_hub_atomic_commit(drm, old_state);
+ drm_atomic_helper_commit_planes(drm, old_state, 0);
+ drm_atomic_helper_commit_modeset_enables(drm, old_state);
+ drm_atomic_helper_commit_hw_done(old_state);
+ drm_atomic_helper_wait_for_vblanks(drm, old_state);
+ drm_atomic_helper_cleanup_planes(drm, old_state);
+ } else {
+ drm_atomic_helper_commit_tail_rpm(old_state);
+ }
+}
+
static const struct drm_mode_config_helper_funcs
tegra_drm_mode_config_helpers = {
- .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+ .atomic_commit_tail = tegra_atomic_commit_tail,
};
static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
@@ -119,6 +169,12 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
if (err < 0)
goto fbdev;
+ if (tegra->hub) {
+ err = tegra_display_hub_prepare(tegra->hub);
+ if (err < 0)
+ goto device;
+ }
+
/*
* We don't use the drm_irq_install() helpers provided by the DRM
* core, so we need to set this manually in order to allow the
@@ -131,16 +187,19 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
err = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (err < 0)
- goto device;
+ goto hub;
drm_mode_config_reset(drm);
err = tegra_drm_fb_init(drm);
if (err < 0)
- goto device;
+ goto hub;
return 0;
+hub:
+ if (tegra->hub)
+ tegra_display_hub_cleanup(tegra->hub);
device:
host1x_device_exit(device);
fbdev:
@@ -1235,6 +1294,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
{ .compatible = "nvidia,tegra210-sor", },
{ .compatible = "nvidia,tegra210-sor1", },
{ .compatible = "nvidia,tegra210-vic", },
+ { .compatible = "nvidia,tegra186-display", },
{ .compatible = "nvidia,tegra186-vic", },
{ /* sentinel */ }
};
@@ -1250,6 +1310,7 @@ static struct host1x_driver host1x_drm_driver = {
};
static struct platform_driver * const drivers[] = {
+ &tegra_display_hub_driver,
&tegra_dc_driver,
&tegra_hdmi_driver,
&tegra_dsi_driver,