Commit 176278d8 authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

drm/amd/display: reset DSC clock in post unlock update

[why]
Switching between DSC clock or disable DSC block are not double buffered update.
Corruption is observed if these updates happen before DSC double buffered
disconnection.

[how]
Move DSC disable and refclk reset to post unlock update. Wait for DSC double buffered
disconnection and all mpccs are disconnected before reset DSC clock.
Reviewed-by: default avatarSamson Tam <samson.tam@amd.com>
Acked-by: default avatarTom Chung <chiahsuan.chung@amd.com>
Signed-off-by: default avatarWenjing Liu <wenjing.liu@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 3706bf2e
...@@ -726,34 +726,35 @@ void dccg401_init(struct dccg *dccg) ...@@ -726,34 +726,35 @@ void dccg401_init(struct dccg *dccg)
} }
} }
static void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst) static void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst, bool enable)
{ {
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
uint32_t phase = enable ? 1 : 0;
switch (inst) { switch (inst) {
case 0: case 0:
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1, DSCCLK0_DTO_DB_EN, 1);
REG_UPDATE_2(DSCCLK0_DTO_PARAM, REG_UPDATE_2(DSCCLK0_DTO_PARAM,
DSCCLK0_DTO_PHASE, 1, DSCCLK0_DTO_PHASE, phase,
DSCCLK0_DTO_MODULO, 1); DSCCLK0_DTO_MODULO, 1);
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1, DSCCLK0_DTO_DB_EN, 1);
break; break;
case 1: case 1:
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1, DSCCLK1_DTO_DB_EN, 1);
REG_UPDATE_2(DSCCLK1_DTO_PARAM, REG_UPDATE_2(DSCCLK1_DTO_PARAM,
DSCCLK1_DTO_PHASE, 1, DSCCLK1_DTO_PHASE, phase,
DSCCLK1_DTO_MODULO, 1); DSCCLK1_DTO_MODULO, 1);
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1, DSCCLK1_DTO_DB_EN, 1);
break; break;
case 2: case 2:
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1, DSCCLK2_DTO_DB_EN, 1);
REG_UPDATE_2(DSCCLK2_DTO_PARAM, REG_UPDATE_2(DSCCLK2_DTO_PARAM,
DSCCLK2_DTO_PHASE, 1, DSCCLK2_DTO_PHASE, phase,
DSCCLK2_DTO_MODULO, 1); DSCCLK2_DTO_MODULO, 1);
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1, DSCCLK2_DTO_DB_EN, 1);
break; break;
case 3: case 3:
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1, DSCCLK3_DTO_DB_EN, 1);
REG_UPDATE_2(DSCCLK3_DTO_PARAM, REG_UPDATE_2(DSCCLK3_DTO_PARAM,
DSCCLK3_DTO_PHASE, 1, DSCCLK3_DTO_PHASE, phase,
DSCCLK3_DTO_MODULO, 1); DSCCLK3_DTO_MODULO, 1);
REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1, DSCCLK3_DTO_DB_EN, 1);
break; break;
default: default:
BREAK_TO_DEBUGGER(); BREAK_TO_DEBUGGER();
...@@ -769,27 +770,15 @@ static void dccg401_set_ref_dscclk(struct dccg *dccg, ...@@ -769,27 +770,15 @@ static void dccg401_set_ref_dscclk(struct dccg *dccg,
switch (dsc_inst) { switch (dsc_inst) {
case 0: case 0:
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 0); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 0);
REG_UPDATE_2(DSCCLK0_DTO_PARAM,
DSCCLK0_DTO_PHASE, 0,
DSCCLK0_DTO_MODULO, 1);
break; break;
case 1: case 1:
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 0); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 0);
REG_UPDATE_2(DSCCLK1_DTO_PARAM,
DSCCLK1_DTO_PHASE, 0,
DSCCLK1_DTO_MODULO, 1);
break; break;
case 2: case 2:
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 0); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 0);
REG_UPDATE_2(DSCCLK2_DTO_PARAM,
DSCCLK2_DTO_PHASE, 0,
DSCCLK2_DTO_MODULO, 1);
break; break;
case 3: case 3:
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 0); REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 0);
REG_UPDATE_2(DSCCLK3_DTO_PARAM,
DSCCLK3_DTO_PHASE, 0,
DSCCLK3_DTO_MODULO, 1);
break; break;
default: default:
return; return;
......
...@@ -40,6 +40,7 @@ static void dsc2_set_config(struct display_stream_compressor *dsc, const struct ...@@ -40,6 +40,7 @@ static void dsc2_set_config(struct display_stream_compressor *dsc, const struct
static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe); static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe);
static void dsc2_disable(struct display_stream_compressor *dsc); static void dsc2_disable(struct display_stream_compressor *dsc);
static void dsc2_disconnect(struct display_stream_compressor *dsc); static void dsc2_disconnect(struct display_stream_compressor *dsc);
static void dsc2_wait_disconnect_pending_clear(struct display_stream_compressor *dsc);
static const struct dsc_funcs dcn20_dsc_funcs = { static const struct dsc_funcs dcn20_dsc_funcs = {
.dsc_get_enc_caps = dsc2_get_enc_caps, .dsc_get_enc_caps = dsc2_get_enc_caps,
...@@ -50,6 +51,7 @@ static const struct dsc_funcs dcn20_dsc_funcs = { ...@@ -50,6 +51,7 @@ static const struct dsc_funcs dcn20_dsc_funcs = {
.dsc_enable = dsc2_enable, .dsc_enable = dsc2_enable,
.dsc_disable = dsc2_disable, .dsc_disable = dsc2_disable,
.dsc_disconnect = dsc2_disconnect, .dsc_disconnect = dsc2_disconnect,
.dsc_wait_disconnect_pending_clear = dsc2_wait_disconnect_pending_clear,
}; };
/* Macro definitios for REG_SET macros*/ /* Macro definitios for REG_SET macros*/
...@@ -260,16 +262,12 @@ static void dsc2_disable(struct display_stream_compressor *dsc) ...@@ -260,16 +262,12 @@ static void dsc2_disable(struct display_stream_compressor *dsc)
{ {
struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
int dsc_clock_en; int dsc_clock_en;
int dsc_fw_config;
int enabled_opp_pipe;
DC_LOG_DSC("disable DSC %d", dsc->inst); DC_LOG_DSC("disable DSC %d", dsc->inst);
REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en);
REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); if (!dsc_clock_en) {
if (!dsc_clock_en || !dsc_fw_config) { DC_LOG_DSC("DSC %d already disabled!", dsc->inst);
DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already disabled!", dsc->inst, enabled_opp_pipe);
ASSERT(0);
} }
REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG,
...@@ -279,6 +277,13 @@ static void dsc2_disable(struct display_stream_compressor *dsc) ...@@ -279,6 +277,13 @@ static void dsc2_disable(struct display_stream_compressor *dsc)
DSC_CLOCK_EN, 0); DSC_CLOCK_EN, 0);
} }
static void dsc2_wait_disconnect_pending_clear(struct display_stream_compressor *dsc)
{
struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
REG_WAIT(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_DOUBLE_BUFFER_REG_UPDATE_PENDING, 0, 2, 50000);
}
static void dsc2_disconnect(struct display_stream_compressor *dsc) static void dsc2_disconnect(struct display_stream_compressor *dsc)
{ {
struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
...@@ -777,4 +782,3 @@ static void dsc_write_to_registers(struct display_stream_compressor *dsc, const ...@@ -777,4 +782,3 @@ static void dsc_write_to_registers(struct display_stream_compressor *dsc, const
RANGE_BPG_OFFSET14, reg_vals->pps.rc_range_params[14].range_bpg_offset); RANGE_BPG_OFFSET14, reg_vals->pps.rc_range_params[14].range_bpg_offset);
} }
...@@ -453,7 +453,8 @@ ...@@ -453,7 +453,8 @@
type DSCCIF_UPDATE_TAKEN_STATUS; \ type DSCCIF_UPDATE_TAKEN_STATUS; \
type DSCCIF_UPDATE_TAKEN_ACK; \ type DSCCIF_UPDATE_TAKEN_ACK; \
type DSCRM_DSC_FORWARD_EN; \ type DSCRM_DSC_FORWARD_EN; \
type DSCRM_DSC_OPP_PIPE_SOURCE type DSCRM_DSC_OPP_PIPE_SOURCE; \
type DSCRM_DSC_DOUBLE_BUFFER_REG_UPDATE_PENDING
struct dcn20_dsc_registers { struct dcn20_dsc_registers {
uint32_t DSC_TOP_CONTROL; uint32_t DSC_TOP_CONTROL;
......
...@@ -21,6 +21,7 @@ static void dsc401_set_config(struct display_stream_compressor *dsc, const struc ...@@ -21,6 +21,7 @@ static void dsc401_set_config(struct display_stream_compressor *dsc, const struc
static void dsc401_enable(struct display_stream_compressor *dsc, int opp_pipe); static void dsc401_enable(struct display_stream_compressor *dsc, int opp_pipe);
static void dsc401_disable(struct display_stream_compressor *dsc); static void dsc401_disable(struct display_stream_compressor *dsc);
static void dsc401_disconnect(struct display_stream_compressor *dsc); static void dsc401_disconnect(struct display_stream_compressor *dsc);
static void dsc401_wait_disconnect_pending_clear(struct display_stream_compressor *dsc);
const struct dsc_funcs dcn401_dsc_funcs = { const struct dsc_funcs dcn401_dsc_funcs = {
.dsc_get_enc_caps = dsc2_get_enc_caps, .dsc_get_enc_caps = dsc2_get_enc_caps,
...@@ -31,6 +32,7 @@ const struct dsc_funcs dcn401_dsc_funcs = { ...@@ -31,6 +32,7 @@ const struct dsc_funcs dcn401_dsc_funcs = {
.dsc_enable = dsc401_enable, .dsc_enable = dsc401_enable,
.dsc_disable = dsc401_disable, .dsc_disable = dsc401_disable,
.dsc_disconnect = dsc401_disconnect, .dsc_disconnect = dsc401_disconnect,
.dsc_wait_disconnect_pending_clear = dsc401_wait_disconnect_pending_clear,
}; };
/* Macro definitios for REG_SET macros*/ /* Macro definitios for REG_SET macros*/
...@@ -231,16 +233,12 @@ static void dsc401_disable(struct display_stream_compressor *dsc) ...@@ -231,16 +233,12 @@ static void dsc401_disable(struct display_stream_compressor *dsc)
{ {
struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc); struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc);
int dsc_clock_en; int dsc_clock_en;
int dsc_fw_config;
int enabled_opp_pipe;
DC_LOG_DSC("disable DSC %d", dsc->inst); DC_LOG_DSC("disable DSC %d", dsc->inst);
REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en);
REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); if (!dsc_clock_en) {
if (!dsc_clock_en || !dsc_fw_config) { DC_LOG_DSC("DSC %d already disabled!", dsc->inst);
DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already disabled!", dsc->inst, enabled_opp_pipe);
ASSERT(0);
} }
REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG,
...@@ -250,6 +248,13 @@ static void dsc401_disable(struct display_stream_compressor *dsc) ...@@ -250,6 +248,13 @@ static void dsc401_disable(struct display_stream_compressor *dsc)
DSC_CLOCK_EN, 0); DSC_CLOCK_EN, 0);
} }
static void dsc401_wait_disconnect_pending_clear(struct display_stream_compressor *dsc)
{
struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc);
REG_WAIT(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_DOUBLE_BUFFER_REG_UPDATE_PENDING, 0, 2, 50000);
}
static void dsc401_disconnect(struct display_stream_compressor *dsc) static void dsc401_disconnect(struct display_stream_compressor *dsc)
{ {
struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc); struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc);
......
...@@ -107,6 +107,7 @@ struct dsc_funcs { ...@@ -107,6 +107,7 @@ struct dsc_funcs {
void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe); void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe);
void (*dsc_disable)(struct display_stream_compressor *dsc); void (*dsc_disable)(struct display_stream_compressor *dsc);
void (*dsc_disconnect)(struct display_stream_compressor *dsc); void (*dsc_disconnect)(struct display_stream_compressor *dsc);
void (*dsc_wait_disconnect_pending_clear)(struct display_stream_compressor *dsc);
}; };
#endif #endif
...@@ -2158,6 +2158,43 @@ void dcn20_program_front_end_for_ctx( ...@@ -2158,6 +2158,43 @@ void dcn20_program_front_end_for_ctx(
} }
} }
/* post_unlock_reset_opp - the function wait for corresponding double
* buffered pending status clear and reset opp head pipe's none double buffered
* registers to their initial state.
*/
static void post_unlock_reset_opp(struct dc *dc,
struct pipe_ctx *opp_head)
{
struct display_stream_compressor *dsc = opp_head->stream_res.dsc;
struct dccg *dccg = dc->res_pool->dccg;
/*
* wait for all DPP pipes in current mpc blending tree completes double
* buffered disconnection before resetting OPP
*/
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, opp_head);
if (dsc) {
bool is_dsc_ungated = false;
if (dc->hwseq->funcs.dsc_pg_status)
is_dsc_ungated = dc->hwseq->funcs.dsc_pg_status(dc->hwseq, dsc->inst);
if (is_dsc_ungated) {
/*
* seamless update specific where we will postpone non
* double buffered DSCCLK disable logic in post unlock
* sequence after DSC is disconnected from OPP but not
* yet power gated.
*/
dsc->funcs->dsc_wait_disconnect_pending_clear(dsc);
if (dccg->funcs->set_ref_dscclk)
dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
dsc->funcs->dsc_disable(dsc);
}
}
}
void dcn20_post_unlock_program_front_end( void dcn20_post_unlock_program_front_end(
struct dc *dc, struct dc *dc,
struct dc_state *context) struct dc_state *context)
...@@ -2167,6 +2204,12 @@ void dcn20_post_unlock_program_front_end( ...@@ -2167,6 +2204,12 @@ void dcn20_post_unlock_program_front_end(
unsigned int polling_interval_us = 1; unsigned int polling_interval_us = 1;
struct dce_hwseq *hwseq = dc->hwseq; struct dce_hwseq *hwseq = dc->hwseq;
for (i = 0; i < dc->res_pool->pipe_count; i++)
if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
!resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))
post_unlock_reset_opp(dc,
&dc->current_state->res_ctx.pipe_ctx[i]);
for (i = 0; i < dc->res_pool->pipe_count; i++) for (i = 0; i < dc->res_pool->pipe_count; i++)
if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]); dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
......
...@@ -60,8 +60,7 @@ ...@@ -60,8 +60,7 @@
#define REG(reg)\ #define REG(reg)\
hws->regs->reg hws->regs->reg
#define DC_LOGGER \ #define DC_LOGGER \
stream->ctx->logger dc->ctx->logger
#undef FN #undef FN
#define FN(reg_name, field_name) \ #define FN(reg_name, field_name) \
...@@ -75,17 +74,19 @@ void dcn32_dsc_pg_control( ...@@ -75,17 +74,19 @@ void dcn32_dsc_pg_control(
uint32_t power_gate = power_on ? 0 : 1; uint32_t power_gate = power_on ? 0 : 1;
uint32_t pwr_status = power_on ? 0 : 2; uint32_t pwr_status = power_on ? 0 : 2;
uint32_t org_ip_request_cntl = 0; uint32_t org_ip_request_cntl = 0;
struct dc *dc = hws->ctx->dc;
if (hws->ctx->dc->debug.disable_dsc_power_gate) if (dc->debug.disable_dsc_power_gate)
return; return;
if (!hws->ctx->dc->debug.enable_double_buffered_dsc_pg_support) if (!dc->debug.enable_double_buffered_dsc_pg_support)
return; return;
REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
if (org_ip_request_cntl == 0) if (org_ip_request_cntl == 0)
REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
DC_LOG_DSC("%s DSC power gate for inst %d", power_gate ? "enable" : "disable", dsc_inst);
switch (dsc_inst) { switch (dsc_inst) {
case 0: /* DSC0 */ case 0: /* DSC0 */
REG_UPDATE(DOMAIN16_PG_CONFIG, REG_UPDATE(DOMAIN16_PG_CONFIG,
...@@ -963,7 +964,7 @@ void dcn32_init_hw(struct dc *dc) ...@@ -963,7 +964,7 @@ void dcn32_init_hw(struct dc *dc)
} }
} }
static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
{ {
struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc *dc = pipe_ctx->stream->ctx->dc;
...@@ -1005,7 +1006,7 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -1005,7 +1006,7 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
if (should_use_dto_dscclk) if (should_use_dto_dscclk)
dccg->funcs->set_dto_dscclk(dccg, dsc->inst); dccg->funcs->set_dto_dscclk(dccg, dsc->inst, true);
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) {
struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
...@@ -1013,7 +1014,7 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -1013,7 +1014,7 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); 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); odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
if (should_use_dto_dscclk) if (should_use_dto_dscclk)
dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst); dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, true);
} }
dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
dsc_cfg.pic_width *= opp_cnt; dsc_cfg.pic_width *= opp_cnt;
...@@ -1032,15 +1033,15 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -1032,15 +1033,15 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
pipe_ctx->stream_res.tg, pipe_ctx->stream_res.tg,
OPTC_DSC_DISABLED, 0, 0); OPTC_DSC_DISABLED, 0, 0);
/* disable DSC block */ /* only disconnect DSC block, DSC is disabled when OPP head pipe is reset */
if (dccg->funcs->set_ref_dscclk) if (dccg->funcs->set_dto_dscclk)
dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst); dccg->funcs->set_dto_dscclk(dccg, pipe_ctx->stream_res.dsc->inst, false);
dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); 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) {
ASSERT(odm_pipe->stream_res.dsc); ASSERT(odm_pipe->stream_res.dsc);
if (dccg->funcs->set_ref_dscclk) if (dccg->funcs->set_dto_dscclk)
dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); dccg->funcs->set_dto_dscclk(dccg, odm_pipe->stream_res.dsc->inst, false);
odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc);
} }
} }
} }
...@@ -1098,7 +1099,7 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx * ...@@ -1098,7 +1099,7 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
if (pipe_ctx->stream_res.dsc) { if (pipe_ctx->stream_res.dsc) {
struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); dcn32_update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC);
/* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */
if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe &&
...@@ -1106,8 +1107,8 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx * ...@@ -1106,8 +1107,8 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc;
struct dccg *dccg = dc->res_pool->dccg; struct dccg *dccg = dc->res_pool->dccg;
if (dccg->funcs->set_ref_dscclk) if (dccg->funcs->set_dto_dscclk)
dccg->funcs->set_ref_dscclk(dccg, dsc->inst); dccg->funcs->set_dto_dscclk(dccg, dsc->inst, false);
/* disconnect DSC block from stream */ /* disconnect DSC block from stream */
dsc->funcs->dsc_disconnect(dsc); dsc->funcs->dsc_disconnect(dsc);
} }
......
...@@ -71,6 +71,8 @@ void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context); ...@@ -71,6 +71,8 @@ void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context);
void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx);
void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable);
unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div); unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div);
void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context); void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context);
......
...@@ -1543,6 +1543,75 @@ void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool en ...@@ -1543,6 +1543,75 @@ void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool en
dc_dmub_srv_fams2_update_config(dc, context, enable && fams2_required); dc_dmub_srv_fams2_update_config(dc, context, enable && fams2_required);
} }
static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context,
struct pipe_ctx *otg_master)
{
int i;
struct pipe_ctx *old_pipe;
struct pipe_ctx *new_pipe;
struct pipe_ctx *old_opp_heads[MAX_PIPES];
struct dccg *dccg = dc->res_pool->dccg;
struct pipe_ctx *old_otg_master =
&dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx];
int old_opp_head_count = resource_get_opp_heads_for_otg_master(
old_otg_master, &dc->current_state->res_ctx,
old_opp_heads);
if (otg_master->stream_res.dsc)
dcn32_update_dsc_on_stream(otg_master,
otg_master->stream->timing.flags.DSC);
if (old_otg_master->stream_res.dsc) {
for (i = 0; i < old_opp_head_count; i++) {
old_pipe = old_opp_heads[i];
new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx];
if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc) {
dccg->funcs->set_dto_dscclk(dccg,
old_pipe->stream_res.dsc->inst, false);
old_pipe->stream_res.dsc->funcs->dsc_disconnect(
old_pipe->stream_res.dsc);
}
}
}
}
void dcn401_update_odm(struct dc *dc, struct dc_state *context,
struct pipe_ctx *otg_master)
{
struct pipe_ctx *opp_heads[MAX_PIPES];
int opp_inst[MAX_PIPES] = {0};
int opp_head_count;
int i;
opp_head_count = resource_get_opp_heads_for_otg_master(
otg_master, &context->res_ctx, opp_heads);
for (i = 0; i < opp_head_count; i++)
opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
if (opp_head_count > 1)
otg_master->stream_res.tg->funcs->set_odm_combine(
otg_master->stream_res.tg,
opp_inst, opp_head_count,
&otg_master->stream->timing);
else
otg_master->stream_res.tg->funcs->set_odm_bypass(
otg_master->stream_res.tg,
&otg_master->stream->timing);
for (i = 0; i < opp_head_count; i++)
opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
opp_heads[i]->stream_res.opp,
true);
update_dsc_for_odm_change(dc, context, otg_master);
if (!resource_is_pipe_type(otg_master, DPP_PIPE))
/*
* blank pattern is generated by OPP, reprogram blank pattern
* due to OPP count change
*/
dc->hwseq->funcs.blank_pixel_data(dc, otg_master, true);
}
void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx, void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx,
struct dc_link_settings *link_settings) struct dc_link_settings *link_settings)
{ {
......
...@@ -74,4 +74,6 @@ void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool en ...@@ -74,4 +74,6 @@ void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool en
void dcn401_fams2_global_control_lock_fast(union block_sequence_params *params); void dcn401_fams2_global_control_lock_fast(union block_sequence_params *params);
void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings);
void dcn401_update_odm(struct dc *dc, struct dc_state *context,
struct pipe_ctx *otg_master);
#endif /* __DC_HWSS_DCN401_H__ */ #endif /* __DC_HWSS_DCN401_H__ */
...@@ -124,7 +124,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = { ...@@ -124,7 +124,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
.enable_power_gating_plane = dcn32_enable_power_gating_plane, .enable_power_gating_plane = dcn32_enable_power_gating_plane,
.hubp_pg_control = dcn32_hubp_pg_control, .hubp_pg_control = dcn32_hubp_pg_control,
.program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
.update_odm = dcn32_update_odm, .update_odm = dcn401_update_odm,
.dsc_pg_control = dcn32_dsc_pg_control, .dsc_pg_control = dcn32_dsc_pg_control,
.dsc_pg_status = dcn32_dsc_pg_status, .dsc_pg_status = dcn32_dsc_pg_status,
.set_hdr_multiplier = dcn10_set_hdr_multiplier, .set_hdr_multiplier = dcn10_set_hdr_multiplier,
......
...@@ -208,7 +208,8 @@ struct dccg_funcs { ...@@ -208,7 +208,8 @@ struct dccg_funcs {
uint32_t otg_inst); uint32_t otg_inst);
void (*set_dto_dscclk)( void (*set_dto_dscclk)(
struct dccg *dccg, struct dccg *dccg,
uint32_t dsc_inst); uint32_t dsc_inst,
bool enable);
void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst); void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst);
}; };
......
...@@ -820,14 +820,14 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -820,14 +820,14 @@ 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_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
if (should_use_dto_dscclk) if (should_use_dto_dscclk)
dccg->funcs->set_dto_dscclk(dccg, dsc->inst); dccg->funcs->set_dto_dscclk(dccg, dsc->inst, true);
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) {
struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; 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_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
if (should_use_dto_dscclk) if (should_use_dto_dscclk)
dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst); dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, true);
} }
dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
dsc_cfg.pic_width *= opp_cnt; dsc_cfg.pic_width *= opp_cnt;
...@@ -879,10 +879,16 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -879,10 +879,16 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
} }
/* disable DSC block */ /* disable DSC block */
if (dccg->funcs->set_dto_dscclk)
dccg->funcs->set_dto_dscclk(dccg, pipe_ctx->stream_res.dsc->inst, false);
pipe_ctx->stream_res.dsc->funcs->dsc_disconnect(pipe_ctx->stream_res.dsc);
if (dccg->funcs->set_ref_dscclk) if (dccg->funcs->set_ref_dscclk)
dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst); 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); 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_dto_dscclk)
dccg->funcs->set_dto_dscclk(dccg, odm_pipe->stream_res.dsc->inst, false);
odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc);
if (dccg->funcs->set_ref_dscclk) if (dccg->funcs->set_ref_dscclk)
dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); 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); odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
......
...@@ -456,6 +456,7 @@ static struct timing_generator_funcs dcn401_tg_funcs = { ...@@ -456,6 +456,7 @@ static struct timing_generator_funcs dcn401_tg_funcs = {
.set_dwb_source = NULL, .set_dwb_source = NULL,
.set_odm_bypass = optc401_set_odm_bypass, .set_odm_bypass = optc401_set_odm_bypass,
.set_odm_combine = optc401_set_odm_combine, .set_odm_combine = optc401_set_odm_combine,
.wait_odm_doublebuffer_pending_clear = optc32_wait_odm_doublebuffer_pending_clear,
.set_h_timing_div_manual_mode = optc401_set_h_timing_div_manual_mode, .set_h_timing_div_manual_mode = optc401_set_h_timing_div_manual_mode,
.get_optc_source = optc2_get_optc_source, .get_optc_source = optc2_get_optc_source,
.set_out_mux = optc401_set_out_mux, .set_out_mux = optc401_set_out_mux,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment