diff --git a/include/uapi/display/drm/msm_drm_pp.h b/include/uapi/display/drm/msm_drm_pp.h index eb18c90c72..3fa7323ac4 100644 --- a/include/uapi/display/drm/msm_drm_pp.h +++ b/include/uapi/display/drm/msm_drm_pp.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _MSM_DRM_PP_H_ @@ -683,4 +683,40 @@ struct drm_msm_rc_mask_cfg { __u64 cfg_param_09[RC_DATA_SIZE_MAX]; }; +#define FP16_SUPPORTED +#define FP16_GC_FLAG_ALPHA_EN (1 << 0) + + /* FP16 GC mode options */ +#define FP16_GC_MODE_INVALID 0 +#define FP16_GC_MODE_SRGB 1 +#define FP16_GC_MODE_PQ 2 + +/** + * struct drm_msm_fp16_gc - FP16 GC configuration structure + * @in flags - Settings flags for FP16 GC + * @in mode - Gamma correction mode to use for FP16 GC + */ +struct drm_msm_fp16_gc { + __u64 flags; + __u64 mode; +}; + +/** + * struct drm_msm_fp16_csc - FP16 CSC configuration structure + * @in flags - Settings flags for FP16 CSC. Currently unused + * @in cfg_param_0_len - Length of data for cfg_param_0 + * @in cfg_param_0 - Data for param 0. Max size is FP16_CSC_CFG0_PARAM_LEN + * @in cfg_param_1_len - Length of data for cfg_param_1 + * @in cfg_param_1 - Data for param 1. Max size is FP16_CSC_CFG1_PARAM_LEN + */ +#define FP16_CSC_CFG0_PARAM_LEN 12 +#define FP16_CSC_CFG1_PARAM_LEN 8 +struct drm_msm_fp16_csc { + __u64 flags; + __u32 cfg_param_0_len; + __u32 cfg_param_0[FP16_CSC_CFG0_PARAM_LEN]; + __u32 cfg_param_1_len; + __u32 cfg_param_1[FP16_CSC_CFG1_PARAM_LEN]; +}; + #endif /* _MSM_DRM_PP_H_ */ diff --git a/include/uapi/display/drm/sde_drm.h b/include/uapi/display/drm/sde_drm.h index 765c0391a0..9e385c67d6 100644 --- a/include/uapi/display/drm/sde_drm.h +++ b/include/uapi/display/drm/sde_drm.h @@ -64,6 +64,14 @@ extern "C" { */ #define DRM_FORMAT_MOD_QCOM_TILE fourcc_mod_code(QCOM, 0x8) +/** + * @DRM_FORMAT_MOD_QCOM_ALPHA_SWAP: Refers to a pixel format for which + * its alpha ordering has been reversed. + * Implementation may be platform and + * base-format specific. + */ +#define DRM_FORMAT_MOD_QCOM_ALPHA_SWAP fourcc_mod_code(QCOM, 0x10) + /** * Blend operations for "blend_op" property * diff --git a/include/uapi/display/media/mmm_color_fmt.h b/include/uapi/display/media/mmm_color_fmt.h index 49f02cd487..193933a069 100644 --- a/include/uapi/display/media/mmm_color_fmt.h +++ b/include/uapi/display/media/mmm_color_fmt.h @@ -765,6 +765,52 @@ enum mmm_color_fmts { * + UV_Stride * UV_Scanlines), 4096) */ MMM_COLOR_FMT_NV12_512, + /* Venus RGBA FP16 UBWC: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGBA plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 8, 256) + * RGB_Scanlines = align(Height, 16) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * RGB_TileWidth = 8 pixels across is 1 tile + * RGB_TileHeight = 4 pixels + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size, 4096) + */ + MMM_COLOR_FMT_RGBA16161616F_UBWC, }; /* @@ -1087,6 +1133,10 @@ static inline unsigned int MMM_COLOR_FMT_RGB_STRIDE(unsigned int color_fmt, case MMM_COLOR_FMT_RGBA1010102_UBWC: alignment = 256; break; + case MMM_COLOR_FMT_RGBA16161616F_UBWC: + alignment = 256; + bpp = 8; + break; default: goto invalid_input; } @@ -1112,6 +1162,7 @@ static inline unsigned int MMM_COLOR_FMT_RGB_SCANLINES(unsigned int color_fmt, case MMM_COLOR_FMT_RGBA8888_UBWC: case MMM_COLOR_FMT_RGBA1010102_UBWC: case MMM_COLOR_FMT_RGB565_UBWC: + case MMM_COLOR_FMT_RGBA16161616F_UBWC: alignment = 16; break; default: @@ -1138,6 +1189,9 @@ static inline unsigned int MMM_COLOR_FMT_RGB_META_STRIDE(unsigned int color_fmt, case MMM_COLOR_FMT_RGB565_UBWC: rgb_tile_width = 16; break; + case MMM_COLOR_FMT_RGBA16161616F_UBWC: + rgb_tile_width = 8; + break; default: goto invalid_input; } @@ -1161,6 +1215,7 @@ static inline unsigned int MMM_COLOR_FMT_RGB_META_SCANLINES( case MMM_COLOR_FMT_RGBA8888_UBWC: case MMM_COLOR_FMT_RGBA1010102_UBWC: case MMM_COLOR_FMT_RGB565_UBWC: + case MMM_COLOR_FMT_RGBA16161616F_UBWC: rgb_tile_height = 4; break; default: @@ -1307,6 +1362,7 @@ static inline unsigned int MMM_COLOR_FMT_BUFFER_SIZE(unsigned int color_fmt, case MMM_COLOR_FMT_RGBA8888_UBWC: case MMM_COLOR_FMT_RGBA1010102_UBWC: case MMM_COLOR_FMT_RGB565_UBWC: + case MMM_COLOR_FMT_RGBA16161616F_UBWC: rgb_ubwc_plane = MMM_COLOR_FMT_ALIGN(rgb_stride * rgb_scanlines, 4096); rgb_meta_stride = MMM_COLOR_FMT_RGB_META_STRIDE(color_fmt, diff --git a/msm/msm_drv.h b/msm/msm_drv.h index c49ea31a58..e61e5d9da1 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -111,6 +111,8 @@ enum msm_mdp_plane_property { PLANE_PROP_VIG_IGC, PLANE_PROP_DMA_IGC, PLANE_PROP_DMA_GC, + PLANE_PROP_FP16_GC, + PLANE_PROP_FP16_CSC, /* # of blob properties */ PLANE_PROP_BLOBCOUNT, @@ -132,6 +134,8 @@ enum msm_mdp_plane_property { PLANE_PROP_SCALER_V1, PLANE_PROP_SCALER_V2, PLANE_PROP_INVERSE_PMA, + PLANE_PROP_FP16_IGC, + PLANE_PROP_FP16_UNMULT, /* enum/bitmask properties */ PLANE_PROP_BLEND_OP, diff --git a/msm/sde/sde_formats.c b/msm/sde/sde_formats.c index 7e6be85e21..56b1e46f43 100644 --- a/msm/sde/sde_formats.c +++ b/msm/sde/sde_formats.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -410,6 +410,18 @@ static const struct sde_format sde_format_map[] = { false, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), + INTERLEAVED_RGB_FMT(ARGB16161616F, + COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 8, SDE_FORMAT_FLAG_FP16, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR16161616F, + COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 8, SDE_FORMAT_FLAG_FP16, + SDE_FETCH_LINEAR, 1), + PSEUDO_YUV_FMT(NV12, 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C1_B_Cb, C2_R_Cr, @@ -471,6 +483,21 @@ static const struct sde_format sde_format_map[] = { SDE_FETCH_LINEAR, 3), }; +/* Base formats supporting the alpha swapping modifier */ +static const struct sde_format sde_format_map_alpha_swap[] = { + INTERLEAVED_RGB_FMT(ARGB16161616F, + COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 8, SDE_FORMAT_FLAG_FP16 | SDE_FORMAT_FLAG_ALPHA_SWAP, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR16161616F, + COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 8, SDE_FORMAT_FLAG_FP16 | SDE_FORMAT_FLAG_ALPHA_SWAP, + SDE_FETCH_LINEAR, 1), +}; + /* * A5x tile formats tables: * These tables hold the A5x tile formats supported. @@ -608,6 +635,12 @@ static const struct sde_format sde_format_map_ubwc[] = { true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED, SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC), + INTERLEAVED_RGB_FMT_TILED(ABGR16161616F, + COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, COLOR_16BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 8, SDE_FORMAT_FLAG_FP16 | SDE_FORMAT_FLAG_COMPRESSED, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC), + PSEUDO_YUV_FMT_TILED(NV12, 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C1_B_Cb, C2_R_Cr, @@ -691,6 +724,7 @@ static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt) {DRM_FORMAT_ABGR2101010, MMM_COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_XBGR2101010, MMM_COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_BGR565, MMM_COLOR_FMT_RGB565_UBWC}, + {DRM_FORMAT_ABGR16161616F, MMM_COLOR_FMT_RGBA16161616F_UBWC}, }; int color_fmt = -1; int i; @@ -1240,6 +1274,10 @@ const struct sde_format *sde_get_sde_format_ext( map = sde_format_map; map_size = ARRAY_SIZE(sde_format_map); break; + case DRM_FORMAT_MOD_QCOM_ALPHA_SWAP: + map = sde_format_map_alpha_swap; + map_size = ARRAY_SIZE(sde_format_map_alpha_swap); + break; case DRM_FORMAT_MOD_QCOM_COMPRESSED: case DRM_FORMAT_MOD_QCOM_COMPRESSED | DRM_FORMAT_MOD_QCOM_TILE: map = sde_format_map_ubwc; diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index ce5c17e360..2e2e2e29d1 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -267,6 +267,7 @@ enum { }; enum { + VIG_SUBBLOCK_INDEX, VIG_QSEED_OFF, VIG_QSEED_LEN, VIG_CSC_OFF, @@ -276,6 +277,10 @@ enum { VIG_GAMUT_PROP, VIG_IGC_PROP, VIG_INVERSE_PMA, + VIG_FP16_IGC_PROP, + VIG_FP16_GC_PROP, + VIG_FP16_CSC_PROP, + VIG_FP16_UNMULT_PROP, VIG_PROP_MAX, }; @@ -292,6 +297,10 @@ enum { DMA_GC_PROP, DMA_DGM_INVERSE_PMA, DMA_CSC_OFF, + DMA_FP16_IGC_PROP, + DMA_FP16_GC_PROP, + DMA_FP16_CSC_PROP, + DMA_FP16_UNMULT_PROP, DMA_PROP_MAX, }; @@ -664,16 +673,34 @@ static struct sde_prop_type sspp_prop[] = { }; static struct sde_prop_type vig_prop[] = { - {VIG_QSEED_OFF, "qcom,sde-vig-qseed-off", false, PROP_TYPE_U32}, - {VIG_QSEED_LEN, "qcom,sde-vig-qseed-size", false, PROP_TYPE_U32}, - {VIG_CSC_OFF, "qcom,sde-vig-csc-off", false, PROP_TYPE_U32}, - {VIG_HSIC_PROP, "qcom,sde-vig-hsic", false, PROP_TYPE_U32_ARRAY}, - {VIG_MEMCOLOR_PROP, "qcom,sde-vig-memcolor", false, - PROP_TYPE_U32_ARRAY}, - {VIG_PCC_PROP, "qcom,sde-vig-pcc", false, PROP_TYPE_U32_ARRAY}, - {VIG_GAMUT_PROP, "qcom,sde-vig-gamut", false, PROP_TYPE_U32_ARRAY}, - {VIG_IGC_PROP, "qcom,sde-vig-igc", false, PROP_TYPE_U32_ARRAY}, - {VIG_INVERSE_PMA, "qcom,sde-vig-inverse-pma", false, PROP_TYPE_BOOL}, + [VIG_SUBBLOCK_INDEX] = {VIG_SUBBLOCK_INDEX, "cell-index", false, + PROP_TYPE_U32}, + [VIG_QSEED_OFF] = {VIG_QSEED_OFF, "qcom,sde-vig-qseed-off", false, + PROP_TYPE_U32}, + [VIG_QSEED_LEN] = {VIG_QSEED_LEN, "qcom,sde-vig-qseed-size", false, + PROP_TYPE_U32}, + [VIG_CSC_OFF] = {VIG_CSC_OFF, "qcom,sde-vig-csc-off", false, + PROP_TYPE_U32}, + [VIG_HSIC_PROP] = {VIG_HSIC_PROP, "qcom,sde-vig-hsic", false, + PROP_TYPE_U32_ARRAY}, + [VIG_MEMCOLOR_PROP] = {VIG_MEMCOLOR_PROP, "qcom,sde-vig-memcolor", + false, PROP_TYPE_U32_ARRAY}, + [VIG_PCC_PROP] = {VIG_PCC_PROP, "qcom,sde-vig-pcc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_GAMUT_PROP] = {VIG_GAMUT_PROP, "qcom,sde-vig-gamut", false, + PROP_TYPE_U32_ARRAY}, + [VIG_IGC_PROP] = {VIG_IGC_PROP, "qcom,sde-vig-igc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_INVERSE_PMA] = {VIG_INVERSE_PMA, "qcom,sde-vig-inverse-pma", false, + PROP_TYPE_BOOL}, + [VIG_FP16_IGC_PROP] = {VIG_FP16_IGC_PROP, "qcom,sde-fp16-igc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_FP16_GC_PROP] = {VIG_FP16_GC_PROP, "qcom,sde-fp16-gc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_FP16_CSC_PROP] = {VIG_FP16_CSC_PROP, "qcom,sde-fp16-csc", false, + PROP_TYPE_U32_ARRAY}, + [VIG_FP16_UNMULT_PROP] = {VIG_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult", + false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type rgb_prop[] = { @@ -683,12 +710,24 @@ static struct sde_prop_type rgb_prop[] = { }; static struct sde_prop_type dma_prop[] = { - {DMA_SUBBLOCK_INDEX, "cell-index", false, PROP_TYPE_U32}, - {DMA_IGC_PROP, "qcom,sde-dma-igc", false, PROP_TYPE_U32_ARRAY}, - {DMA_GC_PROP, "qcom,sde-dma-gc", false, PROP_TYPE_U32_ARRAY}, - {DMA_DGM_INVERSE_PMA, "qcom,sde-dma-inverse-pma", false, - PROP_TYPE_BOOL}, - {DMA_CSC_OFF, "qcom,sde-dma-csc-off", false, PROP_TYPE_U32}, + [DMA_SUBBLOCK_INDEX] = {DMA_SUBBLOCK_INDEX, "cell-index", false, + PROP_TYPE_U32}, + [DMA_IGC_PROP] = {DMA_IGC_PROP, "qcom,sde-dma-igc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_GC_PROP] = {DMA_GC_PROP, "qcom,sde-dma-gc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_DGM_INVERSE_PMA] = {DMA_DGM_INVERSE_PMA, + "qcom,sde-dma-inverse-pma", false, PROP_TYPE_BOOL}, + [DMA_CSC_OFF] = {DMA_CSC_OFF, "qcom,sde-dma-csc-off", false, + PROP_TYPE_U32}, + [DMA_FP16_IGC_PROP] = {DMA_FP16_IGC_PROP, "qcom,sde-fp16-igc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_FP16_GC_PROP] = {DMA_FP16_GC_PROP, "qcom,sde-fp16-gc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_FP16_CSC_PROP] = {DMA_FP16_CSC_PROP, "qcom,sde-fp16-csc", false, + PROP_TYPE_U32_ARRAY}, + [DMA_FP16_UNMULT_PROP] = {DMA_FP16_UNMULT_PROP, "qcom,sde-fp16-unmult", + false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type ctl_prop[] = { @@ -1319,83 +1358,58 @@ static int _add_to_irq_offset_list(struct sde_mdss_cfg *sde_cfg, return 0; } +/* VIG color management (VCM) feature setup */ +static bool _sde_sspp_setup_vcm(struct sde_sspp_cfg *sspp, + const struct sde_dt_props *props, const char *name, + struct sde_pp_blk *blk, u32 type, u32 prop, bool versioned) +{ + bool exists = props->exists[prop]; + + if (exists) { + blk->id = type; + blk->len = 0; + set_bit(type, (unsigned long *) &sspp->features_ext); + blk->base = PROP_VALUE_ACCESS(props->values, prop, 0); + snprintf(blk->name, SDE_HW_BLK_NAME_LEN, "%s%u", name, + sspp->id - SSPP_VIG0); + if (versioned) + blk->version = PROP_VALUE_ACCESS(props->values, + prop, 1); + } else { + blk->id = 0; + } + + return exists; +} + static void _sde_sspp_setup_vigs_pp(struct sde_dt_props *props, struct sde_mdss_cfg *sde_cfg, struct sde_sspp_cfg *sspp) { struct sde_sspp_sub_blks *sblk = sspp->sblk; + if (!props) + return; - sblk->csc_blk.id = SDE_SSPP_CSC; - snprintf(sblk->csc_blk.name, SDE_HW_BLK_NAME_LEN, - "sspp_csc%u", sspp->id - SSPP_VIG0); - if (sde_cfg->csc_type == SDE_SSPP_CSC) { - set_bit(SDE_SSPP_CSC, &sspp->features); - sblk->csc_blk.base = PROP_VALUE_ACCESS(props->values, - VIG_CSC_OFF, 0); - } else if (sde_cfg->csc_type == SDE_SSPP_CSC_10BIT) { - set_bit(SDE_SSPP_CSC_10BIT, &sspp->features); - sblk->csc_blk.base = PROP_VALUE_ACCESS(props->values, - VIG_CSC_OFF, 0); - } + if (sde_cfg->csc_type == SDE_SSPP_CSC) + _sde_sspp_setup_vcm(sspp, props, "sspp_csc", &sblk->csc_blk, + SDE_SSPP_CSC, VIG_CSC_OFF, false); + else if (sde_cfg->csc_type == SDE_SSPP_CSC_10BIT) + _sde_sspp_setup_vcm(sspp, props, "sspp_csc", &sblk->csc_blk, + SDE_SSPP_CSC_10BIT, VIG_CSC_OFF, false); - sblk->hsic_blk.id = SDE_SSPP_HSIC; - snprintf(sblk->hsic_blk.name, SDE_HW_BLK_NAME_LEN, - "sspp_hsic%u", sspp->id - SSPP_VIG0); - if (props->exists[VIG_HSIC_PROP]) { - sblk->hsic_blk.base = PROP_VALUE_ACCESS(props->values, - VIG_HSIC_PROP, 0); - sblk->hsic_blk.version = PROP_VALUE_ACCESS( - props->values, VIG_HSIC_PROP, 1); - sblk->hsic_blk.len = 0; - set_bit(SDE_SSPP_HSIC, &sspp->features); - } + _sde_sspp_setup_vcm(sspp, props, "sspp_hsic", &sblk->hsic_blk, + SDE_SSPP_HSIC, VIG_HSIC_PROP, true); - sblk->memcolor_blk.id = SDE_SSPP_MEMCOLOR; - snprintf(sblk->memcolor_blk.name, SDE_HW_BLK_NAME_LEN, - "sspp_memcolor%u", sspp->id - SSPP_VIG0); - if (props->exists[VIG_MEMCOLOR_PROP]) { - sblk->memcolor_blk.base = PROP_VALUE_ACCESS( - props->values, VIG_MEMCOLOR_PROP, 0); - sblk->memcolor_blk.version = PROP_VALUE_ACCESS( - props->values, VIG_MEMCOLOR_PROP, 1); - sblk->memcolor_blk.len = 0; - set_bit(SDE_SSPP_MEMCOLOR, &sspp->features); - } + _sde_sspp_setup_vcm(sspp, props, "sspp_memcolor", &sblk->memcolor_blk, + SDE_SSPP_MEMCOLOR, VIG_MEMCOLOR_PROP, true); - sblk->pcc_blk.id = SDE_SSPP_PCC; - snprintf(sblk->pcc_blk.name, SDE_HW_BLK_NAME_LEN, - "sspp_pcc%u", sspp->id - SSPP_VIG0); - if (props->exists[VIG_PCC_PROP]) { - sblk->pcc_blk.base = PROP_VALUE_ACCESS(props->values, - VIG_PCC_PROP, 0); - sblk->pcc_blk.version = PROP_VALUE_ACCESS(props->values, - VIG_PCC_PROP, 1); - sblk->pcc_blk.len = 0; - set_bit(SDE_SSPP_PCC, &sspp->features); - } + _sde_sspp_setup_vcm(sspp, props, "sspp_pcc", &sblk->pcc_blk, + SDE_SSPP_PCC, VIG_PCC_PROP, true); - if (props->exists[VIG_GAMUT_PROP]) { - sblk->gamut_blk.id = SDE_SSPP_VIG_GAMUT; - snprintf(sblk->gamut_blk.name, SDE_HW_BLK_NAME_LEN, - "sspp_vig_gamut%u", sspp->id - SSPP_VIG0); - sblk->gamut_blk.base = PROP_VALUE_ACCESS(props->values, - VIG_GAMUT_PROP, 0); - sblk->gamut_blk.version = PROP_VALUE_ACCESS( - props->values, VIG_GAMUT_PROP, 1); - sblk->gamut_blk.len = 0; - set_bit(SDE_SSPP_VIG_GAMUT, &sspp->features); - } + _sde_sspp_setup_vcm(sspp, props, "sspp_vig_gamut", &sblk->gamut_blk, + SDE_SSPP_VIG_GAMUT, VIG_GAMUT_PROP, true); - if (props->exists[VIG_IGC_PROP]) { - sblk->igc_blk[0].id = SDE_SSPP_VIG_IGC; - snprintf(sblk->igc_blk[0].name, SDE_HW_BLK_NAME_LEN, - "sspp_vig_igc%u", sspp->id - SSPP_VIG0); - sblk->igc_blk[0].base = PROP_VALUE_ACCESS(props->values, - VIG_IGC_PROP, 0); - sblk->igc_blk[0].version = PROP_VALUE_ACCESS( - props->values, VIG_IGC_PROP, 1); - sblk->igc_blk[0].len = 0; - set_bit(SDE_SSPP_VIG_IGC, &sspp->features); - } + _sde_sspp_setup_vcm(sspp, props, "sspp_vig_igc", &sblk->igc_blk[0], + SDE_SSPP_VIG_IGC, VIG_IGC_PROP, true); if (props->exists[VIG_INVERSE_PMA]) set_bit(SDE_SSPP_INVERSE_PMA, &sspp->features); @@ -1404,21 +1418,59 @@ static void _sde_sspp_setup_vigs_pp(struct sde_dt_props *props, static int _sde_sspp_setup_vigs(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { - int i; - struct sde_dt_props *props; + int i = 0, j = 0, rc = 0; + struct sde_dt_props *props[SSPP_SUBBLK_COUNT_MAX] = {NULL, NULL}; + struct sde_dt_props *props_tmp = NULL; struct device_node *snp = NULL; struct sde_sc_cfg *sc_cfg = sde_cfg->sc_cfg; - int vig_count = 0; + int vig_count = 0, vcm_count = 0; const char *type; snp = of_get_child_by_name(np, sspp_prop[SSPP_VIG_BLOCKS].prop_name); if (!snp) return 0; - props = sde_get_dt_props(snp, VIG_PROP_MAX, vig_prop, - ARRAY_SIZE(vig_prop), NULL); - if (IS_ERR(props)) - return PTR_ERR(props); + /* Assume sub nodes are in rect order */ + vcm_count = of_get_child_count(snp); + if (vcm_count > 0) { + struct device_node *vcm_snp; + + if (vcm_count > SSPP_SUBBLK_COUNT_MAX) { + SDE_ERROR("exceeded max vcm sub-block count!"); + vcm_count = SSPP_SUBBLK_COUNT_MAX; + } + for_each_child_of_node(snp, vcm_snp) { + + props_tmp = sde_get_dt_props(vcm_snp, + VIG_PROP_MAX, vig_prop, + ARRAY_SIZE(vig_prop), NULL); + if (IS_ERR(props_tmp)) { + rc = PTR_ERR(props_tmp); + props_tmp = NULL; + goto end; + } + + if (!props_tmp->exists[VIG_SUBBLOCK_INDEX]) { + SDE_ERROR("vcm rect index must be specified!"); + goto end; + } + + i = PROP_VALUE_ACCESS(props_tmp->values, VIG_SUBBLOCK_INDEX, 0); + if (i >= SSPP_SUBBLK_COUNT_MAX) { + SDE_ERROR("invalid vcm rect index: %d", i); + goto end; + } else if (props[i] != NULL) { + SDE_ERROR("vcm rect index must be unique! repeat: %d", i); + goto end; + } + + props[i] = props_tmp; + props_tmp = NULL; + } + } else { + props[0] = sde_get_dt_props(snp, VIG_PROP_MAX, vig_prop, + ARRAY_SIZE(vig_prop), NULL); + } for (i = 0; i < sde_cfg->sspp_count; ++i) { struct sde_sspp_cfg *sspp = sde_cfg->sspp + i; @@ -1445,21 +1497,59 @@ static int _sde_sspp_setup_vigs(struct device_node *np, sblk->format_list = sde_cfg->vig_formats; sblk->virt_format_list = sde_cfg->virt_vig_formats; + sblk->num_fp16_igc_blk = 0; + sblk->num_fp16_gc_blk = 0; + sblk->num_fp16_csc_blk = 0; + sblk->num_fp16_unmult_blk = 0; - if ((sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED2) || + for (j = 0; j < SSPP_SUBBLK_COUNT_MAX; j++) { + if (!props[j]) + continue; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_fp16_igc", + &sblk->fp16_igc_blk[j], + SDE_SSPP_FP16_IGC, VIG_FP16_IGC_PROP, + true)) + sblk->num_fp16_igc_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_fp16_gc", + &sblk->fp16_gc_blk[j], + SDE_SSPP_FP16_GC, VIG_FP16_GC_PROP, + true)) + sblk->num_fp16_gc_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_fp16_csc", + &sblk->fp16_csc_blk[j], + SDE_SSPP_FP16_CSC, VIG_FP16_CSC_PROP, + true)) + sblk->num_fp16_csc_blk += 1; + + if (_sde_sspp_setup_vcm(sspp, props[j], + "sspp_vig_fp16_unmult", + &sblk->fp16_unmult_blk[j], + SDE_SSPP_FP16_UNMULT, + VIG_FP16_UNMULT_PROP, true)) + sblk->num_fp16_unmult_blk += 1; + } + + /* PP + scaling only supported on VIG rect 0 */ + if (props[0] && ((sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED2) || (sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3) || - (sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3LITE)) { + (sde_cfg->qseed_sw_lib_rev == SDE_SSPP_SCALER_QSEED3LITE))) { set_bit(sde_cfg->qseed_sw_lib_rev, &sspp->features); sblk->scaler_blk.id = sde_cfg->qseed_sw_lib_rev; - sblk->scaler_blk.base = PROP_VALUE_ACCESS(props->values, - VIG_QSEED_OFF, 0); - sblk->scaler_blk.len = PROP_VALUE_ACCESS(props->values, - VIG_QSEED_LEN, 0); + sblk->scaler_blk.base = PROP_VALUE_ACCESS( + props[0]->values, VIG_QSEED_OFF, 0); + sblk->scaler_blk.len = PROP_VALUE_ACCESS( + props[0]->values, VIG_QSEED_LEN, 0); snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN, "sspp_scaler%u", sspp->id - SSPP_VIG0); } - _sde_sspp_setup_vigs_pp(props, sde_cfg, sspp); + _sde_sspp_setup_vigs_pp(props[0], sde_cfg, sspp); if (sde_cfg->true_inline_rot_rev > 0) { set_bit(SDE_SSPP_TRUE_INLINE_ROT, &sspp->features); @@ -1503,8 +1593,12 @@ static int _sde_sspp_setup_vigs(struct device_node *np, } - sde_put_dt_props(props); - return 0; +end: + sde_put_dt_props(props_tmp); + for (i = 0; i < SSPP_SUBBLK_COUNT_MAX; i++) + sde_put_dt_props(props[i]); + + return rc; } static void _sde_sspp_setup_rgbs_pp(struct sde_dt_props *props, @@ -1716,6 +1810,34 @@ static int _sde_sspp_setup_dmas(struct device_node *np, _sde_sspp_setup_dgm(sspp, props[j], "sspp_dgm_csc", &sblk->dgm_csc_blk[j], SDE_SSPP_DGM_CSC, DMA_CSC_OFF, false); + + if (props[j]->exists[DMA_FP16_IGC_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_fp16_igc", + &sblk->fp16_igc_blk[j], + SDE_SSPP_FP16_IGC, + DMA_FP16_IGC_PROP, true); + + if (props[j]->exists[DMA_FP16_GC_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_fp16_gc", + &sblk->fp16_gc_blk[j], + SDE_SSPP_FP16_GC, + DMA_FP16_GC_PROP, true); + + if (props[j]->exists[DMA_FP16_CSC_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_fp16_csc", + &sblk->fp16_csc_blk[j], + SDE_SSPP_FP16_CSC, + DMA_FP16_CSC_PROP, true); + + if (props[j]->exists[DMA_FP16_UNMULT_PROP]) + _sde_sspp_setup_dgm(sspp, props[j], + "sspp_dma_fp16_unmult", + &sblk->fp16_unmult_blk[j], + SDE_SSPP_FP16_UNMULT, + DMA_FP16_UNMULT_PROP, true); } } @@ -4423,6 +4545,9 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, /* DMA pipe input formats */ dma_list_size = ARRAY_SIZE(plane_formats); + if (sde_cfg->has_fp16) + dma_list_size += ARRAY_SIZE(fp16_formats); + sde_cfg->dma_formats = kcalloc(dma_list_size, sizeof(struct sde_format_extended), GFP_KERNEL); if (!sde_cfg->dma_formats) { @@ -4432,11 +4557,17 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, index = sde_copy_formats(sde_cfg->dma_formats, dma_list_size, 0, plane_formats, ARRAY_SIZE(plane_formats)); + if (sde_cfg->has_fp16) + index += sde_copy_formats(sde_cfg->dma_formats, dma_list_size, + index, fp16_formats, ARRAY_SIZE(fp16_formats)); /* ViG pipe input formats */ vig_list_size = ARRAY_SIZE(plane_formats_vig); if (sde_cfg->has_vig_p010) vig_list_size += ARRAY_SIZE(p010_ubwc_formats); + if (sde_cfg->has_fp16) + vig_list_size += ARRAY_SIZE(fp16_formats); + sde_cfg->vig_formats = kcalloc(vig_list_size, sizeof(struct sde_format_extended), GFP_KERNEL); if (!sde_cfg->vig_formats) { @@ -4450,9 +4581,15 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, index += sde_copy_formats(sde_cfg->vig_formats, vig_list_size, index, p010_ubwc_formats, ARRAY_SIZE(p010_ubwc_formats)); + if (sde_cfg->has_fp16) + index += sde_copy_formats(sde_cfg->vig_formats, vig_list_size, + index, fp16_formats, ARRAY_SIZE(fp16_formats)); /* Virtual ViG pipe input formats (all virt pipes use DMA formats) */ virt_vig_list_size = ARRAY_SIZE(plane_formats); + if (sde_cfg->has_fp16) + virt_vig_list_size += ARRAY_SIZE(fp16_formats); + sde_cfg->virt_vig_formats = kcalloc(virt_vig_list_size, sizeof(struct sde_format_extended), GFP_KERNEL); if (!sde_cfg->virt_vig_formats) { @@ -4462,6 +4599,10 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, index = sde_copy_formats(sde_cfg->virt_vig_formats, virt_vig_list_size, 0, plane_formats, ARRAY_SIZE(plane_formats)); + if (sde_cfg->has_fp16) + index += sde_copy_formats(sde_cfg->virt_vig_formats, + virt_vig_list_size, index, fp16_formats, + ARRAY_SIZE(fp16_formats)); /* WB output formats */ wb2_list_size = ARRAY_SIZE(wb2_formats); @@ -4486,6 +4627,9 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, } if (in_rot_list_size) { + if (sde_cfg->has_fp16) + in_rot_list_size += ARRAY_SIZE(fp_16_inline_rot_fmts); + sde_cfg->inline_rot_formats = kcalloc(in_rot_list_size, sizeof(struct sde_format_extended), GFP_KERNEL); if (!sde_cfg->inline_rot_formats) { @@ -4496,6 +4640,10 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, index = sde_copy_formats(sde_cfg->inline_rot_formats, in_rot_list_size, 0, inline_fmt_tbl, in_rot_list_size); + if (sde_cfg->has_fp16) + index += sde_copy_formats(sde_cfg->inline_rot_formats, + in_rot_list_size, index, fp_16_inline_rot_fmts, + ARRAY_SIZE(fp_16_inline_rot_fmts)); } return 0; @@ -4850,6 +4998,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->mdss_hw_block_size = 0x158; sde_cfg->syscache_supported = true; sde_cfg->sspp_multirect_error = true; + sde_cfg->has_fp16 = true; } else { SDE_ERROR("unsupported chipset id:%X\n", hw_rev); sde_cfg->perf.min_prefill_lines = 0xffff; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 14c9bcfbac..abb1755b07 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _SDE_HW_CATALOG_H @@ -91,6 +91,9 @@ #define SDE_COLOR_PROCESS_MAJOR(version) (((version) & 0xFFFF0000) >> 16) #define SDE_COLOR_PROCESS_MINOR(version) ((version) & 0xFFFF) +#define IS_SDE_CP_VER_1_0(version) \ + (version == SDE_COLOR_PROCESS_VER(0x1, 0x0)) + #define MAX_XIN_COUNT 16 #define SSPP_SUBBLK_COUNT_MAX 2 @@ -256,6 +259,10 @@ enum { * @SDE_SSPP_PREDOWNSCALE Support pre-downscale X-direction by 2 for inline * @SDE_SSPP_PREDOWNSCALE_Y Support pre-downscale Y-direction for inline * @SDE_SSPP_INLINE_CONST_CLR Inline rotation requires const clr disabled + * @SDE_SSPP_FP16_IGC FP16 IGC color processing block support + * @SDE_SSPP_FP16_GC FP16 GC color processing block support + * @SDE_SSPP_FP16_CSC FP16 CSC color processing block support + * @SDE_SSPP_FP16_UNMULT FP16 alpha unmult color processing block support * @SDE_SSPP_MAX maximum value */ enum { @@ -288,6 +295,10 @@ enum { SDE_SSPP_PREDOWNSCALE, SDE_SSPP_PREDOWNSCALE_Y, SDE_SSPP_INLINE_CONST_CLR, + SDE_SSPP_FP16_IGC, + SDE_SSPP_FP16_GC, + SDE_SSPP_FP16_CSC, + SDE_SSPP_FP16_UNMULT, SDE_SSPP_MAX }; @@ -581,7 +592,10 @@ enum { u32 id; \ u32 base; \ u32 len; \ - unsigned long features; \ + union { \ + unsigned long features; \ + u64 features_ext; \ + }; \ unsigned long perf_features /** @@ -701,6 +715,14 @@ enum sde_qos_lut_usage { * @gc_blk: 1D LUT GC block * @num_dgm_csc_blk: number of DGM CSC blocks * @dgm_csc_blk: DGM CSC blocks + * @num_fp16_igc_blk: number of FP16 IGC blocks + * @fp16_igc_blk: FP16 IGC block array + * @num_fp16_gc_blk: number of FP16 GC blocks + * @fp16_gc_blk: FP16 GC block array + * @num_fp16_csc_blk: number of FP16 CSC blocks + * @fp16_csc_blk: FP16 CSC block array + * @num_fp16_unmult_blk: number of FP16 UNMULT blocks + * @fp16_unmult_blk: FP16 UNMULT block array * @format_list: Pointer to list of supported formats * @virt_format_list: Pointer to list of supported formats for virtual planes * @in_rot_format_list: Pointer to list of supported formats for inline rotation @@ -743,6 +765,14 @@ struct sde_sspp_sub_blks { struct sde_pp_blk gc_blk[SSPP_SUBBLK_COUNT_MAX]; u32 num_dgm_csc_blk; struct sde_pp_blk dgm_csc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_fp16_igc_blk; + struct sde_pp_blk fp16_igc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_fp16_gc_blk; + struct sde_pp_blk fp16_gc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_fp16_csc_blk; + struct sde_pp_blk fp16_csc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_fp16_unmult_blk; + struct sde_pp_blk fp16_unmult_blk[SSPP_SUBBLK_COUNT_MAX]; const struct sde_format_extended *format_list; const struct sde_format_extended *virt_format_list; @@ -1448,8 +1478,9 @@ struct sde_perf_cfg { * @has_sui_blendstage flag to indicate secure-ui has a blendstage restriction * @has_cursor indicates if hardware cursor is supported * @has_vig_p010 indicates if vig pipe supports p010 format + * @has_fp16 indicates if FP16 format is supported on SSPP pipes * @mdss_hw_block_size Max offset of MDSS_HW block (0 offset), used for debug - * @inline_rot_formats formats supported by the inline rotator feature + * @inline_rot_formats formats supported by the inline rotator feature * @irq_offset_list list of sde_intr_irq_offsets to initialize irq table * @rc_count number of rounded corner hardware instances * @demura_count number of demura hardware instances @@ -1525,6 +1556,7 @@ struct sde_mdss_cfg { bool has_hdr_plus; bool has_cursor; bool has_vig_p010; + bool has_fp16; u32 mdss_hw_block_size; u32 mdss_count; struct sde_mdss_base_cfg mdss[MAX_BLOCKS]; diff --git a/msm/sde/sde_hw_catalog_format.h b/msm/sde/sde_hw_catalog_format.h index 3802c9e319..47d308b44f 100644 --- a/msm/sde/sde_hw_catalog_format.h +++ b/msm/sde/sde_hw_catalog_format.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, 2021 The Linux Foundation. All rights reserved. */ #include "sde_hw_mdss.h" @@ -164,3 +164,18 @@ static const struct sde_format_extended true_inline_rot_v2_fmts[] = { P010_UBWC_FMTS, {0, 0}, }; + +static const struct sde_format_extended fp16_formats[] = { + {DRM_FORMAT_ARGB16161616F, 0}, + {DRM_FORMAT_ARGB16161616F, DRM_FORMAT_MOD_QCOM_ALPHA_SWAP}, + {DRM_FORMAT_ABGR16161616F, 0}, + {DRM_FORMAT_ABGR16161616F, DRM_FORMAT_MOD_QCOM_ALPHA_SWAP}, + {DRM_FORMAT_ABGR16161616F, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {0, 0} +}; + +static const struct sde_format_extended fp_16_inline_rot_fmts[] = { + {DRM_FORMAT_ABGR16161616F, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {0, 0} +}; + diff --git a/msm/sde/sde_hw_color_proc_v4.c b/msm/sde/sde_hw_color_proc_v4.c index 2fb5c209a4..f48193cc1f 100644 --- a/msm/sde/sde_hw_color_proc_v4.c +++ b/msm/sde/sde_hw_color_proc_v4.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include #include "sde_hw_color_proc_common_v4.h" @@ -413,3 +413,198 @@ void sde_demura_backlight_cfg(struct sde_hw_dspp *dspp, u64 val) SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->demura.base + 0x8, backlight); } + +void sde_setup_fp16_cscv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + struct drm_msm_fp16_csc *fp16_csc; + u32 csc_base, csc, i, offset = 0; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + csc_base = ctx->cap->sblk->fp16_csc_blk[0].base; + else + csc_base = ctx->cap->sblk->fp16_csc_blk[1].base; + + if (!csc_base) { + DRM_ERROR("invalid offset for FP16 CSC CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + fp16_csc = (struct drm_msm_fp16_csc *)(hw_cfg->payload); + if (!fp16_csc) + goto write_base; + + if (hw_cfg->len != sizeof(struct drm_msm_fp16_csc) || + !hw_cfg->payload) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tpayload: %pK\n", + ctx->idx, index, hw_cfg->len, hw_cfg->payload); + return; + } + + if (fp16_csc->cfg_param_0_len != FP16_CSC_CFG0_PARAM_LEN) { + DRM_ERROR("invalid param 0 length! Got: %d\tExpected: %d\tpipe: %d\tindex: %d\n", + fp16_csc->cfg_param_0_len, FP16_CSC_CFG0_PARAM_LEN, + ctx->idx, index); + return; + } else if (fp16_csc->cfg_param_1_len != FP16_CSC_CFG1_PARAM_LEN) { + DRM_ERROR("invalid param 1 length! Got: %d\tExpected: %d\tpipe: %d\tindex: %d\n", + fp16_csc->cfg_param_1_len, FP16_CSC_CFG1_PARAM_LEN, + ctx->idx, index); + return; + } + + for (i = 0; i < (fp16_csc->cfg_param_0_len / 2); i++) { + offset += 0x4; + csc = fp16_csc->cfg_param_0[2 * i] & 0xFFFF; + csc |= (fp16_csc->cfg_param_0[2 * i + 1] & 0xFFFF) << 16; + SDE_REG_WRITE(&ctx->hw, csc_base + offset, csc); + } + for (i = 0; i < (fp16_csc->cfg_param_1_len / 2); i++) { + offset += 0x4; + csc = fp16_csc->cfg_param_1[2 * i] & 0xFFFF; + csc |= (fp16_csc->cfg_param_1[2 * i + 1] & 0xFFFF) << 16; + SDE_REG_WRITE(&ctx->hw, csc_base + offset, csc); + } + +write_base: + csc = SDE_REG_READ(&ctx->hw, csc_base); + if (fp16_csc) + csc |= BIT(2); + else + csc &= ~BIT(2); + + SDE_REG_WRITE(&ctx->hw, csc_base, csc); +} + +void sde_setup_fp16_gcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + struct drm_msm_fp16_gc *fp16_gc; + u32 gc_base, gc; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } + + fp16_gc = (struct drm_msm_fp16_gc *)(hw_cfg->payload); + if (fp16_gc && (hw_cfg->len != sizeof(struct drm_msm_fp16_gc) || + fp16_gc->mode == FP16_GC_MODE_INVALID)) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d\tmode: %d", + ctx->idx, index, hw_cfg->len, fp16_gc->mode); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + gc_base = ctx->cap->sblk->fp16_gc_blk[0].base; + else + gc_base = ctx->cap->sblk->fp16_gc_blk[1].base; + + if (!gc_base) { + DRM_ERROR("invalid offset for FP16 GC CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + gc = SDE_REG_READ(&ctx->hw, gc_base); + gc &= ~0xF8; + + if (fp16_gc) { + gc |= BIT(4); + if (fp16_gc->flags & FP16_GC_FLAG_ALPHA_EN) + gc |= BIT(3); + + if (fp16_gc->mode == FP16_GC_MODE_PQ) + gc |= BIT(5); + } + + SDE_REG_WRITE(&ctx->hw, gc_base, gc); +} + +void sde_setup_fp16_igcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + bool *fp16_igc; + u32 igc_base, igc; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } else if (hw_cfg->len != sizeof(bool)) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d", + ctx->idx, index, hw_cfg->len); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + igc_base = ctx->cap->sblk->fp16_igc_blk[0].base; + else + igc_base = ctx->cap->sblk->fp16_igc_blk[1].base; + + if (!igc_base) { + DRM_ERROR("invalid offset for FP16 IGC CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + igc = SDE_REG_READ(&ctx->hw, igc_base); + fp16_igc = (bool *)(hw_cfg->payload); + + if (fp16_igc && *fp16_igc) + igc |= BIT(1); + else + igc &= ~BIT(1); + + SDE_REG_WRITE(&ctx->hw, igc_base, igc); +} + +void sde_setup_fp16_unmultv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data) +{ + struct sde_hw_cp_cfg *hw_cfg = data; + bool *fp16_unmult; + u32 unmult_base, unmult; + + if (!ctx || !data || index == SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid parameter\tctx: %pK\tdata: %pK\tindex: %d\n", + ctx, data, index); + return; + } else if (hw_cfg->len != sizeof(bool)) { + DRM_ERROR("invalid hw_cfg payload\tpipe: %d\tindex: %d\tlen: %d", + ctx->idx, index, hw_cfg->len); + return; + } + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) + unmult_base = ctx->cap->sblk->fp16_unmult_blk[0].base; + else + unmult_base = ctx->cap->sblk->fp16_unmult_blk[1].base; + + if (!unmult_base) { + DRM_ERROR("invalid offset for FP16 UNMULT CP block\tpipe: %d\tindex: %d\n", + ctx->idx, index); + return; + } + + unmult = SDE_REG_READ(&ctx->hw, unmult_base); + fp16_unmult = (bool *)(hw_cfg->payload); + + if (fp16_unmult && *fp16_unmult) + unmult |= BIT(0); + else + unmult &= ~BIT(0); + + SDE_REG_WRITE(&ctx->hw, unmult_base, unmult); +} diff --git a/msm/sde/sde_hw_color_proc_v4.h b/msm/sde/sde_hw_color_proc_v4.h index fa8e0db7a5..8c00b4b80b 100644 --- a/msm/sde/sde_hw_color_proc_v4.h +++ b/msm/sde/sde_hw_color_proc_v4.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _SDE_HW_COLOR_PROC_V4_H_ #define _SDE_HW_COLOR_PROC_V4_H_ @@ -8,6 +8,8 @@ #include "sde_hw_util.h" #include "sde_hw_catalog.h" #include "sde_hw_dspp.h" +#include "sde_hw_sspp.h" + /** * sde_setup_dspp_3d_gamutv4 - Function for 3d gamut v4 version feature * programming. @@ -77,4 +79,39 @@ void sde_ltm_read_intr_status(struct sde_hw_dspp *dspp, u32 *status); */ void sde_demura_backlight_cfg(struct sde_hw_dspp *dspp, u64 val); +/** + * sde_setup_fp16_cscv1 - api to set FP16 CSC cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing drm_msm_fp16_csc data + */ +void sde_setup_fp16_cscv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + +/** + * sde_setup_fp16_gcv1 - api to set FP16 GC cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing drm_msm_fp16_gc data + */ +void sde_setup_fp16_gcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + +/** + * sde_setup_fp16_igcv1 - api to set FP16 IGC cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing bool data + */ +void sde_setup_fp16_igcv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + +/** + * sde_setup_fp16_unmultv1 - api to set FP16 UNMULT cp block + * @ctx: pointer to pipe object + * @index: pipe rectangle to operate on + * @data: pointer to sde_hw_cp_cfg object containing bool data + */ +void sde_setup_fp16_unmultv1(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); #endif /* _SDE_HW_COLOR_PROC_V4_H_ */ diff --git a/msm/sde/sde_hw_mdss.h b/msm/sde/sde_hw_mdss.h index 6d38d29396..c37adff0de 100644 --- a/msm/sde/sde_hw_mdss.h +++ b/msm/sde/sde_hw_mdss.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _SDE_HW_MDSS_H @@ -43,12 +43,16 @@ enum sde_format_flags { SDE_FORMAT_FLAG_YUV_BIT, SDE_FORMAT_FLAG_DX_BIT, SDE_FORMAT_FLAG_COMPRESSED_BIT, + SDE_FORMAT_FLAG_ALPHA_SWAP_BIT, + SDE_FORMAT_FLAG_FP16_BIT, SDE_FORMAT_FLAG_BIT_MAX, }; #define SDE_FORMAT_FLAG_YUV BIT(SDE_FORMAT_FLAG_YUV_BIT) #define SDE_FORMAT_FLAG_DX BIT(SDE_FORMAT_FLAG_DX_BIT) #define SDE_FORMAT_FLAG_COMPRESSED BIT(SDE_FORMAT_FLAG_COMPRESSED_BIT) +#define SDE_FORMAT_FLAG_ALPHA_SWAP BIT(SDE_FORMAT_FLAG_ALPHA_SWAP_BIT) +#define SDE_FORMAT_FLAG_FP16 BIT(SDE_FORMAT_FLAG_FP16_BIT) #define SDE_FORMAT_IS_YUV(X) \ (test_bit(SDE_FORMAT_FLAG_YUV_BIT, (X)->flag)) #define SDE_FORMAT_IS_DX(X) \ @@ -60,6 +64,10 @@ enum sde_format_flags { #define SDE_FORMAT_IS_UBWC(X) \ (((X)->fetch_mode == SDE_FETCH_UBWC) && \ test_bit(SDE_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag)) +#define SDE_FORMAT_IS_ALPHA_SWAPPED(X) \ + (test_bit(SDE_FORMAT_FLAG_ALPHA_SWAP_BIT, (X)->flag)) +#define SDE_FORMAT_IS_FP16(X) \ + (test_bit(SDE_FORMAT_FLAG_FP16_BIT, (X)->flag)) #define SDE_BLEND_FG_ALPHA_FG_CONST (0 << 0) #define SDE_BLEND_FG_ALPHA_BG_CONST (1 << 0) @@ -402,6 +410,7 @@ enum { COLOR_5BIT = 1, /* No 5-bit Alpha */ COLOR_6BIT = 2, /* 6-Bit Alpha also = 2 */ COLOR_8BIT = 3, /* 8-Bit Alpha also = 3 */ + COLOR_16BIT = 3, }; /** diff --git a/msm/sde/sde_hw_sspp.c b/msm/sde/sde_hw_sspp.c index 979f4bd9cb..43c873b7d9 100644 --- a/msm/sde/sde_hw_sspp.c +++ b/msm/sde/sde_hw_sspp.c @@ -359,8 +359,15 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, (fmt->element[1] << 8) | (fmt->element[0] << 0); src_format |= ((fmt->unpack_count - 1) << 12) | (fmt->unpack_tight << 17) | - (fmt->unpack_align_msb << 18) | - ((fmt->bpp - 1) << 9); + (fmt->unpack_align_msb << 18); + + if (SDE_FORMAT_IS_FP16(fmt)) { + src_format |= BIT(16) | BIT(10) | BIT(9); + } else if (fmt->bpp <= 4) { + src_format |= ((fmt->bpp - 1) << 9); + } else if (fmt->bpp <= 8) { + src_format |= BIT(16) | ((fmt->bpp - 5) << 9); + } if ((flags & SDE_SSPP_ROT_90) && test_bit(SDE_SSPP_INLINE_CONST_CLR, &ctx->cap->features)) @@ -1192,6 +1199,22 @@ static void _setup_layer_ops_colorproc(struct sde_hw_pipe *c, c->ops.setup_dma_gc = NULL; } } + + if (test_bit(SDE_SSPP_FP16_IGC, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_igc_blk[0].version)) + c->ops.setup_fp16_igc = sde_setup_fp16_igcv1; + + if (test_bit(SDE_SSPP_FP16_GC, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_gc_blk[0].version)) + c->ops.setup_fp16_gc = sde_setup_fp16_gcv1; + + if (test_bit(SDE_SSPP_FP16_CSC, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_csc_blk[0].version)) + c->ops.setup_fp16_csc = sde_setup_fp16_cscv1; + + if (test_bit(SDE_SSPP_FP16_UNMULT, &features) && + IS_SDE_CP_VER_1_0(c->cap->sblk->fp16_unmult_blk[0].version)) + c->ops.setup_fp16_unmult = sde_setup_fp16_unmultv1; } static void sde_hw_sspp_setup_inverse_pma(struct sde_hw_pipe *ctx, diff --git a/msm/sde/sde_hw_sspp.h b/msm/sde/sde_hw_sspp.h index 57209c5d8b..b5bd819183 100644 --- a/msm/sde/sde_hw_sspp.h +++ b/msm/sde/sde_hw_sspp.h @@ -618,6 +618,42 @@ struct sde_hw_sspp_ops { * @multirect_index: rec in use */ u32 (*get_ubwc_error)(struct sde_hw_pipe *ctx, uint32_t multirect_index); + + /** + * setup_fp16_csc - set FP16 CSC cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @data: Pointer to sde_hw_cp_cfg object holding drm_msm_fp16_csc data + */ + void (*setup_fp16_csc)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + + /** + * sde_setup_fp16_gcv1 - set FP16 GC cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @data: Pointer to sde_hw_cp_cfg object holding drm_msm_fp16_gc data + */ + void (*setup_fp16_gc)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + + /** + * sde_setup_fp16_igcv1 - set FP16 IGC cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @data: Pointer to sde_hw_cp_cfg object containing bool data + */ + void (*setup_fp16_igc)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); + + /** + * sde_setup_fp16_unmultv1 - set FP16 UNMULT cp block + * @ctx: Pointer to pipe object + * @index: Pipe rectangle to operate on + * @data: Pointer to sde_hw_cp_cfg object containing bool data + */ + void (*setup_fp16_unmult)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, void *data); }; /** diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index 8ae38440b3..7b14ad233f 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -101,7 +101,7 @@ struct sde_plane { struct mutex lock; enum sde_sspp pipe; - uint32_t features; /* capabilities from catalog */ + uint64_t features; /* capabilities from catalog */ uint32_t perf_features; /* perf capabilities from catalog */ uint32_t nformats; uint32_t formats[64]; @@ -1156,6 +1156,9 @@ static void sde_color_process_plane_setup(struct drm_plane *plane) size_t memcol_sz = 0, size = 0; struct sde_hw_cp_cfg hw_cfg = {}; struct sde_hw_ctl *ctl = _sde_plane_get_hw_ctl(plane); + bool fp16_igc, fp16_unmult; + struct drm_msm_fp16_gc *fp16_gc = NULL; + struct drm_msm_fp16_csc *fp16_csc = NULL; psde = to_sde_plane(plane); pstate = to_sde_plane_state(plane->state); @@ -1255,6 +1258,58 @@ static void sde_color_process_plane_setup(struct drm_plane *plane) psde->pipe_hw->ops.setup_dma_gc(psde->pipe_hw, &hw_cfg, pstate->multirect_index); } + + if (pstate->dirty & SDE_PLANE_DIRTY_FP16_IGC && + psde->pipe_hw->ops.setup_fp16_igc) { + fp16_igc = !!sde_plane_get_property(pstate, + PLANE_PROP_FP16_IGC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(bool); + hw_cfg.payload = &fp16_igc; + psde->pipe_hw->ops.setup_fp16_igc(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_FP16_GC && + psde->pipe_hw->ops.setup_fp16_gc) { + fp16_gc = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &size, + PLANE_PROP_FP16_GC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = size; + hw_cfg.payload = fp16_gc; + psde->pipe_hw->ops.setup_fp16_gc(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_FP16_CSC && + psde->pipe_hw->ops.setup_fp16_csc) { + fp16_csc = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &size, + PLANE_PROP_FP16_CSC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = size; + hw_cfg.payload = fp16_csc; + psde->pipe_hw->ops.setup_fp16_csc(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_FP16_UNMULT && + psde->pipe_hw->ops.setup_fp16_unmult) { + fp16_unmult = !!sde_plane_get_property(pstate, + PLANE_PROP_FP16_UNMULT); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(bool); + hw_cfg.payload = &fp16_unmult; + psde->pipe_hw->ops.setup_fp16_unmult(psde->pipe_hw, + pstate->multirect_index, &hw_cfg); + } } static void _sde_plane_setup_scaler(struct sde_plane *psde, @@ -2840,6 +2895,11 @@ static void _sde_plane_map_prop_to_dirty_bits(void) plane_prop_array[PLANE_PROP_VALUE_ADJUST] = plane_prop_array[PLANE_PROP_CONTRAST_ADJUST] = SDE_PLANE_DIRTY_ALL; + + plane_prop_array[PLANE_PROP_FP16_IGC] = SDE_PLANE_DIRTY_FP16_IGC; + plane_prop_array[PLANE_PROP_FP16_GC] = SDE_PLANE_DIRTY_FP16_GC; + plane_prop_array[PLANE_PROP_FP16_CSC] = SDE_PLANE_DIRTY_FP16_CSC; + plane_prop_array[PLANE_PROP_FP16_UNMULT] = SDE_PLANE_DIRTY_FP16_UNMULT; } static inline bool _sde_plane_allow_uidle(struct sde_plane *psde, @@ -3535,6 +3595,38 @@ static void _sde_plane_install_colorproc_properties(struct sde_plane *psde, msm_property_install_blob(&psde->property_info, feature_name, 0, PLANE_PROP_DMA_GC); } + + if (psde->features & BIT(SDE_SSPP_FP16_IGC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_FP16_IGC_V", + psde->pipe_sblk->fp16_igc_blk[0].version >> 16); + msm_property_install_range(&psde->property_info, feature_name, + 0x0, 0, 1, 0, PLANE_PROP_FP16_IGC); + } + + if (psde->features & BIT(SDE_SSPP_FP16_GC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_FP16_GC_V", + psde->pipe_sblk->fp16_gc_blk[0].version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_FP16_GC); + } + + if (psde->features & BIT(SDE_SSPP_FP16_CSC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_FP16_CSC_V", + psde->pipe_sblk->fp16_csc_blk[0].version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_FP16_CSC); + } + + if (psde->features & BIT(SDE_SSPP_FP16_UNMULT)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_FP16_UNMULT_V", + psde->pipe_sblk->fp16_unmult_blk[0].version >> 16); + msm_property_install_range(&psde->property_info, feature_name, + 0x0, 0, 1, 0, PLANE_PROP_FP16_UNMULT); + } } static void _sde_plane_setup_capabilities_blob(struct sde_plane *psde, @@ -4476,7 +4568,7 @@ static int _sde_plane_init_debugfs(struct drm_plane *plane) return -ENOMEM; /* don't error check these */ - debugfs_create_x32("features", 0400, + debugfs_create_x64("features", 0400, psde->debugfs_root, &psde->features); if (cfg->features & BIT(SDE_SSPP_SCALER_QSEED3) || @@ -4655,7 +4747,7 @@ struct drm_plane *sde_plane_init(struct drm_device *dev, } /* cache features mask for later */ - psde->features = psde->pipe_hw->cap->features; + psde->features = psde->pipe_hw->cap->features_ext; psde->perf_features = psde->pipe_hw->cap->perf_features; psde->pipe_sblk = psde->pipe_hw->cap->sblk; if (!psde->pipe_sblk) { diff --git a/msm/sde/sde_plane.h b/msm/sde/sde_plane.h index 105756af83..bcc2449c76 100644 --- a/msm/sde/sde_plane.h +++ b/msm/sde/sde_plane.h @@ -38,9 +38,15 @@ #define SDE_PLANE_DIRTY_DMA_IGC 0x80 #define SDE_PLANE_DIRTY_DMA_GC 0x100 #define SDE_PLANE_DIRTY_QOS 0x200 +#define SDE_PLANE_DIRTY_FP16_IGC 0x400 +#define SDE_PLANE_DIRTY_FP16_GC 0x800 +#define SDE_PLANE_DIRTY_FP16_CSC 0x1000 +#define SDE_PLANE_DIRTY_FP16_UNMULT 0x2000 #define SDE_PLANE_DIRTY_CP (SDE_PLANE_DIRTY_VIG_GAMUT |\ SDE_PLANE_DIRTY_VIG_IGC | SDE_PLANE_DIRTY_DMA_IGC |\ - SDE_PLANE_DIRTY_DMA_GC) + SDE_PLANE_DIRTY_DMA_GC | SDE_PLANE_DIRTY_FP16_IGC |\ + SDE_PLANE_DIRTY_FP16_GC | SDE_PLANE_DIRTY_FP16_CSC |\ + SDE_PLANE_DIRTY_FP16_UNMULT) #define SDE_PLANE_DIRTY_ALL (0xFFFFFFFF & ~(SDE_PLANE_DIRTY_CP)) /**