Loading drivers/gpu/drm/radeon/r500_reg.h +3 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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 Loading drivers/gpu/drm/radeon/r600_cs.c +124 −1 Original line number Diff line number Diff line Loading @@ -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", Loading drivers/gpu/drm/radeon/radeon_reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/gpu/drm/radeon/r500_reg.h +3 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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 Loading
drivers/gpu/drm/radeon/r600_cs.c +124 −1 Original line number Diff line number Diff line Loading @@ -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", Loading
drivers/gpu/drm/radeon/radeon_reg.h +1 −0 Original line number Diff line number Diff line Loading @@ -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