1 /*
2  * Copyright 2019 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "../dmub_srv.h"
27 #include "dmub_dcn20.h"
28 #include "dmub_dcn21.h"
29 #include "dmub_cmd.h"
30 #ifdef CONFIG_DRM_AMD_DC_DCN3_0
31 #include "dmub_dcn30.h"
32 #endif
33 #ifdef CONFIG_DRM_AMD_DC_DCN3_01
34 #include "dmub_dcn301.h"
35 #endif
36 #ifdef CONFIG_DRM_AMD_DC_DCN3_02
37 #include "dmub_dcn302.h"
38 #endif
39 #include "os_types.h"
40 /*
41  * Note: the DMUB service is standalone. No additional headers should be
42  * added below or above this line unless they reside within the DMUB
43  * folder.
44  */
45 
46 /* Alignment for framebuffer memory. */
47 #define DMUB_FB_ALIGNMENT (1024 * 1024)
48 
49 /* Stack size. */
50 #define DMUB_STACK_SIZE (128 * 1024)
51 
52 /* Context size. */
53 #define DMUB_CONTEXT_SIZE (512 * 1024)
54 
55 /* Mailbox size */
56 #define DMUB_MAILBOX_SIZE (DMUB_RB_SIZE)
57 
58 /* Default state size if meta is absent. */
59 #define DMUB_FW_STATE_SIZE (64 * 1024)
60 
61 /* Default tracebuffer size if meta is absent. */
62 #define DMUB_TRACE_BUFFER_SIZE (64 * 1024)
63 
64 /* Default scratch mem size. */
65 #define DMUB_SCRATCH_MEM_SIZE (256)
66 
67 /* Number of windows in use. */
68 #define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL)
69 /* Base addresses. */
70 
71 #define DMUB_CW0_BASE (0x60000000)
72 #define DMUB_CW1_BASE (0x61000000)
73 #define DMUB_CW3_BASE (0x63000000)
74 #define DMUB_CW4_BASE (0x64000000)
75 #define DMUB_CW5_BASE (0x65000000)
76 #define DMUB_CW6_BASE (0x66000000)
77 
78 static inline uint32_t dmub_align(uint32_t val, uint32_t factor)
79 {
80 	return (val + factor - 1) / factor * factor;
81 }
82 
83 void dmub_flush_buffer_mem(const struct dmub_fb *fb)
84 {
85 	const uint8_t *base = (const uint8_t *)fb->cpu_addr;
86 	uint8_t buf[64];
87 	uint32_t pos, end;
88 
89 	/**
90 	 * Read 64-byte chunks since we don't want to store a
91 	 * large temporary buffer for this purpose.
92 	 */
93 	end = fb->size / sizeof(buf) * sizeof(buf);
94 
95 	for (pos = 0; pos < end; pos += sizeof(buf))
96 		dmub_memcpy(buf, base + pos, sizeof(buf));
97 
98 	/* Read anything leftover into the buffer. */
99 	if (end < fb->size)
100 		dmub_memcpy(buf, base + pos, fb->size - end);
101 }
102 
103 static const struct dmub_fw_meta_info *
104 dmub_get_fw_meta_info(const struct dmub_srv_region_params *params)
105 {
106 	const union dmub_fw_meta *meta;
107 	const uint8_t *blob = NULL;
108 	uint32_t blob_size = 0;
109 	uint32_t meta_offset = 0;
110 
111 	if (params->fw_bss_data && params->bss_data_size) {
112 		/* Legacy metadata region. */
113 		blob = params->fw_bss_data;
114 		blob_size = params->bss_data_size;
115 		meta_offset = DMUB_FW_META_OFFSET;
116 	} else if (params->fw_inst_const && params->inst_const_size) {
117 		/* Combined metadata region. */
118 		blob = params->fw_inst_const;
119 		blob_size = params->inst_const_size;
120 		meta_offset = 0;
121 	}
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 bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
139 {
140 	struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs;
141 
142 	switch (asic) {
143 	case DMUB_ASIC_DCN20:
144 	case DMUB_ASIC_DCN21:
145 #ifdef CONFIG_DRM_AMD_DC_DCN3_0
146 	case DMUB_ASIC_DCN30:
147 #endif
148 #ifdef CONFIG_DRM_AMD_DC_DCN3_01
149 	case DMUB_ASIC_DCN301:
150 #endif
151 #ifdef CONFIG_DRM_AMD_DC_DCN3_02
152 	case DMUB_ASIC_DCN302:
153 #endif
154 		dmub->regs = &dmub_srv_dcn20_regs;
155 
156 		funcs->reset = dmub_dcn20_reset;
157 		funcs->reset_release = dmub_dcn20_reset_release;
158 		funcs->backdoor_load = dmub_dcn20_backdoor_load;
159 		funcs->setup_windows = dmub_dcn20_setup_windows;
160 		funcs->setup_mailbox = dmub_dcn20_setup_mailbox;
161 		funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr;
162 		funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr;
163 		funcs->is_supported = dmub_dcn20_is_supported;
164 		funcs->is_hw_init = dmub_dcn20_is_hw_init;
165 		funcs->set_gpint = dmub_dcn20_set_gpint;
166 		funcs->is_gpint_acked = dmub_dcn20_is_gpint_acked;
167 		funcs->get_gpint_response = dmub_dcn20_get_gpint_response;
168 
169 		if (asic == DMUB_ASIC_DCN21) {
170 			dmub->regs = &dmub_srv_dcn21_regs;
171 
172 			funcs->is_auto_load_done = dmub_dcn21_is_auto_load_done;
173 			funcs->is_phy_init = dmub_dcn21_is_phy_init;
174 		}
175 #ifdef CONFIG_DRM_AMD_DC_DCN3_0
176 		if (asic == DMUB_ASIC_DCN30) {
177 			dmub->regs = &dmub_srv_dcn30_regs;
178 
179 			funcs->is_auto_load_done = dmub_dcn30_is_auto_load_done;
180 			funcs->backdoor_load = dmub_dcn30_backdoor_load;
181 			funcs->setup_windows = dmub_dcn30_setup_windows;
182 		}
183 #endif
184 #ifdef CONFIG_DRM_AMD_DC_DCN3_01
185 		if (asic == DMUB_ASIC_DCN301) {
186 			dmub->regs = &dmub_srv_dcn301_regs;
187 
188 			funcs->backdoor_load = dmub_dcn30_backdoor_load;
189 			funcs->setup_windows = dmub_dcn30_setup_windows;
190 		}
191 #endif
192 #ifdef CONFIG_DRM_AMD_DC_DCN3_02
193 		if (asic == DMUB_ASIC_DCN302) {
194 			dmub->regs = &dmub_srv_dcn302_regs;
195 
196 			funcs->backdoor_load = dmub_dcn30_backdoor_load;
197 			funcs->setup_windows = dmub_dcn30_setup_windows;
198 		}
199 #endif
200 		break;
201 
202 	default:
203 		return false;
204 	}
205 
206 	return true;
207 }
208 
209 enum dmub_status dmub_srv_create(struct dmub_srv *dmub,
210 				 const struct dmub_srv_create_params *params)
211 {
212 	enum dmub_status status = DMUB_STATUS_OK;
213 
214 	dmub_memset(dmub, 0, sizeof(*dmub));
215 
216 	dmub->funcs = params->funcs;
217 	dmub->user_ctx = params->user_ctx;
218 	dmub->asic = params->asic;
219 	dmub->fw_version = params->fw_version;
220 	dmub->is_virtual = params->is_virtual;
221 
222 	/* Setup asic dependent hardware funcs. */
223 	if (!dmub_srv_hw_setup(dmub, params->asic)) {
224 		status = DMUB_STATUS_INVALID;
225 		goto cleanup;
226 	}
227 
228 	/* Override (some) hardware funcs based on user params. */
229 	if (params->hw_funcs) {
230 		if (params->hw_funcs->emul_get_inbox1_rptr)
231 			dmub->hw_funcs.emul_get_inbox1_rptr =
232 				params->hw_funcs->emul_get_inbox1_rptr;
233 
234 		if (params->hw_funcs->emul_set_inbox1_wptr)
235 			dmub->hw_funcs.emul_set_inbox1_wptr =
236 				params->hw_funcs->emul_set_inbox1_wptr;
237 
238 		if (params->hw_funcs->is_supported)
239 			dmub->hw_funcs.is_supported =
240 				params->hw_funcs->is_supported;
241 	}
242 
243 	/* Sanity checks for required hw func pointers. */
244 	if (!dmub->hw_funcs.get_inbox1_rptr ||
245 	    !dmub->hw_funcs.set_inbox1_wptr) {
246 		status = DMUB_STATUS_INVALID;
247 		goto cleanup;
248 	}
249 
250 cleanup:
251 	if (status == DMUB_STATUS_OK)
252 		dmub->sw_init = true;
253 	else
254 		dmub_srv_destroy(dmub);
255 
256 	return status;
257 }
258 
259 void dmub_srv_destroy(struct dmub_srv *dmub)
260 {
261 	dmub_memset(dmub, 0, sizeof(*dmub));
262 }
263 
264 enum dmub_status
265 dmub_srv_calc_region_info(struct dmub_srv *dmub,
266 			  const struct dmub_srv_region_params *params,
267 			  struct dmub_srv_region_info *out)
268 {
269 	struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST];
270 	struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK];
271 	struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA];
272 	struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS];
273 	struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX];
274 	struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF];
275 	struct dmub_region *fw_state = &out->regions[DMUB_WINDOW_6_FW_STATE];
276 	struct dmub_region *scratch_mem = &out->regions[DMUB_WINDOW_7_SCRATCH_MEM];
277 	const struct dmub_fw_meta_info *fw_info;
278 	uint32_t fw_state_size = DMUB_FW_STATE_SIZE;
279 	uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE;
280 	uint32_t scratch_mem_size = DMUB_SCRATCH_MEM_SIZE;
281 
282 	if (!dmub->sw_init)
283 		return DMUB_STATUS_INVALID;
284 
285 	memset(out, 0, sizeof(*out));
286 
287 	out->num_regions = DMUB_NUM_WINDOWS;
288 
289 	inst->base = 0x0;
290 	inst->top = inst->base + params->inst_const_size;
291 
292 	data->base = dmub_align(inst->top, 256);
293 	data->top = data->base + params->bss_data_size;
294 
295 	/*
296 	 * All cache windows below should be aligned to the size
297 	 * of the DMCUB cache line, 64 bytes.
298 	 */
299 
300 	stack->base = dmub_align(data->top, 256);
301 	stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE;
302 
303 	bios->base = dmub_align(stack->top, 256);
304 	bios->top = bios->base + params->vbios_size;
305 
306 	mail->base = dmub_align(bios->top, 256);
307 	mail->top = mail->base + DMUB_MAILBOX_SIZE;
308 
309 	fw_info = dmub_get_fw_meta_info(params);
310 
311 	if (fw_info) {
312 		fw_state_size = fw_info->fw_region_size;
313 		trace_buffer_size = fw_info->trace_buffer_size;
314 
315 		/**
316 		 * If DM didn't fill in a version, then fill it in based on
317 		 * the firmware meta now that we have it.
318 		 *
319 		 * TODO: Make it easier for driver to extract this out to
320 		 * pass during creation.
321 		 */
322 		if (dmub->fw_version == 0)
323 			dmub->fw_version = fw_info->fw_version;
324 	}
325 
326 	trace_buff->base = dmub_align(mail->top, 256);
327 	trace_buff->top = trace_buff->base + dmub_align(trace_buffer_size, 64);
328 
329 	fw_state->base = dmub_align(trace_buff->top, 256);
330 	fw_state->top = fw_state->base + dmub_align(fw_state_size, 64);
331 
332 	scratch_mem->base = dmub_align(fw_state->top, 256);
333 	scratch_mem->top = scratch_mem->base + dmub_align(scratch_mem_size, 64);
334 
335 	out->fb_size = dmub_align(scratch_mem->top, 4096);
336 
337 	return DMUB_STATUS_OK;
338 }
339 
340 enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub,
341 				       const struct dmub_srv_fb_params *params,
342 				       struct dmub_srv_fb_info *out)
343 {
344 	uint8_t *cpu_base;
345 	uint64_t gpu_base;
346 	uint32_t i;
347 
348 	if (!dmub->sw_init)
349 		return DMUB_STATUS_INVALID;
350 
351 	memset(out, 0, sizeof(*out));
352 
353 	if (params->region_info->num_regions != DMUB_NUM_WINDOWS)
354 		return DMUB_STATUS_INVALID;
355 
356 	cpu_base = (uint8_t *)params->cpu_addr;
357 	gpu_base = params->gpu_addr;
358 
359 	for (i = 0; i < DMUB_NUM_WINDOWS; ++i) {
360 		const struct dmub_region *reg =
361 			&params->region_info->regions[i];
362 
363 		out->fb[i].cpu_addr = cpu_base + reg->base;
364 		out->fb[i].gpu_addr = gpu_base + reg->base;
365 		out->fb[i].size = reg->top - reg->base;
366 	}
367 
368 	out->num_fb = DMUB_NUM_WINDOWS;
369 
370 	return DMUB_STATUS_OK;
371 }
372 
373 enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub,
374 					 bool *is_supported)
375 {
376 	*is_supported = false;
377 
378 	if (!dmub->sw_init)
379 		return DMUB_STATUS_INVALID;
380 
381 	if (dmub->hw_funcs.is_supported)
382 		*is_supported = dmub->hw_funcs.is_supported(dmub);
383 
384 	return DMUB_STATUS_OK;
385 }
386 
387 enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init)
388 {
389 	*is_hw_init = false;
390 
391 	if (!dmub->sw_init)
392 		return DMUB_STATUS_INVALID;
393 
394 	if (!dmub->hw_init)
395 		return DMUB_STATUS_OK;
396 
397 	if (dmub->hw_funcs.is_hw_init)
398 		*is_hw_init = dmub->hw_funcs.is_hw_init(dmub);
399 
400 	return DMUB_STATUS_OK;
401 }
402 
403 enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
404 				  const struct dmub_srv_hw_params *params)
405 {
406 	struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST];
407 	struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK];
408 	struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA];
409 	struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS];
410 	struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX];
411 	struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF];
412 	struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE];
413 	struct dmub_fb *scratch_mem_fb = params->fb[DMUB_WINDOW_7_SCRATCH_MEM];
414 
415 	struct dmub_rb_init_params rb_params;
416 	struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6;
417 	struct dmub_region inbox1;
418 
419 	if (!dmub->sw_init)
420 		return DMUB_STATUS_INVALID;
421 
422 	dmub->fb_base = params->fb_base;
423 	dmub->fb_offset = params->fb_offset;
424 	dmub->psp_version = params->psp_version;
425 
426 	if (inst_fb && data_fb) {
427 		cw0.offset.quad_part = inst_fb->gpu_addr;
428 		cw0.region.base = DMUB_CW0_BASE;
429 		cw0.region.top = cw0.region.base + inst_fb->size - 1;
430 
431 		cw1.offset.quad_part = stack_fb->gpu_addr;
432 		cw1.region.base = DMUB_CW1_BASE;
433 		cw1.region.top = cw1.region.base + stack_fb->size - 1;
434 
435 		if (params->load_inst_const && dmub->hw_funcs.backdoor_load) {
436 		    /**
437 		     * Read back all the instruction memory so we don't hang the
438 		     * DMCUB when backdoor loading if the write from x86 hasn't been
439 		     * flushed yet. This only occurs in backdoor loading.
440 		     */
441 		    dmub_flush_buffer_mem(inst_fb);
442 		    dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1);
443 		}
444 
445 	}
446 
447 	if (dmub->hw_funcs.reset)
448 		dmub->hw_funcs.reset(dmub);
449 
450 	if (inst_fb && data_fb && bios_fb && mail_fb && tracebuff_fb &&
451 	    fw_state_fb && scratch_mem_fb) {
452 		cw2.offset.quad_part = data_fb->gpu_addr;
453 		cw2.region.base = DMUB_CW0_BASE + inst_fb->size;
454 		cw2.region.top = cw2.region.base + data_fb->size;
455 
456 		cw3.offset.quad_part = bios_fb->gpu_addr;
457 		cw3.region.base = DMUB_CW3_BASE;
458 		cw3.region.top = cw3.region.base + bios_fb->size;
459 
460 		cw4.offset.quad_part = mail_fb->gpu_addr;
461 		cw4.region.base = DMUB_CW4_BASE;
462 		cw4.region.top = cw4.region.base + mail_fb->size;
463 
464 		inbox1.base = cw4.region.base;
465 		inbox1.top = cw4.region.top;
466 
467 		cw5.offset.quad_part = tracebuff_fb->gpu_addr;
468 		cw5.region.base = DMUB_CW5_BASE;
469 		cw5.region.top = cw5.region.base + tracebuff_fb->size;
470 
471 		cw6.offset.quad_part = fw_state_fb->gpu_addr;
472 		cw6.region.base = DMUB_CW6_BASE;
473 		cw6.region.top = cw6.region.base + fw_state_fb->size;
474 
475 		dmub->fw_state = fw_state_fb->cpu_addr;
476 
477 		dmub->scratch_mem_fb = *scratch_mem_fb;
478 
479 		if (dmub->hw_funcs.setup_windows)
480 			dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4,
481 						     &cw5, &cw6);
482 
483 		if (dmub->hw_funcs.setup_mailbox)
484 			dmub->hw_funcs.setup_mailbox(dmub, &inbox1);
485 	}
486 
487 	if (mail_fb) {
488 		dmub_memset(&rb_params, 0, sizeof(rb_params));
489 		rb_params.ctx = dmub;
490 		rb_params.base_address = mail_fb->cpu_addr;
491 		rb_params.capacity = DMUB_RB_SIZE;
492 
493 		dmub_rb_init(&dmub->inbox1_rb, &rb_params);
494 	}
495 
496 	if (dmub->hw_funcs.reset_release)
497 		dmub->hw_funcs.reset_release(dmub);
498 
499 	dmub->hw_init = true;
500 
501 	return DMUB_STATUS_OK;
502 }
503 
504 enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
505 {
506 	if (!dmub->sw_init)
507 		return DMUB_STATUS_INVALID;
508 
509 	if (dmub->hw_init == false)
510 		return DMUB_STATUS_OK;
511 
512 	if (dmub->hw_funcs.reset)
513 		dmub->hw_funcs.reset(dmub);
514 
515 	dmub->hw_init = false;
516 
517 	return DMUB_STATUS_OK;
518 }
519 
520 enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub,
521 				    const union dmub_rb_cmd *cmd)
522 {
523 	if (!dmub->hw_init)
524 		return DMUB_STATUS_INVALID;
525 
526 	if (dmub_rb_push_front(&dmub->inbox1_rb, cmd))
527 		return DMUB_STATUS_OK;
528 
529 	return DMUB_STATUS_QUEUE_FULL;
530 }
531 
532 enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub)
533 {
534 	if (!dmub->hw_init)
535 		return DMUB_STATUS_INVALID;
536 
537 	/**
538 	 * Read back all the queued commands to ensure that they've
539 	 * been flushed to framebuffer memory. Otherwise DMCUB might
540 	 * read back stale, fully invalid or partially invalid data.
541 	 */
542 	dmub_rb_flush_pending(&dmub->inbox1_rb);
543 
544 		dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt);
545 	return DMUB_STATUS_OK;
546 }
547 
548 enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub,
549 					     uint32_t timeout_us)
550 {
551 	uint32_t i;
552 
553 	if (!dmub->hw_init)
554 		return DMUB_STATUS_INVALID;
555 
556 	if (!dmub->hw_funcs.is_auto_load_done)
557 		return DMUB_STATUS_OK;
558 
559 	for (i = 0; i <= timeout_us; i += 100) {
560 		if (dmub->hw_funcs.is_auto_load_done(dmub))
561 			return DMUB_STATUS_OK;
562 
563 		udelay(100);
564 	}
565 
566 	return DMUB_STATUS_TIMEOUT;
567 }
568 
569 enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub,
570 					    uint32_t timeout_us)
571 {
572 	uint32_t i = 0;
573 
574 	if (!dmub->hw_init)
575 		return DMUB_STATUS_INVALID;
576 
577 	if (!dmub->hw_funcs.is_phy_init)
578 		return DMUB_STATUS_OK;
579 
580 	for (i = 0; i <= timeout_us; i += 10) {
581 		if (dmub->hw_funcs.is_phy_init(dmub))
582 			return DMUB_STATUS_OK;
583 
584 		udelay(10);
585 	}
586 
587 	return DMUB_STATUS_TIMEOUT;
588 }
589 
590 enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
591 					uint32_t timeout_us)
592 {
593 	uint32_t i;
594 
595 	if (!dmub->hw_init)
596 		return DMUB_STATUS_INVALID;
597 
598 	for (i = 0; i <= timeout_us; ++i) {
599 			dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
600 		if (dmub_rb_empty(&dmub->inbox1_rb))
601 			return DMUB_STATUS_OK;
602 
603 		udelay(1);
604 	}
605 
606 	return DMUB_STATUS_TIMEOUT;
607 }
608 
609 enum dmub_status
610 dmub_srv_send_gpint_command(struct dmub_srv *dmub,
611 			    enum dmub_gpint_command command_code,
612 			    uint16_t param, uint32_t timeout_us)
613 {
614 	union dmub_gpint_data_register reg;
615 	uint32_t i;
616 
617 	if (!dmub->sw_init)
618 		return DMUB_STATUS_INVALID;
619 
620 	if (!dmub->hw_funcs.set_gpint)
621 		return DMUB_STATUS_INVALID;
622 
623 	if (!dmub->hw_funcs.is_gpint_acked)
624 		return DMUB_STATUS_INVALID;
625 
626 	reg.bits.status = 1;
627 	reg.bits.command_code = command_code;
628 	reg.bits.param = param;
629 
630 	dmub->hw_funcs.set_gpint(dmub, reg);
631 
632 	for (i = 0; i < timeout_us; ++i) {
633 		if (dmub->hw_funcs.is_gpint_acked(dmub, reg))
634 			return DMUB_STATUS_OK;
635 	}
636 
637 	return DMUB_STATUS_TIMEOUT;
638 }
639 
640 enum dmub_status dmub_srv_get_gpint_response(struct dmub_srv *dmub,
641 					     uint32_t *response)
642 {
643 	*response = 0;
644 
645 	if (!dmub->sw_init)
646 		return DMUB_STATUS_INVALID;
647 
648 	if (!dmub->hw_funcs.get_gpint_response)
649 		return DMUB_STATUS_INVALID;
650 
651 	*response = dmub->hw_funcs.get_gpint_response(dmub);
652 
653 	return DMUB_STATUS_OK;
654 }
655