From fe251e2fffa1ebc17c8e6e895b0374ae4e732fa5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:36:43 -0400 Subject: [PATCH] drm/radeon/kms/evergreen: setup and enable the CP The command processor (CP) fetches command buffers and feeds the GPU. This patch requires the evergreen family me and pfp ucode files. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 117 ++++++++++++++++++++++----- drivers/gpu/drm/radeon/evergreend.h | 2 + drivers/gpu/drm/radeon/r600.c | 47 +++++++++-- drivers/gpu/drm/radeon/radeon.h | 4 + drivers/gpu/drm/radeon/radeon_asic.c | 6 +- drivers/gpu/drm/radeon/rv770.c | 10 ++- 6 files changed, 154 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 26b219bb1388..57fe569682df 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -32,6 +32,9 @@ #include "avivod.h" #include "evergreen_reg.h" +#define EVERGREEN_PFP_UCODE_SIZE 1120 +#define EVERGREEN_PM4_UCODE_SIZE 1376 + static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); @@ -418,23 +421,91 @@ static void evergreen_mc_program(struct radeon_device *rdev) rv515_vga_render_disable(rdev); } -#if 0 /* * CP. */ -static void evergreen_cp_stop(struct radeon_device *rdev) -{ - /* XXX */ -} - static int evergreen_cp_load_microcode(struct radeon_device *rdev) { - /* XXX */ + const __be32 *fw_data; + int i; + + if (!rdev->me_fw || !rdev->pfp_fw) + return -EINVAL; + r700_cp_stop(rdev); + WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0)); + + fw_data = (const __be32 *)rdev->pfp_fw->data; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < EVERGREEN_PFP_UCODE_SIZE; i++) + WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, 0); + + fw_data = (const __be32 *)rdev->me_fw->data; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < EVERGREEN_PM4_UCODE_SIZE; i++) + WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); + + WREG32(CP_PFP_UCODE_ADDR, 0); + WREG32(CP_ME_RAM_WADDR, 0); + WREG32(CP_ME_RAM_RADDR, 0); return 0; } + +int evergreen_cp_resume(struct radeon_device *rdev) +{ + u32 tmp; + u32 rb_bufsz; + int r; + + /* Reset cp; if cp is reset, then PA, SH, VGT also need to be reset */ + WREG32(GRBM_SOFT_RESET, (SOFT_RESET_CP | + SOFT_RESET_PA | + SOFT_RESET_SH | + SOFT_RESET_VGT | + SOFT_RESET_SX)); + RREG32(GRBM_SOFT_RESET); + mdelay(15); + WREG32(GRBM_SOFT_RESET, 0); + RREG32(GRBM_SOFT_RESET); + + /* Set ring buffer size */ + rb_bufsz = drm_order(rdev->cp.ring_size / 8); + tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; +#ifdef __BIG_ENDIAN + tmp |= BUF_SWAP_32BIT; #endif + WREG32(CP_RB_CNTL, tmp); + WREG32(CP_SEM_WAIT_TIMER, 0x4); + + /* Set the write pointer delay */ + WREG32(CP_RB_WPTR_DELAY, 0); + + /* Initialize the ring buffer's read and write pointers */ + WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA); + WREG32(CP_RB_RPTR_WR, 0); + WREG32(CP_RB_WPTR, 0); + WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF); + WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr)); + mdelay(1); + WREG32(CP_RB_CNTL, tmp); + + WREG32(CP_RB_BASE, rdev->cp.gpu_addr >> 8); + WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); + + rdev->cp.rptr = RREG32(CP_RB_RPTR); + rdev->cp.wptr = RREG32(CP_RB_WPTR); + + r600_cp_start(rdev); + rdev->cp.ready = true; + r = radeon_ring_test(rdev); + if (r) { + rdev->cp.ready = false; + return r; + } + return 0; +} /* * Core functions @@ -1138,15 +1209,15 @@ static int evergreen_startup(struct radeon_device *rdev) { int r; -#if 0 - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + /* XXX until interrupts are supported */ + if (!rdev->me_fw || !rdev->pfp_fw /*|| !rdev->rlc_fw*/) { r = r600_init_microcode(rdev); if (r) { DRM_ERROR("Failed to load firmware!\n"); return r; } } -#endif + evergreen_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { evergreen_agp_enable(rdev); @@ -1184,6 +1255,7 @@ static int evergreen_startup(struct radeon_device *rdev) return r; } r600_irq_set(rdev); +#endif r = radeon_ring_init(rdev, rdev->cp.ring_size); if (r) @@ -1191,12 +1263,12 @@ static int evergreen_startup(struct radeon_device *rdev) r = evergreen_cp_load_microcode(rdev); if (r) return r; - r = r600_cp_resume(rdev); + r = evergreen_cp_resume(rdev); if (r) return r; /* write back buffer are not vital so don't worry about failure */ r600_wb_enable(rdev); -#endif + return 0; } @@ -1221,13 +1293,13 @@ int evergreen_resume(struct radeon_device *rdev) DRM_ERROR("r600 startup failed on resume\n"); return r; } -#if 0 + r = r600_ib_test(rdev); if (r) { DRM_ERROR("radeon: failled testing IB (%d).\n", r); return r; } -#endif + return r; } @@ -1236,12 +1308,11 @@ int evergreen_suspend(struct radeon_device *rdev) { #if 0 int r; - +#endif /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; r600_wb_disable(rdev); -#endif evergreen_pcie_gart_disable(rdev); #if 0 @@ -1348,10 +1419,10 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_irq_kms_init(rdev); if (r) return r; - +#endif rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); - +#if 0 rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); #endif @@ -1362,9 +1433,13 @@ int evergreen_init(struct radeon_device *rdev) rdev->accel_working = false; r = evergreen_startup(rdev); if (r) { - evergreen_suspend(rdev); - /*r600_wb_fini(rdev);*/ - /*radeon_ring_fini(rdev);*/ + dev_err(rdev->dev, "disabling GPU acceleration\n"); + r700_cp_fini(rdev); + r600_wb_fini(rdev); +#if 0 + r600_irq_fini(rdev); + radeon_irq_kms_fini(rdev); +#endif evergreen_pcie_gart_fini(rdev); rdev->accel_working = false; } diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index effe335356c7..10e9768534da 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -89,6 +89,7 @@ #define CP_QUEUE_THRESHOLDS 0x8760 #define ROQ_IB1_START(x) ((x) << 0) #define ROQ_IB2_START(x) ((x) << 8) +#define CP_RB_BASE 0xC100 #define CP_RB_CNTL 0xC104 #define RB_BUFSZ(x) ((x) << 0) #define RB_BLKSZ(x) ((x) << 8) @@ -104,6 +105,7 @@ #define CP_RB_WPTR_ADDR_HI 0xC11C #define CP_RB_WPTR_DELAY 0x8704 #define CP_SEM_WAIT_TIMER 0x85BC +#define CP_DEBUG 0xC1FC #define GC_USER_SHADER_PIPE_CONFIG 0x8954 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 13c9cc34231d..4b0225715b93 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -43,6 +43,8 @@ #define R700_PFP_UCODE_SIZE 848 #define R700_PM4_UCODE_SIZE 1360 #define R700_RLC_UCODE_SIZE 1024 +#define EVERGREEN_PFP_UCODE_SIZE 1120 +#define EVERGREEN_PM4_UCODE_SIZE 1376 /* Firmware Names */ MODULE_FIRMWARE("radeon/R600_pfp.bin"); @@ -67,6 +69,14 @@ MODULE_FIRMWARE("radeon/RV710_pfp.bin"); MODULE_FIRMWARE("radeon/RV710_me.bin"); MODULE_FIRMWARE("radeon/R600_rlc.bin"); MODULE_FIRMWARE("radeon/R700_rlc.bin"); +MODULE_FIRMWARE("radeon/CEDAR_pfp.bin"); +MODULE_FIRMWARE("radeon/CEDAR_me.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_me.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); +MODULE_FIRMWARE("radeon/CYRPESS_pfp.bin"); +MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); int r600_debugfs_mc_info_init(struct radeon_device *rdev); @@ -1449,10 +1459,31 @@ int r600_init_microcode(struct radeon_device *rdev) chip_name = "RV710"; rlc_chip_name = "R700"; break; + case CHIP_CEDAR: + chip_name = "CEDAR"; + rlc_chip_name = ""; + break; + case CHIP_REDWOOD: + chip_name = "REDWOOD"; + rlc_chip_name = ""; + break; + case CHIP_JUNIPER: + chip_name = "JUNIPER"; + rlc_chip_name = ""; + break; + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + chip_name = "CYPRESS"; + rlc_chip_name = ""; + break; default: BUG(); } - if (rdev->family >= CHIP_RV770) { + if (rdev->family >= CHIP_CEDAR) { + pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4; + me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; + rlc_req_size = 0; + } else if (rdev->family >= CHIP_RV770) { pfp_req_size = R700_PFP_UCODE_SIZE * 4; me_req_size = R700_PM4_UCODE_SIZE * 4; rlc_req_size = R700_RLC_UCODE_SIZE * 4; @@ -1487,6 +1518,8 @@ int r600_init_microcode(struct radeon_device *rdev) err = -EINVAL; } + /* XXX until evergreen interrupts are supported */ + if (rdev->family < CHIP_CEDAR) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); if (err) @@ -1497,6 +1530,7 @@ int r600_init_microcode(struct radeon_device *rdev) rdev->rlc_fw->size, fw_name); err = -EINVAL; } + } out: platform_device_unregister(pdev); @@ -1566,12 +1600,15 @@ int r600_cp_start(struct radeon_device *rdev) } radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5)); radeon_ring_write(rdev, 0x1); - if (rdev->family < CHIP_RV770) { - radeon_ring_write(rdev, 0x3); - radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1); - } else { + if (rdev->family >= CHIP_CEDAR) { + radeon_ring_write(rdev, 0x0); + radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1); + } else if (rdev->family >= CHIP_RV770) { radeon_ring_write(rdev, 0x0); radeon_ring_write(rdev, rdev->config.rv770.max_hw_contexts - 1); + } else { + radeon_ring_write(rdev, 0x3); + radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1); } radeon_ring_write(rdev, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(rdev, 0); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a77a86203996..acf21d7e3cb2 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1300,6 +1300,7 @@ extern void rs690_line_buffer_adjust(struct radeon_device *rdev, extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern bool r600_card_posted(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev); +extern int r600_cp_start(struct radeon_device *rdev); extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_cp_resume(struct radeon_device *rdev); extern void r600_cp_fini(struct radeon_device *rdev); @@ -1340,6 +1341,9 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, uint8_t status_bits, uint8_t category_code); +extern void r700_cp_stop(struct radeon_device *rdev); +extern void r700_cp_fini(struct radeon_device *rdev); + /* evergreen */ struct evergreen_mc_save { u32 vga_control[6]; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index d923e4b234d2..3a576ab805cf 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -635,14 +635,14 @@ static struct radeon_asic evergreen_asic = { .fini = &evergreen_fini, .suspend = &evergreen_suspend, .resume = &evergreen_resume, - .cp_commit = NULL, + .cp_commit = &r600_cp_commit, .gpu_is_lockup = &evergreen_gpu_is_lockup, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, - .ring_test = NULL, - .ring_ib_execute = NULL, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, .irq_set = NULL, .irq_process = NULL, .get_vblank_counter = NULL, diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 2b8a4e170654..2642d2642641 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -236,7 +236,6 @@ void r700_cp_stop(struct radeon_device *rdev) WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT)); } - static int rv770_cp_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; @@ -271,6 +270,11 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev) return 0; } +void r700_cp_fini(struct radeon_device *rdev) +{ + r700_cp_stop(rdev); + radeon_ring_fini(rdev); +} /* * Core functions @@ -1125,7 +1129,7 @@ int rv770_init(struct radeon_device *rdev) r = rv770_startup(rdev); if (r) { dev_err(rdev->dev, "disabling GPU acceleration\n"); - r600_cp_fini(rdev); + r700_cp_fini(rdev); r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); @@ -1159,7 +1163,7 @@ void rv770_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); r600_blit_fini(rdev); - r600_cp_fini(rdev); + r700_cp_fini(rdev); r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); -- 2.39.2