Skip to content

Commit

Permalink
drm/radeon/kms/evergreen: setup and enable the CP
Browse files Browse the repository at this point in the history
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 <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Alex Deucher authored and Dave Airlie committed Apr 9, 2010
1 parent 32fcdbf commit fe251e2
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 32 deletions.
117 changes: 96 additions & 21 deletions drivers/gpu/drm/radeon/evergreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1184,19 +1255,20 @@ 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)
return r;
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;
}

Expand All @@ -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;

}
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/radeon/evergreend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
47 changes: 42 additions & 5 deletions drivers/gpu/drm/radeon/r600.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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];
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/radeon/radeon_asic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 7 additions & 3 deletions drivers/gpu/drm/radeon/rv770.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit fe251e2

Please sign in to comment.