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

Commit cd602a89 authored by Xiaoming Zhou's avatar Xiaoming Zhou Committed by Matt Wagantall
Browse files

msm: mdss: add rotator writeback ubwc support



The writeback block in the rotator supports ubwc output.
This change enables the client to specify ubwc input and
output format.

Change-Id: Ic9aee90b0edd2128383ecb03cdf7882cd8c8e3e1
Signed-off-by: default avatarXiaoming Zhou <zhoux@codeaurora.org>
Signed-off-by: default avatarTerence Hampson <thampson@codeaurora.org>
parent 15d01beb
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@
#define MAX_FREE_LIST_SIZE	12
#define OVERLAY_MAX		10

#define VALID_ROT_WB_FORMAT BIT(0)

#define C3_ALPHA	3	/* alpha */
#define C2_R_Cr		2	/* R/Cr */
#define C1_B_Cb		1	/* B/Cb */
@@ -340,6 +342,7 @@ struct mdss_mdp_mixer {

struct mdss_mdp_format_params {
	u32 format;
	u32 flag;
	u8 is_yuv;

	u8 frame_format;
@@ -1134,6 +1137,8 @@ void mdss_mdp_data_calc_offset(struct mdss_mdp_data *data, u16 x, u16 y,
	struct mdss_mdp_plane_sizes *ps, struct mdss_mdp_format_params *fmt);
bool mdss_mdp_initialize_ubwc_factors(struct mdss_data_type *mdata);
struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
void mdss_mdp_get_v_h_subsample_rate(u8 chroma_samp,
	u8 *v_sample, u8 *h_sample);
struct mdss_fudge_factor *mdss_mdp_get_comp_factor(u32 format,
	bool rt_factor);
int mdss_mdp_data_get(struct mdss_mdp_data *data, struct msmfb_data *planes,
+49 −40
Original line number Diff line number Diff line
@@ -31,9 +31,10 @@ enum {
	COLOR_ALPHA_4BIT = 1,
};

#define FMT_RGB_565(fmt, fetch_type, e0, e1, e2)		\
#define FMT_RGB_565(fmt, fetch_type, flag_arg, e0, e1, e2)		\
	{							\
		.format = (fmt),				\
		.flag = flag_arg,					\
		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,	\
		.unpack_tight = 1,				\
		.unpack_align_msb = 0,				\
@@ -49,9 +50,10 @@ enum {
		},						\
	}

#define FMT_RGB_888(fmt, fetch_type, e0, e1, e2)		\
#define FMT_RGB_888(fmt, fetch_type, flag_arg, e0, e1, e2)		\
	{							\
		.format = (fmt),				\
		.flag = flag_arg,					\
		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,	\
		.unpack_tight = 1,				\
		.unpack_align_msb = 0,				\
@@ -67,9 +69,11 @@ enum {
		},						\
	}

#define FMT_RGB_8888(fmt, fetch_type, alpha_en, e0, e1, e2, e3)	\
#define FMT_RGB_8888(fmt, fetch_type, flag_arg,	\
		alpha_en, e0, e1, e2, e3)	\
	{							\
		.format = (fmt),				\
		.flag = flag_arg,					\
		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,	\
		.unpack_tight = 1,				\
		.unpack_align_msb = 0,				\
@@ -98,9 +102,11 @@ enum {
		.unpack_tight = 1,				\
		.unpack_align_msb = 0

#define FMT_YUV_PSEUDO(fmt, fetch_type, samp, e0, e1)		\
#define FMT_YUV_PSEUDO(fmt, fetch_type, samp, \
		flag_arg, e0, e1)		\
	{							\
		FMT_YUV_COMMON(fmt),				\
		.flag = flag_arg,					\
		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,	\
		.chroma_sample = samp,				\
		.unpack_count = 2,				\
@@ -109,9 +115,11 @@ enum {
		.element = { (e0), (e1) },			\
	}

#define FMT_YUV_PLANR(fmt, fetch_type, samp, e0, e1)		\
#define FMT_YUV_PLANR(fmt, fetch_type, samp, \
		flag_arg, e0, e1)		\
	{							\
		FMT_YUV_COMMON(fmt),				\
		.flag = flag_arg,					\
		.fetch_planes = MDSS_MDP_PLANE_PLANAR,		\
		.chroma_sample = samp,				\
		.bpp = 1,					\
@@ -193,13 +201,14 @@ static struct mdss_fudge_factor ubwc_nrt_factors[][UBWC_TOTAL_FORMATS] = {
static struct mdss_mdp_format_params_ubwc mdss_mdp_format_ubwc_map[] = {
	{
		.mdp_format = FMT_RGB_565(MDP_RGB_565_UBWC,
			MDSS_MDP_FETCH_UBWC, C1_B_Cb, C0_G_Y, C2_R_Cr),
			MDSS_MDP_FETCH_UBWC, VALID_ROT_WB_FORMAT,
			C1_B_Cb, C0_G_Y, C2_R_Cr),
		.comp_ratio_rt = {1, 1},
		.comp_ratio_nrt = {1, 1},
	},
	{
		.mdp_format = FMT_RGB_8888(MDP_RGBA_8888_UBWC,
			MDSS_MDP_FETCH_UBWC, 1,
			MDSS_MDP_FETCH_UBWC, VALID_ROT_WB_FORMAT, 1,
			C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
		.comp_ratio_rt = {1, 1},
		.comp_ratio_nrt = {1, 1},
@@ -207,80 +216,80 @@ static struct mdss_mdp_format_params_ubwc mdss_mdp_format_ubwc_map[] = {
	{
		.mdp_format = FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2_UBWC,
			MDSS_MDP_FETCH_UBWC, MDSS_MDP_CHROMA_420,
			C1_B_Cb, C2_R_Cr),
			VALID_ROT_WB_FORMAT, C1_B_Cb, C2_R_Cr),
		.comp_ratio_rt = {1, 1},
		.comp_ratio_nrt = {1, 1},
	},
};

static struct mdss_mdp_format_params mdss_mdp_format_map[] = {
	FMT_RGB_565(MDP_RGB_565, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_565(MDP_RGB_565, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		C1_B_Cb, C0_G_Y, C2_R_Cr),
	FMT_RGB_565(MDP_BGR_565, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_565(MDP_BGR_565, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		C2_R_Cr, C0_G_Y, C1_B_Cb),
	FMT_RGB_565(MDP_RGB_565_TILE, MDSS_MDP_FETCH_TILE,
	FMT_RGB_565(MDP_RGB_565_TILE, MDSS_MDP_FETCH_TILE, VALID_ROT_WB_FORMAT,
		C1_B_Cb, C0_G_Y, C2_R_Cr),
	FMT_RGB_565(MDP_BGR_565_TILE, MDSS_MDP_FETCH_TILE,
	FMT_RGB_565(MDP_BGR_565_TILE, MDSS_MDP_FETCH_TILE, VALID_ROT_WB_FORMAT,
		C2_R_Cr, C0_G_Y, C1_B_Cb),
	FMT_RGB_888(MDP_RGB_888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_888(MDP_RGB_888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		C2_R_Cr, C0_G_Y, C1_B_Cb),
	FMT_RGB_888(MDP_BGR_888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_888(MDP_BGR_888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		C1_B_Cb, C0_G_Y, C2_R_Cr),

	FMT_RGB_8888(MDP_XRGB_8888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_8888(MDP_XRGB_8888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
	FMT_RGB_8888(MDP_ARGB_8888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_8888(MDP_ARGB_8888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
	FMT_RGB_8888(MDP_RGBA_8888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_8888(MDP_RGBA_8888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
	FMT_RGB_8888(MDP_RGBX_8888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_8888(MDP_RGBX_8888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
	FMT_RGB_8888(MDP_BGRA_8888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_8888(MDP_BGRA_8888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
	FMT_RGB_8888(MDP_BGRX_8888, MDSS_MDP_FETCH_LINEAR,
	FMT_RGB_8888(MDP_BGRX_8888, MDSS_MDP_FETCH_LINEAR, VALID_ROT_WB_FORMAT,
		0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
	FMT_RGB_8888(MDP_RGBA_8888_TILE, MDSS_MDP_FETCH_TILE,
		1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
		VALID_ROT_WB_FORMAT, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
	FMT_RGB_8888(MDP_ARGB_8888_TILE, MDSS_MDP_FETCH_TILE,
		1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
		VALID_ROT_WB_FORMAT, 1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
	FMT_RGB_8888(MDP_ABGR_8888_TILE, MDSS_MDP_FETCH_TILE,
		1, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
		VALID_ROT_WB_FORMAT, 1, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
	FMT_RGB_8888(MDP_BGRA_8888_TILE, MDSS_MDP_FETCH_TILE,
		1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
		VALID_ROT_WB_FORMAT, 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
	FMT_RGB_8888(MDP_RGBX_8888_TILE, MDSS_MDP_FETCH_TILE,
		0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
		VALID_ROT_WB_FORMAT, 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
	FMT_RGB_8888(MDP_XRGB_8888_TILE, MDSS_MDP_FETCH_TILE,
		0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
		VALID_ROT_WB_FORMAT, 0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
	FMT_RGB_8888(MDP_XBGR_8888_TILE, MDSS_MDP_FETCH_TILE,
		0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
		VALID_ROT_WB_FORMAT, 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
	FMT_RGB_8888(MDP_BGRX_8888_TILE, MDSS_MDP_FETCH_TILE,
		0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
		VALID_ROT_WB_FORMAT, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),

	FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V1, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_RGB, C2_R_Cr, C1_B_Cb),
		MDSS_MDP_CHROMA_RGB, 0, C2_R_Cr, C1_B_Cb),
	FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V1, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_RGB, C1_B_Cb, C2_R_Cr),
		MDSS_MDP_CHROMA_RGB, 0, C1_B_Cb, C2_R_Cr),
	FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V1, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_H2V1, C2_R_Cr, C1_B_Cb),
		MDSS_MDP_CHROMA_H2V1, 0, C2_R_Cr, C1_B_Cb),
	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V1, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_H2V1, C1_B_Cb, C2_R_Cr),
		MDSS_MDP_CHROMA_H2V1, VALID_ROT_WB_FORMAT, C1_B_Cb, C2_R_Cr),
	FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V2, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_H1V2, C2_R_Cr, C1_B_Cb),
		MDSS_MDP_CHROMA_H1V2, 0, C2_R_Cr, C1_B_Cb),
	FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V2, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_H1V2, C1_B_Cb, C2_R_Cr),
		MDSS_MDP_CHROMA_H1V2, VALID_ROT_WB_FORMAT, C1_B_Cb, C2_R_Cr),
	FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V2, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
		MDSS_MDP_CHROMA_420, 0, C2_R_Cr, C1_B_Cb),
	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
		MDSS_MDP_CHROMA_420, VALID_ROT_WB_FORMAT, C1_B_Cb, C2_R_Cr),
	FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2_VENUS, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
		MDSS_MDP_CHROMA_420, 0, C1_B_Cb, C2_R_Cr),

	FMT_YUV_PLANR(MDP_Y_CB_CR_H2V2, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
		MDSS_MDP_CHROMA_420, VALID_ROT_WB_FORMAT, C2_R_Cr, C1_B_Cb),
	FMT_YUV_PLANR(MDP_Y_CR_CB_H2V2, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
		MDSS_MDP_CHROMA_420, 0, C1_B_Cb, C2_R_Cr),
	FMT_YUV_PLANR(MDP_Y_CR_CB_GH2V2, MDSS_MDP_FETCH_LINEAR,
		MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
		MDSS_MDP_CHROMA_420, 0, C1_B_Cb, C2_R_Cr),

	{
		FMT_YUV_COMMON(MDP_YCBCR_H1V1),
+0 −5
Original line number Diff line number Diff line
@@ -272,11 +272,6 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx,
			pr_err("unsupported wb chroma samp=%d\n", chroma_samp);
			return -EINVAL;
		}
	} else if (ctx->rot90) {
		if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
			chroma_samp = MDSS_MDP_CHROMA_H1V2;
		else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
			chroma_samp = MDSS_MDP_CHROMA_H2V1;
	}

	dst_format = (chroma_samp << 23) |
+35 −16
Original line number Diff line number Diff line
@@ -300,6 +300,29 @@ end:
		!mdss_mdp_is_ubwc_supported(mdata)) ? NULL : fmt;
}

void mdss_mdp_get_v_h_subsample_rate(u8 chroma_sample,
		u8 *v_sample, u8 *h_sample)
{
	switch (chroma_sample) {
	case MDSS_MDP_CHROMA_H2V1:
		*v_sample = 1;
		*h_sample = 2;
		break;
	case MDSS_MDP_CHROMA_H1V2:
		*v_sample = 2;
		*h_sample = 1;
		break;
	case MDSS_MDP_CHROMA_420:
		*v_sample = 2;
		*h_sample = 2;
		break;
	default:
		*v_sample = 1;
		*h_sample = 1;
		break;
	}
}

void mdss_mdp_intersect_rect(struct mdss_rect *res_rect,
	const struct mdss_rect *dst_rect,
	const struct mdss_rect *sci_rect)
@@ -596,9 +619,7 @@ int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h,
			ps->plane_size[1] = VENUS_UV_SCANLINES(cf, h) *
				ps->ystride[1];
		} else {
			u8 hmap[] = { 1, 2, 1, 2 };
			u8 vmap[] = { 1, 1, 2, 2 };
			u8 horiz, vert, stride_align, height_align;
			u8 v_subsample, h_subsample, stride_align, height_align;
			u32 chroma_samp;

			chroma_samp = fmt->chroma_sample;
@@ -610,13 +631,8 @@ int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h,
					chroma_samp = MDSS_MDP_CHROMA_H2V1;
			}

			if (chroma_samp >= ARRAY_SIZE(hmap) ||
				chroma_samp >= ARRAY_SIZE(vmap)) {
				pr_err("%s: out of bounds error\n", __func__);
				return -ERANGE;
			}
			horiz = hmap[chroma_samp];
			vert = vmap[chroma_samp];
			mdss_mdp_get_v_h_subsample_rate(chroma_samp,
				&v_subsample, &h_subsample);

			switch (fmt->format) {
			case MDP_Y_CR_CB_GH2V2:
@@ -630,10 +646,10 @@ int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h,
			}

			ps->ystride[0] = ALIGN(w, stride_align);
			ps->ystride[1] = ALIGN(w / horiz, stride_align);
			ps->ystride[1] = ALIGN(w / h_subsample, stride_align);
			ps->plane_size[0] = ps->ystride[0] *
				ALIGN(h, height_align);
			ps->plane_size[1] = ps->ystride[1] * (h / vert);
			ps->plane_size[1] = ps->ystride[1] * (h / v_subsample);

			if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
				ps->num_planes = 2;
@@ -806,10 +822,13 @@ void mdss_mdp_data_calc_offset(struct mdss_mdp_data *data, u16 x, u16 y,
	if (data->num_planes == 1) {
		data->p[0].addr += x * fmt->bpp;
	} else {
		u8 hmap[] = { 1, 2, 1, 2 };
		u8 vmap[] = { 1, 1, 2, 2 };
		u16 xoff = x / hmap[fmt->chroma_sample];
		u16 yoff = y / vmap[fmt->chroma_sample];
		u16 xoff, yoff;
		u8 v_subsample, h_subsample;
		mdss_mdp_get_v_h_subsample_rate(fmt->chroma_sample,
			&v_subsample, &h_subsample);

		xoff = x / h_subsample;
		yoff = y / v_subsample;

		data->p[0].addr += x;
		data->p[1].addr += xoff + (yoff * ps->ystride[1]);
+129 −40
Original line number Diff line number Diff line
@@ -657,6 +657,7 @@ static int mdss_rotator_config_dnsc_factor(struct mdss_rot_mgr *mgr,
	int ret = 0;
	u16 src_w, src_h, dst_w, dst_h, bit;
	struct mdp_rotation_item *item = &entry->item;
	struct mdss_mdp_format_params *fmt;

	src_w = item->src_rect.w;
	src_h = item->src_rect.h;
@@ -698,6 +699,14 @@ static int mdss_rotator_config_dnsc_factor(struct mdss_rot_mgr *mgr,
		}
	}

	fmt =  mdss_mdp_get_format_params(item->output.format);
	if (mdss_mdp_is_ubwc_format(fmt) &&
		(entry->dnsc_factor_h || entry->dnsc_factor_w)) {
		pr_err("ubwc not supported with downscale %d\n",
			item->output.format);
		ret = -EINVAL;
	}

dnsc_err:

	/* Downscaler does not support asymmetrical dnsc */
@@ -713,29 +722,114 @@ dnsc_err:
	return ret;
}

static u32 mdss_rotator_get_out_format(u32 in_format, bool rot90)
static bool mdss_rotator_verify_format(struct mdss_rot_mgr *mgr,
	struct mdss_mdp_format_params *in_fmt,
	struct mdss_mdp_format_params *out_fmt, bool rotation)
{
	u32 format;
	u8 in_v_subsample, in_h_subsample;
	u8 out_v_subsample, out_h_subsample;

	switch (in_format) {
	case MDP_Y_CBCR_H2V2_VENUS:
	case MDP_Y_CBCR_H2V2:
		if (rot90)
			format = MDP_Y_CRCB_H2V2;
		else
			format = in_format;
		break;
	case MDP_Y_CB_CR_H2V2:
	case MDP_Y_CR_CB_GH2V2:
	case MDP_Y_CR_CB_H2V2:
		format = MDP_Y_CRCB_H2V2;
		break;
	default:
		format = in_format;
		break;
	if (!mgr->has_ubwc && (mdss_mdp_is_ubwc_format(in_fmt) ||
			mdss_mdp_is_ubwc_format(out_fmt))) {
		pr_err("Rotator doesn't allow ubwc\n");
		return -EINVAL;
	}

	if (!(out_fmt->flag & VALID_ROT_WB_FORMAT)) {
		pr_err("Invalid output format\n");
		return false;
	}

	return format;
	if (in_fmt->is_yuv != out_fmt->is_yuv) {
		pr_err("Rotator does not support CSC\n");
		return false;
	}

	/* Forcing same pixel depth */
	if (memcmp(in_fmt->bits, out_fmt->bits, sizeof(in_fmt->bits))) {
		pr_err("Bit format does not match\n");
		return false;
	}

	/* Need to make sure that sub-sampling persists through rotation */
	if (rotation) {
		mdss_mdp_get_v_h_subsample_rate(in_fmt->chroma_sample,
			&in_v_subsample, &in_h_subsample);
		mdss_mdp_get_v_h_subsample_rate(out_fmt->chroma_sample,
			&out_v_subsample, &out_h_subsample);

		if ((in_v_subsample != out_h_subsample) ||
				(in_h_subsample != out_v_subsample)) {
			pr_err("Rotation has invalid subsampling\n");
			return false;
		}
	} else {
		if (in_fmt->chroma_sample != out_fmt->chroma_sample) {
			pr_err("Format subsampling mismatch\n");
			return false;
		}
	}

	pr_debug("in_fmt=%0d, out_fmt=%d, has_ubwc=%d\n",
		in_fmt->format, out_fmt->format, mgr->has_ubwc);
	return true;
}

static int mdss_rotator_verify_config(struct mdss_rot_mgr *mgr,
	struct mdp_rotation_config *config)
{
	struct mdss_mdp_format_params *in_fmt, *out_fmt;
	u8 in_v_subsample, in_h_subsample;
	u8 out_v_subsample, out_h_subsample;
	u32 input, output;
	bool rotation;

	input = config->input.format;
	output = config->output.format;
	rotation = (config->flags & MDP_ROTATION_90) ? true : false;

	in_fmt = mdss_mdp_get_format_params(input);
	if (!in_fmt) {
		pr_err("Unrecognized input format:%u\n", input);
		return -EINVAL;
	}

	out_fmt = mdss_mdp_get_format_params(output);
	if (!out_fmt) {
		pr_err("Unrecognized output format:%u\n", output);
		return -EINVAL;
	}

	mdss_mdp_get_v_h_subsample_rate(in_fmt->chroma_sample,
		&in_v_subsample, &in_h_subsample);
	mdss_mdp_get_v_h_subsample_rate(out_fmt->chroma_sample,
		&out_v_subsample, &out_h_subsample);

	/* Dimension of image needs to be divisible by subsample rate  */
	if ((config->input.height % in_v_subsample) ||
			(config->input.width % in_h_subsample)) {
		pr_err("In ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n",
			config->input.width, config->input.height,
			in_v_subsample, in_h_subsample);
		return -EINVAL;
	}

	if ((config->output.height % out_v_subsample) ||
			(config->output.width % out_h_subsample)) {
		pr_err("Out ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n",
			config->output.width, config->output.height,
			out_v_subsample, out_h_subsample);
		return -EINVAL;
	}

	if (!mdss_rotator_verify_format(mgr, in_fmt,
			out_fmt, rotation)) {
		pr_err("Rot format pairing invalid, in_fmt:%d, out_fmt:%d\n",
			input, output);
		return -EINVAL;
	}

	return 0;
}

static int mdss_rotator_validate_entry(struct mdss_rot_mgr *mgr,
@@ -744,11 +838,10 @@ static int mdss_rotator_validate_entry(struct mdss_rot_mgr *mgr,
	int ret;
	u32 out_format, in_format;
	struct mdp_rotation_item *item;
	struct mdss_mdp_format_params *fmt;
	bool rotation = false;

	item = &entry->item;
	in_format = item->input.format;
	out_format = item->output.format;

	if (item->wb_idx != item->pipe_idx) {
		pr_err("invalid writeback and pipe idx\n");
@@ -761,20 +854,6 @@ static int mdss_rotator_validate_entry(struct mdss_rot_mgr *mgr,
		return -EINVAL;
	}

	fmt = mdss_mdp_get_format_params(in_format);
	if (!fmt) {
		pr_err("invalid input format %u\n", in_format);
		return -EINVAL;
	}

	rotation = (item->flags &  MDP_ROTATION_90) ? true : false;
	out_format =
		mdss_rotator_get_out_format(in_format, rotation);
	if (item->output.format != out_format) {
		pr_err("invalid output format %u\n", item->output.format);
		return -EINVAL;
	}

	ret = mdss_rotator_config_dnsc_factor(mgr, entry);
	if (ret) {
		pr_err("fail to configure downscale factor\n");
@@ -1202,7 +1281,6 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr,
	struct mdp_rotation_config config;
	struct mdss_rot_perf *perf;
	int ret;
	u32 in_format;

	ret = copy_from_user(&config, (void __user *)arg, sizeof(config));
	if (ret) {
@@ -1210,6 +1288,12 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr,
		return ret;
	}

	ret = mdss_rotator_verify_config(mgr, &config);
	if (ret) {
		pr_err("Rotator verify format failed\n");
		return ret;
	}

	perf = devm_kzalloc(&mgr->pdev->dev, sizeof(*perf), GFP_KERNEL);
	if (!perf) {
		pr_err("fail to allocate session\n");
@@ -1217,9 +1301,6 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr,
	}

	config.session_id = mdss_rotator_generator_session_id(mgr);
	in_format = config.input.format;
	config.output.format =
		mdss_rotator_get_out_format(in_format, true);
	perf->config = config;
	INIT_LIST_HEAD(&perf->list);

@@ -1287,6 +1368,12 @@ static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr,
		return ret;
	}

	ret = mdss_rotator_verify_config(mgr, &config);
	if (ret) {
		pr_err("Rotator verify format failed\n");
		return ret;
	}

	perf = mdss_rotator_find_session(private, config.session_id);
	if (!perf)
		return -EINVAL;
@@ -1693,6 +1780,8 @@ static int mdss_rotator_parse_dt(struct mdss_rot_mgr *mgr,
	rot_mgr->queue_count = data;
	rot_mgr->has_downscale = of_property_read_bool(dev->dev.of_node,
					   "qcom,mdss-has-downscale");
	rot_mgr->has_ubwc = of_property_read_bool(dev->dev.of_node,
					   "qcom,mdss-has-ubwc");
	return 0;
}

Loading