1// SPDX-License-Identifier: MIT
2//
3// Copyright 2024 Advanced Micro Devices, Inc.
4
5#include "../dmub_srv.h"
6#include "dmub_reg.h"
7#include "dmub_dcn401.h"
8
9#include "dcn/dcn_4_1_0_offset.h"
10#include "dcn/dcn_4_1_0_sh_mask.h"
11
12#define DCN_BASE__INST0_SEG2 0x000034C0
13
14#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg
15#define CTX dmub
16#define REGS dmub->regs_dcn401
17#define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
18
19const struct dmub_srv_dcn401_regs dmub_srv_dcn401_regs = {
20#define DMUB_SR(reg) REG_OFFSET_EXP(reg),
21 {
22 DMUB_DCN401_REGS()
23 DMCUB_INTERNAL_REGS()
24 },
25#undef DMUB_SR
26
27#define DMUB_SF(reg, field) FD_MASK(reg, field),
28 { DMUB_DCN401_FIELDS() },
29#undef DMUB_SF
30
31#define DMUB_SF(reg, field) FD_SHIFT(reg, field),
32 { DMUB_DCN401_FIELDS() },
33#undef DMUB_SF
34};
35
36static void dmub_dcn401_get_fb_base_offset(struct dmub_srv *dmub,
37 uint64_t *fb_base,
38 uint64_t *fb_offset)
39{
40 uint32_t tmp;
41
42 if (dmub->fb_base || dmub->fb_offset) {
43 *fb_base = dmub->fb_base;
44 *fb_offset = dmub->fb_offset;
45 return;
46 }
47
48 REG_GET(DCN_VM_FB_LOCATION_BASE, FB_BASE, &tmp);
49 *fb_base = (uint64_t)tmp << 24;
50
51 REG_GET(DCN_VM_FB_OFFSET, FB_OFFSET, &tmp);
52 *fb_offset = (uint64_t)tmp << 24;
53}
54
55static inline void dmub_dcn401_translate_addr(const union dmub_addr *addr_in,
56 uint64_t fb_base,
57 uint64_t fb_offset,
58 union dmub_addr *addr_out)
59{
60 addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset;
61}
62
63void dmub_dcn401_reset(struct dmub_srv *dmub)
64{
65 union dmub_gpint_data_register cmd;
66 const uint32_t timeout_us = 1 * 1000 * 1000; //1s
67 const uint32_t poll_delay_us = 1; //1us
68 uint32_t i = 0;
69 uint32_t enabled, in_reset, scratch, pwait_mode;
70
71 REG_GET(DMCUB_CNTL,
72 DMCUB_ENABLE, &enabled);
73 REG_GET(DMCUB_CNTL2,
74 DMCUB_SOFT_RESET, &in_reset);
75
76 if (enabled && in_reset == 0) {
77 cmd.bits.status = 1;
78 cmd.bits.command_code = DMUB_GPINT__STOP_FW;
79 cmd.bits.param = 0;
80
81 dmub->hw_funcs.set_gpint(dmub, cmd);
82
83 for (; i < timeout_us; i++) {
84 scratch = REG_READ(DMCUB_SCRATCH7);
85 if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
86 break;
87
88 udelay(usec: poll_delay_us);
89 }
90
91 for (; i < timeout_us; i++) {
92 REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &pwait_mode);
93 if (pwait_mode & (1 << 0))
94 break;
95
96 udelay(usec: poll_delay_us);
97 }
98 }
99
100 if (enabled) {
101 REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
102 udelay(usec: 1);
103 REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
104 }
105
106 if (i >= timeout_us) {
107 /* timeout should never occur */
108 BREAK_TO_DEBUGGER();
109 }
110
111 REG_UPDATE(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_ENABLE, 0);
112 REG_UPDATE(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_ENABLE, 0);
113 REG_UPDATE(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_ENABLE, 0);
114 REG_UPDATE(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_ENABLE, 0);
115 REG_UPDATE(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, 0);
116 REG_UPDATE(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_ENABLE, 0);
117
118 REG_WRITE(DMCUB_INBOX1_RPTR, 0);
119 REG_WRITE(DMCUB_INBOX1_WPTR, 0);
120 REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
121 REG_WRITE(DMCUB_OUTBOX1_WPTR, 0);
122 REG_WRITE(DMCUB_OUTBOX0_RPTR, 0);
123 REG_WRITE(DMCUB_OUTBOX0_WPTR, 0);
124 REG_WRITE(DMCUB_SCRATCH0, 0);
125
126 /* Clear the GPINT command manually so we don't reset again. */
127 cmd.all = 0;
128 dmub->hw_funcs.set_gpint(dmub, cmd);
129}
130
131void dmub_dcn401_reset_release(struct dmub_srv *dmub)
132{
133 REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0);
134 REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF);
135 REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1);
136 REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 0);
137}
138
139void dmub_dcn401_backdoor_load(struct dmub_srv *dmub,
140 const struct dmub_window *cw0,
141 const struct dmub_window *cw1)
142{
143 union dmub_addr offset;
144 uint64_t fb_base, fb_offset;
145
146 dmub_dcn401_get_fb_base_offset(dmub, fb_base: &fb_base, fb_offset: &fb_offset);
147
148 /* reset and disable DMCUB and MMHUBBUB DMUIF */
149 REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
150 REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
151
152 dmub_dcn401_translate_addr(addr_in: &cw0->offset, fb_base, fb_offset, addr_out: &offset);
153
154 REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part);
155 REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part);
156 REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base);
157 REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0,
158 DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top,
159 DMCUB_REGION3_CW0_ENABLE, 1);
160
161 dmub_dcn401_translate_addr(addr_in: &cw1->offset, fb_base, fb_offset, addr_out: &offset);
162
163 REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part);
164 REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part);
165 REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base);
166 REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0,
167 DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
168 DMCUB_REGION3_CW1_ENABLE, 1);
169
170 /* release DMCUB reset only to prevent premature execution */
171 REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
172 0x20);
173}
174
175void dmub_dcn401_backdoor_load_zfb_mode(struct dmub_srv *dmub,
176 const struct dmub_window *cw0,
177 const struct dmub_window *cw1)
178{
179 union dmub_addr offset;
180
181 /* reset and disable DMCUB and MMHUBBUB DMUIF */
182 REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
183 REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
184
185 offset = cw0->offset;
186
187 REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part);
188 REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part);
189 REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base);
190 REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0,
191 DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top,
192 DMCUB_REGION3_CW0_ENABLE, 1);
193
194 offset = cw1->offset;
195
196 REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part);
197 REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part);
198 REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base);
199 REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0,
200 DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
201 DMCUB_REGION3_CW1_ENABLE, 1);
202
203 /* release DMCUB reset only to prevent premature execution */
204 REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
205 0x20);
206}
207
208void dmub_dcn401_setup_windows(struct dmub_srv *dmub,
209 const struct dmub_window *cw2,
210 const struct dmub_window *cw3,
211 const struct dmub_window *cw4,
212 const struct dmub_window *cw5,
213 const struct dmub_window *cw6,
214 const struct dmub_window *region6)
215{
216 union dmub_addr offset;
217
218 offset = cw3->offset;
219
220 REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part);
221 REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part);
222 REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base);
223 REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0,
224 DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top,
225 DMCUB_REGION3_CW3_ENABLE, 1);
226
227 offset = cw4->offset;
228
229 REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part);
230 REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part);
231 REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base);
232 REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0,
233 DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top,
234 DMCUB_REGION3_CW4_ENABLE, 1);
235
236 offset = cw5->offset;
237
238 REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part);
239 REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part);
240 REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base);
241 REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0,
242 DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top,
243 DMCUB_REGION3_CW5_ENABLE, 1);
244
245 REG_WRITE(DMCUB_REGION5_OFFSET, offset.u.low_part);
246 REG_WRITE(DMCUB_REGION5_OFFSET_HIGH, offset.u.high_part);
247 REG_SET_2(DMCUB_REGION5_TOP_ADDRESS, 0,
248 DMCUB_REGION5_TOP_ADDRESS,
249 cw5->region.top - cw5->region.base - 1,
250 DMCUB_REGION5_ENABLE, 1);
251
252 offset = cw6->offset;
253
254 REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part);
255 REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part);
256 REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base);
257 REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0,
258 DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top,
259 DMCUB_REGION3_CW6_ENABLE, 1);
260
261 offset = region6->offset;
262
263 REG_WRITE(DMCUB_REGION6_OFFSET, offset.u.low_part);
264 REG_WRITE(DMCUB_REGION6_OFFSET_HIGH, offset.u.high_part);
265 REG_SET_2(DMCUB_REGION6_TOP_ADDRESS, 0,
266 DMCUB_REGION6_TOP_ADDRESS,
267 region6->region.top - region6->region.base - 1,
268 DMCUB_REGION6_ENABLE, 1);
269}
270
271void dmub_dcn401_setup_mailbox(struct dmub_srv *dmub,
272 const struct dmub_region *inbox1)
273{
274 REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, inbox1->base);
275 REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base);
276}
277
278uint32_t dmub_dcn401_get_inbox1_wptr(struct dmub_srv *dmub)
279{
280 return REG_READ(DMCUB_INBOX1_WPTR);
281}
282
283uint32_t dmub_dcn401_get_inbox1_rptr(struct dmub_srv *dmub)
284{
285 return REG_READ(DMCUB_INBOX1_RPTR);
286}
287
288void dmub_dcn401_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset)
289{
290 REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset);
291}
292
293void dmub_dcn401_setup_out_mailbox(struct dmub_srv *dmub,
294 const struct dmub_region *outbox1)
295{
296 REG_WRITE(DMCUB_OUTBOX1_BASE_ADDRESS, outbox1->base);
297 REG_WRITE(DMCUB_OUTBOX1_SIZE, outbox1->top - outbox1->base);
298}
299
300uint32_t dmub_dcn401_get_outbox1_wptr(struct dmub_srv *dmub)
301{
302 /**
303 * outbox1 wptr register is accessed without locks (dal & dc)
304 * and to be called only by dmub_srv_stat_get_notification()
305 */
306 return REG_READ(DMCUB_OUTBOX1_WPTR);
307}
308
309void dmub_dcn401_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset)
310{
311 /**
312 * outbox1 rptr register is accessed without locks (dal & dc)
313 * and to be called only by dmub_srv_stat_get_notification()
314 */
315 REG_WRITE(DMCUB_OUTBOX1_RPTR, rptr_offset);
316}
317
318bool dmub_dcn401_is_hw_init(struct dmub_srv *dmub)
319{
320 union dmub_fw_boot_status status;
321 uint32_t is_hw_init;
322
323 status.all = REG_READ(DMCUB_SCRATCH0);
324 REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_hw_init);
325
326 return is_hw_init != 0 && status.bits.dal_fw;
327}
328
329bool dmub_dcn401_is_supported(struct dmub_srv *dmub)
330{
331 uint32_t supported = 0;
332
333 REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported);
334
335 return supported;
336}
337
338void dmub_dcn401_set_gpint(struct dmub_srv *dmub,
339 union dmub_gpint_data_register reg)
340{
341 REG_WRITE(DMCUB_GPINT_DATAIN1, reg.all);
342}
343
344bool dmub_dcn401_is_gpint_acked(struct dmub_srv *dmub,
345 union dmub_gpint_data_register reg)
346{
347 union dmub_gpint_data_register test;
348
349 reg.bits.status = 0;
350 test.all = REG_READ(DMCUB_GPINT_DATAIN1);
351
352 return test.all == reg.all;
353}
354
355uint32_t dmub_dcn401_get_gpint_response(struct dmub_srv *dmub)
356{
357 return REG_READ(DMCUB_SCRATCH7);
358}
359
360uint32_t dmub_dcn401_get_gpint_dataout(struct dmub_srv *dmub)
361{
362 uint32_t dataout = REG_READ(DMCUB_GPINT_DATAOUT);
363
364 REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 0);
365
366 REG_WRITE(DMCUB_GPINT_DATAOUT, 0);
367 REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 1);
368 REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 0);
369
370 REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 1);
371
372 return dataout;
373}
374
375union dmub_fw_boot_status dmub_dcn401_get_fw_boot_status(struct dmub_srv *dmub)
376{
377 union dmub_fw_boot_status status;
378
379 status.all = REG_READ(DMCUB_SCRATCH0);
380 return status;
381}
382
383void dmub_dcn401_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params)
384{
385 union dmub_fw_boot_options boot_options = {0};
386
387 boot_options.bits.z10_disable = params->disable_z10;
388
389 boot_options.bits.skip_phy_access = params->disallow_phy_access;
390
391 REG_WRITE(DMCUB_SCRATCH14, boot_options.all);
392}
393
394void dmub_dcn401_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip)
395{
396 union dmub_fw_boot_options boot_options;
397 boot_options.all = REG_READ(DMCUB_SCRATCH14);
398 boot_options.bits.skip_phy_init_panel_sequence = skip;
399 REG_WRITE(DMCUB_SCRATCH14, boot_options.all);
400}
401
402void dmub_dcn401_setup_outbox0(struct dmub_srv *dmub,
403 const struct dmub_region *outbox0)
404{
405 REG_WRITE(DMCUB_OUTBOX0_BASE_ADDRESS, outbox0->base);
406
407 REG_WRITE(DMCUB_OUTBOX0_SIZE, outbox0->top - outbox0->base);
408}
409
410uint32_t dmub_dcn401_get_outbox0_wptr(struct dmub_srv *dmub)
411{
412 return REG_READ(DMCUB_OUTBOX0_WPTR);
413}
414
415void dmub_dcn401_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset)
416{
417 REG_WRITE(DMCUB_OUTBOX0_RPTR, rptr_offset);
418}
419
420uint32_t dmub_dcn401_get_current_time(struct dmub_srv *dmub)
421{
422 return REG_READ(DMCUB_TIMER_CURRENT);
423}
424
425void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub)
426{
427 uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset, is_pwait;
428 uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled;
429 struct dmub_timeout_info timeout = {0};
430
431 if (!dmub)
432 return;
433
434 /* timeout data filled externally, cache before resetting memory */
435 timeout = dmub->debug.timeout_info;
436 memset(&dmub->debug, 0, sizeof(dmub->debug));
437 dmub->debug.timeout_info = timeout;
438
439 dmub->debug.dmcub_version = dmub->fw_version;
440
441 dmub->debug.scratch[0] = REG_READ(DMCUB_SCRATCH0);
442 dmub->debug.scratch[1] = REG_READ(DMCUB_SCRATCH1);
443 dmub->debug.scratch[2] = REG_READ(DMCUB_SCRATCH2);
444 dmub->debug.scratch[3] = REG_READ(DMCUB_SCRATCH3);
445 dmub->debug.scratch[4] = REG_READ(DMCUB_SCRATCH4);
446 dmub->debug.scratch[5] = REG_READ(DMCUB_SCRATCH5);
447 dmub->debug.scratch[6] = REG_READ(DMCUB_SCRATCH6);
448 dmub->debug.scratch[7] = REG_READ(DMCUB_SCRATCH7);
449 dmub->debug.scratch[8] = REG_READ(DMCUB_SCRATCH8);
450 dmub->debug.scratch[9] = REG_READ(DMCUB_SCRATCH9);
451 dmub->debug.scratch[10] = REG_READ(DMCUB_SCRATCH10);
452 dmub->debug.scratch[11] = REG_READ(DMCUB_SCRATCH11);
453 dmub->debug.scratch[12] = REG_READ(DMCUB_SCRATCH12);
454 dmub->debug.scratch[13] = REG_READ(DMCUB_SCRATCH13);
455 dmub->debug.scratch[14] = REG_READ(DMCUB_SCRATCH14);
456 dmub->debug.scratch[15] = REG_READ(DMCUB_SCRATCH15);
457 dmub->debug.scratch[16] = REG_READ(DMCUB_SCRATCH16);
458
459 dmub->debug.undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR);
460 dmub->debug.inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR);
461 dmub->debug.data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR);
462
463 dmub->debug.inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR);
464 dmub->debug.inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR);
465 dmub->debug.inbox1_size = REG_READ(DMCUB_INBOX1_SIZE);
466
467 dmub->debug.inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR);
468 dmub->debug.inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR);
469 dmub->debug.inbox0_size = REG_READ(DMCUB_INBOX0_SIZE);
470
471 dmub->debug.outbox1_rptr = REG_READ(DMCUB_OUTBOX1_RPTR);
472 dmub->debug.outbox1_wptr = REG_READ(DMCUB_OUTBOX1_WPTR);
473 dmub->debug.outbox1_size = REG_READ(DMCUB_OUTBOX1_SIZE);
474
475 REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled);
476 dmub->debug.is_dmcub_enabled = is_dmub_enabled;
477
478 REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &is_pwait);
479 dmub->debug.is_pwait = is_pwait;
480
481 REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset);
482 dmub->debug.is_dmcub_soft_reset = is_soft_reset;
483
484 REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset);
485 dmub->debug.is_dmcub_secure_reset = is_sec_reset;
486
487 REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled);
488 dmub->debug.is_traceport_en = is_traceport_enabled;
489
490 REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled);
491 dmub->debug.is_cw0_enabled = is_cw0_enabled;
492
493 REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled);
494 dmub->debug.is_cw6_enabled = is_cw6_enabled;
495
496 dmub->debug.gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0);
497}
498void dmub_dcn401_configure_dmub_in_system_memory(struct dmub_srv *dmub)
499{
500 /* DMCUB_REGION3_TMR_AXI_SPACE values:
501 * 0b011 (0x3) - FB physical address
502 * 0b100 (0x4) - GPU virtual address
503 *
504 * Default value is 0x3 (FB Physical address for TMR). When programming
505 * DMUB to be in system memory, change to 0x4. The system memory allocated
506 * is accessible by both GPU and CPU, so we use GPU virtual address.
507 */
508 REG_WRITE(DMCUB_REGION3_TMR_AXI_SPACE, 0x4);
509}
510
511void dmub_dcn401_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data)
512{
513 REG_WRITE(DMCUB_INBOX0_WPTR, data.inbox0_cmd_common.all);
514}
515
516void dmub_dcn401_clear_inbox0_ack_register(struct dmub_srv *dmub)
517{
518 REG_WRITE(DMCUB_SCRATCH17, 0);
519}
520
521uint32_t dmub_dcn401_read_inbox0_ack_register(struct dmub_srv *dmub)
522{
523 return REG_READ(DMCUB_SCRATCH17);
524}
525
526void dmub_dcn401_send_reg_inbox0_cmd_msg(struct dmub_srv *dmub,
527 union dmub_rb_cmd *cmd)
528{
529 uint32_t *dwords = (uint32_t *)cmd;
530 int32_t payload_size_bytes = cmd->cmd_common.header.payload_bytes;
531 uint32_t msg_index;
532 static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch");
533
534 /* read remaining data based on payload size */
535 for (msg_index = 0; msg_index < 15; msg_index++) {
536 if (payload_size_bytes <= msg_index * 4) {
537 break;
538 }
539
540 switch (msg_index) {
541 case 0:
542 REG_WRITE(DMCUB_REG_INBOX0_MSG0, dwords[msg_index + 1]);
543 break;
544 case 1:
545 REG_WRITE(DMCUB_REG_INBOX0_MSG1, dwords[msg_index + 1]);
546 break;
547 case 2:
548 REG_WRITE(DMCUB_REG_INBOX0_MSG2, dwords[msg_index + 1]);
549 break;
550 case 3:
551 REG_WRITE(DMCUB_REG_INBOX0_MSG3, dwords[msg_index + 1]);
552 break;
553 case 4:
554 REG_WRITE(DMCUB_REG_INBOX0_MSG4, dwords[msg_index + 1]);
555 break;
556 case 5:
557 REG_WRITE(DMCUB_REG_INBOX0_MSG5, dwords[msg_index + 1]);
558 break;
559 case 6:
560 REG_WRITE(DMCUB_REG_INBOX0_MSG6, dwords[msg_index + 1]);
561 break;
562 case 7:
563 REG_WRITE(DMCUB_REG_INBOX0_MSG7, dwords[msg_index + 1]);
564 break;
565 case 8:
566 REG_WRITE(DMCUB_REG_INBOX0_MSG8, dwords[msg_index + 1]);
567 break;
568 case 9:
569 REG_WRITE(DMCUB_REG_INBOX0_MSG9, dwords[msg_index + 1]);
570 break;
571 case 10:
572 REG_WRITE(DMCUB_REG_INBOX0_MSG10, dwords[msg_index + 1]);
573 break;
574 case 11:
575 REG_WRITE(DMCUB_REG_INBOX0_MSG11, dwords[msg_index + 1]);
576 break;
577 case 12:
578 REG_WRITE(DMCUB_REG_INBOX0_MSG12, dwords[msg_index + 1]);
579 break;
580 case 13:
581 REG_WRITE(DMCUB_REG_INBOX0_MSG13, dwords[msg_index + 1]);
582 break;
583 case 14:
584 REG_WRITE(DMCUB_REG_INBOX0_MSG14, dwords[msg_index + 1]);
585 break;
586 }
587 }
588
589 /* writing to INBOX RDY register will trigger DMUB REG INBOX0 RDY
590 * interrupt.
591 */
592 REG_WRITE(DMCUB_REG_INBOX0_RDY, dwords[0]);
593}
594
595uint32_t dmub_dcn401_read_reg_inbox0_rsp_int_status(struct dmub_srv *dmub)
596{
597 uint32_t status;
598
599 REG_GET(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_STAT, &status);
600 return status;
601}
602
603void dmub_dcn401_read_reg_inbox0_cmd_rsp(struct dmub_srv *dmub,
604 union dmub_rb_cmd *cmd)
605{
606 uint32_t *dwords = (uint32_t *)cmd;
607
608 static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch");
609
610 dwords[0] = REG_READ(DMCUB_REG_INBOX0_RSP);
611 dwords[1] = REG_READ(DMCUB_REG_INBOX0_MSG0);
612 dwords[2] = REG_READ(DMCUB_REG_INBOX0_MSG1);
613 dwords[3] = REG_READ(DMCUB_REG_INBOX0_MSG2);
614 dwords[4] = REG_READ(DMCUB_REG_INBOX0_MSG3);
615 dwords[5] = REG_READ(DMCUB_REG_INBOX0_MSG4);
616 dwords[6] = REG_READ(DMCUB_REG_INBOX0_MSG5);
617 dwords[7] = REG_READ(DMCUB_REG_INBOX0_MSG6);
618 dwords[8] = REG_READ(DMCUB_REG_INBOX0_MSG7);
619 dwords[9] = REG_READ(DMCUB_REG_INBOX0_MSG8);
620 dwords[10] = REG_READ(DMCUB_REG_INBOX0_MSG9);
621 dwords[11] = REG_READ(DMCUB_REG_INBOX0_MSG10);
622 dwords[12] = REG_READ(DMCUB_REG_INBOX0_MSG11);
623 dwords[13] = REG_READ(DMCUB_REG_INBOX0_MSG12);
624 dwords[14] = REG_READ(DMCUB_REG_INBOX0_MSG13);
625 dwords[15] = REG_READ(DMCUB_REG_INBOX0_MSG14);
626}
627
628void dmub_dcn401_write_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub)
629{
630 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 1);
631}
632
633void dmub_dcn401_clear_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub)
634{
635 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 0);
636}
637
638void dmub_dcn401_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable)
639{
640 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN, enable ? 1:0);
641}
642
643void dmub_dcn401_write_reg_outbox0_rdy_int_ack(struct dmub_srv *dmub)
644{
645 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK, 1);
646 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK, 0);
647}
648
649void dmub_dcn401_read_reg_outbox0_msg(struct dmub_srv *dmub, uint32_t *msg)
650{
651 *msg = REG_READ(DMCUB_REG_OUTBOX0_MSG0);
652}
653
654void dmub_dcn401_write_reg_outbox0_rsp(struct dmub_srv *dmub, uint32_t *rsp)
655{
656 REG_WRITE(DMCUB_REG_OUTBOX0_RSP, *rsp);
657}
658
659uint32_t dmub_dcn401_read_reg_outbox0_rsp_int_status(struct dmub_srv *dmub)
660{
661 uint32_t status;
662
663 REG_GET(DMCUB_INTERRUPT_STATUS, DMCUB_REG_OUTBOX0_RSP_INT_STAT, &status);
664 return status;
665}
666
667void dmub_dcn401_enable_reg_outbox0_rdy_int(struct dmub_srv *dmub, bool enable)
668{
669 REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN, enable ? 1:0);
670}
671
672uint32_t dmub_dcn401_read_reg_outbox0_rdy_int_status(struct dmub_srv *dmub)
673{
674 uint32_t status;
675
676 REG_GET(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_STAT, &status);
677 return status;
678}
679

source code of linux/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c