The below patches add support for data flow metering as mentioned in the section 6.5.6 FRL data flow metering of HDMI 2.1 specification.
Add functions to calclulate the DFM parameters for the given frl config, which is further used to evaluate the data flow metering requirement as specified in the spec.
As per the spec the below patches implement the frl capacity computation functions for both compressed and uncompressed video. Finally exposing 1 function each for compressed and uncompressed video to figure out if the data flow metering requirement is met or not.
v2: Changed u32 to unsigned int, corrected patch 4 to address build issue, addressed checkpatch issues, moved the drm_frl_dfm_helper under kms_helpers section for compilation in the Makefile.
Ankit Nautiyal (1): drm/hdmi21: Add support for DFM calculation with DSC
Vandita Kulkarni (4): drm/hdmi21: Define frl_dfm structure drm/hdmi21: Add non dsc frl capacity computation helpers drm/hdmi21: Add helpers to verify non-dsc DFM requirements drm/hdmi21: Add frl_dfm_helper to Makefile
drivers/gpu/drm/Makefile | 4 +- drivers/gpu/drm/drm_frl_dfm_helper.c | 854 +++++++++++++++++++++++++++ include/drm/drm_frl_dfm_helper.h | 129 ++++ 3 files changed, 986 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_frl_dfm_helper.c create mode 100644 include/drm/drm_frl_dfm_helper.h
Define frl_dfm structure to hold frl characteristics needed for frl capacity computation in order to meet the data flow metering requirement.
Signed-off-by: Vandita Kulkarni vandita.kulkarni@intel.com --- include/drm/drm_frl_dfm_helper.h | 124 +++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 include/drm/drm_frl_dfm_helper.h
diff --git a/include/drm/drm_frl_dfm_helper.h b/include/drm/drm_frl_dfm_helper.h new file mode 100644 index 000000000000..5cab102fe25f --- /dev/null +++ b/include/drm/drm_frl_dfm_helper.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: MIT + * Copyright © 2022 Intel Corp + */ + +#ifndef DRM_FRL_DFM_H_ +#define DRM_FRL_DFM_H_ + +/* DFM constraints and tolerance values from HDMI2.1 spec */ +#define TB_BORROWED_MAX 400 +#define FRL_CHAR_PER_CHAR_BLK 510 +/* Tolerance pixel clock unit is in mHz */ +#define TOLERANCE_PIXEL_CLOCK 5 +#define TOLERANCE_FRL_BIT_RATE 300 +#define TOLERANCE_AUDIO_CLOCK 1000 +#define ACR_RATE_MAX 1500 +#define EFFICIENCY_MULTIPLIER 1000 +#define OVERHEAD_M (3 * EFFICIENCY_MULTIPLIER / 1000) +#define BPP_MULTIPLIER 16 +#define FRL_TIMING_NS_MULTIPLIER 1000000000 + +/* ALl the input config needed to compute DFM requirements */ +struct drm_frl_dfm_input_config { + /* + * Pixel clock rate kHz, when FVA is + * enabled this rate is the rate after adjustment + */ + unsigned int pixel_clock_nominal_khz; + + /* active pixels per line */ + unsigned int hactive; + + /* Blanking pixels per line */ + unsigned int hblank; + + /* Bits per component */ + unsigned int bpc; + + /* Pixel encoding */ + unsigned int color_format; + + /* FRL bit rate in kbps */ + unsigned int bit_rate_kbps; + + /* FRL lanes */ + unsigned int lanes; + + /* Number of audio channels */ + unsigned int audio_channels; + + /* Audio rate in Hz */ + unsigned int audio_hz; + + /* Selected bpp target value */ + unsigned int target_bpp_16; + + /* + * Number of horizontal pixels in a slice. + * Equivalent to PPS parameter slice_width + */ + unsigned int slice_width; +}; + +/* Computed dfm parameters as per the HDMI2.1 spec */ +struct drm_frl_dfm_params { + /* + * Link overhead in percentage + * multiplied by 1000 (efficiency multiplier) + */ + unsigned int overhead_max; + + /* Maximum pixel rate in kHz */ + unsigned int pixel_clock_max_khz; + + /* Minimum video line period in nano sec */ + unsigned int line_time_ns; + + /* worst case slow frl character rate in kbps */ + unsigned int char_rate_min_kbps; + + /* minimum total frl charecters per line perios */ + unsigned int cfrl_line; + + /* Average tribyte rate in khz */ + unsigned int ftb_avg_k; + + /* Audio characteristics */ + + /* number of audio packets needed during hblank */ + unsigned int num_audio_pkts_line; + + /* + * Minimum required hblank assuming no control preiod + * RC compression + */ + unsigned int hblank_audio_min; + + /* Number of tribytes required to carry active video */ + unsigned int tb_active; + + /* Total available tribytes during the blanking period */ + unsigned int tb_blank; + + /* + * Number of tribytes required to be transmitted during + * the hblank period + */ + unsigned int tb_borrowed; + + /* DSC frl characteristics */ + + /* Tribytes required to carry the target bpp */ + unsigned int hcactive_target; + + /* tribytes available during blanking with target bpp */ + unsigned int hcblank_target; +}; + +/* FRL DFM structure to hold involved in DFM computation */ +struct drm_hdmi_frl_dfm { + struct drm_frl_dfm_input_config config; + struct drm_frl_dfm_params params; +}; + +#endif
Add helper functions for computing non dsc frl link characteristics
Signed-off-by: Vandita Kulkarni vandita.kulkarni@intel.com --- drivers/gpu/drm/drm_frl_dfm_helper.c | 396 +++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 drivers/gpu/drm/drm_frl_dfm_helper.c
diff --git a/drivers/gpu/drm/drm_frl_dfm_helper.c b/drivers/gpu/drm/drm_frl_dfm_helper.c new file mode 100644 index 000000000000..d3ae35653370 --- /dev/null +++ b/drivers/gpu/drm/drm_frl_dfm_helper.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corp + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <drm/drm_frl_dfm_helper.h> +#include <drm/drm_connector.h> + +/* Total frl charecters per super block */ +static unsigned int drm_get_frl_char_per_super_blk(unsigned int lanes) +{ + unsigned int frl_char_per_sb; + + frl_char_per_sb = (4 * FRL_CHAR_PER_CHAR_BLK) + lanes; + return frl_char_per_sb; +} + +/* + * Determine the overhead due to the inclusion of + * the SR and SSB FRL charecters used for + * super block framing + */ +static unsigned int drm_get_overhead_super_blk(unsigned int lanes) +{ + return (lanes * EFFICIENCY_MULTIPLIER) / drm_get_frl_char_per_super_blk(lanes); +} + +/* + * Determine the overhead due to the inclusion of RS FEC pairity + * symbols. Each charecter block uses 8 FRL charecters for RS Pairity + * and there are 4 charecter blocks per super block + */ +static unsigned int drm_get_overhead_rs(unsigned int lanes) +{ + return (8 * 4 * EFFICIENCY_MULTIPLIER) / drm_get_frl_char_per_super_blk(lanes); +} + +/* Determine the overhead due to FRL Map charecters. + * In a bandwidth constrained application, the FRL packets will be long, + * there will typically be two FRL Map Charecters per Super Block most of the time. + * When a tracnsition occurs between Hactive and Hblank (uncomperssed video) or + * HCactive and HCblank (compressed video transport), there may be a + * third FRL Map Charected. Therefore this spec assumes 2.5 FRL Map Charecters + * per Super Block. + */ +static unsigned int drm_get_overhead_frl_map_char(unsigned int lanes) +{ + return (25 * EFFICIENCY_MULTIPLIER) / (10 * drm_get_frl_char_per_super_blk(lanes)); +} + +/* Total minimum overhead multiplied by EFFICIENCY_MULIPLIER */ +static unsigned int drm_get_total_minimum_overhead(unsigned int lanes) +{ + unsigned int total_overhead_min; + unsigned int overhead_sb = drm_get_overhead_super_blk(lanes); + unsigned int overhead_rs = drm_get_overhead_rs(lanes); + unsigned int overhead_map = drm_get_overhead_frl_map_char(lanes); + + total_overhead_min = overhead_sb + overhead_rs + overhead_map; + + return total_overhead_min; +} + +/* + * Additional margin to the overhead is provided to account for the possibility + * of more Map Charecters, zero padding at the end of HCactive, and other minor + * items + */ +static unsigned int drm_get_max_overhead(unsigned int total_overhead_min) +{ + unsigned int total_overhead_max; + + total_overhead_max = total_overhead_min + OVERHEAD_M; + return total_overhead_max; +} + +/* Collect the link charecteristics */ + +/* Determine the maximum legal pixel rate */ +static unsigned int drm_get_max_legal_pixel_rate(unsigned int fpixel_clock_nominal_k) +{ + unsigned int fpixel_clock_max_k = (fpixel_clock_nominal_k * + (1000 + TOLERANCE_PIXEL_CLOCK)) / 1000; + return fpixel_clock_max_k; +} + +/* Determine the minimum Video Line period */ +static unsigned int drm_get_min_video_line_period(unsigned int hactive, unsigned int hblank, + unsigned int fpixel_clock_max_k) +{ + unsigned int line_time_ns; + + line_time_ns = ((hactive + hblank) * FRL_TIMING_NS_MULTIPLIER) / + fpixel_clock_max_k; + return line_time_ns; +} + +/* Determine the worst-case slow FRL Bit Rate in kbps*/ +static unsigned int drm_get_min_frl_bit_rate(unsigned int frl_bit_rate_nominal_k) +{ + unsigned int frl_bit_rate_min_k; + + frl_bit_rate_min_k = (frl_bit_rate_nominal_k / 1000000) * + (1000000 - TOLERANCE_FRL_BIT_RATE); + return frl_bit_rate_min_k; +} + +/* Determine the worst-case slow FRL Charecter Rate */ +static unsigned int drm_get_min_frl_char_rate(unsigned int frl_bit_rate_min_k) +{ + unsigned int frl_char_rate_min_k; + + frl_char_rate_min_k = frl_bit_rate_min_k / 18; + return frl_char_rate_min_k; +} + +/* Determine the Minimum Total FRL charecters per line period */ +static unsigned int +drm_get_total_frl_char_per_line_period(unsigned int line_time_ns, unsigned int frl_char_rate_min_k, + unsigned int lanes) +{ + unsigned int frl_char_per_line_period; + + frl_char_per_line_period = (line_time_ns * frl_char_rate_min_k * lanes * + 1000) / FRL_TIMING_NS_MULTIPLIER; + return frl_char_per_line_period; +} + +/* Audio Support Verification Computations */ + +/* + * Determine Audio Related Packet Rate considering the audio clock + * increased to maximim rate permitted by Tolerance Audio clock + */ +static unsigned int +drm_get_audio_pkt_rate(unsigned int f_audio, unsigned int num_audio_pkt) +{ + unsigned int audio_pkt_rate; + + audio_pkt_rate = ((f_audio * num_audio_pkt + (2 * ACR_RATE_MAX)) * + (1000000 + TOLERANCE_AUDIO_CLOCK)) / 1000000; + return audio_pkt_rate; +} + +/* + * Average required packets per line is + * Number of audio packets needed during Hblank + */ +static unsigned int +drm_get_audio_pkts_hblank(unsigned int audio_pkt_rate, unsigned int line_time_ns) +{ + unsigned int avg_audio_pkts_per_line; + + avg_audio_pkts_per_line = DIV_ROUND_UP(audio_pkt_rate * line_time_ns, + FRL_TIMING_NS_MULTIPLIER); + return avg_audio_pkts_per_line; +} + +/* + * Minimum required Hblank assuming no Control Period RC Compression + * This includes Video Guard band, Two Island Guard bands, two 12 character + * Control Periods and 32 * AudioPackets_Line. + * In addition, 32 character periods are allocated for the transmission of an + * ACR packet + */ +static unsigned int +drm_get_audio_hblank_min(unsigned int audio_pkts_line) +{ + unsigned int hblank_audio_min; + + hblank_audio_min = 32 + 32 * audio_pkts_line; + return hblank_audio_min; +} + +/* + * During the Hblank period, Audio packets (32 frl characters each), + * ACR packets (32 frl characters each), Island guard band (4 total frl characters) + * and Video guard band (3 frl characters) do not benefit from RC compression + * Therefore start by determining the number of Control Characters that maybe + * RC compressible + */ +static unsigned int +drm_get_num_char_rc_compressible(unsigned int color_format, + unsigned int bpc, unsigned int audio_packets_line, unsigned int hblank) +{ + unsigned int cfrl_free; + unsigned int kcd, k420; + + if (color_format == DRM_COLOR_FORMAT_YCBCR420) + k420 = 2; + else + k420 = 1; + + if (color_format == DRM_COLOR_FORMAT_YCBCR422) + kcd = 1; + else + kcd = bpc / 8; + + cfrl_free = max(((hblank * kcd) / k420 - 32 * audio_packets_line - 7), + U32_MIN); + return cfrl_free; +} + +/* + * Determine the actual number of characters made available by + * RC compression + */ +static unsigned int +drm_get_num_char_compression_savings(unsigned int cfrl_free) +{ + /*In order to be conservative, situations are considered where + * maximum RC compression may not be possible. + * Add one character each for RC break caused by: + * • Island Preamble not aligned to the RC Compression + * • Video Preamble not aligned to the RC Compression + * • HSYNC lead edge not aligned to the RC Compression + * • HSYNC trail edge not aligned to the RC Compression + */ + const unsigned int cfrl_margin = 4; + unsigned int cfrl_savings = max(((7 * cfrl_free) / 8) - cfrl_margin, U32_MIN); + return cfrl_savings; +} + +static unsigned int +drm_get_frl_bits_per_pixel(unsigned int color_format, unsigned int bpc) +{ + unsigned int kcd, k420, bpp; + + if (color_format == DRM_COLOR_FORMAT_YCBCR420) + k420 = 2; + else + k420 = 1; + + if (color_format == DRM_COLOR_FORMAT_YCBCR422) + kcd = 1; + else + kcd = bpc / 8; + + bpp = (24 * kcd) / k420; + return bpp; +} + +static unsigned int +drm_get_video_bytes_per_line(unsigned int bpp, unsigned int hactive) +{ + unsigned int bytes_per_line; + + bytes_per_line = (bpp * hactive) / 8; + return bytes_per_line; +} + +/* + * Determine the required number of tribytes to carry active video + * per line + */ +static unsigned int +drm_get_active_video_tribytes_reqd(unsigned int bytes_per_line) +{ + unsigned int tribyte_active; + + tribyte_active = DIV_ROUND_UP(bytes_per_line, 3); + return tribyte_active; +} + +/* Determine the total available tribytes during the blanking period */ +static unsigned int +drm_get_blanking_tribytes_avail(unsigned int color_format, + unsigned int hblank, unsigned int bpc) +{ + unsigned int tribytes_blank; + unsigned int kcd, k420; + + if (color_format == DRM_COLOR_FORMAT_YCBCR420) + k420 = 2; + else + k420 = 1; + + if (color_format == DRM_COLOR_FORMAT_YCBCR422) + kcd = 1; + else + kcd = bpc / 8; + + tribytes_blank = (hblank * kcd) / k420; + return tribytes_blank; +} + +/* Determine the average tribyte rate in kilo tribytes per sec */ +static unsigned int +drm_get_avg_tribyte_rate(unsigned int pixel_clk_max_khz, unsigned int tb_active, unsigned int tb_blank, + unsigned int hactive, unsigned int hblank) +{ + unsigned int ftb_avg_k; + + ftb_avg_k = (pixel_clk_max_khz * (tb_active + tb_blank)) / (hactive + hblank); + return ftb_avg_k; +} + +/* + * Determine the time required to transmit the active portion of the + * minimum possible active line period in the base timing + */ +static unsigned int +drm_get_tactive_ref(unsigned int line_time_ns, unsigned int hblank, unsigned int hactive) +{ + unsigned int tactive_ref_ns; + + tactive_ref_ns = (line_time_ns * hactive) / (hblank + hactive); + return tactive_ref_ns; +} + +/* + * Determine the time required to transmit the Video blanking portion + * of the minimum possible active line period in the base timing + */ +static unsigned int +drm_get_tblank_ref(unsigned int line_time_ns, unsigned int hblank, unsigned int hactive) +{ + unsigned int tblank_ref_ns; + + tblank_ref_ns = (line_time_ns * hactive) / (hblank + hactive); + return tblank_ref_ns; +} + +/* + * Determine the minimum time necessary to transmit the active tribytes + * considering frl bandwidth limitation. + * Given the available bandwidth (i.e after overhead is considered), + * tactive_min represents the amount of time needed to transmit all the + * active data + */ +static unsigned int +drm_get_tactive_min(unsigned int num_lanes, unsigned int tribyte_active, + unsigned int overhead_max_k, unsigned int frl_char_min_rate_k) +{ + unsigned int tactive_min_ns, nr, dr; + + nr = (3 * tribyte_active * FRL_TIMING_NS_MULTIPLIER) / 2; + dr = (num_lanes * frl_char_min_rate_k * 1000 * + (EFFICIENCY_MULTIPLIER - overhead_max_k)) / EFFICIENCY_MULTIPLIER; + tactive_min_ns = nr / dr; + + return tactive_min_ns; +} + +/* + * Determine the minimum time necessary to transmit the video blanking + * tribytes considering frl bandwidth limitations + */ +static unsigned int +drm_get_tblank_min(unsigned int num_lanes, unsigned int tribyte_blank, + unsigned int overhead_max_k, unsigned int frl_char_min_rate_k) +{ + unsigned int tblank_min_ns, nr, dr; + + nr = tribyte_blank * FRL_TIMING_NS_MULTIPLIER; + dr = (num_lanes * frl_char_min_rate_k * 1000 * + (EFFICIENCY_MULTIPLIER - overhead_max_k)) / EFFICIENCY_MULTIPLIER; + tblank_min_ns = nr / dr; + return tblank_min_ns; +} + +/* Determine the disparity in tribytes */ +static unsigned int +drm_get_tribytes_borrowed(unsigned int tborrowed_ns, unsigned int ftb_avg_k) +{ + unsigned int tribytes_borrowed; + + tribytes_borrowed = DIV_ROUND_UP((tborrowed_ns * ftb_avg_k * 1000), + FRL_TIMING_NS_MULTIPLIER); + return tribytes_borrowed; +} + +/* + * Determine the actual number of payload FRL characters required to carry each + * video line + */ +static unsigned int +drm_get_frl_char_payload_actual(unsigned int tribytes_active, unsigned int tribytes_blank, unsigned int cfrl_savings) +{ + unsigned int frl_char_payload_actual; + + frl_char_payload_actual = DIV_ROUND_UP(3 * tribytes_active, 2) + tribytes_blank - cfrl_savings; + return frl_char_payload_actual; +} + +/* Determine the payload utilization of the total number of FRL characters */ +static unsigned int +drm_compute_payload_utilization(unsigned int frl_char_payload_actual, unsigned int frl_char_per_line_period) +{ + unsigned int utilization; + + utilization = (frl_char_payload_actual * EFFICIENCY_MULTIPLIER) / frl_char_per_line_period; + return utilization; +}
Add helpers to compute DFM variables and to verify if the DFM requirements are met or not in non dsc cases.
Signed-off-by: Vandita Kulkarni vandita.kulkarni@intel.com --- drivers/gpu/drm/drm_frl_dfm_helper.c | 161 +++++++++++++++++++++++++++ include/drm/drm_frl_dfm_helper.h | 2 + 2 files changed, 163 insertions(+)
diff --git a/drivers/gpu/drm/drm_frl_dfm_helper.c b/drivers/gpu/drm/drm_frl_dfm_helper.c index d3ae35653370..b8f4f8ee50d3 100644 --- a/drivers/gpu/drm/drm_frl_dfm_helper.c +++ b/drivers/gpu/drm/drm_frl_dfm_helper.c @@ -394,3 +394,164 @@ drm_compute_payload_utilization(unsigned int frl_char_payload_actual, unsigned i utilization = (frl_char_payload_actual * EFFICIENCY_MULTIPLIER) / frl_char_per_line_period; return utilization; } + +/* Collect link characteristics */ +static void +drm_frl_dfm_compute_link_characteristics(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int frl_bit_rate_min_kbps; + + frl_dfm->params.pixel_clock_max_khz = + drm_get_max_legal_pixel_rate(frl_dfm->config.pixel_clock_nominal_khz); + frl_dfm->params.line_time_ns = + drm_get_min_video_line_period(frl_dfm->config.hblank, + frl_dfm->config.hactive, + frl_dfm->params.pixel_clock_max_khz); + frl_bit_rate_min_kbps = drm_get_min_frl_bit_rate(frl_dfm->config.bit_rate_kbps); + frl_dfm->params.char_rate_min_kbps = drm_get_min_frl_char_rate(frl_bit_rate_min_kbps); + frl_dfm->params.cfrl_line = + drm_get_total_frl_char_per_line_period(frl_dfm->params.line_time_ns, + frl_dfm->params.char_rate_min_kbps, + frl_dfm->config.lanes); +} + +/* Determine FRL link overhead */ +static void drm_frl_dfm_compute_max_frl_link_overhead(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int overhead_min; + + overhead_min = drm_get_total_minimum_overhead(frl_dfm->config.lanes); + frl_dfm->params.overhead_max = drm_get_max_overhead(overhead_min); +} + +/* Audio support Verification computations */ +static void +drm_frl_dfm_compute_audio_hblank_min(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int num_audio_pkt, audio_pkt_rate; + + /* + * TBD: get the actual audio pkt type as described in + * table 6.44 of HDMI2.1 spec to find the num_audio_pkt, + * for now assume audio sample packet and audio packet + * layout as 1, resulting in number of audio packets + * required to carry each audio sample or audio frame + * as 1 + */ + num_audio_pkt = 1; + audio_pkt_rate = drm_get_audio_pkt_rate(frl_dfm->config.audio_hz, num_audio_pkt); + frl_dfm->params.num_audio_pkts_line = + drm_get_audio_pkts_hblank(audio_pkt_rate, frl_dfm->params.line_time_ns); + frl_dfm->params.hblank_audio_min = + drm_get_audio_hblank_min(frl_dfm->params.num_audio_pkts_line); +} + +/* + * Determine the number of tribytes required for active video , blanking period + * with the pixel configuration + */ +static void +drm_frl_dfm_compute_tbactive_tbblank(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int bpp, bytes_per_line; + + bpp = drm_get_frl_bits_per_pixel(frl_dfm->config.color_format, frl_dfm->config.bpc); + bytes_per_line = drm_get_video_bytes_per_line(bpp, frl_dfm->config.hactive); + + frl_dfm->params.tb_active = drm_get_active_video_tribytes_reqd(bytes_per_line); + frl_dfm->params.tb_blank = + drm_get_blanking_tribytes_avail(frl_dfm->config.color_format, + frl_dfm->config.hblank, + frl_dfm->config.bpc); +} + +/* Verify the configuration meets the capacity requirements for the FRL configuration*/ +static bool +drm_frl_dfm_verify_frl_capacity_requirement(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int tactive_ref_ns, tblank_ref_ns, tactive_min_ns, tblank_min_ns; + unsigned int tborrowed_ns; + + frl_dfm->params.ftb_avg_k = + drm_get_avg_tribyte_rate(frl_dfm->params.pixel_clock_max_khz, + frl_dfm->params.tb_active, frl_dfm->params.tb_blank, + frl_dfm->config.hactive, frl_dfm->config.hblank); + tactive_ref_ns = drm_get_tactive_ref(frl_dfm->params.line_time_ns, + frl_dfm->config.hblank, + frl_dfm->config.hactive); + tblank_ref_ns = drm_get_tblank_ref(frl_dfm->params.line_time_ns, + frl_dfm->config.hblank, + frl_dfm->config.hactive); + tactive_min_ns = drm_get_tactive_min(frl_dfm->config.lanes, + frl_dfm->params.tb_active, + frl_dfm->params.overhead_max, + frl_dfm->params.char_rate_min_kbps); + tblank_min_ns = drm_get_tblank_min(frl_dfm->config.lanes, + frl_dfm->params.tb_blank, + frl_dfm->params.overhead_max, + frl_dfm->params.char_rate_min_kbps); + + if (tactive_ref_ns >= tactive_min_ns && + tblank_ref_ns >= tblank_min_ns) { + tborrowed_ns = 0; + frl_dfm->params.tb_borrowed = 0; + return true; + } + + if (tactive_ref_ns < tactive_min_ns && + tblank_ref_ns >= tblank_min_ns) { + tborrowed_ns = tactive_min_ns - tactive_ref_ns; + frl_dfm->params.tb_borrowed = drm_get_tribytes_borrowed(tborrowed_ns, + frl_dfm->params.ftb_avg_k); + if (frl_dfm->params.tb_borrowed <= TB_BORROWED_MAX) + return true; + } + + return false; +} + +/* Verify utilization does not exceed capacity */ +static bool +drm_frl_dfm_verify_utilization_possible(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int cfrl_free, cfrl_savings, frl_char_payload_actual; + unsigned int utilization, margin; + + cfrl_free = drm_get_num_char_rc_compressible(frl_dfm->config.color_format, + frl_dfm->config.bpc, + frl_dfm->params.num_audio_pkts_line, + frl_dfm->config.hblank); + cfrl_savings = drm_get_num_char_compression_savings(cfrl_free); + frl_char_payload_actual = drm_get_frl_char_payload_actual(frl_dfm->params.tb_active, + frl_dfm->params.tb_blank, + cfrl_savings); + utilization = drm_compute_payload_utilization(frl_char_payload_actual, + frl_dfm->params.cfrl_line); + + margin = 1000 - (utilization + frl_dfm->params.overhead_max); + + if (margin > 0) + return true; + + return false; +} + +/* Check if DFM requirement is met */ +bool +drm_frl_dfm_nondsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm) +{ + bool frl_capacity_req_met; + + drm_frl_dfm_compute_max_frl_link_overhead(frl_dfm); + drm_frl_dfm_compute_link_characteristics(frl_dfm); + drm_frl_dfm_compute_audio_hblank_min(frl_dfm); + drm_frl_dfm_compute_tbactive_tbblank(frl_dfm); + + frl_capacity_req_met = drm_frl_dfm_verify_frl_capacity_requirement(frl_dfm); + + if (frl_capacity_req_met) + return drm_frl_dfm_verify_utilization_possible(frl_dfm); + + return false; +} +EXPORT_SYMBOL(drm_frl_dfm_nondsc_requirement_met); diff --git a/include/drm/drm_frl_dfm_helper.h b/include/drm/drm_frl_dfm_helper.h index 5cab102fe25f..67f9caebd903 100644 --- a/include/drm/drm_frl_dfm_helper.h +++ b/include/drm/drm_frl_dfm_helper.h @@ -121,4 +121,6 @@ struct drm_hdmi_frl_dfm { struct drm_frl_dfm_params params; };
+bool drm_frl_dfm_nondsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm); + #endif
From: Ankit Nautiyal ankit.k.nautiyal@intel.com
Add helper functions for calculating FRL capacity and DFM requirements with given compressed bpp.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com Signed-off-by: Vandita Kulkarni vandita.kulkarni@intel.com --- drivers/gpu/drm/drm_frl_dfm_helper.c | 297 +++++++++++++++++++++++++++ include/drm/drm_frl_dfm_helper.h | 3 + 2 files changed, 300 insertions(+)
diff --git a/drivers/gpu/drm/drm_frl_dfm_helper.c b/drivers/gpu/drm/drm_frl_dfm_helper.c index b8f4f8ee50d3..9eb91dd4e21e 100644 --- a/drivers/gpu/drm/drm_frl_dfm_helper.c +++ b/drivers/gpu/drm/drm_frl_dfm_helper.c @@ -555,3 +555,300 @@ drm_frl_dfm_nondsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm) return false; } EXPORT_SYMBOL(drm_frl_dfm_nondsc_requirement_met); + +/* DSC DFM functions */ +/* Get FRL Available characters */ +static unsigned int +drm_get_frl_available_chars(unsigned int overhead_max, unsigned int cfrl_line) +{ + unsigned int frl_char_avlb = ((EFFICIENCY_MULTIPLIER - overhead_max) * cfrl_line); + + return frl_char_avlb / EFFICIENCY_MULTIPLIER; +} + +/* Get required no. of tribytes during HCActive */ +static unsigned int +drm_get_frl_hcactive_tb_target(unsigned int dsc_bpp_x16, unsigned int slice_width, unsigned int num_slices) +{ + unsigned int bytes_target; + + bytes_target = num_slices * DIV_ROUND_UP(dsc_bpp_x16 * slice_width, + 8 * BPP_MULTIPLIER); + + return DIV_ROUND_UP(bytes_target, 3); +} + +/* Get required no. of tribytes (estimate1) during HCBlank */ +static unsigned int +drm_get_frl_hcblank_tb_est1_target(unsigned int hcactive_target_tb, + unsigned int hactive, unsigned int hblank) +{ + return DIV_ROUND_UP(hcactive_target_tb * hblank, hactive); +} + +/* Get required no. of tribytes during HCBlank */ +static unsigned int +drm_get_frl_hcblank_tb_target(unsigned int hcactive_target_tb, unsigned int hactive, unsigned int hblank, + unsigned int hcblank_audio_min, unsigned int cfrl_available) +{ + unsigned int hcblank_target_tb1 = drm_get_frl_hcblank_tb_est1_target(hcactive_target_tb, + hactive, hblank); + unsigned int hcblank_target_tb2 = max(hcblank_target_tb1, hcblank_audio_min); + + return 4 * (min(hcblank_target_tb2, + (2 * cfrl_available - 3 * hcactive_target_tb) / 2) / 4); +} + +/* Get the avg no of tribytes sent per sec (Kbps) */ +static unsigned int +drm_frl_dsc_get_ftb_avg(unsigned int hcactive_target_tb, unsigned int hcblank_target_tb, + unsigned int hactive, unsigned int hblank, + unsigned int fpixelclock_max_khz) +{ + return (hcactive_target_tb + hcblank_target_tb) * (fpixelclock_max_khz / (hactive + hblank)); +} + +/* Time to send Active tribytes in nanoseconds */ +static unsigned int +drm_frl_dsc_get_tactive_ref_ns(unsigned int line_time_ns, unsigned int hactive, unsigned int hblank) +{ + return (line_time_ns * hactive) / (hactive + hblank); +} + +/* Time to send Blanking tribytes in nanoseconds */ +static unsigned int +drm_frl_dsc_get_tblank_ref_ns(unsigned int line_time_ns, unsigned int hactive, unsigned int hblank) +{ + return (line_time_ns * hblank) / (hactive + hblank); +} + +/* Get time to send all tribytes in hcactive region in nsec*/ +static unsigned int +drm_frl_dsc_tactive_target_ns(unsigned int frl_lanes, unsigned int hcactive_target_tb, unsigned int ftb_avg_k, + unsigned int min_frl_char_rate_k, unsigned int overhead_max) +{ + unsigned int avg_tribyte_time_ns, tribyte_time_ns; + unsigned int num_chars_hcactive; + unsigned int frl_char_rate_k; + + /* Avg time to transmit all active region tribytes */ + avg_tribyte_time_ns = (hcactive_target_tb * FRL_TIMING_NS_MULTIPLIER) / + (ftb_avg_k * 1000); + + /* + * 2 bytes in active region = 1 FRL characters + * 1 Tribyte in active region = 3/2 FRL characters + */ + + num_chars_hcactive = (hcactive_target_tb * 3) / 2; + + /* + * FRL rate = lanes * frl character rate + * But actual bandwidth wil be less, due to FRL limitations so account + * for the overhead involved. + * FRL rate with overhead = FRL rate * (100 - overhead %) / 100 + */ + frl_char_rate_k = frl_lanes * min_frl_char_rate_k; + frl_char_rate_k = (frl_char_rate_k * (EFFICIENCY_MULTIPLIER - overhead_max)) / + EFFICIENCY_MULTIPLIER; + + /* Time to transmit all characters with FRL limitations */ + tribyte_time_ns = (num_chars_hcactive * FRL_TIMING_NS_MULTIPLIER) / + frl_char_rate_k * 1000; + + return max(avg_tribyte_time_ns, tribyte_time_ns); +} + +/* Get no. of tri bytes borrowed with DSC enabled */ +static unsigned int +drm_frl_get_dsc_tri_bytes_borrowed(unsigned int tactive_target_ns, unsigned int ftb_avg_k, + unsigned int hcactive_target_tb) +{ + return (tactive_target_ns * FRL_TIMING_NS_MULTIPLIER * ftb_avg_k * 1000) - + hcactive_target_tb; +} + +/* Get TBdelta */ +static unsigned int +drm_frl_get_dsc_tri_bytes_delta(unsigned int tactive_target_ns, unsigned int tactive_ref_ns, + unsigned int hcactive_target_tb, unsigned int ftb_avg_k, + unsigned int hactive, unsigned int hblank, unsigned int line_time_ns) +{ + unsigned int tb_delta_limit; + unsigned int tblank_target_ns = line_time_ns - tactive_target_ns; + unsigned int tblank_ref_ns = line_time_ns - tactive_ref_ns; + unsigned int hcblank_target_tb1 = drm_get_frl_hcblank_tb_est1_target(hcactive_target_tb, + hactive, hblank); + + if (tblank_ref_ns < tblank_target_ns) { + tb_delta_limit = (((tactive_ref_ns * FRL_TIMING_NS_MULTIPLIER) - (hcactive_target_tb / (ftb_avg_k * 1000))) * + (hcactive_target_tb + hcblank_target_tb1)) / + (line_time_ns * FRL_TIMING_NS_MULTIPLIER); + } else { + unsigned int _tb_delta_ns; + + if (tactive_target_ns > tactive_ref_ns) + _tb_delta_ns = tactive_target_ns - tactive_ref_ns; + else + _tb_delta_ns = tactive_ref_ns - tactive_target_ns; + tb_delta_limit = (_tb_delta_ns * (hcactive_target_tb + hcblank_target_tb1)) / line_time_ns; + } + + return tb_delta_limit; +} + +/* Compute hcactive and hcblank tribytes for given dsc bpp setting */ +static void +drm_frl_dfm_dsc_compute_tribytes(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int hcactive_target_tb; + unsigned int hcblank_target_tb; + unsigned int cfrl_available; + unsigned int num_slices; + + /* Assert for slice width ?*/ + if (!frl_dfm->config.slice_width) + return; + + num_slices = DIV_ROUND_UP(frl_dfm->config.hactive, frl_dfm->config.slice_width); + + hcactive_target_tb = drm_get_frl_hcactive_tb_target(frl_dfm->config.target_bpp_16, + frl_dfm->config.slice_width, + num_slices); + + cfrl_available = + drm_get_frl_available_chars(frl_dfm->params.overhead_max, + frl_dfm->params.cfrl_line); + + hcblank_target_tb = + drm_get_frl_hcblank_tb_target(hcactive_target_tb, + frl_dfm->config.hactive, + frl_dfm->config.hblank, + frl_dfm->params.hblank_audio_min, + cfrl_available); + + frl_dfm->params.hcactive_target = hcactive_target_tb; + frl_dfm->params.hcblank_target = hcblank_target_tb; +} + +/* Check if audio supported with given dsc bpp and frl bandwidth */ +static bool +drm_frl_dfm_dsc_audio_supported(struct drm_hdmi_frl_dfm *frl_dfm) +{ + return frl_dfm->params.hcblank_target < frl_dfm->params.hblank_audio_min; +} + +/* Is DFM timing requirement is met with DSC */ +static +bool drm_frl_dfm_dsc_is_timing_req_met(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int ftb_avg_k; + unsigned int tactive_ref_ns, tblank_ref_ns, tactive_target_ns, tblank_target_ns; + unsigned int tb_borrowed, tb_delta, tb_worst; + + ftb_avg_k = drm_frl_dsc_get_ftb_avg(frl_dfm->params.hcactive_target, + frl_dfm->params.hcblank_target, + frl_dfm->config.hactive, + frl_dfm->config.hblank, + frl_dfm->params.pixel_clock_max_khz); + + tactive_ref_ns = drm_frl_dsc_get_tactive_ref_ns(frl_dfm->params.line_time_ns, + frl_dfm->config.hactive, + frl_dfm->config.hblank); + + tblank_ref_ns = drm_frl_dsc_get_tblank_ref_ns(frl_dfm->params.line_time_ns, + frl_dfm->config.hactive, + frl_dfm->config.hblank); + + tactive_target_ns = drm_frl_dsc_tactive_target_ns(frl_dfm->config.lanes, + frl_dfm->params.hcactive_target, + ftb_avg_k, + frl_dfm->params.char_rate_min_kbps, + frl_dfm->params.overhead_max); + + tblank_target_ns = frl_dfm->params.line_time_ns - tactive_target_ns; + + tb_borrowed = drm_frl_get_dsc_tri_bytes_borrowed(tactive_target_ns, + ftb_avg_k, + frl_dfm->params.hcactive_target); + + tb_delta = drm_frl_get_dsc_tri_bytes_delta(tactive_target_ns, + tactive_ref_ns, + frl_dfm->params.hcactive_target, + ftb_avg_k, + frl_dfm->config.hactive, + frl_dfm->config.hblank, + frl_dfm->params.line_time_ns); + + tb_worst = max(tb_borrowed, tb_delta); + if (tb_worst > TB_BORROWED_MAX) + return false; + + frl_dfm->params.ftb_avg_k = ftb_avg_k; + frl_dfm->params.tb_borrowed = tb_borrowed; + + return true; +} + +/* Check Utilization constraint with DSC */ +static bool +drm_frl_dsc_check_utilization(struct drm_hdmi_frl_dfm *frl_dfm) +{ + unsigned int hcactive_target_tb = frl_dfm->params.hcactive_target; + unsigned int hcblank_target_tb = frl_dfm->params.hcblank_target; + unsigned int frl_char_per_line = frl_dfm->params.cfrl_line; + unsigned int overhead_max = frl_dfm->params.overhead_max; + unsigned int actual_frl_char_payload; + unsigned int utilization; + unsigned int utilization_with_overhead; + + /* Note: + * 1 FRL characters per 2 bytes in active period + * 1 FRL char per byte in Blanking period + */ + actual_frl_char_payload = DIV_ROUND_UP(3 * hcactive_target_tb, 2) + + hcblank_target_tb; + + utilization = (actual_frl_char_payload * EFFICIENCY_MULTIPLIER) / + frl_char_per_line; + + /* + * Utilization with overhead = utlization% +overhead % + * should be less than 100% + */ + utilization_with_overhead = utilization + overhead_max; + if (utilization_with_overhead > EFFICIENCY_MULTIPLIER) + return false; + + return false; +} + +/* + * drm_frl_fm_dsc_requirement_met : Check if FRL DFM requirements are met with + * the given bpp. + * @frl_dfm: dfm structure + * + * Returns true if the frl dfm requirements are met, else returns false. + */ +bool drm_frl_dfm_dsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm) +{ + if (!frl_dfm->config.slice_width || !frl_dfm->config.target_bpp_16) + return false; + + drm_frl_dfm_compute_max_frl_link_overhead(frl_dfm); + drm_frl_dfm_compute_link_characteristics(frl_dfm); + drm_frl_dfm_compute_audio_hblank_min(frl_dfm); + drm_frl_dfm_dsc_compute_tribytes(frl_dfm); + + if (!drm_frl_dfm_dsc_audio_supported(frl_dfm)) + return false; + + if (!drm_frl_dfm_dsc_is_timing_req_met(frl_dfm)) + return false; + + if (!drm_frl_dsc_check_utilization(frl_dfm)) + return false; + + return true; +} +EXPORT_SYMBOL(drm_frl_dfm_dsc_requirement_met); diff --git a/include/drm/drm_frl_dfm_helper.h b/include/drm/drm_frl_dfm_helper.h index 67f9caebd903..a6dc2479683b 100644 --- a/include/drm/drm_frl_dfm_helper.h +++ b/include/drm/drm_frl_dfm_helper.h @@ -123,4 +123,7 @@ struct drm_hdmi_frl_dfm {
bool drm_frl_dfm_nondsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm);
+bool +drm_frl_dfm_dsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm); + #endif
Add helper functions for calculating FRL capacity and DFM requirements with given compressed bpp.
v2: Fixed: -Build warnings/errors: Removed unused variables. -Checkpatch warnings.
Signed-off-by: Ankit Nautiyal ankit.k.nautiyal@intel.com Signed-off-by: Vandita Kulkarni vandita.kulkarni@intel.com --- drivers/gpu/drm/drm_frl_dfm_helper.c | 303 +++++++++++++++++++++++++++ include/drm/drm_frl_dfm_helper.h | 3 + 2 files changed, 306 insertions(+)
diff --git a/drivers/gpu/drm/drm_frl_dfm_helper.c b/drivers/gpu/drm/drm_frl_dfm_helper.c index b8f4f8ee50d3..95de7a6978a2 100644 --- a/drivers/gpu/drm/drm_frl_dfm_helper.c +++ b/drivers/gpu/drm/drm_frl_dfm_helper.c @@ -555,3 +555,306 @@ drm_frl_dfm_nondsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm) return false; } EXPORT_SYMBOL(drm_frl_dfm_nondsc_requirement_met); + +/* DSC DFM functions */ +/* Get FRL Available characters */ +static u32 +drm_get_frl_available_chars(u32 overhead_max, u32 cfrl_line) +{ + u32 frl_char_avlb = ((EFFICIENCY_MULTIPLIER - overhead_max) * cfrl_line); + + return frl_char_avlb / EFFICIENCY_MULTIPLIER; +} + +/* Get required no. of tribytes during HCActive */ +static u32 +drm_get_frl_hcactive_tb_target(u32 dsc_bpp_x16, u32 slice_width, u32 num_slices) +{ + u32 bytes_target; + + bytes_target = num_slices * DIV_ROUND_UP(dsc_bpp_x16 * slice_width, + 8 * BPP_MULTIPLIER); + + return DIV_ROUND_UP(bytes_target, 3); +} + +/* Get required no. of tribytes (estimate1) during HCBlank */ +static u32 +drm_get_frl_hcblank_tb_est1_target(u32 hcactive_target_tb, + u32 hactive, u32 hblank) +{ + return DIV_ROUND_UP(hcactive_target_tb * hblank, hactive); +} + +/* Get required no. of tribytes during HCBlank */ +static u32 +drm_get_frl_hcblank_tb_target(u32 hcactive_target_tb, u32 hactive, u32 hblank, + u32 hcblank_audio_min, u32 cfrl_available) +{ + u32 hcblank_target_tb1 = drm_get_frl_hcblank_tb_est1_target(hcactive_target_tb, + hactive, hblank); + u32 hcblank_target_tb2 = max(hcblank_target_tb1, hcblank_audio_min); + + return 4 * (min(hcblank_target_tb2, + (2 * cfrl_available - 3 * hcactive_target_tb) / 2) / 4); +} + +/* Get the avg no of tribytes sent per sec (Kbps) */ +static u32 +drm_frl_dsc_get_ftb_avg(u32 hcactive_target_tb, u32 hcblank_target_tb, + u32 hactive, u32 hblank, + u32 fpixelclock_max_khz) +{ + return (hcactive_target_tb + hcblank_target_tb) * + (fpixelclock_max_khz / (hactive + hblank)); +} + +/* Time to send Active tribytes in nanoseconds */ +static u32 +drm_frl_dsc_get_tactive_ref_ns(u32 line_time_ns, u32 hactive, u32 hblank) +{ + return (line_time_ns * hactive) / (hactive + hblank); +} + +/* Time to send Blanking tribytes in nanoseconds */ +static u32 +drm_frl_dsc_get_tblank_ref_ns(u32 line_time_ns, u32 hactive, u32 hblank) +{ + return (line_time_ns * hblank) / (hactive + hblank); +} + +/* Get time to send all tribytes in hcactive region in nsec*/ +static u32 +drm_frl_dsc_tactive_target_ns(u32 frl_lanes, u32 hcactive_target_tb, u32 ftb_avg_k, + u32 min_frl_char_rate_k, u32 overhead_max) +{ + u32 avg_tribyte_time_ns, tribyte_time_ns; + u32 num_chars_hcactive; + u32 frl_char_rate_k; + + /* Avg time to transmit all active region tribytes */ + avg_tribyte_time_ns = (hcactive_target_tb * FRL_TIMING_NS_MULTIPLIER) / + (ftb_avg_k * 1000); + + /* + * 2 bytes in active region = 1 FRL characters + * 1 Tribyte in active region = 3/2 FRL characters + */ + + num_chars_hcactive = (hcactive_target_tb * 3) / 2; + + /* + * FRL rate = lanes * frl character rate + * But actual bandwidth wil be less, due to FRL limitations so account + * for the overhead involved. + * FRL rate with overhead = FRL rate * (100 - overhead %) / 100 + */ + frl_char_rate_k = frl_lanes * min_frl_char_rate_k; + frl_char_rate_k = (frl_char_rate_k * (EFFICIENCY_MULTIPLIER - overhead_max)) / + EFFICIENCY_MULTIPLIER; + + /* Time to transmit all characters with FRL limitations */ + tribyte_time_ns = (num_chars_hcactive * FRL_TIMING_NS_MULTIPLIER) / + frl_char_rate_k * 1000; + + return max(avg_tribyte_time_ns, tribyte_time_ns); +} + +/* Get no. of tri bytes borrowed with DSC enabled */ +static u32 +drm_frl_get_dsc_tri_bytes_borrowed(u32 tactive_target_ns, u32 ftb_avg_k, + u32 hcactive_target_tb) +{ + return (tactive_target_ns * FRL_TIMING_NS_MULTIPLIER * ftb_avg_k * 1000) - + hcactive_target_tb; +} + +/* Get TBdelta : borrowing in tribytes relative to avg tribyte rate */ +static u32 +drm_frl_get_dsc_tri_bytes_delta(u32 tactive_target_ns, u32 tblank_target_ns, + u32 tactive_ref_ns, u32 tblank_ref_ns, + u32 hcactive_target_tb, u32 ftb_avg_k, + u32 hactive, u32 hblank, u32 line_time_ns) +{ + u32 tb_delta_limit; + u32 hcblank_target_tb1 = drm_get_frl_hcblank_tb_est1_target(hcactive_target_tb, + hactive, hblank); + u32 tribytes_per_ns = (hcactive_target_tb + hcblank_target_tb1) / line_time_ns; + u32 tribytes_per_sec = tribytes_per_ns * FRL_TIMING_NS_MULTIPLIER; + + if (tblank_ref_ns < tblank_target_ns) { + u32 tactive_ref_sec = tactive_ref_ns * FRL_TIMING_NS_MULTIPLIER; + u32 tactive_avg_sec = hcactive_target_tb / (ftb_avg_k * 1000); + + tb_delta_limit = (tactive_ref_sec - tactive_avg_sec) * + tribytes_per_sec; + } else { + u32 t_delta_ns; + + if (tactive_target_ns > tactive_ref_ns) + t_delta_ns = tactive_target_ns - tactive_ref_ns; + else + t_delta_ns = tactive_ref_ns - tactive_target_ns; + tb_delta_limit = t_delta_ns * tribytes_per_ns; + } + + return tb_delta_limit; +} + +/* Compute hcactive and hcblank tribytes for given dsc bpp setting */ +static void +drm_frl_dfm_dsc_compute_tribytes(struct drm_hdmi_frl_dfm *frl_dfm) +{ + u32 hcactive_target_tb; + u32 hcblank_target_tb; + u32 cfrl_available; + u32 num_slices; + + /* Assert for slice width ?*/ + if (!frl_dfm->config.slice_width) + return; + + num_slices = DIV_ROUND_UP(frl_dfm->config.hactive, frl_dfm->config.slice_width); + + hcactive_target_tb = drm_get_frl_hcactive_tb_target(frl_dfm->config.target_bpp_16, + frl_dfm->config.slice_width, + num_slices); + + cfrl_available = + drm_get_frl_available_chars(frl_dfm->params.overhead_max, + frl_dfm->params.cfrl_line); + + hcblank_target_tb = + drm_get_frl_hcblank_tb_target(hcactive_target_tb, + frl_dfm->config.hactive, + frl_dfm->config.hblank, + frl_dfm->params.hblank_audio_min, + cfrl_available); + + frl_dfm->params.hcactive_target = hcactive_target_tb; + frl_dfm->params.hcblank_target = hcblank_target_tb; +} + +/* Check if audio supported with given dsc bpp and frl bandwidth */ +static bool +drm_frl_dfm_dsc_audio_supported(struct drm_hdmi_frl_dfm *frl_dfm) +{ + return frl_dfm->params.hcblank_target < frl_dfm->params.hblank_audio_min; +} + +/* Is DFM timing requirement is met with DSC */ +static +bool drm_frl_dfm_dsc_is_timing_req_met(struct drm_hdmi_frl_dfm *frl_dfm) +{ + u32 ftb_avg_k; + u32 tactive_ref_ns, tblank_ref_ns, tactive_target_ns, tblank_target_ns; + u32 tb_borrowed, tb_delta, tb_worst; + + ftb_avg_k = drm_frl_dsc_get_ftb_avg(frl_dfm->params.hcactive_target, + frl_dfm->params.hcblank_target, + frl_dfm->config.hactive, + frl_dfm->config.hblank, + frl_dfm->params.pixel_clock_max_khz); + + tactive_ref_ns = drm_frl_dsc_get_tactive_ref_ns(frl_dfm->params.line_time_ns, + frl_dfm->config.hactive, + frl_dfm->config.hblank); + + tblank_ref_ns = drm_frl_dsc_get_tblank_ref_ns(frl_dfm->params.line_time_ns, + frl_dfm->config.hactive, + frl_dfm->config.hblank); + + tactive_target_ns = drm_frl_dsc_tactive_target_ns(frl_dfm->config.lanes, + frl_dfm->params.hcactive_target, + ftb_avg_k, + frl_dfm->params.char_rate_min_kbps, + frl_dfm->params.overhead_max); + + tblank_target_ns = frl_dfm->params.line_time_ns - tactive_target_ns; + + tb_borrowed = drm_frl_get_dsc_tri_bytes_borrowed(tactive_target_ns, + ftb_avg_k, + frl_dfm->params.hcactive_target); + + tb_delta = drm_frl_get_dsc_tri_bytes_delta(tactive_target_ns, + tblank_target_ns, + tactive_ref_ns, + tblank_ref_ns, + frl_dfm->params.hcactive_target, + ftb_avg_k, + frl_dfm->config.hactive, + frl_dfm->config.hblank, + frl_dfm->params.line_time_ns); + + tb_worst = max(tb_borrowed, tb_delta); + if (tb_worst > TB_BORROWED_MAX) + return false; + + frl_dfm->params.ftb_avg_k = ftb_avg_k; + frl_dfm->params.tb_borrowed = tb_borrowed; + + return true; +} + +/* Check Utilization constraint with DSC */ +static bool +drm_frl_dsc_check_utilization(struct drm_hdmi_frl_dfm *frl_dfm) +{ + u32 hcactive_target_tb = frl_dfm->params.hcactive_target; + u32 hcblank_target_tb = frl_dfm->params.hcblank_target; + u32 frl_char_per_line = frl_dfm->params.cfrl_line; + u32 overhead_max = frl_dfm->params.overhead_max; + u32 actual_frl_char_payload; + u32 utilization; + u32 utilization_with_overhead; + + /* Note: + * 1 FRL characters per 2 bytes in active period + * 1 FRL char per byte in Blanking period + */ + actual_frl_char_payload = DIV_ROUND_UP(3 * hcactive_target_tb, 2) + + hcblank_target_tb; + + utilization = (actual_frl_char_payload * EFFICIENCY_MULTIPLIER) / + frl_char_per_line; + + /* + * Utilization with overhead = utlization% +overhead % + * should be less than 100% + */ + utilization_with_overhead = utilization + overhead_max; + if (utilization_with_overhead > EFFICIENCY_MULTIPLIER) + return false; + + return false; +} + +/* + * drm_frl_fm_dsc_requirement_met : Check if FRL DFM requirements are met with + * the given bpp. + * @frl_dfm: dfm structure + * + * Returns true if the frl dfm requirements are met, else returns false. + */ +bool drm_frl_dfm_dsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm) +{ + if (!frl_dfm->config.slice_width || !frl_dfm->config.target_bpp_16) + return false; + + drm_frl_dfm_compute_max_frl_link_overhead(frl_dfm); + drm_frl_dfm_compute_link_characteristics(frl_dfm); + drm_frl_dfm_compute_audio_hblank_min(frl_dfm); + drm_frl_dfm_dsc_compute_tribytes(frl_dfm); + + if (!drm_frl_dfm_dsc_audio_supported(frl_dfm)) + return false; + + if (!drm_frl_dfm_dsc_is_timing_req_met(frl_dfm)) + return false; + + if (!drm_frl_dsc_check_utilization(frl_dfm)) + return false; + + return true; +} +EXPORT_SYMBOL(drm_frl_dfm_dsc_requirement_met); diff --git a/include/drm/drm_frl_dfm_helper.h b/include/drm/drm_frl_dfm_helper.h index 67f9caebd903..a6dc2479683b 100644 --- a/include/drm/drm_frl_dfm_helper.h +++ b/include/drm/drm_frl_dfm_helper.h @@ -123,4 +123,7 @@ struct drm_hdmi_frl_dfm {
bool drm_frl_dfm_nondsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm);
+bool +drm_frl_dfm_dsc_requirement_met(struct drm_hdmi_frl_dfm *frl_dfm); + #endif
Add the new frl_dfm_helper file to drm Makefile
Signed-off-by: Vandita Kulkarni vandita.kulkarni@intel.com --- drivers/gpu/drm/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 8675c2af7ae1..81fe3df8bfda 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -57,7 +57,9 @@ drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \ drm_scdc_helper.o drm_gem_atomic_helper.o \ drm_gem_framebuffer_helper.o \ drm_atomic_state_helper.o drm_damage_helper.o \ - drm_format_helper.o drm_self_refresh_helper.o drm_rect.o + drm_format_helper.o drm_self_refresh_helper.o drm_rect.o \ + drm_frl_dfm_helper.o + drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
dri-devel@lists.freedesktop.org