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

Commit 15e5e395 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm: add YUV format support"

parents 2cbd28d7 ed859f5d
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