drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c
Extension
.c
Size
9416 bytes
Lines
202
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 (!fclk_fine_grained) {
			min_table->dram_bw_table.entries[i].min_fclk_khz = round_up_to_quantized_values(min_table->dram_bw_table.entries[i].min_fclk_khz, soc_bb->clk_table.fclk.clk_values_khz, soc_bb->clk_table.fclk.num_clk_values);
		}
	}
	min_table->dram_bw_table.entries[0].min_fclk_khz /= 2;

	// Clamp to minimums and maximums
	for (i = 0; i < (int)min_table->dram_bw_table.num_entries; i++) {
		if (min_table->dram_bw_table.entries[i].min_dcfclk_khz < min_dcfclk_khz)
			min_table->dram_bw_table.entries[i].min_dcfclk_khz = min_dcfclk_khz;

		if (min_table->dram_bw_table.entries[i].min_fclk_khz < min_fclk_khz)
			min_table->dram_bw_table.entries[i].min_fclk_khz = min_fclk_khz;

		if (soc_bb->max_fclk_for_uclk_dpm_khz > 0 &&
			min_table->dram_bw_table.entries[i].min_fclk_khz > soc_bb->max_fclk_for_uclk_dpm_khz)
			min_table->dram_bw_table.entries[i].min_fclk_khz = soc_bb->max_fclk_for_uclk_dpm_khz;

		min_table->dram_bw_table.entries[i].min_dcfclk_khz =
			min_table->dram_bw_table.entries[i].min_fclk_khz *
			soc_bb->qos_parameters.derate_table.system_active_urgent.fclk_derate_percent / soc_bb->qos_parameters.derate_table.system_active_urgent.dcfclk_derate_percent;

		min_table->dram_bw_table.entries[i].min_dcfclk_khz =
			min_table->dram_bw_table.entries[i].min_dcfclk_khz * soc_bb->fabric_datapath_to_dcn_data_return_bytes / soc_bb->return_bus_width_bytes;

		if (!dcfclk_fine_grained) {
			min_table->dram_bw_table.entries[i].min_dcfclk_khz = round_up_to_quantized_values(min_table->dram_bw_table.entries[i].min_dcfclk_khz, soc_bb->clk_table.dcfclk.clk_values_khz, soc_bb->clk_table.dcfclk.num_clk_values);
		}
	}

	// Prune states which are invalid (some clocks exceed maximum)
	for (i = 0; i < (int)min_table->dram_bw_table.num_entries; i++) {
		if (min_table->dram_bw_table.entries[i].min_dcfclk_khz > min_table->max_clocks_khz.dcfclk ||
			min_table->dram_bw_table.entries[i].min_fclk_khz > min_table->max_clocks_khz.fclk) {
			min_table->dram_bw_table.num_entries = i;
			break;
		}
	}

	// Prune duplicate states
	for (i = 0; i < (int)min_table->dram_bw_table.num_entries - 1; i++) {
		if (min_table->dram_bw_table.entries[i].min_dcfclk_khz == min_table->dram_bw_table.entries[i + 1].min_dcfclk_khz &&
			min_table->dram_bw_table.entries[i].min_fclk_khz == min_table->dram_bw_table.entries[i + 1].min_fclk_khz &&
			min_table->dram_bw_table.entries[i].pre_derate_dram_bw_kbps == min_table->dram_bw_table.entries[i + 1].pre_derate_dram_bw_kbps) {

			// i + 1 is the same state as i, so shift everything
			for (j = i + 1; j < min_table->dram_bw_table.num_entries; j++) {
				min_table->dram_bw_table.entries[j].min_dcfclk_khz = min_table->dram_bw_table.entries[j + 1].min_dcfclk_khz;
				min_table->dram_bw_table.entries[j].min_fclk_khz = min_table->dram_bw_table.entries[j + 1].min_fclk_khz;
				min_table->dram_bw_table.entries[j].pre_derate_dram_bw_kbps = min_table->dram_bw_table.entries[j + 1].pre_derate_dram_bw_kbps;
			}
			min_table->dram_bw_table.num_entries--;
		}
	}

	return true;
}

static bool build_min_clk_table_coarse_grained(const struct dml2_soc_bb *soc_bb, struct dml2_mcg_min_clock_table *min_table)
{
	int i;

	for (i = 0; i < soc_bb->clk_table.uclk.num_clk_values; i++) {
		min_table->dram_bw_table.entries[i].pre_derate_dram_bw_kbps = uclk_to_dram_bw_kbps(soc_bb->clk_table.uclk.clk_values_khz[i], &soc_bb->clk_table.dram_config);
		min_table->dram_bw_table.entries[i].min_dcfclk_khz = soc_bb->clk_table.dcfclk.clk_values_khz[i];
		min_table->dram_bw_table.entries[i].min_fclk_khz = soc_bb->clk_table.fclk.clk_values_khz[i];
	}
	min_table->dram_bw_table.num_entries = soc_bb->clk_table.uclk.num_clk_values;

	return true;
}

static bool build_min_clock_table(const struct dml2_soc_bb *soc_bb, struct dml2_mcg_min_clock_table *min_table)
{
	bool result;
	bool dcfclk_fine_grained = false, fclk_fine_grained = false, clock_state_count_equal = false;

	if (!soc_bb || !min_table)
		return false;

	if (soc_bb->clk_table.dcfclk.num_clk_values < 2 || soc_bb->clk_table.fclk.num_clk_values < 2)
		return false;

	if (soc_bb->clk_table.uclk.num_clk_values > DML_MCG_MAX_CLK_TABLE_SIZE)
		return false;

	if (soc_bb->clk_table.dcfclk.num_clk_values == 2) {
		dcfclk_fine_grained = true;
	}

Annotation

Implementation Notes