Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed859f5d authored by Chirag Khurana's avatar Chirag Khurana Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm: add YUV format support



Enable YUV formats for current resolution if supported.
Also, chooses the best mode for turning on the
sink based on sink source capabilities. This can
be either RGB or YUV. For YUV formats adjust
the pxl clock and also configure the relevant
hardware blocks in SDE.

Change-Id: I48a36a991c194badb3ddca4bbf5bcbc21d838b8f
Signed-off-by: default avatarYuan Zhao <yzhao@codeaurora.org>
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
Signed-off-by: default avatarChirag Khurana <ckhurana@codeaurora.org>
parent 857b40cc
Loading
Loading
Loading
Loading
+132 −0
Original line number Diff line number Diff line
@@ -161,6 +161,33 @@ enum sde_enc_rc_states {
	SDE_ENC_RC_STATE_IDLE
};

/* rgb to yuv color space conversion matrix */
static struct sde_csc_cfg sde_csc_10bit_convert[SDE_MAX_CSC] = {
	[SDE_CSC_RGB2YUV_601L] = {
		{
			TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032),
			TO_S15D16(0xffb4), TO_S15D16(0xff6b), TO_S15D16(0x00e1),
			TO_S15D16(0x00e1), TO_S15D16(0xff44), TO_S15D16(0xffdb),
		},
		{ 0x0, 0x0, 0x0,},
		{ 0x0040, 0x0200, 0x0200,},
		{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
		{ 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,},
	},

	[SDE_CSC_RGB2YUV_601FR] = {
		{
			TO_S15D16(0x0099), TO_S15D16(0x012d), TO_S15D16(0x003a),
			TO_S15D16(0xffaa), TO_S15D16(0xff56), TO_S15D16(0x0100),
			TO_S15D16(0x0100), TO_S15D16(0xff2a), TO_S15D16(0xffd6),
		},
		{ 0x0, 0x0, 0x0,},
		{ 0x0000, 0x0200, 0x0200,},
		{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
		{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
	},
};

/**
 * struct sde_encoder_virt - virtual encoder. Container of one or more physical
 *	encoders. Virtual encoder manages one "logical" display. Physical
@@ -5128,3 +5155,108 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc)

	return 0;
}

/**
 * sde_encoder_phys_setup_cdm - setup chroma down block
 * @phys_enc:	Pointer to physical encoder
 * @output_type: HDMI/WB
 * @format:	Output format
 * @roi: Output size
 */
void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
		const struct sde_format *format, u32 output_type,
		struct sde_rect *roi)
{
	struct drm_encoder *encoder = phys_enc->parent;
	struct sde_encoder_virt *sde_enc = NULL;
	struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
	struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg;
	int ret;
	u32 csc_type = 0;

	if (!encoder) {
		SDE_ERROR("invalid encoder\n");
		return;
	}
	sde_enc = to_sde_encoder_virt(encoder);

	if (!SDE_FORMAT_IS_YUV(format)) {
		SDE_DEBUG_ENC(sde_enc, "[cdm_disable fmt:%x]\n",
				format->base.pixel_format);

		if (hw_cdm && hw_cdm->ops.disable)
			hw_cdm->ops.disable(hw_cdm);

		return;
	}

	memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg));

	cdm_cfg->output_width = roi->w;
	cdm_cfg->output_height = roi->h;
	cdm_cfg->output_fmt = format;
	cdm_cfg->output_type = output_type;
	cdm_cfg->output_bit_depth = SDE_FORMAT_IS_DX(format) ?
		CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;

	/* enable 10 bit logic */
	switch (cdm_cfg->output_fmt->chroma_sample) {
	case SDE_CHROMA_RGB:
		cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
		break;
	case SDE_CHROMA_H2V1:
		cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
		break;
	case SDE_CHROMA_420:
		cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
		break;
	case SDE_CHROMA_H1V2:
	default:
		SDE_ERROR("unsupported chroma sampling type\n");
		cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
		break;
	}

	SDE_DEBUG_ENC(sde_enc, "[cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
			cdm_cfg->output_width,
			cdm_cfg->output_height,
			cdm_cfg->output_fmt->base.pixel_format,
			cdm_cfg->output_type,
			cdm_cfg->output_bit_depth,
			cdm_cfg->h_cdwn_type,
			cdm_cfg->v_cdwn_type);

	if (output_type == CDM_CDWN_OUTPUT_HDMI)
		csc_type = SDE_CSC_RGB2YUV_601FR;
	else if (output_type == CDM_CDWN_OUTPUT_WB)
		csc_type = SDE_CSC_RGB2YUV_601L;

	if (hw_cdm && hw_cdm->ops.setup_csc_data) {
		ret = hw_cdm->ops.setup_csc_data(hw_cdm,
				&sde_csc_10bit_convert[csc_type]);
		if (ret < 0) {
			SDE_ERROR("failed to setup CSC %d\n", ret);
			return;
		}
	}

	if (hw_cdm && hw_cdm->ops.setup_cdwn) {
		ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg);
		if (ret < 0) {
			SDE_ERROR("failed to setup CDM %d\n", ret);
			return;
		}
	}

	if (hw_cdm && hw_cdm->ops.enable) {
		ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
		if (ret < 0) {
			SDE_ERROR("failed to enable CDM %d\n", ret);
			return;
		}
	}
}
+2 −2
Original line number Diff line number Diff line
@@ -493,8 +493,8 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init(
#endif

void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
		struct drm_framebuffer *fb, const struct sde_format *format,
		struct sde_rect *wb_roi);
		const struct sde_format *format, u32 output_type,
		struct sde_rect *roi);

/**
 * sde_encoder_helper_trigger_flush - control flush helper function
+49 −3
Original line number Diff line number Diff line
@@ -385,17 +385,20 @@ static void sde_encoder_phys_vid_setup_timing_engine(
	SDE_DEBUG_VIDENC(vid_enc, "enabling mode:\n");
	drm_mode_debug_printmodeline(&mode);

	if (phys_enc->split_role != ENC_ROLE_SOLO) {
	if (phys_enc->split_role != ENC_ROLE_SOLO ||
	    (mode.private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)) {
		mode.hdisplay >>= 1;
		mode.htotal >>= 1;
		mode.hsync_start >>= 1;
		mode.hsync_end >>= 1;
		mode.hskew >>= 1;

		SDE_DEBUG_VIDENC(vid_enc,
			"split_role %d, halve horizontal %d %d %d %d\n",
			"split_role %d, halve horizontal %d %d %d %d %d\n",
			phys_enc->split_role,
			mode.hdisplay, mode.htotal,
			mode.hsync_start, mode.hsync_end);
			mode.hsync_start, mode.hsync_end,
			mode.hskew);
	}

	if (!phys_enc->vfp_cached) {
@@ -590,6 +593,9 @@ static void sde_encoder_phys_vid_mode_set(
		return;
	}

	phys_enc->hw_ctl = NULL;
	phys_enc->hw_cdm = NULL;

	rm = &phys_enc->sde_kms->rm;
	vid_enc = to_sde_encoder_phys_vid(phys_enc);

@@ -615,6 +621,20 @@ static void sde_encoder_phys_vid_mode_set(
	}

	_sde_encoder_phys_vid_setup_irq_hw_idx(phys_enc);

	/* CDM is optional */
	sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CDM);
	for (i = 0; i <= instance; i++) {
		sde_rm_get_hw(rm, &iter);
		if (i == instance)
			phys_enc->hw_cdm = (struct sde_hw_cdm *) iter.hw;
	}

	if (IS_ERR(phys_enc->hw_cdm)) {
		SDE_ERROR("CDM required but not allocated: %ld\n",
				PTR_ERR(phys_enc->hw_cdm));
		phys_enc->hw_cdm = NULL;
	}
}

