diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display')
44 files changed, 1360 insertions, 249 deletions
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index ec3285f65517..5b124a67404c 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -11,7 +11,7 @@ config DRM_AMD_DC config DRM_AMD_DC_PRE_VEGA bool "DC support for Polaris and older ASICs" - default n + default y help Choose this option to enable the new DC support for older asics by default. This includes Polaris, Carrizo, Tonga, Bonaire, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7e5c5c9eeb4f..ae512ecb65ee 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1131,7 +1131,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) if (adev->asic_type == CHIP_VEGA10 || adev->asic_type == CHIP_RAVEN) - client_id = AMDGPU_IH_CLIENTID_DCE; + client_id = SOC15_IH_CLIENTID_DCE; int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; @@ -1231,7 +1231,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP; i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1; i++) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->crtc_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq); if (r) { DRM_ERROR("Failed to add crtc irq id!\n"); @@ -1255,7 +1255,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT; i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + adev->mode_info.num_crtc - 1; i++) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->pageflip_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq); if (r) { DRM_ERROR("Failed to add page flip irq id!\n"); return r; @@ -1276,7 +1276,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) } /* HPD */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, &adev->hpd_irq); if (r) { DRM_ERROR("Failed to add hpd irq id!\n"); @@ -1365,6 +1365,43 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) #endif +static int initialize_plane(struct amdgpu_display_manager *dm, + struct amdgpu_mode_info *mode_info, + int plane_id) +{ + struct amdgpu_plane *plane; + unsigned long possible_crtcs; + int ret = 0; + + plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL); + mode_info->planes[plane_id] = plane; + + if (!plane) { + DRM_ERROR("KMS: Failed to allocate plane\n"); + return -ENOMEM; + } + plane->base.type = mode_info->plane_type[plane_id]; + + /* + * HACK: IGT tests expect that each plane can only have one + * one possible CRTC. For now, set one CRTC for each + * plane that is not an underlay, but still allow multiple + * CRTCs for underlay planes. + */ + possible_crtcs = 1 << plane_id; + if (plane_id >= dm->dc->caps.max_streams) + possible_crtcs = 0xff; + + ret = amdgpu_dm_plane_init(dm, mode_info->planes[plane_id], possible_crtcs); + + if (ret) { + DRM_ERROR("KMS: Failed to initialize plane\n"); + return ret; + } + + return ret; +} + /* In this architecture, the association * connector -> encoder -> crtc * id not really requried. The crtc and connector will hold the @@ -1375,12 +1412,12 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) { struct amdgpu_display_manager *dm = &adev->dm; - uint32_t i; + int32_t i; struct amdgpu_dm_connector *aconnector = NULL; struct amdgpu_encoder *aencoder = NULL; struct amdgpu_mode_info *mode_info = &adev->mode_info; uint32_t link_cnt; - unsigned long possible_crtcs; + int32_t total_overlay_planes, total_primary_planes; link_cnt = dm->dc->caps.max_links; if (amdgpu_dm_mode_config_init(dm->adev)) { @@ -1388,30 +1425,22 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) return -1; } - for (i = 0; i < dm->dc->caps.max_planes; i++) { - struct amdgpu_plane *plane; + /* Identify the number of planes to be initialized */ + total_overlay_planes = dm->dc->caps.max_slave_planes; + total_primary_planes = dm->dc->caps.max_planes - dm->dc->caps.max_slave_planes; - plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL); - mode_info->planes[i] = plane; - - if (!plane) { - DRM_ERROR("KMS: Failed to allocate plane\n"); + /* First initialize overlay planes, index starting after primary planes */ + for (i = (total_overlay_planes - 1); i >= 0; i--) { + if (initialize_plane(dm, mode_info, (total_primary_planes + i))) { + DRM_ERROR("KMS: Failed to initialize overlay plane\n"); goto fail; } - plane->base.type = mode_info->plane_type[i]; - - /* - * HACK: IGT tests expect that each plane can only have one - * one possible CRTC. For now, set one CRTC for each - * plane that is not an underlay, but still allow multiple - * CRTCs for underlay planes. - */ - possible_crtcs = 1 << i; - if (i >= dm->dc->caps.max_streams) - possible_crtcs = 0xff; + } - if (amdgpu_dm_plane_init(dm, mode_info->planes[i], possible_crtcs)) { - DRM_ERROR("KMS: Failed to initialize plane\n"); + /* Initialize primary planes */ + for (i = (total_primary_planes - 1); i >= 0; i--) { + if (initialize_plane(dm, mode_info, i)) { + DRM_ERROR("KMS: Failed to initialize primary plane\n"); goto fail; } } @@ -1982,6 +2011,10 @@ static int fill_plane_attributes(struct amdgpu_device *adev, * every time. */ ret = amdgpu_dm_set_degamma_lut(crtc_state, dc_plane_state); + if (ret) { + dc_transfer_func_release(dc_plane_state->in_transfer_func); + dc_plane_state->in_transfer_func = NULL; + } return ret; } @@ -4691,8 +4724,8 @@ static int dm_update_planes_state(struct dc *dc, int ret = 0; - /* Add new planes */ - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { + /* Add new planes, in reverse order as DC expectation */ + for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { new_plane_crtc = new_plane_state->crtc; old_plane_crtc = old_plane_state->crtc; dm_new_plane_state = to_dm_plane_state(new_plane_state); @@ -4737,6 +4770,7 @@ static int dm_update_planes_state(struct dc *dc, *lock_and_validation_needed = true; } else { /* Add new planes */ + struct dc_plane_state *dc_new_plane_state; if (drm_atomic_plane_disabling(plane->state, new_plane_state)) continue; @@ -4755,34 +4789,42 @@ static int dm_update_planes_state(struct dc *dc, WARN_ON(dm_new_plane_state->dc_state); - dm_new_plane_state->dc_state = dc_create_plane_state(dc); + dc_new_plane_state = dc_create_plane_state(dc); + if (!dc_new_plane_state) + return -ENOMEM; DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", plane->base.id, new_plane_crtc->base.id); - if (!dm_new_plane_state->dc_state) { - ret = -EINVAL; - return ret; - } - ret = fill_plane_attributes( new_plane_crtc->dev->dev_private, - dm_new_plane_state->dc_state, + dc_new_plane_state, new_plane_state, new_crtc_state); - if (ret) + if (ret) { + dc_plane_state_release(dc_new_plane_state); return ret; + } + /* + * Any atomic check errors that occur after this will + * not need a release. The plane state will be attached + * to the stream, and therefore part of the atomic + * state. It'll be released when the atomic state is + * cleaned. + */ if (!dc_add_plane_to_context( dc, dm_new_crtc_state->stream, - dm_new_plane_state->dc_state, + dc_new_plane_state, dm_state->context)) { - ret = -EINVAL; - return ret; + dc_plane_state_release(dc_new_plane_state); + return -EINVAL; } + dm_new_plane_state->dc_state = dc_new_plane_state; + /* Tell DC to do a full surface update every time there * is a plane change. Inefficient, but works for now. */ @@ -4812,6 +4854,9 @@ static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, return -EDEADLK; crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + if (crtc->primary == plane && crtc_state->active) { if (!plane_state->fb) return -EINVAL; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index e845c511656e..f6cb502c303f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -193,6 +193,7 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) struct drm_property_blob *blob = crtc->base.ctm; struct dc_stream_state *stream = crtc->stream; struct drm_color_ctm *ctm; + int64_t val; int i; if (!blob) { @@ -206,7 +207,9 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) * DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating * with homogeneous coordinates, augment the matrix with 0's. * - * The format provided is S31.32, which is the same as our fixed31_32. + * The format provided is S31.32, using signed-magnitude representation. + * Our fixed31_32 is also S31.32, but is using 2's complement. We have + * to convert from signed-magnitude to 2's complement. */ for (i = 0; i < 12; i++) { /* Skip 4th element */ @@ -214,8 +217,14 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) stream->gamut_remap_matrix.matrix[i] = dal_fixed31_32_zero; continue; } - /* csc[i] = ctm[i - floor(i/4)] */ - stream->gamut_remap_matrix.matrix[i].value = ctm->matrix[i - (i/4)]; + + /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ + val = ctm->matrix[i - (i/4)]; + /* If negative, convert to 2's complement. */ + if (val & (1ULL << 63)) + val = -(val & ~(1ULL << 63)); + + stream->gamut_remap_matrix.matrix[i].value = val; } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 39cfe0fbf1b9..8291d74f26bc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -85,6 +85,9 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, enum ddc_result res; ssize_t read_bytes; + if (WARN_ON(msg->size > 16)) + return -E2BIG; + switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_READ: read_bytes = dal_ddc_service_read_dpcd_data( diff --git a/drivers/gpu/drm/amd/display/dc/basics/logger.c b/drivers/gpu/drm/amd/display/dc/basics/logger.c index 180a9d69d351..31bee054f43a 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/logger.c +++ b/drivers/gpu/drm/amd/display/dc/basics/logger.c @@ -60,7 +60,8 @@ static const struct dc_log_type_info log_type_info_tbl[] = { {LOG_EVENT_LINK_LOSS, "LinkLoss"}, {LOG_EVENT_UNDERFLOW, "Underflow"}, {LOG_IF_TRACE, "InterfaceTrace"}, - {LOG_DTN, "DTN"} + {LOG_DTN, "DTN"}, + {LOG_PROFILING, "Profiling"} }; diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 1689c670ca6f..e7680c41f117 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -44,7 +44,7 @@ #include "bios_parser_common.h" #define LAST_RECORD_TYPE 0xff - +#define SMU9_SYSPLL0_ID 0 struct i2c_id_config_access { uint8_t bfI2C_LineMux:4; @@ -1220,7 +1220,7 @@ static unsigned int bios_parser_get_smu_clock_info( if (!bp->cmd_tbl.get_smu_clock_info) return BP_RESULT_FAILURE; - return bp->cmd_tbl.get_smu_clock_info(bp); + return bp->cmd_tbl.get_smu_clock_info(bp, 0); } static enum bp_result bios_parser_program_crtc_timing( @@ -1376,7 +1376,7 @@ static enum bp_result get_firmware_info_v3_1( if (bp->cmd_tbl.get_smu_clock_info != NULL) { /* VBIOS gives in 10KHz */ info->smu_gpu_pll_output_freq = - bp->cmd_tbl.get_smu_clock_info(bp) * 10; + bp->cmd_tbl.get_smu_clock_info(bp, SMU9_SYSPLL0_ID) * 10; } return BP_RESULT_OK; diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index e362658aa3ce..3f63f712c8a4 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -796,7 +796,7 @@ static enum bp_result set_dce_clock_v2_1( ****************************************************************************** *****************************************************************************/ -static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp); +static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id); static void init_get_smu_clock_info(struct bios_parser *bp) { @@ -805,12 +805,13 @@ static void init_get_smu_clock_info(struct bios_parser *bp) } -static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp) +static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) { struct atom_get_smu_clock_info_parameters_v3_1 smu_input = {0}; struct atom_get_smu_clock_info_output_parameters_v3_1 smu_output; smu_input.command = GET_SMU_CLOCK_INFO_V3_1_GET_PLLVCO_FREQ; + smu_input.syspll_id = id; /* Get Specific Clock */ if (EXEC_BIOS_CMD_TABLE(getsmuclockinfo, smu_input)) { diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h index 59061b806df5..ec1c0c9f3f1d 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h @@ -96,7 +96,7 @@ struct cmd_tbl { struct bios_parser *bp, struct bp_set_dce_clock_parameters *bp_params); unsigned int (*get_smu_clock_info)( - struct bios_parser *bp); + struct bios_parser *bp, uint8_t id); }; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c index 6d38b8f43198..0cbab81ab304 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c @@ -85,7 +85,6 @@ static void calculate_bandwidth( const uint32_t s_mid5 = 5; const uint32_t s_mid6 = 6; const uint32_t s_high = 7; - const uint32_t bus_efficiency = 1; const uint32_t dmif_chunk_buff_margin = 1; uint32_t max_chunks_fbc_mode; @@ -592,7 +591,12 @@ static void calculate_bandwidth( /* 1 = use channel 0 and 1*/ /* 2 = use channel 0,1,2,3*/ if ((fbc_enabled == 1 && lpt_enabled == 1)) { - data->dram_efficiency = bw_int_to_fixed(1); + if (vbios->memory_type == bw_def_hbm) + data->dram_efficiency = bw_frc_to_fixed(5, 10); + else + data->dram_efficiency = bw_int_to_fixed(1); + + if (dceip->low_power_tiling_mode == 0) { data->number_of_dram_channels = 1; } @@ -607,7 +611,10 @@ static void calculate_bandwidth( } } else { - data->dram_efficiency = bw_frc_to_fixed(8, 10); + if (vbios->memory_type == bw_def_hbm) + data->dram_efficiency = bw_frc_to_fixed(5, 10); + else + data->dram_efficiency = bw_frc_to_fixed(8, 10); } /*memory request size and latency hiding:*/ /*request size is normally 64 byte, 2-line interleaved, with full latency hiding*/ @@ -1171,9 +1178,9 @@ static void calculate_bandwidth( } for (i = 0; i <= 2; i++) { for (j = 0; j <= 7; j++) { - data->dmif_burst_time[i][j] = bw_max3(data->dmif_total_page_close_open_time, bw_div(data->total_display_reads_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))), bw_div(data->total_display_reads_required_data, (bw_mul(bw_mul(sclk[j], vbios->data_return_bus_width), bw_int_to_fixed(bus_efficiency))))); + data->dmif_burst_time[i][j] = bw_max3(data->dmif_total_page_close_open_time, bw_div(data->total_display_reads_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))), bw_div(data->total_display_reads_required_data, (bw_mul(bw_mul(sclk[j], vbios->data_return_bus_width), bw_frc_to_fixed(dceip->percent_of_ideal_port_bw_received_after_urgent_latency, 100))))); if (data->d1_display_write_back_dwb_enable == 1) { - data->mcifwr_burst_time[i][j] = bw_max3(data->mcifwr_total_page_close_open_time, bw_div(data->total_display_writes_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_wrchannels)))), bw_div(data->total_display_writes_required_data, (bw_mul(bw_mul(sclk[j], vbios->data_return_bus_width), bw_int_to_fixed(bus_efficiency))))); + data->mcifwr_burst_time[i][j] = bw_max3(data->mcifwr_total_page_close_open_time, bw_div(data->total_display_writes_required_dram_access_data, (bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[i]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_wrchannels)))), bw_div(data->total_display_writes_required_data, (bw_mul(sclk[j], vbios->data_return_bus_width)))); } } } @@ -1258,6 +1265,16 @@ static void calculate_bandwidth( /* / (dispclk - display bw)*/ /*the minimum latency hiding is the minimum for all pipes of one screen line time, plus one more line time if doing lb prefetch, plus the dmif data buffer size equivalent in time, minus the urgent latency.*/ /*the minimum latency hiding is further limited by the cursor. the cursor latency hiding is the number of lines of the cursor buffer, minus one if the downscaling is less than two, or minus three if it is more*/ + + /*initialize variables*/ + number_of_displays_enabled = 0; + number_of_displays_enabled_with_margin = 0; + for (k = 0; k <= maximum_number_of_surfaces - 1; k++) { + if (data->enable[k]) { + number_of_displays_enabled = number_of_displays_enabled + 1; + } + data->display_pstate_change_enable[k] = 0; + } for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { if ((bw_equ(dceip->stutter_and_dram_clock_state_change_gated_before_cursor, bw_int_to_fixed(0)) && bw_mtn(data->cursor_width_pixels[i], bw_int_to_fixed(0)))) { @@ -1276,7 +1293,10 @@ static void calculate_bandwidth( for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { if (dceip->graphics_lb_nodownscaling_multi_line_prefetching == 1 && (bw_equ(data->vsr[i], bw_int_to_fixed(1)) || (bw_leq(data->vsr[i], bw_frc_to_fixed(8, 10)) && bw_leq(data->v_taps[i], bw_int_to_fixed(2)) && data->lb_bpc[i] == 8)) && surface_type[i] == bw_def_graphics) { - data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_sub(data->lb_partitions[i], bw_int_to_fixed(1)), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); + if (number_of_displays_enabled > 2) + data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_sub(data->lb_partitions[i], bw_int_to_fixed(2)), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); + else + data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_sub(data->lb_partitions[i], bw_int_to_fixed(1)), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); } else { data->minimum_latency_hiding[i] = bw_sub(bw_div(bw_mul((bw_div((bw_add(bw_int_to_fixed(1 + data->line_buffer_prefetch[i]), bw_div(bw_div(data->data_buffer_size[i], bw_int_to_fixed(data->bytes_per_pixel[i])), data->source_width_pixels[i]))), data->vsr[i])), data->h_total[i]), data->pixel_rate[i]), data->total_dmifmc_urgent_latency); @@ -1338,24 +1358,15 @@ static void calculate_bandwidth( for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { if (dceip->graphics_lb_nodownscaling_multi_line_prefetching == 1) { - data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(8, 10), data->total_dmifmc_urgent_latency)); + data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(5, 10), data->total_dmifmc_urgent_latency)); } else { /*maximum_latency_hiding(i) = minimum_latency_hiding(i) + 1 / vsr(i) * h_total(i) / pixel_rate(i) + 0.5 * total_dmifmc_urgent_latency*/ - data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(8, 10), data->total_dmifmc_urgent_latency)); + data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(5, 10), data->total_dmifmc_urgent_latency)); } data->maximum_latency_hiding_with_cursor[i] = bw_min2(data->maximum_latency_hiding[i], data->cursor_latency_hiding[i]); } } - /*initialize variables*/ - number_of_displays_enabled = 0; - number_of_displays_enabled_with_margin = 0; - for (k = 0; k <= maximum_number_of_surfaces - 1; k++) { - if (data->enable[k]) { - number_of_displays_enabled = number_of_displays_enabled + 1; - } - data->display_pstate_change_enable[k] = 0; - } for (i = 0; i <= 2; i++) { for (j = 0; j <= 7; j++) { data->min_dram_speed_change_margin[i][j] = bw_int_to_fixed(9999); @@ -1370,10 +1381,11 @@ static void calculate_bandwidth( /*determine the minimum dram clock change margin for each set of clock frequencies*/ data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin); /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/ - data->dispclk_required_for_dram_speed_change[i][j] = bw_max3(data->dispclk_required_for_dram_speed_change[i][j], bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->active_time[k])))); - if ((bw_ltn(data->dispclk_required_for_dram_speed_change[i][j], vbios->high_voltage_max_dispclk))) { + data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->active_time[k])))); + if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) { data->display_pstate_change_enable[k] = 1; data->num_displays_with_margin[i][j] = data->num_displays_with_margin[i][j] + 1; + data->dispclk_required_for_dram_speed_change[i][j] = bw_max2(data->dispclk_required_for_dram_speed_change[i][j], data->dispclk_required_for_dram_speed_change_pipe[i][j]); } } } @@ -1383,10 +1395,11 @@ static void calculate_bandwidth( /*determine the minimum dram clock change margin for each display pipe*/ data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin); /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/ - data->dispclk_required_for_dram_speed_change[i][j] = bw_max3(data->dispclk_required_for_dram_speed_change[i][j], bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]), data->active_time[k])))); - if ((bw_ltn(data->dispclk_required_for_dram_speed_change[i][j], vbios->high_voltage_max_dispclk))) { + data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]), data->active_time[k])))); + if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) { data->display_pstate_change_enable[k] = 1; data->num_displays_with_margin[i][j] = data->num_displays_with_margin[i][j] + 1; + data->dispclk_required_for_dram_speed_change[i][j] = bw_max2(data->dispclk_required_for_dram_speed_change[i][j], data->dispclk_required_for_dram_speed_change_pipe[i][j]); } } } @@ -1420,7 +1433,7 @@ static void calculate_bandwidth( data->displays_with_same_mode[i] = bw_int_to_fixed(0); if (data->enable[i] == 1 && data->display_pstate_change_enable[i] == 0 && bw_mtn(data->v_blank_dram_speed_change_margin[i], bw_int_to_fixed(0))) { for (j = 0; j <= maximum_number_of_surfaces - 1; j++) { - if ((data->enable[j] == 1 && bw_equ(data->source_width_rounded_up_to_chunks[i], data->source_width_rounded_up_to_chunks[j]) && bw_equ(data->source_height_rounded_up_to_chunks[i], data->source_height_rounded_up_to_chunks[j]) && bw_equ(data->vsr[i], data->vsr[j]) && bw_equ(data->hsr[i], data->hsr[j]) && bw_equ(data->pixel_rate[i], data->pixel_rate[j]))) { + if ((i == j || data->display_synchronization_enabled) && (data->enable[j] == 1 && bw_equ(data->source_width_rounded_up_to_chunks[i], data->source_width_rounded_up_to_chunks[j]) && bw_equ(data->source_height_rounded_up_to_chunks[i], data->source_height_rounded_up_to_chunks[j]) && bw_equ(data->vsr[i], data->vsr[j]) && bw_equ(data->hsr[i], data->hsr[j]) && bw_equ(data->pixel_rate[i], data->pixel_rate[j]))) { data->displays_with_same_mode[i] = bw_add(data->displays_with_same_mode[i], bw_int_to_fixed(1)); } } @@ -1435,7 +1448,7 @@ static void calculate_bandwidth( /*aligned displays with the same timing.*/ /*the display(s) with the negative margin can be switched in the v_blank region while the other*/ /*displays are in v_blank or v_active.*/ - if ((number_of_displays_enabled_with_margin + number_of_aligned_displays_with_no_margin == number_of_displays_enabled && bw_mtn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(9999)) && bw_ltn(data->dispclk_required_for_dram_speed_change[high][s_high], vbios->high_voltage_max_dispclk))) { + if (number_of_displays_enabled_with_margin > 0 && (number_of_displays_enabled_with_margin + number_of_aligned_displays_with_no_margin) == number_of_displays_enabled && bw_mtn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[high][s_high], bw_int_to_fixed(9999)) && bw_ltn(data->dispclk_required_for_dram_speed_change[high][s_high], vbios->high_voltage_max_dispclk)) { data->nbp_state_change_enable = bw_def_yes; } else { @@ -1448,6 +1461,25 @@ static void calculate_bandwidth( else { nbp_state_change_enable_blank = bw_def_no; } + + /*average bandwidth*/ + /*the average bandwidth with no compression is the vertical active time is the source width times the bytes per pixel divided by the line time, multiplied by the vertical scale ratio and the ratio of bytes per request divided by the useful bytes per request.*/ + /*the average bandwidth with compression is the same, divided by the compression ratio*/ + for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { + if (data->enable[i]) { + data->average_bandwidth_no_compression[i] = bw_div(bw_mul(bw_mul(bw_div(bw_mul(data->source_width_rounded_up_to_chunks[i], bw_int_to_fixed(data->bytes_per_pixel[i])), (bw_div(data->h_total[i], data->pixel_rate[i]))), data->vsr[i]), data->bytes_per_request[i]), data->useful_bytes_per_request[i]); + data->average_bandwidth[i] = bw_div(data->average_bandwidth_no_compression[i], data->compression_rate[i]); + } + } + data->total_average_bandwidth_no_compression = bw_int_to_fixed(0); + data->total_average_bandwidth = bw_int_to_fixed(0); + for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { + if (data->enable[i]) { + data->total_average_bandwidth_no_compression = bw_add(data->total_average_bandwidth_no_compression, data->average_bandwidth_no_compression[i]); + data->total_average_bandwidth = bw_add(data->total_average_bandwidth, data->average_bandwidth[i]); + } + } + /*required yclk(pclk)*/ /*yclk requirement only makes sense if the dmif and mcifwr data total page close-open time is less than the time for data transfer and the total pte requests fit in the scatter-gather saw queque size*/ /*if that is the case, the yclk requirement is the maximum of the ones required by dmif and mcifwr, and the high/low yclk(pclk) is chosen accordingly*/ @@ -1497,17 +1529,20 @@ static void calculate_bandwidth( } else { data->required_dram_bandwidth_gbyte_per_second = bw_div(bw_max2(data->dmif_required_dram_bandwidth, data->mcifwr_required_dram_bandwidth), bw_int_to_fixed(1000)); - if (bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[low]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[low][s_high], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[low][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[low][s_high] == number_of_displays_enabled_with_margin))) { + if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation, 100),yclk[low]),bw_div(bw_int_to_fixed(vbios->dram_channel_width_in_bits),bw_int_to_fixed(8))),bw_int_to_fixed(vbios->number_of_dram_channels))) + && bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[low]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[low][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[low][s_high], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[low][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[low][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[low][s_high] == number_of_displays_enabled_with_margin))) { yclk_message = bw_fixed_to_int(vbios->low_yclk); data->y_clk_level = low; data->dram_bandwidth = bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[low]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)); } - else if (bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[mid]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[mid][s_high], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[mid][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[mid][s_high] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation, 100),yclk[mid]),bw_div(bw_int_to_fixed(vbios->dram_channel_width_in_bits),bw_int_to_fixed(8))),bw_int_to_fixed(vbios->number_of_dram_channels))) + && bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[mid]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels))) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[mid][s_high], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[mid][s_high], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[mid][s_high], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[mid][s_high], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[mid][s_high] == number_of_displays_enabled_with_margin))) { yclk_message = bw_fixed_to_int(vbios->mid_yclk); data->y_clk_level = mid; data->dram_bandwidth = bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[mid]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)); } - else if (bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[high]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation, 100),yclk[high]),bw_div(bw_int_to_fixed(vbios->dram_channel_width_in_bits),bw_int_to_fixed(8))),bw_int_to_fixed(vbios->number_of_dram_channels))) + && bw_ltn(bw_mul(data->required_dram_bandwidth_gbyte_per_second, bw_int_to_fixed(1000)), bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[high]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)))) { yclk_message = bw_fixed_to_int(vbios->high_yclk); data->y_clk_level = high; data->dram_bandwidth = bw_mul(bw_div(bw_mul(bw_mul(data->dram_efficiency, yclk[high]), bw_int_to_fixed(vbios->dram_channel_width_in_bits)), bw_int_to_fixed(8)), bw_int_to_fixed(data->number_of_dram_channels)); @@ -1523,8 +1558,8 @@ static void calculate_bandwidth( /*if that is the case, the sclk requirement is the maximum of the ones required by dmif and mcifwr, and the high/mid/low sclk is chosen accordingly, unless that choice results in foresaking dram speed/nb p-state change.*/ /*the dmif and mcifwr sclk required is the one that allows the transfer of all pipe's data buffer size through the sclk bus in the time for data transfer*/ /*for dmif, pte and cursor requests have to be included.*/ - data->dmif_required_sclk = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer), (bw_mul(vbios->data_return_bus_width, bw_int_to_fixed(bus_efficiency)))); - data->mcifwr_required_sclk = bw_div(bw_div(data->total_display_writes_required_data, data->display_writes_time_for_data_transfer), (bw_mul(vbios->data_return_bus_width, bw_int_to_fixed(bus_efficiency)))); + data->dmif_required_sclk = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer), (bw_mul(vbios->data_return_bus_width, bw_frc_to_fixed(dceip->percent_of_ideal_port_bw_received_after_urgent_latency, 100)))); + data->mcifwr_required_sclk = bw_div(bw_div(data->total_display_writes_required_data, data->display_writes_time_for_data_transfer), vbios->data_return_bus_width); if (bw_mtn(data->scatter_gather_total_pte_requests, dceip->maximum_total_outstanding_pte_requests_allowed_by_saw)) { data->required_sclk = bw_int_to_fixed(9999); sclk_message = bw_def_exceeded_allowed_outstanding_pte_req_queue_size; @@ -1537,42 +1572,56 @@ static void calculate_bandwidth( } else { data->required_sclk = bw_max2(data->dmif_required_sclk, data->mcifwr_required_sclk); - if (bw_ltn(data->required_sclk, sclk[s_low]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_low], vbios->low_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_low] == number_of_displays_enabled_with_margin))) { + if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[low]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_low]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_low], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_low], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_low], vbios->low_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_low] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_low; data->sclk_level = s_low; data->required_sclk = vbios->low_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid1]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid1], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid1] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[mid]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid1]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid1], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid1], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid1], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid1] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid1; data->required_sclk = vbios->mid1_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid2]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid2], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid2] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid2]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid2]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid2], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid2], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid2], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid2] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid2; data->required_sclk = vbios->mid2_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid3]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid3], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid3] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid3]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid3]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid3], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid3], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid3], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid3] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid3; data->required_sclk = vbios->mid3_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid4]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid4], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid4] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid4]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid4]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid4], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid4], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid4], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid4] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid4; data->required_sclk = vbios->mid4_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid5]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid5], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid5] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid5]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid5]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid5], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid5], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid5], vbios->mid_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid5] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid5; data->required_sclk = vbios->mid5_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_mid6]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid6] == number_of_displays_enabled_with_margin))) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_mid6]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_mid6]) && (data->cpup_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (data->cpuc_state_change_enable == bw_def_no || (bw_mtn(data->blackout_duration_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->dispclk_required_for_blackout_duration[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && bw_ltn(data->dispclk_required_for_blackout_recovery[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk))) && (!data->increase_voltage_to_support_mclk_switch || data->nbp_state_change_enable == bw_def_no || (bw_mtn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(0)) && bw_ltn(data->min_dram_speed_change_margin[data->y_clk_level][s_mid6], bw_int_to_fixed(9999)) && bw_leq(data->dispclk_required_for_dram_speed_change[data->y_clk_level][s_mid6], vbios->high_voltage_max_dispclk) && data->num_displays_with_margin[data->y_clk_level][s_mid6] == number_of_displays_enabled_with_margin))) { sclk_message = bw_def_mid; data->sclk_level = s_mid6; data->required_sclk = vbios->mid6_sclk; } - else if (bw_ltn(data->required_sclk, sclk[s_high])) { + else if (bw_ltn(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_high]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_high])) { + sclk_message = bw_def_high; + data->sclk_level = s_high; + data->required_sclk = vbios->high_sclk; + } + else if (bw_meq(data->total_average_bandwidth_no_compression, bw_mul(bw_mul(bw_frc_to_fixed(dceip->max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation, 100),sclk[s_high]),vbios->data_return_bus_width)) + && bw_ltn(data->required_sclk, sclk[s_high])) { sclk_message = bw_def_high; data->sclk_level = s_high; data->required_sclk = vbios->high_sclk; @@ -1681,7 +1730,7 @@ static void calculate_bandwidth( data->total_dispclk_required_with_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_with_ramping_with_request_bandwidth, data->dispclk_required_for_blackout_duration[data->y_clk_level][data->sclk_level]); data->total_dispclk_required_without_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_without_ramping_with_request_bandwidth, data->dispclk_required_for_blackout_duration[data->y_clk_level][data->sclk_level]); } - if (data->nbp_state_change_enable == bw_def_yes) { + if (data->nbp_state_change_enable == bw_def_yes && data->increase_voltage_to_support_mclk_switch) { data->total_dispclk_required_with_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_with_ramping_with_request_bandwidth, data->dispclk_required_for_dram_speed_change[data->y_clk_level][data->sclk_level]); data->total_dispclk_required_without_ramping_with_request_bandwidth = bw_max2(data->total_dispclk_required_without_ramping_with_request_bandwidth, data->dispclk_required_for_dram_speed_change[data->y_clk_level][data->sclk_level]); } @@ -1861,23 +1910,6 @@ static void calculate_bandwidth( else { data->mcifwrdram_access_efficiency = bw_int_to_fixed(0); } - /*average bandwidth*/ - /*the average bandwidth with no compression is the vertical active time is the source width times the bytes per pixel divided by the line time, multiplied by the vertical scale ratio and the ratio of bytes per request divided by the useful bytes per request.*/ - /*the average bandwidth with compression is the same, divided by the compression ratio*/ - for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { - if (data->enable[i]) { - data->average_bandwidth_no_compression[i] = bw_div(bw_mul(bw_mul(bw_div(bw_mul(data->source_width_rounded_up_to_chunks[i], bw_int_to_fixed(data->bytes_per_pixel[i])), (bw_div(data->h_total[i], data->pixel_rate[i]))), data->vsr[i]), data->bytes_per_request[i]), data->useful_bytes_per_request[i]); - data->average_bandwidth[i] = bw_div(data->average_bandwidth_no_compression[i], data->compression_rate[i]); - } - } - data->total_average_bandwidth_no_compression = bw_int_to_fixed(0); - data->total_average_bandwidth = bw_int_to_fixed(0); - for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { - if (data->enable[i]) { - data->total_average_bandwidth_no_compression = bw_add(data->total_average_bandwidth_no_compression, data->average_bandwidth_no_compression[i]); - data->total_average_bandwidth = bw_add(data->total_average_bandwidth, data->average_bandwidth[i]); - } - } /*stutter efficiency*/ /*the stutter efficiency is the frame-average time in self-refresh divided by the frame-average stutter cycle duration. only applies if the display write-back is not enabled.*/ /*the frame-average stutter cycle used is the minimum for all pipes of the frame-average data buffer size in time, times the compression rate*/ @@ -1905,7 +1937,7 @@ static void calculate_bandwidth( data->total_stutter_dmif_buffer_size = bw_fixed_to_int(bw_add(data->stutter_dmif_buffer_size[i], bw_int_to_fixed(data->total_stutter_dmif_buffer_size))); } } - data->stutter_burst_time = bw_div(bw_int_to_fixed(data->total_stutter_dmif_buffer_size), bw_min2(bw_mul(data->dram_bandwidth, data->dmifdram_access_efficiency), bw_mul(sclk[data->sclk_level], bw_int_to_fixed(32)))); + data->stutter_burst_time = bw_div(bw_int_to_fixed(data->total_stutter_dmif_buffer_size), bw_mul(sclk[data->sclk_level], vbios->data_return_bus_width)); data->num_stutter_bursts = data->total_bytes_requested / data->min_stutter_dmif_buffer_size; data->total_stutter_cycle_duration = bw_add(bw_add(data->min_stutter_refresh_duration, vbios->stutter_self_refresh_exit_latency), data->stutter_burst_time); data->time_in_self_refresh = data->min_stutter_refresh_duration; @@ -1957,7 +1989,7 @@ static void calculate_bandwidth( for (i = 1; i <= 5; i++) { data->display_reads_time_for_data_transfer_and_urgent_latency = bw_sub(data->min_read_buffer_size_in_time, bw_mul(data->total_dmifmc_urgent_trips, bw_int_to_fixed(i))); if (pipe_check == bw_def_ok && (bw_mtn(data->display_reads_time_for_data_transfer_and_urgent_latency, data->dmif_total_page_close_open_time))) { - data->dmif_required_sclk_for_urgent_latency[i] = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer_and_urgent_latency), (bw_mul(vbios->data_return_bus_width, bw_int_to_fixed(bus_efficiency)))); + data->dmif_required_sclk_for_urgent_latency[i] = bw_div(bw_div(data->total_display_reads_required_data, data->display_reads_time_for_data_transfer_and_urgent_latency), (bw_mul(vbios->data_return_bus_width, bw_frc_to_fixed(dceip->percent_of_ideal_port_bw_received_after_urgent_latency, 100)))); } else { data->dmif_required_sclk_for_urgent_latency[i] = bw_int_to_fixed(bw_def_na); @@ -2036,6 +2068,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2146,6 +2181,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2259,6 +2297,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2369,6 +2410,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); dceip.dmif_pipe_en_fbc_chunk_tracker = false; @@ -2479,6 +2523,9 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.blackout_duration = bw_int_to_fixed(0); /* us */ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); + dceip.max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation = 100; + dceip.max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation = 100; + dceip.percent_of_ideal_port_bw_received_after_urgent_latency = 100; dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(2304); dceip.dmif_pipe_en_fbc_chunk_tracker = true; @@ -2597,6 +2644,7 @@ static void populate_initial_data( data->graphics_tiling_mode = bw_def_tiled; data->underlay_micro_tile_mode = bw_def_display_micro_tiling; data->graphics_micro_tile_mode = bw_def_display_micro_tiling; + data->increase_voltage_to_support_mclk_switch = true; /* Pipes with underlay first */ for (i = 0; i < pipe_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 8020bc7742c1..4bb43a371292 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -983,8 +983,6 @@ bool dcn_validate_bandwidth( context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); } - context->bw.dcn.calc_clk.dram_ccm_us = (int)(v->dram_clock_change_margin); - context->bw.dcn.calc_clk.min_active_dram_ccm_us = (int)(v->min_active_dram_clock_change_margin); context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); context->bw.dcn.calc_clk.dcfclk_khz = (int)(v->dcfclk * 1000); @@ -998,7 +996,26 @@ bool dcn_validate_bandwidth( dc->debug.min_disp_clk_khz; } - context->bw.dcn.calc_clk.max_dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; + context->bw.dcn.calc_clk.dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; + + switch (v->voltage_level) { + case 0: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vmin0p65 * 1000); + break; + case 1: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vmid0p72 * 1000); + break; + case 2: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vnom0p8 * 1000); + break; + default: + context->bw.dcn.calc_clk.max_supported_dppclk_khz = + (int)(dc->dcn_soc->max_dppclk_vmax0p9 * 1000); + break; + } for (i = 0, input_idx = 0; i < pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 8394d69b963f..63a3d468939a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -42,6 +42,7 @@ #include "dmcu.h" #include "dpp.h" #include "timing_generator.h" +#include "abm.h" #include "virtual/virtual_link_encoder.h" #include "link_hwss.h" @@ -802,6 +803,8 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c if (!dcb->funcs->is_accelerated_mode(dcb)) dc->hwss.enable_accelerated_mode(dc, context); + dc->hwss.set_bandwidth(dc, context, false); + /* re-program planes for existing stream, in case we need to * free up plane resource for later use */ @@ -870,6 +873,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c dc_enable_stereo(dc, context, dc_streams, context->stream_count); + /* pplib is notified if disp_num changed */ + dc->hwss.set_bandwidth(dc, context, true); + dc_release_state(dc->current_state); dc->current_state = context; @@ -1104,9 +1110,6 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa if (u->plane_info->input_tf != u->surface->input_tf) update_flags->bits.input_tf_change = 1; - if (u->plane_info->sdr_white_level != u->surface->sdr_white_level) - update_flags->bits.output_tf_change = 1; - if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) update_flags->bits.horizontal_mirror_change = 1; @@ -1361,6 +1364,17 @@ static void commit_planes_for_stream(struct dc *dc, dc->hwss.apply_ctx_for_surface( dc, pipe_ctx->stream, stream_status->plane_count, context); + + if (stream_update && stream_update->abm_level && pipe_ctx->stream_res.abm) { + if (pipe_ctx->stream_res.tg->funcs->is_blanked) { + // if otg funcs defined check if blanked before programming + if (!pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) + pipe_ctx->stream_res.abm->funcs->set_abm_level( + pipe_ctx->stream_res.abm, stream->abm_level); + } else + pipe_ctx->stream_res.abm->funcs->set_abm_level( + pipe_ctx->stream_res.abm, stream->abm_level); + } } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index c15565092ca8..5a552cb3f8a7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -36,26 +36,22 @@ #include "hw_sequencer.h" #include "resource.h" +#define DC_LOGGER \ + logger #define SURFACE_TRACE(...) do {\ if (dc->debug.surface_trace) \ - dm_logger_write(logger, \ - LOG_IF_TRACE, \ - ##__VA_ARGS__); \ + DC_LOG_IF_TRACE(__VA_ARGS__); \ } while (0) #define TIMING_TRACE(...) do {\ if (dc->debug.timing_trace) \ - dm_logger_write(logger, \ - LOG_SYNC, \ - ##__VA_ARGS__); \ + DC_LOG_SYNC(__VA_ARGS__); \ } while (0) #define CLOCK_TRACE(...) do {\ if (dc->debug.clock_trace) \ - dm_logger_write(logger, \ - LOG_BANDWIDTH_CALCS, \ - ##__VA_ARGS__); \ + DC_LOG_BANDWIDTH_CALCS(__VA_ARGS__); \ } while (0) void pre_surface_trace( @@ -362,25 +358,19 @@ void context_clock_trace( struct dal_logger *logger = core_dc->ctx->logger; CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n" - "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.max_dppclk_khz, + context->bw.dcn.calc_clk.dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz, - context->bw.dcn.calc_clk.dram_ccm_us, - context->bw.dcn.calc_clk.min_active_dram_ccm_us); + context->bw.dcn.calc_clk.socclk_khz); CLOCK_TRACE("Calculated: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n" - "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.max_dppclk_khz, + context->bw.dcn.calc_clk.dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.dram_ccm_us, - context->bw.dcn.calc_clk.min_active_dram_ccm_us); + context->bw.dcn.calc_clk.fclk_khz); #endif } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index f8c09273e0f1..eeb04471b2f5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1960,6 +1960,13 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, (abm->funcs->set_backlight_level == NULL)) return false; + if (stream) { + if (stream->bl_pwm_level == 0) + frame_ramp = 0; + + ((struct dc_stream_state *)stream)->bl_pwm_level = level; + } + use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", level, level); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index b9fc6d842931..ba3487e97361 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1124,6 +1124,7 @@ bool dc_add_plane_to_context( ASSERT(tail_pipe); free_pipe->stream_res.tg = tail_pipe->stream_res.tg; + free_pipe->stream_res.abm = tail_pipe->stream_res.abm; free_pipe->stream_res.opp = tail_pipe->stream_res.opp; free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; free_pipe->stream_res.audio = tail_pipe->stream_res.audio; @@ -1736,6 +1737,10 @@ enum dc_status resource_map_pool_resources( pipe_ctx->stream_res.audio, true); } + /* Add ABM to the resource if on EDP */ + if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.abm = pool->abm; + for (i = 0; i < context->stream_count; i++) if (context->streams[i] == stream) { context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index cd5819789d76..ce0747ed0f00 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -198,8 +198,7 @@ bool dc_stream_set_cursor_attributes( for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && - !pipe_ctx->plane_res.dpp) || !pipe_ctx->plane_res.ipp) + if (pipe_ctx->stream != stream) continue; if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) continue; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2cd97342bf0f..fa4b3c8b3bb7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.37" +#define DC_VER "3.1.38" #define MAX_SURFACES 3 #define MAX_STREAMS 6 @@ -186,13 +186,12 @@ enum wm_report_mode { struct dc_clocks { int dispclk_khz; - int max_dppclk_khz; + int max_supported_dppclk_khz; + int dppclk_khz; int dcfclk_khz; int socclk_khz; int dcfclk_deep_sleep_khz; int fclk_khz; - int dram_ccm_us; - int min_active_dram_ccm_us; }; struct dc_debug { @@ -447,6 +446,7 @@ union surface_update_flags { struct dc_plane_state { struct dc_plane_address address; + struct dc_plane_flip_time time; struct scaling_taps scaling_quality; struct rect src_rect; struct rect dst_rect; @@ -557,6 +557,7 @@ struct dc_transfer_func *dc_create_transfer_func(void); */ struct dc_flip_addrs { struct dc_plane_address address; + unsigned int flip_timestamp_in_us; bool flip_immediate; /* TODO: add flip duration for FreeSync */ }; diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index e91ac6811990..b83a7dc2f5a9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -692,8 +692,18 @@ struct crtc_trigger_info { enum trigger_delay delay; }; -struct dc_crtc_timing { +enum vrr_state { + VRR_STATE_OFF = 0, + VRR_STATE_VARIABLE, + VRR_STATE_FIXED, +}; +struct dc_crtc_timing_adjust { + uint32_t v_total_min; + uint32_t v_total_max; +}; + +struct dc_crtc_timing { uint32_t h_total; uint32_t h_border_left; uint32_t h_addressable; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index f44cd4d87b79..d017df56b2ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -48,6 +48,8 @@ struct dc_stream_status { struct dc_stream_state { struct dc_sink *sink; struct dc_crtc_timing timing; + struct dc_crtc_timing_adjust timing_adjust; + struct vrr_params vrr_params; struct rect src; /* composition area */ struct rect dst; /* stream addressable area */ @@ -74,6 +76,10 @@ struct dc_stream_state { unsigned char psr_version; /* TODO: CEA VIC */ + /* DMCU info */ + unsigned int abm_level; + unsigned int bl_pwm_level; + /* from core_stream struct */ struct dc_context *ctx; @@ -106,6 +112,7 @@ struct dc_stream_update { struct dc_transfer_func *out_transfer_func; struct dc_hdr_static_metadata *hdr_static_metadata; enum color_transfer_func color_output_tf; + unsigned int *abm_level; }; bool dc_is_stream_unchanged( diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 8811b6f86bff..9441305d3ab5 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -521,6 +521,24 @@ struct audio_info { struct audio_mode modes[DC_MAX_AUDIO_DESC_COUNT]; }; +struct vrr_params { + enum vrr_state state; + uint32_t window_min; + uint32_t window_max; + uint32_t inserted_frame_duration_in_us; + uint32_t frames_to_insert; + uint32_t frame_counter; +}; + +#define DC_PLANE_UPDATE_TIMES_MAX 10 + +struct dc_plane_flip_time { + unsigned int time_elapsed_in_us[DC_PLANE_UPDATE_TIMES_MAX]; + unsigned int index; + unsigned int prev_update_time_in_us; +}; + +// Will combine with vrr_params at some point. struct freesync_context { bool supported; bool enabled; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h index 1d4546f23135..c24c0e5ea44e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h @@ -46,6 +46,23 @@ SR(SMU_INTERRUPT_CONTROL), \ SR(DC_DMCU_SCRATCH) +#define DMCU_DCE80_REG_LIST() \ + SR(DMCU_CTRL), \ + SR(DMCU_STATUS), \ + SR(DMCU_RAM_ACCESS_CTRL), \ + SR(DMCU_IRAM_WR_CTRL), \ + SR(DMCU_IRAM_WR_DATA), \ + SR(MASTER_COMM_DATA_REG1), \ + SR(MASTER_COMM_DATA_REG2), \ + SR(MASTER_COMM_DATA_REG3), \ + SR(MASTER_COMM_CMD_REG), \ + SR(MASTER_COMM_CNTL_REG), \ + SR(DMCU_IRAM_RD_CTRL), \ + SR(DMCU_IRAM_RD_DATA), \ + SR(DMCU_INTERRUPT_TO_UC_EN_MASK), \ + SR(SMU_INTERRUPT_CONTROL), \ + SR(DC_DMCU_SCRATCH) + #define DMCU_DCE110_COMMON_REG_LIST() \ DMCU_COMMON_REG_LIST_DCE_BASE(), \ SR(DCI_MEM_PWR_STATUS) @@ -83,6 +100,24 @@ STATIC_SCREEN4_INT_TO_UC_EN, mask_sh), \ DMCU_SF(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, mask_sh) +#define DMCU_MASK_SH_LIST_DCE80(mask_sh) \ + DMCU_SF(DMCU_CTRL, \ + DMCU_ENABLE, mask_sh), \ + DMCU_SF(DMCU_STATUS, \ + UC_IN_STOP_MODE, mask_sh), \ + DMCU_SF(DMCU_STATUS, \ + UC_IN_RESET, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_HOST_ACCESS_EN, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_WR_ADDR_AUTO_INC, mask_sh), \ + DMCU_SF(DMCU_RAM_ACCESS_CTRL, \ + IRAM_RD_ADDR_AUTO_INC, mask_sh), \ + DMCU_SF(MASTER_COMM_CMD_REG, \ + MASTER_COMM_CMD_REG_BYTE0, mask_sh), \ + DMCU_SF(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, mask_sh), \ + DMCU_SF(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, mask_sh) + #define DMCU_MASK_SH_LIST_DCE110(mask_sh) \ DMCU_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh), \ DMCU_SF(DCI_MEM_PWR_STATUS, \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c index 4b8e7ce2de8c..487724345d9d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c @@ -56,7 +56,7 @@ void dce_pipe_control_lock(struct dc *dc, if (lock && pipe->stream_res.tg->funcs->is_blanked(pipe->stream_res.tg)) return; - val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->pipe_idx], + val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], BLND_DCP_GRPH_V_UPDATE_LOCK, &dcp_grph, BLND_SCL_V_UPDATE_LOCK, &scl, BLND_BLND_V_UPDATE_LOCK, &blnd, @@ -67,19 +67,19 @@ void dce_pipe_control_lock(struct dc *dc, blnd = lock_val; update_lock_mode = lock_val; - REG_SET_2(BLND_V_UPDATE_LOCK[pipe->pipe_idx], val, + REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, BLND_DCP_GRPH_V_UPDATE_LOCK, dcp_grph, BLND_SCL_V_UPDATE_LOCK, scl); if (hws->masks->BLND_BLND_V_UPDATE_LOCK != 0) - REG_SET_2(BLND_V_UPDATE_LOCK[pipe->pipe_idx], val, + REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, BLND_BLND_V_UPDATE_LOCK, blnd, BLND_V_UPDATE_LOCK_MODE, update_lock_mode); if (hws->wa.blnd_crtc_trigger) { if (!lock) { - uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->pipe_idx]); - REG_WRITE(CRTC_H_BLANK_START_END[pipe->pipe_idx], value); + uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst]); + REG_WRITE(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst], value); } } } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 3336428b1fed..057b8afd74bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -190,6 +190,7 @@ SR(D2VGA_CONTROL), \ SR(D3VGA_CONTROL), \ SR(D4VGA_CONTROL), \ + SR(VGA_TEST_CONTROL), \ SR(DC_IP_REQUEST_CNTL), \ BL_REG_LIST() @@ -261,6 +262,7 @@ struct dce_hwseq_registers { uint32_t D2VGA_CONTROL; uint32_t D3VGA_CONTROL; uint32_t D4VGA_CONTROL; + uint32_t VGA_TEST_CONTROL; /* MMHUB registers. read only. temporary hack */ uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32; uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; @@ -327,6 +329,8 @@ struct dce_hwseq_registers { HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, mask_sh),\ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh),\ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) @@ -403,7 +407,15 @@ struct dce_hwseq_registers { HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D2VGA_CONTROL, D2VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D3VGA_CONTROL, D3VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D4VGA_CONTROL, D4VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ + HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh), \ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) #define HWSEQ_REG_FIELD_LIST(type) \ @@ -436,7 +448,9 @@ struct dce_hwseq_registers { type ENABLE_L1_TLB;\ type SYSTEM_ACCESS_MODE;\ type LVTMA_BLON;\ - type LVTMA_PWRSEQ_TARGET_STATE_R; + type LVTMA_PWRSEQ_TARGET_STATE_R;\ + type LVTMA_DIGON;\ + type LVTMA_DIGON_OVRD; #define HWSEQ_DCN_REG_FIELD_LIST(type) \ type HUBP_VTG_SEL; \ @@ -483,7 +497,13 @@ struct dce_hwseq_registers { type DCFCLK_GATE_DIS; \ type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ type DENTIST_DPPCLK_WDIVIDER; \ - type DENTIST_DISPCLK_WDIVIDER; + type DENTIST_DISPCLK_WDIVIDER; \ + type VGA_TEST_ENABLE; \ + type VGA_TEST_RENDER_START; \ + type D1VGA_MODE_ENABLE; \ + type D2VGA_MODE_ENABLE; \ + type D3VGA_MODE_ENABLE; \ + type D4VGA_MODE_ENABLE; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 81776e4797ed..8167cad7bcf7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -767,8 +767,7 @@ void dce110_link_encoder_construct( bp_cap_info.DP_HBR3_EN; enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; } else { - dm_logger_write(enc110->base.ctx->logger, LOG_WARNING, - "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", + DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", __func__, result); } diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 3bdbed80f7f8..3092f76bdb75 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -51,6 +51,9 @@ #include "dce/dce_10_0_d.h" #include "dce/dce_10_0_sh_mask.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_abm.h" + #ifndef mmMC_HUB_RDREQ_DMIF_LIMIT #include "gmc/gmc_8_2_d.h" #include "gmc/gmc_8_2_sh_mask.h" @@ -320,7 +323,29 @@ static const struct dce110_clk_src_mask cs_mask = { CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; #define DCFE_MEM_PWR_CTRL_REG_BASE 0x1b03 @@ -622,6 +647,12 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.display_clock != NULL) dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + if (pool->base.irqs != NULL) dal_irq_service_destroy(&pool->base.irqs); } @@ -829,6 +860,25 @@ static bool construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } /* get static clock information for PPLIB or firmware, save * max_clock_state diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index c2041a63cccd..30dd62f0f5fa 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -737,10 +737,14 @@ static bool is_panel_backlight_on(struct dce_hwseq *hws) static bool is_panel_powered_on(struct dce_hwseq *hws) { - uint32_t value; + uint32_t pwr_seq_state, dig_on, dig_on_ovrd; + + + REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &pwr_seq_state); + + REG_GET_2(LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, &dig_on, LVTMA_DIGON_OVRD, &dig_on_ovrd); - REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &value); - return value == 1; + return (pwr_seq_state == 1) || (dig_on == 1 && dig_on_ovrd == 1); } static enum bp_result link_transmitter_control( @@ -1002,8 +1006,10 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, if (dc_is_dp_signal(pipe_ctx->stream->signal)) pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { link->dc->hwss.edp_backlight_control(link, true); + stream->bl_pwm_level = 0; + } } void dce110_blank_stream(struct pipe_ctx *pipe_ctx) { @@ -1128,7 +1134,7 @@ static void build_audio_output( static void get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx, struct tg_color *color) { - uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->pipe_idx) / 4; + uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->stream_res.tg->inst) / 4; switch (pipe_ctx->plane_res.scl_data.format) { case PIXEL_FORMAT_ARGB8888: @@ -2106,9 +2112,6 @@ enum dc_status dce110_apply_ctx_to_hw( return status; } - /* pplib is notified if disp_num changed */ - dc->hwss.set_bandwidth(dc, context, true); - /* to save power */ apply_min_clocks(dc, context, &clocks_state, false); @@ -2936,15 +2939,18 @@ void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) { struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; - if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) + if (pipe_ctx->plane_res.ipp && + pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( pipe_ctx->plane_res.ipp, attributes); - if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) + if (pipe_ctx->plane_res.mi && + pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( pipe_ctx->plane_res.mi, attributes); - if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) + if (pipe_ctx->plane_res.xfm && + pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( pipe_ctx->plane_res.xfm, attributes); } diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index a36c14d3d9a8..5d854a37a978 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -53,6 +53,8 @@ #include "reg_helper.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_abm.h" /* TODO remove this include */ #ifndef mmMC_HUB_RDREQ_DMIF_LIMIT @@ -364,6 +366,29 @@ static const struct resource_caps res_cap_83 = { .num_pll = 2, }; +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE80_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE80(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE80(_MASK) +}; +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + #define CTX ctx #define REG(reg) mm ## reg @@ -643,6 +668,12 @@ static void destruct(struct dce110_resource_pool *pool) } } + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + if (pool->base.dp_clock_source != NULL) dce80_clock_source_destroy(&pool->base.dp_clock_source); @@ -850,7 +881,25 @@ static bool dce80_construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) pool->base.display_clock->max_clks_state = static_clk_info.max_clocks_state; @@ -1016,6 +1065,25 @@ static bool dce81_construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) pool->base.display_clock->max_clks_state = @@ -1178,6 +1246,25 @@ static bool dce83_construct( goto res_create_fail; } + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) pool->base.display_clock->max_clks_state = diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index f0b798930b51..e305c28c98de 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -464,6 +464,7 @@ static const struct dpp_funcs dcn10_dpp_funcs = { .set_cursor_attributes = dpp1_set_cursor_attributes, .set_cursor_position = dpp1_set_cursor_position, .dpp_dppclk_control = dpp1_dppclk_control, + .dpp_set_hdr_multiplier = dpp1_set_hdr_multiplier, }; static struct dpp_caps dcn10_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index 07003d9c6bba..17b062a8f88a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -113,7 +113,8 @@ SRI(CURSOR0_CONTROL, CNVC_CUR, id), \ SRI(CURSOR0_COLOR0, CNVC_CUR, id), \ SRI(CURSOR0_COLOR1, CNVC_CUR, id), \ - SRI(DPP_CONTROL, DPP_TOP, id) + SRI(DPP_CONTROL, DPP_TOP, id), \ + SRI(CM_HDR_MULT_COEF, CM, id) @@ -308,7 +309,8 @@ TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh), \ - TF_SF(DPP_TOP0_DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh) + TF_SF(DPP_TOP0_DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh), \ + TF_SF(CM0_CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, mask_sh) #define TF_REG_LIST_SH_MASK_DCN10(mask_sh)\ TF_REG_LIST_SH_MASK_DCN(mask_sh),\ @@ -1012,7 +1014,8 @@ type CUR0_COLOR0; \ type CUR0_COLOR1; \ type DPPCLK_RATE_CONTROL; \ - type DPP_CLOCK_ENABLE; + type DPP_CLOCK_ENABLE; \ + type CM_HDR_MULT_COEF; struct dcn_dpp_shift { TF_REG_FIELD_LIST(uint8_t) @@ -1258,7 +1261,8 @@ struct dcn_dpp_mask { uint32_t CURSOR0_CONTROL; \ uint32_t CURSOR0_COLOR0; \ uint32_t CURSOR0_COLOR1; \ - uint32_t DPP_CONTROL; + uint32_t DPP_CONTROL; \ + uint32_t CM_HDR_MULT_COEF; struct dcn_dpp_registers { DPP_COMMON_REG_VARIABLE_LIST @@ -1414,6 +1418,10 @@ void dpp1_dppclk_control( bool dppclk_div, bool enable); +void dpp1_set_hdr_multiplier( + struct dpp *dpp_base, + uint32_t multiplier); + void dpp1_construct(struct dcn10_dpp *dpp1, struct dc_context *ctx, uint32_t inst, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index bd3fcdfb79c5..fb32975e4b67 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -804,3 +804,12 @@ void dpp1_program_input_lut( REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, rama_occupied ? 3 : 2); REG_GET(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, &ram_num); } + +void dpp1_set_hdr_multiplier( + struct dpp *dpp_base, + uint32_t multiplier) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_UPDATE(CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, multiplier); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 1907ade1574a..8b0f6b8a5627 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -220,10 +220,34 @@ static void enable_power_gating_plane( static void disable_vga( struct dce_hwseq *hws) { + unsigned int in_vga1_mode = 0; + unsigned int in_vga2_mode = 0; + unsigned int in_vga3_mode = 0; + unsigned int in_vga4_mode = 0; + + REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); + REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); + REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); + REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); + + if (in_vga1_mode == 0 && in_vga2_mode == 0 && + in_vga3_mode == 0 && in_vga4_mode == 0) + return; + REG_WRITE(D1VGA_CONTROL, 0); REG_WRITE(D2VGA_CONTROL, 0); REG_WRITE(D3VGA_CONTROL, 0); REG_WRITE(D4VGA_CONTROL, 0); + + /* HW Engineer's Notes: + * During switch from vga->extended, if we set the VGA_TEST_ENABLE and + * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. + * + * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset + * VGA_TEST_ENABLE, to leave it in the same state as before. + */ + REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); + REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); } static void dpp_pg_control( @@ -1685,16 +1709,22 @@ static void update_dchubp_dpp( union plane_size size = plane_state->plane_size; /* depends on DML calculation, DPP clock value may change dynamically */ + /* If request max dpp clk is lower than current dispclk, no need to + * divided by 2 + */ if (plane_state->update_flags.bits.full_update) { + bool should_divided_by_2 = context->bw.dcn.calc_clk.dppclk_khz <= + context->bw.dcn.cur_clk.dispclk_khz / 2; + dpp->funcs->dpp_dppclk_control( dpp, - context->bw.dcn.calc_clk.max_dppclk_khz < - context->bw.dcn.calc_clk.dispclk_khz, + should_divided_by_2, true); - dc->current_state->bw.dcn.cur_clk.max_dppclk_khz = - context->bw.dcn.calc_clk.max_dppclk_khz; - context->bw.dcn.cur_clk.max_dppclk_khz = context->bw.dcn.calc_clk.max_dppclk_khz; + dc->current_state->bw.dcn.cur_clk.dppclk_khz = + should_divided_by_2 ? + context->bw.dcn.cur_clk.dispclk_khz / 2 : + context->bw.dcn.cur_clk.dispclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG @@ -1780,14 +1810,62 @@ static void update_dchubp_dpp( hubp->funcs->set_blank(hubp, false); } +static void dcn10_otg_blank( + struct dc *dc, + struct stream_resource stream_res, + struct dc_stream_state *stream, + bool blank) +{ + enum dc_color_space color_space; + struct tg_color black_color = {0}; + + /* program otg blank color */ + color_space = stream->output_color_space; + color_space_to_black_color(dc, color_space, &black_color); + + if (stream_res.tg->funcs->set_blank_color) + stream_res.tg->funcs->set_blank_color( + stream_res.tg, + &black_color); + + if (!blank) { + if (stream_res.tg->funcs->set_blank) + stream_res.tg->funcs->set_blank(stream_res.tg, blank); + if (stream_res.abm) + stream_res.abm->funcs->set_abm_level(stream_res.abm, stream->abm_level); + } else if (blank) { + if (stream_res.abm) + stream_res.abm->funcs->set_abm_immediate_disable(stream_res.abm); + if (stream_res.tg->funcs->set_blank) + stream_res.tg->funcs->set_blank(stream_res.tg, blank); + } +} + +static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) +{ + struct fixed31_32 multiplier = dal_fixed31_32_from_fraction( + pipe_ctx->plane_state->sdr_white_level, 80); + uint32_t hw_mult = 0x1f000; // 1.0 default multiplier + struct custom_float_format fmt; + + fmt.exponenta_bits = 6; + fmt.mantissa_bits = 12; + fmt.sign = true; + + if (pipe_ctx->plane_state->sdr_white_level > 80) + convert_to_custom_float_format(multiplier, &fmt, &hw_mult); + + pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( + pipe_ctx->plane_res.dpp, hw_mult); +} static void program_all_pipe_in_tree( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { - if (pipe_ctx->top_pipe == NULL) { + bool blank = !is_pipe_tree_visible(pipe_ctx); pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; @@ -1798,10 +1876,8 @@ static void program_all_pipe_in_tree( pipe_ctx->stream_res.tg->funcs->program_global_sync( pipe_ctx->stream_res.tg); - if (pipe_ctx->stream_res.tg->funcs->set_blank) - pipe_ctx->stream_res.tg->funcs->set_blank( - pipe_ctx->stream_res.tg, - !is_pipe_tree_visible(pipe_ctx)); + dcn10_otg_blank(dc, pipe_ctx->stream_res, + pipe_ctx->stream, blank); } if (pipe_ctx->plane_state != NULL) { @@ -1810,6 +1886,8 @@ static void program_all_pipe_in_tree( update_dchubp_dpp(dc, pipe_ctx, context); + set_hdr_multiplier(pipe_ctx); + if (pipe_ctx->plane_state->update_flags.bits.full_update || pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || pipe_ctx->plane_state->update_flags.bits.gamma_change) @@ -1836,16 +1914,10 @@ static void dcn10_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->all_displays_in_sync = false;/*todo*/ - pp_display_cfg->nb_pstate_switch_disable = false; pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz; pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz; pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->avail_mclk_switch_time_us = - context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0; - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = - context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0; pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz; pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); @@ -1908,29 +1980,23 @@ static void dcn10_apply_ctx_for_surface( { int i; struct timing_generator *tg; - struct output_pixel_processor *opp; bool removed_pipe[4] = { false }; unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; bool program_water_mark = false; struct dc_context *ctx = dc->ctx; - struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); if (!top_pipe_to_program) return; - opp = top_pipe_to_program->stream_res.opp; - tg = top_pipe_to_program->stream_res.tg; dcn10_pipe_control_lock(dc, top_pipe_to_program, true); if (num_planes == 0) { - /* OTG blank before remove all front end */ - if (tg->funcs->set_blank) - tg->funcs->set_blank(tg, true); + dcn10_otg_blank(dc, top_pipe_to_program->stream_res, top_pipe_to_program->stream, true); } /* Disconnect unused mpcc */ @@ -2056,6 +2122,101 @@ static void dcn10_apply_ctx_for_surface( */ } +static inline bool should_set_clock(bool decrease_allowed, int calc_clk, int cur_clk) +{ + return ((decrease_allowed && calc_clk < cur_clk) || calc_clk > cur_clk); +} + +static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) +{ + bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.calc_clk.dppclk_khz; + bool dispclk_increase = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.cur_clk.dispclk_khz; + int disp_clk_threshold = context->bw.dcn.calc_clk.max_supported_dppclk_khz; + bool cur_dpp_div = context->bw.dcn.cur_clk.dispclk_khz > + context->bw.dcn.cur_clk.dppclk_khz; + + /* increase clock, looking for div is 0 for current, request div is 1*/ + if (dispclk_increase) { + /* already divided by 2, no need to reach target clk with 2 steps*/ + if (cur_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* request disp clk is lower than maximum supported dpp clk, + * no need to reach target clk with two steps. + */ + if (context->bw.dcn.calc_clk.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* target dpp clk not request divided by 2, still within threshold */ + if (!request_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + } else { + /* decrease clock, looking for current dppclk divided by 2, + * request dppclk not divided by 2. + */ + + /* current dpp clk not divided by 2, no need to ramp*/ + if (!cur_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* current disp clk is lower than current maximum dpp clk, + * no need to ramp + */ + if (context->bw.dcn.cur_clk.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* request dpp clk need to be divided by 2 */ + if (request_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + } + + return disp_clk_threshold; +} + +static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) +{ + int i; + bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.calc_clk.dppclk_khz; + + int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); + + /* set disp clk to dpp clk threshold */ + dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock, + dispclk_to_dpp_threshold); + + /* update request dpp clk division option */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->plane_state) + continue; + + pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( + pipe_ctx->plane_res.dpp, + request_dpp_div, + true); + } + + /* If target clk not same as dppclk threshold, set to target clock */ + if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { + dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock, + context->bw.dcn.calc_clk.dispclk_khz); + } + + context->bw.dcn.cur_clk.dispclk_khz = + context->bw.dcn.calc_clk.dispclk_khz; + context->bw.dcn.cur_clk.dppclk_khz = + context->bw.dcn.calc_clk.dppclk_khz; + context->bw.dcn.cur_clk.max_supported_dppclk_khz = + context->bw.dcn.calc_clk.max_supported_dppclk_khz; +} + static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, @@ -2073,32 +2234,32 @@ static void dcn10_set_bandwidth( if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) return; - if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz - > dc->current_state->bw.dcn.cur_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - } - if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dcfclk_khz, + dc->current_state->bw.dcn.cur_clk.dcfclk_khz)) { context->bw.dcn.cur_clk.dcfclk_khz = context->bw.dcn.calc_clk.dcfclk_khz; smu_req.hard_min_dcefclk_khz = context->bw.dcn.calc_clk.dcfclk_khz; } - if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz - > dc->current_state->bw.dcn.cur_clk.fclk_khz) { + + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, + dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz)) { + context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = + context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; + } + + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.fclk_khz, + dc->current_state->bw.dcn.cur_clk.fclk_khz)) { context->bw.dcn.cur_clk.fclk_khz = context->bw.dcn.calc_clk.fclk_khz; smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; } - if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) { - context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; - } smu_req.display_count = context->stream_count; @@ -2107,17 +2268,17 @@ static void dcn10_set_bandwidth( *smu_req_cur = smu_req; - /* Decrease in freq is increase in period so opposite comparison for dram_ccm */ - if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us - < dc->current_state->bw.dcn.cur_clk.dram_ccm_us) { - context->bw.dcn.cur_clk.dram_ccm_us = - context->bw.dcn.calc_clk.dram_ccm_us; - } - if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us - < dc->current_state->bw.dcn.cur_clk.min_active_dram_ccm_us) { - context->bw.dcn.cur_clk.min_active_dram_ccm_us = - context->bw.dcn.calc_clk.min_active_dram_ccm_us; + /* make sure dcf clk is before dpp clk to + * make sure we have enough voltage to run dpp clk + */ + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dispclk_khz, + dc->current_state->bw.dcn.cur_clk.dispclk_khz)) { + + ramp_up_dispclk_with_dpp(dc, context); } + dcn10_pplib_apply_display_requirements(dc, context); if (dc->debug.sanity_checks) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index c4a564cb56b9..02bd664aed3e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -440,7 +440,11 @@ static const struct dc_debug debug_defaults_drv = { .timing_trace = false, .clock_trace = true, - .min_disp_clk_khz = 300000, + /* raven smu dones't allow 0 disp clk, + * smu min disp clk limit is 50Mhz + * keep min disp clk 100Mhz avoid smu hang + */ + .min_disp_clk_khz = 100000, .disable_pplib_clock_request = true, .disable_pplib_wm_range = false, @@ -963,6 +967,7 @@ static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer( idle_pipe->stream = head_pipe->stream; idle_pipe->stream_res.tg = head_pipe->stream_res.tg; + idle_pipe->stream_res.abm = head_pipe->stream_res.abm; idle_pipe->stream_res.opp = head_pipe->stream_res.opp; idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c index 189052e911fc..48400d642610 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c @@ -24,6 +24,7 @@ */ #include "display_rq_dlg_helpers.h" +#include "dml_logger.h" void print__rq_params_st(struct display_mode_lib *mode_lib, display_rq_params_st rq_param) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h b/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h index b2847bc469fe..f78cbae9db88 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h @@ -31,8 +31,6 @@ #include "display_mode_structs.h" #include "display_mode_enums.h" -#define dml_print(str, ...) {dm_logger_write(mode_lib->logger, LOG_DML, str, ##__VA_ARGS__); } -#define DTRACE(str, ...) {dm_logger_write(mode_lib->logger, LOG_DML, str, ##__VA_ARGS__); } double dml_round(double a); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h b/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h index e68086b8a22f..f9cf08357989 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h @@ -28,6 +28,7 @@ #include "dml_common_defs.h" #include "../calcs/dcn_calc_math.h" +#include "dml_logger.h" static inline double dml_min(double a, double b) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_logger.h b/drivers/gpu/drm/amd/display/dc/dml/dml_logger.h new file mode 100644 index 000000000000..465859b77248 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_logger.h @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#ifndef __DML_LOGGER_H_ +#define __DML_LOGGER_H_ + +#define DC_LOGGER \ + mode_lib->logger + +#define dml_print(str, ...) {DC_LOG_DML(str, ##__VA_ARGS__); } +#define DTRACE(str, ...) {DC_LOG_DML(str, ##__VA_ARGS__); } + +#endif + + diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index b8f05384a897..8c51ad70cace 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -194,6 +194,8 @@ struct stream_resource { struct pixel_clk_params pix_clk_params; struct encoder_info_frame encoder_info_frame; + + struct abm *abm; }; struct plane_resource { diff --git a/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h index ae2399f16d1c..a9bfe9ff8ce6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h @@ -130,6 +130,9 @@ enum bw_defines { struct bw_calcs_dceip { enum bw_calcs_version version; + uint32_t percent_of_ideal_port_bw_received_after_urgent_latency; + uint32_t max_average_percent_of_ideal_port_bw_display_can_use_in_normal_system_operation; + uint32_t max_average_percent_of_ideal_drambw_display_can_use_in_normal_system_operation; bool large_cursor; uint32_t cursor_max_outstanding_group_num; bool dmif_pipe_en_fbc_chunk_tracker; @@ -230,6 +233,7 @@ struct bw_calcs_vbios { struct bw_calcs_data { /* data for all displays */ + bool display_synchronization_enabled; uint32_t number_of_displays; enum bw_defines underlay_surface_type; enum bw_defines panning_and_bezel_adjustment; @@ -241,6 +245,7 @@ struct bw_calcs_data { bool d1_display_write_back_dwb_enable; enum bw_defines d1_underlay_mode; + bool increase_voltage_to_support_mclk_switch; bool cpup_state_change_enable; bool cpuc_state_change_enable; bool nbp_state_change_enable; @@ -449,6 +454,7 @@ struct bw_calcs_data { struct bw_fixed dram_speed_change_line_source_transfer_time[maximum_number_of_surfaces][3][8]; struct bw_fixed min_dram_speed_change_margin[3][8]; struct bw_fixed dispclk_required_for_dram_speed_change[3][8]; + struct bw_fixed dispclk_required_for_dram_speed_change_pipe[3][8]; struct bw_fixed blackout_duration_margin[3][8]; struct bw_fixed dispclk_required_for_blackout_duration[3][8]; struct bw_fixed dispclk_required_for_blackout_recovery[3][8]; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index c5aae2daf442..99995608b620 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -132,6 +132,9 @@ struct dpp_funcs { const struct dc_cursor_mi_param *param, uint32_t width ); + void (*dpp_set_hdr_multiplier)( + struct dpp *dpp_base, + uint32_t multiplier); void (*dpp_dppclk_control)( struct dpp *dpp_base, diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index b727f5eeb3a9..427796bdc14a 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -98,6 +98,7 @@ enum dc_log_type { LOG_EVENT_UNDERFLOW, LOG_IF_TRACE, LOG_PERF_TRACE, + LOG_PROFILING, LOG_SECTION_TOTAL_COUNT }; diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 57d5c2575de1..e7e374f56864 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1267,7 +1267,8 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, bool ret = false; struct pwl_float_data_ex *rgb_regamma = NULL; - if (trans == TRANSFER_FUNCTION_UNITY) { + if (trans == TRANSFER_FUNCTION_UNITY || + trans == TRANSFER_FUNCTION_LINEAR) { points->end_exponent = 0; points->x_point_at_y1_red = 1; points->x_point_at_y1_green = 1; @@ -1337,7 +1338,8 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, bool ret = false; struct pwl_float_data_ex *rgb_degamma = NULL; - if (trans == TRANSFER_FUNCTION_UNITY) { + if (trans == TRANSFER_FUNCTION_UNITY || + trans == TRANSFER_FUNCTION_LINEAR) { for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = coordinates_x[i].x; diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index b4723af368a5..27d4003aa2c7 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -33,7 +33,7 @@ /* Refresh rate ramp at a fixed rate of 65 Hz/second */ #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) /* Number of elements in the render times cache array */ -#define RENDER_TIMES_MAX_COUNT 20 +#define RENDER_TIMES_MAX_COUNT 10 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ #define BTR_EXIT_MARGIN 2000 /* Number of consecutive frames to check before entering/exiting fixed refresh*/ @@ -46,13 +46,15 @@ #define FREESYNC_NO_STATIC_FOR_INTERNAL_REGKEY "DalFreeSyncNoStaticForInternal" +#define FREESYNC_DEFAULT_REGKEY "LCDFreeSyncDefault" + struct gradual_static_ramp { bool ramp_is_active; bool ramp_direction_is_up; unsigned int ramp_current_frame_duration_in_ns; }; -struct time_cache { +struct freesync_time { /* video (48Hz feature) related */ unsigned int update_duration_in_ns; @@ -64,6 +66,9 @@ struct time_cache { unsigned int render_times_index; unsigned int render_times[RENDER_TIMES_MAX_COUNT]; + + unsigned int min_window; + unsigned int max_window; }; struct below_the_range { @@ -98,11 +103,14 @@ struct freesync_state { bool static_screen; bool video; + unsigned int vmin; + unsigned int vmax; + + struct freesync_time time; + unsigned int nominal_refresh_rate_in_micro_hz; bool windowed_fullscreen; - struct time_cache time; - struct gradual_static_ramp static_ramp; struct below_the_range btr; struct fixed_refresh fixed_refresh; @@ -119,14 +127,16 @@ struct freesync_entity { struct freesync_registry_options { bool drr_external_supported; bool drr_internal_supported; + bool lcd_freesync_default_set; + int lcd_freesync_default_value; }; struct core_freesync { struct mod_freesync public; struct dc *dc; + struct freesync_registry_options opts; struct freesync_entity *map; int num_entities; - struct freesync_registry_options opts; }; #define MOD_FREESYNC_TO_CORE(mod_freesync)\ @@ -146,7 +156,7 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) goto fail_alloc_context; core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, - GFP_KERNEL); + GFP_KERNEL); if (core_freesync->map == NULL) goto fail_alloc_map; @@ -183,6 +193,16 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) (data & 1) ? false : true; } + if (dm_read_persistent_data(dc->ctx, NULL, NULL, + FREESYNC_DEFAULT_REGKEY, + &data, sizeof(data), &flag)) { + core_freesync->opts.lcd_freesync_default_set = true; + core_freesync->opts.lcd_freesync_default_value = data; + } else { + core_freesync->opts.lcd_freesync_default_set = false; + core_freesync->opts.lcd_freesync_default_value = 0; + } + return &core_freesync->public; fail_construct: @@ -288,6 +308,18 @@ bool mod_freesync_add_stream(struct mod_freesync *mod_freesync, core_freesync->map[core_freesync->num_entities].user_enable. enable_for_video = (persistent_freesync_enable & 4) ? true : false; + /* If FreeSync display and LCDFreeSyncDefault is set, use as default values write back to userenable */ + } else if (caps->supported && (core_freesync->opts.lcd_freesync_default_set)) { + core_freesync->map[core_freesync->num_entities].user_enable.enable_for_gaming = + (core_freesync->opts.lcd_freesync_default_value & 1) ? true : false; + core_freesync->map[core_freesync->num_entities].user_enable.enable_for_static = + (core_freesync->opts.lcd_freesync_default_value & 2) ? true : false; + core_freesync->map[core_freesync->num_entities].user_enable.enable_for_video = + (core_freesync->opts.lcd_freesync_default_value & 4) ? true : false; + dm_write_persistent_data(dc->ctx, stream->sink, + FREESYNC_REGISTRY_NAME, + "userenable", &core_freesync->opts.lcd_freesync_default_value, + sizeof(int), &flag); } else { core_freesync->map[core_freesync->num_entities].user_enable. enable_for_gaming = false; @@ -330,6 +362,25 @@ bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync, return true; } +static void adjust_vmin_vmax(struct core_freesync *core_freesync, + struct dc_stream_state **streams, + int num_streams, + int map_index, + unsigned int v_total_min, + unsigned int v_total_max) +{ + if (num_streams == 0 || streams == NULL || num_streams > 1) + return; + + core_freesync->map[map_index].state.vmin = v_total_min; + core_freesync->map[map_index].state.vmax = v_total_max; + + dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, + num_streams, v_total_min, + v_total_max); +} + + static void update_stream_freesync_context(struct core_freesync *core_freesync, struct dc_stream_state *stream) { @@ -588,9 +639,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, update_stream_freesync_context(core_freesync, streams[stream_idx]); - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total_min, - v_total_max); + adjust_vmin_vmax(core_freesync, streams, + num_streams, map_index, + v_total_min, + v_total_max); return true; @@ -613,9 +665,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, core_freesync, streams[stream_idx]); - dc_stream_adjust_vmin_vmax( - core_freesync->dc, streams, - num_streams, v_total_nominal, + adjust_vmin_vmax( + core_freesync, streams, + num_streams, map_index, + v_total_nominal, v_total_nominal); } return true; @@ -632,9 +685,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, core_freesync, streams[stream_idx]); - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total_nominal, - v_total_nominal); + adjust_vmin_vmax(core_freesync, streams, + num_streams, map_index, + v_total_nominal, + v_total_nominal); /* Reset the cached variables */ reset_freesync_state_variables(state); @@ -650,9 +704,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, * not support freesync because a former stream has * be programmed */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total_nominal, - v_total_nominal); + adjust_vmin_vmax(core_freesync, streams, + num_streams, map_index, + v_total_nominal, + v_total_nominal); /* Reset the cached variables */ reset_freesync_state_variables(state); } @@ -769,8 +824,9 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, vmin = inserted_frame_v_total; /* Program V_TOTAL */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, vmin, vmax); + adjust_vmin_vmax(core_freesync, streams, + num_streams, index, + vmin, vmax); } if (state->btr.frame_counter > 0) @@ -804,9 +860,10 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, update_stream_freesync_context(core_freesync, streams[0]); /* Program static screen ramp values */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, - num_streams, v_total, - v_total); + adjust_vmin_vmax(core_freesync, streams, + num_streams, index, + v_total, + v_total); triggers.overlay_update = true; triggers.surface_update = true; @@ -1063,9 +1120,9 @@ bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync, max_refresh); /* Program vtotal min/max */ - dc_stream_adjust_vmin_vmax(core_freesync->dc, &streams, 1, - state->freesync_range.vmin, - state->freesync_range.vmax); + adjust_vmin_vmax(core_freesync, &streams, 1, index, + state->freesync_range.vmin, + state->freesync_range.vmax); } if (min_refresh != 0 && @@ -1399,11 +1456,9 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, } else { vmin = state->freesync_range.vmin; - vmax = vmin; - - dc_stream_adjust_vmin_vmax(core_freesync->dc, &stream, - 1, vmin, vmax); + adjust_vmin_vmax(core_freesync, &stream, map_index, + 1, vmin, vmax); } } @@ -1457,3 +1512,43 @@ void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, } } + +void mod_freesync_get_settings(struct mod_freesync *mod_freesync, + struct dc_stream_state **streams, int num_streams, + unsigned int *v_total_min, unsigned int *v_total_max, + unsigned int *event_triggers, + unsigned int *window_min, unsigned int *window_max, + unsigned int *lfc_mid_point_in_us, + unsigned int *inserted_frames, + unsigned int *inserted_duration_in_us) +{ + unsigned int stream_index, map_index; + struct core_freesync *core_freesync = NULL; + + if (mod_freesync == NULL) + return; + + core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); + + for (stream_index = 0; stream_index < num_streams; stream_index++) { + + map_index = map_index_from_stream(core_freesync, + streams[stream_index]); + + if (core_freesync->map[map_index].caps->supported) { + struct freesync_state state = + core_freesync->map[map_index].state; + *v_total_min = state.vmin; + *v_total_max = state.vmax; + *event_triggers = 0; + *window_min = state.time.min_window; + *window_max = state.time.max_window; + *lfc_mid_point_in_us = state.btr.mid_point_in_us; + *inserted_frames = state.btr.frames_to_insert; + *inserted_duration_in_us = + state.btr.inserted_frame_duration_in_us; + } + + } +} + diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index 84b53425f2c8..f083e1619dbe 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -164,4 +164,13 @@ void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, struct dc_stream_state **streams, int num_streams, unsigned int curr_time_stamp); +void mod_freesync_get_settings(struct mod_freesync *mod_freesync, + struct dc_stream_state **streams, int num_streams, + unsigned int *v_total_min, unsigned int *v_total_max, + unsigned int *event_triggers, + unsigned int *window_min, unsigned int *window_max, + unsigned int *lfc_mid_point_in_us, + unsigned int *inserted_frames, + unsigned int *inserted_duration_in_us); + #endif diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h new file mode 100644 index 000000000000..3230e2adb870 --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h @@ -0,0 +1,65 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef MODULES_INC_MOD_STATS_H_ +#define MODULES_INC_MOD_STATS_H_ + +#include "dm_services.h" + +struct mod_stats { + int dummy; +}; + +struct mod_stats_caps { + bool dummy; +}; + +struct mod_stats *mod_stats_create(struct dc *dc); + +void mod_stats_destroy(struct mod_stats *mod_stats); + +bool mod_stats_init(struct mod_stats *mod_stats); + +void mod_stats_dump(struct mod_stats *mod_stats); + +void mod_stats_reset_data(struct mod_stats *mod_stats); + +void mod_stats_update_flip(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns); + +void mod_stats_update_vupdate(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns); + +void mod_stats_update_freesync(struct mod_stats *mod_stats, + unsigned int v_total_min, + unsigned int v_total_max, + unsigned int event_triggers, + unsigned int window_min, + unsigned int window_max, + unsigned int lfc_mid_point_in_us, + unsigned int inserted_frames, + unsigned int inserted_frame_duration_in_us); + +#endif /* MODULES_INC_MOD_STATS_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/stats/stats.c b/drivers/gpu/drm/amd/display/modules/stats/stats.c new file mode 100644 index 000000000000..041f87b73d5f --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/stats/stats.c @@ -0,0 +1,334 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "mod_stats.h" +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" + +#define DAL_STATS_ENABLE_REGKEY "DalStatsEnable" +#define DAL_STATS_ENABLE_REGKEY_DEFAULT 0x00000001 +#define DAL_STATS_ENABLE_REGKEY_ENABLED 0x00000001 + +#define DAL_STATS_ENTRIES_REGKEY "DalStatsEntries" +#define DAL_STATS_ENTRIES_REGKEY_DEFAULT 0x00350000 +#define DAL_STATS_ENTRIES_REGKEY_MAX 0x01000000 + +#define MOD_STATS_NUM_VSYNCS 5 + +struct stats_time_cache { + unsigned long flip_timestamp_in_ns; + unsigned long vupdate_timestamp_in_ns; + + unsigned int render_time_in_us; + unsigned int avg_render_time_in_us_last_ten; + unsigned int v_sync_time_in_us[MOD_STATS_NUM_VSYNCS]; + unsigned int num_vsync_between_flips; + + unsigned int flip_to_vsync_time_in_us; + unsigned int vsync_to_flip_time_in_us; + + unsigned int min_window; + unsigned int max_window; + unsigned int v_total_min; + unsigned int v_total_max; + unsigned int event_triggers; + + unsigned int lfc_mid_point_in_us; + unsigned int num_frames_inserted; + unsigned int inserted_duration_in_us; + + unsigned int flags; +}; + +struct core_stats { + struct mod_stats public; + struct dc *dc; + + struct stats_time_cache *time; + unsigned int index; + + bool enabled; + unsigned int entries; +}; + +#define MOD_STATS_TO_CORE(mod_stats)\ + container_of(mod_stats, struct core_stats, public) + +bool mod_stats_init(struct mod_stats *mod_stats) +{ + bool result = false; + struct core_stats *core_stats = NULL; + struct dc *dc = NULL; + + if (mod_stats == NULL) + return false; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + dc = core_stats->dc; + + return result; +} + +struct mod_stats *mod_stats_create(struct dc *dc) +{ + struct core_stats *core_stats = NULL; + struct persistent_data_flag flag; + unsigned int reg_data; + int i = 0; + + core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL); + + if (core_stats == NULL) + goto fail_alloc_context; + + if (dc == NULL) + goto fail_construct; + + core_stats->dc = dc; + + core_stats->enabled = DAL_STATS_ENABLE_REGKEY_DEFAULT; + if (dm_read_persistent_data(dc->ctx, NULL, NULL, + DAL_STATS_ENABLE_REGKEY, + ®_data, sizeof(unsigned int), &flag)) + core_stats->enabled = reg_data; + + core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT; + if (dm_read_persistent_data(dc->ctx, NULL, NULL, + DAL_STATS_ENTRIES_REGKEY, + ®_data, sizeof(unsigned int), &flag)) { + if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX) + core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX; + else + core_stats->entries = reg_data; + } + + core_stats->time = kzalloc(sizeof(struct stats_time_cache) * core_stats->entries, + GFP_KERNEL); + + if (core_stats->time == NULL) + goto fail_construct; + + /* Purposely leave index 0 unused so we don't need special logic to + * handle calculation cases that depend on previous flip data. + */ + core_stats->index = 1; + + return &core_stats->public; + +fail_construct: + kfree(core_stats); + +fail_alloc_context: + return NULL; +} + +void mod_stats_destroy(struct mod_stats *mod_stats) +{ + if (mod_stats != NULL) { + struct core_stats *core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->time != NULL) + kfree(core_stats->time); + + kfree(core_stats); + } +} + +void mod_stats_dump(struct mod_stats *mod_stats) +{ + struct dc *dc = NULL; + struct dal_logger *logger = NULL; + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + dc = core_stats->dc; + logger = dc->ctx->logger; + time = core_stats->time; + + //LogEntry* pLog = GetLog()->Open(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); + + //if (!pLog->IsDummyEntry()) + { + dm_logger_write(logger, LOG_PROFILING, "==Display Caps==\n"); + dm_logger_write(logger, LOG_PROFILING, "\n"); + dm_logger_write(logger, LOG_PROFILING, "\n"); + + dm_logger_write(logger, LOG_PROFILING, "==Stats==\n"); + dm_logger_write(logger, LOG_PROFILING, + "render avgRender minWindow midPoint maxWindow vsyncToFlip flipToVsync #vsyncBetweenFlip #frame insertDuration vTotalMin vTotalMax eventTrigs vSyncTime1 vSyncTime2 vSyncTime3 vSyncTime4 vSyncTime5 flags\n"); + + for (int i = 0; i < core_stats->index && i < core_stats->entries; i++) { + dm_logger_write(logger, LOG_PROFILING, + "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n", + time[i].render_time_in_us, + time[i].avg_render_time_in_us_last_ten, + time[i].min_window, + time[i].lfc_mid_point_in_us, + time[i].max_window, + time[i].vsync_to_flip_time_in_us, + time[i].flip_to_vsync_time_in_us, + time[i].num_vsync_between_flips, + time[i].num_frames_inserted, + time[i].inserted_duration_in_us, + time[i].v_total_min, + time[i].v_total_max, + time[i].event_triggers, + time[i].v_sync_time_in_us[0], + time[i].v_sync_time_in_us[1], + time[i].v_sync_time_in_us[2], + time[i].v_sync_time_in_us[3], + time[i].v_sync_time_in_us[4], + time[i].flags); + } + } + //GetLog()->Close(pLog); + //GetLog()->UnSetLogMask(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); +} + +void mod_stats_reset_data(struct mod_stats *mod_stats) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + memset(core_stats->time, 0, + sizeof(struct stats_time_cache) * core_stats->entries); + + core_stats->index = 0; +} + +void mod_stats_update_flip(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->index >= core_stats->entries) + return; + + time = core_stats->time; + index = core_stats->index; + + time[index].flip_timestamp_in_ns = timestamp_in_ns; + time[index].render_time_in_us = + timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; + + if (index >= 10) { + for (unsigned int i = 0; i < 10; i++) + time[index].avg_render_time_in_us_last_ten += + time[index - i].render_time_in_us; + time[index].avg_render_time_in_us_last_ten /= 10; + } + + if (time[index].num_vsync_between_flips > 0) + time[index].vsync_to_flip_time_in_us = + timestamp_in_ns - time[index].vupdate_timestamp_in_ns; + else + time[index].vsync_to_flip_time_in_us = + timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; + + core_stats->index++; +} + +void mod_stats_update_vupdate(struct mod_stats *mod_stats, + unsigned long timestamp_in_ns) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->index >= core_stats->entries) + return; + + time = core_stats->time; + index = core_stats->index; + + time[index].vupdate_timestamp_in_ns = timestamp_in_ns; + if (time[index].num_vsync_between_flips < MOD_STATS_NUM_VSYNCS) + time[index].v_sync_time_in_us[time[index].num_vsync_between_flips] = + timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; + time[index].flip_to_vsync_time_in_us = + timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; + + time[index].num_vsync_between_flips++; +} + +void mod_stats_update_freesync(struct mod_stats *mod_stats, + unsigned int v_total_min, + unsigned int v_total_max, + unsigned int event_triggers, + unsigned int window_min, + unsigned int window_max, + unsigned int lfc_mid_point_in_us, + unsigned int inserted_frames, + unsigned int inserted_duration_in_us) +{ + struct core_stats *core_stats = NULL; + struct stats_time_cache *time = NULL; + unsigned int index = 0; + + if (mod_stats == NULL) + return; + + core_stats = MOD_STATS_TO_CORE(mod_stats); + + if (core_stats->index >= core_stats->entries) + return; + + time = core_stats->time; + index = core_stats->index; + + time[index].v_total_min = v_total_min; + time[index].v_total_max = v_total_max; + time[index].event_triggers = event_triggers; + time[index].min_window = window_min; + time[index].max_window = window_max; + time[index].lfc_mid_point_in_us = lfc_mid_point_in_us; + time[index].num_frames_inserted = inserted_frames; + time[index].inserted_duration_in_us = inserted_duration_in_us; +} + |