diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index dfa52e1..e5c8c6c 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -302,9 +302,9 @@ int r100_wb_init(struct radeon_device *rdev) return r; } } - WREG32(0x774, rdev->wb.gpu_addr); - WREG32(0x70C, rdev->wb.gpu_addr + 1024); - WREG32(0x770, 0xff); + WREG32(RADEON_SCRATCH_ADDR, rdev->wb.gpu_addr); + WREG32(RADEON_CP_RB_RPTR_ADDR, rdev->wb.gpu_addr + 1024); + WREG32(RADEON_SCRATCH_UMSK, 0xff); return 0; } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index fed40d7..a1d2d29 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -27,6 +27,7 @@ */ #include #include "drmP.h" +#include "radeon_drm.h" #include "radeon.h" #include "radeon_mode.h" #include "radeon_share.h" @@ -1222,6 +1223,94 @@ void r600_scratch_init(struct radeon_device *rdev) } } +int r600_ring_test(struct radeon_device *rdev) +{ + uint32_t scratch; + uint32_t tmp = 0; + unsigned i; + int r; + + r = radeon_scratch_get(rdev, &scratch); + if (r) { + DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r); + return r; + } + WREG32(scratch, 0xCAFEDEAD); + r = radeon_ring_lock(rdev, 2); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + radeon_scratch_free(rdev, scratch); + return r; + } + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); + radeon_ring_write(rdev, 0xDEADBEEF); + radeon_ring_unlock_commit(rdev); + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(scratch); + if (tmp == 0xDEADBEEF) { + break; + } + DRM_UDELAY(1); + } + if (i < rdev->usec_timeout) { + DRM_INFO("ring test succeeded in %d usecs\n", i); + } else { + DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n", + scratch, tmp); + r = -EINVAL; + } + radeon_scratch_free(rdev, scratch); + return r; +} + +/* + * Writeback + */ +int r600_wb_init(struct radeon_device *rdev) +{ + int r; + + if (rdev->wb.wb_obj == NULL) { + r = radeon_object_create(rdev, NULL, 4096, + true, + RADEON_GEM_DOMAIN_GTT, + false, &rdev->wb.wb_obj); + if (r) { + DRM_ERROR("radeon: failed to create WB buffer (%d).\n", r); + return r; + } + r = radeon_object_pin(rdev->wb.wb_obj, + RADEON_GEM_DOMAIN_GTT, + &rdev->wb.gpu_addr); + if (r) { + DRM_ERROR("radeon: failed to pin WB buffer (%d).\n", r); + return r; + } + r = radeon_object_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb); + if (r) { + DRM_ERROR("radeon: failed to map WB buffer (%d).\n", r); + return r; + } + } + WREG32(SCRATCH_ADDR, (rdev->wb.gpu_addr >> 8) & 0xFFFFFFFF); + WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + 1024) & 0xFFFFFFFC); + WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + 1024) & 0xFF); + WREG32(SCRATCH_UMSK, 0xff); + return 0; +} + +void r600_wb_fini(struct radeon_device *rdev) +{ + if (rdev->wb.wb_obj) { + radeon_object_kunmap(rdev->wb.wb_obj); + radeon_object_unpin(rdev->wb.wb_obj); + radeon_object_unref(&rdev->wb.wb_obj); + rdev->wb.wb = NULL; + rdev->wb.wb_obj = NULL; + } +} + /* * CS @@ -1230,7 +1319,8 @@ void r600_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence) { /* Emit fence sequence & fire IRQ */ - radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0)); + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); radeon_ring_write(rdev, fence->seq); } @@ -1315,6 +1405,9 @@ int r600_resume(struct radeon_device *rdev) r = r600_ib_test(rdev); if (r) return r; + r = r600_wb_init(rdev); + if (r) + return r; return 0; } @@ -1444,7 +1537,7 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) } radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); radeon_ring_write(rdev, ib->gpu_addr & 0xFFFFFFFC); - radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr)); + radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF); radeon_ring_write(rdev, ib->length_dw); //DRM_INFO("%s %d %d dw\n", __func__, __LINE__, ib->length_dw); } @@ -1467,9 +1560,9 @@ int r600_ib_test(struct radeon_device *rdev) if (r) { return r; } - ib->ptr[0] = PACKET0(scratch, 0); - ib->ptr[1] = 0xDEADBEEF; - ib->ptr[2] = PACKET2(0); + ib->ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1); + ib->ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); + ib->ptr[2] = 0xDEADBEEF; ib->ptr[3] = PACKET2(0); ib->ptr[4] = PACKET2(0); ib->ptr[5] = PACKET2(0); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index bfd1f41..22bc1e9 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -482,6 +482,8 @@ int r600_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); int r600_suspend(struct radeon_device *rdev); int r600_resume(struct radeon_device *rdev); +int r600_wb_init(struct radeon_device *rdev); +void r600_wb_fini(struct radeon_device *rdev); void r600_cp_commit(struct radeon_device *rdev); void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg); @@ -503,6 +505,7 @@ int r600_set_surface_reg(struct radeon_device *rdev, int reg, int r600_clear_surface_reg(struct radeon_device *rdev, int reg); void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int r600_ib_test(struct radeon_device *rdev); +int r600_ring_test(struct radeon_device *rdev); static struct radeon_asic r600_asic = { .errata = NULL, @@ -515,8 +518,8 @@ static struct radeon_asic r600_asic = { .gpu_reset = &r600_gpu_reset, .mc_init = NULL, .mc_fini = NULL, - .wb_init = NULL, - .wb_fini = NULL, + .wb_init = &r600_wb_init, + .wb_fini = &r600_wb_fini, .gart_enable = NULL, .gart_disable = NULL, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, @@ -525,7 +528,7 @@ static struct radeon_asic r600_asic = { .cp_fini = NULL, .cp_disable = NULL, .ring_start = NULL, - .ring_test = &r100_ring_test, + .ring_test = &r600_ring_test, .ring_ib_execute = &r600_ring_ib_execute, .ib_test = &r600_ib_test, .irq_set = &r600_irq_set, @@ -564,8 +567,8 @@ static struct radeon_asic rv770_asic = { .gpu_reset = &rv770_gpu_reset, .mc_init = NULL, .mc_fini = NULL, - .wb_init = NULL, - .wb_fini = NULL, + .wb_init = &r600_wb_init, + .wb_fini = &r600_wb_fini, .gart_enable = NULL, .gart_disable = NULL, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, @@ -574,7 +577,7 @@ static struct radeon_asic rv770_asic = { .cp_fini = NULL, .cp_disable = NULL, .ring_start = NULL, - .ring_test = &r100_ring_test, + .ring_test = &r600_ring_test, .ring_ib_execute = &r600_ring_ib_execute, .ib_test = &r600_ib_test, .irq_set = &r600_irq_set, diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index e1b6185..f0e4373 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -3194,6 +3194,24 @@ #define RADEON_CP_RB_WPTR 0x0714 #define RADEON_CP_RB_RPTR_WR 0x071c +#define RADEON_SCRATCH_UMSK 0x0770 +#define RADEON_SCRATCH_ADDR 0x0774 + +#define R600_CP_RB_BASE 0xc100 +#define R600_CP_RB_CNTL 0xc104 +# define R600_RB_BUFSZ(x) ((x) << 0) +# define R600_RB_BLKSZ(x) ((x) << 8) +# define R600_RB_NO_UPDATE (1 << 27) +# define R600_RB_RPTR_WR_ENA (1 << 31) +#define R600_CP_RB_RPTR_WR 0xc108 +#define R600_CP_RB_RPTR_ADDR 0xc10c +#define R600_CP_RB_RPTR_ADDR_HI 0xc110 +#define R600_CP_RB_WPTR 0xc114 +#define R600_CP_RB_WPTR_ADDR 0xc118 +#define R600_CP_RB_WPTR_ADDR_HI 0xc11c +#define R600_CP_RB_RPTR 0x8700 +#define R600_CP_RB_WPTR_DELAY 0x8704 + #define RADEON_CP_IB_BASE 0x0738 #define RADEON_CP_IB_BUFSZ 0x073c diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 82b85e5..51d2012 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -213,7 +213,10 @@ void radeon_ib_pool_fini(struct radeon_device *rdev) */ void radeon_ring_free_size(struct radeon_device *rdev) { - rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); + if (rdev->family >= CHIP_R600) + rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); + else + rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); /* This works because ring_size is a power of 2 */ rdev->cp.ring_free_dw = (rdev->cp.rptr + (rdev->cp.ring_size / 4)); rdev->cp.ring_free_dw -= rdev->cp.wptr; diff --git a/drivers/gpu/drm/radeon/radeon_share.h b/drivers/gpu/drm/radeon/radeon_share.h index 25bf269..72c827d 100644 --- a/drivers/gpu/drm/radeon/radeon_share.h +++ b/drivers/gpu/drm/radeon/radeon_share.h @@ -69,6 +69,10 @@ int r600_gart_clear_page(struct radeon_device *rdev, int i); int r600_mc_wait_for_idle(struct radeon_device *rdev); void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); int r600_ib_test(struct radeon_device *rdev); +int r600_ring_test(struct radeon_device *rdev); +int r600_wb_init(struct radeon_device *rdev); +void r600_wb_fini(struct radeon_device *rdev); + struct r600_asic { unsigned max_pipes; unsigned max_tile_pipes; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 3e12447..4193804 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -879,7 +879,15 @@ int rv770_resume(struct radeon_device *rdev) r = rv770_cp_load_microcode(rdev); if (r) return r; - r600_cp_resume(rdev); + r = r600_cp_resume(rdev); + if (r) + return r; + r = r600_ib_test(rdev); + if (r) + return r; + r = r600_wb_init(rdev); + if (r) + return r; return 0; }