Path: blob/master/drivers/gpu/drm/amd/display/dc/dc_helper.c
26535 views
/*1* Copyright 2017 Advanced Micro Devices, Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*21*/22/*23* dc_helper.c24*25* Created on: Aug 30, 201626* Author: agrodzov27*/2829#include <linux/delay.h>30#include <linux/stdarg.h>3132#include "dm_services.h"3334#include "dc.h"35#include "dc_dmub_srv.h"36#include "reg_helper.h"3738#define DC_LOGGER \39ctx->logger4041static inline void submit_dmub_read_modify_write(42struct dc_reg_helper_state *offload,43const struct dc_context *ctx)44{45struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write;4647offload->should_burst_write =48(offload->same_addr_count == (DMUB_READ_MODIFY_WRITE_SEQ__MAX - 1));49cmd_buf->header.payload_bytes =50sizeof(struct dmub_cmd_read_modify_write_sequence) * offload->reg_seq_count;5152dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT);5354memset(cmd_buf, 0, sizeof(*cmd_buf));5556offload->reg_seq_count = 0;57offload->same_addr_count = 0;58}5960static inline void submit_dmub_burst_write(61struct dc_reg_helper_state *offload,62const struct dc_context *ctx)63{64struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write;6566cmd_buf->header.payload_bytes =67sizeof(uint32_t) * offload->reg_seq_count;6869dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT);7071memset(cmd_buf, 0, sizeof(*cmd_buf));7273offload->reg_seq_count = 0;74}7576static inline void submit_dmub_reg_wait(77struct dc_reg_helper_state *offload,78const struct dc_context *ctx)79{80struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait;8182dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT);8384memset(cmd_buf, 0, sizeof(*cmd_buf));85offload->reg_seq_count = 0;86}8788struct dc_reg_value_masks {89uint32_t value;90uint32_t mask;91};9293static inline void set_reg_field_value_masks(94struct dc_reg_value_masks *field_value_mask,95uint32_t value,96uint32_t mask,97uint8_t shift)98{99ASSERT(mask != 0);100101field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift));102field_value_mask->mask = field_value_mask->mask | mask;103}104105static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask,106uint32_t addr, int n,107uint8_t shift1, uint32_t mask1, uint32_t field_value1,108va_list ap)109{110uint32_t shift, mask, field_value;111int i = 1;112113/* gather all bits value/mask getting updated in this register */114set_reg_field_value_masks(field_value_mask,115field_value1, mask1, shift1);116117while (i < n) {118shift = va_arg(ap, uint32_t);119mask = va_arg(ap, uint32_t);120field_value = va_arg(ap, uint32_t);121122set_reg_field_value_masks(field_value_mask,123field_value, mask, shift);124i++;125}126}127128static void dmub_flush_buffer_execute(129struct dc_reg_helper_state *offload,130const struct dc_context *ctx)131{132submit_dmub_read_modify_write(offload, ctx);133}134135static void dmub_flush_burst_write_buffer_execute(136struct dc_reg_helper_state *offload,137const struct dc_context *ctx)138{139submit_dmub_burst_write(offload, ctx);140}141142static bool dmub_reg_value_burst_set_pack(const struct dc_context *ctx, uint32_t addr,143uint32_t reg_val)144{145struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload;146struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write;147148/* flush command if buffer is full */149if (offload->reg_seq_count == DMUB_BURST_WRITE_VALUES__MAX)150dmub_flush_burst_write_buffer_execute(offload, ctx);151152if (offload->cmd_data.cmd_common.header.type == DMUB_CMD__REG_SEQ_BURST_WRITE &&153addr != cmd_buf->addr) {154dmub_flush_burst_write_buffer_execute(offload, ctx);155return false;156}157158cmd_buf->header.type = DMUB_CMD__REG_SEQ_BURST_WRITE;159cmd_buf->header.sub_type = 0;160cmd_buf->addr = addr;161cmd_buf->write_values[offload->reg_seq_count] = reg_val;162offload->reg_seq_count++;163164return true;165}166167static uint32_t dmub_reg_value_pack(const struct dc_context *ctx, uint32_t addr,168struct dc_reg_value_masks *field_value_mask)169{170struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload;171struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write;172struct dmub_cmd_read_modify_write_sequence *seq;173174/* flush command if buffer is full */175if (offload->cmd_data.cmd_common.header.type != DMUB_CMD__REG_SEQ_BURST_WRITE &&176offload->reg_seq_count == DMUB_READ_MODIFY_WRITE_SEQ__MAX)177dmub_flush_buffer_execute(offload, ctx);178179if (offload->should_burst_write) {180if (dmub_reg_value_burst_set_pack(ctx, addr, field_value_mask->value))181return field_value_mask->value;182else183offload->should_burst_write = false;184}185186/* pack commands */187cmd_buf->header.type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE;188cmd_buf->header.sub_type = 0;189seq = &cmd_buf->seq[offload->reg_seq_count];190191if (offload->reg_seq_count) {192if (cmd_buf->seq[offload->reg_seq_count - 1].addr == addr)193offload->same_addr_count++;194else195offload->same_addr_count = 0;196}197198seq->addr = addr;199seq->modify_mask = field_value_mask->mask;200seq->modify_value = field_value_mask->value;201offload->reg_seq_count++;202203return field_value_mask->value;204}205206static void dmub_reg_wait_done_pack(const struct dc_context *ctx, uint32_t addr,207uint32_t mask, uint32_t shift, uint32_t condition_value, uint32_t time_out_us)208{209struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload;210struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait;211212cmd_buf->header.type = DMUB_CMD__REG_REG_WAIT;213cmd_buf->header.sub_type = 0;214cmd_buf->reg_wait.addr = addr;215cmd_buf->reg_wait.condition_field_value = mask & (condition_value << shift);216cmd_buf->reg_wait.mask = mask;217cmd_buf->reg_wait.time_out_us = time_out_us;218}219220uint32_t generic_reg_update_ex(const struct dc_context *ctx,221uint32_t addr, int n,222uint8_t shift1, uint32_t mask1, uint32_t field_value1,223...)224{225struct dc_reg_value_masks field_value_mask = {0};226uint32_t reg_val;227va_list ap;228229va_start(ap, field_value1);230231set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,232field_value1, ap);233234va_end(ap);235236if (ctx->dmub_srv &&237ctx->dmub_srv->reg_helper_offload.gather_in_progress)238return dmub_reg_value_pack(ctx, addr, &field_value_mask);239/* todo: return void so we can decouple code running in driver from register states */240241/* mmio write directly */242reg_val = dm_read_reg(ctx, addr);243reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;244dm_write_reg(ctx, addr, reg_val);245return reg_val;246}247248uint32_t generic_reg_set_ex(const struct dc_context *ctx,249uint32_t addr, uint32_t reg_val, int n,250uint8_t shift1, uint32_t mask1, uint32_t field_value1,251...)252{253struct dc_reg_value_masks field_value_mask = {0};254va_list ap;255256va_start(ap, field_value1);257258set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,259field_value1, ap);260261va_end(ap);262263/* mmio write directly */264reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;265266if (ctx->dmub_srv &&267ctx->dmub_srv->reg_helper_offload.gather_in_progress) {268return dmub_reg_value_burst_set_pack(ctx, addr, reg_val);269/* todo: return void so we can decouple code running in driver from register states */270}271272dm_write_reg(ctx, addr, reg_val);273return reg_val;274}275276uint32_t generic_reg_get(const struct dc_context *ctx, uint32_t addr,277uint8_t shift, uint32_t mask, uint32_t *field_value)278{279uint32_t reg_val = dm_read_reg(ctx, addr);280*field_value = get_reg_field_value_ex(reg_val, mask, shift);281return reg_val;282}283284uint32_t generic_reg_get2(const struct dc_context *ctx, uint32_t addr,285uint8_t shift1, uint32_t mask1, uint32_t *field_value1,286uint8_t shift2, uint32_t mask2, uint32_t *field_value2)287{288uint32_t reg_val = dm_read_reg(ctx, addr);289*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);290*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);291return reg_val;292}293294uint32_t generic_reg_get3(const struct dc_context *ctx, uint32_t addr,295uint8_t shift1, uint32_t mask1, uint32_t *field_value1,296uint8_t shift2, uint32_t mask2, uint32_t *field_value2,297uint8_t shift3, uint32_t mask3, uint32_t *field_value3)298{299uint32_t reg_val = dm_read_reg(ctx, addr);300*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);301*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);302*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);303return reg_val;304}305306uint32_t generic_reg_get4(const struct dc_context *ctx, uint32_t addr,307uint8_t shift1, uint32_t mask1, uint32_t *field_value1,308uint8_t shift2, uint32_t mask2, uint32_t *field_value2,309uint8_t shift3, uint32_t mask3, uint32_t *field_value3,310uint8_t shift4, uint32_t mask4, uint32_t *field_value4)311{312uint32_t reg_val = dm_read_reg(ctx, addr);313*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);314*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);315*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);316*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);317return reg_val;318}319320uint32_t generic_reg_get5(const struct dc_context *ctx, uint32_t addr,321uint8_t shift1, uint32_t mask1, uint32_t *field_value1,322uint8_t shift2, uint32_t mask2, uint32_t *field_value2,323uint8_t shift3, uint32_t mask3, uint32_t *field_value3,324uint8_t shift4, uint32_t mask4, uint32_t *field_value4,325uint8_t shift5, uint32_t mask5, uint32_t *field_value5)326{327uint32_t reg_val = dm_read_reg(ctx, addr);328*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);329*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);330*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);331*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);332*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);333return reg_val;334}335336uint32_t generic_reg_get6(const struct dc_context *ctx, uint32_t addr,337uint8_t shift1, uint32_t mask1, uint32_t *field_value1,338uint8_t shift2, uint32_t mask2, uint32_t *field_value2,339uint8_t shift3, uint32_t mask3, uint32_t *field_value3,340uint8_t shift4, uint32_t mask4, uint32_t *field_value4,341uint8_t shift5, uint32_t mask5, uint32_t *field_value5,342uint8_t shift6, uint32_t mask6, uint32_t *field_value6)343{344uint32_t reg_val = dm_read_reg(ctx, addr);345*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);346*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);347*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);348*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);349*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);350*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);351return reg_val;352}353354uint32_t generic_reg_get7(const struct dc_context *ctx, uint32_t addr,355uint8_t shift1, uint32_t mask1, uint32_t *field_value1,356uint8_t shift2, uint32_t mask2, uint32_t *field_value2,357uint8_t shift3, uint32_t mask3, uint32_t *field_value3,358uint8_t shift4, uint32_t mask4, uint32_t *field_value4,359uint8_t shift5, uint32_t mask5, uint32_t *field_value5,360uint8_t shift6, uint32_t mask6, uint32_t *field_value6,361uint8_t shift7, uint32_t mask7, uint32_t *field_value7)362{363uint32_t reg_val = dm_read_reg(ctx, addr);364*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);365*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);366*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);367*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);368*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);369*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);370*field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);371return reg_val;372}373374uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr,375uint8_t shift1, uint32_t mask1, uint32_t *field_value1,376uint8_t shift2, uint32_t mask2, uint32_t *field_value2,377uint8_t shift3, uint32_t mask3, uint32_t *field_value3,378uint8_t shift4, uint32_t mask4, uint32_t *field_value4,379uint8_t shift5, uint32_t mask5, uint32_t *field_value5,380uint8_t shift6, uint32_t mask6, uint32_t *field_value6,381uint8_t shift7, uint32_t mask7, uint32_t *field_value7,382uint8_t shift8, uint32_t mask8, uint32_t *field_value8)383{384uint32_t reg_val = dm_read_reg(ctx, addr);385*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);386*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);387*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);388*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);389*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);390*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);391*field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);392*field_value8 = get_reg_field_value_ex(reg_val, mask8, shift8);393return reg_val;394}395/* note: va version of this is pretty bad idea, since there is a output parameter pass by pointer396* compiler won't be able to check for size match and is prone to stack corruption type of bugs397398uint32_t generic_reg_get(const struct dc_context *ctx,399uint32_t addr, int n, ...)400{401uint32_t shift, mask;402uint32_t *field_value;403uint32_t reg_val;404int i = 0;405406reg_val = dm_read_reg(ctx, addr);407408va_list ap;409va_start(ap, n);410411while (i < n) {412shift = va_arg(ap, uint32_t);413mask = va_arg(ap, uint32_t);414field_value = va_arg(ap, uint32_t *);415416*field_value = get_reg_field_value_ex(reg_val, mask, shift);417i++;418}419420va_end(ap);421422return reg_val;423}424*/425426void generic_reg_wait(const struct dc_context *ctx,427uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value,428unsigned int delay_between_poll_us, unsigned int time_out_num_tries,429const char *func_name, int line)430{431uint32_t field_value;432uint32_t reg_val;433int i;434435if (ctx->dmub_srv &&436ctx->dmub_srv->reg_helper_offload.gather_in_progress) {437dmub_reg_wait_done_pack(ctx, addr, mask, shift, condition_value,438delay_between_poll_us * time_out_num_tries);439return;440}441442/*443* Something is terribly wrong if time out is > 3000ms.444* 3000ms is the maximum time needed for SMU to pass values back.445* This value comes from experiments.446*447*/448ASSERT(delay_between_poll_us * time_out_num_tries <= 3000000);449450for (i = 0; i <= time_out_num_tries; i++) {451if (i) {452if (delay_between_poll_us >= 1000)453msleep(delay_between_poll_us/1000);454else if (delay_between_poll_us > 0)455udelay(delay_between_poll_us);456}457458reg_val = dm_read_reg(ctx, addr);459460field_value = get_reg_field_value_ex(reg_val, mask, shift);461462if (field_value == condition_value) {463if (i * delay_between_poll_us > 1000)464DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n",465delay_between_poll_us * i / 1000,466func_name, line);467return;468}469}470471DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n",472delay_between_poll_us, time_out_num_tries,473func_name, line);474475BREAK_TO_DEBUGGER();476}477478void generic_write_indirect_reg(const struct dc_context *ctx,479uint32_t addr_index, uint32_t addr_data,480uint32_t index, uint32_t data)481{482dm_write_reg(ctx, addr_index, index);483dm_write_reg(ctx, addr_data, data);484}485486uint32_t generic_read_indirect_reg(const struct dc_context *ctx,487uint32_t addr_index, uint32_t addr_data,488uint32_t index)489{490uint32_t value = 0;491492// when reg read, there should not be any offload.493if (ctx->dmub_srv &&494ctx->dmub_srv->reg_helper_offload.gather_in_progress) {495ASSERT(false);496}497498dm_write_reg(ctx, addr_index, index);499value = dm_read_reg(ctx, addr_data);500501return value;502}503504uint32_t generic_indirect_reg_get(const struct dc_context *ctx,505uint32_t addr_index, uint32_t addr_data,506uint32_t index, int n,507uint8_t shift1, uint32_t mask1, uint32_t *field_value1,508...)509{510uint32_t shift, mask, *field_value;511uint32_t value = 0;512int i = 1;513514va_list ap;515516va_start(ap, field_value1);517518value = generic_read_indirect_reg(ctx, addr_index, addr_data, index);519*field_value1 = get_reg_field_value_ex(value, mask1, shift1);520521while (i < n) {522shift = va_arg(ap, uint32_t);523mask = va_arg(ap, uint32_t);524field_value = va_arg(ap, uint32_t *);525526*field_value = get_reg_field_value_ex(value, mask, shift);527i++;528}529530va_end(ap);531532return value;533}534535uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx,536uint32_t addr_index, uint32_t addr_data,537uint32_t index, uint32_t reg_val, int n,538uint8_t shift1, uint32_t mask1, uint32_t field_value1,539...)540{541uint32_t shift, mask, field_value;542int i = 1;543544va_list ap;545546va_start(ap, field_value1);547548reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);549550while (i < n) {551shift = va_arg(ap, uint32_t);552mask = va_arg(ap, uint32_t);553field_value = va_arg(ap, uint32_t);554555reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);556i++;557}558559generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val);560va_end(ap);561562return reg_val;563}564565566uint32_t generic_indirect_reg_update_ex_sync(const struct dc_context *ctx,567uint32_t index, uint32_t reg_val, int n,568uint8_t shift1, uint32_t mask1, uint32_t field_value1,569...)570{571uint32_t shift, mask, field_value;572int i = 1;573574va_list ap;575576va_start(ap, field_value1);577578reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);579580while (i < n) {581shift = va_arg(ap, uint32_t);582mask = va_arg(ap, uint32_t);583field_value = va_arg(ap, uint32_t);584585reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);586i++;587}588589dm_write_index_reg(ctx, CGS_IND_REG__PCIE, index, reg_val);590va_end(ap);591592return reg_val;593}594595uint32_t generic_indirect_reg_get_sync(const struct dc_context *ctx,596uint32_t index, int n,597uint8_t shift1, uint32_t mask1, uint32_t *field_value1,598...)599{600uint32_t shift, mask, *field_value;601uint32_t value = 0;602int i = 1;603604va_list ap;605606va_start(ap, field_value1);607608value = dm_read_index_reg(ctx, CGS_IND_REG__PCIE, index);609*field_value1 = get_reg_field_value_ex(value, mask1, shift1);610611while (i < n) {612shift = va_arg(ap, uint32_t);613mask = va_arg(ap, uint32_t);614field_value = va_arg(ap, uint32_t *);615616*field_value = get_reg_field_value_ex(value, mask, shift);617i++;618}619620va_end(ap);621622return value;623}624625void reg_sequence_start_gather(const struct dc_context *ctx)626{627/* if reg sequence is supported and enabled, set flag to628* indicate we want to have REG_SET, REG_UPDATE macro build629* reg sequence command buffer rather than MMIO directly.630*/631632if (ctx->dmub_srv && ctx->dc->debug.dmub_offload_enabled) {633struct dc_reg_helper_state *offload =634&ctx->dmub_srv->reg_helper_offload;635636/* caller sequence mismatch. need to debug caller. offload will not work!!! */637ASSERT(!offload->gather_in_progress);638639offload->gather_in_progress = true;640}641}642643void reg_sequence_start_execute(const struct dc_context *ctx)644{645struct dc_reg_helper_state *offload;646647if (!ctx->dmub_srv)648return;649650offload = &ctx->dmub_srv->reg_helper_offload;651652if (offload && offload->gather_in_progress) {653offload->gather_in_progress = false;654offload->should_burst_write = false;655switch (offload->cmd_data.cmd_common.header.type) {656case DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE:657submit_dmub_read_modify_write(offload, ctx);658break;659case DMUB_CMD__REG_REG_WAIT:660submit_dmub_reg_wait(offload, ctx);661break;662case DMUB_CMD__REG_SEQ_BURST_WRITE:663submit_dmub_burst_write(offload, ctx);664break;665default:666return;667}668}669}670671void reg_sequence_wait_done(const struct dc_context *ctx)672{673/* callback to DM to poll for last submission done*/674struct dc_reg_helper_state *offload;675676if (!ctx->dmub_srv)677return;678679offload = &ctx->dmub_srv->reg_helper_offload;680681if (offload &&682ctx->dc->debug.dmub_offload_enabled &&683!ctx->dc->debug.dmcub_emulation) {684dc_dmub_srv_wait_for_idle(ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL);685}686}687688char *dce_version_to_string(const int version)689{690switch (version) {691case DCE_VERSION_6_0:692return "DCE 6.0";693case DCE_VERSION_6_1:694return "DCE 6.1";695case DCE_VERSION_6_4:696return "DCE 6.4";697case DCE_VERSION_8_0:698return "DCE 8.0";699case DCE_VERSION_8_1:700return "DCE 8.1";701case DCE_VERSION_8_3:702return "DCE 8.3";703case DCE_VERSION_10_0:704return "DCE 10.0";705case DCE_VERSION_11_0:706return "DCE 11.0";707case DCE_VERSION_11_2:708return "DCE 11.2";709case DCE_VERSION_11_22:710return "DCE 11.22";711case DCE_VERSION_12_0:712return "DCE 12.0";713case DCE_VERSION_12_1:714return "DCE 12.1";715case DCN_VERSION_1_0:716return "DCN 1.0";717case DCN_VERSION_1_01:718return "DCN 1.0.1";719case DCN_VERSION_2_0:720return "DCN 2.0";721case DCN_VERSION_2_1:722return "DCN 2.1";723case DCN_VERSION_2_01:724return "DCN 2.0.1";725case DCN_VERSION_3_0:726return "DCN 3.0";727case DCN_VERSION_3_01:728return "DCN 3.0.1";729case DCN_VERSION_3_02:730return "DCN 3.0.2";731case DCN_VERSION_3_03:732return "DCN 3.0.3";733case DCN_VERSION_3_1:734return "DCN 3.1";735case DCN_VERSION_3_14:736return "DCN 3.1.4";737case DCN_VERSION_3_15:738return "DCN 3.1.5";739case DCN_VERSION_3_16:740return "DCN 3.1.6";741case DCN_VERSION_3_2:742return "DCN 3.2";743case DCN_VERSION_3_21:744return "DCN 3.2.1";745case DCN_VERSION_3_5:746return "DCN 3.5";747case DCN_VERSION_3_51:748return "DCN 3.5.1";749case DCN_VERSION_3_6:750return "DCN 3.6";751case DCN_VERSION_4_01:752return "DCN 4.0.1";753default:754return "Unknown";755}756}757758759