diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/radeon/r100.c | 105 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r300.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r500_reg.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv515.c | 23 |
4 files changed, 137 insertions, 6 deletions
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index a3db56bb013..154648a2c02 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -752,6 +752,102 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p, } /** + * r100_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 + * PACKET0 - WAIT_UNTIL +_value + * RELOC (P3) - crtc_id in reloc. + * + * This function parses this and relocates the VLINE START END + * and WAIT UNTIL packets to the correct crtc. + * It also detects a switched off crtc and nulls out the + * wait in that case. + */ +int r100_cs_packet_parse_vline(struct radeon_cs_parser *p) +{ + struct radeon_cs_chunk *ib_chunk; + struct drm_mode_object *obj; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + struct radeon_cs_packet p3reloc, waitreloc; + int crtc_id; + int r; + uint32_t header, h_idx, reg; + + ib_chunk = &p->chunks[p->chunk_ib_idx]; + + /* parse the wait until */ + r = r100_cs_packet_parse(p, &waitreloc, p->idx); + if (r) + return r; + + /* check its a wait until and only 1 count */ + if (waitreloc.reg != RADEON_WAIT_UNTIL || + waitreloc.count != 0) { + DRM_ERROR("vline wait had illegal wait until segment\n"); + r = -EINVAL; + return r; + } + + if (ib_chunk->kdata[waitreloc.idx + 1] != RADEON_WAIT_CRTC_VLINE) { + DRM_ERROR("vline wait had illegal wait until\n"); + r = -EINVAL; + return r; + } + + /* jump over the NOP */ + r = r100_cs_packet_parse(p, &p3reloc, p->idx); + if (r) + return r; + + h_idx = p->idx - 2; + p->idx += waitreloc.count; + p->idx += p3reloc.count; + + header = ib_chunk->kdata[h_idx]; + crtc_id = ib_chunk->kdata[h_idx + 5]; + reg = ib_chunk->kdata[h_idx] >> 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 until */ + ib_chunk->kdata[h_idx + 2] = PACKET2(0); + ib_chunk->kdata[h_idx + 3] = PACKET2(0); + } else if (crtc_id == 1) { + switch (reg) { + case AVIVO_D1MODE_VLINE_START_END: + header &= R300_CP_PACKET0_REG_MASK; + header |= AVIVO_D2MODE_VLINE_START_END >> 2; + break; + case RADEON_CRTC_GUI_TRIG_VLINE: + header &= R300_CP_PACKET0_REG_MASK; + header |= RADEON_CRTC2_GUI_TRIG_VLINE >> 2; + break; + default: + DRM_ERROR("unknown crtc reloc\n"); + r = -EINVAL; + goto out; + } + ib_chunk->kdata[h_idx] = header; + ib_chunk->kdata[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1; + } +out: + mutex_unlock(&p->rdev->ddev->mode_config.mutex); + return r; +} + +/** * r100_cs_packet_next_reloc() - parse next packet which should be reloc packet3 * @parser: parser structure holding parsing context. * @data: pointer to relocation data @@ -824,6 +920,15 @@ static int r100_packet0_check(struct radeon_cs_parser *p, } for (i = 0; i <= pkt->count; i++, idx++, reg += 4) { switch (reg) { + case RADEON_CRTC_GUI_TRIG_VLINE: + r = r100_cs_packet_parse_vline(p); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + break; /* FIXME: only allow PACKET3 blit? easier to check for out of * range access */ case RADEON_DST_PITCH_OFFSET: diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index cd9ea98e9c6..656d9238bb0 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -44,6 +44,7 @@ int r100_gui_wait_for_idle(struct radeon_device *rdev); int r100_cs_packet_parse(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, unsigned idx); +int r100_cs_packet_parse_vline(struct radeon_cs_parser *p); int r100_cs_packet_next_reloc(struct radeon_cs_parser *p, struct radeon_cs_reloc **cs_reloc); int r100_cs_parse_packet0(struct radeon_cs_parser *p, @@ -972,7 +973,7 @@ static inline void r300_cs_track_clear(struct r300_cs_track *track) static const unsigned r300_reg_safe_bm[159] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, @@ -1029,6 +1030,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p, ib_chunk = &p->chunks[p->chunk_ib_idx]; track = (struct r300_cs_track*)p->track; switch(reg) { + case AVIVO_D1MODE_VLINE_START_END: + case RADEON_CRTC_GUI_TRIG_VLINE: + r = r100_cs_packet_parse_vline(p); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + break; case RADEON_DST_PITCH_OFFSET: case RADEON_SRC_PITCH_OFFSET: r = r100_cs_packet_next_reloc(p, &reloc); diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 9070a1c2ce2..036691b38cb 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -445,6 +445,7 @@ #define AVIVO_D1MODE_DATA_FORMAT 0x6528 # define AVIVO_D1MODE_INTERLEAVE_EN (1 << 0) #define AVIVO_D1MODE_DESKTOP_HEIGHT 0x652C +#define AVIVO_D1MODE_VLINE_START_END 0x6538 #define AVIVO_D1MODE_VIEWPORT_START 0x6580 #define AVIVO_D1MODE_VIEWPORT_SIZE 0x6584 #define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6588 @@ -496,6 +497,7 @@ #define AVIVO_D2CUR_SIZE 0x6c10 #define AVIVO_D2CUR_POSITION 0x6c14 +#define AVIVO_D2MODE_VLINE_START_END 0x6d38 #define AVIVO_D2MODE_VIEWPORT_START 0x6d80 #define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84 #define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88 diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index ffea37b1b3e..d1384d3991a 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -509,9 +509,9 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev) /* * Asic initialization */ -static const unsigned r500_reg_safe_bm[159] = { +static const unsigned r500_reg_safe_bm[219] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, @@ -549,11 +549,24 @@ static const unsigned r500_reg_safe_bm[159] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0003FC01, 0x3FFFFCF8, 0xFE800B19, + 0x0003FC01, 0x3FFFFCF8, 0xFE800B19, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, }; - - int rv515_init(struct radeon_device *rdev) { rdev->config.r300.reg_safe_bm = r500_reg_safe_bm; |