From ec10b80313356749f3d452f327c488155c29d5c5 Mon Sep 17 00:00:00 2001
From: Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com>
Date: Thu, 27 Apr 2023 13:59:54 +0700
Subject: [PATCH 2/2] Raw mode support for forward-passthrough.

---
 .../forward-passthrough-core.c                | 175 ++++++++++++------
 .../forward-passthrough-fd722.c               |  60 ++++--
 .../forward-passthrough-fd788.c               |  60 ++++--
 .../forward-passthrough-formats.c             |  66 ++++---
 forward-passthrough/forward-passthrough.h     |   5 +-
 5 files changed, 253 insertions(+), 113 deletions(-)

diff --git a/forward-passthrough/forward-passthrough-core.c b/forward-passthrough/forward-passthrough-core.c
index 5b8d140..6f20585 100644
--- a/forward-passthrough/forward-passthrough-core.c
+++ b/forward-passthrough/forward-passthrough-core.c
@@ -42,10 +42,11 @@
  *     Buffers used as ring buffer, i.e. first frame placed into buffer 0, next - 1, 2, 3, 0, 1, 2 ....
  *     Odd (first, top) field always placed in buffers 0, 2, 4, 6, even (second, bottom) - 1, 3, 5, 7
  *   - On output, board defines 2 video buffers which works same manner as inputs.
- *   - Currently, this driver captures and outputs video in 10-bit mode, with top VANC lines
- *   - On input, ancillary data is placed into separate buffers, same number and order as video
- *   - Ancillary data captured as-is from SDI stream, audio extracted by software
- *   - On output, audio is encoded into ancillary data by hardware, so, audio passed as raw samples in single buffer
+ *   - This driver captures and outputs video in 10-bit mode, with top VANC lines, or full-frame 10-bit RAW mode 
+ *   - If not in RAW mode, on input ancillary data is placed into separate buffers, same number and order as video
+ *   - If not in RAW mode, ancillary data captured as-is from SDI stream, audio extracted by software
+ *   - If not in RAW mode, on output, audio is encoded into ancillary data by hardware, so, audio passed as raw samples in single buffer
+ * 	 - If in RAW mode, the whole SDI frame is passed into/from video buffer memory
  *   - Board generates IRQ at each field on input and output
  *   - Boards have special jitter-attenuator/PLL IC which "cleans" and converts analog h-sync signal
  *     or digital pixel clock signal into output pixel clock.
@@ -71,6 +72,34 @@
 extern struct forward_passthrough_dev_ops fd788_ops;
 extern struct forward_passthrough_dev_ops fd722_ops;
 