static int sde_encoder_phys_vid_control_vblank_irq(
@@ -713,6 +733,9 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc)
	struct sde_encoder_phys_vid *vid_enc;
	struct sde_hw_intf *intf;
	struct sde_hw_ctl *ctl;
	struct sde_hw_cdm *hw_cdm = NULL;
	struct drm_display_mode mode;
	const struct sde_format *fmt = NULL;
	u32 flush_mask = 0;

	if (!phys_enc || !phys_enc->parent || !phys_enc->parent->dev ||
@@ -721,7 +744,9 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc)
		SDE_ERROR("invalid encoder/device\n");
		return;
	}
	hw_cdm = phys_enc->hw_cdm;
	priv = phys_enc->parent->dev->dev_private;
	mode = phys_enc->cached_mode;

	vid_enc = to_sde_encoder_phys_vid(phys_enc);
	intf = vid_enc->hw_intf;
@@ -765,7 +790,21 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc)
		goto skip_flush;
	}

	if (mode.private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)
		fmt = sde_get_sde_format(DRM_FORMAT_YUV420);

	if (fmt) {
		struct sde_rect hdmi_roi;

		hdmi_roi.w = mode.hdisplay;
		hdmi_roi.h = mode.vdisplay;
		sde_encoder_phys_setup_cdm(phys_enc, fmt,
			CDM_CDWN_OUTPUT_HDMI, &hdmi_roi);
	}

	ctl->ops.get_bitmask_intf(ctl, &flush_mask, intf->idx);
	if (ctl->ops.get_bitmask_cdm && hw_cdm)
		ctl->ops.get_bitmask_cdm(ctl, &flush_mask, hw_cdm->idx);
	ctl->ops.update_pending_flush(ctl, flush_mask);

skip_flush:
@@ -814,6 +853,8 @@ static void sde_encoder_phys_vid_get_hw_resources(

	SDE_DEBUG_VIDENC(vid_enc, "\n");
	hw_res->intfs[vid_enc->hw_intf->idx - INTF_0] = INTF_MODE_VIDEO;
	hw_res->needs_cdm = true;
	SDE_DEBUG_DRIVER("[vid] needs_cdm=%d\n", hw_res->needs_cdm);
}

static int _sde_encoder_phys_vid_wait_for_vblank(
@@ -987,6 +1028,11 @@ static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
		}
		sde_encoder_phys_vid_control_vblank_irq(phys_enc, false);
	}

	if (phys_enc->hw_cdm && phys_enc->hw_cdm->ops.disable) {
		SDE_DEBUG_DRIVER("[cdm_disable]\n");
		phys_enc->hw_cdm->ops.disable(phys_enc->hw_cdm);
	}
exit:
	phys_enc->vfp_cached = 0;
	phys_enc->enable_state = SDE_ENC_DISABLED;
+2 −120
Original line number Diff line number Diff line
@@ -30,24 +30,6 @@
#define WBID(wb_enc) \
	((wb_enc && wb_enc->wb_dev) ? wb_enc->wb_dev->wb_idx - WB_0 : -1)

#define TO_S15D16(_x_)	((_x_) << 7)

/**
 * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix
 *
 */
static struct sde_csc_cfg sde_encoder_phys_wb_rgb2yuv_601l = {
	{
		TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032),
		TO_S15D16(0x1fb5), TO_S15D16(0x1f6c), TO_S15D16(0x00e1),
		TO_S15D16(0x00e1), TO_S15D16(0x1f45), TO_S15D16(0x1fdc)
	},
	{ 0x00, 0x00, 0x00 },
	{ 0x0040, 0x0200, 0x0200 },
	{ 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff },
	{ 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 },
};

/**
 * sde_encoder_phys_wb_is_master - report wb always as master encoder
 */
