diff options
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/Makefile | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/bios/command_table2.c | 91 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 119 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc_helper.c | 273 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc_types.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dm_services.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/inc/reg_helper.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/os_types.h | 1 |
15 files changed, 640 insertions, 1 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index a160512a2f04..6fe39f6392c7 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -70,5 +70,9 @@ AMD_DM_REG_UPDATE = $(addprefix $(AMDDALPATH)/dc/,dc_helper.o) AMD_DISPLAY_FILES += $(AMD_DISPLAY_CORE) AMD_DISPLAY_FILES += $(AMD_DM_REG_UPDATE) - +ifdef CONFIG_DRM_AMD_DC_DMUB +DC_DMUB += dc_dmub_srv.o +AMD_DISPLAY_DMUB = $(addprefix $(AMDDALPATH)/dc/,$(DC_DMUB)) +AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB) +endif diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index bb2e8105e6ab..a3d890050e39 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -37,6 +37,10 @@ #include "bios_parser_types_internal2.h" #include "amdgpu.h" +#ifdef CONFIG_DRM_AMD_DC_DMUB +#include "dc_dmub_srv.h" +#include "dc.h" +#endif #define DC_LOGGER \ bp->base.ctx->logger @@ -103,6 +107,21 @@ static void init_dig_encoder_control(struct bios_parser *bp) } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static void encoder_control_dmcub( + struct dc_dmub_srv *dmcub, + struct dig_encoder_stream_setup_parameters_v1_5 *dig) +{ + struct dmub_rb_cmd_digx_encoder_control encoder_control = { 0 }; + + encoder_control.header.type = DMUB_CMD__DIGX_ENCODER_CONTROL; + encoder_control.encoder_control.dig.stream_param = *dig; + + dc_dmub_srv_cmd_queue(dmcub, &encoder_control.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} +#endif static enum bp_result encoder_control_digx_v1_5( struct bios_parser *bp, struct bp_encoder_control *cntl) @@ -154,6 +173,13 @@ static enum bp_result encoder_control_digx_v1_5( default: break; } +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + encoder_control_dmcub(bp->base.ctx->dmub_srv, ¶ms); + return BP_RESULT_OK; + } +#endif if (EXEC_BIOS_CMD_TABLE(digxencodercontrol, params)) result = BP_RESULT_OK; @@ -190,7 +216,21 @@ static void init_transmitter_control(struct bios_parser *bp) break; } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static void transmitter_control_dmcub( + struct dc_dmub_srv *dmcub, + struct dig_transmitter_control_parameters_v1_6 *dig) +{ + struct dmub_rb_cmd_dig1_transmitter_control transmitter_control; + + transmitter_control.header.type = DMUB_CMD__DIG1_TRANSMITTER_CONTROL; + transmitter_control.transmitter_control.dig = *dig; + dc_dmub_srv_cmd_queue(dmcub, &transmitter_control.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} +#endif static enum bp_result transmitter_control_v1_6( struct bios_parser *bp, struct bp_transmitter_control *cntl) @@ -223,6 +263,14 @@ static enum bp_result transmitter_control_v1_6( } +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + transmitter_control_dmcub(bp->base.ctx->dmub_srv, &ps.param); + return BP_RESULT_OK; + } +#endif + /*color_depth not used any more, driver has deep color factor in the Phyclk*/ if (EXEC_BIOS_CMD_TABLE(dig1transmittercontrol, ps)) result = BP_RESULT_OK; @@ -255,7 +303,21 @@ static void init_set_pixel_clock(struct bios_parser *bp) } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static void set_pixel_clock_dmcub( + struct dc_dmub_srv *dmcub, + struct set_pixel_clock_parameter_v1_7 *clk) +{ + struct dmub_rb_cmd_set_pixel_clock pixel_clock = { 0 }; + pixel_clock.header.type = DMUB_CMD__SET_PIXEL_CLOCK; + pixel_clock.pixel_clock.clk = *clk; + + dc_dmub_srv_cmd_queue(dmcub, &pixel_clock.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} +#endif static enum bp_result set_pixel_clock_v7( struct bios_parser *bp, @@ -331,6 +393,13 @@ static enum bp_result set_pixel_clock_v7( if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK) clk.miscinfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN; +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + set_pixel_clock_dmcub(bp->base.ctx->dmub_srv, &clk); + return BP_RESULT_OK; + } +#endif if (EXEC_BIOS_CMD_TABLE(setpixelclock, clk)) result = BP_RESULT_OK; } @@ -584,7 +653,21 @@ static void init_enable_disp_power_gating( break; } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static void enable_disp_power_gating_dmcub( + struct dc_dmub_srv *dmcub, + struct enable_disp_power_gating_parameters_v2_1 *pwr) +{ + struct dmub_rb_cmd_enable_disp_power_gating power_gating; + + power_gating.header.type = DMUB_CMD__ENABLE_DISP_POWER_GATING; + power_gating.power_gating.pwr = *pwr; + dc_dmub_srv_cmd_queue(dmcub, &power_gating.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} +#endif static enum bp_result enable_disp_power_gating_v2_1( struct bios_parser *bp, enum controller_id crtc_id, @@ -604,6 +687,14 @@ static enum bp_result enable_disp_power_gating_v2_1( ps.param.enable = bp->cmd_helper->disp_power_gating_action_to_atom(action); +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + enable_disp_power_gating_dmcub(bp->base.ctx->dmub_srv, + &ps.param); + return BP_RESULT_OK; + } +#endif if (EXEC_BIOS_CMD_TABLE(enabledisppowergating, ps.param)) result = BP_RESULT_OK; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 32f31bf91915..2bf4da41577a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -59,6 +59,10 @@ #include "dc_link_dp.h" +#ifdef CONFIG_DRM_AMD_DC_DMUB +#include "dc_dmub_srv.h" +#endif + #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dsc.h" #endif @@ -2406,6 +2410,10 @@ void dc_set_power_state( switch (power_state) { case DC_ACPI_CM_POWER_STATE_D0: dc_resource_state_construct(dc, dc->current_state); +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (dc->ctx->dmub_srv) + dc_dmub_srv_wait_phy_init(dc->ctx->dmub_srv); +#endif dc->hwss.init_hw(dc); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 0416a17b0897..33828f03fe9e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -112,6 +112,9 @@ struct dc_caps { bool disable_dp_clk_share; bool psp_setup_panel_mode; bool extended_aux_timeout_support; +#ifdef CONFIG_DRM_AMD_DC_DMUB + bool dmcub_support; +#endif #ifdef CONFIG_DRM_AMD_DC_DCN2_0 bool hw_3d_lut; #endif @@ -401,6 +404,11 @@ struct dc_debug_options { unsigned int force_odm_combine; //bit vector based on otg inst unsigned int force_fclk_khz; bool disable_tri_buf; +#ifdef CONFIG_DRM_AMD_DC_DMUB + bool dmub_offload_enabled; + bool dmcub_emulation; + bool dmub_command_table; /* for testing only */ +#endif struct dc_bw_validation_profile bw_val_profile; #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool disable_fec; @@ -558,6 +566,10 @@ struct dc_init_data { struct dc_bios *vbios_override; enum dce_environment dce_environment; +#ifdef CONFIG_DRM_AMD_DC_DMUB + struct dmub_offload_funcs *dmub_if; + struct dc_reg_helper_state *dmub_offload; +#endif struct dc_config flags; uint32_t log_mask; #ifdef CONFIG_DRM_AMD_DC_DCN2_0 diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c new file mode 100644 index 000000000000..61cefe0a3790 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -0,0 +1,119 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dc.h" +#include "dc_dmub_srv.h" +#include "../dmub/inc/dmub_srv.h" + +static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc, + struct dmub_srv *dmub) +{ + dc_srv->dmub = dmub; + dc_srv->ctx = dc->ctx; +} + +struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub) +{ + struct dc_dmub_srv *dc_srv = + kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL); + + if (dc_srv == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dc_dmub_srv_construct(dc_srv, dc, dmub); + + return dc_srv; +} + +void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv) +{ + if (*dmub_srv) { + kfree(*dmub_srv); + *dmub_srv = NULL; + } +} + +void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, + struct dmub_cmd_header *cmd) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + status = dmub_srv_cmd_queue(dmub, cmd); + if (status == DMUB_STATUS_OK) + return; + + if (status != DMUB_STATUS_QUEUE_FULL) + goto error; + + /* Execute and wait for queue to become empty again. */ + dc_dmub_srv_cmd_execute(dc_dmub_srv); + dc_dmub_srv_wait_idle(dc_dmub_srv); + + /* Requeue the command. */ + status = dmub_srv_cmd_queue(dmub, cmd); + if (status == DMUB_STATUS_OK) + return; + +error: + DC_ERROR("Error queuing DMUB command: status=%d\n", status); +} + +void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + status = dmub_srv_cmd_execute(dmub); + if (status != DMUB_STATUS_OK) + DC_ERROR("Error starting DMUB exeuction: status=%d\n", status); +} + +void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + status = dmub_srv_wait_for_idle(dmub, 100000); + if (status != DMUB_STATUS_OK) + DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); +} + +void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + status = dmub_srv_wait_for_phy_init(dmub, 1000000); + if (status != DMUB_STATUS_OK) + DC_ERROR("Error waiting for DMUB phy init: status=%d\n", + status); +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h new file mode 100644 index 000000000000..754b6077539c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_DC_SRV_H_ +#define _DMUB_DC_SRV_H_ + +#include "os_types.h" +#include "../dmub/inc/dmub_cmd.h" + +struct dmub_srv; +struct dmub_cmd_header; + +struct dc_reg_helper_state { + bool gather_in_progress; + uint32_t same_addr_count; + bool should_burst_write; + union dmub_rb_cmd cmd_data; + unsigned int reg_seq_count; +}; + +struct dc_dmub_srv { + struct dmub_srv *dmub; + struct dc_reg_helper_state reg_helper_offload; + + struct dc_context *ctx; + void *dm; +}; + +void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, + struct dmub_cmd_header *cmd); + +void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv); + +void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv); + +void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv); + +#endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index 30b2f9edd42f..59b4bbefb7a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -32,6 +32,76 @@ #include "dm_services.h" #include <stdarg.h> +#ifdef CONFIG_DRM_AMD_DC_DMUB +#include "dc.h" +#include "dc_dmub_srv.h" + +static inline void submit_dmub_read_modify_write( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; + bool gather = false; + + offload->should_burst_write = + (offload->same_addr_count == (DMUB_READ_MODIFY_WRITE_SEQ__MAX - 1)); + cmd_buf->header.payload_bytes = + sizeof(struct dmub_cmd_read_modify_write_sequence) * offload->reg_seq_count; + + gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; + ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; + + dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); + + ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; + + memset(cmd_buf, 0, sizeof(*cmd_buf)); + + offload->reg_seq_count = 0; + offload->same_addr_count = 0; +} + +static inline void submit_dmub_burst_write( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; + bool gather = false; + + cmd_buf->header.payload_bytes = + sizeof(uint32_t) * offload->reg_seq_count; + + gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; + ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; + + dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); + + ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; + + memset(cmd_buf, 0, sizeof(*cmd_buf)); + + offload->reg_seq_count = 0; +} + +static inline void submit_dmub_reg_wait( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; + bool gather = false; + + gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; + ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; + + dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); + + memset(cmd_buf, 0, sizeof(*cmd_buf)); + offload->reg_seq_count = 0; + + ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; +} +#endif + struct dc_reg_value_masks { uint32_t value; uint32_t mask; @@ -77,6 +147,100 @@ static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask, } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static void dmub_flush_buffer_execute( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + submit_dmub_read_modify_write(offload, ctx); + dc_dmub_srv_cmd_execute(ctx->dmub_srv); +} + +static void dmub_flush_burst_write_buffer_execute( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + submit_dmub_burst_write(offload, ctx); + dc_dmub_srv_cmd_execute(ctx->dmub_srv); +} + +static bool dmub_reg_value_burst_set_pack(const struct dc_context *ctx, uint32_t addr, + uint32_t reg_val) +{ + struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; + struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; + + /* flush command if buffer is full */ + if (offload->reg_seq_count == DMUB_BURST_WRITE_VALUES__MAX) + dmub_flush_burst_write_buffer_execute(offload, ctx); + + if (offload->cmd_data.cmd_common.header.type == DMUB_CMD__REG_SEQ_BURST_WRITE && + addr != cmd_buf->addr) { + dmub_flush_burst_write_buffer_execute(offload, ctx); + return false; + } + + cmd_buf->header.type = DMUB_CMD__REG_SEQ_BURST_WRITE; + cmd_buf->addr = addr; + cmd_buf->write_values[offload->reg_seq_count] = reg_val; + offload->reg_seq_count++; + + return true; +} + +static uint32_t dmub_reg_value_pack(const struct dc_context *ctx, uint32_t addr, + struct dc_reg_value_masks *field_value_mask) +{ + struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; + struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; + struct dmub_cmd_read_modify_write_sequence *seq; + + /* flush command if buffer is full */ + if (offload->cmd_data.cmd_common.header.type != DMUB_CMD__REG_SEQ_BURST_WRITE && + offload->reg_seq_count == DMUB_READ_MODIFY_WRITE_SEQ__MAX) + dmub_flush_buffer_execute(offload, ctx); + + if (offload->should_burst_write) { + if (dmub_reg_value_burst_set_pack(ctx, addr, field_value_mask->value)) + return field_value_mask->value; + else + offload->should_burst_write = false; + } + + /* pack commands */ + cmd_buf->header.type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE; + seq = &cmd_buf->seq[offload->reg_seq_count]; + + if (offload->reg_seq_count) { + if (cmd_buf->seq[offload->reg_seq_count - 1].addr == addr) + offload->same_addr_count++; + else + offload->same_addr_count = 0; + } + + seq->addr = addr; + seq->modify_mask = field_value_mask->mask; + seq->modify_value = field_value_mask->value; + offload->reg_seq_count++; + + return field_value_mask->value; +} + +static void dmub_reg_wait_done_pack(const struct dc_context *ctx, uint32_t addr, + uint32_t mask, uint32_t shift, uint32_t condition_value, uint32_t time_out_us) +{ + struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; + struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; + + cmd_buf->header.type = DMUB_CMD__REG_REG_WAIT; + cmd_buf->reg_wait.addr = addr; + cmd_buf->reg_wait.condition_field_value = mask & (condition_value << shift); + cmd_buf->reg_wait.mask = mask; + cmd_buf->reg_wait.time_out_us = time_out_us; +} + +#endif + uint32_t generic_reg_update_ex(const struct dc_context *ctx, uint32_t addr, int n, uint8_t shift1, uint32_t mask1, uint32_t field_value1, @@ -93,6 +257,13 @@ uint32_t generic_reg_update_ex(const struct dc_context *ctx, va_end(ap); +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) + return dmub_reg_value_pack(ctx, addr, &field_value_mask); + /* todo: return void so we can decouple code running in driver from register states */ +#endif + /* mmio write directly */ reg_val = dm_read_reg(ctx, addr); reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; @@ -118,6 +289,13 @@ uint32_t generic_reg_set_ex(const struct dc_context *ctx, /* mmio write directly */ reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) { + return dmub_reg_value_burst_set_pack(ctx, addr, reg_val); + /* todo: return void so we can decouple code running in driver from register states */ + } +#endif dm_write_reg(ctx, addr, reg_val); return reg_val; } @@ -134,6 +312,16 @@ uint32_t dm_read_reg_func( return 0; } #endif + +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress && + !ctx->dmub_srv->reg_helper_offload.should_burst_write) { + ASSERT(false); + return 0; + } +#endif + value = cgs_read_register(ctx->cgs_device, address); trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value); @@ -299,6 +487,15 @@ void generic_reg_wait(const struct dc_context *ctx, uint32_t reg_val; int i; +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) { + dmub_reg_wait_done_pack(ctx, addr, mask, shift, condition_value, + delay_between_poll_us * time_out_num_tries); + return; + } +#endif + /* something is terribly wrong if time out is > 200ms. (5Hz) */ ASSERT(delay_between_poll_us * time_out_num_tries <= 3000000); @@ -345,6 +542,13 @@ uint32_t generic_read_indirect_reg(const struct dc_context *ctx, uint32_t index) { uint32_t value = 0; +#ifdef CONFIG_DRM_AMD_DC_DMUB + // when reg read, there should not be any offload. + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) { + ASSERT(false); + } +#endif dm_write_reg(ctx, addr_index, index); value = dm_read_reg(ctx, addr_data); @@ -382,3 +586,72 @@ uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, return reg_val; } + +#ifdef CONFIG_DRM_AMD_DC_DMUB +void reg_sequence_start_gather(const struct dc_context *ctx) +{ + /* if reg sequence is supported and enabled, set flag to + * indicate we want to have REG_SET, REG_UPDATE macro build + * reg sequence command buffer rather than MMIO directly. + */ + + if (ctx->dmub_srv && ctx->dc->debug.dmub_offload_enabled) { + struct dc_reg_helper_state *offload = + &ctx->dmub_srv->reg_helper_offload; + + /* caller sequence mismatch. need to debug caller. offload will not work!!! */ + ASSERT(!offload->gather_in_progress); + + offload->gather_in_progress = true; + } +} + +void reg_sequence_start_execute(const struct dc_context *ctx) +{ + struct dc_reg_helper_state *offload; + + if (!ctx->dmub_srv) + return; + + offload = &ctx->dmub_srv->reg_helper_offload; + + if (offload && offload->gather_in_progress) { + offload->gather_in_progress = false; + offload->should_burst_write = false; + switch (offload->cmd_data.cmd_common.header.type) { + case DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE: + submit_dmub_read_modify_write(offload, ctx); + break; + case DMUB_CMD__REG_REG_WAIT: + submit_dmub_reg_wait(offload, ctx); + break; + case DMUB_CMD__REG_SEQ_BURST_WRITE: + submit_dmub_burst_write(offload, ctx); + break; + default: + return; + } + + dc_dmub_srv_cmd_execute(ctx->dmub_srv); + } +} + +void reg_sequence_wait_done(const struct dc_context *ctx) +{ + /* callback to DM to poll for last submission done*/ + struct dc_reg_helper_state *offload; + + if (!ctx->dmub_srv) + return; + + offload = &ctx->dmub_srv->reg_helper_offload; + + if (offload && + ctx->dc->debug.dmub_offload_enabled && + !ctx->dc->debug.dmcub_emulation) { + dc_dmub_srv_wait_idle(ctx->dmub_srv); + } +} + + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index d9be8fc3889f..fb70ed9b351f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -48,6 +48,9 @@ struct dc_stream_state; struct dc_link; struct dc_sink; struct dal; +#ifdef CONFIG_DRM_AMD_DC_DMUB +struct dc_dmub_srv; +#endif /******************************** * Environment definitions @@ -109,6 +112,9 @@ struct dc_context { uint32_t dc_sink_id_count; uint32_t dc_stream_id_count; uint64_t fbc_gpu_addr; +#ifdef CONFIG_DRM_AMD_DC_DMUB + struct dc_dmub_srv *dmub_srv; +#endif #ifdef CONFIG_DRM_AMD_DC_HDCP struct cp_psp cp_psp; #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index aa0c7a7d13a0..41a0e53d2ba4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -352,6 +352,9 @@ void dpp1_cm_program_regamma_lut(struct dpp *dpp_base, uint32_t i; struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); +#ifdef CONFIG_DRM_AMD_DC_DMUB + REG_SEQ_START(); +#endif for (i = 0 ; i < num; i++) { REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].red_reg); REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].green_reg); @@ -630,6 +633,10 @@ void dpp1_set_degamma( BREAK_TO_DEBUGGER(); break; } +#ifdef CONFIG_DRM_AMD_DC_DMUB + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); +#endif } void dpp1_degamma_ram_select( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index dabccbd49ad4..8710f3ac2abf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -457,11 +457,19 @@ static bool optc1_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); +#ifdef CONFIG_DRM_AMD_DC_DMUB + REG_SEQ_START(); +#endif /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 3, OTG_MASTER_EN, 1); +#ifdef CONFIG_DRM_AMD_DC_DMUB + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); +#endif + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c index 5a188b2bc033..2417d933ef2b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c @@ -345,6 +345,11 @@ static void mpc20_program_ogam_pwl( uint32_t i; struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); +#ifdef CONFIG_DRM_AMD_DC_DMUB + PERF_TRACE(); + REG_SEQ_START(); +#endif + for (i = 0 ; i < num; i++) { REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].red_reg); REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].green_reg); @@ -463,6 +468,12 @@ void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id) ASSERT(!mpc_disabled); ASSERT(!mpc_idle); } +#ifdef CONFIG_DRM_AMD_DC_DMUB + REG_SEQ_SUBMIT(); + PERF_TRACE(); + REG_SEQ_WAIT_DONE(); + PERF_TRACE(); +#endif } static void mpc2_init_mpcc(struct mpcc *mpcc, int mpcc_inst) diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index ae1a250c2f7d..eb7ce4a5cbac 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -1678,6 +1678,9 @@ static bool construct( dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; dc->caps.extended_aux_timeout_support = true; +#ifdef CONFIG_DRM_AMD_DC_DMUB + dc->caps.dmcub_support = true; +#endif if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) dc->debug = debug_defaults_drv; diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 1a0429744630..0a3891edfd94 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -40,6 +40,11 @@ #undef DEPRECATED +#ifdef CONFIG_DRM_AMD_DC_DMUB +struct dmub_srv; +struct dc_dmub_srv; + +#endif irq_handler_idx dm_register_interrupt( struct dc_context *ctx, struct dc_interrupt_params *int_params, @@ -139,6 +144,15 @@ uint32_t generic_reg_update_ex(const struct dc_context *ctx, uint32_t addr, int n, uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...); +#ifdef CONFIG_DRM_AMD_DC_DMUB +struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub); +void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv); + +void reg_sequence_start_gather(const struct dc_context *ctx); +void reg_sequence_start_execute(const struct dc_context *ctx); +void reg_sequence_wait_done(const struct dc_context *ctx); +#endif + #define FD(reg_field) reg_field ## __SHIFT, \ reg_field ## _MASK diff --git a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h index 8503d9cc4763..a9a9657c095a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h +++ b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h @@ -485,4 +485,26 @@ uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...); + +#ifdef CONFIG_DRM_AMD_DC_DMUB +/* register offload macros + * + * instead of MMIO to register directly, in some cases we want + * to gather register sequence and execute the register sequence + * from another thread so we optimize time required for lengthy ops + */ + +/* start gathering register sequence */ +#define REG_SEQ_START() \ + reg_sequence_start_gather(CTX) + +/* start execution of register sequence gathered since REG_SEQ_START */ +#define REG_SEQ_SUBMIT() \ + reg_sequence_start_execute(CTX) + +/* wait for the last REG_SEQ_SUBMIT to finish */ +#define REG_SEQ_WAIT_DONE() \ + reg_sequence_wait_done(CTX) +#endif + #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_REG_HELPER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index 30ec80ac6fc8..9a4b5bab03c6 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -29,6 +29,7 @@ #include <linux/kgdb.h> #include <linux/kref.h> #include <linux/types.h> +#include <linux/slab.h> #include <asm/byteorder.h> |