Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4755fb9 authored by Thierry Reding's avatar Thierry Reding
Browse files

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: default avatarThierry Reding <treding@nvidia.com>
parent 5acd3514
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -5,6 +5,7 @@ tegra-drm-y := \
	drm.o \
	drm.o \
	gem.o \
	gem.o \
	fb.o \
	fb.o \
	hub.o \
	plane.o \
	plane.o \
	dc.o \
	dc.o \
	output.o \
	output.o \
+31 −0
Original line number Original line Diff line number Diff line
@@ -447,6 +447,15 @@ static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
	num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
	num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
	formats = tegra_primary_plane_formats;
	formats = tegra_primary_plane_formats;


	/*
	 * XXX compute offset so that we can directly access windows.
	 *
	 * Always use window A as primary window.
	 */
	plane->offset = 0;
	plane->index = 0;
	plane->depth = 255;

	err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
	err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
				       &tegra_plane_funcs, formats,
				       &tegra_plane_funcs, formats,
				       num_formats, NULL,
				       num_formats, NULL,
@@ -641,7 +650,10 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
	if (!plane)
	if (!plane)
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);


	/* XXX compute offset so that we can directly access windows */
	plane->offset = 0;
	plane->index = index;
	plane->index = index;
	plane->depth = 0;


	num_formats = ARRAY_SIZE(tegra_overlay_plane_formats);
	num_formats = ARRAY_SIZE(tegra_overlay_plane_formats);
	formats = tegra_overlay_plane_formats;
	formats = tegra_overlay_plane_formats;
@@ -1382,6 +1394,25 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
				   struct drm_crtc_state *state)
				   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;
	return 0;
}
}


+114 −0
Original line number Original line Diff line number Diff line
@@ -209,6 +209,8 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define WIN_B_UPDATE    (1 << 10)
#define WIN_B_UPDATE    (1 << 10)
#define WIN_C_UPDATE    (1 << 11)
#define WIN_C_UPDATE    (1 << 11)
#define CURSOR_UPDATE   (1 << 15)
#define CURSOR_UPDATE   (1 << 15)
#define COMMON_ACTREQ   (1 << 16)
#define COMMON_UPDATE   (1 << 17)
#define NC_HOST_TRIG    (1 << 24)
#define NC_HOST_TRIG    (1 << 24)


#define DC_CMD_DISPLAY_WINDOW_HEADER		0x042
#define DC_CMD_DISPLAY_WINDOW_HEADER		0x042
@@ -486,6 +488,35 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define CURSOR_SRC_BLEND_MASK			(3 << 8)
#define CURSOR_SRC_BLEND_MASK			(3 << 8)
#define CURSOR_ALPHA				0xff
#define CURSOR_ALPHA				0xff


#define DC_WIN_CORE_ACT_CONTROL 0x50e
#define  VCOUNTER (0 << 0)
#define  HCOUNTER (1 << 0)

#define DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA 0x543
#define  LATENCY_CTL_MODE_ENABLE (1 << 2)

#define DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB 0x544
#define  WATERMARK_MASK 0x1fffffff

#define DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER 0x560
#define  PIPE_METER_INT(x)  (((x) & 0xff) << 8)
#define  PIPE_METER_FRAC(x) (((x) & 0xff) << 0)

#define DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG 0x561
#define  MEMPOOL_ENTRIES(x) (((x) & 0xffff) << 0)

#define DC_WIN_CORE_IHUB_WGRP_FETCH_METER 0x562
#define  SLOTS(x) (((x) & 0xff) << 0)

#define DC_WIN_CORE_IHUB_LINEBUF_CONFIG 0x563
#define  MODE_TWO_LINES  (0 << 14)
#define  MODE_FOUR_LINES (1 << 14)

#define DC_WIN_CORE_IHUB_THREAD_GROUP 0x568
#define  THREAD_NUM_MASK (0x1f << 1)
#define  THREAD_NUM(x) (((x) & 0x1f) << 1)
#define  THREAD_GROUP_ENABLE (1 << 0)

#define DC_WIN_CSC_YOF				0x611
#define DC_WIN_CSC_YOF				0x611
#define DC_WIN_CSC_KYRGB			0x612
#define DC_WIN_CSC_KYRGB			0x612
#define DC_WIN_CSC_KUR				0x613
#define DC_WIN_CSC_KUR				0x613
@@ -596,8 +627,91 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);


#define DC_WINBUF_START_ADDR_HI			0x80d
#define DC_WINBUF_START_ADDR_HI			0x80d


