2 * Copyright 2020 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "../dmub_srv.h"
28 #include "dmub_dcn31.h"
30 #include "yellow_carp_offset.h"
31 #include "dcn/dcn_3_1_2_offset.h"
32 #include "dcn/dcn_3_1_2_sh_mask.h"
34 #define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg
36 #define REGS dmub->regs_dcn31
37 #define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
39 const struct dmub_srv_dcn31_regs dmub_srv_dcn31_regs = {
40 #define DMUB_SR(reg) REG_OFFSET_EXP(reg),
41 { DMUB_DCN31_REGS() },
44 #define DMUB_SF(reg, field) FD_MASK(reg, field),
45 { DMUB_DCN31_FIELDS() },
48 #define DMUB_SF(reg, field) FD_SHIFT(reg, field),
49 { DMUB_DCN31_FIELDS() },
53 static void dmub_dcn31_get_fb_base_offset(struct dmub_srv *dmub,
59 if (dmub->fb_base || dmub->fb_offset) {
60 *fb_base = dmub->fb_base;
61 *fb_offset = dmub->fb_offset;
65 REG_GET(DCN_VM_FB_LOCATION_BASE, FB_BASE, &tmp);
66 *fb_base = (uint64_t)tmp << 24;
68 REG_GET(DCN_VM_FB_OFFSET, FB_OFFSET, &tmp);
69 *fb_offset = (uint64_t)tmp << 24;
72 static inline void dmub_dcn31_translate_addr(const union dmub_addr *addr_in,
75 union dmub_addr *addr_out)
77 addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset;
80 void dmub_dcn31_reset(struct dmub_srv *dmub)
82 union dmub_gpint_data_register cmd;
83 const uint32_t timeout = 30;
84 uint32_t in_reset, scratch, i;
86 REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
90 cmd.bits.command_code = DMUB_GPINT__STOP_FW;
93 dmub->hw_funcs.set_gpint(dmub, cmd);
96 * Timeout covers both the ACK and the wait
97 * for remaining work to finish.
99 * This is mostly bound by the PHY disable sequence.
100 * Each register check will be greater than 1us, so
101 * don't bother using udelay.
104 for (i = 0; i < timeout; ++i) {
105 if (dmub->hw_funcs.is_gpint_acked(dmub, cmd))
109 for (i = 0; i < timeout; ++i) {
110 scratch = dmub->hw_funcs.get_gpint_response(dmub);
111 if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
115 /* Clear the GPINT command manually so we don't reset again. */
117 dmub->hw_funcs.set_gpint(dmub, cmd);
119 /* Force reset in case we timed out, DMCUB is likely hung. */
122 REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
123 REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
124 REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
125 REG_WRITE(DMCUB_INBOX1_RPTR, 0);
126 REG_WRITE(DMCUB_INBOX1_WPTR, 0);
127 REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
128 REG_WRITE(DMCUB_OUTBOX1_WPTR, 0);
129 REG_WRITE(DMCUB_SCRATCH0, 0);
132 void dmub_dcn31_reset_release(struct dmub_srv *dmub)
134 REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0);
135 REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF);
136 REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1);
137 REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 0);
140 void dmub_dcn31_backdoor_load(struct dmub_srv *dmub,
141 const struct dmub_window *cw0,
142 const struct dmub_window *cw1)
144 union dmub_addr offset;
145 uint64_t fb_base, fb_offset;
147 dmub_dcn31_get_fb_base_offset(dmub, &fb_base, &fb_offset);
149 REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
151 dmub_dcn31_translate_addr(&cw0->offset, fb_base, fb_offset, &offset);
153 REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part);
154 REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part);
155 REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base);
156 REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0,
157 DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top,
158 DMCUB_REGION3_CW0_ENABLE, 1);
160 dmub_dcn31_translate_addr(&cw1->offset, fb_base, fb_offset, &offset);
162 REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part);
163 REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part);
164 REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base);
165 REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0,
166 DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
167 DMCUB_REGION3_CW1_ENABLE, 1);
169 REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
173 void dmub_dcn31_setup_windows(struct dmub_srv *dmub,
174 const struct dmub_window *cw2,
175 const struct dmub_window *cw3,
176 const struct dmub_window *cw4,
177 const struct dmub_window *cw5,
178 const struct dmub_window *cw6)
180 union dmub_addr offset;
182 offset = cw3->offset;
184 REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part);
185 REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part);
186 REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base);
187 REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0,
188 DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top,
189 DMCUB_REGION3_CW3_ENABLE, 1);
191 offset = cw4->offset;
193 REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part);
194 REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part);
195 REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base);
196 REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0,
197 DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top,
198 DMCUB_REGION3_CW4_ENABLE, 1);
200 offset = cw5->offset;
202 REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part);
203 REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part);
204 REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base);
205 REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0,
206 DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top,
207 DMCUB_REGION3_CW5_ENABLE, 1);
209 REG_WRITE(DMCUB_REGION5_OFFSET, offset.u.low_part);
210 REG_WRITE(DMCUB_REGION5_OFFSET_HIGH, offset.u.high_part);
211 REG_SET_2(DMCUB_REGION5_TOP_ADDRESS, 0,
212 DMCUB_REGION5_TOP_ADDRESS,
213 cw5->region.top - cw5->region.base - 1,
214 DMCUB_REGION5_ENABLE, 1);
216 offset = cw6->offset;
218 REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part);
219 REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part);
220 REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base);
221 REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0,
222 DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top,
223 DMCUB_REGION3_CW6_ENABLE, 1);
226 void dmub_dcn31_setup_mailbox(struct dmub_srv *dmub,
227 const struct dmub_region *inbox1)
229 REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, inbox1->base);
230 REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base);
233 uint32_t dmub_dcn31_get_inbox1_rptr(struct dmub_srv *dmub)
235 return REG_READ(DMCUB_INBOX1_RPTR);
238 void dmub_dcn31_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset)
240 REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset);
243 void dmub_dcn31_setup_out_mailbox(struct dmub_srv *dmub,
244 const struct dmub_region *outbox1)
246 REG_WRITE(DMCUB_OUTBOX1_BASE_ADDRESS, outbox1->base);
247 REG_WRITE(DMCUB_OUTBOX1_SIZE, outbox1->top - outbox1->base);
250 uint32_t dmub_dcn31_get_outbox1_wptr(struct dmub_srv *dmub)
253 * outbox1 wptr register is accessed without locks (dal & dc)
254 * and to be called only by dmub_srv_stat_get_notification()
256 return REG_READ(DMCUB_OUTBOX1_WPTR);
259 void dmub_dcn31_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset)
262 * outbox1 rptr register is accessed without locks (dal & dc)
263 * and to be called only by dmub_srv_stat_get_notification()
265 REG_WRITE(DMCUB_OUTBOX1_RPTR, rptr_offset);
268 bool dmub_dcn31_is_hw_init(struct dmub_srv *dmub)
272 REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_hw_init);
274 return is_hw_init != 0;
277 bool dmub_dcn31_is_supported(struct dmub_srv *dmub)
279 uint32_t supported = 0;
281 REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported);
286 void dmub_dcn31_set_gpint(struct dmub_srv *dmub,
287 union dmub_gpint_data_register reg)
289 REG_WRITE(DMCUB_GPINT_DATAIN1, reg.all);
292 bool dmub_dcn31_is_gpint_acked(struct dmub_srv *dmub,
293 union dmub_gpint_data_register reg)
295 union dmub_gpint_data_register test;
298 test.all = REG_READ(DMCUB_GPINT_DATAIN1);
300 return test.all == reg.all;
303 uint32_t dmub_dcn31_get_gpint_response(struct dmub_srv *dmub)
305 return REG_READ(DMCUB_SCRATCH7);
308 union dmub_fw_boot_status dmub_dcn31_get_fw_boot_status(struct dmub_srv *dmub)
310 union dmub_fw_boot_status status;
312 status.all = REG_READ(DMCUB_SCRATCH0);
316 void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params)
318 union dmub_fw_boot_options boot_options = {0};
320 boot_options.bits.z10_disable = params->disable_z10;
322 REG_WRITE(DMCUB_SCRATCH14, boot_options.all);
325 void dmub_dcn31_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip)
327 union dmub_fw_boot_options boot_options;
328 boot_options.all = REG_READ(DMCUB_SCRATCH14);
329 boot_options.bits.skip_phy_init_panel_sequence = skip;
330 REG_WRITE(DMCUB_SCRATCH14, boot_options.all);
333 void dmub_dcn31_setup_outbox0(struct dmub_srv *dmub,
334 const struct dmub_region *outbox0)
336 REG_WRITE(DMCUB_OUTBOX0_BASE_ADDRESS, outbox0->base);
338 REG_WRITE(DMCUB_OUTBOX0_SIZE, outbox0->top - outbox0->base);
341 uint32_t dmub_dcn31_get_outbox0_wptr(struct dmub_srv *dmub)
343 return REG_READ(DMCUB_OUTBOX0_WPTR);
346 void dmub_dcn31_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset)
348 REG_WRITE(DMCUB_OUTBOX0_RPTR, rptr_offset);
351 uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub)
353 return REG_READ(DMCUB_TIMER_CURRENT);
356 void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
358 uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset;
359 uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled;
361 if (!dmub || !diag_data)
364 memset(diag_data, 0, sizeof(*diag_data));
366 diag_data->dmcub_version = dmub->fw_version;
368 diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0);
369 diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1);
370 diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2);
371 diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3);
372 diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4);
373 diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5);
374 diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6);
375 diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7);
376 diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8);
377 diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9);
378 diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10);
379 diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11);
380 diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12);
381 diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13);
382 diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14);
383 diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15);
385 diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR);
386 diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR);
387 diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR);
389 diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR);
390 diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR);
391 diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE);
393 diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR);
394 diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR);
395 diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE);
397 REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled);
398 diag_data->is_dmcub_enabled = is_dmub_enabled;
400 REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset);
401 diag_data->is_dmcub_soft_reset = is_soft_reset;
403 REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset);
404 diag_data->is_dmcub_secure_reset = is_sec_reset;
406 REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled);
407 diag_data->is_traceport_en = is_traceport_enabled;
409 REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled);
410 diag_data->is_cw0_enabled = is_cw0_enabled;
412 REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled);
413 diag_data->is_cw6_enabled = is_cw6_enabled;