Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
   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#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 "os_types.h"
  42/*
  43 * Note: the DMUB service is standalone. No additional headers should be
  44 * added below or above this line unless they reside within the DMUB
  45 * folder.
  46 */
  47
  48/* Alignment for framebuffer memory. */
  49#define DMUB_FB_ALIGNMENT (1024 * 1024)
  50
  51/* Stack size. */
  52#define DMUB_STACK_SIZE (128 * 1024)
  53
  54/* Context size. */
  55#define DMUB_CONTEXT_SIZE (512 * 1024)
  56
  57/* Mailbox size : Ring buffers are required for both inbox and outbox */
  58#define DMUB_MAILBOX_SIZE ((2 * DMUB_RB_SIZE))
  59
  60/* Default state size if meta is absent. */
  61#define DMUB_FW_STATE_SIZE (64 * 1024)
  62
  63/* Default tracebuffer size if meta is absent. */
  64#define DMUB_TRACE_BUFFER_SIZE (64 * 1024)
  65
  66
  67/* Default scratch mem size. */
  68#define DMUB_SCRATCH_MEM_SIZE (1024)
  69
  70/* Number of windows in use. */
  71#define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL)
  72/* Base addresses. */
  73
  74#define DMUB_CW0_BASE (0x60000000)
  75#define DMUB_CW1_BASE (0x61000000)
  76#define DMUB_CW3_BASE (0x63000000)
  77#define DMUB_CW4_BASE (0x64000000)
  78#define DMUB_CW5_BASE (0x65000000)
  79#define DMUB_CW6_BASE (0x66000000)
  80
  81#define DMUB_REGION5_BASE (0xA0000000)
  82#define DMUB_REGION6_BASE (0xC0000000)
  83
  84static struct dmub_srv_dcn32_regs dmub_srv_dcn32_regs;
  85static struct dmub_srv_dcn35_regs dmub_srv_dcn35_regs;
  86
  87static inline uint32_t dmub_align(uint32_t val, uint32_t factor)
  88{
  89	return (val + factor - 1) / factor * factor;
  90}
  91
  92void dmub_flush_buffer_mem(const struct dmub_fb *fb)
  93{
  94	const uint8_t *base = (const uint8_t *)fb->cpu_addr;
  95	uint8_t buf[64];
  96	uint32_t pos, end;
  97
  98	/**
  99	 * Read 64-byte chunks since we don't want to store a
 100	 * large temporary buffer for this purpose.
 101	 */
 102	end = fb->size / sizeof(buf) * sizeof(buf);
 103
 104	for (pos = 0; pos < end; pos += sizeof(buf))
 105		dmub_memcpy(buf, base + pos, sizeof(buf));
 106
 107	/* Read anything leftover into the buffer. */
 108	if (end < fb->size)
 109		dmub_memcpy(buf, base + pos, fb->size - end);
 110}
 111
 112static const struct dmub_fw_meta_info *
 113dmub_get_fw_meta_info_from_blob(const uint8_t *blob, uint32_t blob_size, uint32_t meta_offset)
 114{
 115	const union dmub_fw_meta *meta;
 116
 117	if (!blob || !blob_size)
 118		return NULL;
 119
 120	if (blob_size < sizeof(union dmub_fw_meta) + meta_offset)
 121		return NULL;
 122
 123	meta = (const union dmub_fw_meta *)(blob + blob_size - meta_offset -
 124					    sizeof(union dmub_fw_meta));
 125
 126	if (meta->info.magic_value != DMUB_FW_META_MAGIC)
 127		return NULL;
 128
 129	return &meta->info;
 130}
 131
 132static const struct dmub_fw_meta_info *
 133dmub_get_fw_meta_info(const struct dmub_srv_region_params *params)
 134{
 135	const struct dmub_fw_meta_info *info = NULL;
 136
 137	if (params->fw_bss_data && params->bss_data_size) {
 138		/* Legacy metadata region. */
 139		info = dmub_get_fw_meta_info_from_blob(params->fw_bss_data,
 140						       params->bss_data_size,
 141						       DMUB_FW_META_OFFSET);
 142	} else if (params->fw_inst_const && params->inst_const_size) {
 143		/* Combined metadata region - can be aligned to 16-bytes. */
 144		uint32_t i;
 145
 146		for (i = 0; i < 16; ++i) {
 147			info = dmub_get_fw_meta_info_from_blob(
 148				params->fw_inst_const, params->inst_const_size, i);
 149
 150			if (info)
 151				break;
 152		}
 153	}
 154
 155	return info;
 156}
 157
 158static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
 159{
 160	struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs;
 161
 162	switch (asic) {
 163	case DMUB_ASIC_DCN20:
 164	case DMUB_ASIC_DCN21:
 165	case DMUB_ASIC_DCN30:
 166	case DMUB_ASIC_DCN301:
 167	case DMUB_ASIC_DCN302:
 168	case DMUB_ASIC_DCN303:
 169		dmub->regs = &dmub_srv_dcn20_regs;
 170
 171		funcs->reset = dmub_dcn20_reset;
 172		funcs->reset_release = dmub_dcn20_reset_release;
 173		funcs->backdoor_load = dmub_dcn20_backdoor_load;
 174		funcs->setup_windows = dmub_dcn20_setup_windows;
 175		funcs->setup_mailbox = dmub_dcn20_setup_mailbox;
 176		funcs->get_inbox1_wptr = dmub_dcn20_get_inbox1_wptr;
 177		funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr;
 178		funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr;
 179		funcs->is_supported = dmub_dcn20_is_supported;
 180		funcs->is_hw_init = dmub_dcn20_is_hw_init;
 181		funcs->set_gpint = dmub_dcn20_set_gpint;
 182		funcs->is_gpint_acked = dmub_dcn20_is_gpint_acked;
 183		funcs->get_gpint_response = dmub_dcn20_get_gpint_response;
 184		funcs->get_fw_status = dmub_dcn20_get_fw_boot_status;
 185		funcs->enable_dmub_boot_options = dmub_dcn20_enable_dmub_boot_options;
 186		funcs->skip_dmub_panel_power_sequence = dmub_dcn20_skip_dmub_panel_power_sequence;
 187		funcs->get_current_time = dmub_dcn20_get_current_time;
 188
 189		// Out mailbox register access functions for RN and above
 190		funcs->setup_out_mailbox = dmub_dcn20_setup_out_mailbox;
 191		funcs->get_outbox1_wptr = dmub_dcn20_get_outbox1_wptr;
 192		funcs->set_outbox1_rptr = dmub_dcn20_set_outbox1_rptr;
 193
 194		//outbox0 call stacks
 195		funcs->setup_outbox0 = dmub_dcn20_setup_outbox0;
 196		funcs->get_outbox0_wptr = dmub_dcn20_get_outbox0_wptr;
 197		funcs->set_outbox0_rptr = dmub_dcn20_set_outbox0_rptr;
 198
 199		funcs->get_diagnostic_data = dmub_dcn20_get_diagnostic_data;
 200
 201		if (asic == DMUB_ASIC_DCN21)
 202			dmub->regs = &dmub_srv_dcn21_regs;
 203
 204		if (asic == DMUB_ASIC_DCN30) {
 205			dmub->regs = &dmub_srv_dcn30_regs;
 206
 207			funcs->backdoor_load = dmub_dcn30_backdoor_load;
 208			funcs->setup_windows = dmub_dcn30_setup_windows;
 209		}
 210		if (asic == DMUB_ASIC_DCN301) {
 211			dmub->regs = &dmub_srv_dcn301_regs;
 212
 213			funcs->backdoor_load = dmub_dcn30_backdoor_load;
 214			funcs->setup_windows = dmub_dcn30_setup_windows;
 215		}
 216		if (asic == DMUB_ASIC_DCN302) {
 217			dmub->regs = &dmub_srv_dcn302_regs;
 218
 219			funcs->backdoor_load = dmub_dcn30_backdoor_load;
 220			funcs->setup_windows = dmub_dcn30_setup_windows;
 221		}
 222		if (asic == DMUB_ASIC_DCN303) {
 223			dmub->regs = &dmub_srv_dcn303_regs;
 224
 225			funcs->backdoor_load = dmub_dcn30_backdoor_load;
 226			funcs->setup_windows = dmub_dcn30_setup_windows;
 227		}
 228		break;
 229
 230	case DMUB_ASIC_DCN31:
 231	case DMUB_ASIC_DCN31B:
 232	case DMUB_ASIC_DCN314:
 233	case DMUB_ASIC_DCN315:
 234	case DMUB_ASIC_DCN316:
 235		if (asic == DMUB_ASIC_DCN314) {
 236			dmub->regs_dcn31 = &dmub_srv_dcn314_regs;
 237			funcs->is_psrsu_supported = dmub_dcn314_is_psrsu_supported;
 238		} else if (asic == DMUB_ASIC_DCN315) {
 239			dmub->regs_dcn31 = &dmub_srv_dcn315_regs;
 240		} else if (asic == DMUB_ASIC_DCN316) {
 241			dmub->regs_dcn31 = &dmub_srv_dcn316_regs;
 242		} else {
 243			dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
 244			funcs->is_psrsu_supported = dmub_dcn31_is_psrsu_supported;
 245		}
 246		funcs->reset = dmub_dcn31_reset;
 247		funcs->reset_release = dmub_dcn31_reset_release;
 248		funcs->backdoor_load = dmub_dcn31_backdoor_load;
 249		funcs->setup_windows = dmub_dcn31_setup_windows;
 250		funcs->setup_mailbox = dmub_dcn31_setup_mailbox;
 251		funcs->get_inbox1_wptr = dmub_dcn31_get_inbox1_wptr;
 252		funcs->get_inbox1_rptr = dmub_dcn31_get_inbox1_rptr;
 253		funcs->set_inbox1_wptr = dmub_dcn31_set_inbox1_wptr;
 254		funcs->setup_out_mailbox = dmub_dcn31_setup_out_mailbox;
 255		funcs->get_outbox1_wptr = dmub_dcn31_get_outbox1_wptr;
 256		funcs->set_outbox1_rptr = dmub_dcn31_set_outbox1_rptr;
 257		funcs->is_supported = dmub_dcn31_is_supported;
 258		funcs->is_hw_init = dmub_dcn31_is_hw_init;
 259		funcs->set_gpint = dmub_dcn31_set_gpint;
 260		funcs->is_gpint_acked = dmub_dcn31_is_gpint_acked;
 261		funcs->get_gpint_response = dmub_dcn31_get_gpint_response;
 262		funcs->get_gpint_dataout = dmub_dcn31_get_gpint_dataout;
 263		funcs->get_fw_status = dmub_dcn31_get_fw_boot_status;
 264		funcs->get_fw_boot_option = dmub_dcn31_get_fw_boot_option;
 265		funcs->enable_dmub_boot_options = dmub_dcn31_enable_dmub_boot_options;
 266		funcs->skip_dmub_panel_power_sequence = dmub_dcn31_skip_dmub_panel_power_sequence;
 267		//outbox0 call stacks
 268		funcs->setup_outbox0 = dmub_dcn31_setup_outbox0;
 269		funcs->get_outbox0_wptr = dmub_dcn31_get_outbox0_wptr;
 270		funcs->set_outbox0_rptr = dmub_dcn31_set_outbox0_rptr;
 271
 272		funcs->get_diagnostic_data = dmub_dcn31_get_diagnostic_data;
 273		funcs->should_detect = dmub_dcn31_should_detect;
 274		funcs->get_current_time = dmub_dcn31_get_current_time;
 275
 276		break;
 277
 278	case DMUB_ASIC_DCN32:
 279	case DMUB_ASIC_DCN321:
 280		dmub->regs_dcn32 = &dmub_srv_dcn32_regs;
 281		funcs->configure_dmub_in_system_memory = dmub_dcn32_configure_dmub_in_system_memory;
 282		funcs->send_inbox0_cmd = dmub_dcn32_send_inbox0_cmd;
 283		funcs->clear_inbox0_ack_register = dmub_dcn32_clear_inbox0_ack_register;
 284		funcs->read_inbox0_ack_register = dmub_dcn32_read_inbox0_ack_register;
 285		funcs->subvp_save_surf_addr = dmub_dcn32_save_surf_addr;
 286		funcs->reset = dmub_dcn32_reset;
 287		funcs->reset_release = dmub_dcn32_reset_release;
 288		funcs->backdoor_load = dmub_dcn32_backdoor_load;
 289		funcs->backdoor_load_zfb_mode = dmub_dcn32_backdoor_load_zfb_mode;
 290		funcs->setup_windows = dmub_dcn32_setup_windows;
 291		funcs->setup_mailbox = dmub_dcn32_setup_mailbox;
 292		funcs->get_inbox1_wptr = dmub_dcn32_get_inbox1_wptr;
 293		funcs->get_inbox1_rptr = dmub_dcn32_get_inbox1_rptr;
 294		funcs->set_inbox1_wptr = dmub_dcn32_set_inbox1_wptr;
 295		funcs->setup_out_mailbox = dmub_dcn32_setup_out_mailbox;
 296		funcs->get_outbox1_wptr = dmub_dcn32_get_outbox1_wptr;
 297		funcs->set_outbox1_rptr = dmub_dcn32_set_outbox1_rptr;
 298		funcs->is_supported = dmub_dcn32_is_supported;
 299		funcs->is_hw_init = dmub_dcn32_is_hw_init;
 300		funcs->set_gpint = dmub_dcn32_set_gpint;
 301		funcs->is_gpint_acked = dmub_dcn32_is_gpint_acked;
 302		funcs->get_gpint_response = dmub_dcn32_get_gpint_response;
 303		funcs->get_gpint_dataout = dmub_dcn32_get_gpint_dataout;
 304		funcs->get_fw_status = dmub_dcn32_get_fw_boot_status;
 305		funcs->enable_dmub_boot_options = dmub_dcn32_enable_dmub_boot_options;
 306		funcs->skip_dmub_panel_power_sequence = dmub_dcn32_skip_dmub_panel_power_sequence;
 307
 308		/* outbox0 call stacks */
 309		funcs->setup_outbox0 = dmub_dcn32_setup_outbox0;
 310		funcs->get_outbox0_wptr = dmub_dcn32_get_outbox0_wptr;
 311		funcs->set_outbox0_rptr = dmub_dcn32_set_outbox0_rptr;
 312		funcs->get_current_time = dmub_dcn32_get_current_time;
 313		funcs->get_diagnostic_data = dmub_dcn32_get_diagnostic_data;
 314		funcs->init_reg_offsets = dmub_srv_dcn32_regs_init;
 315
 316		break;
 317
 318	case DMUB_ASIC_DCN35:
 319	case DMUB_ASIC_DCN351:
 320			dmub->regs_dcn35 = &dmub_srv_dcn35_regs;
 321			funcs->configure_dmub_in_system_memory = dmub_dcn35_configure_dmub_in_system_memory;
 322			funcs->send_inbox0_cmd = dmub_dcn35_send_inbox0_cmd;
 323			funcs->clear_inbox0_ack_register = dmub_dcn35_clear_inbox0_ack_register;
 324			funcs->read_inbox0_ack_register = dmub_dcn35_read_inbox0_ack_register;
 325			funcs->reset = dmub_dcn35_reset;
 326			funcs->reset_release = dmub_dcn35_reset_release;
 327			funcs->backdoor_load = dmub_dcn35_backdoor_load;
 328			funcs->backdoor_load_zfb_mode = dmub_dcn35_backdoor_load_zfb_mode;
 329			funcs->setup_windows = dmub_dcn35_setup_windows;
 330			funcs->setup_mailbox = dmub_dcn35_setup_mailbox;
 331			funcs->get_inbox1_wptr = dmub_dcn35_get_inbox1_wptr;
 332			funcs->get_inbox1_rptr = dmub_dcn35_get_inbox1_rptr;
 333			funcs->set_inbox1_wptr = dmub_dcn35_set_inbox1_wptr;
 334			funcs->setup_out_mailbox = dmub_dcn35_setup_out_mailbox;
 335			funcs->get_outbox1_wptr = dmub_dcn35_get_outbox1_wptr;
 336			funcs->set_outbox1_rptr = dmub_dcn35_set_outbox1_rptr;
 337			funcs->is_supported = dmub_dcn35_is_supported;
 338			funcs->is_hw_init = dmub_dcn35_is_hw_init;
 339			funcs->set_gpint = dmub_dcn35_set_gpint;
 340			funcs->is_gpint_acked = dmub_dcn35_is_gpint_acked;
 341			funcs->get_gpint_response = dmub_dcn35_get_gpint_response;
 342			funcs->get_gpint_dataout = dmub_dcn35_get_gpint_dataout;
 343			funcs->get_fw_status = dmub_dcn35_get_fw_boot_status;
 344			funcs->get_fw_boot_option = dmub_dcn35_get_fw_boot_option;
 345			funcs->enable_dmub_boot_options = dmub_dcn35_enable_dmub_boot_options;
 346			funcs->skip_dmub_panel_power_sequence = dmub_dcn35_skip_dmub_panel_power_sequence;
 347			//outbox0 call stacks
 348			funcs->setup_outbox0 = dmub_dcn35_setup_outbox0;
 349			funcs->get_outbox0_wptr = dmub_dcn35_get_outbox0_wptr;
 350			funcs->set_outbox0_rptr = dmub_dcn35_set_outbox0_rptr;
 351
 352			funcs->get_current_time = dmub_dcn35_get_current_time;
 353			funcs->get_diagnostic_data = dmub_dcn35_get_diagnostic_data;
 354
 355			funcs->init_reg_offsets = dmub_srv_dcn35_regs_init;
 356			if (asic == DMUB_ASIC_DCN351)
 357                                funcs->init_reg_offsets = dmub_srv_dcn351_regs_init;
 358
 359			funcs->is_hw_powered_up = dmub_dcn35_is_hw_powered_up;
 360			funcs->should_detect = dmub_dcn35_should_detect;
 361			break;
 362
 363	default:
 364		return false;
 365	}
 366
 367	return true;
 368}
 369
 370enum dmub_status dmub_srv_create(struct dmub_srv *dmub,
 371				 const struct dmub_srv_create_params *params)
 372{
 373	enum dmub_status status = DMUB_STATUS_OK;
 374
 375	dmub_memset(dmub, 0, sizeof(*dmub));
 376
 377	dmub->funcs = params->funcs;
 378	dmub->user_ctx = params->user_ctx;
 379	dmub->asic = params->asic;
 380	dmub->fw_version = params->fw_version;
 381	dmub->is_virtual = params->is_virtual;
 382
 383	/* Setup asic dependent hardware funcs. */
 384	if (!dmub_srv_hw_setup(dmub, params->asic)) {
 385		status = DMUB_STATUS_INVALID;
 386		goto cleanup;
 387	}
 388
 389	/* Override (some) hardware funcs based on user params. */
 390	if (params->hw_funcs) {
 391		if (params->hw_funcs->emul_get_inbox1_rptr)
 392			dmub->hw_funcs.emul_get_inbox1_rptr =
 393				params->hw_funcs->emul_get_inbox1_rptr;
 394
 395		if (params->hw_funcs->emul_set_inbox1_wptr)
 396			dmub->hw_funcs.emul_set_inbox1_wptr =
 397				params->hw_funcs->emul_set_inbox1_wptr;
 398
 399		if (params->hw_funcs->is_supported)
 400			dmub->hw_funcs.is_supported =
 401				params->hw_funcs->is_supported;
 402	}
 403
 404	/* Sanity checks for required hw func pointers. */
 405	if (!dmub->hw_funcs.get_inbox1_rptr ||
 406	    !dmub->hw_funcs.set_inbox1_wptr) {
 407		status = DMUB_STATUS_INVALID;
 408		goto cleanup;
 409	}
 410
 411cleanup:
 412	if (status == DMUB_STATUS_OK)
 413		dmub->sw_init = true;
 414	else
 415		dmub_srv_destroy(dmub);
 416
 417	return status;
 418}
 419
 420void dmub_srv_destroy(struct dmub_srv *dmub)
 421{
 422	dmub_memset(dmub, 0, sizeof(*dmub));
 423}
 424
 425static uint32_t dmub_srv_calc_regions_for_memory_type(const struct dmub_srv_region_params *params,
 426	struct dmub_srv_region_info *out,
 427	const uint32_t *window_sizes,
 428	enum dmub_window_memory_type memory_type)
 429{
 430	uint32_t i, top = 0;
 431
 432	for (i = 0; i < DMUB_WINDOW_TOTAL; ++i) {
 433		if (params->window_memory_type[i] == memory_type) {
 434			struct dmub_region *region = &out->regions[i];
 435
 436			region->base = dmub_align(top, 256);
 437			region->top = region->base + dmub_align(window_sizes[i], 64);
 438			top = region->top;
 439		}
 440	}
 441
 442	return dmub_align(top, 4096);
 443}
 444
 445enum dmub_status
 446	dmub_srv_calc_region_info(struct dmub_srv *dmub,
 447		const struct dmub_srv_region_params *params,
 448		struct dmub_srv_region_info *out)
 449{
 450	const struct dmub_fw_meta_info *fw_info;
 451	uint32_t fw_state_size = DMUB_FW_STATE_SIZE;
 452	uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE;
 453	uint32_t window_sizes[DMUB_WINDOW_TOTAL] = { 0 };
 454
 455	if (!dmub->sw_init)
 456		return DMUB_STATUS_INVALID;
 457
 458	memset(out, 0, sizeof(*out));
 459	memset(window_sizes, 0, sizeof(window_sizes));
 460
 461	out->num_regions = DMUB_NUM_WINDOWS;
 462
 463	fw_info = dmub_get_fw_meta_info(params);
 464
 465	if (fw_info) {
 466		fw_state_size = fw_info->fw_region_size;
 467		trace_buffer_size = fw_info->trace_buffer_size;
 468
 469		/**
 470		 * If DM didn't fill in a version, then fill it in based on
 471		 * the firmware meta now that we have it.
 472		 *
 473		 * TODO: Make it easier for driver to extract this out to
 474		 * pass during creation.
 475		 */
 476		if (dmub->fw_version == 0)
 477			dmub->fw_version = fw_info->fw_version;
 478	}
 479
 480	window_sizes[DMUB_WINDOW_0_INST_CONST] = params->inst_const_size;
 481	window_sizes[DMUB_WINDOW_1_STACK] = DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE;
 482	window_sizes[DMUB_WINDOW_2_BSS_DATA] = params->bss_data_size;
 483	window_sizes[DMUB_WINDOW_3_VBIOS] = params->vbios_size;
 484	window_sizes[DMUB_WINDOW_4_MAILBOX] = DMUB_MAILBOX_SIZE;
 485	window_sizes[DMUB_WINDOW_5_TRACEBUFF] = trace_buffer_size;
 486	window_sizes[DMUB_WINDOW_6_FW_STATE] = fw_state_size;
 487	window_sizes[DMUB_WINDOW_7_SCRATCH_MEM] = DMUB_SCRATCH_MEM_SIZE;
 488	window_sizes[DMUB_WINDOW_SHARED_STATE] = DMUB_FW_HEADER_SHARED_STATE_SIZE;
 489
 490	out->fb_size =
 491		dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_FB);
 492
 493	out->gart_size =
 494		dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_GART);
 495
 496	return DMUB_STATUS_OK;
 497}
 498
 499enum dmub_status dmub_srv_calc_mem_info(struct dmub_srv *dmub,
 500				       const struct dmub_srv_memory_params *params,
 501				       struct dmub_srv_fb_info *out)
 502{
 503	uint32_t i;
 504
 505	if (!dmub->sw_init)
 506		return DMUB_STATUS_INVALID;
 507
 508	memset(out, 0, sizeof(*out));
 509
 510	if (params->region_info->num_regions != DMUB_NUM_WINDOWS)
 511		return DMUB_STATUS_INVALID;
 512
 513	for (i = 0; i < DMUB_NUM_WINDOWS; ++i) {
 514		const struct dmub_region *reg =
 515			&params->region_info->regions[i];
 516
 517		if (params->window_memory_type[i] == DMUB_WINDOW_MEMORY_TYPE_GART) {
 518			out->fb[i].cpu_addr = (uint8_t *)params->cpu_gart_addr + reg->base;
 519			out->fb[i].gpu_addr = params->gpu_gart_addr + reg->base;
 520		} else {
 521			out->fb[i].cpu_addr = (uint8_t *)params->cpu_fb_addr + reg->base;
 522			out->fb[i].gpu_addr = params->gpu_fb_addr + reg->base;
 523		}
 524
 525		out->fb[i].size = reg->top - reg->base;
 526	}
 527
 528	out->num_fb = DMUB_NUM_WINDOWS;
 529
 530	return DMUB_STATUS_OK;
 531}
 532
 533enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub,
 534					 bool *is_supported)
 535{
 536	*is_supported = false;
 537
 538	if (!dmub->sw_init)
 539		return DMUB_STATUS_INVALID;
 540
 541	if (dmub->hw_funcs.is_supported)
 542		*is_supported = dmub->hw_funcs.is_supported(dmub);
 543
 544	return DMUB_STATUS_OK;
 545}
 546
 547enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init)
 548{
 549	*is_hw_init = false;
 550
 551	if (!dmub->sw_init)
 552		return DMUB_STATUS_INVALID;
 553
 554	if (!dmub->hw_init)
 555		return DMUB_STATUS_OK;
 556
 557	if (dmub->hw_funcs.is_hw_init)
 558		*is_hw_init = dmub->hw_funcs.is_hw_init(dmub);
 559
 560	return DMUB_STATUS_OK;
 561}
 562
 563enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
 564				  const struct dmub_srv_hw_params *params)
 565{
 566	struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST];
 567	struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK];
 568	struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA];
 569	struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS];
 570	struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX];
 571	struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF];
 572	struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE];
 573	struct dmub_fb *scratch_mem_fb = params->fb[DMUB_WINDOW_7_SCRATCH_MEM];
 574	struct dmub_fb *shared_state_fb = params->fb[DMUB_WINDOW_SHARED_STATE];
 575
 576	struct dmub_rb_init_params rb_params, outbox0_rb_params;
 577	struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6, region6;
 578	struct dmub_region inbox1, outbox1, outbox0;
 579
 580	if (!dmub->sw_init)
 581		return DMUB_STATUS_INVALID;
 582
 583	if (!inst_fb || !stack_fb || !data_fb || !bios_fb || !mail_fb ||
 584		!tracebuff_fb || !fw_state_fb || !scratch_mem_fb) {
 585		ASSERT(0);
 586		return DMUB_STATUS_INVALID;
 587	}
 588
 589	dmub->fb_base = params->fb_base;
 590	dmub->fb_offset = params->fb_offset;
 591	dmub->psp_version = params->psp_version;
 592
 593	if (dmub->hw_funcs.reset)
 594		dmub->hw_funcs.reset(dmub);
 595
 596	/* reset the cache of the last wptr as well now that hw is reset */
 597	dmub->inbox1_last_wptr = 0;
 598
 599	cw0.offset.quad_part = inst_fb->gpu_addr;
 600	cw0.region.base = DMUB_CW0_BASE;
 601	cw0.region.top = cw0.region.base + inst_fb->size - 1;
 602
 603	cw1.offset.quad_part = stack_fb->gpu_addr;
 604	cw1.region.base = DMUB_CW1_BASE;
 605	cw1.region.top = cw1.region.base + stack_fb->size - 1;
 606
 607	if (params->fw_in_system_memory && dmub->hw_funcs.configure_dmub_in_system_memory)
 608		dmub->hw_funcs.configure_dmub_in_system_memory(dmub);
 609
 610	if (params->load_inst_const && dmub->hw_funcs.backdoor_load) {
 611		/**
 612		 * Read back all the instruction memory so we don't hang the
 613		 * DMCUB when backdoor loading if the write from x86 hasn't been
 614		 * flushed yet. This only occurs in backdoor loading.
 615		 */
 616		if (params->mem_access_type == DMUB_MEMORY_ACCESS_CPU)
 617			dmub_flush_buffer_mem(inst_fb);
 618
 619		if (params->fw_in_system_memory && dmub->hw_funcs.backdoor_load_zfb_mode)
 620			dmub->hw_funcs.backdoor_load_zfb_mode(dmub, &cw0, &cw1);
 621		else
 622			dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1);
 623	}
 624
 625	cw2.offset.quad_part = data_fb->gpu_addr;
 626	cw2.region.base = DMUB_CW0_BASE + inst_fb->size;
 627	cw2.region.top = cw2.region.base + data_fb->size;
 628
 629	cw3.offset.quad_part = bios_fb->gpu_addr;
 630	cw3.region.base = DMUB_CW3_BASE;
 631	cw3.region.top = cw3.region.base + bios_fb->size;
 632
 633	cw4.offset.quad_part = mail_fb->gpu_addr;
 634	cw4.region.base = DMUB_CW4_BASE;
 635	cw4.region.top = cw4.region.base + mail_fb->size;
 636
 637	/**
 638	 * Doubled the mailbox region to accomodate inbox and outbox.
 639	 * Note: Currently, currently total mailbox size is 16KB. It is split
 640	 * equally into 8KB between inbox and outbox. If this config is
 641	 * changed, then uncached base address configuration of outbox1
 642	 * has to be updated in funcs->setup_out_mailbox.
 643	 */
 644	inbox1.base = cw4.region.base;
 645	inbox1.top = cw4.region.base + DMUB_RB_SIZE;
 646	outbox1.base = inbox1.top;
 647	outbox1.top = cw4.region.top;
 648
 649	cw5.offset.quad_part = tracebuff_fb->gpu_addr;
 650	cw5.region.base = DMUB_CW5_BASE;
 651	cw5.region.top = cw5.region.base + tracebuff_fb->size;
 652
 653	outbox0.base = DMUB_REGION5_BASE + TRACE_BUFFER_ENTRY_OFFSET;
 654	outbox0.top = outbox0.base + tracebuff_fb->size - TRACE_BUFFER_ENTRY_OFFSET;
 655
 656	cw6.offset.quad_part = fw_state_fb->gpu_addr;
 657	cw6.region.base = DMUB_CW6_BASE;
 658	cw6.region.top = cw6.region.base + fw_state_fb->size;
 659
 660	dmub->fw_state = fw_state_fb->cpu_addr;
 661
 662	region6.offset.quad_part = shared_state_fb->gpu_addr;
 663	region6.region.base = DMUB_CW6_BASE;
 664	region6.region.top = region6.region.base + shared_state_fb->size;
 665
 666	dmub->shared_state = shared_state_fb->cpu_addr;
 667
 668	dmub->scratch_mem_fb = *scratch_mem_fb;
 669
 670	if (dmub->hw_funcs.setup_windows)
 671		dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, &cw5, &cw6, &region6);
 672
 673	if (dmub->hw_funcs.setup_outbox0)
 674		dmub->hw_funcs.setup_outbox0(dmub, &outbox0);
 675
 676	if (dmub->hw_funcs.setup_mailbox)
 677		dmub->hw_funcs.setup_mailbox(dmub, &inbox1);
 678	if (dmub->hw_funcs.setup_out_mailbox)
 679		dmub->hw_funcs.setup_out_mailbox(dmub, &outbox1);
 680
 681	dmub_memset(&rb_params, 0, sizeof(rb_params));
 682	rb_params.ctx = dmub;
 683	rb_params.base_address = mail_fb->cpu_addr;
 684	rb_params.capacity = DMUB_RB_SIZE;
 685	dmub_rb_init(&dmub->inbox1_rb, &rb_params);
 686
 687	// Initialize outbox1 ring buffer
 688	rb_params.ctx = dmub;
 689	rb_params.base_address = (void *) ((uint8_t *) (mail_fb->cpu_addr) + DMUB_RB_SIZE);
 690	rb_params.capacity = DMUB_RB_SIZE;
 691	dmub_rb_init(&dmub->outbox1_rb, &rb_params);
 692
 693	dmub_memset(&outbox0_rb_params, 0, sizeof(outbox0_rb_params));
 694	outbox0_rb_params.ctx = dmub;
 695	outbox0_rb_params.base_address = (void *)((uintptr_t)(tracebuff_fb->cpu_addr) + TRACE_BUFFER_ENTRY_OFFSET);
 696	outbox0_rb_params.capacity = tracebuff_fb->size - dmub_align(TRACE_BUFFER_ENTRY_OFFSET, 64);
 697	dmub_rb_init(&dmub->outbox0_rb, &outbox0_rb_params);
 698
 699	/* Report to DMUB what features are supported by current driver */
 700	if (dmub->hw_funcs.enable_dmub_boot_options)
 701		dmub->hw_funcs.enable_dmub_boot_options(dmub, params);
 702
 703	if (dmub->hw_funcs.skip_dmub_panel_power_sequence && !dmub->is_virtual)
 704		dmub->hw_funcs.skip_dmub_panel_power_sequence(dmub,
 705			params->skip_panel_power_sequence);
 706
 707	if (dmub->hw_funcs.reset_release && !dmub->is_virtual)
 708		dmub->hw_funcs.reset_release(dmub);
 709
 710	dmub->hw_init = true;
 711	dmub->power_state = DMUB_POWER_STATE_D0;
 712
 713	return DMUB_STATUS_OK;
 714}
 715
 716enum dmub_status dmub_srv_sync_inbox1(struct dmub_srv *dmub)
 717{
 718	if (!dmub->sw_init)
 719		return DMUB_STATUS_INVALID;
 720
 721	if (dmub->hw_funcs.get_inbox1_rptr && dmub->hw_funcs.get_inbox1_wptr) {
 722		uint32_t rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
 723		uint32_t wptr = dmub->hw_funcs.get_inbox1_wptr(dmub);
 724
 725		if (rptr > dmub->inbox1_rb.capacity || wptr > dmub->inbox1_rb.capacity) {
 726			return DMUB_STATUS_HW_FAILURE;
 727		} else {
 728			dmub->inbox1_rb.rptr = rptr;
 729			dmub->inbox1_rb.wrpt = wptr;
 730			dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt;
 731		}
 732	}
 733
 734	return DMUB_STATUS_OK;
 735}
 736
 737enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
 738{
 739	if (!dmub->sw_init)
 740		return DMUB_STATUS_INVALID;
 741
 742	if (dmub->hw_funcs.reset)
 743		dmub->hw_funcs.reset(dmub);
 744
 745	/* mailboxes have been reset in hw, so reset the sw state as well */
 746	dmub->inbox1_last_wptr = 0;
 747	dmub->inbox1_rb.wrpt = 0;
 748	dmub->inbox1_rb.rptr = 0;
 749	dmub->outbox0_rb.wrpt = 0;
 750	dmub->outbox0_rb.rptr = 0;
 751	dmub->outbox1_rb.wrpt = 0;
 752	dmub->outbox1_rb.rptr = 0;
 753
 754	dmub->hw_init = false;
 755
 756	return DMUB_STATUS_OK;
 757}
 758
 759enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub,
 760				    const union dmub_rb_cmd *cmd)
 761{
 762	if (!dmub->hw_init)
 763		return DMUB_STATUS_INVALID;
 764
 765	if (dmub->power_state != DMUB_POWER_STATE_D0)
 766		return DMUB_STATUS_POWER_STATE_D3;
 767
 768	if (dmub->inbox1_rb.rptr > dmub->inbox1_rb.capacity ||
 769	    dmub->inbox1_rb.wrpt > dmub->inbox1_rb.capacity) {
 770		return DMUB_STATUS_HW_FAILURE;
 771	}
 772
 773	if (dmub_rb_push_front(&dmub->inbox1_rb, cmd))
 774		return DMUB_STATUS_OK;
 775
 776	return DMUB_STATUS_QUEUE_FULL;
 777}
 778
 779enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub)
 780{
 781	struct dmub_rb flush_rb;
 782
 783	if (!dmub->hw_init)
 784		return DMUB_STATUS_INVALID;
 785
 786	if (dmub->power_state != DMUB_POWER_STATE_D0)
 787		return DMUB_STATUS_POWER_STATE_D3;
 788
 789	/**
 790	 * Read back all the queued commands to ensure that they've
 791	 * been flushed to framebuffer memory. Otherwise DMCUB might
 792	 * read back stale, fully invalid or partially invalid data.
 793	 */
 794	flush_rb = dmub->inbox1_rb;
 795	flush_rb.rptr = dmub->inbox1_last_wptr;
 796	dmub_rb_flush_pending(&flush_rb);
 797
 798	dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt);
 799
 800	dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt;
 801
 802	return DMUB_STATUS_OK;
 803}
 804
 805bool dmub_srv_is_hw_pwr_up(struct dmub_srv *dmub)
 806{
 807	if (!dmub->hw_funcs.is_hw_powered_up)
 808		return true;
 809
 810	if (!dmub->hw_funcs.is_hw_powered_up(dmub))
 811		return false;
 812
 813	return true;
 814}
 815
 816enum dmub_status dmub_srv_wait_for_hw_pwr_up(struct dmub_srv *dmub,
 817					     uint32_t timeout_us)
 818{
 819	uint32_t i;
 820
 821	if (!dmub->hw_init)
 822		return DMUB_STATUS_INVALID;
 823
 824	for (i = 0; i <= timeout_us; i += 100) {
 825		if (dmub_srv_is_hw_pwr_up(dmub))
 826			return DMUB_STATUS_OK;
 827
 828		udelay(100);
 829	}
 830
 831	return DMUB_STATUS_TIMEOUT;
 832}
 833
 834enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub,
 835					     uint32_t timeout_us)
 836{
 837	uint32_t i;
 838	bool hw_on = true;
 839
 840	if (!dmub->hw_init)
 841		return DMUB_STATUS_INVALID;
 842
 843	for (i = 0; i <= timeout_us; i += 100) {
 844		union dmub_fw_boot_status status = dmub->hw_funcs.get_fw_status(dmub);
 845
 846		if (dmub->hw_funcs.is_hw_powered_up)
 847			hw_on = dmub->hw_funcs.is_hw_powered_up(dmub);
 848
 849		if (status.bits.dal_fw && status.bits.mailbox_rdy && hw_on)
 850			return DMUB_STATUS_OK;
 851
 852		udelay(100);
 853	}
 854
 855	return DMUB_STATUS_TIMEOUT;
 856}
 857
 858enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
 859					uint32_t timeout_us)
 860{
 861	uint32_t i, rptr;
 862
 863	if (!dmub->hw_init)
 864		return DMUB_STATUS_INVALID;
 865
 866	for (i = 0; i <= timeout_us; ++i) {
 867		rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
 868
 869		if (rptr > dmub->inbox1_rb.capacity)
 870			return DMUB_STATUS_HW_FAILURE;
 871
 872		dmub->inbox1_rb.rptr = rptr;
 873
 874		if (dmub_rb_empty(&dmub->inbox1_rb))
 875			return DMUB_STATUS_OK;
 876
 877		udelay(1);
 878	}
 879
 880	return DMUB_STATUS_TIMEOUT;
 881}
 882
 883enum dmub_status
 884dmub_srv_send_gpint_command(struct dmub_srv *dmub,
 885			    enum dmub_gpint_command command_code,
 886			    uint16_t param, uint32_t timeout_us)
 887{
 888	union dmub_gpint_data_register reg;
 889	uint32_t i;
 890
 891	if (!dmub->sw_init)
 892		return DMUB_STATUS_INVALID;
 893
 894	if (!dmub->hw_funcs.set_gpint)
 895		return DMUB_STATUS_INVALID;
 896
 897	if (!dmub->hw_funcs.is_gpint_acked)
 898		return DMUB_STATUS_INVALID;
 899
 900	reg.bits.status = 1;
 901	reg.bits.command_code = command_code;
 902	reg.bits.param = param;
 903
 904	dmub->hw_funcs.set_gpint(dmub, reg);
 905
 906	for (i = 0; i < timeout_us; ++i) {
 907		udelay(1);
 908
 909		if (dmub->hw_funcs.is_gpint_acked(dmub, reg))
 910			return DMUB_STATUS_OK;
 911	}
 912
 913	return DMUB_STATUS_TIMEOUT;
 914}
 915
 916enum dmub_status dmub_srv_get_gpint_response(struct dmub_srv *dmub,
 917					     uint32_t *response)
 918{
 919	*response = 0;
 920
 921	if (!dmub->sw_init)
 922		return DMUB_STATUS_INVALID;
 923
 924	if (!dmub->hw_funcs.get_gpint_response)
 925		return DMUB_STATUS_INVALID;
 926
 927	*response = dmub->hw_funcs.get_gpint_response(dmub);
 928
 929	return DMUB_STATUS_OK;
 930}
 931
 932enum dmub_status dmub_srv_get_gpint_dataout(struct dmub_srv *dmub,
 933					     uint32_t *dataout)
 934{
 935	*dataout = 0;
 936
 937	if (!dmub->sw_init)
 938		return DMUB_STATUS_INVALID;
 939
 940	if (!dmub->hw_funcs.get_gpint_dataout)
 941		return DMUB_STATUS_INVALID;
 942
 943	*dataout = dmub->hw_funcs.get_gpint_dataout(dmub);
 944
 945	return DMUB_STATUS_OK;
 946}
 947
 948enum dmub_status dmub_srv_get_fw_boot_status(struct dmub_srv *dmub,
 949					     union dmub_fw_boot_status *status)
 950{
 951	status->all = 0;
 952
 953	if (!dmub->sw_init)
 954		return DMUB_STATUS_INVALID;
 955
 956	if (dmub->hw_funcs.get_fw_status)
 957		*status = dmub->hw_funcs.get_fw_status(dmub);
 958
 959	return DMUB_STATUS_OK;
 960}
 961
 962enum dmub_status dmub_srv_get_fw_boot_option(struct dmub_srv *dmub,
 963					     union dmub_fw_boot_options *option)
 964{
 965	option->all = 0;
 966
 967	if (!dmub->sw_init)
 968		return DMUB_STATUS_INVALID;
 969
 970	if (dmub->hw_funcs.get_fw_boot_option)
 971		*option = dmub->hw_funcs.get_fw_boot_option(dmub);
 972
 973	return DMUB_STATUS_OK;
 974}
 975
 976enum dmub_status dmub_srv_set_skip_panel_power_sequence(struct dmub_srv *dmub,
 977					     bool skip)
 978{
 979	if (!dmub->sw_init)
 980		return DMUB_STATUS_INVALID;
 981
 982	if (dmub->hw_funcs.skip_dmub_panel_power_sequence && !dmub->is_virtual)
 983		dmub->hw_funcs.skip_dmub_panel_power_sequence(dmub, skip);
 984
 985	return DMUB_STATUS_OK;
 986}
 987
 988enum dmub_status dmub_srv_cmd_with_reply_data(struct dmub_srv *dmub,
 989					      union dmub_rb_cmd *cmd)
 990{
 991	enum dmub_status status = DMUB_STATUS_OK;
 992
 993	// Queue command
 994	status = dmub_srv_cmd_queue(dmub, cmd);
 995
 996	if (status != DMUB_STATUS_OK)
 997		return status;
 998
 999	// Execute command
1000	status = dmub_srv_cmd_execute(dmub);
1001
1002	if (status != DMUB_STATUS_OK)
1003		return status;
1004
1005	// Wait for DMUB to process command
1006	status = dmub_srv_wait_for_idle(dmub, 100000);
1007
1008	if (status != DMUB_STATUS_OK)
1009		return status;
1010
1011	// Copy data back from ring buffer into command
1012	dmub_rb_get_return_data(&dmub->inbox1_rb, cmd);
1013
1014	return status;
1015}
1016
1017static inline bool dmub_rb_out_trace_buffer_front(struct dmub_rb *rb,
1018				 void *entry)
1019{
1020	const uint64_t *src = (const uint64_t *)(rb->base_address) + rb->rptr / sizeof(uint64_t);
1021	uint64_t *dst = (uint64_t *)entry;
1022	uint8_t i;
1023	uint8_t loop_count;
1024
1025	if (rb->rptr == rb->wrpt)
1026		return false;
1027
1028	loop_count = sizeof(struct dmcub_trace_buf_entry) / sizeof(uint64_t);
1029	// copying data
1030	for (i = 0; i < loop_count; i++)
1031		*dst++ = *src++;
1032
1033	rb->rptr += sizeof(struct dmcub_trace_buf_entry);
1034
1035	rb->rptr %= rb->capacity;
1036
1037	return true;
1038}
1039
1040bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entry *entry)
1041{
1042	dmub->outbox0_rb.wrpt = dmub->hw_funcs.get_outbox0_wptr(dmub);
1043
1044	return dmub_rb_out_trace_buffer_front(&dmub->outbox0_rb, (void *)entry);
1045}
1046
1047bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
1048{
1049	if (!dmub || !dmub->hw_funcs.get_diagnostic_data || !diag_data)
1050		return false;
1051	dmub->hw_funcs.get_diagnostic_data(dmub, diag_data);
1052	return true;
1053}
1054
1055bool dmub_srv_should_detect(struct dmub_srv *dmub)
1056{
1057	if (!dmub->hw_init || !dmub->hw_funcs.should_detect)
1058		return false;
1059
1060	return dmub->hw_funcs.should_detect(dmub);
1061}
1062
1063enum dmub_status dmub_srv_clear_inbox0_ack(struct dmub_srv *dmub)
1064{
1065	if (!dmub->hw_init || !dmub->hw_funcs.clear_inbox0_ack_register)
1066		return DMUB_STATUS_INVALID;
1067
1068	dmub->hw_funcs.clear_inbox0_ack_register(dmub);
1069	return DMUB_STATUS_OK;
1070}
1071
1072enum dmub_status dmub_srv_wait_for_inbox0_ack(struct dmub_srv *dmub, uint32_t timeout_us)
1073{
1074	uint32_t i = 0;
1075	uint32_t ack = 0;
1076
1077	if (!dmub->hw_init || !dmub->hw_funcs.read_inbox0_ack_register)
1078		return DMUB_STATUS_INVALID;
1079
1080	for (i = 0; i <= timeout_us; i++) {
1081		ack = dmub->hw_funcs.read_inbox0_ack_register(dmub);
1082		if (ack)
1083			return DMUB_STATUS_OK;
1084		udelay(1);
1085	}
1086	return DMUB_STATUS_TIMEOUT;
1087}
1088
1089enum dmub_status dmub_srv_send_inbox0_cmd(struct dmub_srv *dmub,
1090		union dmub_inbox0_data_register data)
1091{
1092	if (!dmub->hw_init || !dmub->hw_funcs.send_inbox0_cmd)
1093		return DMUB_STATUS_INVALID;
1094
1095	dmub->hw_funcs.send_inbox0_cmd(dmub, data);
1096	return DMUB_STATUS_OK;
1097}
1098
1099void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_address *addr, uint8_t subvp_index)
1100{
1101	if (dmub->hw_funcs.subvp_save_surf_addr) {
1102		dmub->hw_funcs.subvp_save_surf_addr(dmub,
1103				addr,
1104				subvp_index);
1105	}
1106}
1107
1108void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state)
1109{
1110	if (!dmub || !dmub->hw_init)
1111		return;
1112
1113	dmub->power_state = dmub_srv_power_state;
1114}