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

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

drm/tegra: Add hardware cursor support



Enable hardware cursor support on Tegra124. Earlier generations support
the hardware cursor to some degree as well, but not in a way that can be
generically exposed.

Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 9910f5c4
Loading
Loading
Loading
Loading
+111 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

struct tegra_dc_soc_info {
	bool supports_interlacing;
	bool supports_cursor;
};

struct tegra_plane {
@@ -477,6 +478,109 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc)
	spin_unlock_irqrestore(&dc->lock, flags);
}

static int tegra_dc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file,
				uint32_t handle, uint32_t width,
				uint32_t height, int32_t hot_x, int32_t hot_y)
{
	unsigned long value = CURSOR_CLIP_DISPLAY;
	struct tegra_dc *dc = to_tegra_dc(crtc);
	struct drm_gem_object *gem;
	struct tegra_bo *bo = NULL;

	if (!dc->soc->supports_cursor)
		return -ENXIO;

	if (width != height)
		return -EINVAL;

	switch (width) {
	case 32:
		value |= CURSOR_SIZE_32x32;
		break;

	case 64:
		value |= CURSOR_SIZE_64x64;
		break;

	case 128:
		value |= CURSOR_SIZE_128x128;

	case 256:
		value |= CURSOR_SIZE_256x256;
		break;

	default:
		return -EINVAL;
	}

	if (handle) {
		gem = drm_gem_object_lookup(crtc->dev, file, handle);
		if (!gem)
			return -ENOENT;

		bo = to_tegra_bo(gem);
	}

	if (bo) {
		unsigned long addr = (bo->paddr & 0xfffffc00) >> 10;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
		unsigned long high = (bo->paddr & 0xfffffffc) >> 32;
#endif

		tegra_dc_writel(dc, value | addr, DC_DISP_CURSOR_START_ADDR);

#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
		tegra_dc_writel(dc, high, DC_DISP_CURSOR_START_ADDR_HI);
#endif

		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
		value |= CURSOR_ENABLE;
		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);

		value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
		value &= ~CURSOR_DST_BLEND_MASK;
		value &= ~CURSOR_SRC_BLEND_MASK;
		value |= CURSOR_MODE_NORMAL;
		value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
		value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
		value |= CURSOR_ALPHA;
		tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
	} else {
		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
		value &= ~CURSOR_ENABLE;
		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
	}

	tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
	tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);

	tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);

	return 0;
}

static int tegra_dc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
	struct tegra_dc *dc = to_tegra_dc(crtc);
	unsigned long value;

	if (!dc->soc->supports_cursor)
		return -ENXIO;

	value = ((y & 0x3fff) << 16) | (x & 0x3fff);
	tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);

	tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
	tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);

	/* XXX: only required on generations earlier than Tegra124? */
	tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);

	return 0;
}

static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
{
	struct drm_device *drm = dc->base.dev;
@@ -553,6 +657,8 @@ static void tegra_dc_destroy(struct drm_crtc *crtc)
}

static const struct drm_crtc_funcs tegra_crtc_funcs = {
	.cursor_set2 = tegra_dc_cursor_set2,
	.cursor_move = tegra_dc_cursor_move,
	.page_flip = tegra_dc_page_flip,
	.set_config = drm_crtc_helper_set_config,
	.destroy = tegra_dc_destroy,
@@ -999,6 +1105,8 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
	DUMP_REG(DC_DISP_SD_BL_CONTROL);
	DUMP_REG(DC_DISP_SD_HW_K_VALUES);
	DUMP_REG(DC_DISP_SD_MAN_K_VALUES);
	DUMP_REG(DC_DISP_CURSOR_START_ADDR_HI);
	DUMP_REG(DC_DISP_BLEND_CURSOR_CONTROL);
	DUMP_REG(DC_WIN_WIN_OPTIONS);
	DUMP_REG(DC_WIN_BYTE_SWAP);
	DUMP_REG(DC_WIN_BUFFER_CONTROL);
@@ -1168,14 +1276,17 @@ static const struct host1x_client_ops dc_client_ops = {

static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
	.supports_interlacing = false,
	.supports_cursor = false,
};

static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
	.supports_interlacing = false,
	.supports_cursor = false,
};

static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
	.supports_interlacing = true,
	.supports_cursor = true,
};

static const struct of_device_id tegra_dc_of_match[] = {
+27 −3
Original line number Diff line number Diff line
@@ -67,10 +67,12 @@
#define WIN_A_ACT_REQ   (1 <<  1)
#define WIN_B_ACT_REQ   (1 <<  2)
#define WIN_C_ACT_REQ   (1 <<  3)
#define CURSOR_ACT_REQ  (1 <<  7)
#define GENERAL_UPDATE  (1 <<  8)
#define WIN_A_UPDATE    (1 <<  9)
#define WIN_B_UPDATE    (1 << 10)
#define WIN_C_UPDATE    (1 << 11)
#define CURSOR_UPDATE   (1 << 15)
#define NC_HOST_TRIG    (1 << 24)

#define DC_CMD_DISPLAY_WINDOW_HEADER		0x042
@@ -119,6 +121,7 @@
#define HDMI_ENABLE	(1 << 30)
#define DSI_ENABLE	(1 << 29)
#define SOR_ENABLE	(1 << 25)
#define CURSOR_ENABLE	(1 << 16)

#define DC_DISP_DISP_MEM_HIGH_PRIORITY		0x403
#define CURSOR_THRESHOLD(x)   (((x) & 0x03) << 24)
@@ -266,6 +269,14 @@
#define DC_DISP_CURSOR_BACKGROUND		0x43d

#define DC_DISP_CURSOR_START_ADDR		0x43e
#define CURSOR_CLIP_DISPLAY	(0 << 28)
#define CURSOR_CLIP_WIN_A	(1 << 28)
#define CURSOR_CLIP_WIN_B	(2 << 28)
#define CURSOR_CLIP_WIN_C	(3 << 28)
#define CURSOR_SIZE_32x32	(0 << 24)
#define CURSOR_SIZE_64x64	(1 << 24)
#define CURSOR_SIZE_128x128	(2 << 24)
#define CURSOR_SIZE_256x256	(3 << 24)
#define DC_DISP_CURSOR_START_ADDR_NS		0x43f

#define DC_DISP_CURSOR_POSITION			0x440
@@ -302,6 +313,19 @@
#define  INTERLACE_START  (1 << 1)
#define  INTERLACE_ENABLE (1 << 0)

#define DC_DISP_CURSOR_START_ADDR_HI		0x4ec
#define DC_DISP_BLEND_CURSOR_CONTROL		0x4f1
#define CURSOR_MODE_LEGACY			(0 << 24)
#define CURSOR_MODE_NORMAL			(1 << 24)
#define CURSOR_DST_BLEND_ZERO			(0 << 16)
#define CURSOR_DST_BLEND_K1			(1 << 16)
#define CURSOR_DST_BLEND_NEG_K1_TIMES_SRC	(2 << 16)
#define CURSOR_DST_BLEND_MASK			(3 << 16)
#define CURSOR_SRC_BLEND_K1			(0 << 8)
#define CURSOR_SRC_BLEND_K1_TIMES_SRC		(1 << 8)
#define CURSOR_SRC_BLEND_MASK			(3 << 8)
#define CURSOR_ALPHA				0xff

#define DC_WIN_CSC_YOF				0x611
#define DC_WIN_CSC_KYRGB			0x612
#define DC_WIN_CSC_KUR				0x613