aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.4/950-0645-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0645-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0645-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch308
1 files changed, 0 insertions, 308 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0645-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch b/target/linux/bcm27xx/patches-5.4/950-0645-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch
deleted file mode 100644
index 836ced8a04..0000000000
--- a/target/linux/bcm27xx/patches-5.4/950-0645-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch
+++ /dev/null
@@ -1,308 +0,0 @@
-From 0eb6753788616ffed17a0484a14fd7d3df2a2a05 Mon Sep 17 00:00:00 2001
-From: Naushir Patuck <naush@raspberrypi.com>
-Date: Thu, 2 Apr 2020 16:08:51 +0100
-Subject: [PATCH] media: bcm2835-unicam: Use dummy buffer if none have
- been queued
-
-If no buffer has been queued by a userland application, we use an
-internal dummy buffer for the hardware to spin in. This will allow
-the driver to release the existing userland buffer back to the
-application for processing.
-
-Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
----
- .../media/platform/bcm2835/bcm2835-unicam.c | 160 ++++++++++++------
- 1 file changed, 110 insertions(+), 50 deletions(-)
-
---- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
-+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
-@@ -47,6 +47,7 @@
- #include <linux/clk.h>
- #include <linux/delay.h>
- #include <linux/device.h>
-+#include <linux/dma-mapping.h>
- #include <linux/err.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
-@@ -112,6 +113,12 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
- /* Default size of the embedded buffer */
- #define UNICAM_EMBEDDED_SIZE 8192
-
-+/*
-+ * Size of the dummy buffer. Can be any size really, but the DMA
-+ * allocation works in units of page sizes.
-+ */
-+#define DUMMY_BUF_SIZE (PAGE_SIZE)
-+
- enum pad_types {
- IMAGE_PAD,
- METADATA_PAD,
-@@ -390,6 +397,12 @@ struct unicam_node {
- struct media_pad pad;
- struct v4l2_ctrl_handler ctrl_handler;
- unsigned int embedded_lines;
-+ /*
-+ * Dummy buffer intended to be used by unicam
-+ * if we have no other queued buffers to swap to.
-+ */
-+ void *dummy_buf_cpu_addr;
-+ dma_addr_t dummy_buf_dma_addr;
- };
-
- struct unicam_device {
-@@ -661,27 +674,24 @@ static int unicam_reset_format(struct un
- return 0;
- }
-
--static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr,
-- int pad_id)
-+static void unicam_wr_dma_addr(struct unicam_cfg *cfg, dma_addr_t dmaaddr,
-+ unsigned int buffer_size, int pad_id)
- {
-- dma_addr_t endaddr;
-+ dma_addr_t endaddr = dmaaddr + buffer_size;
-
- /*
-- * dmaaddr should be a 32-bit address with the top two bits set to 0x3
-- * to signify uncached access through the Videocore memory controller.
-+ * dmaaddr and endaddr should be a 32-bit address with the top two bits
-+ * set to 0x3 to signify uncached access through the Videocore memory
-+ * controller.
- */
-- BUG_ON((dmaaddr >> 30) != 0x3);
-+ BUG_ON((dmaaddr >> 30) != 0x3 && (endaddr >> 30) != 0x3);
-
- if (pad_id == IMAGE_PAD) {
-- endaddr = dmaaddr +
-- dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage;
-- reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr);
-- reg_write(&dev->cfg, UNICAM_IBEA0, endaddr);
-+ reg_write(cfg, UNICAM_IBSA0, dmaaddr);
-+ reg_write(cfg, UNICAM_IBEA0, endaddr);
- } else {
-- endaddr = dmaaddr +
-- dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
-- reg_write(&dev->cfg, UNICAM_DBSA0, dmaaddr);
-- reg_write(&dev->cfg, UNICAM_DBEA0, endaddr);
-+ reg_write(cfg, UNICAM_DBSA0, dmaaddr);
-+ reg_write(cfg, UNICAM_DBEA0, endaddr);
- }
- }
-
-@@ -704,6 +714,7 @@ static inline void unicam_schedule_next_
- struct unicam_device *dev = node->dev;
- struct unicam_dmaqueue *dma_q = &node->dma_queue;
- struct unicam_buffer *buf;
-+ unsigned int size;
- dma_addr_t addr;
-
- buf = list_entry(dma_q->active.next, struct unicam_buffer, list);
-@@ -711,7 +722,23 @@ static inline void unicam_schedule_next_
- list_del(&buf->list);
-
- addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
-- unicam_wr_dma_addr(dev, addr, node->pad_id);
-+ size = (node->pad_id == IMAGE_PAD) ?
-+ dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage :
-+ dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
-+
-+ unicam_wr_dma_addr(&dev->cfg, addr, size, node->pad_id);
-+}
-+
-+static inline void unicam_schedule_dummy_buffer(struct unicam_node *node)
-+{
-+ struct unicam_device *dev = node->dev;
-+ dma_addr_t addr = node->dummy_buf_dma_addr;
-+
-+ unicam_dbg(3, dev, "Scheduling dummy buffer for node %d\n",
-+ node->pad_id);
-+
-+ unicam_wr_dma_addr(&dev->cfg, addr, DUMMY_BUF_SIZE, node->pad_id);
-+ node->next_frm = NULL;
- }
-
- static inline void unicam_process_buffer_complete(struct unicam_node *node,
-@@ -721,7 +748,6 @@ static inline void unicam_process_buffer
- node->cur_frm->vb.sequence = sequence;
-
- vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
-- node->cur_frm = node->next_frm;
- }
-
- static int unicam_num_nodes_streaming(struct unicam_device *dev)
-@@ -788,6 +814,28 @@ static irqreturn_t unicam_isr(int irq, v
- if (!(sta && (UNICAM_IS | UNICAM_PI0)))
- return IRQ_HANDLED;
-
-+ /*
-+ * We must run the frame end handler first. If we have a valid next_frm
-+ * and we get a simultaneout FE + FS interrupt, running the FS handler
-+ * first would null out the next_frm ptr and we would have lost the
-+ * buffer forever.
-+ */
-+ if (ista & UNICAM_FEI || sta & UNICAM_PI0) {
-+ /*
-+ * Ensure we have swapped buffers already as we can't
-+ * stop the peripheral. If no buffer is available, use a
-+ * dummy buffer to dump out frames until we get a new buffer
-+ * to use.
-+ */
-+ for (i = 0; i < num_nodes_streaming; i++) {
-+ if (unicam->node[i].cur_frm)
-+ unicam_process_buffer_complete(&unicam->node[i],
-+ sequence);
-+ unicam->node[i].cur_frm = unicam->node[i].next_frm;
-+ }
-+ unicam->sequence++;
-+ }
-+
- if (ista & UNICAM_FSI) {
- /*
- * Timestamp is to be when the first data byte was captured,
-@@ -798,24 +846,16 @@ static irqreturn_t unicam_isr(int irq, v
- if (unicam->node[i].cur_frm)
- unicam->node[i].cur_frm->vb.vb2_buf.timestamp =
- ts;
-+ /*
-+ * Set the next frame output to go to a dummy frame
-+ * if we have not managed to obtain another frame
-+ * from the queue.
-+ */
-+ unicam_schedule_dummy_buffer(&unicam->node[i]);
- }
- }
-- if (ista & UNICAM_FEI || sta & UNICAM_PI0) {
-- /*
-- * Ensure we have swapped buffers already as we can't
-- * stop the peripheral. Overwrite the frame we've just
-- * captured instead.
-- */
-- for (i = 0; i < num_nodes_streaming; i++) {
-- if (unicam->node[i].cur_frm &&
-- unicam->node[i].cur_frm != unicam->node[i].next_frm)
-- unicam_process_buffer_complete(&unicam->node[i],
-- sequence);
-- }
-- unicam->sequence++;
-- }
--
-- /* Cannot swap buffer at frame end, there may be a race condition
-+ /*
-+ * Cannot swap buffer at frame end, there may be a race condition
- * where the HW does not actually swap it if the new frame has
- * already started.
- */
-@@ -823,7 +863,7 @@ static irqreturn_t unicam_isr(int irq, v
- for (i = 0; i < num_nodes_streaming; i++) {
- spin_lock(&unicam->node[i].dma_queue_lock);
- if (!list_empty(&unicam->node[i].dma_queue.active) &&
-- unicam->node[i].cur_frm == unicam->node[i].next_frm)
-+ !unicam->node[i].next_frm)
- unicam_schedule_next_buffer(&unicam->node[i]);
- spin_unlock(&unicam->node[i].dma_queue_lock);
- }
-@@ -1352,7 +1392,7 @@ static void unicam_start_rx(struct unica
- {
- struct unicam_cfg *cfg = &dev->cfg;
- int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2;
-- unsigned int i;
-+ unsigned int size, i;
- u32 val;
-
- if (line_int_freq < 128)
-@@ -1413,7 +1453,7 @@ static void unicam_start_rx(struct unica
- reg_write_field(cfg, UNICAM_ANA, 0, UNICAM_DDL);
-
- /* Always start in trigger frame capture mode (UNICAM_FCM set) */
-- val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM;
-+ val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
- set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
- reg_write(cfg, UNICAM_ICTL, val);
- reg_write(cfg, UNICAM_STA, UNICAM_STA_MASK_ALL);
-@@ -1501,7 +1541,8 @@ static void unicam_start_rx(struct unica
-
- reg_write(&dev->cfg, UNICAM_IBLS,
- dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline);
-- unicam_wr_dma_addr(dev, addr[IMAGE_PAD], IMAGE_PAD);
-+ size = dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage;
-+ unicam_wr_dma_addr(&dev->cfg, addr[IMAGE_PAD], size, IMAGE_PAD);
- unicam_set_packing_config(dev);
- unicam_cfg_image_id(dev);
-
-@@ -1511,8 +1552,10 @@ static void unicam_start_rx(struct unica
- reg_write(cfg, UNICAM_MISC, val);
-
- if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) {
-+ size = dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
- unicam_enable_ed(dev);
-- unicam_wr_dma_addr(dev, addr[METADATA_PAD], METADATA_PAD);
-+ unicam_wr_dma_addr(&dev->cfg, addr[METADATA_PAD], size,
-+ METADATA_PAD);
- }
-
- /* Enable peripheral */
-@@ -1686,13 +1729,14 @@ static void unicam_stop_streaming(struct
- unicam_runtime_put(dev);
-
- } else if (node->pad_id == METADATA_PAD) {
-- /* Null out the embedded data buffer address so the HW does
-- * not use it. This is only really needed if the embedded data
-- * pad is disabled before the image pad. The 0x3 in the top two
-- * bits signifies uncached accesses through the Videocore
-- * memory controller.
-+ /* Allow the hardware to spin in the dummy buffer.
-+ * This is only really needed if the embedded data pad is
-+ * disabled before the image pad. The 0x3 in the top two bits
-+ * signifies uncached accesses through the Videocore memory
-+ * controller.
- */
-- unicam_wr_dma_addr(dev, 0xc0000000, METADATA_PAD);
-+ unicam_wr_dma_addr(&dev->cfg, node->dummy_buf_dma_addr,
-+ DUMMY_BUF_SIZE, METADATA_PAD);
- }
-
- /* Clear all queued buffers for the node */
-@@ -2321,6 +2365,15 @@ static int register_node(struct unicam_d
- video_set_drvdata(vdev, node);
- vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
-
-+ node->dummy_buf_cpu_addr = dma_alloc_coherent(&unicam->pdev->dev,
-+ DUMMY_BUF_SIZE,
-+ &node->dummy_buf_dma_addr,
-+ GFP_ATOMIC);
-+ if (!node->dummy_buf_cpu_addr) {
-+ unicam_err(unicam, "Unable to allocate dummy buffer.\n");
-+ return -ENOMEM;
-+ }
-+
- if (node->pad_id == METADATA_PAD ||
- !v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
- v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD);
-@@ -2376,13 +2429,20 @@ static int register_node(struct unicam_d
-
- static void unregister_nodes(struct unicam_device *unicam)
- {
-- if (unicam->node[IMAGE_PAD].registered) {
-- video_unregister_device(&unicam->node[IMAGE_PAD].video_dev);
-- unicam->node[IMAGE_PAD].registered = 0;
-- }
-- if (unicam->node[METADATA_PAD].registered) {
-- video_unregister_device(&unicam->node[METADATA_PAD].video_dev);
-- unicam->node[METADATA_PAD].registered = 0;
-+ struct unicam_node *node;
-+ int i;
-+
-+ for (i = 0; i < MAX_NODES; i++) {
-+ node = &unicam->node[i];
-+ if (node->dummy_buf_cpu_addr) {
-+ dma_free_coherent(&unicam->pdev->dev, DUMMY_BUF_SIZE,
-+ node->dummy_buf_cpu_addr,
-+ node->dummy_buf_dma_addr);
-+ }
-+ if (node->registered) {
-+ video_unregister_device(&node->video_dev);
-+ node->registered = 0;
-+ }
- }
- }
-