+/**
+ * Main processing function for RAW mode, place processing code here
+ * @field - current frame field (false - first/odd/top, true - second/even/bottom)
+ * @buffer - input (and next output) video buffer, 10-bit full-frame, geometry and sizes can be taken from io->format
+ */
+static void forward_passthrough_data_process_raw(struct forward_passthrough_io *io, bool field,
+						 void *buffer)
+{
+	struct forward_passthrough_format *fmt = &io->format;
+	size_t size = fmt->raw_size[field ? 1 : 0];
+	int hanc_size = fmt->total_width - fmt->width; // HANC area size
+
+	int x = ((ktime_get_ns() / 1000000) % fmt->width) & 0xFFFFFFFC;
+	int y = ((ktime_get_ns() / 1000000) / fmt->width) % (fmt->height / 2 - 16) +
+		fmt->topVBIs[field];
+	int i, j;
+
+	// Draw 16x16 moving rect
+	for (i = y; i < y + 16; i++) {
+		for (j = x; j < x + 16; j += 4) {
+			// Process 4 pixels = 40 bits = 5 bytes
+			uint64_t *p = (uint64_t *)&(
+				(u8 *)buffer)[(i * fmt->total_width + j + hanc_size) * 20 / 8];
+			*p = (*p & 0xFFFFFF0000000000ULL) | 0xFE200FE200;
+		}
+	}
+}
+
 /**
  * Copy audio to output buffer
  * Hardware uses circular buffer with 24-bit frames in lower 32-bit words on output.
@@ -137,48 +166,63 @@ static void forward_passthrough_toggle_streaming(struct forward_passthrough_io *
 		forward_vdma_get_region(io->pass->dev->vdma, io, v_region_address, v_region_size);
 		forward_vdma_get_region(io->pass->dev->vdma, io, a_region_address, a_region_size);
 
-		io->v_buffer_size = max(io->format.size[0], io->format.size[1]);
+		if (!io->raw)
+			io->v_buffer_size = max(io->format.size[0], io->format.size[1]);
+		else
+			io->v_buffer_size = max(io->format.raw_size[0], io->format.raw_size[1]);
 		io->v_buffer_size = (((io->v_buffer_size - 1) >> PAGE_SHIFT) + 1) << PAGE_SHIFT;
 
-		io->a_in_buffer_size = ops->audio_buffer_size;
-		io->a_in_buffer_size = (((io->a_in_buffer_size - 1) >> PAGE_SHIFT) + 1)
-				       << PAGE_SHIFT;
+		if (!io->raw) {
+			io->a_in_buffer_size = ops->audio_buffer_size;
+			io->a_in_buffer_size = (((io->a_in_buffer_size - 1) >> PAGE_SHIFT) + 1)
+					       << PAGE_SHIFT;
 
-		io->a_out_buffer_size = ops->audio_buffer_size;
-		io->a_out_buffer_size = (((io->a_out_buffer_size - 1) >> PAGE_SHIFT) + 1)
-					<< PAGE_SHIFT;
+			io->a_out_buffer_size = ops->audio_buffer_size;
+			io->a_out_buffer_size = (((io->a_out_buffer_size - 1) >> PAGE_SHIFT) + 1)
+						<< PAGE_SHIFT;
 
-		for (i = 0; i < 2; i++) {
-			io->a_in_decode_buffers[i] = vmalloc(io->a_in_buffer_size);
-			io->a_in_decoded_buffers[i] = vmalloc(io->a_in_buffer_size);
+			for (i = 0; i < 2; i++) {
+				io->a_in_decode_buffers[i] = vmalloc(io->a_in_buffer_size);
+				io->a_in_decoded_buffers[i] = vmalloc(io->a_in_buffer_size);
+			}
 		}
+
 		for (i = 0; i < ops->num_in_buffers; i++) {
 			io->v_in_buffers[i] = vmalloc(io->v_buffer_size);
-			io->a_in_buffers[i] = vmalloc(io->a_in_buffer_size);
+			if (!io->raw)
+				io->a_in_buffers[i] = vmalloc(io->a_in_buffer_size);
 			if (ops->buffer_map_address(io, i, false, &video_addr, &audio_addr)) {
 				forward_vdma_map_kernel_buf(io->pass->dev->vdma, io,
 							    io->v_in_buffers[i], video_addr,
 							    io->v_buffer_size, true);
-				forward_vdma_map_kernel_buf(io->pass->dev->vdma, io,
-							    io->a_in_buffers[i], audio_addr,
-							    io->a_in_buffer_size, true);
+				if (!io->raw)
+					forward_vdma_map_kernel_buf(io->pass->dev->vdma, io,
+								    io->a_in_buffers[i], audio_addr,
+								    io->a_in_buffer_size, true);
 			}
 		}
-		for (i = 0; i < ops->num_out_buffers; i++) {
-			io->v_out_buffers[i] = vmalloc(io->v_buffer_size);
+
+		if (!io->raw) {
+			for (i = 0; i < ops->num_out_buffers; i++) {
+				io->v_out_buffers[i] = vmalloc(io->v_buffer_size);
+				if (ops->buffer_map_address(io, i, true, &video_addr,
+							    &audio_addr)) {
+					forward_vdma_map_kernel_buf(io->pass->dev->vdma, io,
+								    io->v_out_buffers[i],
+								    video_addr, io->v_buffer_size,
+								    false);
+				}
+			}
+			io->a_out_buffer = vmalloc(io->a_out_buffer_size);
 			if (ops->buffer_map_address(io, i, true, &video_addr, &audio_addr)) {
 				forward_vdma_map_kernel_buf(io->pass->dev->vdma, io,
-							    io->v_out_buffers[i], video_addr,
-							    io->v_buffer_size, false);
+							    io->a_out_buffer, audio_addr,
+							    io->a_out_buffer_size, false);
 			}
 		}
-		io->a_out_buffer = vmalloc(io->a_out_buffer_size);
-		if (ops->buffer_map_address(io, i, true, &video_addr, &audio_addr)) {
-			forward_vdma_map_kernel_buf(io->pass->dev->vdma, io, io->a_out_buffer,
-						    audio_addr, io->a_out_buffer_size, false);
-		}
 
-		ops->toggle_streaming(io, true);
+		// Toggle only input for first frame to avoid output garbage
+		ops->toggle_streaming(io, true, false);
 
 		io->streaming = true;
 	} else if (!enable && io->streaming) {
@@ -188,14 +232,15 @@ static void forward_passthrough_toggle_streaming(struct forward_passthrough_io *
 		u32 audio_addr, video_addr;
 
 		io->streaming = false;
-		ops->toggle_streaming(io, false);
+		ops->toggle_streaming(io, false, false);
 
 		for (i = 0; i < ops->num_in_buffers; i++) {
 			if (ops->buffer_map_address(io, i, false, &video_addr, &audio_addr)) {
 				forward_vdma_unmap_buf(io->pass->dev->vdma, io, video_addr,
 						       io->v_buffer_size);
-				forward_vdma_unmap_buf(io->pass->dev->vdma, io, audio_addr,
-						       io->a_in_buffer_size);
+				if (!io->raw)
+					forward_vdma_unmap_buf(io->pass->dev->vdma, io, audio_addr,
+							       io->a_in_buffer_size);
 			}
 
 			vfree(io->v_in_buffers[i]);
@@ -212,9 +257,11 @@ static void forward_passthrough_toggle_streaming(struct forward_passthrough_io *
 			vfree(io->v_out_buffers[i]);
 			io->v_out_buffers[i] = NULL;
 		}
-		if (ops->buffer_map_address(io, i, true, &video_addr, &audio_addr)) {
-			forward_vdma_unmap_buf(io->pass->dev->vdma, io, audio_addr,
-					       io->a_out_buffer_size);
+		if (!io->raw) {
+			if (ops->buffer_map_address(io, i, true, &video_addr, &audio_addr)) {
+				forward_vdma_unmap_buf(io->pass->dev->vdma, io, audio_addr,
+						       io->a_out_buffer_size);
+			}
 		}
 
 		vfree(io->a_out_buffer);
@@ -272,36 +319,59 @@ static void forward_passthrough_process(struct forward_passthrough_io *io, u32 i
 		io->last_in_buffers[field] = in_prev;
 
 		// Extract audio from input
-		forward_passthrough_decode_hanc(io, field, io->a_in_buffers[in_prev], in_a_size);
+		if (!io->raw)
+			forward_passthrough_decode_hanc(io, field, io->a_in_buffers[in_prev],
+							in_a_size);
+
+		// Enable output
+		ops->toggle_streaming(io, true, true);
 	}
 
 	// End of output field/frame, select corresponding input buffer and process
 	if (ops->irq_info_out(io, irq, &out_prev, &out_cur, &out_next, &out_a_ptr)) {
 		int field = io->format.interlaced ? (out_next & 0x1) : 0;
 		int in_buf = io->last_in_buffers[field];
-		u32 out_a_ptr_wr = io->last_a_wr_ptr;
-		s32 realdelta = (s32)io->last_a_wr_ptr - (s32)out_a_ptr;
 
-		// Compensate possible output DMA jitter (max +/-2 samples for i formats)
-		if (realdelta < 0)
-			realdelta += io->a_out_buffer_size / 4;
+		if (!io->raw) {
+			u32 out_a_ptr_wr = io->last_a_wr_ptr;
+			s32 realdelta = (s32)io->last_a_wr_ptr - (s32)out_a_ptr;
 
-		if ((realdelta / io->a_out_groups / 4) > 2)
-			out_a_ptr_wr = out_a_ptr;
+			// Compensate possible output DMA jitter (max +/-2 samples for i formats)
+			if (realdelta < 0)
+				realdelta += io->a_out_buffer_size / 4;
 
-		out_a_ptr_wr += io->a_in_decoded_size[(!io->format.interlaced || field) ? 0 : 1];
-		if (out_a_ptr_wr > io->a_out_buffer_size / 4)
-			out_a_ptr_wr -= io->a_out_buffer_size / 4;
+			if ((realdelta / io->a_out_groups / 4) > 2)
+				out_a_ptr_wr = out_a_ptr;
 
-		io->last_a_wr_ptr = out_a_ptr_wr;
+			out_a_ptr_wr +=
+				io->a_in_decoded_size[(!io->format.interlaced || field) ? 0 : 1];
+			if (out_a_ptr_wr > io->a_out_buffer_size / 4)
+				out_a_ptr_wr -= io->a_out_buffer_size / 4;
 
-		ops->update_meta(io);
+			io->last_a_wr_ptr = out_a_ptr_wr;
 
-		// Process data
-		forward_passthrough_data_process(io, field, io->v_in_buffers[in_buf],
-						 io->a_in_decoded_buffers[field],
-						 io->v_out_buffers[out_next], out_a_ptr_wr,
-						 io->a_in_decoded_size[field]);
+			ops->update_meta(io);
+
+			// Process data
+			forward_passthrough_data_process(io, field, io->v_in_buffers[in_buf],
+							 io->a_in_decoded_buffers[field],
+							 io->v_out_buffers[out_next], out_a_ptr_wr,
+							 io->a_in_decoded_size[field]);
+		} else {
+			u32 video_addr, audio_addr;
+			if (ops->buffer_map_address(io, out_prev, true, &video_addr, &audio_addr)) {
+				forward_vdma_unmap_buf(io->pass->dev->vdma, io, video_addr,
+						       io->v_buffer_size);
+			}
+
+			forward_passthrough_data_process_raw(io, field, io->v_in_buffers[in_buf]);
+
+			if (ops->buffer_map_address(io, out_next, true, &video_addr, &audio_addr)) {
+				forward_vdma_map_kernel_buf(io->pass->dev->vdma, io,
+							    io->v_in_buffers[in_buf], video_addr,
+							    io->v_buffer_size, false);
+			}
+		}
 	}
 }
 
@@ -315,6 +385,7 @@ static int forward_passthrough_thread(void *p)
 	struct forward_irq_listener listener;
 
 	mutex_lock(&io->lock);
+	io->raw = true;
 	io->a_out_groups = 1;
 	pass->ops->configure_io(io);
 	mutex_unlock(&io->lock);
diff --git a/forward-passthrough/forward-passthrough-fd722.c b/forward-passthrough/forward-passthrough-fd722.c
index 6595bbd..4f7e2d7 100644
--- a/forward-passthrough/forward-passthrough-fd722.c
+++ b/forward-passthrough/forward-passthrough-fd722.c
@@ -195,8 +195,6 @@ static void fd722_setup_out_format(struct forward_passthrough_io *io,
 	FD722_VideoOutStop stop;
 	FD722_VideoOutField field;
 	FD722_VideoOutVPID vpid;
-	FD722_VideoOutOddDataCount oddC;
-	FD722_VideoOutEvenDataCount evenC;
 
 	ocs.reset = 1;
 	ocs.levelB = 0;
@@ -238,10 +236,6 @@ static void fd722_setup_out_format(struct forward_passthrough_io *io,
 	field.switchOdd = fmt->field_switch[0];
 	field.switchEven = fmt->field_switch[1];
 	vpid.vpid = fmt->vpid;
-	oddC.count =
-		((fmt->height / (fmt->interlaced ? 2 : 1)) + fmt->topVBIs[0]) * fmt->width * 20 / 8;
-	evenC.count =
-		((fmt->height / (fmt->interlaced ? 2 : 1)) + fmt->topVBIs[1]) * fmt->width * 20 / 8;
 
 	FD722_VideoOutLine_W(dev->csr, (io->out_index - 2), line);
 	FD722_VideoOutPixel_W(dev->csr, (io->out_index - 2), pixel);
@@ -250,8 +244,6 @@ static void fd722_setup_out_format(struct forward_passthrough_io *io,
 	FD722_VideoOutField_W(dev->csr, (io->out_index - 2), field);
 	FD722_VideoOutVPID_W(dev->csr, (io->out_index - 2), vpid);
 	FD722_VideoOutCS_W(dev->csr, (io->out_index - 2), ocs);
-	FD722_VideoOutOddDataCount_W(dev->csr, (io->out_index - 2), oddC);
-	FD722_VideoOutEvenDataCount_W(dev->csr, (io->out_index - 2), evenC);
 
 	ocs.reset = 0;
 	FD722_VideoOutCS_W(dev->csr, (io->out_index - 2), ocs);
@@ -455,18 +447,48 @@ bool fd722_genlock_irq_info(struct forward_passthrough_io *io, u32 irq, bool *fi
 	return true;
 }
 
-static void fd722_toggle_streaming(struct forward_passthrough_io *io, bool enable)
+static void fd722_toggle_streaming(struct forward_passthrough_io *io, bool in_enable,
+				   bool out_enable)
 {
-	FD722_VideoInCS ics = FD722_VideoInCS_R(io->pass->dev->csr, io->in_index);
-	ics.vbiTop = 1;
-	ics.vbiBottom = 0;
-	ics.test = 0;
-	ics.vbi10b = 1;
-	ics.vis10b = 1;
-	FD722_VideoInCS_W(io->pass->dev->csr, io->in_index, ics);
-
-	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->in_index, enable);
-	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->out_index, enable);
+	if (in_enable) {
+		FD722_VideoInCS ics = FD722_VideoInCS_R(io->pass->dev->csr, io->in_index);
+		ics.vbiTop = 1;
+		ics.vbiBottom = 0;
+		ics.test = 0;
+		ics.vbi10b = 1;
+		ics.vis10b = 1;
+		ics.captureRaw = io->raw ? 1 : 0;
+		FD722_VideoInCS_W(io->pass->dev->csr, io->in_index, ics);
+	}
+
+	if (out_enable) {
+		FD722_VideoOutOddDataCount oddC;
+		FD722_VideoOutEvenDataCount evenC;
+		FD722_VideoOutCS ocs = FD722_VideoOutCS_R(io->pass->dev->csr, io->out_index - 2);
+		struct forward_passthrough_format *fmt = &io->format;
+
+		ocs.vbiTop = 1;
+		ocs.vbiBottom = 0;
+		ocs.test = 0;
+		ocs.vbi10b = 1;
+		ocs.vis10b = 1;
+		ocs.playbackRaw = io->raw ? 1 : 0;
+
+		if (io->raw) {
+			oddC.count = fmt->raw_size[0];
+			evenC.count = fmt->raw_size[1];
+		} else {
+			oddC.count = fmt->size[0];
+			evenC.count = fmt->size[1];
+		}
+
+		FD722_VideoOutOddDataCount_W(io->pass->dev->csr, (io->out_index - 2), oddC);
+		FD722_VideoOutEvenDataCount_W(io->pass->dev->csr, (io->out_index - 2), evenC);
+		FD722_VideoOutCS_W(io->pass->dev->csr, (io->out_index - 2), ocs);
+	}
+
+	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->in_index, in_enable);
+	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->out_index, out_enable);
 }
 
 static void fd722_update_meta(struct forward_passthrough_io *io)
diff --git a/forward-passthrough/forward-passthrough-fd788.c b/forward-passthrough/forward-passthrough-fd788.c
index c72a769..3d013aa 100644
--- a/forward-passthrough/forward-passthrough-fd788.c
+++ b/forward-passthrough/forward-passthrough-fd788.c
@@ -171,8 +171,6 @@ static void fd788_setup_out_format(struct forward_passthrough_io *io,
 	FD788_VideoOutStop stop;
 	FD788_VideoOutField field;
 	FD788_VideoOutVPID vpid;
-	FD788_VideoOutOddDataCount oddC;
-	FD788_VideoOutEvenDataCount evenC;
 
 	ocs.reset = 1;
 	ocs.levelB = 0;
@@ -216,10 +214,6 @@ static void fd788_setup_out_format(struct forward_passthrough_io *io,
 	field.switchOdd = fmt->field_switch[0];
 	field.switchEven = fmt->field_switch[1];
 	vpid.vpid = fmt->vpid;
-	oddC.count =
-		((fmt->height / (fmt->interlaced ? 2 : 1)) + fmt->topVBIs[0]) * fmt->width * 20 / 8;
-	evenC.count =
-		((fmt->height / (fmt->interlaced ? 2 : 1)) + fmt->topVBIs[1]) * fmt->width * 20 / 8;
 
 	FD788_VideoOutLine_W(dev->csr, io->out_index, line);
 	FD788_VideoOutPixel_W(dev->csr, io->out_index, pixel);
@@ -228,8 +222,6 @@ static void fd788_setup_out_format(struct forward_passthrough_io *io,
 	FD788_VideoOutField_W(dev->csr, io->out_index, field);
 	FD788_VideoOutVPID_W(dev->csr, io->out_index, vpid);
 	FD788_VideoOutCS_W(dev->csr, io->out_index, ocs);
-	FD788_VideoOutOddDataCount_W(dev->csr, io->out_index, oddC);
-	FD788_VideoOutEvenDataCount_W(dev->csr, io->out_index, evenC);
 
 	ocs.reset = 0;
 	FD788_VideoOutCS_W(dev->csr, io->out_index, ocs);
@@ -433,18 +425,48 @@ bool fd788_genlock_irq_info(struct forward_passthrough_io *io, u32 irq, bool *fi
 	return true;
 }
 
-static void fd788_toggle_streaming(struct forward_passthrough_io *io, bool enable)
+static void fd788_toggle_streaming(struct forward_passthrough_io *io, bool in_enable,
+				   bool out_enable)
 {
-	FD788_VideoInCS ics = FD788_VideoInCS_R(io->pass->dev->csr, io->in_index);
-	ics.vbiTop = 1;
-	ics.vbiBottom = 0;
-	ics.test = 0;
-	ics.vbi10b = 1;
-	ics.vis10b = 1;
-	FD788_VideoInCS_W(io->pass->dev->csr, io->in_index, ics);
-
-	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->in_index, enable);
-	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->out_index, enable);
+	if (in_enable) {
+		FD788_VideoInCS ics = FD788_VideoInCS_R(io->pass->dev->csr, io->in_index);
+		ics.vbiTop = 1;
+		ics.vbiBottom = 0;
+		ics.test = 0;
+		ics.vbi10b = 1;
+		ics.vis10b = 1;
+		ics.captureRaw = io->raw ? 1 : 0;
+		FD788_VideoInCS_W(io->pass->dev->csr, io->in_index, ics);
+	}
+
+	if (out_enable) {
+		FD788_VideoOutOddDataCount oddC;
+		FD788_VideoOutEvenDataCount evenC;
+		FD788_VideoOutCS ocs = FD788_VideoOutCS_R(io->pass->dev->csr, io->out_index);
+		struct forward_passthrough_format *fmt = &io->format;
+
+		ocs.vbiTop = 1;
+		ocs.vbiBottom = 0;
+		ocs.test = 0;
+		ocs.vbi10b = 1;
+		ocs.vis10b = 1;
+		ocs.playbackRaw = io->raw ? 1 : 0;
+
+		if (io->raw) {
+			oddC.count = fmt->raw_size[0];
+			evenC.count = fmt->raw_size[1];
+		} else {
+			oddC.count = fmt->size[0];
+			evenC.count = fmt->size[1];
+		}
+
+		FD788_VideoOutOddDataCount_W(io->pass->dev->csr, io->out_index, oddC);
+		FD788_VideoOutEvenDataCount_W(io->pass->dev->csr, io->out_index, evenC);
+		FD788_VideoOutCS_W(io->pass->dev->csr, io->out_index, ocs);
+	}
+
+	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->in_index, in_enable);
+	io->pass->dev->cfg.toggle_streaming(io->pass->dev, io->out_index, out_enable);
 }
 
 static void fd788_update_meta(struct forward_passthrough_io *io)
diff --git a/forward-passthrough/forward-passthrough-formats.c b/forward-passthrough/forward-passthrough-formats.c
index 732829c..4753e5e 100644
--- a/forward-passthrough/forward-passthrough-formats.c
+++ b/forward-passthrough/forward-passthrough-formats.c
@@ -33,7 +33,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 20, 20 },
 	  { 3, 2 },
 	  0x85050000,
-	  { 2688000, 2688000 } },
+	  { 560 * 1920 * 20 / 8, 560 * 1920 * 20 / 8 },
+	  { 563 * 2640 * 20 / 8, 562 * 2640 * 20 / 8 } },
 	// 1080i60
 	{ 74250000,
 	  false,
@@ -46,7 +47,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 20, 20 },
 	  { 3, 2 },
 	  0x85070000,
-	  { 2688000, 2688000 } },
+	  { 560 * 1920 * 20 / 8, 560 * 1920 * 20 / 8 },
+	  { 563 * 2200 * 20 / 8, 562 * 2200 * 20 / 8 } },
 	// 1080i59.94
 	{ 74250000,
 	  true,
@@ -59,7 +61,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 20, 20 },
 	  { 3, 2 },
 	  0x85060000,
-	  { 2688000, 2688000 } },
+	  { 560 * 1920 * 20 / 8, 560 * 1920 * 20 / 8 },
+	  { 563 * 2200 * 20 / 8, 562 * 2200 * 20 / 8 } },
 	// 576i50
 	{ 13500000,
 	  false,
@@ -72,7 +75,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 22, 23 },
 	  { 2, 2 },
 	  0x81050000,
-	  { 558000, 559800 } },
+	  { 310 * 720 * 20 / 8, 311 * 720 * 20 / 8 },
+	  { 312 * 864 * 20 / 8, 313 * 864 * 20 / 8 } },
 	// 480i59.94
 	{ 13500000,
 	  false,
@@ -85,7 +89,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 19, 19 },
 	  { 0, 0 },
 	  0x81060000,
-	  { 473400, 471600 } },
+	  { 263 * 720 * 20 / 8, 262 * 720 * 20 / 8 },
+	  { 263 * 858 * 20 / 8, 262 * 858 * 20 / 8 } },
 	// 720p50
 	{ 74250000,
 	  false,
@@ -98,7 +103,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 25, 25 },
 	  { 5, 5 },
 	  0x84490000,
-	  { 2384000, 2384000 } },
+	  { 745 * 1280 * 20 / 8, 745 * 1280 * 20 / 8 },
+	  { 750 * 1980 * 20 / 8, 750 * 1980 * 20 / 8 } },
 	// 720p60
 	{ 74250000,
 	  false,
@@ -111,7 +117,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 25, 25 },
 	  { 5, 5 },
 	  0x844B0000,
-	  { 2384000, 2384000 } },
+	  { 745 * 1280 * 20 / 8, 745 * 1280 * 20 / 8 },
+	  { 750 * 1650 * 20 / 8, 750 * 1650 * 20 / 8 } },
 	// 720p59.94
 	{ 74250000,
 	  true,
@@ -124,7 +131,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 25, 25 },
 	  { 5, 5 },
 	  0x844A0000,
-	  { 2384000, 2384000 } },
+	  { 745 * 1280 * 20 / 8, 745 * 1280 * 20 / 8 },
+	  { 750 * 1650 * 20 / 8, 750 * 1650 * 20 / 8 } },
 	// 1080p25
 	{ 74250000,
 	  false,
@@ -137,7 +145,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x85C50000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2640 * 20 / 8, 1125 * 2640 * 20 / 8 } },
 	// 1080p30
 	{ 74250000,
 	  false,
@@ -150,7 +159,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x85C70000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 20 / 8, 1125 * 2200 * 20 / 8 } },
 	// 1080p29.97
 	{ 74250000,
 	  true,
@@ -163,7 +173,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x85C60000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 20 / 8, 1125 * 2200 * 20 / 8 } },
 	// 1080p24
 	{ 74250000,
 	  false,
@@ -176,7 +187,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x85C30000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2750 * 20 / 8, 1125 * 2750 * 20 / 8 } },
 	// 1080p23.98
 	{ 74250000,
 	  true,
@@ -189,7 +201,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x85C20000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2750 * 20 / 8, 1125 * 2750 * 20 / 8 } },
 	// 1080p50
 	{ 148500000,
 	  false,
@@ -202,7 +215,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x89C90000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2640 * 20 / 8, 1125 * 2640 * 20 / 8 } },
 	// 1080p60
 	{ 148500000,
 	  false,
@@ -215,7 +229,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x89CB0000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 20 / 8, 1125 * 2200 * 20 / 8 } },
 	// 1080p59.94
 	{ 148500000,
 	  true,
@@ -228,7 +243,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 41, 41 },
 	  { 4, 4 },
 	  0x89CA0000,
-	  { 5380800, 5380800 } },
+	  { 1121 * 1920 * 20 / 8, 1121 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 20 / 8, 1125 * 2200 * 20 / 8 } },
 	// 2160p25
 	{ 297000000,
 	  false,
@@ -241,7 +257,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 82, 82 },
 	  { 8, 8 },
 	  0xC0C50000,
-	  { 21523200, 21523200 } },
+	  { 1121 * 1920 * 4 * 20 / 8, 1121 * 4 * 1920 * 20 / 8 },
+	  { 1125 * 2640 * 4 * 20 / 8, 1125 * 4 * 2640 * 20 / 8 } },
 	// 2160p30
 	{ 297000000,
 	  false,
@@ -254,7 +271,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 82, 82 },
 	  { 8, 8 },
 	  0xC0C70000,
-	  { 21523200, 21523200 } },
+	  { 1121 * 1920 * 4 * 20 / 8, 1121 * 4 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 4 * 20 / 8, 1125 * 4 * 2200 * 20 / 8 } },
 	// 2160p29.97
 	{ 297000000,
 	  true,
@@ -267,7 +285,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 82, 82 },
 	  { 8, 8 },
 	  0xC0C60000,
-	  { 21523200, 21523200 } },
+	  { 1121 * 1920 * 4 * 20 / 8, 1121 * 4 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 4 * 20 / 8, 1125 * 4 * 2200 * 20 / 8 } },
 	// 2160p50
 	{ 594000000,
 	  false,
@@ -280,7 +299,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 82, 82 },
 	  { 8, 8 },
 	  0xCEC90000,
-	  { 21523200, 21523200 } },
+	  { 1121 * 1920 * 4 * 20 / 8, 1121 * 4 * 1920 * 20 / 8 },
+	  { 1125 * 2640 * 4 * 20 / 8, 1125 * 4 * 2640 * 20 / 8 } },
 	// 2160p60
 	{ 594000000,
 	  false,
@@ -293,7 +313,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 82, 82 },
 	  { 8, 8 },
 	  0xCECB0000,
-	  { 21523200, 21523200 } },
+	  { 1121 * 1920 * 4 * 20 / 8, 1121 * 4 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 4 * 20 / 8, 1125 * 4 * 2200 * 20 / 8 } },
 	// 2160p59.94
 	{ 594000000,
 	  true,
@@ -306,7 +327,8 @@ const struct forward_passthrough_format forward_passthrough_formats[] = {
 	  { 82, 82 },
 	  { 8, 8 },
 	  0xCECA0000,
-	  { 21523200, 21523200 } },
+	  { 1121 * 1920 * 4 * 20 / 8, 1121 * 4 * 1920 * 20 / 8 },
+	  { 1125 * 2200 * 4 * 20 / 8, 1125 * 4 * 2200 * 20 / 8 } },
 };
 
 const int forward_passthrough_formats_count =
diff --git a/forward-passthrough/forward-passthrough.h b/forward-passthrough/forward-passthrough.h
index 8a5292c..8f25693 100644
--- a/forward-passthrough/forward-passthrough.h
+++ b/forward-passthrough/forward-passthrough.h
@@ -59,6 +59,7 @@ struct forward_passthrough_format {
 	int bottomVBIs[2];
 	u32 vpid;
 	u32 size[2];
+	u32 raw_size[2];
 };
 
 /**
@@ -120,6 +121,7 @@ struct forward_passthrough_io {
 	struct mutex lock;
 
 	int in_index, out_index;
+	bool raw;
 	bool configured;
 	bool streaming;
 	struct forward_passthrough_format format;
@@ -201,7 +203,8 @@ struct forward_passthrough_dev_ops {
 	bool (*genlock_irq_info)(struct forward_passthrough_io *io, u32 irq, bool *field,
 				 s32 *gl_offset);
 	void (*genlock_offset)(struct forward_passthrough_io *io, s32 offset);
-	void (*toggle_streaming)(struct forward_passthrough_io *io, bool enable);
+	void (*toggle_streaming)(struct forward_passthrough_io *io, bool in_enable,
+				 bool out_enable);
 
 	void (*update_meta)(struct forward_passthrough_io *io);
 
-- 
2.39.1

