提交 2f67c6e0 编写于 作者: A Alex Deucher 提交者: Dave Airlie

drm/radeon/kms/r600: add support for vline relocs

Provides support for anti-tearing functionality
in the ddx.
Signed-off-by: NAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: NDave Airlie <airlied@linux.ie>
上级 90ebd065
...@@ -445,6 +445,8 @@ ...@@ -445,6 +445,8 @@
#define AVIVO_D1MODE_VBLANK_STATUS 0x6534 #define AVIVO_D1MODE_VBLANK_STATUS 0x6534
# define AVIVO_VBLANK_ACK (1 << 4) # define AVIVO_VBLANK_ACK (1 << 4)
#define AVIVO_D1MODE_VLINE_START_END 0x6538 #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_DxMODE_INT_MASK 0x6540
# define AVIVO_D1MODE_INT_MASK (1 << 0) # define AVIVO_D1MODE_INT_MASK (1 << 0)
# define AVIVO_D2MODE_INT_MASK (1 << 8) # define AVIVO_D2MODE_INT_MASK (1 << 8)
...@@ -502,6 +504,7 @@ ...@@ -502,6 +504,7 @@
#define AVIVO_D2MODE_VBLANK_STATUS 0x6d34 #define AVIVO_D2MODE_VBLANK_STATUS 0x6d34
#define AVIVO_D2MODE_VLINE_START_END 0x6d38 #define AVIVO_D2MODE_VLINE_START_END 0x6d38
#define AVIVO_D2MODE_VLINE_STATUS 0x6d3c
#define AVIVO_D2MODE_VIEWPORT_START 0x6d80 #define AVIVO_D2MODE_VIEWPORT_START 0x6d80
#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84 #define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84
#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88 #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, ...@@ -177,13 +177,136 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
return 0; 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, static int r600_packet0_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt, struct radeon_cs_packet *pkt,
unsigned idx, unsigned reg) unsigned idx, unsigned reg)
{ {
int r;
switch (reg) { switch (reg) {
case AVIVO_D1MODE_VLINE_START_END: 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; break;
default: default:
printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
......
...@@ -3333,6 +3333,7 @@ ...@@ -3333,6 +3333,7 @@
# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12) # define RADEON_CP_PACKET_MAX_DWORDS (1 << 12)
# define RADEON_CP_PACKET0_REG_MASK 0x000007ff # define RADEON_CP_PACKET0_REG_MASK 0x000007ff
# define R300_CP_PACKET0_REG_MASK 0x00001fff # 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_REG0_MASK 0x000007ff
# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 # define RADEON_CP_PACKET1_REG1_MASK 0x003ff800
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册