Hardware cursor support.
This commit is contained in:
parent
a83db5274c
commit
6737f07729
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: tegra_dcreg.h,v 1.4 2015/11/10 22:14:05 jmcneill Exp $ */
|
||||
/* $NetBSD: tegra_dcreg.h,v 1.5 2015/11/14 11:55:36 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
@ -235,9 +235,26 @@
|
||||
#define DC_DISP_COLOR_KEY1_UPPER_REG 0x10e4
|
||||
#define DC_DISP_CURSOR_FOREGROUND_REG 0x10f0
|
||||
#define DC_DISP_CURSOR_BACKGROUND_REG 0x10f4
|
||||
|
||||
#define DC_DISP_CURSOR_START_ADDR_REG 0x10f8
|
||||
#define DC_DISP_CURSOR_START_ADDR_CLIPPING __BITS(29,28)
|
||||
#define DC_DISP_CURSOR_START_ADDR_CLIPPING_DISPLAY 0
|
||||
#define DC_DISP_CURSOR_START_ADDR_CLIPPING_WA 1
|
||||
#define DC_DISP_CURSOR_START_ADDR_CLIPPING_WB 2
|
||||
#define DC_DISP_CURSOR_START_ADDR_CLIPPING_WC 3
|
||||
#define DC_DISP_CURSOR_START_ADDR_SIZE __BITS(25,24)
|
||||
#define DC_DISP_CURSOR_START_ADDR_SIZE_32 0
|
||||
#define DC_DISP_CURSOR_START_ADDR_SIZE_64 1
|
||||
#define DC_DISP_CURSOR_START_ADDR_SIZE_128 2
|
||||
#define DC_DISP_CURSOR_START_ADDR_SIZE_256 3
|
||||
#define DC_DISP_CURSOR_START_ADDR_ADDRESS_LO __BITS(21,0)
|
||||
|
||||
#define DC_DISP_CURSOR_START_ADDR_NS_REG 0x10fc
|
||||
|
||||
#define DC_DISP_CURSOR_POSITION_REG 0x1100
|
||||
#define DC_DISP_CURSOR_POSITION_V __BITS(29,16)
|
||||
#define DC_DISP_CURSOR_POSITION_H __BITS(13,0)
|
||||
|
||||
#define DC_DISP_CURSOR_POSITION_NS_REG 0x1104
|
||||
#define DC_DISP_DC_MCCIF_FIFOCTRL_REG 0x1200
|
||||
#define DC_DISP_MCCIF_DISPLAY0A_HYST_REG 0x1204
|
||||
@ -272,7 +289,13 @@
|
||||
#define DC_DISP_CURSOR_START_ADDR_HI_NS_REG 0x13b4
|
||||
#define DC_DISP_CURSOR_INTERLACE_CONTROL_REG 0x13b8
|
||||
#define DC_DISP_CSC2_CONTROL_REG 0x13bc
|
||||
|
||||
#define DC_DISP_BLEND_CURSOR_CONTROL_REG 0x13c4
|
||||
#define DC_DISP_BLEND_CURSOR_CONTROL_MODE_SEL __BIT(24)
|
||||
#define DC_DISP_BLEND_CURSOR_CONTROL_DST_BLEND_FACTOR_SEL __BITS(17,16)
|
||||
#define DC_DISP_BLEND_CURSOR_CONTROL_SRC_BLEND_FACTOR_SEL __BITS(9,8)
|
||||
#define DC_DISP_BLEND_CURSOR_CONTROL_ALPHA __BITS(7,0)
|
||||
|
||||
#define DC_DISP_DVFS_CURSOR_CONTROL_REG 0x13c8
|
||||
#define DC_DISP_CURSOR_UFLOW_DBG_PIXEL_REG 0x13cc
|
||||
#define DC_DISP_CURSOR_SPOOLUP_CONTROL_REG 0x13d0
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: tegra_drm.h,v 1.3 2015/11/12 00:43:52 jmcneill Exp $ */
|
||||
/* $NetBSD: tegra_drm.h,v 1.4 2015/11/14 11:55:36 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
@ -43,6 +43,8 @@
|
||||
|
||||
struct tegra_framebuffer;
|
||||
|
||||
struct tegra_gem_object;
|
||||
|
||||
struct tegra_drm_softc {
|
||||
device_t sc_dev;
|
||||
struct drm_device *sc_ddev;
|
||||
@ -76,6 +78,11 @@ struct tegra_crtc {
|
||||
int intr;
|
||||
int index;
|
||||
void *ih;
|
||||
bool enabled;
|
||||
|
||||
struct tegra_gem_object *cursor_obj;
|
||||
int cursor_x;
|
||||
int cursor_y;
|
||||
};
|
||||
|
||||
struct tegra_encoder {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: tegra_drm_mode.c,v 1.5 2015/11/12 00:43:52 jmcneill Exp $ */
|
||||
/* $NetBSD: tegra_drm_mode.c,v 1.6 2015/11/14 11:55:36 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: tegra_drm_mode.c,v 1.5 2015/11/12 00:43:52 jmcneill Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: tegra_drm_mode.c,v 1.6 2015/11/14 11:55:36 jmcneill Exp $");
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
@ -61,9 +61,14 @@ static const struct drm_framebuffer_funcs tegra_framebuffer_funcs = {
|
||||
|
||||
static int tegra_crtc_init(struct drm_device *, int);
|
||||
static void tegra_crtc_destroy(struct drm_crtc *);
|
||||
static int tegra_crtc_cursor_set(struct drm_crtc *, struct drm_file *,
|
||||
uint32_t, uint32_t, uint32_t);
|
||||
static int tegra_crtc_cursor_move(struct drm_crtc *, int, int);
|
||||
static int tegra_crtc_intr(void *);
|
||||
|
||||
static const struct drm_crtc_funcs tegra_crtc_funcs = {
|
||||
.cursor_set = tegra_crtc_cursor_set,
|
||||
.cursor_move = tegra_crtc_cursor_move,
|
||||
.set_config = drm_crtc_helper_set_config,
|
||||
.destroy = tegra_crtc_destroy
|
||||
};
|
||||
@ -314,6 +319,12 @@ tegra_crtc_init(struct drm_device *ddev, int index)
|
||||
if (crtc->ih == NULL) {
|
||||
DRM_ERROR("failed to establish interrupt for crtc %d\n", index);
|
||||
}
|
||||
const size_t cursor_size = 256 * 256 * 4;
|
||||
crtc->cursor_obj = tegra_drm_obj_alloc(ddev, cursor_size);
|
||||
if (crtc->cursor_obj == NULL) {
|
||||
kmem_free(crtc, sizeof(*crtc));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tegra_car_dc_enable(crtc->index);
|
||||
|
||||
@ -325,6 +336,166 @@ tegra_crtc_init(struct drm_device *ddev, int index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tegra_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
|
||||
uint32_t handle, uint32_t width, uint32_t height)
|
||||
{
|
||||
struct tegra_crtc *tegra_crtc = to_tegra_crtc(crtc);
|
||||
struct drm_gem_object *gem_obj = NULL;
|
||||
struct tegra_gem_object *obj;
|
||||
uint32_t cfg, opt;
|
||||
int error;
|
||||
|
||||
if (tegra_crtc->enabled == false)
|
||||
return 0;
|
||||
|
||||
if (handle == 0) {
|
||||
/* hide cursor */
|
||||
opt = DC_READ(tegra_crtc, DC_DISP_DISP_WIN_OPTIONS_REG);
|
||||
if ((opt & DC_DISP_DISP_WIN_OPTIONS_CURSOR_ENABLE) != 0) {
|
||||
opt &= ~DC_DISP_DISP_WIN_OPTIONS_CURSOR_ENABLE;
|
||||
DC_WRITE(tegra_crtc, DC_DISP_DISP_WIN_OPTIONS_REG, opt);
|
||||
/* Commit settings */
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_GENERAL_UPDATE);
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_GENERAL_ACT_REQ);
|
||||
}
|
||||
error = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((width != height) ||
|
||||
(width != 32 && width != 64 && width != 128 && width != 256)) {
|
||||
DRM_ERROR("Cursor dimension %ux%u not supported\n",
|
||||
width, height);
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
gem_obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
|
||||
if (gem_obj == NULL) {
|
||||
DRM_ERROR("Cannot find cursor object %#x for crtc %d\n",
|
||||
handle, tegra_crtc->index);
|
||||
error = -ENOENT;
|
||||
goto done;
|
||||
}
|
||||
obj = to_tegra_gem_obj(gem_obj);
|
||||
|
||||
if (obj->base.size < width * height * 4) {
|
||||
DRM_ERROR("Cursor buffer is too small\n");
|
||||
error = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cfg = __SHIFTIN(DC_DISP_CURSOR_START_ADDR_CLIPPING_DISPLAY,
|
||||
DC_DISP_CURSOR_START_ADDR_CLIPPING);
|
||||
switch (width) {
|
||||
case 32:
|
||||
cfg |= __SHIFTIN(DC_DISP_CURSOR_START_ADDR_SIZE_32,
|
||||
DC_DISP_CURSOR_START_ADDR_SIZE);
|
||||
break;
|
||||
case 64:
|
||||
cfg |= __SHIFTIN(DC_DISP_CURSOR_START_ADDR_SIZE_64,
|
||||
DC_DISP_CURSOR_START_ADDR_SIZE);
|
||||
break;
|
||||
case 128:
|
||||
cfg |= __SHIFTIN(DC_DISP_CURSOR_START_ADDR_SIZE_128,
|
||||
DC_DISP_CURSOR_START_ADDR_SIZE);
|
||||
break;
|
||||
case 256:
|
||||
cfg |= __SHIFTIN(DC_DISP_CURSOR_START_ADDR_SIZE_256,
|
||||
DC_DISP_CURSOR_START_ADDR_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy cursor (argb -> rgba) */
|
||||
struct tegra_gem_object *cursor_obj = tegra_crtc->cursor_obj;
|
||||
uint32_t off, *cp = obj->dmap, *crtc_cp = cursor_obj->dmap;
|
||||
for (off = 0; off < width * height; off++) {
|
||||
crtc_cp[off] = (cp[off] << 8) | (cp[off] >> 24);
|
||||
}
|
||||
|
||||
cfg |= __SHIFTIN((cursor_obj->dmasegs[0].ds_addr >> 10) & 0x3fffff,
|
||||
DC_DISP_CURSOR_START_ADDR_ADDRESS_LO);
|
||||
const uint32_t ocfg =
|
||||
DC_READ(tegra_crtc, DC_DISP_CURSOR_START_ADDR_REG);
|
||||
if (cfg != ocfg) {
|
||||
DC_WRITE(tegra_crtc, DC_DISP_CURSOR_START_ADDR_REG, cfg);
|
||||
}
|
||||
|
||||
cfg = DC_READ(tegra_crtc, DC_DISP_BLEND_CURSOR_CONTROL_REG);
|
||||
cfg &= ~DC_DISP_BLEND_CURSOR_CONTROL_DST_BLEND_FACTOR_SEL;
|
||||
cfg |= __SHIFTIN(2, DC_DISP_BLEND_CURSOR_CONTROL_DST_BLEND_FACTOR_SEL);
|
||||
cfg &= ~DC_DISP_BLEND_CURSOR_CONTROL_SRC_BLEND_FACTOR_SEL;
|
||||
cfg |= __SHIFTIN(1, DC_DISP_BLEND_CURSOR_CONTROL_SRC_BLEND_FACTOR_SEL);
|
||||
cfg &= ~DC_DISP_BLEND_CURSOR_CONTROL_ALPHA;
|
||||
cfg |= __SHIFTIN(255, DC_DISP_BLEND_CURSOR_CONTROL_ALPHA);
|
||||
cfg |= DC_DISP_BLEND_CURSOR_CONTROL_MODE_SEL;
|
||||
DC_WRITE(tegra_crtc, DC_DISP_BLEND_CURSOR_CONTROL_REG, cfg);
|
||||
|
||||
/* set cursor position */
|
||||
DC_WRITE(tegra_crtc, DC_DISP_CURSOR_POSITION_REG,
|
||||
__SHIFTIN(tegra_crtc->cursor_x, DC_DISP_CURSOR_POSITION_H) |
|
||||
__SHIFTIN(tegra_crtc->cursor_y, DC_DISP_CURSOR_POSITION_V));
|
||||
|
||||
/* Commit settings */
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_CURSOR_UPDATE);
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_CURSOR_ACT_REQ);
|
||||
|
||||
/* show cursor */
|
||||
opt = DC_READ(tegra_crtc, DC_DISP_DISP_WIN_OPTIONS_REG);
|
||||
if ((opt & DC_DISP_DISP_WIN_OPTIONS_CURSOR_ENABLE) == 0) {
|
||||
opt |= DC_DISP_DISP_WIN_OPTIONS_CURSOR_ENABLE;
|
||||
DC_WRITE(tegra_crtc, DC_DISP_DISP_WIN_OPTIONS_REG, opt);
|
||||
|
||||
/* Commit settings */
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_GENERAL_UPDATE);
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_GENERAL_ACT_REQ);
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
done:
|
||||
if (error == 0) {
|
||||
/* Wait for activation request to complete */
|
||||
while (DC_READ(tegra_crtc, DC_CMD_STATE_CONTROL_REG) &
|
||||
DC_CMD_STATE_CONTROL_GENERAL_ACT_REQ)
|
||||
;
|
||||
}
|
||||
|
||||
if (gem_obj) {
|
||||
drm_gem_object_unreference_unlocked(gem_obj);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
tegra_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
|
||||
{
|
||||
struct tegra_crtc *tegra_crtc = to_tegra_crtc(crtc);
|
||||
|
||||
tegra_crtc->cursor_x = x & 0x3fff;
|
||||
tegra_crtc->cursor_y = y & 0x3fff;
|
||||
|
||||
DC_WRITE(tegra_crtc, DC_DISP_CURSOR_POSITION_REG,
|
||||
__SHIFTIN(x & 0x3fff, DC_DISP_CURSOR_POSITION_H) |
|
||||
__SHIFTIN(y & 0x3fff, DC_DISP_CURSOR_POSITION_V));
|
||||
|
||||
/* Commit settings */
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_CURSOR_UPDATE);
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_CURSOR_ACT_REQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tegra_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
@ -333,6 +504,7 @@ tegra_crtc_destroy(struct drm_crtc *crtc)
|
||||
if (tegra_crtc->ih) {
|
||||
intr_disestablish(tegra_crtc->ih);
|
||||
}
|
||||
tegra_drm_obj_free(tegra_crtc->cursor_obj);
|
||||
bus_space_unmap(tegra_crtc->bst, tegra_crtc->bsh, tegra_crtc->size);
|
||||
kmem_free(tegra_crtc, sizeof(*tegra_crtc));
|
||||
}
|
||||
@ -543,6 +715,8 @@ tegra_crtc_commit(struct drm_crtc *crtc)
|
||||
DC_WRITE(tegra_crtc, DC_CMD_STATE_CONTROL_REG,
|
||||
DC_CMD_STATE_CONTROL_GENERAL_ACT_REQ |
|
||||
DC_CMD_STATE_CONTROL_WIN_A_ACT_REQ);
|
||||
|
||||
tegra_crtc->enabled = true;
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user