Display mode lib handles clock, watermark, and bandwidth calculations for DCN. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1282 lines
40 KiB
C
1282 lines
40 KiB
C
/*
|
|
* 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"
|
|
|
|
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;
|
|
}
|