diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c
index fdab41165f5a..480f89381f15 100644
--- a/drivers/media/platform/rcar_fdp1.c
+++ b/drivers/media/platform/rcar_fdp1.c
@@ -40,7 +40,7 @@ static unsigned int debug;
 module_param(debug, uint, 0644);
 MODULE_PARM_DESC(debug, "activate debug info");
 
-/* Min Width/Height/Height-Field */
+/* Minimum and maximum frame width/height */
 #define FDP1_MIN_W		80U
 #define FDP1_MIN_H		80U
 
@@ -48,6 +48,7 @@ MODULE_PARM_DESC(debug, "activate debug info");
 #define FDP1_MAX_H		2160U
 
 #define FDP1_MAX_PLANES		3U
+#define FDP1_MAX_STRIDE		8190U
 
 /* Flags that indicate a format can be used for capture/output */
 #define FDP1_CAPTURE		BIT(0)
@@ -1506,82 +1507,12 @@ static int fdp1_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return 0;
 }
 
-static int __fdp1_try_fmt(struct fdp1_ctx *ctx, const struct fdp1_fmt **fmtinfo,
-			  struct v4l2_pix_format_mplane *pix,
-			  enum v4l2_buf_type type)
+static void fdp1_compute_stride(struct v4l2_pix_format_mplane *pix,
+				const struct fdp1_fmt *fmt)
 {
-	const struct fdp1_fmt *fmt;
-	unsigned int width = pix->width;
-	unsigned int height = pix->height;
-	unsigned int fmt_type;
 	unsigned int i;
 
-	fmt_type = V4L2_TYPE_IS_OUTPUT(type) ? FDP1_OUTPUT : FDP1_CAPTURE;
-
-	fmt = fdp1_find_format(pix->pixelformat);
-	if (!fmt || !(fmt->types & fmt_type))
-		fmt = fdp1_find_format(V4L2_PIX_FMT_YUYV);
-
-	pix->pixelformat = fmt->fourcc;
-
-	/* Manage colorspace on the two queues */
-	if (V4L2_TYPE_IS_OUTPUT(type)) {
-		if (pix->colorspace == V4L2_COLORSPACE_DEFAULT)
-			pix->colorspace = V4L2_COLORSPACE_REC709;
-
-		if (pix->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
-			pix->ycbcr_enc =
-				V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
-
-		if (pix->quantization == V4L2_QUANTIZATION_DEFAULT)
-			pix->quantization =
-				V4L2_MAP_QUANTIZATION_DEFAULT(false,
-						pix->colorspace,
-						pix->ycbcr_enc);
-	} else {
-		/* Manage the CAPTURE Queue */
-		struct fdp1_q_data *src_data = &ctx->out_q;
-
-		if (fdp1_fmt_is_rgb(fmt)) {
-			pix->colorspace = V4L2_COLORSPACE_SRGB;
-			pix->ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
-			pix->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-		} else {
-			/* Copy input queue colorspace across */
-			pix->colorspace = src_data->format.colorspace;
-			pix->ycbcr_enc = src_data->format.ycbcr_enc;
-			pix->quantization = src_data->format.quantization;
-		}
-	}
-
-	/* We should be allowing FIELDS through on the Output queue !*/
-	if (V4L2_TYPE_IS_OUTPUT(type)) {
-		/* Clamp to allowable field types */
-		if (pix->field == V4L2_FIELD_ANY ||
-		    pix->field == V4L2_FIELD_NONE)
-			pix->field = V4L2_FIELD_NONE;
-		else if (!V4L2_FIELD_HAS_BOTH(pix->field))
-			pix->field = V4L2_FIELD_INTERLACED;
-
-		dprintk(ctx->fdp1, "Output Field Type set as %d\n", pix->field);
-	} else {
-		pix->field = V4L2_FIELD_NONE;
-	}
-
-	pix->num_planes = fmt->num_planes;
-
-	/* Align the width and height for YUV 4:2:2 and 4:2:0 formats. */
-	width = round_down(width, fmt->hsub);
-	height = round_down(height, fmt->vsub);
-
-	/* Clamp the width and height */
-	pix->width = clamp(width, FDP1_MIN_W, FDP1_MAX_W);
-	pix->height = clamp(height, FDP1_MIN_H, FDP1_MAX_H);
-
-	/* Compute and clamp the stride and image size. While not documented in
-	 * the datasheet, strides not aligned to a multiple of 128 bytes result
-	 * in image corruption.
-	 */
+	/* Compute and clamp the stride and image size. */
 	for (i = 0; i < min_t(unsigned int, fmt->num_planes, 2U); ++i) {
 		unsigned int hsub = i > 0 ? fmt->hsub : 1;
 		unsigned int vsub = i > 0 ? fmt->vsub : 1;
@@ -1591,91 +1522,247 @@ static int __fdp1_try_fmt(struct fdp1_ctx *ctx, const struct fdp1_fmt **fmtinfo,
 
 		bpl = clamp_t(unsigned int, pix->plane_fmt[i].bytesperline,
 			      pix->width / hsub * fmt->bpp[i] / 8,
-			      round_down(65535U, align));
+			      round_down(FDP1_MAX_STRIDE, align));
 
 		pix->plane_fmt[i].bytesperline = round_up(bpl, align);
 		pix->plane_fmt[i].sizeimage = pix->plane_fmt[i].bytesperline
 					    * pix->height / vsub;
 
 		memset(pix->plane_fmt[i].reserved, 0,
-				sizeof(pix->plane_fmt[i].reserved));
+		       sizeof(pix->plane_fmt[i].reserved));
 	}
 
 	if (fmt->num_planes == 3) {
-		/* The second and third planes must have the same stride. */
+		/* The two chroma planes must have the same stride. */
 		pix->plane_fmt[2].bytesperline = pix->plane_fmt[1].bytesperline;
 		pix->plane_fmt[2].sizeimage = pix->plane_fmt[1].sizeimage;
 
 		memset(pix->plane_fmt[2].reserved, 0,
-				sizeof(pix->plane_fmt[2].reserved));
+		       sizeof(pix->plane_fmt[2].reserved));
 	}
