summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dml/display_watermark.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dml/display_watermark.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_watermark.c1282
1 files changed, 1282 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_watermark.c b/drivers/gpu/drm/amd/display/dc/dml/display_watermark.c
new file mode 100644
index 000000000000..142a3284ac44
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_watermark.c
@@ -0,0 +1,1282 @@
+/*
+ * Copyright 2017 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 "display_watermark.h"
+#include "display_mode_lib.h"
+#include "dml_inline_defs.h"
+
+static void get_bytes_per_pixel(
+ enum source_format_class format,
+ struct _vcs_dpi_wm_calc_pipe_params_st *plane)
+{
+ switch (format) {
+ case dm_444_64:
+ plane->bytes_per_pixel_y = 8.0;
+ plane->bytes_per_pixel_c = 0.0;
+ break;
+ case dm_444_32:
+ plane->bytes_per_pixel_y = 4.0;
+ plane->bytes_per_pixel_c = 0.0;
+ break;
+ case dm_444_16:
+ plane->bytes_per_pixel_y = 2.0;
+ plane->bytes_per_pixel_c = 0.0;
+ break;
+ case dm_422_10:
+ plane->bytes_per_pixel_y = 4.0;
+ plane->bytes_per_pixel_c = 0.0;
+ break;
+ case dm_422_8:
+ plane->bytes_per_pixel_y = 2.0;
+ plane->bytes_per_pixel_c = 0.0;
+ break;
+ case dm_420_8:
+ plane->bytes_per_pixel_y = 1.0;
+ plane->bytes_per_pixel_c = 2.0;
+ break;
+ case dm_420_10:
+ plane->bytes_per_pixel_y = 4.0 / 3;
+ plane->bytes_per_pixel_c = 8.0 / 3;
+ break;
+ default:
+ BREAK_TO_DEBUGGER(); /* invalid format in get_bytes_per_pixel */
+ }
+}
+
+static unsigned int get_swath_width_y(
+ struct _vcs_dpi_display_pipe_source_params_st *src_param,
+ unsigned int num_dpp)
+{
+ unsigned int val;
+
+ /* note that we don't divide by num_dpp here because we have an interface which has already split
+ * any viewports
+ */
+ if (src_param->source_scan == dm_horz) {
+ val = src_param->viewport_width;
+ } else {
+ val = src_param->viewport_height;
+ }
+
+ return val;
+}
+
+static void get_swath_height(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_pipe_source_params_st *src_param,
+ struct _vcs_dpi_wm_calc_pipe_params_st *plane,
+ unsigned int swath_width_y)
+{
+ double buffer_width;
+
+ if (src_param->source_format == dm_444_64 || src_param->source_format == dm_444_32
+ || src_param->source_format == dm_444_16) {
+ if (src_param->sw_mode == dm_sw_linear) {
+ plane->swath_height_y = 1;
+ } else if (src_param->source_format == dm_444_64) {
+ plane->swath_height_y = 4;
+ } else {
+ plane->swath_height_y = 8;
+ }
+
+ if (src_param->source_scan != dm_horz) {
+ plane->swath_height_y = 256 / (unsigned int) plane->bytes_per_pixel_y
+ / plane->swath_height_y;
+ }
+
+ plane->swath_height_c = 0;
+
+ } else {
+ if (src_param->sw_mode == dm_sw_linear) {
+ plane->swath_height_y = 1;
+ plane->swath_height_c = 1;
+ } else if (src_param->source_format == dm_420_8) {
+ plane->swath_height_y = 16;
+ plane->swath_height_c = 8;
+ } else {
+ plane->swath_height_y = 8;
+ plane->swath_height_c = 8;
+ }
+
+ if (src_param->source_scan != dm_horz) {
+ double bytes_per_pixel_c_ceil;
+
+ plane->swath_height_y = 256 / dml_ceil(plane->bytes_per_pixel_y)
+ / plane->swath_height_y;
+
+ bytes_per_pixel_c_ceil = dml_ceil_2(plane->bytes_per_pixel_c);
+
+ plane->swath_height_c = 256 / bytes_per_pixel_c_ceil
+ / plane->swath_height_c;
+ }
+ }
+
+ /* use swath height min if buffer isn't big enough */
+
+ buffer_width = ((double) mode_lib->ip.det_buffer_size_kbytes * 1024.0 / 2.0)
+ / (plane->bytes_per_pixel_y * (double) plane->swath_height_y
+ + (plane->bytes_per_pixel_c / 2.0
+ * (double) plane->swath_height_c));
+
+ if ((double) swath_width_y <= buffer_width) {
+ /* do nothing, just keep code structure from Gabes vba */
+ } else {
+ /* substitute swath height with swath height min */
+ if (src_param->source_format == dm_444_64 || src_param->source_format == dm_444_32
+ || src_param->source_format == dm_444_16) {
+ if ((src_param->sw_mode == dm_sw_linear)
+ || (src_param->source_format == dm_444_64
+ && (src_param->sw_mode == dm_sw_4kb_s
+ || src_param->sw_mode
+ == dm_sw_4kb_s_x
+ || src_param->sw_mode
+ == dm_sw_64kb_s
+ || src_param->sw_mode
+ == dm_sw_64kb_s_t
+ || src_param->sw_mode
+ == dm_sw_64kb_s_x
+ || src_param->sw_mode
+ == dm_sw_var_s
+ || src_param->sw_mode
+ == dm_sw_var_s_x)
+ && src_param->source_scan == dm_horz)) {
+ /* do nothing, just keep code structure from Gabes vba */
+ } else {
+ plane->swath_height_y = plane->swath_height_y / 2;
+ }
+ } else {
+ if (src_param->sw_mode == dm_sw_linear) {
+ /* do nothing, just keep code structure from Gabes vba */
+ } else if (src_param->source_format == dm_420_8
+ && src_param->source_scan == dm_horz) {
+ plane->swath_height_y = plane->swath_height_y / 2;
+ } else if (src_param->source_format == dm_420_10
+ && src_param->source_scan == dm_horz) {
+ plane->swath_height_c = plane->swath_height_c / 2;
+ }
+ }
+ }
+
+ if (plane->swath_height_c == 0) {
+ plane->det_buffer_size_y = mode_lib->ip.det_buffer_size_kbytes * 1024.0;
+ } else if (plane->swath_height_c <= plane->swath_height_y) {
+ plane->det_buffer_size_y = mode_lib->ip.det_buffer_size_kbytes * 1024.0 / 2.0;
+ } else {
+ plane->det_buffer_size_y = mode_lib->ip.det_buffer_size_kbytes * 1024.0 * 2.0 / 3.0;
+ }
+}
+
+static void calc_display_pipe_line_delivery_time(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_planes; i++) {
+ if (planes[i].v_ratio <= 1.0) {
+ planes[i].display_pipe_line_delivery_time = planes[i].swath_width_y
+ * planes[i].num_dpp / planes[i].h_ratio
+ / planes[i].pixclk_mhz;
+ } else {
+ double dchub_pscl_bw_per_clk;
+
+ if (planes[i].h_ratio > 1) {
+ double num_hscl_kernels;
+
+ num_hscl_kernels = dml_ceil((double) planes[i].h_taps / 6);
+ dchub_pscl_bw_per_clk =
+ dml_min(
+ (double) mode_lib->ip.max_dchub_pscl_bw_pix_per_clk,
+ mode_lib->ip.max_pscl_lb_bw_pix_per_clk
+ * planes[i].h_ratio
+ / num_hscl_kernels);
+ } else {
+ dchub_pscl_bw_per_clk =
+ dml_min(
+ (double) mode_lib->ip.max_dchub_pscl_bw_pix_per_clk,
+ (double) mode_lib->ip.max_pscl_lb_bw_pix_per_clk);
+ }
+
+ planes[i].display_pipe_line_delivery_time = planes[i].swath_width_y
+ / dchub_pscl_bw_per_clk / planes[i].dppclk_mhz;
+ }
+ }
+}
+
+static double calc_total_data_read_bw(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ double val = 0.0;
+ unsigned int i;
+
+ for (i = 0; i < num_planes; i++) {
+ double swath_width_y_plane = planes[i].swath_width_y * planes[i].num_dpp;
+
+ planes[i].read_bw = swath_width_y_plane
+ * (dml_ceil(planes[i].bytes_per_pixel_y)
+ + dml_ceil_2(planes[i].bytes_per_pixel_c) / 2)
+ / (planes[i].h_total / planes[i].pixclk_mhz) * planes[i].v_ratio;
+
+ val += planes[i].read_bw;
+
+ DTRACE("plane[%d] start", i);
+ DTRACE("read_bw = %f", planes[i].read_bw);
+ DTRACE("plane[%d] end", i);
+ }
+
+ return val;
+}
+
+double dml_wm_calc_total_data_read_bw(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ return calc_total_data_read_bw(mode_lib, planes, num_planes);
+}
+
+static double calc_dcfclk_mhz(
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ double dcfclk_mhz = -1.0;
+ unsigned int i;
+
+ for (i = 0; i < num_planes; i++) {
+ /* voltage and dcfclk must be the same for all pipes */
+ ASSERT(dcfclk_mhz == -1.0 || dcfclk_mhz == planes[i].dcfclk_mhz);
+ dcfclk_mhz = planes[i].dcfclk_mhz;
+ }
+
+ return dcfclk_mhz;
+}
+
+static enum voltage_state find_voltage(
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ int voltage = -1;
+ unsigned int i;
+
+ for (i = 0; i < num_planes; i++) {
+ ASSERT(voltage == -1 || voltage == planes[i].voltage);
+ voltage = planes[i].voltage;
+ }
+
+ return (enum voltage_state) voltage;
+}
+
+static bool find_dcc_enable(struct _vcs_dpi_wm_calc_pipe_params_st *planes, unsigned int num_planes)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_planes; i++) {
+ if (planes[i].dcc_enable) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static double calc_return_bw(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ struct _vcs_dpi_soc_bounding_box_st *soc;
+ double return_bw_mbps;
+ double dcfclk_mhz;
+ double return_bus_bw;
+ enum voltage_state voltage;
+ double return_bw_to_dcn;
+ bool dcc_enable;
+ double rob_chunk_diff;
+ double urgent_latency_traffic;
+ double critical_compression;
+ struct _vcs_dpi_voltage_scaling_st state;
+
+ soc = &mode_lib->soc;
+
+ dcfclk_mhz = calc_dcfclk_mhz(planes, num_planes);
+ return_bus_bw = dcfclk_mhz * soc->return_bus_width_bytes;
+
+ DTRACE("INTERMEDIATE dcfclk_mhz = %f", dcfclk_mhz);
+ DTRACE("INTERMEDIATE return_bus_bw = %f", return_bus_bw);
+
+ voltage = find_voltage(planes, num_planes);
+ return_bw_to_dcn = dml_socbb_return_bw_mhz(soc, voltage);
+
+ dcc_enable = find_dcc_enable(planes, num_planes);
+
+ return_bw_mbps = return_bw_to_dcn;
+ DTRACE("INTERMEDIATE return_bw_mbps = %f", return_bw_mbps);
+
+ rob_chunk_diff =
+ (mode_lib->ip.rob_buffer_size_kbytes - mode_lib->ip.pixel_chunk_size_kbytes)
+ * 1024.0;
+ DTRACE("INTERMEDIATE rob_chunk_diff = %f", rob_chunk_diff);
+
+ if (dcc_enable && return_bw_to_dcn > return_bus_bw / 4) {
+ double dcc_return_bw =
+ return_bw_to_dcn * 4.0
+ * (1.0
+ - soc->urgent_latency_us
+ / (rob_chunk_diff
+ / (return_bw_to_dcn
+ - return_bus_bw
+ / 4.0)
+ + soc->urgent_latency_us));
+ return_bw_mbps = dml_min(return_bw_mbps, dcc_return_bw);
+ DTRACE("INTERMEDIATE dcc_return_bw = %f", dcc_return_bw);
+ }
+
+ urgent_latency_traffic = return_bus_bw * soc->urgent_latency_us;
+ DTRACE("INTERMEDIATE urgent_latency_traffic = %f", urgent_latency_traffic);
+ critical_compression = 2.0 * urgent_latency_traffic
+ / (return_bw_to_dcn * soc->urgent_latency_us + rob_chunk_diff);
+ DTRACE("INTERMEDIATE critical_compression = %f", critical_compression);
+
+ if (dcc_enable && critical_compression > 1.0 && critical_compression < 4.0) {
+ double crit_return_bw = (4 * return_bw_to_dcn * rob_chunk_diff
+ * urgent_latency_traffic);
+ crit_return_bw = crit_return_bw
+ / dml_pow(
+ return_bw_to_dcn * soc->urgent_latency_us
+ + rob_chunk_diff,
+ 2);
+ DTRACE("INTERMEDIATE critical_return_bw = %f", crit_return_bw);
+ return_bw_mbps = dml_min(return_bw_mbps, crit_return_bw);
+ }
+
+ /* Gabe does this again for some reason using the value of return_bw_mpbs from the previous calculation
+ * and a lightly different return_bw_to_dcn
+ */
+
+ state = dml_socbb_voltage_scaling(soc, voltage);
+ return_bw_to_dcn = dml_min(
+ soc->return_bus_width_bytes * dcfclk_mhz,
+ state.dram_bw_per_chan_gbps * 1000.0 * (double) soc->num_chans);
+
+ DTRACE("INTERMEDIATE rob_chunk_diff = %f", rob_chunk_diff);
+
+ if (dcc_enable && return_bw_to_dcn > return_bus_bw / 4) {
+ double dcc_return_bw =
+ return_bw_to_dcn * 4.0
+ * (1.0
+ - soc->urgent_latency_us
+ / (rob_chunk_diff
+ / (return_bw_to_dcn
+ - return_bus_bw
+ / 4.0)
+ + soc->urgent_latency_us));
+ return_bw_mbps = dml_min(return_bw_mbps, dcc_return_bw);
+ DTRACE("INTERMEDIATE dcc_return_bw = %f", dcc_return_bw);
+ }
+
+ urgent_latency_traffic = return_bus_bw * soc->urgent_latency_us;
+ DTRACE("INTERMEDIATE urgent_latency_traffic = %f", urgent_latency_traffic);
+ critical_compression = 2.0 * urgent_latency_traffic
+ / (return_bw_to_dcn * soc->urgent_latency_us + rob_chunk_diff);
+ DTRACE("INTERMEDIATE critical_compression = %f", critical_compression);
+
+ /* problem here? */
+ if (dcc_enable && critical_compression > 1.0 && critical_compression < 4.0) {
+ double crit_return_bw = (4 * return_bw_to_dcn * rob_chunk_diff
+ * urgent_latency_traffic);
+ crit_return_bw = crit_return_bw
+ / dml_pow(
+ return_bw_to_dcn * soc->urgent_latency_us
+ + rob_chunk_diff,
+ 2);
+ DTRACE("INTERMEDIATE critical_return_bw = %f", crit_return_bw);
+ DTRACE("INTERMEDIATE return_bw_to_dcn = %f", return_bw_to_dcn);
+ DTRACE("INTERMEDIATE rob_chunk_diff = %f", rob_chunk_diff);
+ DTRACE("INTERMEDIATE urgent_latency_traffic = %f", urgent_latency_traffic);
+
+ return_bw_mbps = dml_min(return_bw_mbps, crit_return_bw);
+ }
+
+ DTRACE("INTERMEDIATE final return_bw_mbps = %f", return_bw_mbps);
+ return return_bw_mbps;
+}
+
+double dml_wm_calc_return_bw(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ return calc_return_bw(mode_lib, planes, num_planes);
+}
+
+static double calc_last_pixel_of_line_extra_wm_us(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ double val = 0.0;
+ double total_data_read_bw = calc_total_data_read_bw(mode_lib, planes, num_planes);
+ int voltage = -1;
+ unsigned int i;
+ double return_bw_mbps;
+
+ for (i = 0; i < num_planes; i++) {
+ /* voltage mode must be the same for all pipes */
+ ASSERT(voltage == -1 || voltage == planes[i].voltage);
+ voltage = planes[i].voltage;
+ }
+ return_bw_mbps = calc_return_bw(mode_lib, planes, num_planes);
+
+ for (i = 0; i < num_planes; i++) {
+ double bytes_pp_y = dml_ceil(planes[i].bytes_per_pixel_y);
+ double bytes_pp_c = dml_ceil_2(planes[i].bytes_per_pixel_c);
+ double swath_bytes_y = (double) planes[i].swath_width_y
+ * (double) planes[i].swath_height_y * (double) bytes_pp_y;
+ double swath_bytes_c = ((double) planes[i].swath_width_y / 2.0)
+ * (double) planes[i].swath_height_c * (double) bytes_pp_c;
+ double data_fabric_line_delivery_time = (swath_bytes_y + swath_bytes_c)
+ / (return_bw_mbps * planes[i].read_bw / (double) planes[i].num_dpp
+ / total_data_read_bw);
+
+ DTRACE(
+ "bytes_pp_y = %f, swath_width_y = %f, swath_height_y = %f, swath_bytes_y = %f",
+ bytes_pp_y,
+ (double) planes[i].swath_width_y,
+ (double) planes[i].swath_height_y,
+ swath_bytes_y);
+ DTRACE(
+ "bytes_pp_c = %f, swath_width_c = %f, swath_height_c = %f, swath_bytes_c = %f",
+ bytes_pp_c,
+ ((double) planes[i].swath_width_y / 2.0),
+ (double) planes[i].swath_height_c,
+ swath_bytes_c);
+ DTRACE(
+ "return_bw_mbps = %f, read_bw = %f, num_dpp = %d, total_data_read_bw = %f",
+ return_bw_mbps,
+ planes[i].read_bw,
+ planes[i].num_dpp,
+ total_data_read_bw);
+ DTRACE("data_fabric_line_delivery_time = %f", data_fabric_line_delivery_time);
+ DTRACE(
+ "display_pipe_line_delivery_time = %f",
+ planes[i].display_pipe_line_delivery_time);
+
+ val = dml_max(
+ val,
+ data_fabric_line_delivery_time
+ - planes[i].display_pipe_line_delivery_time);
+ }
+
+ DTRACE("last_pixel_of_line_extra_wm is %f us", val);
+ return val;
+}
+
+static bool calc_pte_enable(struct _vcs_dpi_wm_calc_pipe_params_st *planes, unsigned int num_planes)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_planes; i++) {
+ if (planes[i].pte_enable) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void calc_lines_in_det_y(struct _vcs_dpi_wm_calc_pipe_params_st *plane)
+{
+ plane->lines_in_det_y = plane->det_buffer_size_y / plane->bytes_per_pixel_y
+ / plane->swath_width_y;
+ plane->lines_in_det_y_rounded_down_to_swath = dml_floor(
+ (double) plane->lines_in_det_y / plane->swath_height_y)
+ * plane->swath_height_y;
+ plane->full_det_buffering_time = plane->lines_in_det_y_rounded_down_to_swath
+ * (plane->h_total / plane->pixclk_mhz);
+}
+
+/* CHECKME: not obviously 1:1 with calculation described in architectural
+ * document or spreadsheet */
+static void calc_dcfclk_deepsleep_mhz_per_plane(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *plane)
+{
+ double bus_width_per_pixel;
+
+ if (plane->swath_height_c == 0) {
+ bus_width_per_pixel = dml_ceil(plane->bytes_per_pixel_y) / 64;
+ } else {
+ double bus_width_per_pixel_c;
+
+ bus_width_per_pixel = dml_ceil(plane->bytes_per_pixel_y) / 32;
+ bus_width_per_pixel_c = dml_ceil(plane->bytes_per_pixel_c) / 32;
+ if (bus_width_per_pixel < bus_width_per_pixel_c)
+ bus_width_per_pixel = bus_width_per_pixel_c;
+ }
+
+ if (plane->v_ratio <= 1) {
+ plane->dcfclk_deepsleep_mhz_per_plane = 1.1 * plane->pixclk_mhz / plane->num_dpp
+ * plane->h_ratio * bus_width_per_pixel;
+ } else if (plane->h_ratio > 1) {
+ double num_hscl_kernels = dml_ceil((double) plane->h_taps / 6);
+ double dchub_pscl_bw_per_clk = dml_min(
+ (double) mode_lib->ip.max_dchub_pscl_bw_pix_per_clk,
+ mode_lib->ip.max_pscl_lb_bw_pix_per_clk * plane->h_ratio
+ / num_hscl_kernels);
+
+ plane->dcfclk_deepsleep_mhz_per_plane = 1.1 * plane->dppclk_mhz
+ * dchub_pscl_bw_per_clk * bus_width_per_pixel;
+ } else {
+ double dchub_pscl_bw_per_clk = dml_min(
+ (double) mode_lib->ip.max_dchub_pscl_bw_pix_per_clk,
+ (double) mode_lib->ip.max_pscl_lb_bw_pix_per_clk);
+
+ plane->dcfclk_deepsleep_mhz_per_plane = 1.1 * plane->dppclk_mhz
+ * dchub_pscl_bw_per_clk * bus_width_per_pixel;
+ }
+
+ plane->dcfclk_deepsleep_mhz_per_plane = dml_max(
+ plane->dcfclk_deepsleep_mhz_per_plane,
+ plane->pixclk_mhz / 16);
+}
+
+/* Implementation of expected stutter efficiency from DCN1_Display_Mode.docx */
+double dml_wm_expected_stutter_eff_e2e(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_e2e_pipe_params_st *e2e,
+ unsigned int num_pipes)
+{
+ double min_full_det_buffering_time_us;
+ double frame_time_for_min_full_det_buffering_time_us = 0.0;
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes = mode_lib->wm_param;
+ unsigned int num_planes;
+ unsigned int i;
+ double total_data_read_bw_mbps;
+ double average_read_bw_gbps;
+ double min_full_det_buffer_size_bytes;
+ double rob_fill_size_bytes;
+ double part_of_burst_that_fits_in_rob;
+ int voltage;
+ double dcfclk_mhz;
+ unsigned int total_writeback;
+ double return_bw_mbps;
+ double stutter_burst_time_us;
+ double stutter_eff_not_including_vblank;
+ double smallest_vblank_us;
+ double stutter_eff;
+
+ memset(mode_lib->wm_param, 0, sizeof(mode_lib->wm_param));
+ DTRACE("calculating expected stutter efficiency");
+
+ num_planes = dml_wm_e2e_to_wm(mode_lib, e2e, num_pipes, planes);
+
+ for (i = 0; i < num_planes; i++) {
+ calc_lines_in_det_y(&planes[i]);
+
+ DTRACE("swath width y plane %d = %d", i, planes[i].swath_width_y);
+ DTRACE("swath height y plane %d = %d", i, planes[i].swath_height_y);
+ DTRACE(
+ "bytes per pixel det y plane %d = %f",
+ i,
+ planes[i].bytes_per_pixel_y);
+ DTRACE(
+ "bytes per pixel det c plane %d = %f",
+ i,
+ planes[i].bytes_per_pixel_c);
+ DTRACE(
+ "det buffer size plane %d = %d",
+ i,
+ planes[i].det_buffer_size_y);
+ DTRACE("lines in det plane %d = %d", i, planes[i].lines_in_det_y);
+ DTRACE(
+ "lines in det rounded to swaths plane %d = %d",
+ i,
+ planes[i].lines_in_det_y_rounded_down_to_swath);
+ }
+
+ min_full_det_buffering_time_us = 9999.0;
+ for (i = 0; i < num_planes; i++) {
+ if (planes[i].full_det_buffering_time < min_full_det_buffering_time_us) {
+ min_full_det_buffering_time_us = planes[i].full_det_buffering_time;
+ frame_time_for_min_full_det_buffering_time_us = (double) planes[i].v_total
+ * planes[i].h_total / planes[i].pixclk_mhz;
+ }
+ }
+
+ DTRACE("INTERMEDIATE: min_full_det_buffering_time_us = %f", min_full_det_buffering_time_us);
+
+ total_data_read_bw_mbps = calc_total_data_read_bw(mode_lib, planes, num_planes);
+
+ average_read_bw_gbps = 0.0;
+
+ for (i = 0; i < num_planes; i++) {
+ if (planes[i].dcc_enable) {
+ average_read_bw_gbps += planes[i].read_bw / planes[i].dcc_rate / 1000;
+ } else {
+ average_read_bw_gbps += planes[i].read_bw / 1000;
+ }
+
+ if (planes[i].dcc_enable) {
+ average_read_bw_gbps += planes[i].read_bw / 1000 / 256;
+ }
+
+ if (planes[i].pte_enable) {
+ average_read_bw_gbps += planes[i].read_bw / 1000 / 512;
+ }
+ }
+
+ min_full_det_buffer_size_bytes = min_full_det_buffering_time_us * total_data_read_bw_mbps;
+ rob_fill_size_bytes = mode_lib->ip.rob_buffer_size_kbytes * 1024 * total_data_read_bw_mbps
+ / (average_read_bw_gbps * 1000);
+ part_of_burst_that_fits_in_rob = dml_min(
+ min_full_det_buffer_size_bytes,
+ rob_fill_size_bytes);
+
+ voltage = -1;
+ dcfclk_mhz = -1.0;
+ total_writeback = 0;
+
+ for (i = 0; i < num_pipes; i++) {
+ /* voltage and dcfclk must be the same for all pipes */
+ ASSERT(voltage == -1 || voltage == e2e[i].clks_cfg.voltage);
+ voltage = e2e[i].clks_cfg.voltage;
+ ASSERT(dcfclk_mhz == -1.0 || dcfclk_mhz == e2e[i].clks_cfg.dcfclk_mhz);
+ dcfclk_mhz = e2e[i].clks_cfg.dcfclk_mhz;
+
+ if (e2e[i].dout.output_type == dm_wb)
+ total_writeback++;
+ }
+
+ return_bw_mbps = calc_return_bw(mode_lib, planes, num_planes);
+
+ DTRACE("INTERMEDIATE: part_of_burst_that_fits_in_rob = %f", part_of_burst_that_fits_in_rob);
+ DTRACE("INTERMEDIATE: average_read_bw_gbps = %f", average_read_bw_gbps);
+ DTRACE("INTERMEDIATE: total_data_read_bw_mbps = %f", total_data_read_bw_mbps);
+ DTRACE("INTERMEDIATE: return_bw_mbps = %f", return_bw_mbps);
+
+ stutter_burst_time_us = part_of_burst_that_fits_in_rob * (average_read_bw_gbps * 1000)
+ / total_data_read_bw_mbps / return_bw_mbps
+ + (min_full_det_buffering_time_us * total_data_read_bw_mbps
+ - part_of_burst_that_fits_in_rob) / (dcfclk_mhz * 64);
+ DTRACE("INTERMEDIATE: stutter_burst_time_us = %f", stutter_burst_time_us);
+
+ if (total_writeback == 0) {
+ stutter_eff_not_including_vblank = (1.0
+ - ((mode_lib->soc.sr_exit_time_us + stutter_burst_time_us)
+ / min_full_det_buffering_time_us)) * 100.0;
+ } else {
+ stutter_eff_not_including_vblank = 0.0;
+ }
+
+ DTRACE("stutter_efficiency_not_including_vblank = %f", stutter_eff_not_including_vblank);
+
+ smallest_vblank_us = 9999.0;
+
+ for (i = 0; i < num_pipes; i++) {
+ double vblank_us;
+ if (e2e[i].pipe.dest.syncronized_vblank_all_planes != 0 || num_pipes == 1) {
+ vblank_us = (double) (e2e[i].pipe.dest.vtotal + 1
+ - e2e[i].pipe.dest.vblank_start
+ + e2e[i].pipe.dest.vblank_end * e2e[i].pipe.dest.htotal)
+ / e2e[i].pipe.dest.pixel_rate_mhz;
+ } else {
+ vblank_us = 0.0;
+ }
+
+ smallest_vblank_us = dml_min(smallest_vblank_us, vblank_us);
+ }
+
+ DTRACE("smallest vblank = %f us", smallest_vblank_us);
+
+ stutter_eff = 100.0
+ * (((stutter_eff_not_including_vblank / 100.0)
+ * (frame_time_for_min_full_det_buffering_time_us
+ - smallest_vblank_us) + smallest_vblank_us)
+ / frame_time_for_min_full_det_buffering_time_us);
+
+ DTRACE("stutter_efficiency = %f", stutter_eff);
+
+ return stutter_eff_not_including_vblank;
+}
+
+double dml_wm_expected_stutter_eff_e2e_with_vblank(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_e2e_pipe_params_st *e2e,
+ unsigned int num_pipes)
+{
+ double min_full_det_buffering_time_us;
+ double frame_time_for_min_full_det_buffering_time_us = 0.0;
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes = mode_lib->wm_param;
+ unsigned int num_planes;
+ unsigned int i;
+ double total_data_read_bw_mbps;
+ double average_read_bw_gbps;
+ double min_full_det_buffer_size_bytes;
+ double rob_fill_size_bytes;
+ double part_of_burst_that_fits_in_rob;
+ int voltage;
+ double dcfclk_mhz;
+ unsigned int total_writeback;
+ double return_bw_mbps;
+ double stutter_burst_time_us;
+ double stutter_eff_not_including_vblank;
+ double smallest_vblank_us;
+ double stutter_eff;
+
+ memset(mode_lib->wm_param, 0, sizeof(mode_lib->wm_param));
+ num_planes = dml_wm_e2e_to_wm(mode_lib, e2e, num_pipes, planes);
+
+ for (i = 0; i < num_planes; i++) {
+ calc_lines_in_det_y(&planes[i]);
+ }
+
+ min_full_det_buffering_time_us = 9999.0;
+ for (i = 0; i < num_planes; i++) {
+ if (planes[i].full_det_buffering_time < min_full_det_buffering_time_us) {
+ min_full_det_buffering_time_us = planes[i].full_det_buffering_time;
+ frame_time_for_min_full_det_buffering_time_us = (double) planes[i].v_total
+ * planes[i].h_total / planes[i].pixclk_mhz;
+ }
+ }
+
+ total_data_read_bw_mbps = calc_total_data_read_bw(mode_lib, planes, num_planes);
+ average_read_bw_gbps = 0.0;
+
+ for (i = 0; i < num_planes; i++) {
+ if (planes[i].dcc_enable) {
+ average_read_bw_gbps += planes[i].read_bw / planes[i].dcc_rate / 1000;
+ } else {
+ average_read_bw_gbps += planes[i].read_bw / 1000;
+ }
+
+ if (planes[i].dcc_enable) {
+ average_read_bw_gbps += planes[i].read_bw / 1000 / 256;
+ }
+
+ if (planes[i].pte_enable) {
+ average_read_bw_gbps += planes[i].read_bw / 1000 / 512;
+ }
+ }
+
+ min_full_det_buffer_size_bytes = min_full_det_buffering_time_us * total_data_read_bw_mbps;
+ rob_fill_size_bytes = mode_lib->ip.rob_buffer_size_kbytes * 1024 * total_data_read_bw_mbps
+ / (average_read_bw_gbps * 1000);
+ part_of_burst_that_fits_in_rob = dml_min(
+ min_full_det_buffer_size_bytes,
+ rob_fill_size_bytes);
+
+ voltage = -1;
+ dcfclk_mhz = -1.0;
+ total_writeback = 0;
+
+ for (i = 0; i < num_pipes; i++) {
+ /* voltage and dcfclk must be the same for all pipes */
+ ASSERT(voltage == -1 || voltage == e2e[i].clks_cfg.voltage);
+ voltage = e2e[i].clks_cfg.voltage;
+ ASSERT(dcfclk_mhz == -1.0 || dcfclk_mhz == e2e[i].clks_cfg.dcfclk_mhz);
+ dcfclk_mhz = e2e[i].clks_cfg.dcfclk_mhz;
+
+ if (e2e[i].dout.output_type == dm_wb)
+ total_writeback++;
+ }
+
+ return_bw_mbps = calc_return_bw(mode_lib, planes, num_planes);
+
+ stutter_burst_time_us = part_of_burst_that_fits_in_rob * (average_read_bw_gbps * 1000)
+ / total_data_read_bw_mbps / return_bw_mbps
+ + (min_full_det_buffering_time_us * total_data_read_bw_mbps
+ - part_of_burst_that_fits_in_rob) / (dcfclk_mhz * 64);
+
+ if (total_writeback == 0) {
+ stutter_eff_not_including_vblank = (1.0
+ - ((mode_lib->soc.sr_exit_time_us + stutter_burst_time_us)
+ / min_full_det_buffering_time_us)) * 100.0;
+ } else {
+ stutter_eff_not_including_vblank = 0.0;
+ }
+
+ smallest_vblank_us = 9999.0;
+
+ for (i = 0; i < num_pipes; i++) {
+ double vblank_us;
+ if (e2e[i].pipe.dest.syncronized_vblank_all_planes != 0 || num_pipes == 1) {
+ vblank_us = (double) (e2e[i].pipe.dest.vtotal + 1
+ - e2e[i].pipe.dest.vblank_start
+ + e2e[i].pipe.dest.vblank_end * e2e[i].pipe.dest.htotal)
+ / e2e[i].pipe.dest.pixel_rate_mhz;
+ } else {
+ vblank_us = 0.0;
+ }
+
+ smallest_vblank_us = dml_min(smallest_vblank_us, vblank_us);
+ }
+
+ stutter_eff = 100.0
+ * (((stutter_eff_not_including_vblank / 100.0)
+ * (frame_time_for_min_full_det_buffering_time_us
+ - smallest_vblank_us) + smallest_vblank_us)
+ / frame_time_for_min_full_det_buffering_time_us);
+
+
+ return stutter_eff;
+}
+
+double urgent_extra_calc(
+ struct display_mode_lib *mode_lib,
+ double dcfclk_mhz,
+ double return_bw_mbps,
+ unsigned int total_active_dpp,
+ unsigned int total_dcc_active_dpp)
+{
+ double urgent_extra_latency_us = 0.0;
+ double urgent_round_trip_ooo_latency_us;
+
+ urgent_round_trip_ooo_latency_us =
+ (((double) mode_lib->soc.round_trip_ping_latency_dcfclk_cycles + 32)
+ / dcfclk_mhz)
+ + (((double) (mode_lib->soc.urgent_out_of_order_return_per_channel_bytes
+ * mode_lib->soc.num_chans)) / return_bw_mbps);
+
+ DTRACE(
+ "INTERMEDIATE round_trip_ping_latency_dcfclk_cycles = %d",
+ mode_lib->soc.round_trip_ping_latency_dcfclk_cycles);
+ DTRACE("INTERMEDIATE dcfclk_mhz = %f", dcfclk_mhz);
+ DTRACE(
+ "INTERMEDIATE urgent_out_of_order_return_per_channel_bytes = %d",
+ mode_lib->soc.urgent_out_of_order_return_per_channel_bytes);
+
+ urgent_extra_latency_us = urgent_round_trip_ooo_latency_us
+ + ((double) total_active_dpp * mode_lib->ip.pixel_chunk_size_kbytes
+ + (double) total_dcc_active_dpp
+ * mode_lib->ip.meta_chunk_size_kbytes)
+ * 1024.0 / return_bw_mbps; /* to us */
+
+ DTRACE(
+ "INTERMEDIATE urgent_round_trip_ooo_latency_us = %f",
+ urgent_round_trip_ooo_latency_us);
+ DTRACE("INTERMEDIATE total_active_dpp = %d", total_active_dpp);
+ DTRACE(
+ "INTERMEDIATE pixel_chunk_size_kbytes = %d",
+ mode_lib->ip.pixel_chunk_size_kbytes);
+ DTRACE("INTERMEDIATE total_dcc_active_dpp = %d", total_dcc_active_dpp);
+ DTRACE(
+ "INTERMEDIATE meta_chunk_size_kbyte = %d",
+ mode_lib->ip.meta_chunk_size_kbytes);
+ DTRACE("INTERMEDIATE return_bw_mbps = %f", return_bw_mbps);
+
+ return urgent_extra_latency_us;
+}
+
+double dml_wm_urgent_extra_max(struct display_mode_lib *mode_lib)
+{
+ unsigned int total_active_dpp = DC__NUM_DPP;
+ unsigned int total_dcc_active_dpp = total_active_dpp;
+ double urgent_extra_latency_us = 0.0;
+ double dcfclk_mhz = 0.0;
+ double return_bw_mbps = 0.0;
+ int voltage = dm_vmin;
+
+ /* use minimum voltage */
+ return_bw_mbps = dml_socbb_return_bw_mhz(&mode_lib->soc, (enum voltage_state) voltage);
+ /* use minimum dcfclk */
+ dcfclk_mhz = mode_lib->soc.vmin.dcfclk_mhz;
+ /* use max dpps and dpps with dcc */
+
+ urgent_extra_latency_us = urgent_extra_calc(
+ mode_lib,
+ dcfclk_mhz,
+ return_bw_mbps,
+ total_active_dpp,
+ total_dcc_active_dpp);
+
+ DTRACE("urgent extra max = %f", urgent_extra_latency_us);
+ return urgent_extra_latency_us;
+}
+
+double dml_wm_urgent_extra(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *pipes,
+ unsigned int num_pipes)
+{
+ unsigned int total_active_dpp = 0;
+ unsigned int total_dcc_active_dpp = 0;
+ double urgent_extra_latency_us = 0.0;
+ double dcfclk_mhz = 0.0;
+ double return_bw_mbps = 0.0;
+ int voltage = -1;
+ bool pte_enable = false;
+ unsigned int i;
+
+ for (i = 0; i < num_pipes; i++) {
+ /* num_dpp must be greater than 0 */
+ ASSERT(pipes[i].num_dpp > 0);
+
+ /* voltage mode must be the same for all pipes */
+ ASSERT(voltage == -1 || voltage == pipes[i].voltage);
+ voltage = pipes[i].voltage;
+
+ /* dcfclk for all pipes must be the same */
+ ASSERT(dcfclk_mhz == 0.0 || dcfclk_mhz == pipes[i].dcfclk_mhz);
+ dcfclk_mhz = pipes[i].dcfclk_mhz;
+
+ total_active_dpp += pipes[i].num_dpp;
+
+ if (pipes[i].dcc_enable) {
+ total_dcc_active_dpp += pipes[i].num_dpp;
+ }
+ }
+
+ DTRACE("total active dpps %d", total_active_dpp);
+ DTRACE("total active dpps with dcc %d", total_dcc_active_dpp);
+ DTRACE("voltage state is %d", voltage);
+
+ return_bw_mbps = calc_return_bw(mode_lib, pipes, num_pipes);
+
+ DTRACE("return_bandwidth is %f MBps", return_bw_mbps);
+
+ pte_enable = calc_pte_enable(pipes, num_pipes);
+
+ /* calculate the maximum extra latency just for comparison purposes */
+ /* dml_wm_urgent_extra_max(); */
+ urgent_extra_latency_us = urgent_extra_calc(
+ mode_lib,
+ dcfclk_mhz,
+ return_bw_mbps,
+ total_active_dpp,
+ total_dcc_active_dpp);
+
+ DTRACE("INTERMEDIATE urgent_extra_latency_us_before_pte = %f", urgent_extra_latency_us);
+
+ if (pte_enable) {
+ urgent_extra_latency_us += total_active_dpp * mode_lib->ip.pte_chunk_size_kbytes
+ * 1024.0 / return_bw_mbps;
+
+ DTRACE("INTERMEDIATE pte_enable = true");
+ DTRACE("INTERMEDIATE total_active_dpp = %d", total_active_dpp);
+ DTRACE(
+ "INTERMEDIATE pte_chunk_size_kbytes = %d",
+ mode_lib->ip.pte_chunk_size_kbytes);
+ DTRACE("INTERMEDIATE return_bw_mbps = %f", return_bw_mbps);
+ }
+
+ return urgent_extra_latency_us;
+}
+
+double dml_wm_urgent_e2e(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_e2e_pipe_params_st *pipes,
+ unsigned int num_pipes)
+{
+ struct _vcs_dpi_wm_calc_pipe_params_st *wm = mode_lib->wm_param;
+ unsigned int combined_pipes;
+ double urgent_wm;
+
+ memset(mode_lib->wm_param, 0, sizeof(mode_lib->wm_param));
+ combined_pipes = dml_wm_e2e_to_wm(mode_lib, pipes, num_pipes, wm);
+
+ urgent_wm = dml_wm_urgent(mode_lib, wm, combined_pipes);
+
+ return urgent_wm;
+}
+
+double dml_wm_urgent(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ double urgent_watermark;
+ double urgent_extra_latency_us;
+ double last_pixel_of_line_extra_wm_us = 0.0;
+
+ DTRACE("calculating urgent watermark");
+ calc_display_pipe_line_delivery_time(mode_lib, planes, num_planes);
+ urgent_extra_latency_us = dml_wm_urgent_extra(mode_lib, planes, num_planes);
+
+ last_pixel_of_line_extra_wm_us = calc_last_pixel_of_line_extra_wm_us(
+ mode_lib,
+ planes,
+ num_planes);
+
+ urgent_watermark = mode_lib->soc.urgent_latency_us + last_pixel_of_line_extra_wm_us
+ + urgent_extra_latency_us;
+
+ DTRACE("INTERMEDIATE urgent_latency_us = %f", mode_lib->soc.urgent_latency_us);
+ DTRACE("INTERMEDIATE last_pixel_of_line_extra_wm_us = %f", last_pixel_of_line_extra_wm_us);
+ DTRACE("INTERMEDIATE urgent_extra_latency_us = %f", urgent_extra_latency_us);
+
+ DTRACE("urgent_watermark_us = %f", urgent_watermark);
+ return urgent_watermark;
+}
+
+double dml_wm_pte_meta_urgent(struct display_mode_lib *mode_lib, double urgent_wm_us)
+{
+ double val;
+
+ val = urgent_wm_us + 2.0 * mode_lib->soc.urgent_latency_us;
+ DTRACE("pte_meta_urgent_watermark_us = %f", val);
+
+ return val;
+}
+
+double dml_wm_dcfclk_deepsleep_mhz_e2e(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_e2e_pipe_params_st *pipes,
+ unsigned int num_pipes)
+{
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes = mode_lib->wm_param;
+ unsigned int num_planes;
+ double val;
+
+ memset(mode_lib->wm_param, 0, sizeof(mode_lib->wm_param));
+ num_planes = dml_wm_e2e_to_wm(mode_lib, pipes, num_pipes, planes);
+
+ val = dml_wm_dcfclk_deepsleep_mhz(mode_lib, planes, num_planes);
+
+ return val;
+}
+
+double dml_wm_dcfclk_deepsleep_mhz(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *planes,
+ unsigned int num_planes)
+{
+ double val = 8.0;
+ unsigned int i;
+
+ for (i = 0; i < num_planes; i++) {
+ calc_dcfclk_deepsleep_mhz_per_plane(mode_lib, &planes[i]);
+
+ if (val < planes[i].dcfclk_deepsleep_mhz_per_plane) {
+ val = planes[i].dcfclk_deepsleep_mhz_per_plane;
+ }
+
+ DTRACE("plane[%d] start", i);
+ DTRACE("dcfclk_deepsleep_per_plane = %f", planes[i].dcfclk_deepsleep_mhz_per_plane);
+ DTRACE("plane[%d] end", i);
+ }
+
+ DTRACE("dcfclk_deepsleep_mhz = %f", val);
+
+ return val;
+}
+
+struct _vcs_dpi_cstate_pstate_watermarks_st dml_wm_cstate_pstate_e2e(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_e2e_pipe_params_st *pipes,
+ unsigned int num_pipes)
+{
+ struct _vcs_dpi_wm_calc_pipe_params_st *wm = mode_lib->wm_param;
+ unsigned int combined_pipes;
+ struct _vcs_dpi_cstate_pstate_watermarks_st cstate_pstate_wm;
+
+ memset(mode_lib->wm_param, 0, sizeof(mode_lib->wm_param));
+ combined_pipes = dml_wm_e2e_to_wm(mode_lib, pipes, num_pipes, wm);
+ cstate_pstate_wm = dml_wm_cstate_pstate(mode_lib, wm, combined_pipes);
+
+
+ return cstate_pstate_wm;
+}
+
+struct _vcs_dpi_cstate_pstate_watermarks_st dml_wm_cstate_pstate(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *pipes,
+ unsigned int num_pipes)
+{
+ struct _vcs_dpi_cstate_pstate_watermarks_st wm;
+ double urgent_extra_latency_us;
+ double urgent_watermark_us;
+ double last_pixel_of_line_extra_wm_us;
+ double dcfclk_deepsleep_freq;
+
+ DTRACE("calculating cstate and pstate watermarks");
+ urgent_extra_latency_us = dml_wm_urgent_extra(mode_lib, pipes, num_pipes);
+ urgent_watermark_us = dml_wm_urgent(mode_lib, pipes, num_pipes);
+
+ last_pixel_of_line_extra_wm_us = calc_last_pixel_of_line_extra_wm_us(
+ mode_lib,
+ pipes,
+ num_pipes);
+ dcfclk_deepsleep_freq = dml_wm_dcfclk_deepsleep_mhz(mode_lib, pipes, num_pipes);
+
+ wm.cstate_exit_us = mode_lib->soc.sr_exit_time_us + last_pixel_of_line_extra_wm_us
+ + urgent_extra_latency_us
+ + mode_lib->ip.dcfclk_cstate_latency / dcfclk_deepsleep_freq;
+ wm.cstate_enter_plus_exit_us = mode_lib->soc.sr_enter_plus_exit_time_us
+ + last_pixel_of_line_extra_wm_us + urgent_extra_latency_us;
+ wm.pstate_change_us = mode_lib->soc.dram_clock_change_latency_us + urgent_watermark_us;
+
+ DTRACE("stutter_exit_watermark_us = %f", wm.cstate_exit_us);
+ DTRACE("stutter_enter_plus_exit_watermark_us = %f", wm.cstate_enter_plus_exit_us);
+ DTRACE("dram_clock_change_watermark_us = %f", wm.pstate_change_us);
+
+ return wm;
+}
+
+double dml_wm_writeback_pstate_e2e(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_e2e_pipe_params_st *pipes,
+ unsigned int num_pipes)
+{
+ struct _vcs_dpi_wm_calc_pipe_params_st *wm = mode_lib->wm_param;
+ unsigned int combined_pipes;
+
+ memset(mode_lib->wm_param, 0, sizeof(mode_lib->wm_param));
+ combined_pipes = dml_wm_e2e_to_wm(mode_lib, pipes, num_pipes, wm);
+
+
+ return dml_wm_writeback_pstate(mode_lib, wm, combined_pipes);
+}
+
+double dml_wm_writeback_pstate(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_wm_calc_pipe_params_st *pipes,
+ unsigned int num_pipes)
+{
+ unsigned int total_active_wb = 0;
+ double wm = 0.0;
+ double socclk_mhz = 0.0;
+ unsigned int i;
+
+ DTRACE("calculating wb pstate watermark");
+ for (i = 0; i < num_pipes; i++) {
+ if (pipes[i].output_type == dm_wb)
+ total_active_wb++;
+ ASSERT(socclk_mhz == 0.0 || socclk_mhz == pipes[i].socclk_mhz);
+ socclk_mhz = pipes[i].socclk_mhz;
+ }
+
+ DTRACE("total wb outputs %d", total_active_wb);
+ DTRACE("socclk frequency %f Mhz", socclk_mhz);
+
+ if (total_active_wb <= 1) {
+ wm = mode_lib->soc.writeback_dram_clock_change_latency_us;
+ } else {
+ wm = mode_lib->soc.writeback_dram_clock_change_latency_us
+ + (mode_lib->ip.writeback_chunk_size_kbytes * 1024.0) / 32.0
+ / socclk_mhz;
+ }
+
+ DTRACE("wb pstate watermark %f us", wm);
+ return wm;
+}
+
+unsigned int dml_wm_e2e_to_wm(
+ struct display_mode_lib *mode_lib,
+ struct _vcs_dpi_display_e2e_pipe_params_st *e2e,
+ unsigned int num_pipes,
+ struct _vcs_dpi_wm_calc_pipe_params_st *wm)
+{
+ unsigned int num_planes = 0;
+ bool visited[DC__NUM_PIPES];
+ unsigned int i, j;
+
+ for (i = 0; i < num_pipes; i++) {
+ visited[i] = false;
+ }
+
+ for (i = 0; i < num_pipes; i++) {
+ unsigned int num_dpp = 1;
+
+ if (visited[i]) {
+ continue;
+ }
+
+ visited[i] = true;
+
+ if (e2e[i].pipe.src.is_hsplit) {
+ for (j = i + 1; j < num_pipes; j++) {
+ if (e2e[j].pipe.src.is_hsplit && !visited[j]
+ && (e2e[i].pipe.src.hsplit_grp
+ == e2e[j].pipe.src.hsplit_grp)) {
+ num_dpp++;
+ visited[j] = true;
+ }
+ }
+ }
+
+ wm[num_planes].num_dpp = num_dpp;
+ wm[num_planes].voltage = e2e[i].clks_cfg.voltage;
+ wm[num_planes].output_type = e2e[i].dout.output_type;
+ wm[num_planes].dcfclk_mhz = e2e[i].clks_cfg.dcfclk_mhz;
+ wm[num_planes].socclk_mhz = e2e[i].clks_cfg.socclk_mhz;
+ wm[num_planes].dppclk_mhz = e2e[i].clks_cfg.dppclk_mhz;
+ wm[num_planes].pixclk_mhz = e2e[i].pipe.dest.pixel_rate_mhz;
+
+ wm[num_planes].pte_enable = e2e[i].pipe.src.vm;
+ wm[num_planes].dcc_enable = e2e[i].pipe.src.dcc;
+ wm[num_planes].dcc_rate = e2e[i].pipe.src.dcc_rate;
+
+ get_bytes_per_pixel(
+ (enum source_format_class) e2e[i].pipe.src.source_format,
+ &wm[num_planes]);
+ wm[num_planes].swath_width_y = get_swath_width_y(&e2e[i].pipe.src, num_dpp);
+ get_swath_height(
+ mode_lib,
+ &e2e[i].pipe.src,
+ &wm[num_planes],
+ wm[num_planes].swath_width_y);
+
+ wm[num_planes].interlace_en = e2e[i].pipe.dest.interlaced;
+ wm[num_planes].h_ratio = e2e[i].pipe.scale_ratio_depth.hscl_ratio;
+ wm[num_planes].v_ratio = e2e[i].pipe.scale_ratio_depth.vscl_ratio;
+ if (wm[num_planes].interlace_en) {
+ wm[num_planes].v_ratio = 2 * wm[num_planes].v_ratio;
+ }
+ wm[num_planes].h_taps = e2e[i].pipe.scale_taps.htaps;
+ wm[num_planes].h_total = e2e[i].pipe.dest.htotal;
+ wm[num_planes].v_total = e2e[i].pipe.dest.vtotal;
+ wm[num_planes].v_active = e2e[i].pipe.dest.vactive;
+ wm[num_planes].e2e_index = i;
+ num_planes++;
+ }
+
+ for (i = 0; i < num_planes; i++) {
+ DTRACE("plane[%d] start", i);
+ DTRACE("voltage = %d", wm[i].voltage);
+ DTRACE("v_active = %d", wm[i].v_active);
+ DTRACE("h_total = %d", wm[i].h_total);
+ DTRACE("v_total = %d", wm[i].v_total);
+ DTRACE("pixclk_mhz = %f", wm[i].pixclk_mhz);
+ DTRACE("dcfclk_mhz = %f", wm[i].dcfclk_mhz);
+ DTRACE("dppclk_mhz = %f", wm[i].dppclk_mhz);
+ DTRACE("h_ratio = %f", wm[i].h_ratio);
+ DTRACE("v_ratio = %f", wm[i].v_ratio);
+ DTRACE("interlaced = %d", wm[i].interlace_en);
+ DTRACE("h_taps = %d", wm[i].h_taps);
+ DTRACE("num_dpp = %d", wm[i].num_dpp);
+ DTRACE("swath_width_y = %d", wm[i].swath_width_y);
+ DTRACE("swath_height_y = %d", wm[i].swath_height_y);
+ DTRACE("swath_height_c = %d", wm[i].swath_height_c);
+ DTRACE("det_buffer_size_y = %d", wm[i].det_buffer_size_y);
+ DTRACE("dcc_rate = %f", wm[i].dcc_rate);
+ DTRACE("dcc_enable = %s", wm[i].dcc_enable ? "true" : "false");
+ DTRACE("pte_enable = %s", wm[i].pte_enable ? "true" : "false");
+ DTRACE("plane[%d] end", i);
+ }
+
+ return num_planes;
+}