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;
*
*/
+#include "core_types.h"
#include "dm_services.h"
#include "dcn20_opp.h"
#include "reg_helper.h"
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 */
/*****************************************/
.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,
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
.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,
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;
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);
/* 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.
}
}
- 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);
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;
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);
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;
/* 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);
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) {
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);
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);
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);
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);
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) {
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);
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);
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;
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, ¶ms, &event_triggers);
+ &opp_cnt, opp_heads, &manual_mode, ¶ms, &event_triggers);
if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
dc->res_pool->dccg->funcs->set_pixel_rate_div(
/* 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.
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,
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(
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);
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
* 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);
}
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);
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;
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,
}
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
}
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;
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);
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) {
}
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;
*/
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;
}
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->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;
}
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);
* 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;
}
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;
}
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);
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);
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
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;