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

drm/amd/display: Add left edge pixel for YCbCr422/420 + ODM pipe split

[WHY]
Currently 3-tap chroma subsampling is used for YCbCr422/420. When ODM
pipesplit is used, pixels on the left edge of ODM slices need one extra
pixel from the right edge of the previous slice to calculate the correct
chroma value.

Without this change, the chroma value is slightly different than
expected. This is usually imperceptible visually, but it impacts test
pattern CRCs for compliance test automation.

[HOW]
Update logic to use the register for adding extra left edge pixel for
YCbCr422/420 ODM cases.
Reviewed-by: default avatarGeorge Shen <george.shen@amd.com>
Acked-by: default avatarAlex Hung <alex.hung@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 d5192c15
......@@ -2110,12 +2110,19 @@ struct rect resource_get_odm_slice_src_rect(struct pipe_ctx *pipe_ctx)
struct rect odm_slice_dst;
struct rect odm_slice_src;
struct pipe_ctx *opp_head = resource_get_opp_head(pipe_ctx);
struct output_pixel_processor *opp = opp_head->stream_res.opp;
uint32_t left_edge_extra_pixel_count;
odm_slice_dst = resource_get_odm_slice_dst_rect(opp_head);
odm_slice_src = odm_slice_dst;
left_edge_extra_pixel_count = 0;
if (opp->funcs->opp_get_left_edge_extra_pixel_count)
left_edge_extra_pixel_count =
opp->funcs->opp_get_left_edge_extra_pixel_count(
opp, pipe_ctx->stream->timing.pixel_encoding,
resource_is_pipe_type(opp_head, OTG_MASTER));
else
left_edge_extra_pixel_count = 0;
odm_slice_src.x -= left_edge_extra_pixel_count;
odm_slice_src.width += left_edge_extra_pixel_count;
......
......@@ -23,6 +23,7 @@
*
*/
#include "core_types.h"
#include "dm_services.h"
#include "dcn20_opp.h"
#include "reg_helper.h"
......@@ -350,19 +351,32 @@ bool opp2_dpg_is_pending(struct output_pixel_processor *opp)
return (dpg_en == 1 && double_buffer_pending == 1);
}
void opp2_program_left_edge_extra_pixel (
void opp2_program_left_edge_extra_pixel(
struct output_pixel_processor *opp,
bool count)
enum dc_pixel_encoding pixel_encoding,
bool is_primary)
{
struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp);
uint32_t count = opp2_get_left_edge_extra_pixel_count(opp, pixel_encoding, is_primary);
/* Specifies the number of extra left edge pixels that are supplied to
/*
* Specifies the number of extra left edge pixels that are supplied to
* the 422 horizontal chroma sub-sample filter.
* Note that when left edge pixel is not "0", fmt pixel encoding can be in either 420 or 422 mode
* */
*/
REG_UPDATE(FMT_422_CONTROL, FMT_LEFT_EDGE_EXTRA_PIXEL_COUNT, count);
}
uint32_t opp2_get_left_edge_extra_pixel_count(struct output_pixel_processor *opp,
enum dc_pixel_encoding pixel_encoding, bool is_primary)
{
if ((pixel_encoding == PIXEL_ENCODING_YCBCR422 || pixel_encoding == PIXEL_ENCODING_YCBCR420) &&
!opp->ctx->dc->debug.force_chroma_subsampling_1tap &&
!is_primary)
return 1;
else
return 0;
}
/*****************************************/
/* Constructor, Destructor */
/*****************************************/
......@@ -380,6 +394,7 @@ static struct opp_funcs dcn20_opp_funcs = {
.opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
.opp_destroy = opp1_destroy,
.opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
.opp_get_left_edge_extra_pixel_count = opp2_get_left_edge_extra_pixel_count,
};
void dcn20_opp_construct(struct dcn20_opp *oppn20,
......
......@@ -167,6 +167,8 @@ void opp2_dpg_set_blank_color(
void opp2_program_left_edge_extra_pixel (
struct output_pixel_processor *opp,
bool count);
enum dc_pixel_encoding pixel_encoding, bool is_primary);
uint32_t opp2_get_left_edge_extra_pixel_count(struct output_pixel_processor *opp,
enum dc_pixel_encoding pixel_encoding, bool is_primary);
#endif
......@@ -54,6 +54,7 @@ static struct opp_funcs dcn201_opp_funcs = {
.opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
.opp_destroy = opp1_destroy,
.opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
.opp_get_left_edge_extra_pixel_count = opp2_get_left_edge_extra_pixel_count,
};
void dcn201_opp_construct(struct dcn201_opp *oppn201,
......
......@@ -820,9 +820,8 @@ enum dc_status dcn20_enable_stream_timing(
struct dc_stream_state *stream = pipe_ctx->stream;
struct drr_params params = {0};
unsigned int event_triggers = 0;
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
int opp_inst[MAX_PIPES] = {0};
bool interlace = stream->timing.flags.INTERLACE;
int i;
struct mpc_dwb_flow_control flow_control;
......@@ -832,6 +831,9 @@ enum dc_status dcn20_enable_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;
int odm_slice_width;
int last_odm_slice_width;
struct pipe_ctx *opp_heads[MAX_PIPES];
if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
......@@ -850,16 +852,17 @@ enum dc_status dcn20_enable_stream_timing(
/* TODO check if timing_changed, disable stream if timing changed */
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
opp_cnt++;
}
opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
for (i = 0; i < opp_cnt; i++)
opp_inst[opp_cnt] = opp_heads[i]->stream_res.opp->inst;
odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
if (opp_cnt > 1)
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
opp_inst, opp_cnt, odm_slice_width,
last_odm_slice_width);
/* HW program guide assume display already disable
* by unplug sequence. OTG assume stop.
......@@ -927,14 +930,15 @@ enum dc_status dcn20_enable_stream_timing(
}
}
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
odm_pipe->stream_res.opp,
for (i = 0; i < opp_cnt; i++) {
opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
opp_heads[i]->stream_res.opp,
true);
pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
pipe_ctx->stream_res.opp,
true);
opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
opp_heads[i]->stream_res.opp,
stream->timing.pixel_encoding,
resource_is_pipe_type(opp_heads[i], OTG_MASTER));
}
hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
......@@ -1175,6 +1179,8 @@ void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
......@@ -1185,7 +1191,7 @@ void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
odm_slice_width, last_odm_slice_width);
else
pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
......@@ -1203,12 +1209,7 @@ void dcn20_blank_pixel_data(
enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
struct pipe_ctx *odm_pipe;
int odm_cnt = 1;
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);
struct rect odm_slice_src;
if (stream->link->test_pattern_enabled)
return;
......@@ -1216,13 +1217,6 @@ void dcn20_blank_pixel_data(
/* get opp dpg blank color */
color_space_to_black_color(dc, color_space, &black_color);
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) {
dc->hwss.set_abm_immediate_disable(pipe_ctx);
......@@ -1237,28 +1231,29 @@ void dcn20_blank_pixel_data(
odm_pipe = pipe_ctx;
while (odm_pipe->next_odm_pipe) {
odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
dc->hwss.set_disp_pattern_generator(dc,
odm_pipe,
test_pattern,
test_pattern_color_space,
stream->timing.display_color_depth,
&black_color,
odm_slice_width,
v_active,
offset);
offset += odm_slice_width;
odm_slice_src.width,
odm_slice_src.height,
odm_slice_src.x);
odm_pipe = odm_pipe->next_odm_pipe;
}
odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
dc->hwss.set_disp_pattern_generator(dc,
odm_pipe,
test_pattern,
test_pattern_color_space,
stream->timing.display_color_depth,
&black_color,
last_odm_slice_width,
v_active,
offset);
odm_slice_src.width,
odm_slice_src.height,
odm_slice_src.x);
if (!blank)
if (stream_res->abm) {
......
......@@ -160,6 +160,8 @@ void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx
struct pipe_ctx *odm_pipe;
int opp_cnt = 0;
int opp_inst[MAX_PIPES] = {0};
int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
opp_cnt = get_odm_config(pipe_ctx, opp_inst);
......@@ -167,7 +169,7 @@ void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
odm_slice_width, last_odm_slice_width);
else
pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
......
......@@ -1078,6 +1078,8 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
struct pipe_ctx *odm_pipe;
int opp_cnt = 0;
int opp_inst[MAX_PIPES] = {0};
int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
opp_cnt = get_odm_config(pipe_ctx, opp_inst);
......@@ -1085,7 +1087,7 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
odm_slice_width, last_odm_slice_width);
else
pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
......@@ -1094,6 +1096,10 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
odm_pipe->stream_res.opp,
true);
odm_pipe->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
odm_pipe->stream_res.opp,
pipe_ctx->stream->timing.pixel_encoding,
resource_is_pipe_type(odm_pipe, OTG_MASTER));
}
if (pipe_ctx->stream_res.dsc) {
......
......@@ -451,6 +451,8 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
struct pipe_ctx *odm_pipe;
int opp_cnt = 0;
int opp_inst[MAX_PIPES] = {0};
int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
opp_cnt = get_odm_config(pipe_ctx, opp_inst);
......@@ -458,7 +460,7 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
odm_slice_width, last_odm_slice_width);
else
pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
......
......@@ -744,20 +744,20 @@ static void enable_stream_timing_calc(
unsigned int *tmds_div,
int *opp_inst,
int *opp_cnt,
struct pipe_ctx *opp_heads[MAX_PIPES],
bool *manual_mode,
struct drr_params *params,
unsigned int *event_triggers)
{
struct dc_stream_state *stream = pipe_ctx->stream;
struct pipe_ctx *odm_pipe;
int i;
if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal))
dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
opp_inst[*opp_cnt] = odm_pipe->stream_res.opp->inst;
(*opp_cnt)++;
}
*opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
for (i = 0; i < *opp_cnt; i++)
opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
if (dc_is_tmds_signal(stream->signal)) {
stream->link->phy_state.symclk_ref_cnts.otg = 1;
......@@ -786,18 +786,21 @@ enum dc_status dcn401_enable_stream_timing(
struct dc_stream_state *stream = pipe_ctx->stream;
struct drr_params params = {0};
unsigned int event_triggers = 0;
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
int opp_inst[MAX_PIPES] = {0};
struct pipe_ctx *opp_heads[MAX_PIPES];
bool manual_mode;
unsigned int tmds_div = PIXEL_RATE_DIV_NA;
unsigned int unused_div = PIXEL_RATE_DIV_NA;
int odm_slice_width;
int last_odm_slice_width;
int i;
if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
return DC_OK;
enable_stream_timing_calc(pipe_ctx, context, dc, &tmds_div, opp_inst,
&opp_cnt, &manual_mode, &params, &event_triggers);
&opp_cnt, opp_heads, &manual_mode, &params, &event_triggers);
if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
dc->res_pool->dccg->funcs->set_pixel_rate_div(
......@@ -807,11 +810,14 @@ enum dc_status dcn401_enable_stream_timing(
/* TODO check if timing_changed, disable stream if timing changed */
if (opp_cnt > 1)
if (opp_cnt > 1) {
odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
odm_slice_width, last_odm_slice_width);
}
/* HW program guide assume display already disable
* by unplug sequence. OTG assume stop.
......@@ -840,10 +846,15 @@ enum dc_status dcn401_enable_stream_timing(
pipe_ctx->stream->signal,
true);
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
odm_pipe->stream_res.opp,
for (i = 0; i < opp_cnt; i++) {
opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
opp_heads[i]->stream_res.opp,
true);
opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
opp_heads[i]->stream_res.opp,
stream->timing.pixel_encoding,
resource_is_pipe_type(opp_heads[i], OTG_MASTER));
}
pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
pipe_ctx->stream_res.opp,
......@@ -1593,6 +1604,8 @@ void dcn401_update_odm(struct dc *dc, struct dc_state *context,
struct pipe_ctx *opp_heads[MAX_PIPES];
int opp_inst[MAX_PIPES] = {0};
int opp_head_count;
int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false);
int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true);
int i;
opp_head_count = resource_get_opp_heads_for_otg_master(
......@@ -1604,16 +1617,21 @@ void dcn401_update_odm(struct dc *dc, struct dc_state *context,
otg_master->stream_res.tg->funcs->set_odm_combine(
otg_master->stream_res.tg,
opp_inst, opp_head_count,
&otg_master->stream->timing);
odm_slice_width, last_odm_slice_width);
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++)
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);
opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
opp_heads[i]->stream_res.opp,
opp_heads[i]->stream->timing.pixel_encoding,
resource_is_pipe_type(opp_heads[i], OTG_MASTER));
}
update_dsc_for_odm_change(dc, context, otg_master);
......
......@@ -346,8 +346,13 @@ struct opp_funcs {
void (*opp_program_left_edge_extra_pixel)(
struct output_pixel_processor *opp,
bool count);
enum dc_pixel_encoding pixel_encoding,
bool is_primary);
uint32_t (*opp_get_left_edge_extra_pixel_count)(
struct output_pixel_processor *opp,
enum dc_pixel_encoding pixel_encoding,
bool is_primary);
};
#endif
......@@ -313,7 +313,7 @@ struct timing_generator_funcs {
* OPP(s) and turn on/off ODM memory.
*/
void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing);
int segment_width, int last_segment_width);
void (*get_odm_combine_segments)(struct timing_generator *tg, int *odm_segments);
void (*set_h_timing_div_manual_mode)(struct timing_generator *optc, bool manual_mode);
void (*set_gsl)(struct timing_generator *optc, const struct gsl_params *params);
......
......@@ -179,11 +179,9 @@ void optc2_set_odm_bypass(struct timing_generator *optc,
}
void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
int segment_width, int last_segment_width)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
/ opp_cnt;
uint32_t memory_mask;
ASSERT(opp_cnt == 2);
......@@ -213,7 +211,7 @@ void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_c
OPTC_SEG1_SRC_SEL, opp_id[1]);
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, mpcc_hactive);
OPTC_SEGMENT_WIDTH, segment_width);
REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1);
optc1->opp_count = opp_cnt;
......
......@@ -105,7 +105,7 @@ void optc2_set_odm_bypass(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing);
void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing);
int segment_width, int last_segment_width);
void optc2_get_optc_source(struct timing_generator *optc,
uint32_t *num_of_src_opp,
......
......@@ -216,11 +216,9 @@ void optc3_set_odm_bypass(struct timing_generator *optc,
}
void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
int segment_width, int last_segment_width)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
/ opp_cnt;
uint32_t memory_mask = 0;
/* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic
......@@ -267,7 +265,7 @@ void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_c
}
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, mpcc_hactive);
OPTC_SEGMENT_WIDTH, segment_width);
REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
optc1->opp_count = opp_cnt;
......
......@@ -352,7 +352,7 @@ void optc3_set_timing_db_mode(struct timing_generator *optc, bool enable);
void optc3_set_odm_bypass(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing);
void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing);
int segment_width, int last_segment_width);
void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc);
void optc3_tg_init(struct timing_generator *optc);
void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max);
......
......@@ -41,13 +41,11 @@
optc1->tg_shift->field_name, optc1->tg_mask->field_name
static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
int segment_width, int last_segment_width)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
/ opp_cnt;
uint32_t memory_mask = 0;
int mem_count_per_opp = (mpcc_hactive + 2559) / 2560;
int mem_count_per_opp = (segment_width + 2559) / 2560;
/* Assume less than 6 pipes */
if (opp_cnt == 4) {
......@@ -85,7 +83,7 @@ static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, i
}
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, mpcc_hactive);
OPTC_SEGMENT_WIDTH, segment_width);
REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
optc1->opp_count = opp_cnt;
......
......@@ -48,12 +48,11 @@
*/
static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
int segment_width, int last_segment_width)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t memory_mask = 0;
int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
int mpcc_hactive = h_active / opp_cnt;
int h_active = segment_width * opp_cnt;
/* Each memory instance is 2048x(314x2) bits to support half line of 4096 */
int odm_mem_count = (h_active + 2047) / 2048;
......@@ -96,7 +95,7 @@ static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id,
}
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, mpcc_hactive);
OPTC_SEGMENT_WIDTH, segment_width);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
......
......@@ -43,12 +43,11 @@
optc1->tg_shift->field_name, optc1->tg_mask->field_name
static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
int segment_width, int last_segment_width)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t memory_mask = 0;
int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
int mpcc_hactive = h_active / opp_cnt;
int h_active = segment_width * opp_cnt;
/* Each memory instance is 2048x(32x2) bits to support half line of 4096 */
int odm_mem_count = (h_active + 2047) / 2048;
......@@ -91,7 +90,7 @@ static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, i
}
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, mpcc_hactive);
OPTC_SEGMENT_WIDTH, segment_width);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
......
......@@ -55,12 +55,11 @@
* Return: void.
*/
static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
int segment_width, int last_segment_width)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t memory_mask = 0;
int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
int mpcc_hactive = h_active / opp_cnt;
int h_active = segment_width * opp_cnt;
/* Each memory instance is 2048x(314x2) bits to support half line of 4096 */
int odm_mem_count = (h_active + 2047) / 2048;
......@@ -103,7 +102,7 @@ static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, i
}
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, mpcc_hactive);
OPTC_SEGMENT_WIDTH, segment_width);
REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
optc1->opp_count = opp_cnt;
......
......@@ -102,22 +102,12 @@ static uint32_t decide_odm_mem_bit_map(int *opp_id, int opp_cnt, int h_active)
}
static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
int opp_cnt, struct dc_crtc_timing *timing)
int opp_cnt, int segment_width, int last_segment_width)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t h_active = timing->h_addressable +
timing->h_border_left + timing->h_border_right;
uint32_t h_active = segment_width * (opp_cnt - 1) + last_segment_width;
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);
......@@ -129,7 +119,7 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
OPTC_SEG0_SRC_SEL, opp_id[0],
OPTC_SEG1_SRC_SEL, opp_id[1]);
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, odm_segment_width);
OPTC_SEGMENT_WIDTH, segment_width);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, H_TIMING_DIV_BY2);
......@@ -141,10 +131,10 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
OPTC_SEG1_SRC_SEL, opp_id[1],
OPTC_SEG2_SRC_SEL, opp_id[2]);
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, odm_segment_width);
OPTC_SEGMENT_WIDTH, segment_width);
REG_UPDATE(OPTC_WIDTH_CONTROL2,
OPTC_SEGMENT_WIDTH_LAST,
odm_segment_width_last);
last_segment_width);
/* In ODM combine 3:1 mode ODM packs 4 pixels per data transfer
* so OTG_H_TIMING_DIV_MODE should be configured to
* H_TIMING_DIV_BY4 even though ODM combines 3 OPP inputs, it
......@@ -161,7 +151,7 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
OPTC_SEG2_SRC_SEL, opp_id[2],
OPTC_SEG3_SRC_SEL, opp_id[3]);
REG_UPDATE(OPTC_WIDTH_CONTROL,
OPTC_SEGMENT_WIDTH, odm_segment_width);
OPTC_SEGMENT_WIDTH, segment_width);
REG_UPDATE(OTG_H_TIMING_CNTL,
OTG_H_TIMING_DIV_MODE, H_TIMING_DIV_BY4);
break;
......
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