diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core/dc_stream.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 260 |
1 files changed, 217 insertions, 43 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 96e97d25d639..af7f8be230f7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -23,6 +23,9 @@ * */ +#include <linux/delay.h> +#include <linux/slab.h> + #include "dm_services.h" #include "dc.h" #include "core_types.h" @@ -47,8 +50,8 @@ void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink) if (dc_is_dvi_signal(stream->signal)) { if (stream->ctx->dc->caps.dual_link_dvi && - (stream->timing.pix_clk_100hz / 10) > TMDS_MAX_PIXEL_CLOCK && - sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) + (stream->timing.pix_clk_100hz / 10) > TMDS_MAX_PIXEL_CLOCK && + sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; else stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; @@ -105,6 +108,17 @@ static void construct(struct dc_stream_state *stream, /* EDID CAP translation for HDMI 2.0 */ stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg)); + stream->timing.dsc_cfg.num_slices_h = 0; + stream->timing.dsc_cfg.num_slices_v = 0; + stream->timing.dsc_cfg.bits_per_pixel = 128; + stream->timing.dsc_cfg.block_pred_enable = 1; + stream->timing.dsc_cfg.linebuf_depth = 9; + stream->timing.dsc_cfg.version_minor = 2; + stream->timing.dsc_cfg.ycbcr422_simple = 0; +#endif + update_stream_signal(stream, dc_sink_data); stream->out_transfer_func = dc_create_transfer_func(); @@ -167,18 +181,19 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream) { struct dc_stream_state *new_stream; - new_stream = kzalloc(sizeof(struct dc_stream_state), GFP_KERNEL); + new_stream = kmemdup(stream, sizeof(struct dc_stream_state), GFP_KERNEL); if (!new_stream) return NULL; - memcpy(new_stream, stream, sizeof(struct dc_stream_state)); - if (new_stream->sink) dc_sink_retain(new_stream->sink); if (new_stream->out_transfer_func) dc_transfer_func_retain(new_stream->out_transfer_func); + new_stream->stream_id = new_stream->ctx->dc_stream_id_count; + new_stream->ctx->dc_stream_id_count++; + kref_init(&new_stream->refcount); return new_stream; @@ -229,7 +244,7 @@ static void delay_cursor_until_vupdate(struct pipe_ctx *pipe_ctx, struct dc *dc) unsigned int us_per_line; if (stream->ctx->asic_id.chip_family == FAMILY_RV && - ASIC_REV_IS_RAVEN(stream->ctx->asic_id.hw_internal_rev)) { + ASICREV_IS_RAVEN(stream->ctx->asic_id.hw_internal_rev)) { vupdate_line = get_vupdate_offset_from_vsync(pipe_ctx); if (!dc_stream_get_crtc_position(dc, &stream, 1, &vpos, &nvpos)) @@ -352,53 +367,138 @@ bool dc_stream_set_cursor_position( return true; } -uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +bool dc_stream_add_writeback(struct dc *dc, + struct dc_stream_state *stream, + struct dc_writeback_info *wb_info) { - uint8_t i; - struct dc *core_dc = stream->ctx->dc; - struct resource_context *res_ctx = - &core_dc->current_state->res_ctx; + bool isDrc = false; + int i = 0; + struct dwbc *dwb; - for (i = 0; i < MAX_PIPES; i++) { - struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; + if (stream == NULL) { + dm_error("DC: dc_stream is NULL!\n"); + return false; + } - if (res_ctx->pipe_ctx[i].stream != stream) - continue; + if (wb_info == NULL) { + dm_error("DC: dc_writeback_info is NULL!\n"); + return false; + } - return tg->funcs->get_frame_count(tg); + if (wb_info->dwb_pipe_inst >= MAX_DWB_PIPES) { + dm_error("DC: writeback pipe is invalid!\n"); + return false; } - return 0; + wb_info->dwb_params.out_transfer_func = stream->out_transfer_func; + + dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + dwb->dwb_is_drc = false; + + /* recalculate and apply DML parameters */ + + for (i = 0; i < stream->num_wb_info; i++) { + /*dynamic update*/ + if (stream->writeback_info[i].wb_enabled && + stream->writeback_info[i].dwb_pipe_inst == wb_info->dwb_pipe_inst) { + stream->writeback_info[i] = *wb_info; + isDrc = true; + } + } + + if (!isDrc) { + stream->writeback_info[stream->num_wb_info++] = *wb_info; + } + + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* enable writeback */ + if (dc->hwss.enable_writeback) { + struct dc_stream_status *stream_status = dc_stream_get_status(stream); + struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + + if (dwb->funcs->is_enabled(dwb)) { + /* writeback pipe already enabled, only need to update */ + dc->hwss.update_writeback(dc, stream_status, wb_info); + } else { + /* Enable writeback pipe from scratch*/ + dc->hwss.enable_writeback(dc, stream_status, wb_info); + } + } + + return true; } -static void build_dp_sdp_info_frame(struct pipe_ctx *pipe_ctx, - const uint8_t *custom_sdp_message, - unsigned int sdp_message_size) +bool dc_stream_remove_writeback(struct dc *dc, + struct dc_stream_state *stream, + uint32_t dwb_pipe_inst) { - uint8_t i; - struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame; + int i = 0, j = 0; + if (stream == NULL) { + dm_error("DC: dc_stream is NULL!\n"); + return false; + } - /* set valid info */ - info->dpsdp.valid = true; + if (dwb_pipe_inst >= MAX_DWB_PIPES) { + dm_error("DC: writeback pipe is invalid!\n"); + return false; + } - /* set sdp message header */ - info->dpsdp.hb0 = custom_sdp_message[0]; /* package id */ - info->dpsdp.hb1 = custom_sdp_message[1]; /* package type */ - info->dpsdp.hb2 = custom_sdp_message[2]; /* package specific byte 0 any data */ - info->dpsdp.hb3 = custom_sdp_message[3]; /* package specific byte 0 any data */ +// stream->writeback_info[dwb_pipe_inst].wb_enabled = false; + for (i = 0; i < stream->num_wb_info; i++) { + /*dynamic update*/ + if (stream->writeback_info[i].wb_enabled && + stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) { + stream->writeback_info[i].wb_enabled = false; + } + } - /* set sdp message data */ - for (i = 0; i < 32; i++) - info->dpsdp.sb[i] = (custom_sdp_message[i+4]); + /* remove writeback info for disabled writeback pipes from stream */ + for (i = 0, j = 0; i < stream->num_wb_info; i++) { + if (stream->writeback_info[i].wb_enabled) { + if (i != j) + /* trim the array */ + stream->writeback_info[j] = stream->writeback_info[i]; + j++; + } + } + stream->num_wb_info = j; + /* recalculate and apply DML parameters */ + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* disable writeback */ + if (dc->hwss.disable_writeback) + dc->hwss.disable_writeback(dc, dwb_pipe_inst); + + return true; } +#endif -static void invalid_dp_sdp_info_frame(struct pipe_ctx *pipe_ctx) +uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream) { - struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame; + uint8_t i; + struct dc *core_dc = stream->ctx->dc; + struct resource_context *res_ctx = + &core_dc->current_state->res_ctx; + + for (i = 0; i < MAX_PIPES; i++) { + struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; + + if (res_ctx->pipe_ctx[i].stream != stream) + continue; - /* in-valid info */ - info->dpsdp.valid = false; + return tg->funcs->get_frame_count(tg); + } + + return 0; } bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream, @@ -406,7 +506,7 @@ bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream, unsigned int sdp_message_size) { int i; - struct dc *core_dc; + struct dc *dc; struct resource_context *res_ctx; if (stream == NULL) { @@ -414,8 +514,8 @@ bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream, return false; } - core_dc = stream->ctx->dc; - res_ctx = &core_dc->current_state->res_ctx; + dc = stream->ctx->dc; + res_ctx = &dc->current_state->res_ctx; for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; @@ -423,11 +523,14 @@ bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream, if (pipe_ctx->stream != stream) continue; - build_dp_sdp_info_frame(pipe_ctx, custom_sdp_message, sdp_message_size); - - core_dc->hwss.update_info_frame(pipe_ctx); + if (dc->hwss.send_immediate_sdp_message != NULL) + dc->hwss.send_immediate_sdp_message(pipe_ctx, + custom_sdp_message, + sdp_message_size); + else + DC_LOG_WARNING("%s:send_immediate_sdp_message not implemented on this ASIC\n", + __func__); - invalid_dp_sdp_info_frame(pipe_ctx); } return true; @@ -463,6 +566,77 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, return ret; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream) +{ + bool status = true; + struct pipe_ctx *pipe = NULL; + int i; + + if (!dc->hwss.dmdata_status_done) + return false; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream == stream) + break; + } + /* Stream not found, by default we'll assume HUBP fetched dm data */ + if (i == MAX_PIPES) + return true; + + status = dc->hwss.dmdata_status_done(pipe); + return status; +} + +bool dc_stream_set_dynamic_metadata(struct dc *dc, + struct dc_stream_state *stream, + struct dc_dmdata_attributes *attr) +{ + struct pipe_ctx *pipe_ctx = NULL; + struct hubp *hubp; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream == stream) + break; + } + + if (i == MAX_PIPES) + return false; + + hubp = pipe_ctx->plane_res.hubp; + if (hubp == NULL) + return false; + + pipe_ctx->stream->dmdata_address = attr->address; + + if (pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata != NULL) { + if (pipe_ctx->stream->dmdata_address.quad_part != 0) { + /* if using dynamic meta, don't set up generic infopackets */ + pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; + pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata( + pipe_ctx->stream_res.stream_enc, + true, pipe_ctx->plane_res.hubp->inst, + dc_is_dp_signal(pipe_ctx->stream->signal) ? + dmdata_dp : dmdata_hdmi); + } else + pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata( + pipe_ctx->stream_res.stream_enc, + false, pipe_ctx->plane_res.hubp->inst, + dc_is_dp_signal(pipe_ctx->stream->signal) ? + dmdata_dp : dmdata_hdmi); + } + + if (hubp->funcs->dmdata_set_attributes != NULL && + pipe_ctx->stream->dmdata_address.quad_part != 0) { + hubp->funcs->dmdata_set_attributes(hubp, attr); + } + + return true; +} +#endif void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) { |