FILE
dpu_hw_cdm.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2023, The Linux Foundation. All rights reserved. 4 */ 5 6#include <linux/bitfield.h> 7 8#include <drm/drm_managed.h> 9 10#include "dpu_hw_mdss.h" 11#include "dpu_hw_util.h" 12#include "dpu_hw_catalog.h" 13#include "dpu_hw_cdm.h" 14#include "dpu_kms.h" 15 16#define CDM_CSC_10_OPMODE 0x000 17#define CDM_CSC_10_BASE 0x004 18 19#define CDM_CDWN2_OP_MODE 0x100 20#define CDM_CDWN2_CLAMP_OUT 0x104 21#define CDM_CDWN2_PARAMS_3D_0 0x108 22#define CDM_CDWN2_PARAMS_3D_1 0x10C 23#define CDM_CDWN2_COEFF_COSITE_H_0 0x110 24#define CDM_CDWN2_COEFF_COSITE_H_1 0x114 25#define CDM_CDWN2_COEFF_COSITE_H_2 0x118 26#define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C 27#define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 28#define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 29#define CDM_CDWN2_COEFF_COSITE_V 0x128 30#define CDM_CDWN2_COEFF_OFFSITE_V 0x12C 31#define CDM_CDWN2_OUT_SIZE 0x130 32 33#define CDM_HDMI_PACK_OP_MODE 0x200 34#define CDM_CSC_10_MATRIX_COEFF_0 0x004 35 36#define CDM_MUX 0x224 37 38/* CDM CDWN2 sub-block bit definitions */ 39#define CDM_CDWN2_OP_MODE_EN BIT(0) 40#define CDM_CDWN2_OP_MODE_ENABLE_H BIT(1) 41#define CDM_CDWN2_OP_MODE_ENABLE_V BIT(2) 42#define CDM_CDWN2_OP_MODE_BITS_OUT_8BIT BIT(7) 43#define CDM_CDWN2_V_PIXEL_METHOD_MASK GENMASK(6, 5) 44#define CDM_CDWN2_H_PIXEL_METHOD_MASK GENMASK(4, 3) 45 46/* CDM CSC10 sub-block bit definitions */ 47#define CDM_CSC10_OP_MODE_EN BIT(0) 48#define CDM_CSC10_OP_MODE_SRC_FMT_YUV BIT(1) 49#define CDM_CSC10_OP_MODE_DST_FMT_YUV BIT(2) 50 51/* CDM HDMI pack sub-block bit definitions */ 52#define CDM_HDMI_PACK_OP_MODE_EN BIT(0) 53 54/* 55 * Horizontal coefficients for cosite chroma downscale 56 * s13 representation of coefficients 57 */ 58static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; 59 60/* 61 * Horizontal coefficients for offsite chroma downscale 62 */ 63static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; 64 65/* 66 * Vertical coefficients for cosite chroma downscale 67 */ 68static u32 cosite_v_coeff[] = {0x00080004}; 69/* 70 * Vertical coefficients for offsite chroma downscale 71 */ 72static u32 offsite_v_coeff[] = {0x00060002}; 73 74static int dpu_hw_cdm_setup_cdwn(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cfg) 75{ 76 struct dpu_hw_blk_reg_map *c = &ctx->hw; 77 u32 opmode; 78 u32 out_size; 79 80 switch (cfg->h_cdwn_type) { 81 case CDM_CDWN_DISABLE: 82 opmode = 0; 83 break; 84 case CDM_CDWN_PIXEL_DROP: 85 opmode = CDM_CDWN2_OP_MODE_ENABLE_H | 86 FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, 87 CDM_CDWN2_METHOD_PIXEL_DROP); 88 break; 89 case CDM_CDWN_AVG: 90 opmode = CDM_CDWN2_OP_MODE_ENABLE_H | 91 FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, 92 CDM_CDWN2_METHOD_AVG); 93 break; 94 case CDM_CDWN_COSITE: 95 opmode = CDM_CDWN2_OP_MODE_ENABLE_H | 96 FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, 97 CDM_CDWN2_METHOD_COSITE); 98 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, 99 cosite_h_coeff[0]); 100 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, 101 cosite_h_coeff[1]); 102 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, 103 cosite_h_coeff[2]); 104 break; 105 case CDM_CDWN_OFFSITE: 106 opmode = CDM_CDWN2_OP_MODE_ENABLE_H | 107 FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, CDM_CDWN2_METHOD_OFFSITE); 108 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, 109 offsite_h_coeff[0]); 110 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, 111 offsite_h_coeff[1]); 112 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, 113 offsite_h_coeff[2]); 114 break; 115 default: 116 DPU_ERROR("%s invalid horz down sampling type\n", __func__); 117 return -EINVAL; 118 } 119 120 switch (cfg->v_cdwn_type) { 121 case CDM_CDWN_DISABLE: 122 /* if its only Horizontal downsample, we dont need to do anything here */ 123 break; 124 case CDM_CDWN_PIXEL_DROP: 125 opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | 126 FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, 127 CDM_CDWN2_METHOD_PIXEL_DROP); 128 break; 129 case CDM_CDWN_AVG: 130 opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | 131 FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, 132 CDM_CDWN2_METHOD_AVG); 133 break; 134 case CDM_CDWN_COSITE: 135 opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | 136 FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, 137 CDM_CDWN2_METHOD_COSITE); 138 DPU_REG_WRITE(c, 139 CDM_CDWN2_COEFF_COSITE_V, 140 cosite_v_coeff[0]); 141 break; 142 case CDM_CDWN_OFFSITE: 143 opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | 144 FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, 145 CDM_CDWN2_METHOD_OFFSITE); 146 DPU_REG_WRITE(c, 147 CDM_CDWN2_COEFF_OFFSITE_V, 148 offsite_v_coeff[0]); 149 break; 150 default: 151 return -EINVAL; 152 } 153 154 if (cfg->output_bit_depth != CDM_CDWN_OUTPUT_10BIT) 155 opmode |= CDM_CDWN2_OP_MODE_BITS_OUT_8BIT; 156 157 if (cfg->v_cdwn_type || cfg->h_cdwn_type) 158 opmode |= CDM_CDWN2_OP_MODE_EN; /* EN CDWN module */ 159 else 160 opmode &= ~CDM_CDWN2_OP_MODE_EN; 161 162 out_size = (cfg->output_width & 0xFFFF) | ((cfg->output_height & 0xFFFF) << 16); 163 DPU_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); 164 DPU_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); 165 DPU_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, ((0x3FF << 16) | 0x0)); 166 167 return 0; 168} 169 170static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cdm) 171{ 172 struct dpu_hw_blk_reg_map *c = &ctx->hw; 173 const struct msm_format *fmt; 174 u32 opmode = 0; 175 u32 csc = 0; 176 177 if (!ctx || !cdm) 178 return -EINVAL; 179 180 fmt = cdm->output_fmt; 181 182 if (!MSM_FORMAT_IS_YUV(fmt)) 183 return -EINVAL; 184 185 dpu_hw_csc_setup(&ctx->hw, CDM_CSC_10_MATRIX_COEFF_0, cdm->csc_cfg, true); 186 dpu_hw_cdm_setup_cdwn(ctx, cdm); 187 188 if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { 189 if (fmt->chroma_sample == CHROMA_H1V2) 190 return -EINVAL; /*unsupported format */ 191 opmode = CDM_HDMI_PACK_OP_MODE_EN; 192 opmode |= (fmt->chroma_sample << 1); 193 } 194 195 csc |= CDM_CSC10_OP_MODE_DST_FMT_YUV; 196 csc &= ~CDM_CSC10_OP_MODE_SRC_FMT_YUV; 197 csc |= CDM_CSC10_OP_MODE_EN; 198 199 if (ctx && ctx->ops.bind_pingpong_blk) 200 ctx->ops.bind_pingpong_blk(ctx, cdm->pp_id); 201 202 DPU_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); 203 DPU_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); 204 return 0; 205} 206 207static void dpu_hw_cdm_bind_pingpong_blk(struct dpu_hw_cdm *ctx, const enum dpu_pingpong pp) 208{ 209 struct dpu_hw_blk_reg_map *c; 210 int mux_cfg; 211 212 c = &ctx->hw; 213 214 mux_cfg = DPU_REG_READ(c, CDM_MUX); 215 mux_cfg &= ~0xf; 216 217 if (pp >= PINGPONG_CWB_0) 218 mux_cfg |= 0xd; 219 else if (pp) 220 mux_cfg |= (pp - PINGPONG_0) & 0x7; 221 else 222 mux_cfg |= 0xf; 223 224 DPU_REG_WRITE(c, CDM_MUX, mux_cfg); 225} 226 227/** 228 * dpu_hw_cdm_init - initializes the cdm hw driver object. 229 * should be called once before accessing every cdm. 230 * @dev: DRM device handle 231 * @cfg: CDM catalog entry for which driver object is required 232 * @addr : mapped register io address of MDSS 233 * @mdss_rev: mdss hw core revision 234 */ 235struct dpu_hw_cdm *dpu_hw_cdm_init(struct drm_device *dev, 236 const struct dpu_cdm_cfg *cfg, void __iomem *addr, 237 const struct dpu_mdss_version *mdss_rev) 238{ 239 struct dpu_hw_cdm *c; 240 241 c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); 242 if (!c) 243 return ERR_PTR(-ENOMEM); 244 245 c->hw.blk_addr = addr + cfg->base; 246 c->hw.log_mask = DPU_DBG_MASK_CDM; 247 248 /* Assign ops */ 249 c->idx = cfg->id; 250 c->caps = cfg; 251 252 c->ops.enable = dpu_hw_cdm_enable; 253 if (mdss_rev->core_major_ver >= 5) 254 c->ops.bind_pingpong_blk = dpu_hw_cdm_bind_pingpong_blk; 255 256 return c; 257}
~/
Read-only file preview.