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