Add helper functions for computing non dsc frl link characteristics Signed-off-by: Vandita Kulkarni <vandita.kulkarni@xxxxxxxxx> --- 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; +} -- 2.32.0