2018-11-28 00:41:07 +03:00
// SPDX-License-Identifier: MIT
/*
* Copyright © 2018 Intel Corp
*
* Author :
* Manasi Navare < manasi . d . navare @ intel . com >
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/byteorder/generic.h>
2019-02-21 23:19:59 +03:00
# include <drm/drm_print.h>
2018-11-28 00:41:07 +03:00
# include <drm/drm_dp_helper.h>
# include <drm/drm_dsc.h>
/**
* DOC : dsc helpers
*
2019-02-07 00:31:48 +03:00
* VESA specification for DP 1.4 adds a new feature called Display Stream
* Compression ( DSC ) used to compress the pixel bits before sending it on
* DP / eDP / MIPI DSI interface . DSC is required to be enabled so that the existing
* display interfaces can support high resolutions at higher frames rates uisng
* the maximum available link capacity of these interfaces .
*
2018-11-28 00:41:07 +03:00
* These functions contain some common logic and helpers to deal with VESA
* Display Stream Compression standard required for DSC on Display Port / eDP or
* MIPI display interfaces .
*/
/**
* drm_dsc_dp_pps_header_init ( ) - Initializes the PPS Header
* for DisplayPort as per the DP 1.4 spec .
2019-02-21 23:20:01 +03:00
* @ pps_header : Secondary data packet header for DSC Picture
* Parameter Set as defined in & struct dp_sdp_header
2019-02-07 00:31:48 +03:00
*
* DP 1.4 spec defines the secondary data packet for sending the
* picture parameter infoframes from the source to the sink .
2019-02-21 23:20:01 +03:00
* This function populates the SDP header defined in
* & struct dp_sdp_header .
2018-11-28 00:41:07 +03:00
*/
2019-02-21 23:20:01 +03:00
void drm_dsc_dp_pps_header_init ( struct dp_sdp_header * pps_header )
2018-11-28 00:41:07 +03:00
{
2019-02-21 23:20:01 +03:00
memset ( pps_header , 0 , sizeof ( * pps_header ) ) ;
2018-11-28 00:41:07 +03:00
2019-02-21 23:20:01 +03:00
pps_header - > HB1 = DP_SDP_PPS ;
pps_header - > HB2 = DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 ;
2018-11-28 00:41:07 +03:00
}
EXPORT_SYMBOL ( drm_dsc_dp_pps_header_init ) ;
/**
2019-02-21 23:20:01 +03:00
* drm_dsc_pps_payload_pack ( ) - Populates the DSC PPS
2018-11-28 00:41:07 +03:00
*
2019-02-21 23:20:01 +03:00
* @ pps_payload :
* Bitwise struct for DSC Picture Parameter Set . This is defined
* by & struct drm_dsc_picture_parameter_set
2018-11-28 00:41:07 +03:00
* @ dsc_cfg :
2019-02-07 00:31:48 +03:00
* DSC Configuration data filled by driver as defined by
* & struct drm_dsc_config
*
2019-02-21 23:20:01 +03:00
* DSC source device sends a picture parameter set ( PPS ) containing the
* information required by the sink to decode the compressed frame . Driver
* populates the DSC PPS struct using the DSC configuration parameters in
* the order expected by the DSC Display Sink device . For the DSC , the sink
* device expects the PPS payload in big endian format for fields
* that span more than 1 byte .
2018-11-28 00:41:07 +03:00
*/
2019-02-21 23:20:01 +03:00
void drm_dsc_pps_payload_pack ( struct drm_dsc_picture_parameter_set * pps_payload ,
2018-11-28 00:41:07 +03:00
const struct drm_dsc_config * dsc_cfg )
{
int i ;
/* Protect against someone accidently changing struct size */
2019-02-21 23:20:01 +03:00
BUILD_BUG_ON ( sizeof ( * pps_payload ) ! =
2018-11-28 00:41:07 +03:00
DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 + 1 ) ;
2019-02-21 23:20:01 +03:00
memset ( pps_payload , 0 , sizeof ( * pps_payload ) ) ;
2018-11-28 00:41:07 +03:00
/* PPS 0 */
2019-02-21 23:20:01 +03:00
pps_payload - > dsc_version =
2018-11-28 00:41:07 +03:00
dsc_cfg - > dsc_version_minor |
dsc_cfg - > dsc_version_major < < DSC_PPS_VERSION_MAJOR_SHIFT ;
/* PPS 1, 2 is 0 */
/* PPS 3 */
2019-02-21 23:20:01 +03:00
pps_payload - > pps_3 =
2018-11-28 00:41:07 +03:00
dsc_cfg - > line_buf_depth |
dsc_cfg - > bits_per_component < < DSC_PPS_BPC_SHIFT ;
/* PPS 4 */
2019-02-21 23:20:01 +03:00
pps_payload - > pps_4 =
2018-11-28 00:41:07 +03:00
( ( dsc_cfg - > bits_per_pixel & DSC_PPS_BPP_HIGH_MASK ) > >
DSC_PPS_MSB_SHIFT ) |
dsc_cfg - > vbr_enable < < DSC_PPS_VBR_EN_SHIFT |
2019-02-21 23:20:00 +03:00
dsc_cfg - > simple_422 < < DSC_PPS_SIMPLE422_SHIFT |
2018-11-28 00:41:07 +03:00
dsc_cfg - > convert_rgb < < DSC_PPS_CONVERT_RGB_SHIFT |
dsc_cfg - > block_pred_enable < < DSC_PPS_BLOCK_PRED_EN_SHIFT ;
/* PPS 5 */
2019-02-21 23:20:01 +03:00
pps_payload - > bits_per_pixel_low =
2018-11-28 00:41:07 +03:00
( dsc_cfg - > bits_per_pixel & DSC_PPS_LSB_MASK ) ;
/*
* The DSC panel expects the PPS packet to have big endian format
* for data spanning 2 bytes . Use a macro cpu_to_be16 ( ) to convert
* to big endian format . If format is little endian , it will swap
* bytes to convert to Big endian else keep it unchanged .
*/
/* PPS 6, 7 */
2019-02-21 23:20:01 +03:00
pps_payload - > pic_height = cpu_to_be16 ( dsc_cfg - > pic_height ) ;
2018-11-28 00:41:07 +03:00
/* PPS 8, 9 */
2019-02-21 23:20:01 +03:00
pps_payload - > pic_width = cpu_to_be16 ( dsc_cfg - > pic_width ) ;
2018-11-28 00:41:07 +03:00
/* PPS 10, 11 */
2019-02-21 23:20:01 +03:00
pps_payload - > slice_height = cpu_to_be16 ( dsc_cfg - > slice_height ) ;
2018-11-28 00:41:07 +03:00
/* PPS 12, 13 */
2019-02-21 23:20:01 +03:00
pps_payload - > slice_width = cpu_to_be16 ( dsc_cfg - > slice_width ) ;
2018-11-28 00:41:07 +03:00
/* PPS 14, 15 */
2019-02-21 23:20:01 +03:00
pps_payload - > chunk_size = cpu_to_be16 ( dsc_cfg - > slice_chunk_size ) ;
2018-11-28 00:41:07 +03:00
/* PPS 16 */
2019-02-21 23:20:01 +03:00
pps_payload - > initial_xmit_delay_high =
2018-11-28 00:41:07 +03:00
( ( dsc_cfg - > initial_xmit_delay &
DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK ) > >
DSC_PPS_MSB_SHIFT ) ;
/* PPS 17 */
2019-02-21 23:20:01 +03:00
pps_payload - > initial_xmit_delay_low =
2018-11-28 00:41:07 +03:00
( dsc_cfg - > initial_xmit_delay & DSC_PPS_LSB_MASK ) ;
/* PPS 18, 19 */
2019-02-21 23:20:01 +03:00
pps_payload - > initial_dec_delay =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( dsc_cfg - > initial_dec_delay ) ;
/* PPS 20 is 0 */
/* PPS 21 */
2019-02-21 23:20:01 +03:00
pps_payload - > initial_scale_value =
2018-11-28 00:41:07 +03:00
dsc_cfg - > initial_scale_value ;
/* PPS 22, 23 */
2019-02-21 23:20:01 +03:00
pps_payload - > scale_increment_interval =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( dsc_cfg - > scale_increment_interval ) ;
/* PPS 24 */
2019-02-21 23:20:01 +03:00
pps_payload - > scale_decrement_interval_high =
2018-11-28 00:41:07 +03:00
( ( dsc_cfg - > scale_decrement_interval &
DSC_PPS_SCALE_DEC_INT_HIGH_MASK ) > >
DSC_PPS_MSB_SHIFT ) ;
/* PPS 25 */
2019-02-21 23:20:01 +03:00
pps_payload - > scale_decrement_interval_low =
2018-11-28 00:41:07 +03:00
( dsc_cfg - > scale_decrement_interval & DSC_PPS_LSB_MASK ) ;
/* PPS 26[7:0], PPS 27[7:5] RESERVED */
/* PPS 27 */
2019-02-21 23:20:01 +03:00
pps_payload - > first_line_bpg_offset =
2018-11-28 00:41:07 +03:00
dsc_cfg - > first_line_bpg_offset ;
/* PPS 28, 29 */
2019-02-21 23:20:01 +03:00
pps_payload - > nfl_bpg_offset =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( dsc_cfg - > nfl_bpg_offset ) ;
/* PPS 30, 31 */
2019-02-21 23:20:01 +03:00
pps_payload - > slice_bpg_offset =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( dsc_cfg - > slice_bpg_offset ) ;
/* PPS 32, 33 */
2019-02-21 23:20:01 +03:00
pps_payload - > initial_offset =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( dsc_cfg - > initial_offset ) ;
/* PPS 34, 35 */
2019-02-21 23:20:01 +03:00
pps_payload - > final_offset = cpu_to_be16 ( dsc_cfg - > final_offset ) ;
2018-11-28 00:41:07 +03:00
/* PPS 36 */
2019-02-21 23:20:01 +03:00
pps_payload - > flatness_min_qp = dsc_cfg - > flatness_min_qp ;
2018-11-28 00:41:07 +03:00
/* PPS 37 */
2019-02-21 23:20:01 +03:00
pps_payload - > flatness_max_qp = dsc_cfg - > flatness_max_qp ;
2018-11-28 00:41:07 +03:00
/* PPS 38, 39 */
2019-02-21 23:20:01 +03:00
pps_payload - > rc_model_size =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( DSC_RC_MODEL_SIZE_CONST ) ;
/* PPS 40 */
2019-02-21 23:20:01 +03:00
pps_payload - > rc_edge_factor = DSC_RC_EDGE_FACTOR_CONST ;
2018-11-28 00:41:07 +03:00
/* PPS 41 */
2019-02-21 23:20:01 +03:00
pps_payload - > rc_quant_incr_limit0 =
2018-11-28 00:41:07 +03:00
dsc_cfg - > rc_quant_incr_limit0 ;
/* PPS 42 */
2019-02-21 23:20:01 +03:00
pps_payload - > rc_quant_incr_limit1 =
2018-11-28 00:41:07 +03:00
dsc_cfg - > rc_quant_incr_limit1 ;
/* PPS 43 */
2019-02-21 23:20:01 +03:00
pps_payload - > rc_tgt_offset = DSC_RC_TGT_OFFSET_LO_CONST |
2018-11-28 00:41:07 +03:00
DSC_RC_TGT_OFFSET_HI_CONST < < DSC_PPS_RC_TGT_OFFSET_HI_SHIFT ;
/* PPS 44 - 57 */
for ( i = 0 ; i < DSC_NUM_BUF_RANGES - 1 ; i + + )
2019-02-21 23:20:01 +03:00
pps_payload - > rc_buf_thresh [ i ] =
2018-11-28 00:41:07 +03:00
dsc_cfg - > rc_buf_thresh [ i ] ;
/* PPS 58 - 87 */
/*
* For DSC sink programming the RC Range parameter fields
* are as follows : Min_qp [ 15 : 11 ] , max_qp [ 10 : 6 ] , offset [ 5 : 0 ]
*/
for ( i = 0 ; i < DSC_NUM_BUF_RANGES ; i + + ) {
2019-02-21 23:20:01 +03:00
pps_payload - > rc_range_parameters [ i ] =
2019-07-10 15:51:40 +03:00
cpu_to_be16 ( ( dsc_cfg - > rc_range_params [ i ] . range_min_qp < <
DSC_PPS_RC_RANGE_MINQP_SHIFT ) |
( dsc_cfg - > rc_range_params [ i ] . range_max_qp < <
DSC_PPS_RC_RANGE_MAXQP_SHIFT ) |
( dsc_cfg - > rc_range_params [ i ] . range_bpg_offset ) ) ;
2018-11-28 00:41:07 +03:00
}
/* PPS 88 */
2019-02-21 23:20:01 +03:00
pps_payload - > native_422_420 = dsc_cfg - > native_422 |
2018-11-28 00:41:07 +03:00
dsc_cfg - > native_420 < < DSC_PPS_NATIVE_420_SHIFT ;
/* PPS 89 */
2019-02-21 23:20:01 +03:00
pps_payload - > second_line_bpg_offset =
2018-11-28 00:41:07 +03:00
dsc_cfg - > second_line_bpg_offset ;
/* PPS 90, 91 */
2019-02-21 23:20:01 +03:00
pps_payload - > nsl_bpg_offset =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( dsc_cfg - > nsl_bpg_offset ) ;
/* PPS 92, 93 */
2019-02-21 23:20:01 +03:00
pps_payload - > second_line_offset_adj =
2018-11-28 00:41:07 +03:00
cpu_to_be16 ( dsc_cfg - > second_line_offset_adj ) ;
/* PPS 94 - 127 are O */
}
2019-02-21 23:20:01 +03:00
EXPORT_SYMBOL ( drm_dsc_pps_payload_pack ) ;
2019-02-21 23:19:59 +03:00
/**
* drm_dsc_compute_rc_parameters ( ) - Write rate control
* parameters to the dsc configuration defined in
2019-02-21 23:20:00 +03:00
* & struct drm_dsc_config in accordance with the DSC 1.2
2019-02-21 23:19:59 +03:00
* specification . Some configuration fields must be present
* beforehand .
*
* @ vdsc_cfg :
* DSC Configuration data partially filled by driver
*/
int drm_dsc_compute_rc_parameters ( struct drm_dsc_config * vdsc_cfg )
{
unsigned long groups_per_line = 0 ;
unsigned long groups_total = 0 ;
unsigned long num_extra_mux_bits = 0 ;
unsigned long slice_bits = 0 ;
unsigned long hrd_delay = 0 ;
unsigned long final_scale = 0 ;
unsigned long rbs_min = 0 ;
2019-02-21 23:20:00 +03:00
if ( vdsc_cfg - > native_420 | | vdsc_cfg - > native_422 ) {
/* Number of groups used to code each line of a slice */
groups_per_line = DIV_ROUND_UP ( vdsc_cfg - > slice_width / 2 ,
DSC_RC_PIXELS_PER_GROUP ) ;
/* chunksize in Bytes */
vdsc_cfg - > slice_chunk_size = DIV_ROUND_UP ( vdsc_cfg - > slice_width / 2 *
vdsc_cfg - > bits_per_pixel ,
( 8 * 16 ) ) ;
} else {
/* Number of groups used to code each line of a slice */
groups_per_line = DIV_ROUND_UP ( vdsc_cfg - > slice_width ,
DSC_RC_PIXELS_PER_GROUP ) ;
/* chunksize in Bytes */
vdsc_cfg - > slice_chunk_size = DIV_ROUND_UP ( vdsc_cfg - > slice_width *
vdsc_cfg - > bits_per_pixel ,
( 8 * 16 ) ) ;
}
2019-02-21 23:19:59 +03:00
if ( vdsc_cfg - > convert_rgb )
num_extra_mux_bits = 3 * ( vdsc_cfg - > mux_word_size +
( 4 * vdsc_cfg - > bits_per_component + 4 )
- 2 ) ;
2019-02-21 23:20:00 +03:00
else if ( vdsc_cfg - > native_422 )
num_extra_mux_bits = 4 * vdsc_cfg - > mux_word_size +
( 4 * vdsc_cfg - > bits_per_component + 4 ) +
3 * ( 4 * vdsc_cfg - > bits_per_component ) - 2 ;
2019-02-21 23:19:59 +03:00
else
num_extra_mux_bits = 3 * vdsc_cfg - > mux_word_size +
( 4 * vdsc_cfg - > bits_per_component + 4 ) +
2 * ( 4 * vdsc_cfg - > bits_per_component ) - 2 ;
/* Number of bits in one Slice */
slice_bits = 8 * vdsc_cfg - > slice_chunk_size * vdsc_cfg - > slice_height ;
while ( ( num_extra_mux_bits > 0 ) & &
( ( slice_bits - num_extra_mux_bits ) % vdsc_cfg - > mux_word_size ) )
num_extra_mux_bits - - ;
if ( groups_per_line < vdsc_cfg - > initial_scale_value - 8 )
vdsc_cfg - > initial_scale_value = groups_per_line + 8 ;
/* scale_decrement_interval calculation according to DSC spec 1.11 */
if ( vdsc_cfg - > initial_scale_value > 8 )
vdsc_cfg - > scale_decrement_interval = groups_per_line /
( vdsc_cfg - > initial_scale_value - 8 ) ;
else
vdsc_cfg - > scale_decrement_interval = DSC_SCALE_DECREMENT_INTERVAL_MAX ;
vdsc_cfg - > final_offset = vdsc_cfg - > rc_model_size -
( vdsc_cfg - > initial_xmit_delay *
vdsc_cfg - > bits_per_pixel + 8 ) / 16 + num_extra_mux_bits ;
if ( vdsc_cfg - > final_offset > = vdsc_cfg - > rc_model_size ) {
DRM_DEBUG_KMS ( " FinalOfs < RcModelSze for this InitialXmitDelay \n " ) ;
return - ERANGE ;
}
final_scale = ( vdsc_cfg - > rc_model_size * 8 ) /
( vdsc_cfg - > rc_model_size - vdsc_cfg - > final_offset ) ;
if ( vdsc_cfg - > slice_height > 1 )
/*
* NflBpgOffset is 16 bit value with 11 fractional bits
* hence we multiply by 2 ^ 11 for preserving the
* fractional part
*/
vdsc_cfg - > nfl_bpg_offset = DIV_ROUND_UP ( ( vdsc_cfg - > first_line_bpg_offset < < 11 ) ,
( vdsc_cfg - > slice_height - 1 ) ) ;
else
vdsc_cfg - > nfl_bpg_offset = 0 ;
/* Number of groups used to code the entire slice */
groups_total = groups_per_line * vdsc_cfg - > slice_height ;
/* slice_bpg_offset is 16 bit value with 11 fractional bits */
vdsc_cfg - > slice_bpg_offset = DIV_ROUND_UP ( ( ( vdsc_cfg - > rc_model_size -
vdsc_cfg - > initial_offset +
num_extra_mux_bits ) < < 11 ) ,
groups_total ) ;
if ( final_scale > 9 ) {
/*
* ScaleIncrementInterval =
* finaloffset / ( ( NflBpgOffset + SliceBpgOffset ) * 8 ( finalscale - 1.125 ) )
* as ( NflBpgOffset + SliceBpgOffset ) has 11 bit fractional value ,
* we need divide by 2 ^ 11 from pstDscCfg values
*/
vdsc_cfg - > scale_increment_interval =
( vdsc_cfg - > final_offset * ( 1 < < 11 ) ) /
( ( vdsc_cfg - > nfl_bpg_offset +
vdsc_cfg - > slice_bpg_offset ) *
( final_scale - 9 ) ) ;
} else {
/*
* If finalScaleValue is less than or equal to 9 , a value of 0 should
* be used to disable the scale increment at the end of the slice
*/
vdsc_cfg - > scale_increment_interval = 0 ;
}
/*
* DSC spec mentions that bits_per_pixel specifies the target
* bits / pixel ( bpp ) rate that is used by the encoder ,
* in steps of 1 / 16 of a bit per pixel
*/
rbs_min = vdsc_cfg - > rc_model_size - vdsc_cfg - > initial_offset +
DIV_ROUND_UP ( vdsc_cfg - > initial_xmit_delay *
vdsc_cfg - > bits_per_pixel , 16 ) +
groups_per_line * vdsc_cfg - > first_line_bpg_offset ;
hrd_delay = DIV_ROUND_UP ( ( rbs_min * 16 ) , vdsc_cfg - > bits_per_pixel ) ;
vdsc_cfg - > rc_bits = ( hrd_delay * vdsc_cfg - > bits_per_pixel ) / 16 ;
vdsc_cfg - > initial_dec_delay = hrd_delay - vdsc_cfg - > initial_xmit_delay ;
return 0 ;
}
EXPORT_SYMBOL ( drm_dsc_compute_rc_parameters ) ;