summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
diff options
context:
space:
mode:
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.c260
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)
{