xref: /linux/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2019-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 #include "../dmub_srv.h"
27 #include "dmub_dcn20.h"
28 #include "dmub_dcn21.h"
29 #include "dmub_cmd.h"
30 #include "dmub_dcn30.h"
31 #include "dmub_dcn301.h"
32 #include "dmub_dcn302.h"
33 #include "dmub_dcn303.h"
34 #include "dmub_dcn31.h"
35 #include "dmub_dcn314.h"
36 #include "dmub_dcn315.h"
37 #include "dmub_dcn316.h"
38 #include "dmub_dcn32.h"
39 #include "dmub_dcn35.h"
40 #include "dmub_dcn351.h"
41 #include "dmub_dcn36.h"
42 #include "dmub_dcn401.h"
43 #include "dmub_dcn42.h"
44 #include "dmub_dcn42b.h"
45 #include "os_types.h"
46 /*
47  * Note: the DMUB service is standalone. No additional headers should be
48  * added below or above this line unless they reside within the DMUB
49  * folder.
50  */
51 
52 /* Alignment for framebuffer memory. */
53 #define DMUB_FB_ALIGNMENT (1024 * 1024)
54 
55 /* Stack size. */
56 #define DMUB_STACK_SIZE (128 * 1024)
57 
58 /* Context size. */
59 #define DMUB_CONTEXT_SIZE (512 * 1024)
60 
61 /* Mailbox size : Ring buffers are required for both inbox and outbox */
62 #define DMUB_MAILBOX_SIZE ((2 * DMUB_RB_SIZE))
63 
64 /* Default state size if meta is absent. */
65 #define DMUB_FW_STATE_SIZE (64 * 1024)
66 
67 /* Default scratch mem size. */
68 #define DMUB_SCRATCH_MEM_SIZE (1024)
69 
70 /* Default indirect buffer size. */
71 #define DMUB_IB_MEM_SIZE (sizeof(struct dmub_fams2_config_v2))
72 
73 /* Default LSDMA ring buffer size. */
74 #define DMUB_LSDMA_RB_SIZE (64 * 1024)
75 
76 /* Number of windows in use. */
77 #define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL)
78 /* Base addresses. */
79 
80 #define DMUB_CW0_BASE (0x60000000)
81 #define DMUB_CW1_BASE (0x61000000)
82 #define DMUB_CW3_BASE (0x63000000)
83 #define DMUB_CW4_BASE (0x64000000)
84 #define DMUB_CW5_BASE (0x65000000)
85 #define DMUB_CW6_BASE (0x66000000)
86 
87 #define DMUB_REGION5_BASE (0xA0000000)
88 #define DMUB_REGION6_BASE (0xC0000000)
89 
90 static struct dmub_srv_dcn32_regs dmub_srv_dcn32_regs;
91 static struct dmub_srv_dcn35_regs dmub_srv_dcn35_regs;
92 struct dmub_srv_dcn42_regs dmub_srv_dcn42_regs;
93 
94 static inline uint32_t dmub_align(uint32_t val, uint32_t factor)
95 {
96 	return (val + factor - 1) / factor * factor;
97 }
98 
99 void dmub_flush_buffer_mem(const struct dmub_fb *fb)
100 {
101 	const uint8_t *base = (const uint8_t *)fb->cpu_addr;
102 	uint8_t buf[64];
103 	uint32_t pos, end;
104 
105 	/**
106 	 * Read 64-byte chunks since we don't want to store a
107 	 * large temporary buffer for this purpose.
108 	 */
109 	end = fb->size / sizeof(buf) * sizeof(buf);
110 
111 	for (pos = 0; pos < end; pos += sizeof(buf))
112 		dmub_memcpy(buf, base + pos, sizeof(buf));
113 
114 	/* Read anything leftover into the buffer. */
115 	if (end < fb->size)
116 		dmub_memcpy(buf, base + pos, fb->size - end);
117 }
118 
119 static const struct dmub_fw_meta_info *
120 dmub_get_fw_meta_info_from_blob(const uint8_t *blob, uint32_t blob_size, uint32_t meta_offset)
121 {
122 	const union dmub_fw_meta *meta;
123 
124 	if (!blob || !blob_size)
125 		return NULL;
126 
127 	if (blob_size < sizeof(union dmub_fw_meta) + meta_offset)
128 		return NULL;
129 
130 	meta = (const union dmub_fw_meta *)(blob + blob_size - meta_offset -
131 					    sizeof(union dmub_fw_meta));
132 
133 	if (meta->info.magic_value != DMUB_FW_META_MAGIC)
134 		return NULL;
135 
136 	return &meta->info;
137 }
138 
139 static const struct dmub_fw_meta_info *
140 dmub_get_fw_meta_info(const struct dmub_srv_fw_meta_info_params *params)
141 {
142 	const struct dmub_fw_meta_info *info = NULL;
143 
144 	if (params->fw_bss_data && params->bss_data_size) {
145 		/* Legacy metadata region. */
146 		info = dmub_get_fw_meta_info_from_blob(params->fw_bss_data,
147 						       params->bss_data_size,
148 						       DMUB_FW_META_OFFSET);
149 	} else if (params->fw_inst_const && params->inst_const_size) {
150 		/* Combined metadata region - can be aligned to 16-bytes. */
151 		uint32_t i;
152 
153 		for (i = 0; i < 16; ++i) {
154 			info = dmub_get_fw_meta_info_from_blob(
155 				params->fw_inst_const, params->inst_const_size, i);
156 
157 			if (info)
158 				break;
159 		}
160 	}
161 
162 	return info;
163 }
164 
165 enum dmub_status
166 dmub_srv_get_fw_meta_info_from_raw_fw(struct dmub_srv_fw_meta_info_params *params,
167 				      struct dmub_fw_meta_info *fw_info_out)
168 {
169 	const struct dmub_fw_meta_info *fw_info = NULL;
170 	uint32_t inst_const_size_temp = params->inst_const_size;
171 
172 	/* First try custom psp footer size, if present */
173 	if (params->custom_psp_footer_size) {
174 		params->inst_const_size -= params->custom_psp_footer_size;
175 		fw_info = dmub_get_fw_meta_info(params);
176 		if (fw_info) {
177 			memcpy(fw_info_out, fw_info, sizeof(*fw_info));
178 			return DMUB_STATUS_OK;
179 		}
180 		params->inst_const_size = inst_const_size_temp;
181 	}
182 
183 	/* Try 256-byte psp footer size */
184 	params->inst_const_size -= PSP_FOOTER_BYTES_256;
185 	fw_info = dmub_get_fw_meta_info(params);
186 	if (fw_info) {
187 		memcpy(fw_info_out, fw_info, sizeof(*fw_info));
188 		return DMUB_STATUS_OK;
189 	}
190 
191 	/* Try 512-byte psp footer size - final attempt */
192 	params->inst_const_size -= PSP_FOOTER_BYTES_256; // 256 bytes already subtracted, subtract 256 again
193 	fw_info = dmub_get_fw_meta_info(params);
194 	if (fw_info) {
195 		memcpy(fw_info_out, fw_info, sizeof(*fw_info));
196 		return DMUB_STATUS_OK;
197 	}
198 
199 	/* Restore original inst_const_size and subtract default PSP footer size - default behaviour */
200 	params->inst_const_size = inst_const_size_temp - PSP_FOOTER_BYTES_256;
201 
202 	return DMUB_STATUS_INVALID;
203 }
204 
205 static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
206 {
207 	struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs;
208 
209 	/* default to specifying now inbox type */
210 	enum dmub_inbox_cmd_interface_type default_inbox_type = DMUB_CMD_INTERFACE_DEFAULT;
211 
212 	switch (asic) {
213 	case DMUB_ASIC_DCN20:
214 	case DMUB_ASIC_DCN21:
215 	case DMUB_ASIC_DCN30:
216 	case DMUB_ASIC_DCN301:
217 	case DMUB_ASIC_DCN302:
218 	case DMUB_ASIC_DCN303:
219 		dmub->regs = &dmub_srv_dcn20_regs;
220 
221 		funcs->reset = dmub_dcn20_reset;
222 		funcs->reset_release = dmub_dcn20_reset_release;
223 		funcs->backdoor_load = dmub_dcn20_backdoor_load;
224 		funcs->setup_windows = dmub_dcn20_setup_windows;
225 		funcs->setup_mailbox = dmub_dcn20_setup_mailbox;
226 		funcs->get_inbox1_wptr = dmub_dcn20_get_inbox1_wptr;
227 		funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr;
228 		funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr;
229 		funcs->is_supported = dmub_dcn20_is_supported;
230 		funcs->is_hw_init = dmub_dcn20_is_hw_init;
231 		funcs->set_gpint = dmub_dcn20_set_gpint;
232 		funcs->is_gpint_acked = dmub_dcn20_is_gpint_acked;
233 		funcs->get_gpint_response = dmub_dcn20_get_gpint_response;
234 		funcs->get_fw_status = dmub_dcn20_get_fw_boot_status;
235 		funcs->enable_dmub_boot_options = dmub_dcn20_enable_dmub_boot_options;
236 		funcs->skip_dmub_panel_power_sequence = dmub_dcn20_skip_dmub_panel_power_sequence;
237 		funcs->get_current_time = dmub_dcn20_get_current_time;
238 
239 		// Out mailbox register access functions for RN and above
240 		funcs->setup_out_mailbox = dmub_dcn20_setup_out_mailbox;
241 		funcs->get_outbox1_wptr = dmub_dcn20_get_outbox1_wptr;
242 		funcs->set_outbox1_rptr = dmub_dcn20_set_outbox1_rptr;
243 
244 		//outbox0 call stacks
245 		funcs->setup_outbox0 = dmub_dcn20_setup_outbox0;
246 		funcs->get_outbox0_wptr = dmub_dcn20_get_outbox0_wptr;
247 		funcs->set_outbox0_rptr = dmub_dcn20_set_outbox0_rptr;
248 
249 		funcs->get_diagnostic_data = dmub_dcn20_get_diagnostic_data;
250 
251 		if (asic == DMUB_ASIC_DCN21)
252 			dmub->regs = &dmub_srv_dcn21_regs;
253 
254 		if (asic == DMUB_ASIC_DCN30) {
255 			dmub->regs = &dmub_srv_dcn30_regs;
256 
257 			funcs->backdoor_load = dmub_dcn30_backdoor_load;
258 			funcs->setup_windows = dmub_dcn30_setup_windows;
259 		}
260 		if (asic == DMUB_ASIC_DCN301) {
261 			dmub->regs = &dmub_srv_dcn301_regs;
262 
263 			funcs->backdoor_load = dmub_dcn30_backdoor_load;
264 			funcs->setup_windows = dmub_dcn30_setup_windows;
265 		}
266 		if (asic == DMUB_ASIC_DCN302) {
267 			dmub->regs = &dmub_srv_dcn302_regs;
268 
269 			funcs->backdoor_load = dmub_dcn30_backdoor_load;
270 			funcs->setup_windows = dmub_dcn30_setup_windows;
271 		}
272 		if (asic == DMUB_ASIC_DCN303) {
273 			dmub->regs = &dmub_srv_dcn303_regs;
274 
275 			funcs->backdoor_load = dmub_dcn30_backdoor_load;
276 			funcs->setup_windows = dmub_dcn30_setup_windows;
277 		}
278 		break;
279 
280 	case DMUB_ASIC_DCN31:
281 	case DMUB_ASIC_DCN31B:
282 	case DMUB_ASIC_DCN314:
283 	case DMUB_ASIC_DCN315:
284 	case DMUB_ASIC_DCN316:
285 		if (asic == DMUB_ASIC_DCN314) {
286 			dmub->regs_dcn31 = &dmub_srv_dcn314_regs;
287 			funcs->is_psrsu_supported = dmub_dcn314_is_psrsu_supported;
288 		} else if (asic == DMUB_ASIC_DCN315) {
289 			dmub->regs_dcn31 = &dmub_srv_dcn315_regs;
290 		} else if (asic == DMUB_ASIC_DCN316) {
291 			dmub->regs_dcn31 = &dmub_srv_dcn316_regs;
292 		} else {
293 			dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
294 			funcs->is_psrsu_supported = dmub_dcn31_is_psrsu_supported;
295 		}
296 		funcs->reset = dmub_dcn31_reset;
297 		funcs->reset_release = dmub_dcn31_reset_release;
298 		funcs->backdoor_load = dmub_dcn31_backdoor_load;
299 		funcs->setup_windows = dmub_dcn31_setup_windows;
300 		funcs->setup_mailbox = dmub_dcn31_setup_mailbox;
301 		funcs->get_inbox1_wptr = dmub_dcn31_get_inbox1_wptr;
302 		funcs->get_inbox1_rptr = dmub_dcn31_get_inbox1_rptr;
303 		funcs->set_inbox1_wptr = dmub_dcn31_set_inbox1_wptr;
304 		funcs->setup_out_mailbox = dmub_dcn31_setup_out_mailbox;
305 		funcs->get_outbox1_wptr = dmub_dcn31_get_outbox1_wptr;
306 		funcs->set_outbox1_rptr = dmub_dcn31_set_outbox1_rptr;
307 		funcs->is_supported = dmub_dcn31_is_supported;
308 		funcs->is_hw_init = dmub_dcn31_is_hw_init;
309 		funcs->set_gpint = dmub_dcn31_set_gpint;
310 		funcs->is_gpint_acked = dmub_dcn31_is_gpint_acked;
311 		funcs->get_gpint_response = dmub_dcn31_get_gpint_response;
312 		funcs->get_gpint_dataout = dmub_dcn31_get_gpint_dataout;
313 		funcs->get_fw_status = dmub_dcn31_get_fw_boot_status;
314 		funcs->get_fw_boot_option = dmub_dcn31_get_fw_boot_option;
315 		funcs->enable_dmub_boot_options = dmub_dcn31_enable_dmub_boot_options;
316 		funcs->skip_dmub_panel_power_sequence = dmub_dcn31_skip_dmub_panel_power_sequence;
317 		//outbox0 call stacks
318 		funcs->setup_outbox0 = dmub_dcn31_setup_outbox0;
319 		funcs->get_outbox0_wptr = dmub_dcn31_get_outbox0_wptr;
320 		funcs->set_outbox0_rptr = dmub_dcn31_set_outbox0_rptr;
321 
322 		funcs->get_diagnostic_data = dmub_dcn31_get_diagnostic_data;
323 		funcs->should_detect = dmub_dcn31_should_detect;
324 		funcs->get_current_time = dmub_dcn31_get_current_time;
325 
326 		break;
327 
328 	case DMUB_ASIC_DCN32:
329 	case DMUB_ASIC_DCN321:
330 		dmub->regs_dcn32 = &dmub_srv_dcn32_regs;
331 		funcs->configure_dmub_in_system_memory = dmub_dcn32_configure_dmub_in_system_memory;
332 		funcs->send_inbox0_cmd = dmub_dcn32_send_inbox0_cmd;
333 		funcs->clear_inbox0_ack_register = dmub_dcn32_clear_inbox0_ack_register;
334 		funcs->read_inbox0_ack_register = dmub_dcn32_read_inbox0_ack_register;
335 		funcs->subvp_save_surf_addr = dmub_dcn32_save_surf_addr;
336 		funcs->reset = dmub_dcn32_reset;
337 		funcs->reset_release = dmub_dcn32_reset_release;
338 		funcs->backdoor_load = dmub_dcn32_backdoor_load;
339 		funcs->backdoor_load_zfb_mode = dmub_dcn32_backdoor_load_zfb_mode;
340 		funcs->setup_windows = dmub_dcn32_setup_windows;
341 		funcs->setup_mailbox = dmub_dcn32_setup_mailbox;
342 		funcs->get_inbox1_wptr = dmub_dcn32_get_inbox1_wptr;
343 		funcs->get_inbox1_rptr = dmub_dcn32_get_inbox1_rptr;
344 		funcs->set_inbox1_wptr = dmub_dcn32_set_inbox1_wptr;
345 		funcs->setup_out_mailbox = dmub_dcn32_setup_out_mailbox;
346 		funcs->get_outbox1_wptr = dmub_dcn32_get_outbox1_wptr;
347 		funcs->set_outbox1_rptr = dmub_dcn32_set_outbox1_rptr;
348 		funcs->is_supported = dmub_dcn32_is_supported;
349 		funcs->is_hw_init = dmub_dcn32_is_hw_init;
350 		funcs->set_gpint = dmub_dcn32_set_gpint;
351 		funcs->is_gpint_acked = dmub_dcn32_is_gpint_acked;
352 		funcs->get_gpint_response = dmub_dcn32_get_gpint_response;
353 		funcs->get_gpint_dataout = dmub_dcn32_get_gpint_dataout;
354 		funcs->get_fw_status = dmub_dcn32_get_fw_boot_status;
355 		funcs->enable_dmub_boot_options = dmub_dcn32_enable_dmub_boot_options;
356 		funcs->skip_dmub_panel_power_sequence = dmub_dcn32_skip_dmub_panel_power_sequence;
357 
358 		/* outbox0 call stacks */
359 		funcs->setup_outbox0 = dmub_dcn32_setup_outbox0;
360 		funcs->get_outbox0_wptr = dmub_dcn32_get_outbox0_wptr;
361 		funcs->set_outbox0_rptr = dmub_dcn32_set_outbox0_rptr;
362 		funcs->get_current_time = dmub_dcn32_get_current_time;
363 		funcs->get_diagnostic_data = dmub_dcn32_get_diagnostic_data;
364 		funcs->init_reg_offsets = dmub_srv_dcn32_regs_init;
365 
366 		break;
367 
368 	case DMUB_ASIC_DCN35:
369 	case DMUB_ASIC_DCN351:
370 	case DMUB_ASIC_DCN36:
371 			dmub->regs_dcn35 = &dmub_srv_dcn35_regs;
372 			funcs->configure_dmub_in_system_memory = dmub_dcn35_configure_dmub_in_system_memory;
373 			funcs->send_inbox0_cmd = dmub_dcn35_send_inbox0_cmd;
374 			funcs->clear_inbox0_ack_register = dmub_dcn35_clear_inbox0_ack_register;
375 			funcs->read_inbox0_ack_register = dmub_dcn35_read_inbox0_ack_register;
376 			funcs->reset = dmub_dcn35_reset;
377 			funcs->reset_release = dmub_dcn35_reset_release;
378 			funcs->backdoor_load = dmub_dcn35_backdoor_load;
379 			funcs->backdoor_load_zfb_mode = dmub_dcn35_backdoor_load_zfb_mode;
380 			funcs->setup_windows = dmub_dcn35_setup_windows;
381 			funcs->setup_mailbox = dmub_dcn35_setup_mailbox;
382 			funcs->get_inbox1_wptr = dmub_dcn35_get_inbox1_wptr;
383 			funcs->get_inbox1_rptr = dmub_dcn35_get_inbox1_rptr;
384 			funcs->set_inbox1_wptr = dmub_dcn35_set_inbox1_wptr;
385 			funcs->setup_out_mailbox = dmub_dcn35_setup_out_mailbox;
386 			funcs->get_outbox1_wptr = dmub_dcn35_get_outbox1_wptr;
387 			funcs->set_outbox1_rptr = dmub_dcn35_set_outbox1_rptr;
388 			funcs->is_supported = dmub_dcn35_is_supported;
389 			funcs->is_hw_init = dmub_dcn35_is_hw_init;
390 			funcs->set_gpint = dmub_dcn35_set_gpint;
391 			funcs->is_gpint_acked = dmub_dcn35_is_gpint_acked;
392 			funcs->get_gpint_response = dmub_dcn35_get_gpint_response;
393 			funcs->get_gpint_dataout = dmub_dcn35_get_gpint_dataout;
394 			funcs->get_fw_status = dmub_dcn35_get_fw_boot_status;
395 			funcs->get_fw_boot_option = dmub_dcn35_get_fw_boot_option;
396 			funcs->enable_dmub_boot_options = dmub_dcn35_enable_dmub_boot_options;
397 			funcs->skip_dmub_panel_power_sequence = dmub_dcn35_skip_dmub_panel_power_sequence;
398 			//outbox0 call stacks
399 			funcs->setup_outbox0 = dmub_dcn35_setup_outbox0;
400 			funcs->get_outbox0_wptr = dmub_dcn35_get_outbox0_wptr;
401 			funcs->set_outbox0_rptr = dmub_dcn35_set_outbox0_rptr;
402 
403 			funcs->get_current_time = dmub_dcn35_get_current_time;
404 			funcs->get_diagnostic_data = dmub_dcn35_get_diagnostic_data;
405 			funcs->get_preos_fw_info = dmub_dcn35_get_preos_fw_info;
406 
407 			funcs->init_reg_offsets = dmub_srv_dcn35_regs_init;
408 			if (asic == DMUB_ASIC_DCN351)
409 				funcs->init_reg_offsets = dmub_srv_dcn351_regs_init;
410 			if (asic == DMUB_ASIC_DCN36)
411 				funcs->init_reg_offsets = dmub_srv_dcn36_regs_init;
412 
413 			funcs->is_hw_powered_up = dmub_dcn35_is_hw_powered_up;
414 			funcs->should_detect = dmub_dcn35_should_detect;
415 			break;
416 	case DMUB_ASIC_DCN42:
417 	case DMUB_ASIC_DCN42B:
418 			dmub->regs_dcn42 = &dmub_srv_dcn42_regs;
419 			funcs->configure_dmub_in_system_memory = dmub_dcn42_configure_dmub_in_system_memory;
420 			funcs->send_inbox0_cmd = dmub_dcn42_send_inbox0_cmd;
421 			funcs->clear_inbox0_ack_register = dmub_dcn42_clear_inbox0_ack_register;
422 			funcs->read_inbox0_ack_register = dmub_dcn42_read_inbox0_ack_register;
423 			funcs->reset = dmub_dcn42_reset;
424 			funcs->reset_release = dmub_dcn42_reset_release;
425 			funcs->backdoor_load = dmub_dcn42_backdoor_load;
426 			funcs->backdoor_load_zfb_mode = dmub_dcn42_backdoor_load_zfb_mode;
427 			funcs->setup_windows = dmub_dcn42_setup_windows;
428 			funcs->setup_mailbox = dmub_dcn42_setup_mailbox;
429 			funcs->get_inbox1_wptr = dmub_dcn42_get_inbox1_wptr;
430 			funcs->get_inbox1_rptr = dmub_dcn42_get_inbox1_rptr;
431 			funcs->set_inbox1_wptr = dmub_dcn42_set_inbox1_wptr;
432 			funcs->setup_out_mailbox = dmub_dcn42_setup_out_mailbox;
433 			funcs->get_outbox1_wptr = dmub_dcn42_get_outbox1_wptr;
434 			funcs->set_outbox1_rptr = dmub_dcn42_set_outbox1_rptr;
435 			funcs->is_supported = dmub_dcn42_is_supported;
436 			funcs->is_hw_init = dmub_dcn42_is_hw_init;
437 			funcs->set_gpint = dmub_dcn42_set_gpint;
438 			funcs->is_gpint_acked = dmub_dcn42_is_gpint_acked;
439 			funcs->get_gpint_response = dmub_dcn42_get_gpint_response;
440 			funcs->get_gpint_dataout = dmub_dcn42_get_gpint_dataout;
441 			funcs->get_fw_status = dmub_dcn42_get_fw_boot_status;
442 			funcs->get_fw_boot_option = dmub_dcn42_get_fw_boot_option;
443 			funcs->enable_dmub_boot_options = dmub_dcn42_enable_dmub_boot_options;
444 			funcs->skip_dmub_panel_power_sequence = dmub_dcn42_skip_dmub_panel_power_sequence;
445 			/*outbox0 call stacks*/
446 			funcs->setup_outbox0 = dmub_dcn42_setup_outbox0;
447 			funcs->get_outbox0_wptr = dmub_dcn42_get_outbox0_wptr;
448 			funcs->set_outbox0_rptr = dmub_dcn42_set_outbox0_rptr;
449 
450 			funcs->get_current_time = dmub_dcn42_get_current_time;
451 			funcs->get_diagnostic_data = dmub_dcn42_get_diagnostic_data;
452 			funcs->get_preos_fw_info = dmub_dcn42_get_preos_fw_info;
453 
454 			/*carried from dcn401*/
455 			funcs->send_reg_inbox0_cmd_msg = dmub_dcn42_send_reg_inbox0_cmd_msg;
456 			funcs->read_reg_inbox0_rsp_int_status = dmub_dcn42_read_reg_inbox0_rsp_int_status;
457 			funcs->read_reg_inbox0_cmd_rsp = dmub_dcn42_read_reg_inbox0_cmd_rsp;
458 			funcs->write_reg_inbox0_rsp_int_ack = dmub_dcn42_write_reg_inbox0_rsp_int_ack;
459 			funcs->clear_reg_inbox0_rsp_int_ack = dmub_dcn42_clear_reg_inbox0_rsp_int_ack;
460 			funcs->enable_reg_inbox0_rsp_int = dmub_dcn42_enable_reg_inbox0_rsp_int;
461 			default_inbox_type = DMUB_CMD_INTERFACE_FB; /*still default to FB for now*/
462 
463 			funcs->write_reg_outbox0_rdy_int_ack = dmub_dcn42_write_reg_outbox0_rdy_int_ack;
464 			funcs->read_reg_outbox0_msg = dmub_dcn42_read_reg_outbox0_msg;
465 			funcs->write_reg_outbox0_rsp = dmub_dcn42_write_reg_outbox0_rsp;
466 			funcs->read_reg_outbox0_rdy_int_status = dmub_dcn42_read_reg_outbox0_rdy_int_status;
467 			funcs->read_reg_outbox0_rsp_int_status = dmub_dcn42_read_reg_outbox0_rsp_int_status;
468 			funcs->enable_reg_inbox0_rsp_int = dmub_dcn42_enable_reg_inbox0_rsp_int;
469 			funcs->enable_reg_outbox0_rdy_int = dmub_dcn42_enable_reg_outbox0_rdy_int;
470 			funcs->init_reg_offsets = dmub_srv_dcn42_regs_init;
471 			if (asic == DMUB_ASIC_DCN42B)
472 				funcs->init_reg_offsets = dmub_srv_dcn42b_regs_init;
473 
474 			funcs->is_hw_powered_up = dmub_dcn42_is_hw_powered_up;
475 			funcs->should_detect = dmub_dcn42_should_detect;
476 			break;
477 
478 	case DMUB_ASIC_DCN401:
479 		dmub->regs_dcn401 = &dmub_srv_dcn401_regs;
480 		funcs->configure_dmub_in_system_memory = dmub_dcn401_configure_dmub_in_system_memory;
481 		funcs->send_inbox0_cmd = dmub_dcn401_send_inbox0_cmd;
482 		funcs->clear_inbox0_ack_register = dmub_dcn401_clear_inbox0_ack_register;
483 		funcs->read_inbox0_ack_register = dmub_dcn401_read_inbox0_ack_register;
484 		funcs->reset = dmub_dcn401_reset;
485 		funcs->reset_release = dmub_dcn401_reset_release;
486 		funcs->backdoor_load = dmub_dcn401_backdoor_load;
487 		funcs->backdoor_load_zfb_mode = dmub_dcn401_backdoor_load_zfb_mode;
488 		funcs->setup_windows = dmub_dcn401_setup_windows;
489 		funcs->setup_mailbox = dmub_dcn401_setup_mailbox;
490 		funcs->get_inbox1_wptr = dmub_dcn401_get_inbox1_wptr;
491 		funcs->get_inbox1_rptr = dmub_dcn401_get_inbox1_rptr;
492 		funcs->set_inbox1_wptr = dmub_dcn401_set_inbox1_wptr;
493 		funcs->setup_out_mailbox = dmub_dcn401_setup_out_mailbox;
494 		funcs->get_outbox1_wptr = dmub_dcn401_get_outbox1_wptr;
495 		funcs->set_outbox1_rptr = dmub_dcn401_set_outbox1_rptr;
496 		funcs->is_supported = dmub_dcn401_is_supported;
497 		funcs->is_hw_init = dmub_dcn401_is_hw_init;
498 		funcs->set_gpint = dmub_dcn401_set_gpint;
499 		funcs->is_gpint_acked = dmub_dcn401_is_gpint_acked;
500 		funcs->get_gpint_response = dmub_dcn401_get_gpint_response;
501 		funcs->get_gpint_dataout = dmub_dcn401_get_gpint_dataout;
502 		funcs->get_fw_status = dmub_dcn401_get_fw_boot_status;
503 		funcs->enable_dmub_boot_options = dmub_dcn401_enable_dmub_boot_options;
504 		funcs->skip_dmub_panel_power_sequence = dmub_dcn401_skip_dmub_panel_power_sequence;
505 		//outbox0 call stacks
506 		funcs->setup_outbox0 = dmub_dcn401_setup_outbox0;
507 		funcs->get_outbox0_wptr = dmub_dcn401_get_outbox0_wptr;
508 		funcs->set_outbox0_rptr = dmub_dcn401_set_outbox0_rptr;
509 
510 		funcs->get_current_time = dmub_dcn401_get_current_time;
511 		funcs->get_diagnostic_data = dmub_dcn401_get_diagnostic_data;
512 
513 		funcs->send_reg_inbox0_cmd_msg = dmub_dcn401_send_reg_inbox0_cmd_msg;
514 		funcs->read_reg_inbox0_rsp_int_status = dmub_dcn401_read_reg_inbox0_rsp_int_status;
515 		funcs->read_reg_inbox0_cmd_rsp = dmub_dcn401_read_reg_inbox0_cmd_rsp;
516 		funcs->write_reg_inbox0_rsp_int_ack = dmub_dcn401_write_reg_inbox0_rsp_int_ack;
517 		funcs->clear_reg_inbox0_rsp_int_ack = dmub_dcn401_clear_reg_inbox0_rsp_int_ack;
518 		funcs->enable_reg_inbox0_rsp_int = dmub_dcn401_enable_reg_inbox0_rsp_int;
519 		default_inbox_type = DMUB_CMD_INTERFACE_FB; // still default to FB for now
520 
521 		funcs->write_reg_outbox0_rdy_int_ack = dmub_dcn401_write_reg_outbox0_rdy_int_ack;
522 		funcs->read_reg_outbox0_msg = dmub_dcn401_read_reg_outbox0_msg;
523 		funcs->write_reg_outbox0_rsp = dmub_dcn401_write_reg_outbox0_rsp;
524 		funcs->read_reg_outbox0_rdy_int_status = dmub_dcn401_read_reg_outbox0_rdy_int_status;
525 		funcs->read_reg_outbox0_rsp_int_status = dmub_dcn401_read_reg_outbox0_rsp_int_status;
526 		funcs->enable_reg_inbox0_rsp_int = dmub_dcn401_enable_reg_inbox0_rsp_int;
527 		funcs->enable_reg_outbox0_rdy_int = dmub_dcn401_enable_reg_outbox0_rdy_int;
528 		break;
529 	default:
530 		return false;
531 	}
532 
533 	/* set default inbox type if not overriden */
534 	if (dmub->inbox_type == DMUB_CMD_INTERFACE_DEFAULT) {
535 		if (default_inbox_type != DMUB_CMD_INTERFACE_DEFAULT) {
536 			/* use default inbox type as specified by DCN rev */
537 			dmub->inbox_type = default_inbox_type;
538 		} else if (funcs->send_reg_inbox0_cmd_msg) {
539 			/* prefer reg as default inbox type if present */
540 			dmub->inbox_type = DMUB_CMD_INTERFACE_REG;
541 		} else {
542 			/* use fb as fallback */
543 			dmub->inbox_type = DMUB_CMD_INTERFACE_FB;
544 		}
545 	}
546 
547 	return true;
548 }
549 
550 enum dmub_status dmub_srv_create(struct dmub_srv *dmub,
551 				 const struct dmub_srv_create_params *params)
552 {
553 	enum dmub_status status = DMUB_STATUS_OK;
554 
555 	dmub_memset(dmub, 0, sizeof(*dmub));
556 
557 	dmub->funcs = params->funcs;
558 	dmub->user_ctx = params->user_ctx;
559 	dmub->asic = params->asic;
560 	dmub->fw_version = params->fw_version;
561 	dmub->is_virtual = params->is_virtual;
562 	dmub->inbox_type = params->inbox_type;
563 
564 	/* Setup asic dependent hardware funcs. */
565 	if (!dmub_srv_hw_setup(dmub, params->asic)) {
566 		status = DMUB_STATUS_INVALID;
567 		goto cleanup;
568 	}
569 
570 	/* Override (some) hardware funcs based on user params. */
571 	if (params->hw_funcs) {
572 		if (params->hw_funcs->emul_get_inbox1_rptr)
573 			dmub->hw_funcs.emul_get_inbox1_rptr =
574 				params->hw_funcs->emul_get_inbox1_rptr;
575 
576 		if (params->hw_funcs->emul_set_inbox1_wptr)
577 			dmub->hw_funcs.emul_set_inbox1_wptr =
578 				params->hw_funcs->emul_set_inbox1_wptr;
579 
580 		if (params->hw_funcs->is_supported)
581 			dmub->hw_funcs.is_supported =
582 				params->hw_funcs->is_supported;
583 	}
584 
585 	/* Sanity checks for required hw func pointers. */
586 	if (!dmub->hw_funcs.get_inbox1_rptr ||
587 	    !dmub->hw_funcs.set_inbox1_wptr) {
588 		status = DMUB_STATUS_INVALID;
589 		goto cleanup;
590 	}
591 
592 cleanup:
593 	if (status == DMUB_STATUS_OK)
594 		dmub->sw_init = true;
595 	else
596 		dmub_srv_destroy(dmub);
597 
598 	return status;
599 }
600 
601 void dmub_srv_destroy(struct dmub_srv *dmub)
602 {
603 	dmub_memset(dmub, 0, sizeof(*dmub));
604 }
605 
606 static uint32_t dmub_srv_calc_regions_for_memory_type(const struct dmub_srv_region_params *params,
607 	struct dmub_srv_region_info *out,
608 	const uint32_t *window_sizes,
609 	enum dmub_window_memory_type memory_type)
610 {
611 	uint32_t i, top = 0;
612 
613 	for (i = 0; i < DMUB_WINDOW_TOTAL; ++i) {
614 		if (params->window_memory_type[i] == memory_type) {
615 			struct dmub_region *region = &out->regions[i];
616 
617 			region->base = dmub_align(top, 256);
618 			region->top = region->base + dmub_align(window_sizes[i], 64);
619 			top = region->top;
620 		}
621 	}
622 
623 	return dmub_align(top, 4096);
624 }
625 
626 enum dmub_status
627 	dmub_srv_calc_region_info(struct dmub_srv *dmub,
628 		const struct dmub_srv_region_params *params,
629 		struct dmub_srv_region_info *out)
630 {
631 	uint32_t fw_state_size = DMUB_FW_STATE_SIZE;
632 	uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE;
633 	uint32_t shared_state_size = DMUB_FW_HEADER_SHARED_STATE_SIZE;
634 	uint32_t window_sizes[DMUB_WINDOW_TOTAL] = { 0 };
635 
636 	if (!dmub->sw_init)
637 		return DMUB_STATUS_INVALID;
638 
639 	memset(out, 0, sizeof(*out));
640 	memset(window_sizes, 0, sizeof(window_sizes));
641 
642 	out->num_regions = DMUB_NUM_WINDOWS;
643 
644 	if (params->fw_info) {
645 		memcpy(&dmub->meta_info, params->fw_info, sizeof(*params->fw_info));
646 
647 		fw_state_size = params->fw_info->fw_region_size;
648 		trace_buffer_size = params->fw_info->trace_buffer_size;
649 		shared_state_size = params->fw_info->shared_state_size;
650 
651 		/**
652 		 * If DM didn't fill in a version, then fill it in based on
653 		 * the firmware meta now that we have it.
654 		 *
655 		 * TODO: Make it easier for driver to extract this out to
656 		 * pass during creation.
657 		 */
658 		if (dmub->fw_version == 0)
659 			dmub->fw_version = params->fw_info->fw_version;
660 	}
661 
662 	window_sizes[DMUB_WINDOW_0_INST_CONST] = params->inst_const_size;
663 	window_sizes[DMUB_WINDOW_1_STACK] = DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE;
664 	window_sizes[DMUB_WINDOW_2_BSS_DATA] = params->bss_data_size;
665 	window_sizes[DMUB_WINDOW_3_VBIOS] = params->vbios_size;
666 	window_sizes[DMUB_WINDOW_4_MAILBOX] = DMUB_MAILBOX_SIZE;
667 	window_sizes[DMUB_WINDOW_5_TRACEBUFF] = trace_buffer_size;
668 	window_sizes[DMUB_WINDOW_6_FW_STATE] = fw_state_size;
669 	window_sizes[DMUB_WINDOW_7_SCRATCH_MEM] = dmub_align(DMUB_SCRATCH_MEM_SIZE, 64);
670 	window_sizes[DMUB_WINDOW_IB_MEM] = dmub_align(DMUB_IB_MEM_SIZE, 64);
671 	window_sizes[DMUB_WINDOW_SHARED_STATE] = max(DMUB_FW_HEADER_SHARED_STATE_SIZE, shared_state_size);
672 	window_sizes[DMUB_WINDOW_LSDMA_BUFFER] = DMUB_LSDMA_RB_SIZE;
673 	window_sizes[DMUB_WINDOW_CURSOR_OFFLOAD] = dmub_align(sizeof(struct dmub_cursor_offload_v1), 64);
674 
675 	out->fb_size =
676 		dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_FB);
677 
678 	out->gart_size =
679 		dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_GART);
680 
681 	return DMUB_STATUS_OK;
682 }
683 
684 enum dmub_status dmub_srv_calc_mem_info(struct dmub_srv *dmub,
685 				       const struct dmub_srv_memory_params *params,
686 				       struct dmub_srv_fb_info *out)
687 {
688 	uint32_t i;
689 
690 	if (!dmub->sw_init)
691 		return DMUB_STATUS_INVALID;
692 
693 	memset(out, 0, sizeof(*out));
694 
695 	if (params->region_info->num_regions != DMUB_NUM_WINDOWS)
696 		return DMUB_STATUS_INVALID;
697 
698 	for (i = 0; i < DMUB_NUM_WINDOWS; ++i) {
699 		const struct dmub_region *reg =
700 			&params->region_info->regions[i];
701 
702 		if (params->window_memory_type[i] == DMUB_WINDOW_MEMORY_TYPE_GART) {
703 			out->fb[i].cpu_addr = (uint8_t *)params->cpu_gart_addr + reg->base;
704 			out->fb[i].gpu_addr = params->gpu_gart_addr + reg->base;
705 		} else {
706 			out->fb[i].cpu_addr = (uint8_t *)params->cpu_fb_addr + reg->base;
707 			out->fb[i].gpu_addr = params->gpu_fb_addr + reg->base;
708 		}
709 
710 		out->fb[i].size = reg->top - reg->base;
711 	}
712 
713 	out->num_fb = DMUB_NUM_WINDOWS;
714 
715 	return DMUB_STATUS_OK;
716 }
717 
718 enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub,
719 					 bool *is_supported)
720 {
721 	*is_supported = false;
722 
723 	if (!dmub->sw_init)
724 		return DMUB_STATUS_INVALID;
725 
726 	if (dmub->hw_funcs.is_supported)
727 		*is_supported = dmub->hw_funcs.is_supported(dmub);
728 
729 	return DMUB_STATUS_OK;
730 }
731 
732 enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init)
733 {
734 	*is_hw_init = false;
735 
736 	if (!dmub->sw_init)
737 		return DMUB_STATUS_INVALID;
738 
739 	if (!dmub->hw_init)
740 		return DMUB_STATUS_OK;
741 
742 	if (dmub->hw_funcs.is_hw_init)
743 		*is_hw_init = dmub->hw_funcs.is_hw_init(dmub);
744 
745 	return DMUB_STATUS_OK;
746 }
747 
748 enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
749 				  const struct dmub_srv_hw_params *params)
750 {
751 	struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST];
752 	struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK];
753 	struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA];
754 	struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS];
755 	struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX];
756 	struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF];
757 	struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE];
758 	struct dmub_fb *shared_state_fb = params->fb[DMUB_WINDOW_SHARED_STATE];
759 
760 	struct dmub_rb_init_params rb_params, outbox0_rb_params;
761 	struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6, region6;
762 	struct dmub_region inbox1, outbox1, outbox0;
763 
764 	uint32_t i;
765 
766 	if (!dmub->sw_init)
767 		return DMUB_STATUS_INVALID;
768 
769 	for (i = 0; i < DMUB_WINDOW_TOTAL; ++i) {
770 		if (!params->fb[i]) {
771 			ASSERT(0);
772 			return DMUB_STATUS_INVALID;
773 		}
774 	}
775 
776 	memcpy(&dmub->soc_fb_info, &params->soc_fb_info, sizeof(params->soc_fb_info));
777 	dmub->psp_version = params->psp_version;
778 
779 	if (dmub->hw_funcs.reset)
780 		dmub->hw_funcs.reset(dmub);
781 
782 	/* reset the cache of the last wptr as well now that hw is reset */
783 	dmub->inbox1_last_wptr = 0;
784 
785 	cw0.offset.quad_part = inst_fb->gpu_addr;
786 	cw0.region.base = DMUB_CW0_BASE;
787 	cw0.region.top = cw0.region.base + inst_fb->size - 1;
788 
789 	cw1.offset.quad_part = stack_fb->gpu_addr;
790 	cw1.region.base = DMUB_CW1_BASE;
791 	cw1.region.top = cw1.region.base + stack_fb->size - 1;
792 
793 	if (params->fw_in_system_memory && dmub->hw_funcs.configure_dmub_in_system_memory)
794 		dmub->hw_funcs.configure_dmub_in_system_memory(dmub);
795 
796 	if (params->load_inst_const && dmub->hw_funcs.backdoor_load) {
797 		/**
798 		 * Read back all the instruction memory so we don't hang the
799 		 * DMCUB when backdoor loading if the write from x86 hasn't been
800 		 * flushed yet. This only occurs in backdoor loading.
801 		 */
802 		if (params->mem_access_type == DMUB_MEMORY_ACCESS_CPU)
803 			dmub_flush_buffer_mem(inst_fb);
804 
805 		if (params->fw_in_system_memory && dmub->hw_funcs.backdoor_load_zfb_mode)
806 			dmub->hw_funcs.backdoor_load_zfb_mode(dmub, &cw0, &cw1);
807 		else
808 			dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1);
809 	}
810 
811 	cw2.offset.quad_part = data_fb->gpu_addr;
812 	cw2.region.base = DMUB_CW0_BASE + inst_fb->size;
813 	cw2.region.top = cw2.region.base + data_fb->size;
814 
815 	cw3.offset.quad_part = bios_fb->gpu_addr;
816 	cw3.region.base = DMUB_CW3_BASE;
817 	cw3.region.top = cw3.region.base + bios_fb->size;
818 
819 	cw4.offset.quad_part = mail_fb->gpu_addr;
820 	cw4.region.base = DMUB_CW4_BASE;
821 	cw4.region.top = cw4.region.base + mail_fb->size;
822 
823 	/**
824 	 * Doubled the mailbox region to accomodate inbox and outbox.
825 	 * Note: Currently, currently total mailbox size is 16KB. It is split
826 	 * equally into 8KB between inbox and outbox. If this config is
827 	 * changed, then uncached base address configuration of outbox1
828 	 * has to be updated in funcs->setup_out_mailbox.
829 	 */
830 	inbox1.base = cw4.region.base;
831 	inbox1.top = cw4.region.base + DMUB_RB_SIZE;
832 	outbox1.base = inbox1.top;
833 	outbox1.top = inbox1.top + DMUB_RB_SIZE;
834 
835 	cw5.offset.quad_part = tracebuff_fb->gpu_addr;
836 	cw5.region.base = DMUB_CW5_BASE;
837 	cw5.region.top = cw5.region.base + tracebuff_fb->size;
838 
839 	outbox0.base = DMUB_REGION5_BASE + TRACE_BUFFER_ENTRY_OFFSET;
840 	outbox0.top = outbox0.base + tracebuff_fb->size - TRACE_BUFFER_ENTRY_OFFSET;
841 
842 	cw6.offset.quad_part = fw_state_fb->gpu_addr;
843 	cw6.region.base = DMUB_CW6_BASE;
844 	cw6.region.top = cw6.region.base + fw_state_fb->size;
845 
846 	dmub->fw_state = (void *)((uintptr_t)(fw_state_fb->cpu_addr) + DMUB_DEBUG_FW_STATE_OFFSET);
847 
848 	region6.offset.quad_part = shared_state_fb->gpu_addr;
849 	region6.region.base = DMUB_CW6_BASE;
850 	region6.region.top = region6.region.base + shared_state_fb->size;
851 
852 	dmub->shared_state = shared_state_fb->cpu_addr;
853 
854 	dmub->scratch_mem_fb = *params->fb[DMUB_WINDOW_7_SCRATCH_MEM];
855 	dmub->ib_mem_gart = *params->fb[DMUB_WINDOW_IB_MEM];
856 
857 	dmub->cursor_offload_fb = *params->fb[DMUB_WINDOW_CURSOR_OFFLOAD];
858 	dmub->cursor_offload_v1 = (struct dmub_cursor_offload_v1 *)dmub->cursor_offload_fb.cpu_addr;
859 
860 	if (dmub->hw_funcs.setup_windows)
861 		dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, &cw5, &cw6, &region6);
862 
863 	if (dmub->hw_funcs.setup_outbox0)
864 		dmub->hw_funcs.setup_outbox0(dmub, &outbox0);
865 
866 	if (dmub->hw_funcs.setup_mailbox)
867 		dmub->hw_funcs.setup_mailbox(dmub, &inbox1);
868 	if (dmub->hw_funcs.setup_out_mailbox)
869 		dmub->hw_funcs.setup_out_mailbox(dmub, &outbox1);
870 	if (dmub->hw_funcs.enable_reg_inbox0_rsp_int)
871 		dmub->hw_funcs.enable_reg_inbox0_rsp_int(dmub, true);
872 	if (dmub->hw_funcs.enable_reg_outbox0_rdy_int)
873 		dmub->hw_funcs.enable_reg_outbox0_rdy_int(dmub, true);
874 
875 	dmub_memset(&rb_params, 0, sizeof(rb_params));
876 	rb_params.ctx = dmub;
877 	rb_params.base_address = mail_fb->cpu_addr;
878 	rb_params.capacity = DMUB_RB_SIZE;
879 	dmub_rb_init(&dmub->inbox1.rb, &rb_params);
880 
881 	// Initialize outbox1 ring buffer
882 	rb_params.ctx = dmub;
883 	rb_params.base_address = (void *) ((uint8_t *) (mail_fb->cpu_addr) + DMUB_RB_SIZE);
884 	rb_params.capacity = DMUB_RB_SIZE;
885 	dmub_rb_init(&dmub->outbox1_rb, &rb_params);
886 
887 	dmub_memset(&outbox0_rb_params, 0, sizeof(outbox0_rb_params));
888 	outbox0_rb_params.ctx = dmub;
889 	outbox0_rb_params.base_address = (void *)((uintptr_t)(tracebuff_fb->cpu_addr) + TRACE_BUFFER_ENTRY_OFFSET);
890 	outbox0_rb_params.capacity = tracebuff_fb->size - dmub_align(TRACE_BUFFER_ENTRY_OFFSET, 64);
891 	dmub_rb_init(&dmub->outbox0_rb, &outbox0_rb_params);
892 
893 	/* Report to DMUB what features are supported by current driver */
894 	if (dmub->hw_funcs.enable_dmub_boot_options)
895 		dmub->hw_funcs.enable_dmub_boot_options(dmub, params);
896 
897 	if (dmub->hw_funcs.skip_dmub_panel_power_sequence && !dmub->is_virtual)
898 		dmub->hw_funcs.skip_dmub_panel_power_sequence(dmub,
899 			params->skip_panel_power_sequence);
900 
901 	if (dmub->hw_funcs.reset_release && !dmub->is_virtual)
902 		dmub->hw_funcs.reset_release(dmub);
903 
904 	dmub->hw_init = true;
905 	dmub->power_state = DMUB_POWER_STATE_D0;
906 
907 	return DMUB_STATUS_OK;
908 }
909 
910 enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
911 {
912 	if (!dmub->sw_init)
913 		return DMUB_STATUS_INVALID;
914 
915 	if (dmub->hw_funcs.reset)
916 		dmub->hw_funcs.reset(dmub);
917 
918 	/* mailboxes have been reset in hw, so reset the sw state as well */
919 	dmub->inbox1_last_wptr = 0;
920 	dmub->inbox1.rb.wrpt = 0;
921 	dmub->inbox1.rb.rptr = 0;
922 	dmub->inbox1.num_reported = 0;
923 	dmub->inbox1.num_submitted = 0;
924 	dmub->reg_inbox0.num_reported = 0;
925 	dmub->reg_inbox0.num_submitted = 0;
926 	dmub->reg_inbox0.is_pending = 0;
927 	dmub->outbox0_rb.wrpt = 0;
928 	dmub->outbox0_rb.rptr = 0;
929 	dmub->outbox1_rb.wrpt = 0;
930 	dmub->outbox1_rb.rptr = 0;
931 
932 	dmub->hw_init = false;
933 
934 	return DMUB_STATUS_OK;
935 }
936 
937 enum dmub_status dmub_srv_fb_cmd_queue(struct dmub_srv *dmub,
938 				    const union dmub_rb_cmd *cmd)
939 {
940 	if (!dmub->hw_init)
941 		return DMUB_STATUS_INVALID;
942 
943 	if (dmub->power_state != DMUB_POWER_STATE_D0)
944 		return DMUB_STATUS_POWER_STATE_D3;
945 
946 	if (dmub->inbox1.rb.rptr > dmub->inbox1.rb.capacity ||
947 	    dmub->inbox1.rb.wrpt > dmub->inbox1.rb.capacity) {
948 		return DMUB_STATUS_HW_FAILURE;
949 	}
950 
951 	if (dmub_rb_push_front(&dmub->inbox1.rb, cmd)) {
952 		dmub->inbox1.num_submitted++;
953 		return DMUB_STATUS_OK;
954 	}
955 
956 	return DMUB_STATUS_QUEUE_FULL;
957 }
958 
959 enum dmub_status dmub_srv_fb_cmd_execute(struct dmub_srv *dmub)
960 {
961 	struct dmub_rb flush_rb;
962 
963 	if (!dmub->hw_init)
964 		return DMUB_STATUS_INVALID;
965 
966 	if (dmub->power_state != DMUB_POWER_STATE_D0)
967 		return DMUB_STATUS_POWER_STATE_D3;
968 
969 	/**
970 	 * Read back all the queued commands to ensure that they've
971 	 * been flushed to framebuffer memory. Otherwise DMCUB might
972 	 * read back stale, fully invalid or partially invalid data.
973 	 */
974 	flush_rb = dmub->inbox1.rb;
975 	flush_rb.rptr = dmub->inbox1_last_wptr;
976 	dmub_rb_flush_pending(&flush_rb);
977 
978 		dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1.rb.wrpt);
979 
980 	dmub->inbox1_last_wptr = dmub->inbox1.rb.wrpt;
981 
982 	return DMUB_STATUS_OK;
983 }
984 
985 bool dmub_srv_is_hw_pwr_up(struct dmub_srv *dmub)
986 {
987 	if (!dmub->hw_funcs.is_hw_powered_up)
988 		return true;
989 
990 	if (!dmub->hw_funcs.is_hw_powered_up(dmub))
991 		return false;
992 
993 	return true;
994 }
995 
996 enum dmub_status dmub_srv_wait_for_hw_pwr_up(struct dmub_srv *dmub,
997 					     uint32_t timeout_us)
998 {
999 	uint32_t i;
1000 
1001 	if (!dmub->hw_init)
1002 		return DMUB_STATUS_INVALID;
1003 
1004 	for (i = 0; i <= timeout_us; i += 100) {
1005 		if (dmub_srv_is_hw_pwr_up(dmub))
1006 			return DMUB_STATUS_OK;
1007 
1008 		udelay(100);
1009 	}
1010 
1011 	return DMUB_STATUS_TIMEOUT;
1012 }
1013 
1014 enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub,
1015 					     uint32_t timeout_us)
1016 {
1017 	uint32_t i;
1018 	bool hw_on = true;
1019 
1020 	if (!dmub->hw_init)
1021 		return DMUB_STATUS_INVALID;
1022 
1023 	for (i = 0; i <= timeout_us; i += 100) {
1024 		union dmub_fw_boot_status status = dmub->hw_funcs.get_fw_status(dmub);
1025 
1026 		if (dmub->hw_funcs.is_hw_powered_up)
1027 			hw_on = dmub->hw_funcs.is_hw_powered_up(dmub);
1028 
1029 		if (status.bits.dal_fw && status.bits.mailbox_rdy && hw_on)
1030 			return DMUB_STATUS_OK;
1031 
1032 		udelay(100);
1033 	}
1034 
1035 	return DMUB_STATUS_TIMEOUT;
1036 }
1037 
1038 static void dmub_srv_update_reg_inbox0_status(struct dmub_srv *dmub)
1039 {
1040 	if (dmub->reg_inbox0.is_pending) {
1041 		dmub->reg_inbox0.is_pending = (dmub->hw_funcs.read_reg_inbox0_rsp_int_status &&
1042 				!dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub)) != 0;
1043 
1044 		if (!dmub->reg_inbox0.is_pending) {
1045 			/* ack the rsp interrupt */
1046 			if (dmub->hw_funcs.write_reg_inbox0_rsp_int_ack)
1047 				dmub->hw_funcs.write_reg_inbox0_rsp_int_ack(dmub);
1048 
1049 			/* only update the reported count if commands aren't being batched */
1050 			if (!dmub->reg_inbox0.is_pending && !dmub->reg_inbox0.is_multi_pending) {
1051 				dmub->reg_inbox0.num_reported = dmub->reg_inbox0.num_submitted;
1052 			}
1053 		}
1054 	}
1055 }
1056 
1057 enum dmub_status dmub_srv_wait_for_pending(struct dmub_srv *dmub,
1058 					uint32_t timeout_us)
1059 {
1060 	uint32_t i;
1061 	const uint32_t polling_interval_us = 1;
1062 	struct dmub_srv_inbox scratch_reg_inbox0 = dmub->reg_inbox0;
1063 	struct dmub_srv_inbox scratch_inbox1 = dmub->inbox1;
1064 	const volatile struct dmub_srv_inbox *reg_inbox0 = &dmub->reg_inbox0;
1065 	const volatile struct dmub_srv_inbox *inbox1 = &dmub->inbox1;
1066 
1067 	if (!dmub->hw_init ||
1068 			!dmub->hw_funcs.get_inbox1_wptr)
1069 		return DMUB_STATUS_INVALID;
1070 
1071 	for (i = 0; i <= timeout_us; i += polling_interval_us) {
1072 			scratch_inbox1.rb.wrpt = dmub->hw_funcs.get_inbox1_wptr(dmub);
1073 			scratch_inbox1.rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
1074 
1075 		scratch_reg_inbox0.is_pending = scratch_reg_inbox0.is_pending &&
1076 				dmub->hw_funcs.read_reg_inbox0_rsp_int_status &&
1077 				!dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub);
1078 
1079 		if (scratch_inbox1.rb.rptr > dmub->inbox1.rb.capacity)
1080 			return DMUB_STATUS_HW_FAILURE;
1081 
1082 		/* check current HW state first, but use command submission vs reported as a fallback */
1083 		if ((dmub_rb_empty(&scratch_inbox1.rb) ||
1084 				inbox1->num_reported >= scratch_inbox1.num_submitted) &&
1085 				(!scratch_reg_inbox0.is_pending ||
1086 				reg_inbox0->num_reported >= scratch_reg_inbox0.num_submitted))
1087 			return DMUB_STATUS_OK;
1088 
1089 		udelay(polling_interval_us);
1090 	}
1091 
1092 	return DMUB_STATUS_TIMEOUT;
1093 }
1094 
1095 enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
1096 					uint32_t timeout_us)
1097 {
1098 	enum dmub_status status;
1099 	uint32_t i;
1100 	const uint32_t polling_interval_us = 1;
1101 
1102 	if (!dmub->hw_init)
1103 		return DMUB_STATUS_INVALID;
1104 
1105 	for (i = 0; i < timeout_us; i += polling_interval_us) {
1106 		status = dmub_srv_update_inbox_status(dmub);
1107 
1108 		if (status != DMUB_STATUS_OK)
1109 			return status;
1110 
1111 		/* check for idle */
1112 		if (dmub_rb_empty(&dmub->inbox1.rb) && !dmub->reg_inbox0.is_pending)
1113 			return DMUB_STATUS_OK;
1114 
1115 		udelay(polling_interval_us);
1116 	}
1117 
1118 	return DMUB_STATUS_TIMEOUT;
1119 }
1120 
1121 enum dmub_status
1122 dmub_srv_send_gpint_command(struct dmub_srv *dmub,
1123 			    enum dmub_gpint_command command_code,
1124 			    uint16_t param, uint32_t timeout_us)
1125 {
1126 	union dmub_gpint_data_register reg;
1127 	uint32_t i;
1128 
1129 	if (!dmub->sw_init)
1130 		return DMUB_STATUS_INVALID;
1131 
1132 	if (!dmub->hw_funcs.set_gpint)
1133 		return DMUB_STATUS_INVALID;
1134 
1135 	if (!dmub->hw_funcs.is_gpint_acked)
1136 		return DMUB_STATUS_INVALID;
1137 
1138 	reg.bits.status = 1;
1139 	reg.bits.command_code = command_code;
1140 	reg.bits.param = param;
1141 
1142 	dmub->hw_funcs.set_gpint(dmub, reg);
1143 
1144 	for (i = 0; i < timeout_us; ++i) {
1145 		udelay(1);
1146 
1147 		if (dmub->hw_funcs.is_gpint_acked(dmub, reg))
1148 			return DMUB_STATUS_OK;
1149 	}
1150 
1151 	return DMUB_STATUS_TIMEOUT;
1152 }
1153 
1154 enum dmub_status dmub_srv_get_gpint_response(struct dmub_srv *dmub,
1155 					     uint32_t *response)
1156 {
1157 	*response = 0;
1158 
1159 	if (!dmub->sw_init)
1160 		return DMUB_STATUS_INVALID;
1161 
1162 	if (!dmub->hw_funcs.get_gpint_response)
1163 		return DMUB_STATUS_INVALID;
1164 
1165 	*response = dmub->hw_funcs.get_gpint_response(dmub);
1166 
1167 	return DMUB_STATUS_OK;
1168 }
1169 
1170 enum dmub_status dmub_srv_get_gpint_dataout(struct dmub_srv *dmub,
1171 					     uint32_t *dataout)
1172 {
1173 	*dataout = 0;
1174 
1175 	if (!dmub->sw_init)
1176 		return DMUB_STATUS_INVALID;
1177 
1178 	if (!dmub->hw_funcs.get_gpint_dataout)
1179 		return DMUB_STATUS_INVALID;
1180 
1181 	*dataout = dmub->hw_funcs.get_gpint_dataout(dmub);
1182 
1183 	return DMUB_STATUS_OK;
1184 }
1185 
1186 enum dmub_status dmub_srv_get_fw_boot_status(struct dmub_srv *dmub,
1187 					     union dmub_fw_boot_status *status)
1188 {
1189 	status->all = 0;
1190 
1191 	if (!dmub->sw_init)
1192 		return DMUB_STATUS_INVALID;
1193 
1194 	if (dmub->hw_funcs.get_fw_status)
1195 		*status = dmub->hw_funcs.get_fw_status(dmub);
1196 
1197 	return DMUB_STATUS_OK;
1198 }
1199 
1200 enum dmub_status dmub_srv_get_fw_boot_option(struct dmub_srv *dmub,
1201 					     union dmub_fw_boot_options *option)
1202 {
1203 	option->all = 0;
1204 
1205 	if (!dmub->sw_init)
1206 		return DMUB_STATUS_INVALID;
1207 
1208 	if (dmub->hw_funcs.get_fw_boot_option)
1209 		*option = dmub->hw_funcs.get_fw_boot_option(dmub);
1210 
1211 	return DMUB_STATUS_OK;
1212 }
1213 
1214 enum dmub_status dmub_srv_set_skip_panel_power_sequence(struct dmub_srv *dmub,
1215 					     bool skip)
1216 {
1217 	if (!dmub->sw_init)
1218 		return DMUB_STATUS_INVALID;
1219 
1220 	if (dmub->hw_funcs.skip_dmub_panel_power_sequence && !dmub->is_virtual)
1221 		dmub->hw_funcs.skip_dmub_panel_power_sequence(dmub, skip);
1222 
1223 	return DMUB_STATUS_OK;
1224 }
1225 
1226 static inline bool dmub_rb_out_trace_buffer_front(struct dmub_rb *rb,
1227 				 void *entry)
1228 {
1229 	const uint64_t *src = (const uint64_t *)(rb->base_address) + rb->rptr / sizeof(uint64_t);
1230 	uint64_t *dst = (uint64_t *)entry;
1231 	uint8_t i;
1232 	uint8_t loop_count;
1233 
1234 	if (rb->rptr == rb->wrpt)
1235 		return false;
1236 
1237 	loop_count = sizeof(struct dmcub_trace_buf_entry) / sizeof(uint64_t);
1238 	// copying data
1239 	for (i = 0; i < loop_count; i++)
1240 		*dst++ = *src++;
1241 
1242 	rb->rptr += sizeof(struct dmcub_trace_buf_entry);
1243 
1244 	rb->rptr %= rb->capacity;
1245 
1246 	return true;
1247 }
1248 
1249 bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entry *entry)
1250 {
1251 	dmub->outbox0_rb.wrpt = dmub->hw_funcs.get_outbox0_wptr(dmub);
1252 
1253 	return dmub_rb_out_trace_buffer_front(&dmub->outbox0_rb, (void *)entry);
1254 }
1255 
1256 bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub)
1257 {
1258 	if (!dmub || !dmub->hw_funcs.get_diagnostic_data)
1259 		return false;
1260 	dmub->hw_funcs.get_diagnostic_data(dmub);
1261 	return true;
1262 }
1263 
1264 bool dmub_srv_should_detect(struct dmub_srv *dmub)
1265 {
1266 	if (!dmub->hw_init || !dmub->hw_funcs.should_detect)
1267 		return false;
1268 
1269 	return dmub->hw_funcs.should_detect(dmub);
1270 }
1271 
1272 enum dmub_status dmub_srv_clear_inbox0_ack(struct dmub_srv *dmub)
1273 {
1274 	if (!dmub->hw_init || !dmub->hw_funcs.clear_inbox0_ack_register)
1275 		return DMUB_STATUS_INVALID;
1276 
1277 	dmub->hw_funcs.clear_inbox0_ack_register(dmub);
1278 	return DMUB_STATUS_OK;
1279 }
1280 
1281 enum dmub_status dmub_srv_wait_for_inbox0_ack(struct dmub_srv *dmub, uint32_t timeout_us)
1282 {
1283 	uint32_t i = 0;
1284 	uint32_t ack = 0;
1285 
1286 	if (!dmub->hw_init || !dmub->hw_funcs.read_inbox0_ack_register)
1287 		return DMUB_STATUS_INVALID;
1288 
1289 	for (i = 0; i <= timeout_us; i++) {
1290 		ack = dmub->hw_funcs.read_inbox0_ack_register(dmub);
1291 		if (ack)
1292 			return DMUB_STATUS_OK;
1293 		udelay(1);
1294 	}
1295 	return DMUB_STATUS_TIMEOUT;
1296 }
1297 
1298 enum dmub_status dmub_srv_send_inbox0_cmd(struct dmub_srv *dmub,
1299 		union dmub_inbox0_data_register data)
1300 {
1301 	if (!dmub->hw_init || !dmub->hw_funcs.send_inbox0_cmd)
1302 		return DMUB_STATUS_INVALID;
1303 
1304 	dmub->hw_funcs.send_inbox0_cmd(dmub, data);
1305 	return DMUB_STATUS_OK;
1306 }
1307 
1308 void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_address *addr, uint8_t subvp_index)
1309 {
1310 	if (dmub->hw_funcs.subvp_save_surf_addr) {
1311 		dmub->hw_funcs.subvp_save_surf_addr(dmub,
1312 				addr,
1313 				subvp_index);
1314 	}
1315 }
1316 
1317 void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state)
1318 {
1319 	if (!dmub || !dmub->hw_init)
1320 		return;
1321 
1322 	dmub->power_state = dmub_srv_power_state;
1323 }
1324 
1325 enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd)
1326 {
1327 	uint64_t num_pending = 0;
1328 
1329 	if (!dmub->hw_init)
1330 		return DMUB_STATUS_INVALID;
1331 
1332 	if (dmub->power_state != DMUB_POWER_STATE_D0)
1333 		return DMUB_STATUS_POWER_STATE_D3;
1334 
1335 	if (!dmub->hw_funcs.send_reg_inbox0_cmd_msg ||
1336 			!dmub->hw_funcs.clear_reg_inbox0_rsp_int_ack)
1337 		return DMUB_STATUS_INVALID;
1338 
1339 	if (dmub->reg_inbox0.num_submitted >= dmub->reg_inbox0.num_reported)
1340 		num_pending = dmub->reg_inbox0.num_submitted - dmub->reg_inbox0.num_reported;
1341 	else
1342 		/* num_submitted wrapped */
1343 		num_pending = DMUB_REG_INBOX0_RB_MAX_ENTRY -
1344 				(dmub->reg_inbox0.num_reported - dmub->reg_inbox0.num_submitted);
1345 
1346 	if (num_pending >= DMUB_REG_INBOX0_RB_MAX_ENTRY)
1347 		return DMUB_STATUS_QUEUE_FULL;
1348 
1349 	/* clear last rsp ack and send message */
1350 	dmub->hw_funcs.clear_reg_inbox0_rsp_int_ack(dmub);
1351 	dmub->hw_funcs.send_reg_inbox0_cmd_msg(dmub, cmd);
1352 
1353 	dmub->reg_inbox0.num_submitted++;
1354 	dmub->reg_inbox0.is_pending = true;
1355 	dmub->reg_inbox0.is_multi_pending = cmd->cmd_common.header.multi_cmd_pending != 0;
1356 
1357 	return DMUB_STATUS_OK;
1358 }
1359 
1360 void dmub_srv_cmd_get_response(struct dmub_srv *dmub,
1361 		union dmub_rb_cmd *cmd_rsp)
1362 {
1363 	if (dmub) {
1364 		if (dmub->inbox_type == DMUB_CMD_INTERFACE_REG &&
1365 				dmub->hw_funcs.read_reg_inbox0_cmd_rsp) {
1366 			dmub->hw_funcs.read_reg_inbox0_cmd_rsp(dmub, cmd_rsp);
1367 		} else {
1368 			dmub_rb_get_return_data(&dmub->inbox1.rb, cmd_rsp);
1369 		}
1370 	}
1371 }
1372 
1373 static enum dmub_status dmub_srv_sync_reg_inbox0(struct dmub_srv *dmub)
1374 {
1375 	if (!dmub || !dmub->sw_init)
1376 		return DMUB_STATUS_INVALID;
1377 
1378 	dmub->reg_inbox0.is_pending = 0;
1379 	dmub->reg_inbox0.is_multi_pending = 0;
1380 
1381 	return DMUB_STATUS_OK;
1382 }
1383 
1384 static enum dmub_status dmub_srv_sync_inbox1(struct dmub_srv *dmub)
1385 {
1386 	if (!dmub->sw_init)
1387 		return DMUB_STATUS_INVALID;
1388 
1389 	if (dmub->hw_funcs.get_inbox1_rptr && dmub->hw_funcs.get_inbox1_wptr) {
1390 		uint32_t rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
1391 		uint32_t wptr = dmub->hw_funcs.get_inbox1_wptr(dmub);
1392 
1393 		if (rptr > dmub->inbox1.rb.capacity || wptr > dmub->inbox1.rb.capacity) {
1394 			return DMUB_STATUS_HW_FAILURE;
1395 		} else {
1396 			dmub->inbox1.rb.rptr = rptr;
1397 			dmub->inbox1.rb.wrpt = wptr;
1398 			dmub->inbox1_last_wptr = dmub->inbox1.rb.wrpt;
1399 		}
1400 	}
1401 
1402 	return DMUB_STATUS_OK;
1403 }
1404 
1405 enum dmub_status dmub_srv_sync_inboxes(struct dmub_srv *dmub)
1406 {
1407 	enum dmub_status status;
1408 
1409 	status = dmub_srv_sync_reg_inbox0(dmub);
1410 	if (status != DMUB_STATUS_OK)
1411 		return status;
1412 
1413 	status = dmub_srv_sync_inbox1(dmub);
1414 	if (status != DMUB_STATUS_OK)
1415 		return status;
1416 
1417 	return DMUB_STATUS_OK;
1418 }
1419 
1420 enum dmub_status dmub_srv_wait_for_inbox_free(struct dmub_srv *dmub,
1421 		uint32_t timeout_us,
1422 		uint32_t num_free_required)
1423 {
1424 	enum dmub_status status;
1425 	uint32_t i;
1426 	const uint32_t polling_interval_us = 1;
1427 
1428 	if (!dmub->hw_init)
1429 		return DMUB_STATUS_INVALID;
1430 
1431 	for (i = 0; i < timeout_us; i += polling_interval_us) {
1432 		status = dmub_srv_update_inbox_status(dmub);
1433 
1434 		if (status != DMUB_STATUS_OK)
1435 			return status;
1436 
1437 		/* check for space in inbox1 */
1438 		if (dmub_rb_num_free(&dmub->inbox1.rb) >= num_free_required)
1439 			return DMUB_STATUS_OK;
1440 
1441 		udelay(polling_interval_us);
1442 	}
1443 
1444 	return DMUB_STATUS_TIMEOUT;
1445 }
1446 
1447 enum dmub_status dmub_srv_update_inbox_status(struct dmub_srv *dmub)
1448 {
1449 	uint32_t rptr;
1450 
1451 	if (!dmub->hw_init)
1452 		return DMUB_STATUS_INVALID;
1453 
1454 	if (dmub->power_state != DMUB_POWER_STATE_D0)
1455 		return DMUB_STATUS_POWER_STATE_D3;
1456 
1457 	/* update inbox1 state */
1458 	rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
1459 
1460 	if (rptr > dmub->inbox1.rb.capacity)
1461 		return DMUB_STATUS_HW_FAILURE;
1462 
1463 	if (dmub->inbox1.rb.rptr > rptr) {
1464 		/* rb wrapped */
1465 		dmub->inbox1.num_reported += (rptr + dmub->inbox1.rb.capacity - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
1466 	} else {
1467 		dmub->inbox1.num_reported += (rptr - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
1468 	}
1469 	dmub->inbox1.rb.rptr = rptr;
1470 
1471 	/* update reg_inbox0 */
1472 	dmub_srv_update_reg_inbox0_status(dmub);
1473 
1474 	return DMUB_STATUS_OK;
1475 }
1476 
1477 bool dmub_srv_get_preos_info(struct dmub_srv *dmub)
1478 {
1479 	if (!dmub || !dmub->hw_funcs.get_preos_fw_info)
1480 		return false;
1481 
1482 	return dmub->hw_funcs.get_preos_fw_info(dmub);
1483 }
1484