drm/radeon: Add support for RLC init on CIK (v4)

RLC handles the interrupt controller and other tasks
on the GPU.

v2: add documentation
v3: update programming sequence
v4: additional setup

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Alex Deucher 2012-11-09 10:44:08 -05:00
parent f96ab48457
commit f6796caee6
2 changed files with 189 additions and 0 deletions

View file

@ -2777,3 +2777,145 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
radeon_ring_write(ring, 0x0);
}
/*
* RLC
* The RLC is a multi-purpose microengine that handles a
* variety of functions, the most important of which is
* the interrupt controller.
*/
/**
* cik_rlc_stop - stop the RLC ME
*
* @rdev: radeon_device pointer
*
* Halt the RLC ME (MicroEngine) (CIK).
*/
static void cik_rlc_stop(struct radeon_device *rdev)
{
int i, j, k;
u32 mask, tmp;
tmp = RREG32(CP_INT_CNTL_RING0);
tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
WREG32(CP_INT_CNTL_RING0, tmp);
RREG32(CB_CGTT_SCLK_CTRL);
RREG32(CB_CGTT_SCLK_CTRL);
RREG32(CB_CGTT_SCLK_CTRL);
RREG32(CB_CGTT_SCLK_CTRL);
tmp = RREG32(RLC_CGCG_CGLS_CTRL) & 0xfffffffc;
WREG32(RLC_CGCG_CGLS_CTRL, tmp);
WREG32(RLC_CNTL, 0);
for (i = 0; i < rdev->config.cik.max_shader_engines; i++) {
for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) {
cik_select_se_sh(rdev, i, j);
for (k = 0; k < rdev->usec_timeout; k++) {
if (RREG32(RLC_SERDES_CU_MASTER_BUSY) == 0)
break;
udelay(1);
}
}
}
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY;
for (k = 0; k < rdev->usec_timeout; k++) {
if ((RREG32(RLC_SERDES_NONCU_MASTER_BUSY) & mask) == 0)
break;
udelay(1);
}
}
/**
* cik_rlc_start - start the RLC ME
*
* @rdev: radeon_device pointer
*
* Unhalt the RLC ME (MicroEngine) (CIK).
*/
static void cik_rlc_start(struct radeon_device *rdev)
{
u32 tmp;
WREG32(RLC_CNTL, RLC_ENABLE);
tmp = RREG32(CP_INT_CNTL_RING0);
tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
WREG32(CP_INT_CNTL_RING0, tmp);
udelay(50);
}
/**
* cik_rlc_resume - setup the RLC hw
*
* @rdev: radeon_device pointer
*
* Initialize the RLC registers, load the ucode,
* and start the RLC (CIK).
* Returns 0 for success, -EINVAL if the ucode is not available.
*/
static int cik_rlc_resume(struct radeon_device *rdev)
{
u32 i, size;
u32 clear_state_info[3];
const __be32 *fw_data;
if (!rdev->rlc_fw)
return -EINVAL;
switch (rdev->family) {
case CHIP_BONAIRE:
default:
size = BONAIRE_RLC_UCODE_SIZE;
break;
case CHIP_KAVERI:
size = KV_RLC_UCODE_SIZE;
break;
case CHIP_KABINI:
size = KB_RLC_UCODE_SIZE;
break;
}
cik_rlc_stop(rdev);
WREG32(GRBM_SOFT_RESET, SOFT_RESET_RLC);
RREG32(GRBM_SOFT_RESET);
udelay(50);
WREG32(GRBM_SOFT_RESET, 0);
RREG32(GRBM_SOFT_RESET);
udelay(50);
WREG32(RLC_LB_CNTR_INIT, 0);
WREG32(RLC_LB_CNTR_MAX, 0x00008000);
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
WREG32(RLC_LB_PARAMS, 0x00600408);
WREG32(RLC_LB_CNTL, 0x80000004);
WREG32(RLC_MC_CNTL, 0);
WREG32(RLC_UCODE_CNTL, 0);
fw_data = (const __be32 *)rdev->rlc_fw->data;
WREG32(RLC_GPM_UCODE_ADDR, 0);
for (i = 0; i < size; i++)
WREG32(RLC_GPM_UCODE_DATA, be32_to_cpup(fw_data++));
WREG32(RLC_GPM_UCODE_ADDR, 0);
/* XXX */
clear_state_info[0] = 0;//upper_32_bits(rdev->rlc.save_restore_gpu_addr);
clear_state_info[1] = 0;//rdev->rlc.save_restore_gpu_addr;
clear_state_info[2] = 0;//cik_default_size;
WREG32(RLC_GPM_SCRATCH_ADDR, 0x3d);
for (i = 0; i < 3; i++)
WREG32(RLC_GPM_SCRATCH_DATA, clear_state_info[i]);
WREG32(RLC_DRIVER_DMA_STATUS, 0);
cik_rlc_start(rdev);
return 0;
}

View file

@ -497,10 +497,55 @@
#define CP_MEC_ME2_UCODE_ADDR 0xC178
#define CP_MEC_ME2_UCODE_DATA 0xC17C
#define CP_INT_CNTL_RING0 0xC1A8
# define CNTX_BUSY_INT_ENABLE (1 << 19)
# define CNTX_EMPTY_INT_ENABLE (1 << 20)
# define PRIV_INSTR_INT_ENABLE (1 << 22)
# define PRIV_REG_INT_ENABLE (1 << 23)
# define TIME_STAMP_INT_ENABLE (1 << 26)
# define CP_RINGID2_INT_ENABLE (1 << 29)
# define CP_RINGID1_INT_ENABLE (1 << 30)
# define CP_RINGID0_INT_ENABLE (1 << 31)
#define CP_MAX_CONTEXT 0xC2B8
#define CP_RB0_BASE_HI 0xC2C4
#define RLC_CNTL 0xC300
# define RLC_ENABLE (1 << 0)
#define RLC_MC_CNTL 0xC30C
#define RLC_LB_CNTR_MAX 0xC348
#define RLC_LB_CNTL 0xC364
#define RLC_LB_CNTR_INIT 0xC36C
#define RLC_SAVE_AND_RESTORE_BASE 0xC374
#define RLC_DRIVER_DMA_STATUS 0xC378
#define RLC_GPM_UCODE_ADDR 0xC388
#define RLC_GPM_UCODE_DATA 0xC38C
#define RLC_UCODE_CNTL 0xC39C
#define RLC_CGCG_CGLS_CTRL 0xC424
#define RLC_LB_INIT_CU_MASK 0xC43C
#define RLC_LB_PARAMS 0xC444
#define RLC_SERDES_CU_MASTER_BUSY 0xC484
#define RLC_SERDES_NONCU_MASTER_BUSY 0xC488
# define SE_MASTER_BUSY_MASK 0x0000ffff
# define GC_MASTER_BUSY (1 << 16)
# define TC0_MASTER_BUSY (1 << 17)
# define TC1_MASTER_BUSY (1 << 18)
#define RLC_GPM_SCRATCH_ADDR 0xC4B0
#define RLC_GPM_SCRATCH_DATA 0xC4B4
#define PA_SC_RASTER_CONFIG 0x28350
# define RASTER_CONFIG_RB_MAP_0 0
# define RASTER_CONFIG_RB_MAP_1 1
@ -599,6 +644,8 @@
#define TCC_DISABLE_MASK 0xFFFF0000
#define TCC_DISABLE_SHIFT 16
#define CB_CGTT_SCLK_CTRL 0x3c2a0
/*
* PM4
*/