Introduce MSM-specific DSC helper methods, as some calculations are common between DP and DSC. Changes in v2: - Moved files up to msm/ directory - Dropped get_comp_ratio() helper - Used drm_int2fixp() to convert to integers to fp - Style changes to improve readability - Dropped unused bpp variable in msm_dsc_get_dce_bytes_per_line() - Changed msm_dsc_get_slice_per_intf() to a static inline method - Dropped last division step of msm_dsc_get_pclk_per_line() and changed method name accordingly - Changed DSC_BPP macro to drm_dsc_get_bpp_int() helper method - Fixed some math issues caused by passing in incorrect types to drm_fixed methods in get_bytes_per_soft_slice() Signed-off-by: Jessica Zhang <quic_jesszhan@xxxxxxxxxxx> --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/msm_dsc_helper.c | 53 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_dsc_helper.h | 42 ++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 7274c41228ed..b814fc80e2d5 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -94,6 +94,7 @@ msm-y += \ msm_atomic_tracepoints.o \ msm_debugfs.o \ msm_drv.o \ + msm_dsc_helper.o \ msm_fb.o \ msm_fence.o \ msm_gem.o \ diff --git a/drivers/gpu/drm/msm/msm_dsc_helper.c b/drivers/gpu/drm/msm/msm_dsc_helper.c new file mode 100644 index 000000000000..60b73e17e6eb --- /dev/null +++ b/drivers/gpu/drm/msm/msm_dsc_helper.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <drm/drm_fixed.h> + +#include "msm_drv.h" +#include "msm_dsc_helper.h" + +static s64 get_bytes_per_soft_slice(struct drm_dsc_config *dsc, int intf_width, u32 src_bpp) +{ + int bpp = msm_dsc_get_bpp_int(dsc); + s64 numerator_fp, denominator_fp; + s64 comp_ratio_fp = drm_fixp_from_fraction(src_bpp, bpp); + + numerator_fp = drm_int2fixp(dsc->slice_width * 3); + denominator_fp = drm_fixp_from_fraction(comp_ratio_fp * 8, drm_int2fixp(bpp)); + + return drm_fixp_div(numerator_fp, denominator_fp); +} + +u32 msm_dsc_get_eol_byte_num(struct drm_dsc_config *dsc, int intf_width, u32 src_bpp) +{ + u32 bytes_per_soft_slice, extra_eol_bytes, bytes_per_intf; + s64 bytes_per_soft_slice_fp; + int slice_per_intf = msm_dsc_get_slice_per_intf(dsc, intf_width); + + bytes_per_soft_slice_fp = get_bytes_per_soft_slice(dsc, intf_width, src_bpp); + bytes_per_soft_slice = drm_fixp2int_ceil(bytes_per_soft_slice_fp); + + bytes_per_intf = bytes_per_soft_slice * slice_per_intf; + extra_eol_bytes = bytes_per_intf % 3; + if (extra_eol_bytes != 0) + extra_eol_bytes = 3 - extra_eol_bytes; + + return extra_eol_bytes; +} + +int msm_dsc_get_uncompressed_pclk_per_line(struct drm_dsc_config *dsc, int intf_width, u32 src_bpp) +{ + s64 data_width; + + if (!dsc->slice_width || (intf_width < dsc->slice_width)) + return -EINVAL; + + data_width = drm_fixp_mul(dsc->slice_count, + get_bytes_per_soft_slice(dsc, intf_width, src_bpp)); + + return drm_fixp2int_ceil(data_width); +} diff --git a/drivers/gpu/drm/msm/msm_dsc_helper.h b/drivers/gpu/drm/msm/msm_dsc_helper.h new file mode 100644 index 000000000000..743cd324b7d9 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_dsc_helper.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved + */ + +#ifndef MSM_DSC_HELPER_H_ +#define MSM_DSC_HELPER_H_ + +#include <drm/display/drm_dsc_helper.h> +#include <drm/drm_modes.h> + +/* + * Helper methods for MSM specific DSC calculations that are common between timing engine, + * DSI, and DP. + */ + +static inline int msm_dsc_get_bpp_int(struct drm_dsc_config *dsc) +{ + WARN_ON_ONCE(dsc->bits_per_pixel & 0xf); + return dsc->bits_per_pixel >> 4; +} + +static inline int msm_dsc_get_slice_per_intf(struct drm_dsc_config *dsc, int intf_width) +{ + return DIV_ROUND_UP(intf_width, dsc->slice_width); +} + +static inline u32 msm_dsc_get_dce_bytes_per_line(struct drm_dsc_config *dsc, int intf_width) +{ + return DIV_ROUND_UP(msm_dsc_get_bpp_int(dsc) * intf_width, 8); +} + +u32 msm_dsc_get_eol_byte_num(struct drm_dsc_config *dsc, int intf_width, u32 src_bpp); +u32 msm_dsc_get_dce_bytes_per_line(struct drm_dsc_config *dsc, int intf_width); + +/* Calculate uncompressed pclk per line. This value will then be passed along to + * DSI and DP to calculate pclk_per_line. This is because DSI and DP divide the + * uncompressed pclk_per_line by different values depending on if widebus is enabled. + */ +int msm_dsc_get_uncompressed_pclk_per_line(struct drm_dsc_config *dsc, + int intf_width, u32 src_bpp); +#endif /* MSM_DSC_HELPER_H_ */ -- 2.39.2