From: Vandita Kulkarni <[email protected]> Add helper functions for computing non dsc frl link characteristics
Signed-off-by: Vandita Kulkarni <[email protected]> Signed-off-by: Ankit Nautiyal <[email protected]> --- drivers/gpu/drm/i915/Makefile | 1 + .../gpu/drm/i915/display/intel_hdmi_frl_dfm.c | 415 ++++++++++++++++++ .../gpu/drm/i915/display/intel_hdmi_frl_dfm.h | 2 + drivers/gpu/drm/xe/Makefile | 1 + 4 files changed, 419 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index a83fa8be0aba..016816bbfc4b 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -367,6 +367,7 @@ i915-y += \ display/intel_encoder.o \ display/intel_gmbus.o \ display/intel_hdmi.o \ + display/intel_hdmi_frl_dfm.o \ display/intel_lspcon.o \ display/intel_lt_phy.o \ display/intel_lvds.o \ diff --git a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c new file mode 100644 index 000000000000..2de9d3dd23ae --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corp + */ + +#include <linux/kernel.h> + +#include <drm/drm_connector.h> + +#include "intel_hdmi_frl_dfm.h" + +/* DFM constraints and tolerance values */ +#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 + +/* Total FRL characters per super block */ +static u32 get_frl_char_per_super_blk(u32 lanes) +{ + return (4 * FRL_CHAR_PER_CHAR_BLK) + lanes; +} + +/* Total minimum overhead multiplied by EFFICIENCY_MULIPLIER */ +static u32 get_total_minimum_overhead(u32 lanes) +{ + u32 overhead_sb; + u32 overhead_rs; + u32 overhead_map; + + /* + * Determine the overhead due to the inclusion of + * the SR and SSB FRL characters used for + * super block framing + */ + overhead_sb = (lanes * EFFICIENCY_MULTIPLIER) / get_frl_char_per_super_blk(lanes); + + /* + * Determine the overhead due to the inclusion of RS FEC pairity + * symbols. Each character block uses 8 FRL characters for RS Pairity + * and there are 4 character blocks per super block + */ + overhead_rs = (8 * 4 * EFFICIENCY_MULTIPLIER) / get_frl_char_per_super_blk(lanes); + + /* + * Determine the overhead due to FRL Map characters. + * In a bandwidth constrained application, the FRL packets will be long, + * there will typically be two FRL Map Characters 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 Charecter. Therefore this spec assumes 2.5 FRL Map Characters + * per Super Block. + */ + overhead_map = + (25 * EFFICIENCY_MULTIPLIER) / (10 * get_frl_char_per_super_blk(lanes)); + + return overhead_sb + overhead_rs + overhead_map; +} + +/* Audio Support Verification Computations */ + +/* + * 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 u32 +get_num_char_rc_compressible(u32 color_format, u32 bpc, + u32 audio_packets_line, u32 hblank) +{ + u32 cfrl_free; + u32 kcdx100, k420; + + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) + k420 = 2; + else + k420 = 1; + + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) + kcdx100 = 100; + else + kcdx100 = (100 * bpc) / 8; + + cfrl_free = max(((hblank * kcdx100) / (100 * k420) - 32 * audio_packets_line - 7), + U32_MIN); + + return cfrl_free; +} + +/* + * Determine the actual number of characters made available by + * RC compression + */ +static u32 +get_num_char_compression_savings(u32 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 u32 cfrl_margin = 4; + u32 cfrl_savings = max(((7 * cfrl_free) / 8) - cfrl_margin, U32_MIN); + + return cfrl_savings; +} + +static u32 +get_frl_bits_per_pixel(u32 color_format, u32 bpc) +{ + u32 kcdx100, k420; + + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) + k420 = 2; + else + k420 = 1; + + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) + kcdx100 = 100; + else + kcdx100 = (100 * bpc) / 8; + + return (24 * kcdx100) / (100 * k420); +} + +/* Determine the total available tribytes during the blanking period */ +static u32 +get_blanking_tribytes_avail(u32 color_format, + u32 hblank, u32 bpc) +{ + u32 kcdx100, k420; + + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR420) + k420 = 2; + else + k420 = 1; + + if (color_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) + kcdx100 = 100; + else + kcdx100 = (100 * bpc) / 8; + + return DIV_ROUND_UP((hblank * kcdx100), (100 * k420)); +} + +/* + * 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 u32 +get_tactive_min(u32 num_lanes, u32 tribyte_active, + u32 overhead_max_k, u32 frl_char_min_rate_k) +{ + u32 active_bytes, rate_kbps, efficiency_k, effective_rate_kbps; + + active_bytes = (3 * tribyte_active) / 2; + rate_kbps = num_lanes * frl_char_min_rate_k; + efficiency_k = EFFICIENCY_MULTIPLIER - overhead_max_k; + effective_rate_kbps = mult_frac(rate_kbps, efficiency_k, EFFICIENCY_MULTIPLIER); + + return mult_frac(FRL_TIMING_NS_MULTIPLIER, active_bytes, effective_rate_kbps) / 1000; +} + +/* + * Determine the minimum time necessary to transmit the video blanking + * tribytes considering frl bandwidth limitations + */ +static u32 +get_tblank_min(u32 num_lanes, u32 tribyte_blank, + u32 overhead_max_k, u32 frl_char_min_rate_k) +{ + u32 blank_bytes, rate_kbps, efficiency_k, effective_rate_kbps; + + blank_bytes = (3 * tribyte_blank) / 2; + rate_kbps = num_lanes * frl_char_min_rate_k; + efficiency_k = EFFICIENCY_MULTIPLIER - overhead_max_k; + effective_rate_kbps = mult_frac(rate_kbps, efficiency_k, EFFICIENCY_MULTIPLIER); + + return mult_frac(FRL_TIMING_NS_MULTIPLIER, blank_bytes, effective_rate_kbps) / 1000; +} + +/* Collect link characteristics */ +static void +compute_link_characteristics(struct intel_hdmi_frl_dfm *frl_dfm) +{ + u32 frl_bit_rate_min_kbps, line_width, rate_m; + + /* Determine the maximum legal pixel rate */ + frl_dfm->params.pixel_clock_max_khz = + (frl_dfm->config.pixel_clock_nominal_khz * (1000 + TOLERANCE_PIXEL_CLOCK)) / 1000; + + /* Determine the minimum Video Line period */ + line_width = frl_dfm->config.hactive + frl_dfm->config.hblank; + + frl_dfm->params.line_time_ns = mult_frac(FRL_TIMING_NS_MULTIPLIER, + line_width, + frl_dfm->params.pixel_clock_max_khz) / 1000; + + /* Determine the worst-case slow FRL Bit Rate in kbps*/ + frl_bit_rate_min_kbps = + (frl_dfm->config.bit_rate_kbps / 1000000) * (1000000 - TOLERANCE_FRL_BIT_RATE); + + /* Determine the worst-case slow FRL Character Rate */ + frl_dfm->params.char_rate_min_kbps = frl_bit_rate_min_kbps / 18; + + /* Character rate in mega chars/sec */ + rate_m = DIV_ROUND_UP(frl_dfm->params.char_rate_min_kbps * frl_dfm->config.lanes, 1000); + + /* Determine the Minimum Total FRL characters per line period */ + frl_dfm->params.cfrl_line = DIV_ROUND_UP(frl_dfm->params.line_time_ns * rate_m, + FRL_TIMING_NS_MULTIPLIER / 1000000); +} + +/* Determine FRL link overhead */ +static void compute_max_frl_link_overhead(struct intel_hdmi_frl_dfm *frl_dfm) +{ + u32 overhead_min = get_total_minimum_overhead(frl_dfm->config.lanes); + + /* + * Additional margin to the overhead is provided to account for the possibility + * of more Map Characters, zero padding at the end of HCactive, and other minor + * items + */ + frl_dfm->params.overhead_max = overhead_min + OVERHEAD_M; +} + +/* Audio support Verification computations */ +static void +compute_audio_hblank_min(struct intel_hdmi_frl_dfm *frl_dfm) +{ + u32 num_audio_pkt, audio_pkt_rate; + + /* + * #TODO: get the actual audio pkt type 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; + + /* + * Determine Audio Related Packet Rate considering the audio clock + * increased to maximim rate permitted by Tolerance Audio clock + */ + audio_pkt_rate = + ((frl_dfm->config.audio_hz * num_audio_pkt + (2 * ACR_RATE_MAX)) * + (1000000 + TOLERANCE_AUDIO_CLOCK)) / 1000000; + + /* + * Average required packets per line is + * number of audio packets needed during Hblank + */ + frl_dfm->params.num_audio_pkts_line = + DIV_ROUND_UP(audio_pkt_rate * frl_dfm->params.line_time_ns, + FRL_TIMING_NS_MULTIPLIER); + + /* + * 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 + */ + frl_dfm->params.hblank_audio_min = 32 + 32 * frl_dfm->params.num_audio_pkts_line; +} + +/* + * Determine the number of tribytes required for active video , blanking period + * with the pixel configuration + */ +static void +compute_tbactive_tbblank(struct intel_hdmi_frl_dfm *frl_dfm) +{ + u32 bpp, bytes_per_line; + + bpp = get_frl_bits_per_pixel(frl_dfm->config.color_format, frl_dfm->config.bpc); + bytes_per_line = (bpp * frl_dfm->config.hactive) / 8; + + frl_dfm->params.tb_active = DIV_ROUND_UP(bytes_per_line, 3); + + frl_dfm->params.tb_blank = + 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 +verify_frl_capacity_requirement(struct intel_hdmi_frl_dfm *frl_dfm) +{ + u32 tactive_ref_ns, tblank_ref_ns, tactive_min_ns, tblank_min_ns; + u32 tborrowed_ns; + u32 line_time_ns = frl_dfm->params.line_time_ns; + u32 hactive = frl_dfm->config.hactive; + u32 hblank = frl_dfm->config.hblank; + + /* Determine the average tribyte rate in kilo tribytes per sec */ + frl_dfm->params.ftb_avg_k = + (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); + + /* + * Determine the time required to transmit the active portion of the + * minimum possible active line period in the base timing + */ + tactive_ref_ns = (line_time_ns * hactive) / (hblank + hactive); + + /* + * Determine the time required to transmit the Video blanking portion + * of the minimum possible active line period in the base timing + */ + tblank_ref_ns = (line_time_ns * hblank) / (hblank + hactive); + + tactive_min_ns = 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 = 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; + /* Determine the disparity in tribytes */ + frl_dfm->params.tb_borrowed = + DIV_ROUND_UP((tborrowed_ns * frl_dfm->params.ftb_avg_k * 1000), + FRL_TIMING_NS_MULTIPLIER); + + if (frl_dfm->params.tb_borrowed <= TB_BORROWED_MAX) + return true; + } + + return false; +} + +/* Verify utilization does not exceed capacity */ +static bool +verify_utilization_possible(struct intel_hdmi_frl_dfm *frl_dfm) +{ + u32 cfrl_free, cfrl_savings, frl_char_payload_actual; + u32 utilization, margin; + + cfrl_free = 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 = get_num_char_compression_savings(cfrl_free); + + /* + * Determine the actual number of payload FRL characters required to + * carry each video line + */ + frl_char_payload_actual = + DIV_ROUND_UP(3 * frl_dfm->params.tb_active, 2) + + frl_dfm->params.tb_blank - cfrl_savings; + + /* + * Determine the payload utilization of the total number of + * FRL characters + */ + utilization = (frl_char_payload_actual * EFFICIENCY_MULTIPLIER) / 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 +intel_hdmi_frl_dfm_nondsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm) +{ + bool frl_capacity_req_met; + + compute_max_frl_link_overhead(frl_dfm); + compute_link_characteristics(frl_dfm); + compute_audio_hblank_min(frl_dfm); + compute_tbactive_tbblank(frl_dfm); + + frl_capacity_req_met = verify_frl_capacity_requirement(frl_dfm); + + if (frl_capacity_req_met) + return verify_utilization_possible(frl_dfm); + + return false; +} diff --git a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h index c619073eef9b..83d5b0d6370b 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h +++ b/drivers/gpu/drm/i915/display/intel_hdmi_frl_dfm.h @@ -110,4 +110,6 @@ struct intel_hdmi_frl_dfm { struct intel_hdmi_frl_dfm_params params; }; +bool intel_hdmi_frl_dfm_nondsc_requirement_met(struct intel_hdmi_frl_dfm *frl_dfm); + #endif diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 44ed055439d4..7c1c83072851 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -303,6 +303,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_hdcp.o \ i915-display/intel_hdcp_gsc_message.o \ i915-display/intel_hdmi.o \ + i915-display/intel_hdmi_frl_dfm.o \ i915-display/intel_hotplug.o \ i915-display/intel_hotplug_irq.o \ i915-display/intel_hti.o \ -- 2.50.1
