Skip to content

Commit d5ec699

Browse files
committed
drm/tegra: dc: Implement hardware cursor on Tegra186 and later
The hardware cursor on Tegra186 differs slightly from the implementation on older SoC generations. In particular the new implementation relies on software for clipping the cursor against the screen. Fortunately, atomic KMS already computes clipped coordinates for (cursor) planes, so this is trivial to implement. The format supported by the hardware cursor is also slightly different. v2: use more drm_rect helpers (Dmitry) Signed-off-by: Thierry Reding <[email protected]> Reviewed-by: Dmitry Osipenko <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent 042c0bd commit d5ec699

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

drivers/gpu/drm/tegra/dc.c

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -832,10 +832,14 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
832832
return &plane->base;
833833
}
834834

835-
static const u32 tegra_cursor_plane_formats[] = {
835+
static const u32 tegra_legacy_cursor_plane_formats[] = {
836836
DRM_FORMAT_RGBA8888,
837837
};
838838

839+
static const u32 tegra_cursor_plane_formats[] = {
840+
DRM_FORMAT_ARGB8888,
841+
};
842+
839843
static int tegra_cursor_atomic_check(struct drm_plane *plane,
840844
struct drm_atomic_state *state)
841845
{
@@ -875,12 +879,24 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
875879
plane);
876880
struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state);
877881
struct tegra_dc *dc = to_tegra_dc(new_state->crtc);
878-
u32 value = CURSOR_CLIP_DISPLAY;
882+
struct tegra_drm *tegra = plane->dev->dev_private;
883+
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
884+
u64 dma_mask = *dc->dev->dma_mask;
885+
#endif
886+
unsigned int x, y;
887+
u32 value = 0;
879888

880889
/* rien ne va plus */
881890
if (!new_state->crtc || !new_state->fb)
882891
return;
883892

893+
/*
894+
* Legacy display supports hardware clipping of the cursor, but
895+
* nvdisplay relies on software to clip the cursor to the screen.
896+
*/
897+
if (!dc->soc->has_nvdisplay)
898+
value |= CURSOR_CLIP_DISPLAY;
899+
884900
switch (new_state->crtc_w) {
885901
case 32:
886902
value |= CURSOR_SIZE_32x32;
@@ -908,7 +924,7 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
908924
tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
909925

910926
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
911-
value = (tegra_plane_state->iova[0] >> 32) & 0x3;
927+
value = (tegra_plane_state->iova[0] >> 32) & (dma_mask >> 32);
912928
tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);
913929
#endif
914930

@@ -920,15 +936,39 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
920936
value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
921937
value &= ~CURSOR_DST_BLEND_MASK;
922938
value &= ~CURSOR_SRC_BLEND_MASK;
923-
value |= CURSOR_MODE_NORMAL;
939+
940+
if (dc->soc->has_nvdisplay)
941+
value &= ~CURSOR_COMPOSITION_MODE_XOR;
942+
else
943+
value |= CURSOR_MODE_NORMAL;
944+
924945
value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
925946
value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
926947
value |= CURSOR_ALPHA;
927948
tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
928949

950+
/* nvdisplay relies on software for clipping */
951+
if (dc->soc->has_nvdisplay) {
952+
struct drm_rect src;
953+
954+
x = new_state->dst.x1;
955+
y = new_state->dst.y1;
956+
957+
drm_rect_fp_to_int(&src, &new_state->src);
958+
959+
value = (src.y1 & tegra->vmask) << 16 | (src.x1 & tegra->hmask);
960+
tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR);
961+
962+
value = (drm_rect_height(&src) & tegra->vmask) << 16 |
963+
(drm_rect_width(&src) & tegra->hmask);
964+
tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR);
965+
} else {
966+
x = new_state->crtc_x;
967+
y = new_state->crtc_y;
968+
}
969+
929970
/* position the cursor */
930-
value = (new_state->crtc_y & 0x3fff) << 16 |
931-
(new_state->crtc_x & 0x3fff);
971+
value = ((y & tegra->vmask) << 16) | (x & tegra->hmask);
932972
tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
933973
}
934974

@@ -982,8 +1022,13 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
9821022
plane->index = 6;
9831023
plane->dc = dc;
9841024

985-
num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
986-
formats = tegra_cursor_plane_formats;
1025+
if (!dc->soc->has_nvdisplay) {
1026+
num_formats = ARRAY_SIZE(tegra_legacy_cursor_plane_formats);
1027+
formats = tegra_legacy_cursor_plane_formats;
1028+
} else {
1029+
num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
1030+
formats = tegra_cursor_plane_formats;
1031+
}
9871032

9881033
err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
9891034
&tegra_plane_funcs, formats,

drivers/gpu/drm/tegra/dc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,8 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
511511

512512
#define DC_DISP_CURSOR_START_ADDR_HI 0x4ec
513513
#define DC_DISP_BLEND_CURSOR_CONTROL 0x4f1
514+
#define CURSOR_COMPOSITION_MODE_BLEND (0 << 25)
515+
#define CURSOR_COMPOSITION_MODE_XOR (1 << 25)
514516
#define CURSOR_MODE_LEGACY (0 << 24)
515517
#define CURSOR_MODE_NORMAL (1 << 24)
516518
#define CURSOR_DST_BLEND_ZERO (0 << 16)
@@ -705,6 +707,9 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
705707
#define PROTOCOL_MASK (0xf << 8)
706708
#define PROTOCOL_SINGLE_TMDS_A (0x1 << 8)
707709

710+
#define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442
711+
#define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446
712+
708713
#define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL 0x702
709714
#define OWNER_MASK (0xf << 0)
710715
#define OWNER(x) (((x) & 0xf) << 0)

0 commit comments

Comments
 (0)