248 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 0x00017#define CDM_CSC_10_BASE 0x00418 19#define CDM_CDWN2_OP_MODE 0x10020#define CDM_CDWN2_CLAMP_OUT 0x10421#define CDM_CDWN2_PARAMS_3D_0 0x10822#define CDM_CDWN2_PARAMS_3D_1 0x10C23#define CDM_CDWN2_COEFF_COSITE_H_0 0x11024#define CDM_CDWN2_COEFF_COSITE_H_1 0x11425#define CDM_CDWN2_COEFF_COSITE_H_2 0x11826#define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C27#define CDM_CDWN2_COEFF_OFFSITE_H_1 0x12028#define CDM_CDWN2_COEFF_OFFSITE_H_2 0x12429#define CDM_CDWN2_COEFF_COSITE_V 0x12830#define CDM_CDWN2_COEFF_OFFSITE_V 0x12C31#define CDM_CDWN2_OUT_SIZE 0x13032 33#define CDM_HDMI_PACK_OP_MODE 0x20034#define CDM_CSC_10_MATRIX_COEFF_0 0x00435 36#define CDM_MUX 0x22437 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 downscale56 * s13 representation of coefficients57 */58static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e};59 60/*61 * Horizontal coefficients for offsite chroma downscale62 */63static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046};64 65/*66 * Vertical coefficients for cosite chroma downscale67 */68static u32 cosite_v_coeff[] = {0x00080004};69/*70 * Vertical coefficients for offsite chroma downscale71 */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 else160 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)218 mux_cfg |= (pp - PINGPONG_0) & 0x7;219 else220 mux_cfg |= 0xf;221 222 DPU_REG_WRITE(c, CDM_MUX, mux_cfg);223}224 225struct dpu_hw_cdm *dpu_hw_cdm_init(struct drm_device *dev,226 const struct dpu_cdm_cfg *cfg, void __iomem *addr,227 const struct dpu_mdss_version *mdss_rev)228{229 struct dpu_hw_cdm *c;230 231 c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL);232 if (!c)233 return ERR_PTR(-ENOMEM);234 235 c->hw.blk_addr = addr + cfg->base;236 c->hw.log_mask = DPU_DBG_MASK_CDM;237 238 /* Assign ops */239 c->idx = cfg->id;240 c->caps = cfg;241 242 c->ops.enable = dpu_hw_cdm_enable;243 if (mdss_rev->core_major_ver >= 5)244 c->ops.bind_pingpong_blk = dpu_hw_cdm_bind_pingpong_blk;245 246 return c;247}248