xref: /linux/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c (revision 0a5e0416e191571de9362b769feb31b3e87a705e)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4 
5 #include "dcn42_soc_and_ip_translator.h"
6 #include "../dcn401/dcn401_soc_and_ip_translator.h"
7 #include "bounding_boxes/dcn42_soc_bb.h"
8 #include "bounding_boxes/dcn42b_soc_bb.h"
9 
10 /* soc_and_ip_translator component used to get up-to-date values for bounding box.
11  * Bounding box values are stored in several locations and locations can vary with DCN revision.
12  * This component provides an interface to get DCN-specific bounding box values.
13  */
14 
15 static void get_default_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc)
16 {
17 	if (dc->ctx->dce_version == DCN_VERSION_4_2B) {
18 		memcpy(soc_bb, &dml2_socbb_dcn42b, sizeof(struct dml2_soc_bb));
19 		memcpy(&soc_bb->qos_parameters, &dml_dcn42b_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters));
20 	} else {
21 		memcpy(soc_bb, &dml2_socbb_dcn42, sizeof(struct dml2_soc_bb));
22 		memcpy(&soc_bb->qos_parameters, &dml_dcn42_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters));
23 	}
24 }
25 
26 /*
27  * DC clock table is obtained from SMU during runtime.
28  * SMU stands for System Management Unit. It is a power management processor.
29  * It owns the initialization of dc's clock table and programming of clock values
30  * based on dc's requests.
31  * Our clock values in base soc bb is a dummy placeholder. The real clock values
32  * are retrieved from SMU firmware to dc clock table at runtime.
33  * This function overrides our dummy placeholder values with real values in dc
34  * clock table.
35  */
36 static void dcn42_convert_dc_clock_table_to_soc_bb_clock_table(
37 		struct dml2_soc_state_table *dml_clk_table,
38 		struct dml2_soc_vmin_clock_limits *vmin_limit,
39 		const struct clk_bw_params *dc_bw_params)
40 {
41 	int i;
42 	const struct clk_limit_table *dc_clk_table;
43 
44 	if (dc_bw_params == NULL)
45 		/* skip if bw params could not be obtained from smu */
46 		return;
47 
48 	dc_clk_table = &dc_bw_params->clk_table;
49 
50 	/* fclk/dcfclk - dcn42 pmfw table can have 0 entries for inactive dpm levels
51 	 * for use with dml we need to fill in using an active value aiming for >= 2x DCFCLK
52 	 */
53 	if (dc_clk_table->num_entries_per_clk.num_fclk_levels && dc_clk_table->num_entries_per_clk.num_dcfclk_levels) {
54 		dml_clk_table->fclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dcfclk_levels;
55 		dml_clk_table->dcfclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dcfclk_levels;
56 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
57 			if (i < (int)dc_clk_table->num_entries_per_clk.num_dcfclk_levels) {
58 				int j, max_fclk = 0;
59 
60 				dml_clk_table->dcfclk.clk_values_khz[i] = dc_clk_table->entries[i].dcfclk_mhz * 1000;
61 				for (j = 0; j < MAX_NUM_DPM_LVL; j++) {
62 					if ((uint32_t)(dc_clk_table->entries[j].fclk_mhz * 1000) > (uint32_t)max_fclk)
63 						max_fclk = dc_clk_table->entries[j].fclk_mhz * 1000;
64 					dml_clk_table->fclk.clk_values_khz[i] = max_fclk;
65 						if ((uint32_t)max_fclk >= 2 * dml_clk_table->dcfclk.clk_values_khz[i])
66 						break;
67 				}
68 			} else {
69 				dml_clk_table->dcfclk.clk_values_khz[i] = 0;
70 				dml_clk_table->fclk.clk_values_khz[i] = 0;
71 			}
72 		}
73 	}
74 
75 	/* uclk */
76 	if (dc_clk_table->num_entries_per_clk.num_memclk_levels) {
77 		dml_clk_table->uclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_memclk_levels;
78 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
79 			if (i < dml_clk_table->uclk.num_clk_values) {
80 				dml_clk_table->uclk.clk_values_khz[i] = dc_clk_table->entries[i].memclk_mhz * 1000;
81 				dml_clk_table->wck_ratio.clk_values_khz[i] = dc_clk_table->entries[i].wck_ratio;
82 			} else {
83 				dml_clk_table->uclk.clk_values_khz[i] = 0;
84 				dml_clk_table->wck_ratio.clk_values_khz[i] = 0;
85 			}
86 		}
87 	}
88 
89 	/* dispclk */
90 	if (dc_clk_table->num_entries_per_clk.num_dispclk_levels) {
91 		dml_clk_table->dispclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dispclk_levels;
92 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
93 			if (i < dml_clk_table->dispclk.num_clk_values) {
94 				dml_clk_table->dispclk.clk_values_khz[i] = dc_clk_table->entries[i].dispclk_mhz * 1000;
95 			} else {
96 				dml_clk_table->dispclk.clk_values_khz[i] = 0;
97 			}
98 		}
99 		vmin_limit->dispclk_khz = min(dc_clk_table->entries[0].dispclk_mhz * 1000, vmin_limit->dispclk_khz);
100 		/* dispclk is always fine-grain */
101 		dml_clk_table->dispclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dispclk_levels >= 2 ? 2 : 1;
102 		dml_clk_table->dispclk.clk_values_khz[0] = 0;
103 		dml_clk_table->dispclk.clk_values_khz[1] = dc_clk_table->entries[dc_clk_table->num_entries_per_clk.num_dispclk_levels - 1].dispclk_mhz * 1000;
104 	}
105 
106 	/* dppclk */
107 	if (dc_clk_table->num_entries_per_clk.num_dppclk_levels) {
108 		dml_clk_table->dppclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dppclk_levels;
109 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
110 			if (i < dml_clk_table->dppclk.num_clk_values) {
111 				dml_clk_table->dppclk.clk_values_khz[i] = dc_clk_table->entries[i].dppclk_mhz * 1000;
112 			} else {
113 				dml_clk_table->dppclk.clk_values_khz[i] = 0;
114 			}
115 		}
116 		/* dppclk is always fine-grain */
117 		dml_clk_table->dppclk.num_clk_values = dc_clk_table->num_entries_per_clk.num_dppclk_levels >= 2 ? 2 : 1;
118 		dml_clk_table->dppclk.clk_values_khz[0] = 0;
119 		dml_clk_table->dppclk.clk_values_khz[1] = dc_clk_table->entries[dc_clk_table->num_entries_per_clk.num_dppclk_levels - 1].dppclk_mhz * 1000;
120 	}
121 
122 	/* dtbclk */
123 	if (dc_clk_table->num_entries_per_clk.num_dtbclk_levels) {
124 		dml_clk_table->dtbclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_dtbclk_levels;
125 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
126 			if (i < dml_clk_table->dtbclk.num_clk_values) {
127 				dml_clk_table->dtbclk.clk_values_khz[i] = dc_clk_table->entries[i].dtbclk_mhz * 1000;
128 			} else {
129 				dml_clk_table->dtbclk.clk_values_khz[i] = 0;
130 			}
131 		}
132 	}
133 
134 	/* socclk */
135 	if (dc_clk_table->num_entries_per_clk.num_socclk_levels) {
136 		dml_clk_table->socclk.num_clk_values = (uint8_t)dc_clk_table->num_entries_per_clk.num_socclk_levels;
137 		for (i = 0; i < min(DML_MAX_CLK_TABLE_SIZE, MAX_NUM_DPM_LVL); i++) {
138 			if (i < dml_clk_table->socclk.num_clk_values) {
139 				dml_clk_table->socclk.clk_values_khz[i] = dc_clk_table->entries[i].socclk_mhz * 1000;
140 			} else {
141 				dml_clk_table->socclk.clk_values_khz[i] = 0;
142 			}
143 		}
144 	}
145 
146 	/* dram config */
147 	dml_clk_table->dram_config.channel_count = dc_bw_params->num_channels;
148 	dml_clk_table->dram_config.channel_width_bytes = dc_bw_params->dram_channel_width_bytes;
149 }
150 
151 static void dcn42_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc_bb, const struct dc *dc)
152 {
153 	soc_bb->dprefclk_mhz = dc->clk_mgr->dprefclk_khz / 1000;
154 	soc_bb->dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
155 	soc_bb->mall_allocated_for_dcn_mbytes = dc->caps.mall_size_total / (1024 * 1024);
156 
157 	if (dc->clk_mgr->funcs->is_smu_present &&
158 			dc->clk_mgr->funcs->is_smu_present(dc->clk_mgr)) {
159 		dcn42_convert_dc_clock_table_to_soc_bb_clock_table(&soc_bb->clk_table, &soc_bb->vmin_limit,
160 			dc->clk_mgr->bw_params);
161 	}
162 
163 	if (dc->clk_mgr->bw_params->vram_type == Ddr5MemType) {
164 		soc_bb->power_management_parameters = dcn42_ddr5_power_management_parameters;
165 	}
166 }
167 
168 static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
169 {
170 	(void)config;
171 	/* Individual modification can be overwritten even if it was obtained by a previous function.
172 	 * Modifications are acquired in order of priority (lowest to highest).
173 	 */
174 	dc_assert_fp_enabled();
175 
176 	dcn42_update_soc_bb_with_values_from_clk_mgr(soc_bb, dc);
177 	dcn401_update_soc_bb_with_values_from_vbios(soc_bb, dc);
178 	dcn401_update_soc_bb_with_values_from_software_policy(soc_bb, dc);
179 }
180 
181 void dcn42_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config)
182 {
183 	//get default soc_bb with static values
184 	get_default_soc_bb(soc_bb, dc);
185 	//update soc_bb values with more accurate values
186 	apply_soc_bb_updates(soc_bb, dc, config);
187 }
188 
189 static void dcn42_get_ip_caps(struct dml2_ip_capabilities *ip_caps)
190 {
191 	*ip_caps = dml2_dcn42_max_ip_caps;
192 }
193 
194 static struct soc_and_ip_translator_funcs dcn42_translator_funcs = {
195 	.get_soc_bb = dcn42_get_soc_bb,
196 	.get_ip_caps = dcn42_get_ip_caps,
197 };
198 
199 void dcn42_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator)
200 {
201 	soc_and_ip_translator->translator_funcs = &dcn42_translator_funcs;
202 }
203 
204