LCOV - code coverage report
Current view: top level - drivers/gpu/drm/display - drm_dsc_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 144 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 4 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: MIT
       2             : /*
       3             :  * Copyright © 2018 Intel Corp
       4             :  *
       5             :  * Author:
       6             :  * Manasi Navare <manasi.d.navare@intel.com>
       7             :  */
       8             : 
       9             : #include <linux/kernel.h>
      10             : #include <linux/module.h>
      11             : #include <linux/init.h>
      12             : #include <linux/errno.h>
      13             : #include <linux/byteorder/generic.h>
      14             : 
      15             : #include <drm/display/drm_dp_helper.h>
      16             : #include <drm/display/drm_dsc_helper.h>
      17             : #include <drm/drm_print.h>
      18             : 
      19             : /**
      20             :  * DOC: dsc helpers
      21             :  *
      22             :  * VESA specification for DP 1.4 adds a new feature called Display Stream
      23             :  * Compression (DSC) used to compress the pixel bits before sending it on
      24             :  * DP/eDP/MIPI DSI interface. DSC is required to be enabled so that the existing
      25             :  * display interfaces can support high resolutions at higher frames rates uisng
      26             :  * the maximum available link capacity of these interfaces.
      27             :  *
      28             :  * These functions contain some common logic and helpers to deal with VESA
      29             :  * Display Stream Compression standard required for DSC on Display Port/eDP or
      30             :  * MIPI display interfaces.
      31             :  */
      32             : 
      33             : /**
      34             :  * drm_dsc_dp_pps_header_init() - Initializes the PPS Header
      35             :  * for DisplayPort as per the DP 1.4 spec.
      36             :  * @pps_header: Secondary data packet header for DSC Picture
      37             :  *              Parameter Set as defined in &struct dp_sdp_header
      38             :  *
      39             :  * DP 1.4 spec defines the secondary data packet for sending the
      40             :  * picture parameter infoframes from the source to the sink.
      41             :  * This function populates the SDP header defined in
      42             :  * &struct dp_sdp_header.
      43             :  */
      44           0 : void drm_dsc_dp_pps_header_init(struct dp_sdp_header *pps_header)
      45             : {
      46           0 :         memset(pps_header, 0, sizeof(*pps_header));
      47             : 
      48           0 :         pps_header->HB1 = DP_SDP_PPS;
      49           0 :         pps_header->HB2 = DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1;
      50           0 : }
      51             : EXPORT_SYMBOL(drm_dsc_dp_pps_header_init);
      52             : 
      53             : /**
      54             :  * drm_dsc_dp_rc_buffer_size - get rc buffer size in bytes
      55             :  * @rc_buffer_block_size: block size code, according to DPCD offset 62h
      56             :  * @rc_buffer_size: number of blocks - 1, according to DPCD offset 63h
      57             :  *
      58             :  * return:
      59             :  * buffer size in bytes, or 0 on invalid input
      60             :  */
      61           0 : int drm_dsc_dp_rc_buffer_size(u8 rc_buffer_block_size, u8 rc_buffer_size)
      62             : {
      63           0 :         int size = 1024 * (rc_buffer_size + 1);
      64             : 
      65           0 :         switch (rc_buffer_block_size) {
      66             :         case DP_DSC_RC_BUF_BLK_SIZE_1:
      67           0 :                 return 1 * size;
      68             :         case DP_DSC_RC_BUF_BLK_SIZE_4:
      69           0 :                 return 4 * size;
      70             :         case DP_DSC_RC_BUF_BLK_SIZE_16:
      71           0 :                 return 16 * size;
      72             :         case DP_DSC_RC_BUF_BLK_SIZE_64:
      73           0 :                 return 64 * size;
      74             :         default:
      75             :                 return 0;
      76             :         }
      77             : }
      78             : EXPORT_SYMBOL(drm_dsc_dp_rc_buffer_size);
      79             : 
      80             : /**
      81             :  * drm_dsc_pps_payload_pack() - Populates the DSC PPS
      82             :  *
      83             :  * @pps_payload:
      84             :  * Bitwise struct for DSC Picture Parameter Set. This is defined
      85             :  * by &struct drm_dsc_picture_parameter_set
      86             :  * @dsc_cfg:
      87             :  * DSC Configuration data filled by driver as defined by
      88             :  * &struct drm_dsc_config
      89             :  *
      90             :  * DSC source device sends a picture parameter set (PPS) containing the
      91             :  * information required by the sink to decode the compressed frame. Driver
      92             :  * populates the DSC PPS struct using the DSC configuration parameters in
      93             :  * the order expected by the DSC Display Sink device. For the DSC, the sink
      94             :  * device expects the PPS payload in big endian format for fields
      95             :  * that span more than 1 byte.
      96             :  */
      97           0 : void drm_dsc_pps_payload_pack(struct drm_dsc_picture_parameter_set *pps_payload,
      98             :                                 const struct drm_dsc_config *dsc_cfg)
      99             : {
     100             :         int i;
     101             : 
     102             :         /* Protect against someone accidentally changing struct size */
     103             :         BUILD_BUG_ON(sizeof(*pps_payload) !=
     104             :                      DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 + 1);
     105             : 
     106           0 :         memset(pps_payload, 0, sizeof(*pps_payload));
     107             : 
     108             :         /* PPS 0 */
     109           0 :         pps_payload->dsc_version =
     110           0 :                 dsc_cfg->dsc_version_minor |
     111           0 :                 dsc_cfg->dsc_version_major << DSC_PPS_VERSION_MAJOR_SHIFT;
     112             : 
     113             :         /* PPS 1, 2 is 0 */
     114             : 
     115             :         /* PPS 3 */
     116           0 :         pps_payload->pps_3 =
     117           0 :                 dsc_cfg->line_buf_depth |
     118           0 :                 dsc_cfg->bits_per_component << DSC_PPS_BPC_SHIFT;
     119             : 
     120             :         /* PPS 4 */
     121           0 :         pps_payload->pps_4 =
     122           0 :                 ((dsc_cfg->bits_per_pixel & DSC_PPS_BPP_HIGH_MASK) >>
     123           0 :                  DSC_PPS_MSB_SHIFT) |
     124           0 :                 dsc_cfg->vbr_enable << DSC_PPS_VBR_EN_SHIFT |
     125           0 :                 dsc_cfg->simple_422 << DSC_PPS_SIMPLE422_SHIFT |
     126           0 :                 dsc_cfg->convert_rgb << DSC_PPS_CONVERT_RGB_SHIFT |
     127           0 :                 dsc_cfg->block_pred_enable << DSC_PPS_BLOCK_PRED_EN_SHIFT;
     128             : 
     129             :         /* PPS 5 */
     130           0 :         pps_payload->bits_per_pixel_low =
     131           0 :                 (dsc_cfg->bits_per_pixel & DSC_PPS_LSB_MASK);
     132             : 
     133             :         /*
     134             :          * The DSC panel expects the PPS packet to have big endian format
     135             :          * for data spanning 2 bytes. Use a macro cpu_to_be16() to convert
     136             :          * to big endian format. If format is little endian, it will swap
     137             :          * bytes to convert to Big endian else keep it unchanged.
     138             :          */
     139             : 
     140             :         /* PPS 6, 7 */
     141           0 :         pps_payload->pic_height = cpu_to_be16(dsc_cfg->pic_height);
     142             : 
     143             :         /* PPS 8, 9 */
     144           0 :         pps_payload->pic_width = cpu_to_be16(dsc_cfg->pic_width);
     145             : 
     146             :         /* PPS 10, 11 */
     147           0 :         pps_payload->slice_height = cpu_to_be16(dsc_cfg->slice_height);
     148             : 
     149             :         /* PPS 12, 13 */
     150           0 :         pps_payload->slice_width = cpu_to_be16(dsc_cfg->slice_width);
     151             : 
     152             :         /* PPS 14, 15 */
     153           0 :         pps_payload->chunk_size = cpu_to_be16(dsc_cfg->slice_chunk_size);
     154             : 
     155             :         /* PPS 16 */
     156           0 :         pps_payload->initial_xmit_delay_high =
     157           0 :                 ((dsc_cfg->initial_xmit_delay &
     158           0 :                   DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK) >>
     159             :                  DSC_PPS_MSB_SHIFT);
     160             : 
     161             :         /* PPS 17 */
     162           0 :         pps_payload->initial_xmit_delay_low =
     163           0 :                 (dsc_cfg->initial_xmit_delay & DSC_PPS_LSB_MASK);
     164             : 
     165             :         /* PPS 18, 19 */
     166           0 :         pps_payload->initial_dec_delay =
     167           0 :                 cpu_to_be16(dsc_cfg->initial_dec_delay);
     168             : 
     169             :         /* PPS 20 is 0 */
     170             : 
     171             :         /* PPS 21 */
     172           0 :         pps_payload->initial_scale_value =
     173           0 :                 dsc_cfg->initial_scale_value;
     174             : 
     175             :         /* PPS 22, 23 */
     176           0 :         pps_payload->scale_increment_interval =
     177           0 :                 cpu_to_be16(dsc_cfg->scale_increment_interval);
     178             : 
     179             :         /* PPS 24 */
     180           0 :         pps_payload->scale_decrement_interval_high =
     181           0 :                 ((dsc_cfg->scale_decrement_interval &
     182           0 :                   DSC_PPS_SCALE_DEC_INT_HIGH_MASK) >>
     183             :                  DSC_PPS_MSB_SHIFT);
     184             : 
     185             :         /* PPS 25 */
     186           0 :         pps_payload->scale_decrement_interval_low =
     187           0 :                 (dsc_cfg->scale_decrement_interval & DSC_PPS_LSB_MASK);
     188             : 
     189             :         /* PPS 26[7:0], PPS 27[7:5] RESERVED */
     190             : 
     191             :         /* PPS 27 */
     192           0 :         pps_payload->first_line_bpg_offset =
     193           0 :                 dsc_cfg->first_line_bpg_offset;
     194             : 
     195             :         /* PPS 28, 29 */
     196           0 :         pps_payload->nfl_bpg_offset =
     197           0 :                 cpu_to_be16(dsc_cfg->nfl_bpg_offset);
     198             : 
     199             :         /* PPS 30, 31 */
     200           0 :         pps_payload->slice_bpg_offset =
     201           0 :                 cpu_to_be16(dsc_cfg->slice_bpg_offset);
     202             : 
     203             :         /* PPS 32, 33 */
     204           0 :         pps_payload->initial_offset =
     205           0 :                 cpu_to_be16(dsc_cfg->initial_offset);
     206             : 
     207             :         /* PPS 34, 35 */
     208           0 :         pps_payload->final_offset = cpu_to_be16(dsc_cfg->final_offset);
     209             : 
     210             :         /* PPS 36 */
     211           0 :         pps_payload->flatness_min_qp = dsc_cfg->flatness_min_qp;
     212             : 
     213             :         /* PPS 37 */
     214           0 :         pps_payload->flatness_max_qp = dsc_cfg->flatness_max_qp;
     215             : 
     216             :         /* PPS 38, 39 */
     217           0 :         pps_payload->rc_model_size = cpu_to_be16(dsc_cfg->rc_model_size);
     218             : 
     219             :         /* PPS 40 */
     220           0 :         pps_payload->rc_edge_factor = DSC_RC_EDGE_FACTOR_CONST;
     221             : 
     222             :         /* PPS 41 */
     223           0 :         pps_payload->rc_quant_incr_limit0 =
     224           0 :                 dsc_cfg->rc_quant_incr_limit0;
     225             : 
     226             :         /* PPS 42 */
     227           0 :         pps_payload->rc_quant_incr_limit1 =
     228           0 :                 dsc_cfg->rc_quant_incr_limit1;
     229             : 
     230             :         /* PPS 43 */
     231           0 :         pps_payload->rc_tgt_offset = DSC_RC_TGT_OFFSET_LO_CONST |
     232             :                 DSC_RC_TGT_OFFSET_HI_CONST << DSC_PPS_RC_TGT_OFFSET_HI_SHIFT;
     233             : 
     234             :         /* PPS 44 - 57 */
     235           0 :         for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
     236           0 :                 pps_payload->rc_buf_thresh[i] =
     237           0 :                         dsc_cfg->rc_buf_thresh[i];
     238             : 
     239             :         /* PPS 58 - 87 */
     240             :         /*
     241             :          * For DSC sink programming the RC Range parameter fields
     242             :          * are as follows: Min_qp[15:11], max_qp[10:6], offset[5:0]
     243             :          */
     244           0 :         for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
     245           0 :                 pps_payload->rc_range_parameters[i] =
     246           0 :                         cpu_to_be16((dsc_cfg->rc_range_params[i].range_min_qp <<
     247             :                                      DSC_PPS_RC_RANGE_MINQP_SHIFT) |
     248             :                                     (dsc_cfg->rc_range_params[i].range_max_qp <<
     249             :                                      DSC_PPS_RC_RANGE_MAXQP_SHIFT) |
     250             :                                     (dsc_cfg->rc_range_params[i].range_bpg_offset));
     251             :         }
     252             : 
     253             :         /* PPS 88 */
     254           0 :         pps_payload->native_422_420 = dsc_cfg->native_422 |
     255           0 :                 dsc_cfg->native_420 << DSC_PPS_NATIVE_420_SHIFT;
     256             : 
     257             :         /* PPS 89 */
     258           0 :         pps_payload->second_line_bpg_offset =
     259           0 :                 dsc_cfg->second_line_bpg_offset;
     260             : 
     261             :         /* PPS 90, 91 */
     262           0 :         pps_payload->nsl_bpg_offset =
     263           0 :                 cpu_to_be16(dsc_cfg->nsl_bpg_offset);
     264             : 
     265             :         /* PPS 92, 93 */
     266           0 :         pps_payload->second_line_offset_adj =
     267           0 :                 cpu_to_be16(dsc_cfg->second_line_offset_adj);
     268             : 
     269             :         /* PPS 94 - 127 are O */
     270           0 : }
     271             : EXPORT_SYMBOL(drm_dsc_pps_payload_pack);
     272             : 
     273             : /**
     274             :  * drm_dsc_compute_rc_parameters() - Write rate control
     275             :  * parameters to the dsc configuration defined in
     276             :  * &struct drm_dsc_config in accordance with the DSC 1.2
     277             :  * specification. Some configuration fields must be present
     278             :  * beforehand.
     279             :  *
     280             :  * @vdsc_cfg:
     281             :  * DSC Configuration data partially filled by driver
     282             :  */
     283           0 : int drm_dsc_compute_rc_parameters(struct drm_dsc_config *vdsc_cfg)
     284             : {
     285           0 :         unsigned long groups_per_line = 0;
     286           0 :         unsigned long groups_total = 0;
     287           0 :         unsigned long num_extra_mux_bits = 0;
     288           0 :         unsigned long slice_bits = 0;
     289           0 :         unsigned long hrd_delay = 0;
     290           0 :         unsigned long final_scale = 0;
     291           0 :         unsigned long rbs_min = 0;
     292             : 
     293           0 :         if (vdsc_cfg->native_420 || vdsc_cfg->native_422) {
     294             :                 /* Number of groups used to code each line of a slice */
     295           0 :                 groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width / 2,
     296             :                                                DSC_RC_PIXELS_PER_GROUP);
     297             : 
     298             :                 /* chunksize in Bytes */
     299           0 :                 vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width / 2 *
     300             :                                                           vdsc_cfg->bits_per_pixel,
     301             :                                                           (8 * 16));
     302             :         } else {
     303             :                 /* Number of groups used to code each line of a slice */
     304           0 :                 groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width,
     305             :                                                DSC_RC_PIXELS_PER_GROUP);
     306             : 
     307             :                 /* chunksize in Bytes */
     308           0 :                 vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width *
     309             :                                                           vdsc_cfg->bits_per_pixel,
     310             :                                                           (8 * 16));
     311             :         }
     312             : 
     313           0 :         if (vdsc_cfg->convert_rgb)
     314           0 :                 num_extra_mux_bits = 3 * (vdsc_cfg->mux_word_size +
     315           0 :                                           (4 * vdsc_cfg->bits_per_component + 4)
     316           0 :                                           - 2);
     317           0 :         else if (vdsc_cfg->native_422)
     318           0 :                 num_extra_mux_bits = 4 * vdsc_cfg->mux_word_size +
     319           0 :                         (4 * vdsc_cfg->bits_per_component + 4) +
     320           0 :                         3 * (4 * vdsc_cfg->bits_per_component) - 2;
     321             :         else
     322           0 :                 num_extra_mux_bits = 3 * vdsc_cfg->mux_word_size +
     323           0 :                         (4 * vdsc_cfg->bits_per_component + 4) +
     324           0 :                         2 * (4 * vdsc_cfg->bits_per_component) - 2;
     325             :         /* Number of bits in one Slice */
     326           0 :         slice_bits = 8 * vdsc_cfg->slice_chunk_size * vdsc_cfg->slice_height;
     327             : 
     328           0 :         while ((num_extra_mux_bits > 0) &&
     329           0 :                ((slice_bits - num_extra_mux_bits) % vdsc_cfg->mux_word_size))
     330           0 :                 num_extra_mux_bits--;
     331             : 
     332           0 :         if (groups_per_line < vdsc_cfg->initial_scale_value - 8)
     333           0 :                 vdsc_cfg->initial_scale_value = groups_per_line + 8;
     334             : 
     335             :         /* scale_decrement_interval calculation according to DSC spec 1.11 */
     336           0 :         if (vdsc_cfg->initial_scale_value > 8)
     337           0 :                 vdsc_cfg->scale_decrement_interval = groups_per_line /
     338           0 :                         (vdsc_cfg->initial_scale_value - 8);
     339             :         else
     340           0 :                 vdsc_cfg->scale_decrement_interval = DSC_SCALE_DECREMENT_INTERVAL_MAX;
     341             : 
     342           0 :         vdsc_cfg->final_offset = vdsc_cfg->rc_model_size -
     343           0 :                 (vdsc_cfg->initial_xmit_delay *
     344           0 :                  vdsc_cfg->bits_per_pixel + 8) / 16 + num_extra_mux_bits;
     345             : 
     346           0 :         if (vdsc_cfg->final_offset >= vdsc_cfg->rc_model_size) {
     347           0 :                 DRM_DEBUG_KMS("FinalOfs < RcModelSze for this InitialXmitDelay\n");
     348           0 :                 return -ERANGE;
     349             :         }
     350             : 
     351           0 :         final_scale = (vdsc_cfg->rc_model_size * 8) /
     352           0 :                 (vdsc_cfg->rc_model_size - vdsc_cfg->final_offset);
     353           0 :         if (vdsc_cfg->slice_height > 1)
     354             :                 /*
     355             :                  * NflBpgOffset is 16 bit value with 11 fractional bits
     356             :                  * hence we multiply by 2^11 for preserving the
     357             :                  * fractional part
     358             :                  */
     359           0 :                 vdsc_cfg->nfl_bpg_offset = DIV_ROUND_UP((vdsc_cfg->first_line_bpg_offset << 11),
     360             :                                                         (vdsc_cfg->slice_height - 1));
     361             :         else
     362           0 :                 vdsc_cfg->nfl_bpg_offset = 0;
     363             : 
     364             :         /* Number of groups used to code the entire slice */
     365           0 :         groups_total = groups_per_line * vdsc_cfg->slice_height;
     366             : 
     367             :         /* slice_bpg_offset is 16 bit value with 11 fractional bits */
     368           0 :         vdsc_cfg->slice_bpg_offset = DIV_ROUND_UP(((vdsc_cfg->rc_model_size -
     369             :                                                     vdsc_cfg->initial_offset +
     370             :                                                     num_extra_mux_bits) << 11),
     371             :                                                   groups_total);
     372             : 
     373           0 :         if (final_scale > 9) {
     374             :                 /*
     375             :                  * ScaleIncrementInterval =
     376             :                  * finaloffset/((NflBpgOffset + SliceBpgOffset)*8(finalscale - 1.125))
     377             :                  * as (NflBpgOffset + SliceBpgOffset) has 11 bit fractional value,
     378             :                  * we need divide by 2^11 from pstDscCfg values
     379             :                  */
     380           0 :                 vdsc_cfg->scale_increment_interval =
     381           0 :                                 (vdsc_cfg->final_offset * (1 << 11)) /
     382           0 :                                 ((vdsc_cfg->nfl_bpg_offset +
     383           0 :                                 vdsc_cfg->slice_bpg_offset) *
     384           0 :                                 (final_scale - 9));
     385             :         } else {
     386             :                 /*
     387             :                  * If finalScaleValue is less than or equal to 9, a value of 0 should
     388             :                  * be used to disable the scale increment at the end of the slice
     389             :                  */
     390           0 :                 vdsc_cfg->scale_increment_interval = 0;
     391             :         }
     392             : 
     393             :         /*
     394             :          * DSC spec mentions that bits_per_pixel specifies the target
     395             :          * bits/pixel (bpp) rate that is used by the encoder,
     396             :          * in steps of 1/16 of a bit per pixel
     397             :          */
     398           0 :         rbs_min = vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset +
     399           0 :                 DIV_ROUND_UP(vdsc_cfg->initial_xmit_delay *
     400             :                              vdsc_cfg->bits_per_pixel, 16) +
     401           0 :                 groups_per_line * vdsc_cfg->first_line_bpg_offset;
     402             : 
     403           0 :         hrd_delay = DIV_ROUND_UP((rbs_min * 16), vdsc_cfg->bits_per_pixel);
     404           0 :         vdsc_cfg->rc_bits = (hrd_delay * vdsc_cfg->bits_per_pixel) / 16;
     405           0 :         vdsc_cfg->initial_dec_delay = hrd_delay - vdsc_cfg->initial_xmit_delay;
     406             : 
     407           0 :         return 0;
     408             : }
     409             : EXPORT_SYMBOL(drm_dsc_compute_rc_parameters);

Generated by: LCOV version 1.14