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