+}
+
+static void fdp1_try_fmt_output(struct fdp1_ctx *ctx,
+				const struct fdp1_fmt **fmtinfo,
+				struct v4l2_pix_format_mplane *pix)
+{
+	const struct fdp1_fmt *fmt;
+	unsigned int width;
+	unsigned int height;
+
+	/* Validate the pixel format to ensure the output queue supports it. */
+	fmt = fdp1_find_format(pix->pixelformat);
+	if (!fmt || !(fmt->types & FDP1_OUTPUT))
+		fmt = fdp1_find_format(V4L2_PIX_FMT_YUYV);
+
+	if (fmtinfo)
+		*fmtinfo = fmt;
 
+	pix->pixelformat = fmt->fourcc;
 	pix->num_planes = fmt->num_planes;
 
+	/*
+	 * Progressive video and all interlaced field orders are acceptable.
+	 * Default to V4L2_FIELD_INTERLACED.
+	 */
+	if (pix->field != V4L2_FIELD_NONE &&
+	    pix->field != V4L2_FIELD_ALTERNATE &&
+	    !V4L2_FIELD_HAS_BOTH(pix->field))
+		pix->field = V4L2_FIELD_INTERLACED;
+
+	/*
+	 * The deinterlacer doesn't care about the colorspace, accept all values
+	 * and default to V4L2_COLORSPACE_SMPTE170M. The YUV to RGB conversion
+	 * at the output of the deinterlacer supports a subset of encodings and
+	 * quantization methods and will only be available when the colorspace
+	 * allows it.
+	 */
+	if (pix->colorspace == V4L2_COLORSPACE_DEFAULT)
+		pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	/*
+	 * Align the width and height for YUV 4:2:2 and 4:2:0 formats and clamp
+	 * them to the supported frame size range. The height boundary are
+	 * related to the full frame, divide them by two when the format passes
+	 * fields in separate buffers.
+	 */
+	width = round_down(pix->width, fmt->hsub);
+	pix->width = clamp(width, FDP1_MIN_W, FDP1_MAX_W);
+
+	height = round_down(pix->height, fmt->vsub);
+	if (pix->field == V4L2_FIELD_ALTERNATE)
+		pix->height = clamp(height, FDP1_MIN_H / 2, FDP1_MAX_H / 2);
+	else
+		pix->height = clamp(height, FDP1_MIN_H, FDP1_MAX_H);
+
+	fdp1_compute_stride(pix, fmt);
+}
+
+static void fdp1_try_fmt_capture(struct fdp1_ctx *ctx,
+				 const struct fdp1_fmt **fmtinfo,
+				 struct v4l2_pix_format_mplane *pix)
+{
+	struct fdp1_q_data *src_data = &ctx->out_q;
+	enum v4l2_colorspace colorspace;
+	enum v4l2_ycbcr_encoding ycbcr_enc;
+	enum v4l2_quantization quantization;
+	const struct fdp1_fmt *fmt;
+	bool allow_rgb;
+
+	/*
+	 * Validate the pixel format. We can only accept RGB output formats if
+	 * the input encoding and quantization are compatible with the format
+	 * conversions supported by the hardware. The supported combinations are
+	 *
+	 * V4L2_YCBCR_ENC_601 + V4L2_QUANTIZATION_LIM_RANGE
+	 * V4L2_YCBCR_ENC_601 + V4L2_QUANTIZATION_FULL_RANGE
+	 * V4L2_YCBCR_ENC_709 + V4L2_QUANTIZATION_LIM_RANGE
+	 */
+	colorspace = src_data->format.colorspace;
+
+	ycbcr_enc = src_data->format.ycbcr_enc;
+	if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+		ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
+
+	quantization = src_data->format.quantization;
+	if (quantization == V4L2_QUANTIZATION_DEFAULT)
+		quantization = V4L2_MAP_QUANTIZATION_DEFAULT(false, colorspace,
+							     ycbcr_enc);
+
+	allow_rgb = ycbcr_enc == V4L2_YCBCR_ENC_601 ||
+		    (ycbcr_enc == V4L2_YCBCR_ENC_709 &&
+		     quantization == V4L2_QUANTIZATION_LIM_RANGE);
+
+	fmt = fdp1_find_format(pix->pixelformat);
+	if (!fmt || (!allow_rgb && fdp1_fmt_is_rgb(fmt)))
+		fmt = fdp1_find_format(V4L2_PIX_FMT_YUYV);
+
 	if (fmtinfo)
 		*fmtinfo = fmt;
 
-	return 0;
+	pix->pixelformat = fmt->fourcc;
+	pix->num_planes = fmt->num_planes;
+	pix->field = V4L2_FIELD_NONE;
+
+	/*
+	 * The colorspace on the capture queue is copied from the output queue
+	 * as the hardware can't change the colorspace. It can convert YCbCr to
+	 * RGB though, in which case the encoding and quantization are set to
+	 * default values as anything else wouldn't make sense.
+	 */
+	pix->colorspace = src_data->format.colorspace;
+	pix->xfer_func = src_data->format.xfer_func;
+
+	if (fdp1_fmt_is_rgb(fmt)) {
+		pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+		pix->quantization = V4L2_QUANTIZATION_DEFAULT;
+	} else {
+		pix->ycbcr_enc = src_data->format.ycbcr_enc;
+		pix->quantization = src_data->format.quantization;
+	}
+
+	/*
+	 * The frame width is identical to the output queue, and the height is
+	 * either doubled or identical depending on whether the output queue
+	 * field order contains one or two fields per frame.
+	 */
+	pix->width = src_data->format.width;
+	if (src_data->format.field == V4L2_FIELD_ALTERNATE)
+		pix->height = 2 * src_data->format.height;
+	else
+		pix->height = src_data->format.height;
+
+	fdp1_compute_stride(pix, fmt);
 }
 
 static int fdp1_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
 	struct fdp1_ctx *ctx = fh_to_ctx(priv);
