brintos

brintos / linux-shallow public Read only

0
0
Text · 6.8 KiB · 55d2768 Raw
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