@@ -153,107 +135,6 @@ static void sde_encoder_phys_wb_set_qos_remap(
	sde_vbif_set_qos_remap(phys_enc->sde_kms, &qos_params);
}

/**
 * sde_encoder_phys_setup_cdm - setup chroma down block
 * @phys_enc:	Pointer to physical encoder
 * @fb:		Pointer to output framebuffer
 * @format:	Output format
 */
void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
		struct drm_framebuffer *fb, const struct sde_format *format,
		struct sde_rect *wb_roi)
{
	struct sde_hw_cdm *hw_cdm;
	struct sde_hw_cdm_cfg *cdm_cfg;
	int ret;

	if (!phys_enc || !format)
		return;

	cdm_cfg = &phys_enc->cdm_cfg;
	hw_cdm = phys_enc->hw_cdm;
	if (!hw_cdm)
		return;

	if (!SDE_FORMAT_IS_YUV(format)) {
		SDE_DEBUG("[cdm_disable fmt:%x]\n",
				format->base.pixel_format);

		if (hw_cdm && hw_cdm->ops.disable)
			hw_cdm->ops.disable(hw_cdm);

		return;
	}

	memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg));

	if (!wb_roi)
		return;

	cdm_cfg->output_width = wb_roi->w;
	cdm_cfg->output_height = wb_roi->h;
	cdm_cfg->output_fmt = format;
	cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
	cdm_cfg->output_bit_depth = SDE_FORMAT_IS_DX(format) ?
		CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;

	/* enable 10 bit logic */
	switch (cdm_cfg->output_fmt->chroma_sample) {
	case SDE_CHROMA_RGB:
		cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
		break;
	case SDE_CHROMA_H2V1:
		cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
		break;
	case SDE_CHROMA_420:
		cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
		break;
	case SDE_CHROMA_H1V2:
	default:
		SDE_ERROR("unsupported chroma sampling type\n");
		cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
		cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
		break;
	}

	SDE_DEBUG("[cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
			cdm_cfg->output_width,
			cdm_cfg->output_height,
			cdm_cfg->output_fmt->base.pixel_format,
			cdm_cfg->output_type,
			cdm_cfg->output_bit_depth,
			cdm_cfg->h_cdwn_type,
			cdm_cfg->v_cdwn_type);

	if (hw_cdm && hw_cdm->ops.setup_csc_data) {
		ret = hw_cdm->ops.setup_csc_data(hw_cdm,
				&sde_encoder_phys_wb_rgb2yuv_601l);
		if (ret < 0) {
			SDE_ERROR("failed to setup CSC %d\n", ret);
			return;
		}
	}

	if (hw_cdm && hw_cdm->ops.setup_cdwn) {
		ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg);
		if (ret < 0) {
			SDE_ERROR("failed to setup CDM %d\n", ret);
			return;
		}
	}

	if (hw_cdm && hw_cdm->ops.enable) {
		ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
		if (ret < 0) {
			SDE_ERROR("failed to enable CDM %d\n", ret);
			return;
		}
	}
}

/**
 * sde_encoder_phys_wb_setup_fb - setup output framebuffer
 * @phys_enc:	Pointer to physical encoder
@@ -831,7 +712,8 @@ static void sde_encoder_phys_wb_setup(

	sde_encoder_phys_wb_set_qos_remap(phys_enc);

	sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi);
	sde_encoder_phys_setup_cdm(phys_enc, wb_enc->wb_fmt,
		CDM_CDWN_OUTPUT_WB, wb_roi);

	sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);

+2 −2
Original line number Diff line number Diff line
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -230,7 +230,7 @@ int sde_hw_cdm_enable(struct sde_hw_cdm *ctx,
		return -EINVAL;

	if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
		if (fmt->chroma_sample != SDE_CHROMA_H1V2)
		if (fmt->chroma_sample == SDE_CHROMA_H1V2)
			return -EINVAL; /*unsupported format */
		opmode = BIT(0);
		opmode |= (fmt->chroma_sample << 1);
Loading