summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/link/link_dpms.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dpms.c134
1 files changed, 105 insertions, 29 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index a96f07476..007ee32c2 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -38,7 +38,6 @@
#include "link_dpms.h"
#include "link_hwss.h"
#include "link_validation.h"
-#include "accessories/link_fpga.h"
#include "accessories/link_dp_trace.h"
#include "protocols/link_dpcd.h"
#include "protocols/link_ddc.h"
@@ -56,7 +55,10 @@
#include "dccg.h"
#include "clk_mgr.h"
#include "atomfirmware.h"
-#define DC_LOGGER_INIT(logger)
+#define DC_LOGGER \
+ dc_logger
+#define DC_LOGGER_INIT(logger) \
+ struct dal_logger *dc_logger = logger
#define LINK_INFO(...) \
DC_LOG_HW_HOTPLUG( \
@@ -774,10 +776,26 @@ static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
*/
void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
{
+ /* TODO: Move this to HWSS as this is hardware programming sequence not a
+ * link layer sequence
+ */
struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
struct dc_stream_state *stream = pipe_ctx->stream;
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
+ struct dccg *dccg = dc->res_pool->dccg;
+ /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN
+ * register access hung. When DSCCLk is based on refclk, DSCCLk is always a
+ * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is
+ * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings
+ * with DSC such as 480p60Hz, the dispclk could be low enough to trigger
+ * this problem. We are implementing a workaround here to keep using dscclk
+ * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e
+ * 48Mhz) pixel clock to avoid hitting this problem.
+ */
+ bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) &&
+ stream->timing.pix_clk_100hz > 480000;
DC_LOGGER_INIT(dsc->ctx->logger);
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
@@ -800,11 +818,15 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
+ if (should_use_dto_dscclk)
+ dccg->funcs->set_dto_dscclk(dccg, dsc->inst);
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
+ if (should_use_dto_dscclk)
+ dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst);
}
dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
dsc_cfg.pic_width *= opp_cnt;
@@ -854,9 +876,14 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
}
/* disable DSC block */
+ if (dccg->funcs->set_ref_dscclk)
+ dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst);
pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ if (dccg->funcs->set_ref_dscclk)
+ dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst);
odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
+ }
}
}
@@ -1059,18 +1086,21 @@ static struct fixed31_32 get_pbn_from_bw_in_kbps(uint64_t kbps)
uint32_t denominator = 1;
/*
- * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
+ * The 1.006 factor (margin 5300ppm + 300ppm ~ 0.6% as per spec) is not
+ * required when determining PBN/time slot utilization on the link between
+ * us and the branch, since that overhead is already accounted for in
+ * the get_pbn_per_slot function.
+ *
* The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on
* common multiplier to render an integer PBN for all link rate/lane
* counts combinations
* calculate
- * peak_kbps *= (1006/1000)
* peak_kbps *= (64/54)
- * peak_kbps *= 8 convert to bytes
+ * peak_kbps /= (8 * 1000) convert to bytes
*/
- numerator = 64 * PEAK_FACTOR_X1000;
- denominator = 54 * 8 * 1000 * 1000;
+ numerator = 64;
+ denominator = 54 * 8 * 1000;
kbps *= numerator;
peak_kbps = dc_fixpt_from_fraction(kbps, denominator);
@@ -2068,17 +2098,11 @@ static enum dc_status enable_link_dp(struct dc_state *state,
}
}
- /*
- * If the link is DP-over-USB4 do the following:
- * - Train with fallback when enabling DPIA link. Conventional links are
+ /* Train with fallback when enabling DPIA link. Conventional links are
* trained with fallback during sink detection.
- * - Allocate only what the stream needs for bw in Gbps. Inform the CM
- * in case stream needs more or less bw from what has been allocated
- * earlier at plug time.
*/
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
do_fallback = true;
- }
/*
* Temporary w/a to get DP2.0 link rates to work with SST.
@@ -2260,6 +2284,32 @@ static enum dc_status enable_link(
return status;
}
+static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, int bw)
+{
+ return true;
+}
+
+static bool allocate_usb4_bandwidth(struct dc_stream_state *stream)
+{
+ bool ret;
+
+ int bw = dc_bandwidth_in_kbps_from_timing(&stream->timing,
+ dc_link_get_highest_encoding_format(stream->sink->link));
+
+ ret = allocate_usb4_bandwidth_for_stream(stream, bw);
+
+ return ret;
+}
+
+static bool deallocate_usb4_bandwidth(struct dc_stream_state *stream)
+{
+ bool ret;
+
+ ret = allocate_usb4_bandwidth_for_stream(stream, 0);
+
+ return ret;
+}
+
void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
{
struct dc *dc = pipe_ctx->stream->ctx->dc;
@@ -2267,12 +2317,14 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
struct dc_link *link = stream->sink->link;
struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
ASSERT(is_master_pipe_for_link(link, pipe_ctx));
if (dp_is_128b_132b_signal(pipe_ctx))
vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+ if (dc_is_virtual_signal(pipe_ctx->stream->signal))
+ return;
if (pipe_ctx->stream->sink) {
if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
@@ -2283,9 +2335,6 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
}
}
- if (dc_is_virtual_signal(pipe_ctx->stream->signal))
- return;
-
if (!pipe_ctx->stream->sink->edid_caps.panel_patch.skip_avmute) {
if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
set_avmute(pipe_ctx, true);
@@ -2296,6 +2345,9 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
update_psp_stream_config(pipe_ctx, true);
dc->hwss.blank_stream(pipe_ctx);
+ if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ deallocate_usb4_bandwidth(pipe_ctx->stream);
+
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
deallocate_mst_payload(pipe_ctx);
else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
@@ -2355,6 +2407,14 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
if (vpg && vpg->funcs->vpg_powerdown)
vpg->funcs->vpg_powerdown(vpg);
+
+ /* for psp not exist case */
+ if (link->connector_signal == SIGNAL_TYPE_EDP && dc->debug.psp_disabled_wa) {
+ /* reset internal save state to default since eDP is off */
+ enum dp_panel_mode panel_mode = dp_get_panel_mode(pipe_ctx->stream->link);
+ /* since current psp not loaded, we need to reset it to default*/
+ link->panel_mode = panel_mode;
+ }
}
void link_set_dpms_on(
@@ -2372,12 +2432,14 @@ void link_set_dpms_on(
bool apply_edp_fast_boot_optimization =
pipe_ctx->stream->apply_edp_fast_boot_optimization;
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
ASSERT(is_master_pipe_for_link(link, pipe_ctx));
if (dp_is_128b_132b_signal(pipe_ctx))
vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+ if (dc_is_virtual_signal(pipe_ctx->stream->signal))
+ return;
if (pipe_ctx->stream->sink) {
if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
@@ -2388,18 +2450,22 @@ void link_set_dpms_on(
}
}
- if (dc_is_virtual_signal(pipe_ctx->stream->signal))
- return;
-
link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
&& !dp_is_128b_132b_signal(pipe_ctx)) {
+ struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+
if (link_enc)
link_enc->funcs->setup(
link_enc,
pipe_ctx->stream->signal);
+
+ if (stream_enc && stream_enc->funcs->dig_stream_enable)
+ stream_enc->funcs->dig_stream_enable(
+ stream_enc,
+ pipe_ctx->stream->signal, 1);
}
pipe_ctx->stream->link->link_state_valid = true;
@@ -2461,9 +2527,8 @@ void link_set_dpms_on(
*/
if (pipe_ctx->stream->timing.flags.DSC) {
if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
- dc_is_virtual_signal(pipe_ctx->stream->signal))
- link_set_dsc_enable(pipe_ctx, true);
-
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ link_set_dsc_enable(pipe_ctx, true);
}
status = enable_link(state, pipe_ctx);
@@ -2500,10 +2565,18 @@ void link_set_dpms_on(
*/
if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
dp_is_128b_132b_signal(pipe_ctx))) {
+ struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+
if (link_enc)
link_enc->funcs->setup(
link_enc,
pipe_ctx->stream->signal);
+
+ if (stream_enc && stream_enc->funcs->dig_stream_enable)
+ stream_enc->funcs->dig_stream_enable(
+ stream_enc,
+ pipe_ctx->stream->signal, 1);
+
}
dc->hwss.enable_stream(pipe_ctx);
@@ -2517,6 +2590,9 @@ void link_set_dpms_on(
}
}
+ if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ allocate_usb4_bandwidth(pipe_ctx->stream);
+
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
allocate_mst_payload(pipe_ctx);
else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&