diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/soc15.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/soc15.c | 173 | 
1 files changed, 163 insertions, 10 deletions
| diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 8849b74078d6..99ebcf29dcb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -43,6 +43,10 @@  #include "hdp/hdp_4_0_sh_mask.h"  #include "smuio/smuio_9_0_offset.h"  #include "smuio/smuio_9_0_sh_mask.h" +#include "nbio/nbio_7_0_default.h" +#include "nbio/nbio_7_0_sh_mask.h" +#include "nbio/nbio_7_0_smn.h" +#include "mp/mp_9_0_offset.h"  #include "soc15.h"  #include "soc15_common.h" @@ -385,14 +389,13 @@ void soc15_program_register_sequence(struct amdgpu_device *adev,  } - -static int soc15_asic_reset(struct amdgpu_device *adev) +static int soc15_asic_mode1_reset(struct amdgpu_device *adev)  {  	u32 i;  	amdgpu_atombios_scratch_regs_engine_hung(adev, true); -	dev_info(adev->dev, "GPU reset\n"); +	dev_info(adev->dev, "GPU mode1 reset\n");  	/* disable BM */  	pci_clear_master(adev->pdev); @@ -417,6 +420,63 @@ static int soc15_asic_reset(struct amdgpu_device *adev)  	return 0;  } +static int soc15_asic_get_baco_capability(struct amdgpu_device *adev, bool *cap) +{ +	void *pp_handle = adev->powerplay.pp_handle; +	const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + +	if (!pp_funcs || !pp_funcs->get_asic_baco_capability) { +		*cap = false; +		return -ENOENT; +	} + +	return pp_funcs->get_asic_baco_capability(pp_handle, cap); +} + +static int soc15_asic_baco_reset(struct amdgpu_device *adev) +{ +	void *pp_handle = adev->powerplay.pp_handle; +	const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + +	if (!pp_funcs ||!pp_funcs->get_asic_baco_state ||!pp_funcs->set_asic_baco_state) +		return -ENOENT; + +	/* enter BACO state */ +	if (pp_funcs->set_asic_baco_state(pp_handle, 1)) +		return -EIO; + +	/* exit BACO state */ +	if (pp_funcs->set_asic_baco_state(pp_handle, 0)) +		return -EIO; + +	dev_info(adev->dev, "GPU BACO reset\n"); + +	return 0; +} + +static int soc15_asic_reset(struct amdgpu_device *adev) +{ +	int ret; +	bool baco_reset; + +	switch (adev->asic_type) { +	case CHIP_VEGA10: +	case CHIP_VEGA20: +		soc15_asic_get_baco_capability(adev, &baco_reset); +		break; +	default: +		baco_reset = false; +		break; +	} + +	if (baco_reset) +		ret = soc15_asic_baco_reset(adev); +	else +		ret = soc15_asic_mode1_reset(adev); + +	return ret; +} +  /*static int soc15_set_uvd_clock(struct amdgpu_device *adev, u32 clock,  			u32 cntl_reg, u32 status_reg)  { @@ -535,10 +595,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)  		amdgpu_device_ip_block_add(adev, &vega10_common_ip_block);  		amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block);  		amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); -		if (adev->asic_type == CHIP_VEGA20) -			amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); -		else -			amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block); +		if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) { +			if (adev->asic_type == CHIP_VEGA20) +				amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block); +			else +				amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block); +		}  		amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block);  		amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block);  		if (!amdgpu_sriov_vf(adev)) @@ -560,7 +622,8 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)  		amdgpu_device_ip_block_add(adev, &vega10_common_ip_block);  		amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block);  		amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block); -		amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block); +		if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) +			amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block);  		amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block);  		amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block);  		amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); @@ -601,6 +664,68 @@ static bool soc15_need_full_reset(struct amdgpu_device *adev)  	/* change this when we implement soft reset */  	return true;  } +static void soc15_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0, +				 uint64_t *count1) +{ +	uint32_t perfctr = 0; +	uint64_t cnt0_of, cnt1_of; +	int tmp; + +	/* This reports 0 on APUs, so return to avoid writing/reading registers +	 * that may or may not be different from their GPU counterparts +	 */ +	 if (adev->flags & AMD_IS_APU) +		 return; + +	/* Set the 2 events that we wish to watch, defined above */ +	/* Reg 40 is # received msgs, Reg 104 is # of posted requests sent */ +	perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT0_SEL, 40); +	perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT1_SEL, 104); + +	/* Write to enable desired perf counters */ +	WREG32_PCIE(smnPCIE_PERF_CNTL_TXCLK, perfctr); +	/* Zero out and enable the perf counters +	 * Write 0x5: +	 * Bit 0 = Start all counters(1) +	 * Bit 2 = Global counter reset enable(1) +	 */ +	WREG32_PCIE(smnPCIE_PERF_COUNT_CNTL, 0x00000005); + +	msleep(1000); + +	/* Load the shadow and disable the perf counters +	 * Write 0x2: +	 * Bit 0 = Stop counters(0) +	 * Bit 1 = Load the shadow counters(1) +	 */ +	WREG32_PCIE(smnPCIE_PERF_COUNT_CNTL, 0x00000002); + +	/* Read register values to get any >32bit overflow */ +	tmp = RREG32_PCIE(smnPCIE_PERF_CNTL_TXCLK); +	cnt0_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER0_UPPER); +	cnt1_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER1_UPPER); + +	/* Get the values and add the overflow */ +	*count0 = RREG32_PCIE(smnPCIE_PERF_COUNT0_TXCLK) | (cnt0_of << 32); +	*count1 = RREG32_PCIE(smnPCIE_PERF_COUNT1_TXCLK) | (cnt1_of << 32); +} + +static bool soc15_need_reset_on_init(struct amdgpu_device *adev) +{ +	u32 sol_reg; + +	if (adev->flags & AMD_IS_APU) +		return false; + +	/* Check sOS sign of life register to confirm sys driver and sOS +	 * are already been loaded. +	 */ +	sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); +	if (sol_reg) +		return true; + +	return false; +}  static const struct amdgpu_asic_funcs soc15_asic_funcs =  { @@ -617,6 +742,8 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs =  	.invalidate_hdp = &soc15_invalidate_hdp,  	.need_full_reset = &soc15_need_full_reset,  	.init_doorbell_index = &vega10_doorbell_index_init, +	.get_pcie_usage = &soc15_get_pcie_usage, +	.need_reset_on_init = &soc15_need_reset_on_init,  };  static const struct amdgpu_asic_funcs vega20_asic_funcs = @@ -634,6 +761,8 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs =  	.invalidate_hdp = &soc15_invalidate_hdp,  	.need_full_reset = &soc15_need_full_reset,  	.init_doorbell_index = &vega20_doorbell_index_init, +	.get_pcie_usage = &soc15_get_pcie_usage, +	.need_reset_on_init = &soc15_need_reset_on_init,  };  static int soc15_common_early_init(void *handle) @@ -729,11 +858,13 @@ static int soc15_common_early_init(void *handle)  	case CHIP_RAVEN:  		adev->asic_funcs = &soc15_asic_funcs;  		if (adev->rev_id >= 0x8) -			adev->external_rev_id = adev->rev_id + 0x81; +			adev->external_rev_id = adev->rev_id + 0x79;  		else if (adev->pdev->device == 0x15d8)  			adev->external_rev_id = adev->rev_id + 0x41; +		else if (adev->rev_id == 1) +			adev->external_rev_id = adev->rev_id + 0x20;  		else -			adev->external_rev_id = 0x1; +			adev->external_rev_id = adev->rev_id + 0x01;  		if (adev->rev_id >= 0x8) {  			adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG | @@ -840,6 +971,22 @@ static int soc15_common_sw_fini(void *handle)  	return 0;  } +static void soc15_doorbell_range_init(struct amdgpu_device *adev) +{ +	int i; +	struct amdgpu_ring *ring; + +	for (i = 0; i < adev->sdma.num_instances; i++) { +		ring = &adev->sdma.instance[i].ring; +		adev->nbio_funcs->sdma_doorbell_range(adev, i, +			ring->use_doorbell, ring->doorbell_index, +			adev->doorbell_index.sdma_doorbell_range); +	} + +	adev->nbio_funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell, +						adev->irq.ih.doorbell_index); +} +  static int soc15_common_hw_init(void *handle)  {  	struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -852,6 +999,12 @@ static int soc15_common_hw_init(void *handle)  	adev->nbio_funcs->init_registers(adev);  	/* enable the doorbell aperture */  	soc15_enable_doorbell_aperture(adev, true); +	/* HW doorbell routing policy: doorbell writing not +	 * in SDMA/IH/MM/ACV range will be routed to CP. So +	 * we need to init SDMA/IH/MM/ACV doorbell range prior +	 * to CP ip block init and ring test. +	 */ +	soc15_doorbell_range_init(adev);  	return 0;  } | 
