drm/amd/amdgpu: add gfx clock gating support for Fiji.

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Jammy Zhou <Jammy.Zhou@amd.com>
Signed-off-by: Eric Huang <JinHuiEric.Huang@amd.com>
This commit is contained in:
Eric Huang 2015-11-10 10:50:25 -05:00 committed by Alex Deucher
parent 0104aa21a9
commit 6e378858df
1 changed files with 254 additions and 0 deletions

View File

@ -66,6 +66,27 @@
#define MACRO_TILE_ASPECT(x) ((x) << GB_MACROTILE_MODE0__MACRO_TILE_ASPECT__SHIFT) #define MACRO_TILE_ASPECT(x) ((x) << GB_MACROTILE_MODE0__MACRO_TILE_ASPECT__SHIFT)
#define NUM_BANKS(x) ((x) << GB_MACROTILE_MODE0__NUM_BANKS__SHIFT) #define NUM_BANKS(x) ((x) << GB_MACROTILE_MODE0__NUM_BANKS__SHIFT)
#define RLC_CGTT_MGCG_OVERRIDE__CPF_MASK 0x00000001L
#define RLC_CGTT_MGCG_OVERRIDE__RLC_MASK 0x00000002L
#define RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK 0x00000004L
#define RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK 0x00000008L
#define RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK 0x00000010L
#define RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK 0x00000020L
/* BPM SERDES CMD */
#define SET_BPM_SERDES_CMD 1
#define CLE_BPM_SERDES_CMD 0
/* BPM Register Address*/
enum {
BPM_REG_CGLS_EN = 0, /* Enable/Disable CGLS */
BPM_REG_CGLS_ON, /* ON/OFF CGLS: shall be controlled by RLC FW */
BPM_REG_CGCG_OVERRIDE, /* Set/Clear CGCG Override */
BPM_REG_MGCG_OVERRIDE, /* Set/Clear MGCG Override */
BPM_REG_FGCG_OVERRIDE, /* Set/Clear FGCG Override */
BPM_REG_FGCG_MAX
};
MODULE_FIRMWARE("amdgpu/carrizo_ce.bin"); MODULE_FIRMWARE("amdgpu/carrizo_ce.bin");
MODULE_FIRMWARE("amdgpu/carrizo_pfp.bin"); MODULE_FIRMWARE("amdgpu/carrizo_pfp.bin");
MODULE_FIRMWARE("amdgpu/carrizo_me.bin"); MODULE_FIRMWARE("amdgpu/carrizo_me.bin");
@ -4301,9 +4322,242 @@ static int gfx_v8_0_set_powergating_state(void *handle,
return 0; return 0;
} }
static void fiji_send_serdes_cmd(struct amdgpu_device *adev,
uint32_t reg_addr, uint32_t cmd)
{
uint32_t data;
gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff);
WREG32(mmRLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
WREG32(mmRLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
data = RREG32(mmRLC_SERDES_WR_CTRL);
data &= ~(RLC_SERDES_WR_CTRL__WRITE_COMMAND_MASK |
RLC_SERDES_WR_CTRL__READ_COMMAND_MASK |
RLC_SERDES_WR_CTRL__P1_SELECT_MASK |
RLC_SERDES_WR_CTRL__P2_SELECT_MASK |
RLC_SERDES_WR_CTRL__RDDATA_RESET_MASK |
RLC_SERDES_WR_CTRL__POWER_DOWN_MASK |
RLC_SERDES_WR_CTRL__POWER_UP_MASK |
RLC_SERDES_WR_CTRL__SHORT_FORMAT_MASK |
RLC_SERDES_WR_CTRL__BPM_DATA_MASK |
RLC_SERDES_WR_CTRL__REG_ADDR_MASK |
RLC_SERDES_WR_CTRL__SRBM_OVERRIDE_MASK);
data |= (RLC_SERDES_WR_CTRL__RSVD_BPM_ADDR_MASK |
(cmd << RLC_SERDES_WR_CTRL__BPM_DATA__SHIFT) |
(reg_addr << RLC_SERDES_WR_CTRL__REG_ADDR__SHIFT) |
(0xff << RLC_SERDES_WR_CTRL__BPM_ADDR__SHIFT));
WREG32(mmRLC_SERDES_WR_CTRL, data);
}
static void fiji_update_medium_grain_clock_gating(struct amdgpu_device *adev,
bool enable)
{
uint32_t temp, data;
/* It is disabled by HW by default */
if (enable) {
/* 1 - RLC memory Light sleep */
temp = data = RREG32(mmRLC_MEM_SLP_CNTL);
data |= RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
if (temp != data)
WREG32(mmRLC_MEM_SLP_CNTL, data);
/* 2 - CP memory Light sleep */
temp = data = RREG32(mmCP_MEM_SLP_CNTL);
data |= CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
if (temp != data)
WREG32(mmCP_MEM_SLP_CNTL, data);
/* 3 - RLC_CGTT_MGCG_OVERRIDE */
temp = data = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
data &= ~(RLC_CGTT_MGCG_OVERRIDE__CPF_MASK |
RLC_CGTT_MGCG_OVERRIDE__RLC_MASK |
RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK |
RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK);
if (temp != data)
WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data);
/* 4 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* 5 - clear mgcg override */
fiji_send_serdes_cmd(adev, BPM_REG_MGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
/* 6 - Enable CGTS(Tree Shade) MGCG /MGLS */
temp = data = RREG32(mmCGTS_SM_CTRL_REG);
data &= ~(CGTS_SM_CTRL_REG__SM_MODE_MASK);
data |= (0x2 << CGTS_SM_CTRL_REG__SM_MODE__SHIFT);
data |= CGTS_SM_CTRL_REG__SM_MODE_ENABLE_MASK;
data &= ~CGTS_SM_CTRL_REG__OVERRIDE_MASK;
data &= ~CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK;
data |= CGTS_SM_CTRL_REG__ON_MONITOR_ADD_EN_MASK;
data |= (0x96 << CGTS_SM_CTRL_REG__ON_MONITOR_ADD__SHIFT);
if (temp != data)
WREG32(mmCGTS_SM_CTRL_REG, data);
udelay(50);
/* 7 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
} else {
/* 1 - MGCG_OVERRIDE[0] for CP and MGCG_OVERRIDE[1] for RLC */
temp = data = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
data |= (RLC_CGTT_MGCG_OVERRIDE__CPF_MASK |
RLC_CGTT_MGCG_OVERRIDE__RLC_MASK |
RLC_CGTT_MGCG_OVERRIDE__MGCG_MASK |
RLC_CGTT_MGCG_OVERRIDE__GRBM_MASK);
if (temp != data)
WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data);
/* 2 - disable MGLS in RLC */
data = RREG32(mmRLC_MEM_SLP_CNTL);
if (data & RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK) {
data &= ~RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
WREG32(mmRLC_MEM_SLP_CNTL, data);
}
/* 3 - disable MGLS in CP */
data = RREG32(mmCP_MEM_SLP_CNTL);
if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK) {
data &= ~CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
WREG32(mmCP_MEM_SLP_CNTL, data);
}
/* 4 - Disable CGTS(Tree Shade) MGCG and MGLS */
temp = data = RREG32(mmCGTS_SM_CTRL_REG);
data |= (CGTS_SM_CTRL_REG__OVERRIDE_MASK |
CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK);
if (temp != data)
WREG32(mmCGTS_SM_CTRL_REG, data);
/* 5 - wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* 6 - set mgcg override */
fiji_send_serdes_cmd(adev, BPM_REG_MGCG_OVERRIDE, SET_BPM_SERDES_CMD);
udelay(50);
/* 7- wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
}
}
static void fiji_update_coarse_grain_clock_gating(struct amdgpu_device *adev,
bool enable)
{
uint32_t temp, temp1, data, data1;
temp = data = RREG32(mmRLC_CGCG_CGLS_CTRL);
if (enable) {
/* 1 enable cntx_empty_int_enable/cntx_busy_int_enable/
* Cmp_busy/GFX_Idle interrupts
*/
gfx_v8_0_enable_gui_idle_interrupt(adev, true);
temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK;
if (temp1 != data1)
WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
/* 2 wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* 3 - clear cgcg override */
fiji_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* 4 - write cmd to set CGLS */
fiji_send_serdes_cmd(adev, BPM_REG_CGLS_EN, SET_BPM_SERDES_CMD);
/* 5 - enable cgcg */
data |= RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
/* enable cgls*/
data |= RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK;
temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK;
if (temp1 != data1)
WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
if (temp != data)
WREG32(mmRLC_CGCG_CGLS_CTRL, data);
} else {
/* disable cntx_empty_int_enable & GFX Idle interrupt */
gfx_v8_0_enable_gui_idle_interrupt(adev, false);
/* TEST CGCG */
temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
data1 |= (RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK |
RLC_CGTT_MGCG_OVERRIDE__CGLS_MASK);
if (temp1 != data1)
WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
/* read gfx register to wake up cgcg */
RREG32(mmCB_CGTT_SCLK_CTRL);
RREG32(mmCB_CGTT_SCLK_CTRL);
RREG32(mmCB_CGTT_SCLK_CTRL);
RREG32(mmCB_CGTT_SCLK_CTRL);
/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* write cmd to Set CGCG Overrride */
fiji_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, SET_BPM_SERDES_CMD);
/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
gfx_v8_0_wait_for_rlc_serdes(adev);
/* write cmd to Clear CGLS */
fiji_send_serdes_cmd(adev, BPM_REG_CGLS_EN, CLE_BPM_SERDES_CMD);
/* disable cgcg, cgls should be disabled too. */
data &= ~(RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK |
RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
if (temp != data)
WREG32(mmRLC_CGCG_CGLS_CTRL, data);
}
}
static int fiji_update_gfx_clock_gating(struct amdgpu_device *adev,
bool enable)
{
if (enable) {
/* CGCG/CGLS should be enabled after MGCG/MGLS/TS(CG/LS)
* === MGCG + MGLS + TS(CG/LS) ===
*/
fiji_update_medium_grain_clock_gating(adev, enable);
fiji_update_coarse_grain_clock_gating(adev, enable);
} else {
/* CGCG/CGLS should be disabled before MGCG/MGLS/TS(CG/LS)
* === CGCG + CGLS ===
*/
fiji_update_coarse_grain_clock_gating(adev, enable);
fiji_update_medium_grain_clock_gating(adev, enable);
}
return 0;
}
static int gfx_v8_0_set_clockgating_state(void *handle, static int gfx_v8_0_set_clockgating_state(void *handle,
enum amd_clockgating_state state) enum amd_clockgating_state state)
{ {
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
switch (adev->asic_type) {
case CHIP_FIJI:
fiji_update_gfx_clock_gating(adev,
state == AMD_CG_STATE_GATE ? true : false);
break;
default:
break;
}
return 0; return 0;
} }