Commit e6a901a0 authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

drm/amd/display: use even ODM slice width for two pixels per container

[why]
When optc uses two pixel per container, each ODM slice width must be an
even number.

[how]
If ODM slice width is odd number increase it by 1.
Reviewed-by: default avatarDillon Varone <dillon.varone@amd.com>
Acked-by: default avatarWayne Lin <wayne.lin@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 a8baec46
......@@ -827,6 +827,11 @@ static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ct
stream->timing.h_border_right;
int odm_slice_width = h_active / odm_slice_count;
struct rect odm_rec;
bool is_two_pixels_per_container =
pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
if ((odm_slice_width % 2) && is_two_pixels_per_container)
odm_slice_width++;
odm_rec.x = odm_slice_width * odm_slice_idx;
odm_rec.width = is_last_odm_slice ?
......@@ -1464,6 +1469,7 @@ void resource_build_test_pattern_params(struct resource_context *res_ctx,
int v_active = otg_master->stream->timing.v_addressable +
otg_master->stream->timing.v_border_bottom +
otg_master->stream->timing.v_border_top;
bool is_two_pixels_per_container = otg_master->stream_res.tg->funcs->is_two_pixels_per_container(&otg_master->stream->timing);
int i;
controller_test_pattern = convert_dp_to_controller_test_pattern(
......@@ -1477,6 +1483,8 @@ void resource_build_test_pattern_params(struct resource_context *res_ctx,
odm_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads);
odm_slice_width = h_active / odm_cnt;
if ((odm_slice_width % 2) && is_two_pixels_per_container)
odm_slice_width++;
last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1);
for (i = 0; i < odm_cnt; i++) {
......
......@@ -2015,6 +2015,23 @@ bool dce110_tg_validate_timing(struct timing_generator *tg,
return dce110_timing_generator_validate_timing(tg, timing, SIGNAL_TYPE_NONE);
}
/* "Container" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this:
*
* - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as
* container rate.
*
* - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be
* halved to maintain the correct pixel rate.
*
* - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied
* to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well.
*
*/
bool dce110_is_two_pixels_per_container(const struct dc_crtc_timing *timing)
{
return timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
}
void dce110_tg_wait_for_state(struct timing_generator *tg,
enum crtc_state state)
{
......@@ -2239,6 +2256,7 @@ static const struct timing_generator_funcs dce110_tg_funcs = {
.is_tg_enabled = dce110_is_tg_enabled,
.configure_crc = dce110_configure_crc,
.get_crc = dce110_get_crc,
.is_two_pixels_per_container = dce110_is_two_pixels_per_container,
};
void dce110_timing_generator_construct(
......
......@@ -288,4 +288,6 @@ bool dce110_configure_crc(struct timing_generator *tg,
bool dce110_get_crc(struct timing_generator *tg,
uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb);
bool dce110_is_two_pixels_per_container(const struct dc_crtc_timing *timing);
#endif /* __DC_TIMING_GENERATOR_DCE110_H__ */
......@@ -682,7 +682,8 @@ static const struct timing_generator_funcs dce110_tg_v_funcs = {
.tear_down_global_swap_lock =
dce110_timing_generator_v_tear_down_global_swap_lock,
.enable_advanced_request =
dce110_timing_generator_v_enable_advanced_request
dce110_timing_generator_v_enable_advanced_request,
.is_two_pixels_per_container = dce110_is_two_pixels_per_container,
};
void dce110_timing_generator_v_construct(
......
......@@ -1197,6 +1197,7 @@ static const struct timing_generator_funcs dce120_tg_funcs = {
.is_tg_enabled = dce120_is_tg_enabled,
.configure_crc = dce120_configure_crc,
.get_crc = dce120_get_crc,
.is_two_pixels_per_container = dce110_is_two_pixels_per_container,
};
......
......@@ -220,6 +220,7 @@ static const struct timing_generator_funcs dce80_tg_funcs = {
dce80_timing_generator_enable_advanced_request,
.configure_crc = dce110_configure_crc,
.get_crc = dce110_get_crc,
.is_two_pixels_per_container = dce110_is_two_pixels_per_container,
};
void dce80_timing_generator_construct(
......
......@@ -941,7 +941,7 @@ static struct scaler_data get_scaler_data_for_plane(const struct dc_plane_state
temp_pipe->stream = pipe->stream;
temp_pipe->plane_state = pipe->plane_state;
temp_pipe->plane_res.scl_data.taps = pipe->plane_res.scl_data.taps;
temp_pipe->stream_res = pipe->stream_res;
resource_build_scaling_params(temp_pipe);
break;
}
......
......@@ -758,9 +758,9 @@ void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool bla
}
static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
int opp_cnt)
int opp_cnt, bool is_two_pixels_per_container)
{
bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing);
bool hblank_halved = is_two_pixels_per_container;
int flow_ctrl_cnt;
if (opp_cnt >= 2)
......@@ -827,7 +827,9 @@ enum dc_status dcn20_enable_stream_timing(
int i;
struct mpc_dwb_flow_control flow_control;
struct mpc *mpc = dc->res_pool->mpc;
bool rate_control_2x_pclk = (interlace || optc2_is_two_pixels_per_containter(&stream->timing));
bool is_two_pixels_per_container =
pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
bool rate_control_2x_pclk = (interlace || is_two_pixels_per_container);
unsigned int k1_div = PIXEL_RATE_DIV_NA;
unsigned int k2_div = PIXEL_RATE_DIV_NA;
......@@ -913,7 +915,8 @@ enum dc_status dcn20_enable_stream_timing(
rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
flow_control.flow_ctrl_mode = 0;
flow_control.flow_ctrl_cnt0 = 0x80;
flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt);
flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt,
is_two_pixels_per_container);
if (mpc->funcs->set_out_rate_control) {
for (i = 0; i < opp_cnt; ++i) {
mpc->funcs->set_out_rate_control(
......@@ -1204,6 +1207,8 @@ void dcn20_blank_pixel_data(
int h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
int v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
int odm_slice_width, last_odm_slice_width, offset = 0;
bool is_two_pixels_per_container =
pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
if (stream->link->test_pattern_enabled)
return;
......@@ -1214,6 +1219,8 @@ void dcn20_blank_pixel_data(
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_cnt++;
odm_slice_width = h_active / odm_cnt;
if ((odm_slice_width % 2) && is_two_pixels_per_container)
odm_slice_width++;
last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1);
if (blank) {
......@@ -2636,6 +2643,8 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
struct dc_link *link = stream->link;
struct dce_hwseq *hws = link->dc->hwseq;
struct pipe_ctx *odm_pipe;
bool is_two_pixels_per_container =
pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
params.opp_cnt = 1;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
......@@ -2652,7 +2661,7 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
pipe_ctx->stream_res.hpo_dp_stream_enc,
pipe_ctx->stream_res.tg->inst);
} else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1)
if (is_two_pixels_per_container || params.opp_cnt > 1)
params.timing.pix_clk_100hz /= 2;
pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1);
......
......@@ -604,7 +604,7 @@ void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
/*check whether it is half the rate*/
if (optc201_is_two_pixels_per_containter(&stream->timing))
if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing))
params.timing.pix_clk_100hz /= 2;
pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
......
......@@ -302,7 +302,7 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
unsigned int odm_combine_factor = 0;
bool two_pix_per_container = false;
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
two_pix_per_container = pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
......@@ -341,7 +341,7 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
return;
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1)
if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&pipe_ctx->stream->timing) || odm_combine_factor > 1)
pix_per_cycle = 2;
if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode)
......
......@@ -1143,7 +1143,7 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
unsigned int odm_combine_factor = 0;
bool two_pix_per_container = false;
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
two_pix_per_container = pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
......@@ -1182,7 +1182,7 @@ void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
return;
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1
if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&pipe_ctx->stream->timing) || odm_combine_factor > 1
|| dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx))
pix_per_cycle = 2;
......@@ -1246,7 +1246,7 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
pipe_ctx->stream_res.hpo_dp_stream_enc,
pipe_ctx->stream_res.tg->inst);
} else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1
if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing) || params.opp_cnt > 1
|| dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) {
params.timing.pix_clk_100hz /= 2;
pix_per_cycle = 2;
......
......@@ -212,10 +212,10 @@ bool optc1_get_crc(struct timing_generator *optc,
uint32_t *g_y,
uint32_t *b_cb);
bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing);
void optc1_set_vtg_params(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing,
bool program_fp2);
bool optc1_is_two_pixels_per_container(const struct dc_crtc_timing *timing);
#endif
......@@ -276,6 +276,7 @@ struct timing_generator_funcs {
uint32_t *num_of_input_segments,
uint32_t *seg0_src_sel,
uint32_t *seg1_src_sel);
bool (*is_two_pixels_per_container)(const struct dc_crtc_timing *timing);
/**
* Configure CRCs for the given timing generator. Return false if TG is
......
......@@ -297,7 +297,7 @@ void optc1_program_timing(
* of stereo handled in explicit call
*/
if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2)
if (optc->funcs->is_two_pixels_per_container(&patched_crtc_timing) || optc1->opp_count == 2)
h_div = H_TIMING_DIV_BY2;
if (REG(OPTC_DATA_FORMAT_CONTROL) && optc1->tg_mask->OPTC_DATA_FORMAT != 0) {
......@@ -1548,6 +1548,27 @@ bool optc1_get_crc(struct timing_generator *optc,
return true;
}
/* "Container" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this:
*
* - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as
* container rate.
*
* - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be
* halved to maintain the correct pixel rate.
*
* - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied
* to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well.
*
*/
bool optc1_is_two_pixels_per_container(const struct dc_crtc_timing *timing)
{
bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
&& !timing->dsc_cfg.ycbcr422_simple);
return two_pix;
}
static const struct timing_generator_funcs dcn10_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
......@@ -1594,6 +1615,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.program_manual_trigger = optc1_program_manual_trigger,
.setup_manual_trigger = optc1_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn10_timing_generator_init(struct optc *optc1)
......@@ -1609,25 +1631,3 @@ void dcn10_timing_generator_init(struct optc *optc1)
optc1->min_h_sync_width = 4;
optc1->min_v_sync_width = 1;
}
/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this:
*
* - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as
* containter rate.
*
* - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be
* halved to maintain the correct pixel rate.
*
* - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied
* to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well.
*
*/
bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
{
bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
&& !timing->dsc_cfg.ycbcr422_simple);
return two_pix;
}
......@@ -158,13 +158,6 @@ void optc2_get_dsc_status(struct timing_generator *optc,
OPTC_DSC_MODE, dsc_mode);
}
/*TEMP: Need to figure out inheritance model here.*/
bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
{
return optc1_is_two_pixels_per_containter(timing);
}
void optc2_set_odm_bypass(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing)
{
......@@ -177,7 +170,7 @@ void optc2_set_odm_bypass(struct timing_generator *optc,
OPTC_SEG1_SRC_SEL, 0xf);
REG_WRITE(OTG_H_TIMING_CNTL, 0);
h_div_2 = optc2_is_two_pixels_per_containter(dc_crtc_timing);
h_div_2 = optc->funcs->is_two_pixels_per_container(dc_crtc_timing);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_BY2, h_div_2);
REG_SET(OPTC_MEMORY_CONFIG, 0,
......@@ -560,6 +553,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.align_vblanks = optc2_align_vblanks,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn20_timing_generator_init(struct optc *optc1)
......
......@@ -118,7 +118,6 @@ void optc2_lock_doublebuffer_disable(struct timing_generator *optc);
void optc2_lock_doublebuffer_enable(struct timing_generator *optc);
void optc2_setup_manual_trigger(struct timing_generator *optc);
void optc2_program_manual_trigger(struct timing_generator *optc);
bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing);
bool optc2_configure_crc(struct timing_generator *optc,
const struct crc_params *params);
#endif /* __DC_OPTC_DCN20_H__ */
......@@ -38,12 +38,6 @@
#define FN(reg_name, field_name) \
optc1->tg_shift->field_name, optc1->tg_mask->field_name
/*TEMP: Need to figure out inheritance model here.*/
bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
{
return optc1_is_two_pixels_per_containter(timing);
}
static void optc201_triplebuffer_lock(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
......@@ -185,6 +179,7 @@ static struct timing_generator_funcs dcn201_tg_funcs = {
.program_manual_trigger = optc2_program_manual_trigger,
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn201_timing_generator_init(struct optc *optc1)
......
......@@ -68,7 +68,4 @@
SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh)
void dcn201_timing_generator_init(struct optc *optc);
bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing);
#endif
......@@ -206,7 +206,7 @@ void optc3_set_odm_bypass(struct timing_generator *optc,
OPTC_SEG3_SRC_SEL, 0xf
);
h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing);
h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, h_div);
......@@ -376,6 +376,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn30_timing_generator_init(struct optc *optc1)
......
......@@ -168,6 +168,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = {
.setup_manual_trigger = optc301_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn301_timing_generator_init(struct optc *optc1)
......
......@@ -292,6 +292,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn31_timing_generator_init(struct optc *optc1)
......
......@@ -175,7 +175,7 @@ static void optc314_set_odm_bypass(struct timing_generator *optc,
OPTC_SEG3_SRC_SEL, 0xf
);
h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing);
h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, h_div);
......@@ -255,6 +255,7 @@ static struct timing_generator_funcs dcn314_tg_funcs = {
.set_odm_bypass = optc314_set_odm_bypass,
.set_odm_combine = optc314_set_odm_combine,
.set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn314_timing_generator_init(struct optc *optc1)
......
......@@ -239,7 +239,7 @@ void optc32_set_odm_bypass(struct timing_generator *optc,
OPTC_SEG3_SRC_SEL, 0xf
);
h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing);
h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, h_div);
......@@ -361,6 +361,7 @@ static struct timing_generator_funcs dcn32_tg_funcs = {
.program_manual_trigger = optc2_program_manual_trigger,
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn32_timing_generator_init(struct optc *optc1)
......
......@@ -438,6 +438,7 @@ static struct timing_generator_funcs dcn35_tg_funcs = {
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
.set_long_vtotal = optc35_set_long_vtotal,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn35_timing_generator_init(struct optc *optc1)
......
......@@ -107,11 +107,17 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t h_active = timing->h_addressable +
timing->h_border_left + timing->h_border_right;
uint32_t odm_segment_width = h_active / opp_cnt;
uint32_t odm_segment_width_last =
h_active - odm_segment_width * (opp_cnt - 1);
uint32_t odm_mem_bit_map = decide_odm_mem_bit_map(
opp_id, opp_cnt, h_active);
uint32_t odm_segment_width;
uint32_t odm_segment_width_last;
bool is_two_pixels_per_container = optc->funcs->is_two_pixels_per_container(timing);
odm_segment_width = h_active / opp_cnt;
if ((odm_segment_width % 2) && is_two_pixels_per_container)
odm_segment_width++;
odm_segment_width_last =
h_active - odm_segment_width * (opp_cnt - 1);
REG_SET(OPTC_MEMORY_CONFIG, 0,
OPTC_MEM_SEL, odm_mem_bit_map);
......@@ -277,7 +283,7 @@ static void optc401_set_odm_bypass(struct timing_generator *optc,
OPTC_SEG3_SRC_SEL, 0xf
);
h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing);
h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, h_div);
......@@ -461,6 +467,7 @@ static struct timing_generator_funcs dcn401_tg_funcs = {
.program_manual_trigger = optc2_program_manual_trigger,
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
};
void dcn401_timing_generator_init(struct optc *optc1)
......
......@@ -1251,7 +1251,7 @@ static void get_pixel_clock_parameters(
if (opp_cnt == 4)
pixel_clk_params->requested_pix_clk_100hz /= 4;
else if (optc2_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2)
else if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing) || opp_cnt == 2)
pixel_clk_params->requested_pix_clk_100hz /= 2;
else if (hws->funcs.is_dp_dig_pixel_rate_div_policy) {
if (hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx))
......
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