#define DC_WINBUF_CDE_CONTROL			0x82f
#define  ENABLE_SURFACE (1 << 0)

#define DC_WINBUF_AD_UFLOW_STATUS		0xbca
#define DC_WINBUF_AD_UFLOW_STATUS		0xbca
#define DC_WINBUF_BD_UFLOW_STATUS		0xdca
#define DC_WINBUF_BD_UFLOW_STATUS		0xdca
#define DC_WINBUF_CD_UFLOW_STATUS		0xfca
#define DC_WINBUF_CD_UFLOW_STATUS		0xfca


/* Tegra186 and later */
#define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL	0x702
#define OWNER_MASK (0xf << 0)
#define OWNER(x) (((x) & 0xf) << 0)

#define DC_WIN_CROPPED_SIZE			0x706

#define DC_WIN_PLANAR_STORAGE			0x709
#define PITCH(x) (((x) >> 6) & 0x1fff)

#define DC_WIN_SET_PARAMS			0x70d
#define  CLAMP_BEFORE_BLEND (1 << 15)
#define  DEGAMMA_NONE (0 << 13)
#define  DEGAMMA_SRGB (1 << 13)
#define  DEGAMMA_YUV8_10 (2 << 13)
#define  DEGAMMA_YUV12 (3 << 13)
#define  INPUT_RANGE_BYPASS (0 << 10)
#define  INPUT_RANGE_LIMITED (1 << 10)
#define  INPUT_RANGE_FULL (2 << 10)
#define  COLOR_SPACE_RGB (0 << 8)
#define  COLOR_SPACE_YUV_601 (1 << 8)
#define  COLOR_SPACE_YUV_709 (2 << 8)
#define  COLOR_SPACE_YUV_2020 (3 << 8)

#define DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER	0x70e
#define  HORIZONTAL_TAPS_2 (1 << 3)
#define  HORIZONTAL_TAPS_5 (4 << 3)
#define  VERTICAL_TAPS_2 (1 << 0)
#define  VERTICAL_TAPS_5 (4 << 0)

#define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE	0x711
#define  INPUT_SCALER_USE422  (1 << 2)
#define  INPUT_SCALER_VBYPASS (1 << 1)
#define  INPUT_SCALER_HBYPASS (1 << 0)

#define DC_WIN_BLEND_LAYER_CONTROL		0x716
#define  COLOR_KEY_NONE (0 << 25)
#define  COLOR_KEY_SRC (1 << 25)
#define  COLOR_KEY_DST (2 << 25)
#define  BLEND_BYPASS (1 << 24)
#define  K2(x) (((x) & 0xff) << 16)
#define  K1(x) (((x) & 0xff) << 8)
#define  WINDOW_LAYER_DEPTH(x) (((x) & 0xff) << 0)

#define DC_WIN_BLEND_MATCH_SELECT		0x717
#define  BLEND_FACTOR_DST_ALPHA_ZERO			(0 << 12)
#define  BLEND_FACTOR_DST_ALPHA_ONE			(1 << 12)
#define  BLEND_FACTOR_DST_ALPHA_NEG_K1_TIMES_SRC	(2 << 12)
#define  BLEND_FACTOR_DST_ALPHA_K2			(3 << 12)
#define  BLEND_FACTOR_SRC_ALPHA_ZERO			(0 << 8)
#define  BLEND_FACTOR_SRC_ALPHA_K1			(1 << 8)
#define  BLEND_FACTOR_SRC_ALPHA_K2			(2 << 8)
#define  BLEND_FACTOR_SRC_ALPHA_NEG_K1_TIMES_DST	(3 << 8)
#define  BLEND_FACTOR_DST_COLOR_ZERO			(0 << 4)
#define  BLEND_FACTOR_DST_COLOR_ONE			(1 << 4)
#define  BLEND_FACTOR_DST_COLOR_K1			(2 << 4)
#define  BLEND_FACTOR_DST_COLOR_K2			(3 << 4)
#define  BLEND_FACTOR_DST_COLOR_K1_TIMES_DST		(4 << 4)
#define  BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_DST	(5 << 4)
#define  BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC	(6 << 4)
#define  BLEND_FACTOR_DST_COLOR_NEG_K1			(7 << 4)
#define  BLEND_FACTOR_SRC_COLOR_ZERO			(0 << 0)
#define  BLEND_FACTOR_SRC_COLOR_ONE			(1 << 0)
#define  BLEND_FACTOR_SRC_COLOR_K1			(2 << 0)
#define  BLEND_FACTOR_SRC_COLOR_K1_TIMES_DST		(3 << 0)
#define  BLEND_FACTOR_SRC_COLOR_NEG_K1_TIMES_DST	(4 << 0)
#define  BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC		(5 << 0)

#define DC_WIN_BLEND_NOMATCH_SELECT		0x718

#define DC_WIN_PRECOMP_WGRP_PARAMS		0x724
#define  SWAP_UV (1 << 0)

#define DC_WIN_WINDOW_SET_CONTROL		0x730
#define  CONTROL_CSC_ENABLE (1 << 5)

#define DC_WINBUF_CROPPED_POINT			0x806
#define OFFSET_Y(x) (((x) & 0xffff) << 16)
#define OFFSET_X(x) (((x) & 0xffff) << 0)

#endif /* TEGRA_DC_H */
#endif /* TEGRA_DC_H */
+64 −3
Original line number Original line Diff line number Diff line
@@ -33,6 +33,35 @@ struct tegra_drm_file {
	struct mutex lock;
	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 = {
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
@@ -40,11 +69,32 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
#endif
#endif
	.atomic_check = drm_atomic_helper_check,
	.atomic_check = drm_atomic_helper_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)
{
	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
static const struct drm_mode_config_helper_funcs
tegra_drm_mode_config_helpers = {
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)
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)
	if (err < 0)
		goto fbdev;
		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
	 * 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
	 * 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);
	err = drm_vblank_init(drm, drm->mode_config.num_crtc);
	if (err < 0)
	if (err < 0)
		goto device;
		goto hub;


	drm_mode_config_reset(drm);
	drm_mode_config_reset(drm);


	err = tegra_drm_fb_init(drm);
	err = tegra_drm_fb_init(drm);
	if (err < 0)
	if (err < 0)
		goto device;
		goto hub;


	return 0;
	return 0;


hub:
	if (tegra->hub)
		tegra_display_hub_cleanup(tegra->hub);
device:
device:
	host1x_device_exit(device);
	host1x_device_exit(device);
fbdev:
fbdev:
@@ -1235,6 +1294,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
	{ .compatible = "nvidia,tegra210-sor", },
	{ .compatible = "nvidia,tegra210-sor", },
	{ .compatible = "nvidia,tegra210-sor1", },
	{ .compatible = "nvidia,tegra210-sor1", },
	{ .compatible = "nvidia,tegra210-vic", },
	{ .compatible = "nvidia,tegra210-vic", },
	{ .compatible = "nvidia,tegra186-display", },
	{ .compatible = "nvidia,tegra186-vic", },
	{ .compatible = "nvidia,tegra186-vic", },
	{ /* sentinel */ }
	{ /* sentinel */ }
};
};
@@ -1250,6 +1310,7 @@ static struct host1x_driver host1x_drm_driver = {
};
};


static struct platform_driver * const drivers[] = {
static struct platform_driver * const drivers[] = {
	&tegra_display_hub_driver,
	&tegra_dc_driver,
	&tegra_dc_driver,
	&tegra_hdmi_driver,
	&tegra_hdmi_driver,
	&tegra_dsi_driver,
	&tegra_dsi_driver,
+19 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/of_gpio.h>
#include <linux/of_gpio.h>


#include <drm/drmP.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_encoder.h>
@@ -23,6 +24,7 @@
#include <drm/drm_fixed.h>
#include <drm/drm_fixed.h>


#include "gem.h"
#include "gem.h"
#include "hub.h"
#include "trace.h"
#include "trace.h"


struct reset_control;
struct reset_control;
@@ -40,6 +42,20 @@ 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;


@@ -62,6 +78,8 @@ struct tegra_drm {


	unsigned int pitch_align;
	unsigned int pitch_align;


	struct tegra_display_hub *hub;

	struct drm_atomic_state *state;
	struct drm_atomic_state *state;
};
};


@@ -187,6 +205,7 @@ void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
void tegra_fb_output_poll_changed(struct drm_device *drm);
void tegra_fb_output_poll_changed(struct drm_device *drm);
#endif
#endif


extern struct platform_driver tegra_display_hub_driver;
extern struct platform_driver tegra_dc_driver;
extern struct platform_driver tegra_dc_driver;
extern struct platform_driver tegra_hdmi_driver;
extern struct platform_driver tegra_hdmi_driver;
extern struct platform_driver tegra_dsi_driver;
extern struct platform_driver tegra_dsi_driver;
Loading