1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 #include "dml2_internal_shared_types.h"
6 #include "dml_top.h"
7 #include "dml2_mcg_factory.h"
8 #include "dml2_core_factory.h"
9 #include "dml2_dpmm_factory.h"
10 #include "dml2_pmo_factory.h"
11 #include "dml_top_mcache.h"
12 #include "dml2_top_optimization.h"
13 #include "dml2_external_lib_deps.h"
14 
dml2_get_instance_size_bytes(void)15 unsigned int dml2_get_instance_size_bytes(void)
16 {
17 	return sizeof(struct dml2_instance);
18 }
19 
dml2_initialize_instance(struct dml2_initialize_instance_in_out * in_out)20 bool dml2_initialize_instance(struct dml2_initialize_instance_in_out *in_out)
21 {
22 	struct dml2_instance *dml = (struct dml2_instance *)in_out->dml2_instance;
23 	struct dml2_initialize_instance_locals *l = &dml->scratch.initialize_instance_locals;
24 	struct dml2_core_initialize_in_out core_init_params = { 0 };
25 	struct dml2_mcg_build_min_clock_table_params_in_out mcg_build_min_clk_params = { 0 };
26 	struct dml2_pmo_initialize_in_out pmo_init_params = { 0 };
27 	bool result = false;
28 
29 	memset(l, 0, sizeof(struct dml2_initialize_instance_locals));
30 	memset(dml, 0, sizeof(struct dml2_instance));
31 
32 	memcpy(&dml->ip_caps, &in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
33 	memcpy(&dml->soc_bbox, &in_out->soc_bb, sizeof(struct dml2_soc_bb));
34 
35 	dml->project_id = in_out->options.project_id;
36 	dml->pmo_options = in_out->options.pmo_options;
37 
38 	// Initialize All Components
39 	result = dml2_mcg_create(in_out->options.project_id, &dml->mcg_instance);
40 
41 	if (result)
42 		result = dml2_dpmm_create(in_out->options.project_id, &dml->dpmm_instance);
43 
44 	if (result)
45 		result = dml2_core_create(in_out->options.project_id, &dml->core_instance);
46 
47 	if (result) {
48 		mcg_build_min_clk_params.soc_bb = &in_out->soc_bb;
49 		mcg_build_min_clk_params.min_clk_table = &dml->min_clk_table;
50 		result = dml->mcg_instance.build_min_clock_table(&mcg_build_min_clk_params);
51 	}
52 
53 	if (result) {
54 		core_init_params.project_id = in_out->options.project_id;
55 		core_init_params.instance = &dml->core_instance;
56 		core_init_params.minimum_clock_table = &dml->min_clk_table;
57 		core_init_params.explicit_ip_bb = in_out->overrides.explicit_ip_bb;
58 		core_init_params.explicit_ip_bb_size = in_out->overrides.explicit_ip_bb_size;
59 		core_init_params.ip_caps = &in_out->ip_caps;
60 		core_init_params.soc_bb = &in_out->soc_bb;
61 		result = dml->core_instance.initialize(&core_init_params);
62 
63 		if (core_init_params.explicit_ip_bb && core_init_params.explicit_ip_bb_size > 0) {
64 			memcpy(&dml->ip_caps, &in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
65 		}
66 	}
67 
68 	if (result)
69 		result = dml2_pmo_create(in_out->options.project_id, &dml->pmo_instance);
70 
71 	if (result) {
72 		pmo_init_params.instance = &dml->pmo_instance;
73 		pmo_init_params.soc_bb = &dml->soc_bbox;
74 		pmo_init_params.ip_caps = &dml->ip_caps;
75 		pmo_init_params.mcg_clock_table_size = dml->min_clk_table.dram_bw_table.num_entries;
76 		pmo_init_params.options = &dml->pmo_options;
77 		dml->pmo_instance.initialize(&pmo_init_params);
78 	}
79 
80 	return result;
81 }
82 
setup_unoptimized_display_config_with_meta(const struct dml2_instance * dml,struct display_configuation_with_meta * out,const struct dml2_display_cfg * display_config)83 static void setup_unoptimized_display_config_with_meta(const struct dml2_instance *dml, struct display_configuation_with_meta *out, const struct dml2_display_cfg *display_config)
84 {
85 	memcpy(&out->display_config, display_config, sizeof(struct dml2_display_cfg));
86 	out->stage1.min_clk_index_for_latency = dml->min_clk_table.dram_bw_table.num_entries - 1; //dml->min_clk_table.clean_me_up.soc_bb.num_states - 1;
87 }
88 
setup_speculative_display_config_with_meta(const struct dml2_instance * dml,struct display_configuation_with_meta * out,const struct dml2_display_cfg * display_config)89 static void setup_speculative_display_config_with_meta(const struct dml2_instance *dml, struct display_configuation_with_meta *out, const struct dml2_display_cfg *display_config)
90 {
91 	memcpy(&out->display_config, display_config, sizeof(struct dml2_display_cfg));
92 	out->stage1.min_clk_index_for_latency = 0;
93 }
94 
dml2_check_mode_supported(struct dml2_check_mode_supported_in_out * in_out)95 bool dml2_check_mode_supported(struct dml2_check_mode_supported_in_out *in_out)
96 {
97 	struct dml2_instance *dml = (struct dml2_instance *)in_out->dml2_instance;
98 	struct dml2_check_mode_supported_locals *l = &dml->scratch.check_mode_supported_locals;
99 	struct dml2_display_cfg_programming *dpmm_programming = &dml->dpmm_instance.dpmm_scratch.programming;
100 
101 	bool result = false;
102 	bool mcache_success = false;
103 
104 	memset(dpmm_programming, 0, sizeof(struct dml2_display_cfg_programming));
105 
106 	setup_unoptimized_display_config_with_meta(dml, &l->base_display_config_with_meta, in_out->display_config);
107 
108 	l->mode_support_params.instance = &dml->core_instance;
109 	l->mode_support_params.display_cfg = &l->base_display_config_with_meta;
110 	l->mode_support_params.min_clk_table = &dml->min_clk_table;
111 	l->mode_support_params.min_clk_index = l->base_display_config_with_meta.stage1.min_clk_index_for_latency;
112 
113 	result = dml->core_instance.mode_support(&l->mode_support_params);
114 	l->base_display_config_with_meta.mode_support_result = l->mode_support_params.mode_support_result;
115 
116 	if (result) {
117 		struct optimization_phase_params mcache_phase =	{
118 		.dml = dml,
119 		.display_config = &l->base_display_config_with_meta,
120 		.test_function = dml2_top_optimization_test_function_mcache,
121 		.optimize_function = dml2_top_optimization_optimize_function_mcache,
122 		.optimized_display_config = &l->optimized_display_config_with_meta,
123 		.all_or_nothing = false,
124 		};
125 		mcache_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &mcache_phase);
126 	}
127 
128 	/*
129 	 * Call DPMM to map all requirements to minimum clock state
130 	 */
131 	if (result) {
132 		l->dppm_map_mode_params.min_clk_table = &dml->min_clk_table;
133 		l->dppm_map_mode_params.display_cfg = &l->base_display_config_with_meta;
134 		l->dppm_map_mode_params.programming = dpmm_programming;
135 		l->dppm_map_mode_params.soc_bb = &dml->soc_bbox;
136 		l->dppm_map_mode_params.ip = &dml->core_instance.clean_me_up.mode_lib.ip;
137 		result = dml->dpmm_instance.map_mode_to_soc_dpm(&l->dppm_map_mode_params);
138 	}
139 
140 	in_out->is_supported = mcache_success;
141 	result = result && in_out->is_supported;
142 
143 	return result;
144 }
145 
dml2_build_mode_programming(struct dml2_build_mode_programming_in_out * in_out)146 bool dml2_build_mode_programming(struct dml2_build_mode_programming_in_out *in_out)
147 {
148 	struct dml2_instance *dml = (struct dml2_instance *)in_out->dml2_instance;
149 	struct dml2_build_mode_programming_locals *l = &dml->scratch.build_mode_programming_locals;
150 
151 	bool result = false;
152 	bool mcache_success = false;
153 	bool uclk_pstate_success = false;
154 	bool vmin_success = false;
155 	bool stutter_success = false;
156 	unsigned int i;
157 
158 	memset(l, 0, sizeof(struct dml2_build_mode_programming_locals));
159 	memset(in_out->programming, 0, sizeof(struct dml2_display_cfg_programming));
160 
161 	memcpy(&in_out->programming->display_config, in_out->display_config, sizeof(struct dml2_display_cfg));
162 
163 	setup_speculative_display_config_with_meta(dml, &l->base_display_config_with_meta, in_out->display_config);
164 
165 	l->mode_support_params.instance = &dml->core_instance;
166 	l->mode_support_params.display_cfg = &l->base_display_config_with_meta;
167 	l->mode_support_params.min_clk_table = &dml->min_clk_table;
168 	l->mode_support_params.min_clk_index = l->base_display_config_with_meta.stage1.min_clk_index_for_latency;
169 
170 	result = dml->core_instance.mode_support(&l->mode_support_params);
171 	l->base_display_config_with_meta.mode_support_result = l->mode_support_params.mode_support_result;
172 
173 	if (!result) {
174 		setup_unoptimized_display_config_with_meta(dml, &l->base_display_config_with_meta, in_out->display_config);
175 
176 		l->mode_support_params.instance = &dml->core_instance;
177 		l->mode_support_params.display_cfg = &l->base_display_config_with_meta;
178 		l->mode_support_params.min_clk_table = &dml->min_clk_table;
179 		l->mode_support_params.min_clk_index = l->base_display_config_with_meta.stage1.min_clk_index_for_latency;
180 
181 		result = dml->core_instance.mode_support(&l->mode_support_params);
182 		l->base_display_config_with_meta.mode_support_result = l->mode_support_params.mode_support_result;
183 
184 		if (!result) {
185 			l->informative_params.instance = &dml->core_instance;
186 			l->informative_params.programming = in_out->programming;
187 			l->informative_params.mode_is_supported = false;
188 			dml->core_instance.populate_informative(&l->informative_params);
189 
190 			return false;
191 		}
192 
193 		/*
194 		* Phase 1: Determine minimum clocks to satisfy latency requirements for this mode
195 		*/
196 		memset(&l->min_clock_for_latency_phase, 0, sizeof(struct optimization_phase_params));
197 		l->min_clock_for_latency_phase.dml = dml;
198 		l->min_clock_for_latency_phase.display_config = &l->base_display_config_with_meta;
199 		l->min_clock_for_latency_phase.init_function = dml2_top_optimization_init_function_min_clk_for_latency;
200 		l->min_clock_for_latency_phase.test_function = dml2_top_optimization_test_function_min_clk_for_latency;
201 		l->min_clock_for_latency_phase.optimize_function = dml2_top_optimization_optimize_function_min_clk_for_latency;
202 		l->min_clock_for_latency_phase.optimized_display_config = &l->optimized_display_config_with_meta;
203 		l->min_clock_for_latency_phase.all_or_nothing = false;
204 
205 		dml2_top_optimization_perform_optimization_phase_1(&l->optimization_phase_locals, &l->min_clock_for_latency_phase);
206 
207 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
208 	}
209 
210 	/*
211 	* Phase 2: Satisfy DCC mcache requirements
212 	*/
213 	memset(&l->mcache_phase, 0, sizeof(struct optimization_phase_params));
214 	l->mcache_phase.dml = dml;
215 	l->mcache_phase.display_config = &l->base_display_config_with_meta;
216 	l->mcache_phase.test_function = dml2_top_optimization_test_function_mcache;
217 	l->mcache_phase.optimize_function = dml2_top_optimization_optimize_function_mcache;
218 	l->mcache_phase.optimized_display_config = &l->optimized_display_config_with_meta;
219 	l->mcache_phase.all_or_nothing = true;
220 
221 	mcache_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->mcache_phase);
222 
223 	if (!mcache_success) {
224 		l->informative_params.instance = &dml->core_instance;
225 		l->informative_params.programming = in_out->programming;
226 		l->informative_params.mode_is_supported = false;
227 
228 		dml->core_instance.populate_informative(&l->informative_params);
229 
230 		in_out->programming->informative.failed_mcache_validation = true;
231 		return false;
232 	}
233 
234 	memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
235 
236 	/*
237 	* Phase 3: Optimize for Pstate
238 	*/
239 	memset(&l->uclk_pstate_phase, 0, sizeof(struct optimization_phase_params));
240 	l->uclk_pstate_phase.dml = dml;
241 	l->uclk_pstate_phase.display_config = &l->base_display_config_with_meta;
242 	l->uclk_pstate_phase.init_function = dml2_top_optimization_init_function_uclk_pstate;
243 	l->uclk_pstate_phase.test_function = dml2_top_optimization_test_function_uclk_pstate;
244 	l->uclk_pstate_phase.optimize_function = dml2_top_optimization_optimize_function_uclk_pstate;
245 	l->uclk_pstate_phase.optimized_display_config = &l->optimized_display_config_with_meta;
246 	l->uclk_pstate_phase.all_or_nothing = true;
247 
248 	uclk_pstate_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->uclk_pstate_phase);
249 
250 	if (uclk_pstate_success) {
251 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
252 		l->base_display_config_with_meta.stage3.success = true;
253 	}
254 
255 	/*
256 	* Phase 4: Optimize for Vmin
257 	*/
258 	memset(&l->vmin_phase, 0, sizeof(struct optimization_phase_params));
259 	l->vmin_phase.dml = dml;
260 	l->vmin_phase.display_config = &l->base_display_config_with_meta;
261 	l->vmin_phase.init_function = dml2_top_optimization_init_function_vmin;
262 	l->vmin_phase.test_function = dml2_top_optimization_test_function_vmin;
263 	l->vmin_phase.optimize_function = dml2_top_optimization_optimize_function_vmin;
264 	l->vmin_phase.optimized_display_config = &l->optimized_display_config_with_meta;
265 	l->vmin_phase.all_or_nothing = false;
266 
267 	vmin_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->vmin_phase);
268 
269 	if (l->optimized_display_config_with_meta.stage4.performed) {
270 		/*
271 		 * when performed is true, optimization has applied to
272 		 * optimized_display_config_with_meta and it has passed mode
273 		 * support. However it may or may not pass the test function to
274 		 * reach actual Vmin. As long as voltage is optimized even if it
275 		 * doesn't reach Vmin level, there is still power benefit so in
276 		 * this case we will still copy this optimization into base
277 		 * display config.
278 		 */
279 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
280 		l->base_display_config_with_meta.stage4.success = vmin_success;
281 	}
282 
283 	/*
284 	* Phase 5: Optimize for Stutter
285 	*/
286 	memset(&l->stutter_phase, 0, sizeof(struct optimization_phase_params));
287 	l->stutter_phase.dml = dml;
288 	l->stutter_phase.display_config = &l->base_display_config_with_meta;
289 	l->stutter_phase.init_function = dml2_top_optimization_init_function_stutter;
290 	l->stutter_phase.test_function = dml2_top_optimization_test_function_stutter;
291 	l->stutter_phase.optimize_function = dml2_top_optimization_optimize_function_stutter;
292 	l->stutter_phase.optimized_display_config = &l->optimized_display_config_with_meta;
293 	l->stutter_phase.all_or_nothing = true;
294 
295 	stutter_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->stutter_phase);
296 
297 	if (stutter_success) {
298 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
299 		l->base_display_config_with_meta.stage5.success = true;
300 	}
301 
302 	/*
303 	* Populate mcache programming
304 	*/
305 	for (i = 0; i < in_out->display_config->num_planes; i++) {
306 		in_out->programming->plane_programming[i].mcache_allocation = l->base_display_config_with_meta.stage2.mcache_allocations[i];
307 	}
308 
309 	/*
310 	* Call DPMM to map all requirements to minimum clock state
311 	*/
312 	if (result) {
313 		l->dppm_map_mode_params.min_clk_table = &dml->min_clk_table;
314 		l->dppm_map_mode_params.display_cfg = &l->base_display_config_with_meta;
315 		l->dppm_map_mode_params.programming = in_out->programming;
316 		l->dppm_map_mode_params.soc_bb = &dml->soc_bbox;
317 		l->dppm_map_mode_params.ip = &dml->core_instance.clean_me_up.mode_lib.ip;
318 		result = dml->dpmm_instance.map_mode_to_soc_dpm(&l->dppm_map_mode_params);
319 		if (!result)
320 			in_out->programming->informative.failed_dpmm = true;
321 	}
322 
323 	if (result) {
324 		l->mode_programming_params.instance = &dml->core_instance;
325 		l->mode_programming_params.display_cfg = &l->base_display_config_with_meta;
326 		l->mode_programming_params.cfg_support_info = &l->base_display_config_with_meta.mode_support_result.cfg_support_info;
327 		l->mode_programming_params.programming = in_out->programming;
328 
329 		result = dml->core_instance.mode_programming(&l->mode_programming_params);
330 		if (!result)
331 			in_out->programming->informative.failed_mode_programming = true;
332 	}
333 
334 	if (result) {
335 		l->dppm_map_watermarks_params.core = &dml->core_instance;
336 		l->dppm_map_watermarks_params.display_cfg = &l->base_display_config_with_meta;
337 		l->dppm_map_watermarks_params.programming = in_out->programming;
338 		result = dml->dpmm_instance.map_watermarks(&l->dppm_map_watermarks_params);
339 	}
340 
341 	l->informative_params.instance = &dml->core_instance;
342 	l->informative_params.programming = in_out->programming;
343 	l->informative_params.mode_is_supported = result;
344 
345 	dml->core_instance.populate_informative(&l->informative_params);
346 
347 	return result;
348 }
349 
dml2_build_mcache_programming(struct dml2_build_mcache_programming_in_out * in_out)350 bool dml2_build_mcache_programming(struct dml2_build_mcache_programming_in_out *in_out)
351 {
352 	return dml2_top_mcache_build_mcache_programming(in_out);
353 }
354 
355