drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
Extension
.c
Size
28881 bytes
Lines
1050
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (remainder >= arg2_value) {
				res_value |= 1;
				remainder -= arg2_value;
			}
		} while (--i != 0);
	}

	/* round up LSB */
	{
		uint16_t summand = (remainder << 1) >= arg2_value;

		if ((res_value + summand) > 32767 /* SHRT_MAX */)
			return 0;

		res_value += summand;
	}

	return res_value;
}

static uint16_t vpe_internal_get_pratio(uint16_t from_frequency, uint16_t to_frequency)
{
	uint16_t pratio = vpe_u1_8_from_fraction(from_frequency, to_frequency);

	if (GET_PRATIO_INTEGER_PART(pratio) > 1)
		pratio = 0;

	return pratio;
}

/*
 * VPE has 4 DPM levels from level 0 (lowerest) to 3 (highest),
 * VPE FW will dynamically decide which level should be used according to current loading.
 *
 * Get VPE and SOC clocks from PM, and select the appropriate four clock values,
 * calculate the ratios of adjusting from one clock to another.
 * The VPE FW can then request the appropriate frequency from the PMFW.
 */
int amdgpu_vpe_configure_dpm(struct amdgpu_vpe *vpe)
{
	struct amdgpu_device *adev = vpe->ring.adev;
	uint32_t dpm_ctl;

	if (adev->pm.dpm_enabled) {
		struct dpm_clocks clock_table = { 0 };
		struct dpm_clock *VPEClks;
		struct dpm_clock *SOCClks;
		uint32_t idx;
		uint32_t vpeclk_enalbled_num = 0;
		uint32_t pratio_vmax_vnorm = 0, pratio_vnorm_vmid = 0, pratio_vmid_vmin = 0;
		uint16_t pratio_vmin_freq = 0, pratio_vmid_freq = 0, pratio_vnorm_freq = 0, pratio_vmax_freq = 0;

		dpm_ctl = RREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_enable));
		dpm_ctl |= 1; /* DPM enablement */
		WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_enable), dpm_ctl);

		/* Get VPECLK and SOCCLK */
		if (amdgpu_dpm_get_dpm_clock_table(adev, &clock_table)) {
			dev_dbg(adev->dev, "%s: get clock failed!\n", __func__);
			goto disable_dpm;
		}

		SOCClks = clock_table.SocClocks;
		VPEClks = clock_table.VPEClocks;

		/* Comfirm enabled vpe clk num
		 * Enabled VPE clocks are ordered from low to high in VPEClks
		 * The highest valid clock index+1 is the number of VPEClks
		 */
		for (idx = PP_SMU_NUM_VPECLK_DPM_LEVELS; idx && !vpeclk_enalbled_num; idx--)
			if (VPEClks[idx-1].Freq)
				vpeclk_enalbled_num = idx;

		/* vpe dpm only cares 4 levels. */
		for (idx = 0; idx < VPE_MAX_DPM_LEVEL; idx++) {
			uint32_t soc_dpm_level;
			uint32_t min_freq;

			if (idx == 0)
				soc_dpm_level = 0;
			else
				soc_dpm_level = (idx * 2) + 1;

			/* clamp the max level */
			if (soc_dpm_level > vpeclk_enalbled_num - 1)
				soc_dpm_level = vpeclk_enalbled_num - 1;

			min_freq = (SOCClks[soc_dpm_level].Freq < VPEClks[soc_dpm_level].Freq) ?
				   SOCClks[soc_dpm_level].Freq : VPEClks[soc_dpm_level].Freq;

Annotation

Implementation Notes