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.kulka...@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
-- 
2.32.0

Reply via email to