Linux Audio

Check our new training course

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