projects/linux·blob master · refs

964 lines · 29.1 KiB

1// SPDX-License-Identifier: MIT
2/*
3 * Copyright 2026 Advanced Micro Devices, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: AMD
24 *
25 */
26
27#include "dm_services_types.h"
28#include "dc.h"
29#include "dc/inc/core_types.h"
30#include "dc/dc_dmub_srv.h"
31#include "dmub/dmub_srv.h"
32#include "dc/inc/hw/dmcu.h"
33#include "dc/inc/hw/abm.h"
34#include "dal_asic_id.h"
35
36#include "amdgpu.h"
37#include "amdgpu_display.h"
38#include "amdgpu_ucode.h"
39#include "amdgpu_dm.h"
40#include "amdgpu_dm_dmub.h"
41#include "dm_helpers.h"
42#include <linux/component.h>
43#include <linux/firmware.h>
44
45static_assert(AMDGPU_DMUB_NOTIFICATION_MAX == DMUB_NOTIFICATION_MAX, "AMDGPU_DMUB_NOTIFICATION_MAX mismatch");
46
47MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB);
48MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID_DMUB);
49MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER_DMUB);
50MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE_DMUB);
51MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB);
52MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB);
53MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB);
54MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB);
55MODULE_FIRMWARE(FIRMWARE_DCN_314_DMUB);
56MODULE_FIRMWARE(FIRMWARE_DCN_315_DMUB);
57MODULE_FIRMWARE(FIRMWARE_DCN316_DMUB);
58MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_0_DMCUB);
59MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_1_DMCUB);
60MODULE_FIRMWARE(FIRMWARE_DCN_35_DMUB);
61MODULE_FIRMWARE(FIRMWARE_DCN_351_DMUB);
62MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB);
63MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB);
64MODULE_FIRMWARE(FIRMWARE_DCN_42_DMUB);
65MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB);
66MODULE_FIRMWARE(FIRMWARE_DCN_60_DMUB);
67
68/**
69 * dm_dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
70 * @adev: amdgpu_device pointer
71 * @notify: dmub notification structure
72 *
73 * Dmub AUX or SET_CONFIG command completion processing callback
74 * Copies dmub notification to DM which is to be read by AUX command.
75 * issuing thread and also signals the event to wake up the thread.
76 */
77void dm_dmub_aux_setconfig_callback(struct amdgpu_device *adev,
78 struct dmub_notification *notify)
79{
80 if (adev->dm.dmub_notify)
81 memcpy(adev->dm.dmub_notify, notify, sizeof(struct dmub_notification));
82 if (notify->type == DMUB_NOTIFICATION_AUX_REPLY)
83 complete(&adev->dm.dmub_aux_transfer_done);
84}
85EXPORT_IF_KUNIT(dm_dmub_aux_setconfig_callback);
86
87void dm_dmub_aux_fused_io_callback(struct amdgpu_device *adev,
88 struct dmub_notification *notify)
89{
90 if (!adev || !notify) {
91 ASSERT(false);
92 return;
93 }
94
95 const struct dmub_cmd_fused_request *req = &notify->fused_request;
96 const uint8_t ddc_line = req->u.aux.ddc_line;
97
98 if (ddc_line >= ARRAY_SIZE(adev->dm.fused_io)) {
99 ASSERT(false);
100 return;
101 }
102
103 struct fused_io_sync *sync = &adev->dm.fused_io[ddc_line];
104
105 static_assert(sizeof(*req) <= sizeof(sync->reply_data), "Size mismatch");
106 memcpy(sync->reply_data, req, sizeof(*req));
107 complete(&sync->replied);
108}
109EXPORT_IF_KUNIT(dm_dmub_aux_fused_io_callback);
110
111/**
112 * dm_register_dmub_notify_callback - Sets callback for DMUB notify
113 * @adev: amdgpu_device pointer
114 * @type: Type of dmub notification
115 * @callback: Dmub interrupt callback function
116 * @dmub_int_thread_offload: offload indicator
117 *
118 * API to register a dmub callback handler for a dmub notification
119 * Also sets indicator whether callback processing to be offloaded.
120 * to dmub interrupt handling thread
121 * Return: true if successfully registered, false if there is existing registration
122 */
123bool dm_register_dmub_notify_callback(struct amdgpu_device *adev,
124 enum dmub_notification_type type,
125 dmub_notify_interrupt_callback_t callback,
126 bool dmub_int_thread_offload)
127{
128 if (!callback || type >= ARRAY_SIZE(adev->dm.dmub_thread_offload))
129 return false;
130
131 adev->dm.dmub_callback[type] = callback;
132 adev->dm.dmub_thread_offload[type] = dmub_int_thread_offload;
133
134 return true;
135}
136EXPORT_IF_KUNIT(dm_register_dmub_notify_callback);
137
138int dm_dmub_hw_init(struct amdgpu_device *adev)
139{
140 const struct dmcub_firmware_header_v1_0 *hdr;
141 struct dmub_srv *dmub_srv = adev->dm.dmub_srv;
142 struct dmub_srv_fb_info *fb_info = adev->dm.dmub_fb_info;
143 const struct firmware *dmub_fw = adev->dm.dmub_fw;
144 struct dc *dc = adev->dm.dc;
145 struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu;
146 struct abm *abm = adev->dm.dc->res_pool->abm;
147 struct dc_context *ctx = adev->dm.dc->ctx;
148 struct dmub_srv_hw_params hw_params;
149 enum dmub_status status;
150 const unsigned char *fw_inst_const, *fw_bss_data;
151 u32 fw_inst_const_size, fw_bss_data_size;
152 bool has_hw_support;
153
154 if (!dmub_srv)
155 /* DMUB isn't supported on the ASIC. */
156 return 0;
157
158 if (!fb_info) {
159 drm_err(adev_to_drm(adev), "No framebuffer info for DMUB service.\n");
160 return -EINVAL;
161 }
162
163 if (!dmub_fw) {
164 /* Firmware required for DMUB support. */
165 drm_err(adev_to_drm(adev), "No firmware provided for DMUB.\n");
166 return -EINVAL;
167 }
168
169 /* initialize register offsets for ASICs with runtime initialization available */
170 if (dmub_srv->hw_funcs.init_reg_offsets)
171 dmub_srv->hw_funcs.init_reg_offsets(dmub_srv, ctx);
172
173 status = dmub_srv_has_hw_support(dmub_srv, &has_hw_support);
174 if (status != DMUB_STATUS_OK) {
175 drm_err(adev_to_drm(adev), "Error checking HW support for DMUB: %d\n", status);
176 return -EINVAL;
177 }
178
179 if (!has_hw_support) {
180 drm_info(adev_to_drm(adev), "DMUB unsupported on ASIC\n");
181 return 0;
182 }
183
184 /* Reset DMCUB if it was previously running - before we overwrite its memory. */
185 status = dmub_srv_hw_reset(dmub_srv);
186 if (status != DMUB_STATUS_OK)
187 drm_warn(adev_to_drm(adev), "Error resetting DMUB HW: %d\n", status);
188
189 hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data;
190
191 fw_inst_const = dmub_fw->data +
192 le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
193 PSP_HEADER_BYTES_256;
194
195 fw_bss_data = dmub_fw->data +
196 le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
197 le32_to_cpu(hdr->inst_const_bytes);
198
199 /* Copy firmware and bios info into FB memory. */
200 fw_inst_const_size = adev->dm.fw_inst_size;
201
202 fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes);
203
204 /* if adev->firmware.load_type == AMDGPU_FW_LOAD_PSP,
205 * amdgpu_ucode_init_single_fw will load dmub firmware
206 * fw_inst_const part to cw0; otherwise, the firmware back door load
207 * will be done by dm_dmub_hw_init
208 */
209 if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
210 memcpy(fb_info->fb[DMUB_WINDOW_0_INST_CONST].cpu_addr, fw_inst_const,
211 fw_inst_const_size);
212 }
213
214 if (fw_bss_data_size)
215 memcpy(fb_info->fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr,
216 fw_bss_data, fw_bss_data_size);
217
218 /* Copy firmware bios info into FB memory. */
219 memcpy(fb_info->fb[DMUB_WINDOW_3_VBIOS].cpu_addr, adev->bios,
220 adev->bios_size);
221
222 /* Reset regions that need to be reset. */
223 memset(fb_info->fb[DMUB_WINDOW_4_MAILBOX].cpu_addr, 0,
224 fb_info->fb[DMUB_WINDOW_4_MAILBOX].size);
225
226 memset(fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].cpu_addr, 0,
227 fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].size);
228
229 memset(fb_info->fb[DMUB_WINDOW_6_FW_STATE].cpu_addr, 0,
230 fb_info->fb[DMUB_WINDOW_6_FW_STATE].size);
231
232 memset(fb_info->fb[DMUB_WINDOW_SHARED_STATE].cpu_addr, 0,
233 fb_info->fb[DMUB_WINDOW_SHARED_STATE].size);
234
235 /* Initialize hardware. */
236 memset(&hw_params, 0, sizeof(hw_params));
237 hw_params.soc_fb_info.fb_base = adev->gmc.fb_start;
238 hw_params.soc_fb_info.fb_offset = adev->vm_manager.vram_base_offset;
239
240 /* backdoor load firmware and trigger dmub running */
241 if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
242 hw_params.load_inst_const = true;
243
244 if (dmcu)
245 hw_params.psp_version = dmcu->psp_version;
246
247 hw_params.fb_info = fb_info;
248
249 /* Enable usb4 dpia in the FW APU */
250 if (dc->caps.is_apu &&
251 dc->res_pool->usb4_dpia_count != 0 &&
252 !dc->debug.dpia_debug.bits.disable_dpia) {
253 hw_params.dpia_supported = true;
254 hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia;
255 hw_params.dpia_hpd_int_enable_supported = false;
256 hw_params.enable_non_transparent_setconfig = dc->config.consolidated_dpia_dp_lt;
257 hw_params.disable_dpia_bw_allocation = !dc->config.usb4_bw_alloc_support;
258 }
259
260 switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
261 case IP_VERSION(3, 5, 0):
262 case IP_VERSION(3, 5, 1):
263 case IP_VERSION(3, 6, 0):
264 case IP_VERSION(4, 2, 0):
265 case IP_VERSION(4, 2, 1):
266 hw_params.ips_sequential_ono = adev->external_rev_id > 0x10;
267 hw_params.lower_hbr3_phy_ssc = true;
268 break;
269 default:
270 break;
271 }
272
273 status = dmub_srv_hw_init(dmub_srv, &hw_params);
274 if (status != DMUB_STATUS_OK) {
275 drm_err(adev_to_drm(adev), "Error initializing DMUB HW: %d\n", status);
276 return -EINVAL;
277 }
278
279 /* Wait for firmware load to finish. */
280 status = dmub_srv_wait_for_auto_load(dmub_srv, 100000);
281 if (status != DMUB_STATUS_OK)
282 drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status);
283
284 /* Init DMCU and ABM if available. */
285 if (dmcu && abm) {
286 dmcu->funcs->dmcu_init(dmcu);
287 abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu);
288 }
289
290 if (!adev->dm.dc->ctx->dmub_srv)
291 adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv);
292 if (!adev->dm.dc->ctx->dmub_srv) {
293 drm_err(adev_to_drm(adev), "Couldn't allocate DC DMUB server!\n");
294 return -ENOMEM;
295 }
296
297 drm_info(adev_to_drm(adev), "DMUB hardware initialized: version=0x%08X\n",
298 adev->dm.dmcub_fw_version);
299
300 /* Keeping sanity checks off if
301 * DCN31 >= 4.0.59.0
302 * DCN314 >= 8.0.16.0
303 * Otherwise, turn on sanity checks
304 */
305 switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
306 case IP_VERSION(3, 1, 2):
307 case IP_VERSION(3, 1, 3):
308 if (adev->dm.dmcub_fw_version &&
309 adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) &&
310 adev->dm.dmcub_fw_version < DMUB_FW_VERSION(4, 0, 59))
311 adev->dm.dc->debug.sanity_checks = true;
312 break;
313 case IP_VERSION(3, 1, 4):
314 if (adev->dm.dmcub_fw_version &&
315 adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) &&
316 adev->dm.dmcub_fw_version < DMUB_FW_VERSION(8, 0, 16))
317 adev->dm.dc->debug.sanity_checks = true;
318 break;
319 default:
320 break;
321 }
322
323 return 0;
324}
325EXPORT_IF_KUNIT(dm_dmub_hw_init);
326
327void dm_dmub_hw_resume(struct amdgpu_device *adev)
328{
329 struct dmub_srv *dmub_srv = adev->dm.dmub_srv;
330 enum dmub_status status;
331 bool init;
332 int r;
333
334 if (!dmub_srv) {
335 /* DMUB isn't supported on the ASIC. */
336 return;
337 }
338
339 status = dmub_srv_is_hw_init(dmub_srv, &init);
340 if (status != DMUB_STATUS_OK)
341 drm_warn(adev_to_drm(adev), "DMUB hardware init check failed: %d\n", status);
342
343 if (status == DMUB_STATUS_OK && init) {
344 /* Wait for firmware load to finish. */
345 status = dmub_srv_wait_for_auto_load(dmub_srv, 100000);
346 if (status != DMUB_STATUS_OK)
347 drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status);
348 } else {
349 /* Perform the full hardware initialization. */
350 r = dm_dmub_hw_init(adev);
351 if (r)
352 drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r);
353 }
354}
355EXPORT_IF_KUNIT(dm_dmub_hw_resume);
356
357static enum dmub_status
358dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev,
359 enum dmub_gpint_command command_code,
360 uint16_t param,
361 uint32_t timeout_us)
362{
363 union dmub_gpint_data_register reg, test;
364 uint32_t i;
365
366 /* Assume that VBIOS DMUB is ready to take commands */
367
368 reg.bits.status = 1;
369 reg.bits.command_code = command_code;
370 reg.bits.param = param;
371
372 cgs_write_register(adev->dm.cgs_device, 0x34c0 + 0x01f8, reg.all);
373
374 for (i = 0; i < timeout_us; ++i) {
375 udelay(1);
376
377 /* Check if our GPINT got acked */
378 reg.bits.status = 0;
379 test = (union dmub_gpint_data_register)
380 cgs_read_register(adev->dm.cgs_device, 0x34c0 + 0x01f8);
381
382 if (test.all == reg.all)
383 return DMUB_STATUS_OK;
384 }
385
386 return DMUB_STATUS_TIMEOUT;
387}
388
389STATIC_IFN_KUNIT void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev)
390{
391 void *bb;
392 long long addr;
393 unsigned int bb_size;
394 int i = 0;
395 uint16_t chunk;
396 enum dmub_gpint_command send_addrs[] = {
397 DMUB_GPINT__SET_BB_ADDR_WORD0,
398 DMUB_GPINT__SET_BB_ADDR_WORD1,
399 DMUB_GPINT__SET_BB_ADDR_WORD2,
400 DMUB_GPINT__SET_BB_ADDR_WORD3,
401 };
402 enum dmub_status ret;
403
404 switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
405 case IP_VERSION(4, 0, 1):
406 bb_size = sizeof(struct dml2_soc_bb);
407 break;
408 case IP_VERSION(4, 2, 0):
409 case IP_VERSION(4, 2, 1):
410 bb_size = sizeof(struct dml2_soc_bb);
411 break;
412 case IP_VERSION(6, 0, 0):
413 bb_size = sizeof(struct dmub_soc_bb_params);
414 break;
415 default:
416 return NULL;
417 }
418
419 bb = dm_allocate_gpu_mem(adev,
420 DC_MEM_ALLOC_TYPE_GART,
421 bb_size,
422 &addr);
423 if (!bb)
424 return NULL;
425
426 for (i = 0; i < 4; i++) {
427 /* Extract 16-bit chunk */
428 chunk = ((uint64_t) addr >> (i * 16)) & 0xFFFF;
429 /* Send the chunk */
430 ret = dm_dmub_send_vbios_gpint_command(adev, send_addrs[i], chunk, 30000);
431 if (ret != DMUB_STATUS_OK)
432 goto free_bb;
433 }
434
435 /* Now ask DMUB to copy the bb */
436 ret = dm_dmub_send_vbios_gpint_command(adev, DMUB_GPINT__BB_COPY, 1, 200000);
437 if (ret != DMUB_STATUS_OK)
438 goto free_bb;
439
440 return bb;
441
442free_bb:
443 dm_free_gpu_mem(adev, DC_MEM_ALLOC_TYPE_GART, (void *) bb);
444 return NULL;
445
446}
447EXPORT_IF_KUNIT(dm_dmub_get_vbios_bounding_box);
448
449enum dmub_ips_disable_type dm_get_default_ips_mode(
450 struct amdgpu_device *adev)
451{
452 enum dmub_ips_disable_type ret = DMUB_IPS_ENABLE;
453
454 switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
455 case IP_VERSION(3, 5, 0):
456 case IP_VERSION(3, 6, 0):
457 case IP_VERSION(3, 5, 1):
458 ret = DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF;
459 break;
460 default:
461 /* ASICs older than DCN35 do not have IPSs */
462 if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 5, 0))
463 ret = DMUB_IPS_DISABLE_ALL;
464 break;
465 }
466
467 return ret;
468}
469EXPORT_IF_KUNIT(dm_get_default_ips_mode);
470
471static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address)
472{
473 struct amdgpu_device *adev = ctx;
474
475 return dm_read_reg(adev->dm.dc->ctx, address);
476}
477
478static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address,
479 uint32_t value)
480{
481 struct amdgpu_device *adev = ctx;
482
483 return dm_write_reg(adev->dm.dc->ctx, address, value);
484}
485
486int dm_dmub_sw_init(struct amdgpu_device *adev)
487{
488 struct dmub_srv_create_params create_params;
489 struct dmub_srv_fw_meta_info_params fw_meta_info_params;
490 struct dmub_srv_region_params region_params;
491 struct dmub_srv_region_info region_info;
492 struct dmub_srv_memory_params memory_params;
493 struct dmub_fw_meta_info fw_info;
494 struct dmub_srv_fb_info *fb_info;
495 struct dmub_srv *dmub_srv;
496 const struct dmcub_firmware_header_v1_0 *hdr;
497 enum dmub_asic dmub_asic;
498 enum dmub_status status;
499 static enum dmub_window_memory_type window_memory_type[DMUB_WINDOW_TOTAL] = {
500 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_0_INST_CONST */
501 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_1_STACK */
502 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_2_BSS_DATA */
503 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_3_VBIOS */
504 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_4_MAILBOX */
505 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_5_TRACEBUFF */
506 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_6_FW_STATE */
507 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_7_SCRATCH_MEM */
508 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_IB_MEM */
509 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_SHARED_STATE */
510 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_LSDMA_BUFFER */
511 DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_CURSOR_OFFLOAD */
512 };
513 int r;
514 int mem_domain = AMDGPU_GEM_DOMAIN_GTT;
515
516 switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
517 case IP_VERSION(2, 1, 0):
518 dmub_asic = DMUB_ASIC_DCN21;
519 break;
520 case IP_VERSION(3, 0, 0):
521 dmub_asic = DMUB_ASIC_DCN30;
522 break;
523 case IP_VERSION(3, 0, 1):
524 dmub_asic = DMUB_ASIC_DCN301;
525 break;
526 case IP_VERSION(3, 0, 2):
527 dmub_asic = DMUB_ASIC_DCN302;
528 break;
529 case IP_VERSION(3, 0, 3):
530 dmub_asic = DMUB_ASIC_DCN303;
531 break;
532 case IP_VERSION(3, 1, 2):
533 case IP_VERSION(3, 1, 3):
534 dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31;
535 break;
536 case IP_VERSION(3, 1, 4):
537 dmub_asic = DMUB_ASIC_DCN314;
538 break;
539 case IP_VERSION(3, 1, 5):
540 dmub_asic = DMUB_ASIC_DCN315;
541 break;
542 case IP_VERSION(3, 1, 6):
543 dmub_asic = DMUB_ASIC_DCN316;
544 break;
545 case IP_VERSION(3, 2, 0):
546 dmub_asic = DMUB_ASIC_DCN32;
547 break;
548 case IP_VERSION(3, 2, 1):
549 dmub_asic = DMUB_ASIC_DCN321;
550 break;
551 case IP_VERSION(3, 5, 0):
552 case IP_VERSION(3, 5, 1):
553 dmub_asic = DMUB_ASIC_DCN35;
554 break;
555 case IP_VERSION(3, 6, 0):
556 dmub_asic = DMUB_ASIC_DCN36;
557 break;
558 case IP_VERSION(4, 0, 1):
559 dmub_asic = DMUB_ASIC_DCN401;
560 break;
561 case IP_VERSION(4, 2, 0):
562 dmub_asic = DMUB_ASIC_DCN42;
563 break;
564 case IP_VERSION(4, 2, 1):
565 dmub_asic = DMUB_ASIC_DCN42B;
566 break;
567 case IP_VERSION(6, 0, 0):
568 dmub_asic = DMUB_ASIC_DCN60;
569 break;
570 default:
571 /* ASIC doesn't support DMUB. */
572 return 0;
573 }
574
575 hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data;
576 adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version);
577
578 if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
579 adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].ucode_id =
580 AMDGPU_UCODE_ID_DMCUB;
581 adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].fw =
582 adev->dm.dmub_fw;
583 adev->firmware.fw_size +=
584 ALIGN(le32_to_cpu(hdr->inst_const_bytes), PAGE_SIZE);
585
586 drm_info(adev_to_drm(adev), "Loading DMUB firmware via PSP: version=0x%08X\n",
587 adev->dm.dmcub_fw_version);
588 }
589
590
591 adev->dm.dmub_srv = kzalloc_obj(*adev->dm.dmub_srv);
592 dmub_srv = adev->dm.dmub_srv;
593
594 if (!dmub_srv) {
595 drm_err(adev_to_drm(adev), "Failed to allocate DMUB service!\n");
596 return -ENOMEM;
597 }
598
599 memset(&create_params, 0, sizeof(create_params));
600 create_params.user_ctx = adev;
601 create_params.funcs.reg_read = amdgpu_dm_dmub_reg_read;
602 create_params.funcs.reg_write = amdgpu_dm_dmub_reg_write;
603 create_params.asic = dmub_asic;
604
605 /* Create the DMUB service. */
606 status = dmub_srv_create(dmub_srv, &create_params);
607 if (status != DMUB_STATUS_OK) {
608 drm_err(adev_to_drm(adev), "Error creating DMUB service: %d\n", status);
609 return -EINVAL;
610 }
611
612 /* Extract the FW meta info. */
613 memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params));
614
615 fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) -
616 PSP_HEADER_BYTES_256;
617 fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes);
618 fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data +
619 le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
620 PSP_HEADER_BYTES_256;
621 fw_meta_info_params.fw_bss_data = fw_meta_info_params.bss_data_size ? adev->dm.dmub_fw->data +
622 le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
623 le32_to_cpu(hdr->inst_const_bytes) : NULL;
624 fw_meta_info_params.custom_psp_footer_size = 0;
625
626 status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info);
627 if (status != DMUB_STATUS_OK) {
628 /* Skip returning early, just log the error. */
629 drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status);
630 }
631
632 /* Calculate the size of all the regions for the DMUB service. */
633 memset(&region_params, 0, sizeof(region_params));
634
635 region_params.inst_const_size = fw_meta_info_params.inst_const_size;
636 region_params.bss_data_size = fw_meta_info_params.bss_data_size;
637 region_params.vbios_size = adev->bios_size;
638 region_params.fw_bss_data = fw_meta_info_params.fw_bss_data;
639 region_params.fw_inst_const = fw_meta_info_params.fw_inst_const;
640 region_params.window_memory_type = window_memory_type;
641 region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL;
642
643 status = dmub_srv_calc_region_info(dmub_srv, &region_params,
644 &region_info);
645
646 if (status != DMUB_STATUS_OK) {
647 drm_err(adev_to_drm(adev), "Error calculating DMUB region info: %d\n", status);
648 return -EINVAL;
649 }
650
651 /* Limit to allocate dmub to GTT on DCN32/1
652 * TODO: Other asics with GDDR7 may have worse latency
653 */
654 if (dmub_asic != DMUB_ASIC_DCN32 &&
655 dmub_asic != DMUB_ASIC_DCN321)
656 mem_domain |= AMDGPU_GEM_DOMAIN_VRAM;
657
658 /*
659 * Allocate a framebuffer based on the total size of all the regions.
660 * TODO: Move this into GART.
661 */
662 r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE,
663 mem_domain,
664 &adev->dm.dmub_bo,
665 &adev->dm.dmub_bo_gpu_addr,
666 &adev->dm.dmub_bo_cpu_addr);
667 if (r)
668 return r;
669
670 /* Rebase the regions on the framebuffer address. */
671 memset(&memory_params, 0, sizeof(memory_params));
672 memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr;
673 memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr;
674 memory_params.region_info = &region_info;
675 memory_params.window_memory_type = window_memory_type;
676
677 adev->dm.dmub_fb_info = kzalloc_obj(*adev->dm.dmub_fb_info);
678 fb_info = adev->dm.dmub_fb_info;
679
680 if (!fb_info) {
681 drm_err(adev_to_drm(adev),
682 "Failed to allocate framebuffer info for DMUB service!\n");
683 return -ENOMEM;
684 }
685
686 status = dmub_srv_calc_mem_info(dmub_srv, &memory_params, fb_info);
687 if (status != DMUB_STATUS_OK) {
688 drm_err(adev_to_drm(adev), "Error calculating DMUB FB info: %d\n", status);
689 return -EINVAL;
690 }
691
692 adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev);
693 adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size;
694
695 return 0;
696}
697EXPORT_IF_KUNIT(dm_dmub_sw_init);
698
699int dm_init_microcode(struct amdgpu_device *adev)
700{
701 char *fw_name_dmub;
702 int r;
703
704 switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
705 case IP_VERSION(2, 1, 0):
706 fw_name_dmub = FIRMWARE_RENOIR_DMUB;
707 if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id))
708 fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB;
709 break;
710 case IP_VERSION(3, 0, 0):
711 if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 0))
712 fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB;
713 else
714 fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB;
715 break;
716 case IP_VERSION(3, 0, 1):
717 fw_name_dmub = FIRMWARE_VANGOGH_DMUB;
718 break;
719 case IP_VERSION(3, 0, 2):
720 fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB;
721 break;
722 case IP_VERSION(3, 0, 3):
723 fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB;
724 break;
725 case IP_VERSION(3, 1, 2):
726 case IP_VERSION(3, 1, 3):
727 fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB;
728 break;
729 case IP_VERSION(3, 1, 4):
730 fw_name_dmub = FIRMWARE_DCN_314_DMUB;
731 break;
732 case IP_VERSION(3, 1, 5):
733 fw_name_dmub = FIRMWARE_DCN_315_DMUB;
734 break;
735 case IP_VERSION(3, 1, 6):
736 fw_name_dmub = FIRMWARE_DCN316_DMUB;
737 break;
738 case IP_VERSION(3, 2, 0):
739 fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB;
740 break;
741 case IP_VERSION(3, 2, 1):
742 fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB;
743 break;
744 case IP_VERSION(3, 5, 0):
745 fw_name_dmub = FIRMWARE_DCN_35_DMUB;
746 break;
747 case IP_VERSION(3, 5, 1):
748 fw_name_dmub = FIRMWARE_DCN_351_DMUB;
749 break;
750 case IP_VERSION(3, 6, 0):
751 fw_name_dmub = FIRMWARE_DCN_36_DMUB;
752 break;
753 case IP_VERSION(4, 0, 1):
754 fw_name_dmub = FIRMWARE_DCN_401_DMUB;
755 break;
756 case IP_VERSION(4, 2, 0):
757 fw_name_dmub = FIRMWARE_DCN_42_DMUB;
758 break;
759 case IP_VERSION(4, 2, 1):
760 fw_name_dmub = FIRMWARE_DCN_42B_DMUB;
761 break;
762 case IP_VERSION(6, 0, 0):
763 fw_name_dmub = FIRMWARE_DCN_60_DMUB;
764 break;
765 default:
766 /* ASIC doesn't support DMUB. */
767 return 0;
768 }
769 r = amdgpu_ucode_request(adev, &adev->dm.dmub_fw, AMDGPU_UCODE_REQUIRED,
770 "%s", fw_name_dmub);
771 return r;
772}
773EXPORT_IF_KUNIT(dm_init_microcode);
774
775int amdgpu_dm_process_dmub_aux_transfer_sync(
776 struct dc_context *ctx,
777 unsigned int link_index,
778 struct aux_payload *payload,
779 enum aux_return_code_type *operation_result)
780{
781 struct amdgpu_device *adev = ctx->driver_context;
782 struct dmub_notification *p_notify = adev->dm.dmub_notify;
783 int ret = -1;
784
785 mutex_lock(&adev->dm.dpia_aux_lock);
786 if (!dc_process_dmub_aux_transfer_async(ctx->dc, link_index, payload)) {
787 *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
788 goto out;
789 }
790
791 if (!wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
792 drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!");
793 *operation_result = AUX_RET_ERROR_TIMEOUT;
794 goto out;
795 }
796
797 if (p_notify->result != AUX_RET_SUCCESS) {
798 /*
799 * Transient states before tunneling is enabled could
800 * lead to this error. We can ignore this for now.
801 */
802 if (p_notify->result == AUX_RET_ERROR_PROTOCOL_ERROR) {
803 drm_warn(adev_to_drm(adev), "DPIA AUX failed on 0x%x(%d), error %d\n",
804 payload->address, payload->length,
805 p_notify->result);
806 }
807 *operation_result = p_notify->result;
808 goto out;
809 }
810
811 payload->reply[0] = adev->dm.dmub_notify->aux_reply.command & 0xF;
812 if (adev->dm.dmub_notify->aux_reply.command & 0xF0)
813 /* The reply is stored in the top nibble of the command. */
814 payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF;
815
816 /*write req may receive a byte indicating partially written number as well*/
817 if (p_notify->aux_reply.length && payload->data) {
818 /* Bound the reply to the scratch buffer it was read into. */
819 ret = min_t(uint32_t, p_notify->aux_reply.length,
820 sizeof(p_notify->aux_reply.data));
821
822 /*
823 * During a write-status-update retry the caller zeroes
824 * payload->length while still expecting the partial-write
825 * status byte in payload->data (see dce_aux_transfer_with_retries),
826 * so only clamp to payload->length for regular transfers.
827 */
828 if (!payload->write_status_update)
829 ret = min_t(int, ret, payload->length);
830
831 memcpy(payload->data, p_notify->aux_reply.data, ret);
832 } else {
833 /* success */
834 ret = p_notify->aux_reply.length;
835 }
836
837 *operation_result = p_notify->result;
838out:
839 reinit_completion(&adev->dm.dmub_aux_transfer_done);
840 mutex_unlock(&adev->dm.dpia_aux_lock);
841 return ret;
842}
843EXPORT_IF_KUNIT(amdgpu_dm_process_dmub_aux_transfer_sync);
844
845STATIC_IFN_KUNIT void abort_fused_io(
846 struct dc_context *ctx,
847 const struct dmub_cmd_fused_request *request
848)
849{
850 union dmub_rb_cmd command = { 0 };
851 struct dmub_rb_cmd_fused_io *io = &command.fused_io;
852
853 io->header.type = DMUB_CMD__FUSED_IO;
854 io->header.sub_type = DMUB_CMD__FUSED_IO_ABORT;
855 io->header.payload_bytes = sizeof(*io) - sizeof(io->header);
856 io->request = *request;
857 dm_execute_dmub_cmd(ctx, &command, DM_DMUB_WAIT_TYPE_NO_WAIT);
858}
859EXPORT_IF_KUNIT(abort_fused_io);
860
861static bool execute_fused_io(
862 struct amdgpu_device *dev,
863 struct dc_context *ctx,
864 union dmub_rb_cmd *commands,
865 uint8_t count,
866 uint32_t timeout_us
867)
868{
869 const uint8_t ddc_line = commands[0].fused_io.request.u.aux.ddc_line;
870
871 if (ddc_line >= ARRAY_SIZE(dev->dm.fused_io))
872 return false;
873
874 struct fused_io_sync *sync = &dev->dm.fused_io[ddc_line];
875 struct dmub_rb_cmd_fused_io *first = &commands[0].fused_io;
876 const bool result = dm_execute_dmub_cmd_list(ctx, count, commands, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)
877 && first->header.ret_status
878 && first->request.status == FUSED_REQUEST_STATUS_SUCCESS;
879
880 if (!result)
881 return false;
882
883 while (wait_for_completion_timeout(&sync->replied, usecs_to_jiffies(timeout_us))) {
884 reinit_completion(&sync->replied);
885
886 struct dmub_cmd_fused_request *reply = (struct dmub_cmd_fused_request *) sync->reply_data;
887
888 static_assert(sizeof(*reply) <= sizeof(sync->reply_data), "Size mismatch");
889
890 if (reply->identifier == first->request.identifier) {
891 first->request = *reply;
892 return true;
893 }
894 }
895
896 reinit_completion(&sync->replied);
897 first->request.status = FUSED_REQUEST_STATUS_TIMEOUT;
898 abort_fused_io(ctx, &first->request);
899 return false;
900}
901
902bool amdgpu_dm_execute_fused_io(
903 struct amdgpu_device *dev,
904 struct dc_link *link,
905 union dmub_rb_cmd *commands,
906 uint8_t count,
907 uint32_t timeout_us)
908{
909 struct amdgpu_display_manager *dm = &dev->dm;
910
911 mutex_lock(&dm->dpia_aux_lock);
912
913 const bool result = execute_fused_io(dev, link->ctx, commands, count, timeout_us);
914
915 mutex_unlock(&dm->dpia_aux_lock);
916 return result;
917}
918
919int amdgpu_dm_process_dmub_set_config_sync(
920 struct dc_context *ctx,
921 unsigned int link_index,
922 struct set_config_cmd_payload *payload,
923 enum set_config_status *operation_result)
924{
925 struct amdgpu_device *adev = ctx->driver_context;
926 bool is_cmd_complete;
927 int ret;
928
929 mutex_lock(&adev->dm.dpia_aux_lock);
930 is_cmd_complete = dc_process_dmub_set_config_async(ctx->dc,
931 link_index, payload, adev->dm.dmub_notify);
932
933 if (is_cmd_complete || wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
934 ret = 0;
935 *operation_result = adev->dm.dmub_notify->sc_status;
936 } else {
937 drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!");
938 ret = -1;
939 *operation_result = SET_CONFIG_UNKNOWN_ERROR;
940 }
941
942 if (!is_cmd_complete)
943 reinit_completion(&adev->dm.dmub_aux_transfer_done);
944 mutex_unlock(&adev->dm.dpia_aux_lock);
945 return ret;
946}
947EXPORT_IF_KUNIT(amdgpu_dm_process_dmub_set_config_sync);
948
949bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
950{
951 struct amdgpu_device *adev = ctx->driver_context;
952
953 guard(spinlock_irqsave)(&adev->dm.dmub_lock);
954 return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type);
955}
956EXPORT_IF_KUNIT(dm_execute_dmub_cmd);
957
958bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
959{
960 struct amdgpu_device *adev = ctx->driver_context;
961
962 guard(spinlock_irqsave)(&adev->dm.dmub_lock);
963 return dc_dmub_srv_cmd_run_list(ctx->dmub_srv, count, cmd, wait_type);
964}