-	int ret;
 
-	ret = __fdp1_try_fmt(ctx, NULL, &f->fmt.pix_mp, f->type);
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		fdp1_try_fmt_output(ctx, NULL, &f->fmt.pix_mp);
+	else
+		fdp1_try_fmt_capture(ctx, NULL, &f->fmt.pix_mp);
 
-	if (ret < 0)
-		dprintk(ctx->fdp1, "try_fmt failed %d\n", ret);
+	dprintk(ctx->fdp1, "Try %s format: %4s (0x%08x) %ux%u field %u\n",
+		V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture",
+		(char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat,
+		f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field);
 
-	return ret;
+	return 0;
 }
 
-static int fdp1_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+static void fdp1_set_format(struct fdp1_ctx *ctx,
+			    struct v4l2_pix_format_mplane *pix,
+			    enum v4l2_buf_type type)
 {
-	struct vb2_queue *vq;
-	struct fdp1_ctx *ctx = fh_to_ctx(priv);
-	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-	struct fdp1_q_data *q_data;
+	struct fdp1_q_data *q_data = get_q_data(ctx, type);
 	const struct fdp1_fmt *fmtinfo;
-	int ret;
-
-	vq = v4l2_m2m_get_vq(m2m_ctx, f->type);
-
-	if (vb2_is_busy(vq)) {
-		v4l2_err(&ctx->fdp1->v4l2_dev, "%s queue busy\n", __func__);
-		return -EBUSY;
-	}
 
-	ret = __fdp1_try_fmt(ctx, &fmtinfo, &f->fmt.pix_mp, f->type);
-	if (ret < 0) {
-		v4l2_err(&ctx->fdp1->v4l2_dev, "set_fmt failed %d\n", ret);
-		return ret;
-	}
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		fdp1_try_fmt_output(ctx, &fmtinfo, pix);
+	else
+		fdp1_try_fmt_capture(ctx, &fmtinfo, pix);
 
-	q_data = get_q_data(ctx, f->type);
-	q_data->format = f->fmt.pix_mp;
 	q_data->fmt = fmtinfo;
+	q_data->format = *pix;
 
-	q_data->vsize = f->fmt.pix_mp.height;
-	if (q_data->format.field != V4L2_FIELD_NONE)
+	q_data->vsize = pix->height;
+	if (pix->field != V4L2_FIELD_NONE)
 		q_data->vsize /= 2;
 
-	q_data->stride_y = q_data->format.plane_fmt[0].bytesperline;
-	q_data->stride_c = q_data->format.plane_fmt[1].bytesperline;
+	q_data->stride_y = pix->plane_fmt[0].bytesperline;
+	q_data->stride_c = pix->plane_fmt[1].bytesperline;
 
 	/* Adjust strides for interleaved buffers */
-	if (q_data->format.field == V4L2_FIELD_INTERLACED ||
-	    q_data->format.field == V4L2_FIELD_INTERLACED_TB ||
-	    q_data->format.field == V4L2_FIELD_INTERLACED_BT) {
+	if (pix->field == V4L2_FIELD_INTERLACED ||
+	    pix->field == V4L2_FIELD_INTERLACED_TB ||
+	    pix->field == V4L2_FIELD_INTERLACED_BT) {
 		q_data->stride_y *= 2;
 		q_data->stride_c *= 2;
 	}
 
-	dprintk(ctx->fdp1,
-		"Setting format for type %d, wxh: %dx%d, fmt: %4s (%d)\n",
-			f->type, q_data->format.width, q_data->format.height,
-			(char *)&q_data->fmt->fourcc, q_data->fmt->fourcc);
+	/* Propagate the format from the output node to the capture node. */
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		struct fdp1_q_data *dst_data = &ctx->cap_q;
+
+		/*
+		 * Copy the format, clear the per-plane bytes per line and image
+		 * size, override the field and double the height if needed.
+		 */
+		dst_data->format = q_data->format;
+		memset(dst_data->format.plane_fmt, 0,
+		       sizeof(dst_data->format.plane_fmt));
+
+		dst_data->format.field = V4L2_FIELD_NONE;
+		if (pix->field == V4L2_FIELD_ALTERNATE)
+			dst_data->format.height *= 2;
+
+		fdp1_try_fmt_capture(ctx, &dst_data->fmt, &dst_data->format);
+
+		dst_data->vsize = dst_data->format.height;
+		dst_data->stride_y = dst_data->format.plane_fmt[0].bytesperline;
+		dst_data->stride_c = dst_data->format.plane_fmt[1].bytesperline;
+	}
+}
+
+static int fdp1_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+	struct fdp1_ctx *ctx = fh_to_ctx(priv);
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	struct vb2_queue *vq = v4l2_m2m_get_vq(m2m_ctx, f->type);
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ctx->fdp1->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	fdp1_set_format(ctx, &f->fmt.pix_mp, f->type);
+
+	dprintk(ctx->fdp1, "Set %s format: %4s (0x%08x) %ux%u field %u\n",
+		V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture",
+		(char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat,
+		f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field);
 
 	return 0;
 }
@@ -1989,6 +2076,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
 static int fdp1_open(struct file *file)
 {
 	struct fdp1_dev *fdp1 = video_drvdata(file);
+	struct v4l2_pix_format_mplane format;
 	struct fdp1_ctx *ctx = NULL;
 	struct v4l2_ctrl *ctrl;
 	unsigned int i;
@@ -2044,10 +2132,8 @@ static int fdp1_open(struct file *file)
 	v4l2_ctrl_handler_setup(&ctx->hdl);
 
 	/* Configure default parameters. */
-	__fdp1_try_fmt(ctx, &ctx->out_q.fmt, &ctx->out_q.format,
-		      V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-	__fdp1_try_fmt(ctx, &ctx->cap_q.fmt, &ctx->cap_q.format,
-		      V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	memset(&format, 0, sizeof(format));
+	fdp1_set_format(ctx, &format, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
 
 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fdp1->m2m_dev, ctx, &queue_init);
 
