mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-16 18:26:42 +00:00
drm/radeon/kms/r600: add support for vline relocs
Provides support for anti-tearing functionality in the ddx. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@linux.ie>
This commit is contained in:
parent
90ebd0655a
commit
2f67c6e022
@ -445,6 +445,8 @@
|
||||
#define AVIVO_D1MODE_VBLANK_STATUS 0x6534
|
||||
# define AVIVO_VBLANK_ACK (1 << 4)
|
||||
#define AVIVO_D1MODE_VLINE_START_END 0x6538
|
||||
#define AVIVO_D1MODE_VLINE_STATUS 0x653c
|
||||
# define AVIVO_D1MODE_VLINE_STAT (1 << 12)
|
||||
#define AVIVO_DxMODE_INT_MASK 0x6540
|
||||
# define AVIVO_D1MODE_INT_MASK (1 << 0)
|
||||
# define AVIVO_D2MODE_INT_MASK (1 << 8)
|
||||
@ -502,6 +504,7 @@
|
||||
|
||||
#define AVIVO_D2MODE_VBLANK_STATUS 0x6d34
|
||||
#define AVIVO_D2MODE_VLINE_START_END 0x6d38
|
||||
#define AVIVO_D2MODE_VLINE_STATUS 0x6d3c
|
||||
#define AVIVO_D2MODE_VIEWPORT_START 0x6d80
|
||||
#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84
|
||||
#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88
|
||||
|
@ -177,13 +177,136 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* r600_cs_packet_next_vline() - parse userspace VLINE packet
|
||||
* @parser: parser structure holding parsing context.
|
||||
*
|
||||
* Userspace sends a special sequence for VLINE waits.
|
||||
* PACKET0 - VLINE_START_END + value
|
||||
* PACKET3 - WAIT_REG_MEM poll vline status reg
|
||||
* RELOC (P3) - crtc_id in reloc.
|
||||
*
|
||||
* This function parses this and relocates the VLINE START END
|
||||
* and WAIT_REG_MEM packets to the correct crtc.
|
||||
* It also detects a switched off crtc and nulls out the
|
||||
* wait in that case.
|
||||
*/
|
||||
static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p)
|
||||
{
|
||||
struct drm_mode_object *obj;
|
||||
struct drm_crtc *crtc;
|
||||
struct radeon_crtc *radeon_crtc;
|
||||
struct radeon_cs_packet p3reloc, wait_reg_mem;
|
||||
int crtc_id;
|
||||
int r;
|
||||
uint32_t header, h_idx, reg, wait_reg_mem_info;
|
||||
volatile uint32_t *ib;
|
||||
|
||||
ib = p->ib->ptr;
|
||||
|
||||
/* parse the WAIT_REG_MEM */
|
||||
r = r600_cs_packet_parse(p, &wait_reg_mem, p->idx);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* check its a WAIT_REG_MEM */
|
||||
if (wait_reg_mem.type != PACKET_TYPE3 ||
|
||||
wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) {
|
||||
DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n");
|
||||
r = -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1);
|
||||
/* bit 4 is reg (0) or mem (1) */
|
||||
if (wait_reg_mem_info & 0x10) {
|
||||
DRM_ERROR("vline WAIT_REG_MEM waiting on MEM rather than REG\n");
|
||||
r = -EINVAL;
|
||||
return r;
|
||||
}
|
||||
/* waiting for value to be equal */
|
||||
if ((wait_reg_mem_info & 0x7) != 0x3) {
|
||||
DRM_ERROR("vline WAIT_REG_MEM function not equal\n");
|
||||
r = -EINVAL;
|
||||
return r;
|
||||
}
|
||||
if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != AVIVO_D1MODE_VLINE_STATUS) {
|
||||
DRM_ERROR("vline WAIT_REG_MEM bad reg\n");
|
||||
r = -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != AVIVO_D1MODE_VLINE_STAT) {
|
||||
DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n");
|
||||
r = -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* jump over the NOP */
|
||||
r = r600_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
h_idx = p->idx - 2;
|
||||
p->idx += wait_reg_mem.count + 2;
|
||||
p->idx += p3reloc.count + 2;
|
||||
|
||||
header = radeon_get_ib_value(p, h_idx);
|
||||
crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
|
||||
reg = header >> 2;
|
||||
mutex_lock(&p->rdev->ddev->mode_config.mutex);
|
||||
obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
|
||||
if (!obj) {
|
||||
DRM_ERROR("cannot find crtc %d\n", crtc_id);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
crtc = obj_to_crtc(obj);
|
||||
radeon_crtc = to_radeon_crtc(crtc);
|
||||
crtc_id = radeon_crtc->crtc_id;
|
||||
|
||||
if (!crtc->enabled) {
|
||||
/* if the CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */
|
||||
ib[h_idx + 2] = PACKET2(0);
|
||||
ib[h_idx + 3] = PACKET2(0);
|
||||
ib[h_idx + 4] = PACKET2(0);
|
||||
ib[h_idx + 5] = PACKET2(0);
|
||||
ib[h_idx + 6] = PACKET2(0);
|
||||
ib[h_idx + 7] = PACKET2(0);
|
||||
ib[h_idx + 8] = PACKET2(0);
|
||||
} else if (crtc_id == 1) {
|
||||
switch (reg) {
|
||||
case AVIVO_D1MODE_VLINE_START_END:
|
||||
header &= ~R600_CP_PACKET0_REG_MASK;
|
||||
header |= AVIVO_D2MODE_VLINE_START_END >> 2;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("unknown crtc reloc\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ib[h_idx] = header;
|
||||
ib[h_idx + 4] = AVIVO_D2MODE_VLINE_STATUS >> 2;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&p->rdev->ddev->mode_config.mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int r600_packet0_check(struct radeon_cs_parser *p,
|
||||
struct radeon_cs_packet *pkt,
|
||||
unsigned idx, unsigned reg)
|
||||
{
|
||||
int r;
|
||||
|
||||
switch (reg) {
|
||||
case AVIVO_D1MODE_VLINE_START_END:
|
||||
case AVIVO_D2MODE_VLINE_START_END:
|
||||
r = r600_cs_packet_parse_vline(p);
|
||||
if (r) {
|
||||
DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
|
||||
idx, reg);
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
|
||||
|
@ -3333,6 +3333,7 @@
|
||||
# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12)
|
||||
# define RADEON_CP_PACKET0_REG_MASK 0x000007ff
|
||||
# define R300_CP_PACKET0_REG_MASK 0x00001fff
|
||||
# define R600_CP_PACKET0_REG_MASK 0x0000ffff
|
||||
# define RADEON_CP_PACKET1_REG0_MASK 0x000007ff
|
||||
# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user