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: Thierry Reding <treding@nvidia.com>
This commit is contained in:
Thierry Reding 2013-12-20 13:58:33 +01:00
parent 9910f5c455
commit e687651bc1
2 changed files with 138 additions and 3 deletions

View File

@ -17,6 +17,7 @@
struct tegra_dc_soc_info { struct tegra_dc_soc_info {
bool supports_interlacing; bool supports_interlacing;
bool supports_cursor;
}; };
struct tegra_plane { struct tegra_plane {
@ -477,6 +478,109 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc)
spin_unlock_irqrestore(&dc->lock, flags); 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) static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
{ {
struct drm_device *drm = dc->base.dev; 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 = { 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, .page_flip = tegra_dc_page_flip,
.set_config = drm_crtc_helper_set_config, .set_config = drm_crtc_helper_set_config,
.destroy = tegra_dc_destroy, .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_BL_CONTROL);
DUMP_REG(DC_DISP_SD_HW_K_VALUES); DUMP_REG(DC_DISP_SD_HW_K_VALUES);
DUMP_REG(DC_DISP_SD_MAN_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_WIN_OPTIONS);
DUMP_REG(DC_WIN_BYTE_SWAP); DUMP_REG(DC_WIN_BYTE_SWAP);
DUMP_REG(DC_WIN_BUFFER_CONTROL); 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 = { static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
.supports_interlacing = false, .supports_interlacing = false,
.supports_cursor = false,
}; };
static const struct tegra_dc_soc_info tegra30_dc_soc_info = { static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
.supports_interlacing = false, .supports_interlacing = false,
.supports_cursor = false,
}; };
static const struct tegra_dc_soc_info tegra124_dc_soc_info = { static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
.supports_interlacing = true, .supports_interlacing = true,
.supports_cursor = true,
}; };
static const struct of_device_id tegra_dc_of_match[] = { static const struct of_device_id tegra_dc_of_match[] = {

View File

@ -67,10 +67,12 @@
#define WIN_A_ACT_REQ (1 << 1) #define WIN_A_ACT_REQ (1 << 1)
#define WIN_B_ACT_REQ (1 << 2) #define WIN_B_ACT_REQ (1 << 2)
#define WIN_C_ACT_REQ (1 << 3) #define WIN_C_ACT_REQ (1 << 3)
#define CURSOR_ACT_REQ (1 << 7)
#define GENERAL_UPDATE (1 << 8) #define GENERAL_UPDATE (1 << 8)
#define WIN_A_UPDATE (1 << 9) #define WIN_A_UPDATE (1 << 9)
#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 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
@ -116,9 +118,10 @@
#define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401 #define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401
#define DC_DISP_DISP_WIN_OPTIONS 0x402 #define DC_DISP_DISP_WIN_OPTIONS 0x402
#define HDMI_ENABLE (1 << 30) #define HDMI_ENABLE (1 << 30)
#define DSI_ENABLE (1 << 29) #define DSI_ENABLE (1 << 29)
#define SOR_ENABLE (1 << 25) #define SOR_ENABLE (1 << 25)
#define CURSOR_ENABLE (1 << 16)
#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) #define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24)
@ -266,6 +269,14 @@
#define DC_DISP_CURSOR_BACKGROUND 0x43d #define DC_DISP_CURSOR_BACKGROUND 0x43d
#define DC_DISP_CURSOR_START_ADDR 0x43e #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_START_ADDR_NS 0x43f
#define DC_DISP_CURSOR_POSITION 0x440 #define DC_DISP_CURSOR_POSITION 0x440
@ -302,6 +313,19 @@
#define INTERLACE_START (1 << 1) #define INTERLACE_START (1 << 1)
#define INTERLACE_ENABLE (1 << 0) #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_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