836ced8a044e2889de63e705e4cf5206f8ae6d87
[openwrt/staging/ldir.git] /
1 From 0eb6753788616ffed17a0484a14fd7d3df2a2a05 Mon Sep 17 00:00:00 2001
2 From: Naushir Patuck <naush@raspberrypi.com>
3 Date: Thu, 2 Apr 2020 16:08:51 +0100
4 Subject: [PATCH] media: bcm2835-unicam: Use dummy buffer if none have
5 been queued
6
7 If no buffer has been queued by a userland application, we use an
8 internal dummy buffer for the hardware to spin in. This will allow
9 the driver to release the existing userland buffer back to the
10 application for processing.
11
12 Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
13 ---
14 .../media/platform/bcm2835/bcm2835-unicam.c | 160 ++++++++++++------
15 1 file changed, 110 insertions(+), 50 deletions(-)
16
17 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
18 +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
19 @@ -47,6 +47,7 @@
20 #include <linux/clk.h>
21 #include <linux/delay.h>
22 #include <linux/device.h>
23 +#include <linux/dma-mapping.h>
24 #include <linux/err.h>
25 #include <linux/init.h>
26 #include <linux/interrupt.h>
27 @@ -112,6 +113,12 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
28 /* Default size of the embedded buffer */
29 #define UNICAM_EMBEDDED_SIZE 8192
30
31 +/*
32 + * Size of the dummy buffer. Can be any size really, but the DMA
33 + * allocation works in units of page sizes.
34 + */
35 +#define DUMMY_BUF_SIZE (PAGE_SIZE)
36 +
37 enum pad_types {
38 IMAGE_PAD,
39 METADATA_PAD,
40 @@ -390,6 +397,12 @@ struct unicam_node {
41 struct media_pad pad;
42 struct v4l2_ctrl_handler ctrl_handler;
43 unsigned int embedded_lines;
44 + /*
45 + * Dummy buffer intended to be used by unicam
46 + * if we have no other queued buffers to swap to.
47 + */
48 + void *dummy_buf_cpu_addr;
49 + dma_addr_t dummy_buf_dma_addr;
50 };
51
52 struct unicam_device {
53 @@ -661,27 +674,24 @@ static int unicam_reset_format(struct un
54 return 0;
55 }
56
57 -static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr,
58 - int pad_id)
59 +static void unicam_wr_dma_addr(struct unicam_cfg *cfg, dma_addr_t dmaaddr,
60 + unsigned int buffer_size, int pad_id)
61 {
62 - dma_addr_t endaddr;
63 + dma_addr_t endaddr = dmaaddr + buffer_size;
64
65 /*
66 - * dmaaddr should be a 32-bit address with the top two bits set to 0x3
67 - * to signify uncached access through the Videocore memory controller.
68 + * dmaaddr and endaddr should be a 32-bit address with the top two bits
69 + * set to 0x3 to signify uncached access through the Videocore memory
70 + * controller.
71 */
72 - BUG_ON((dmaaddr >> 30) != 0x3);
73 + BUG_ON((dmaaddr >> 30) != 0x3 && (endaddr >> 30) != 0x3);
74
75 if (pad_id == IMAGE_PAD) {
76 - endaddr = dmaaddr +
77 - dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage;
78 - reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr);
79 - reg_write(&dev->cfg, UNICAM_IBEA0, endaddr);
80 + reg_write(cfg, UNICAM_IBSA0, dmaaddr);
81 + reg_write(cfg, UNICAM_IBEA0, endaddr);
82 } else {
83 - endaddr = dmaaddr +
84 - dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
85 - reg_write(&dev->cfg, UNICAM_DBSA0, dmaaddr);
86 - reg_write(&dev->cfg, UNICAM_DBEA0, endaddr);
87 + reg_write(cfg, UNICAM_DBSA0, dmaaddr);
88 + reg_write(cfg, UNICAM_DBEA0, endaddr);
89 }
90 }
91
92 @@ -704,6 +714,7 @@ static inline void unicam_schedule_next_
93 struct unicam_device *dev = node->dev;
94 struct unicam_dmaqueue *dma_q = &node->dma_queue;
95 struct unicam_buffer *buf;
96 + unsigned int size;
97 dma_addr_t addr;
98
99 buf = list_entry(dma_q->active.next, struct unicam_buffer, list);
100 @@ -711,7 +722,23 @@ static inline void unicam_schedule_next_
101 list_del(&buf->list);
102
103 addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
104 - unicam_wr_dma_addr(dev, addr, node->pad_id);
105 + size = (node->pad_id == IMAGE_PAD) ?
106 + dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage :
107 + dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
108 +
109 + unicam_wr_dma_addr(&dev->cfg, addr, size, node->pad_id);
110 +}
111 +
112 +static inline void unicam_schedule_dummy_buffer(struct unicam_node *node)
113 +{
114 + struct unicam_device *dev = node->dev;
115 + dma_addr_t addr = node->dummy_buf_dma_addr;
116 +
117 + unicam_dbg(3, dev, "Scheduling dummy buffer for node %d\n",
118 + node->pad_id);
119 +
120 + unicam_wr_dma_addr(&dev->cfg, addr, DUMMY_BUF_SIZE, node->pad_id);
121 + node->next_frm = NULL;
122 }
123
124 static inline void unicam_process_buffer_complete(struct unicam_node *node,
125 @@ -721,7 +748,6 @@ static inline void unicam_process_buffer
126 node->cur_frm->vb.sequence = sequence;
127
128 vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
129 - node->cur_frm = node->next_frm;
130 }
131
132 static int unicam_num_nodes_streaming(struct unicam_device *dev)
133 @@ -788,6 +814,28 @@ static irqreturn_t unicam_isr(int irq, v
134 if (!(sta && (UNICAM_IS | UNICAM_PI0)))
135 return IRQ_HANDLED;
136
137 + /*
138 + * We must run the frame end handler first. If we have a valid next_frm
139 + * and we get a simultaneout FE + FS interrupt, running the FS handler
140 + * first would null out the next_frm ptr and we would have lost the
141 + * buffer forever.
142 + */
143 + if (ista & UNICAM_FEI || sta & UNICAM_PI0) {
144 + /*
145 + * Ensure we have swapped buffers already as we can't
146 + * stop the peripheral. If no buffer is available, use a
147 + * dummy buffer to dump out frames until we get a new buffer
148 + * to use.
149 + */
150 + for (i = 0; i < num_nodes_streaming; i++) {
151 + if (unicam->node[i].cur_frm)
152 + unicam_process_buffer_complete(&unicam->node[i],
153 + sequence);
154 + unicam->node[i].cur_frm = unicam->node[i].next_frm;
155 + }
156 + unicam->sequence++;
157 + }
158 +
159 if (ista & UNICAM_FSI) {
160 /*
161 * Timestamp is to be when the first data byte was captured,
162 @@ -798,24 +846,16 @@ static irqreturn_t unicam_isr(int irq, v
163 if (unicam->node[i].cur_frm)
164 unicam->node[i].cur_frm->vb.vb2_buf.timestamp =
165 ts;
166 + /*
167 + * Set the next frame output to go to a dummy frame
168 + * if we have not managed to obtain another frame
169 + * from the queue.
170 + */
171 + unicam_schedule_dummy_buffer(&unicam->node[i]);
172 }
173 }
174 - if (ista & UNICAM_FEI || sta & UNICAM_PI0) {
175 - /*
176 - * Ensure we have swapped buffers already as we can't
177 - * stop the peripheral. Overwrite the frame we've just
178 - * captured instead.
179 - */
180 - for (i = 0; i < num_nodes_streaming; i++) {
181 - if (unicam->node[i].cur_frm &&
182 - unicam->node[i].cur_frm != unicam->node[i].next_frm)
183 - unicam_process_buffer_complete(&unicam->node[i],
184 - sequence);
185 - }
186 - unicam->sequence++;
187 - }
188 -
189 - /* Cannot swap buffer at frame end, there may be a race condition
190 + /*
191 + * Cannot swap buffer at frame end, there may be a race condition
192 * where the HW does not actually swap it if the new frame has
193 * already started.
194 */
195 @@ -823,7 +863,7 @@ static irqreturn_t unicam_isr(int irq, v
196 for (i = 0; i < num_nodes_streaming; i++) {
197 spin_lock(&unicam->node[i].dma_queue_lock);
198 if (!list_empty(&unicam->node[i].dma_queue.active) &&
199 - unicam->node[i].cur_frm == unicam->node[i].next_frm)
200 + !unicam->node[i].next_frm)
201 unicam_schedule_next_buffer(&unicam->node[i]);
202 spin_unlock(&unicam->node[i].dma_queue_lock);
203 }
204 @@ -1352,7 +1392,7 @@ static void unicam_start_rx(struct unica
205 {
206 struct unicam_cfg *cfg = &dev->cfg;
207 int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2;
208 - unsigned int i;
209 + unsigned int size, i;
210 u32 val;
211
212 if (line_int_freq < 128)
213 @@ -1413,7 +1453,7 @@ static void unicam_start_rx(struct unica
214 reg_write_field(cfg, UNICAM_ANA, 0, UNICAM_DDL);
215
216 /* Always start in trigger frame capture mode (UNICAM_FCM set) */
217 - val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM;
218 + val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
219 set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
220 reg_write(cfg, UNICAM_ICTL, val);
221 reg_write(cfg, UNICAM_STA, UNICAM_STA_MASK_ALL);
222 @@ -1501,7 +1541,8 @@ static void unicam_start_rx(struct unica
223
224 reg_write(&dev->cfg, UNICAM_IBLS,
225 dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline);
226 - unicam_wr_dma_addr(dev, addr[IMAGE_PAD], IMAGE_PAD);
227 + size = dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage;
228 + unicam_wr_dma_addr(&dev->cfg, addr[IMAGE_PAD], size, IMAGE_PAD);
229 unicam_set_packing_config(dev);
230 unicam_cfg_image_id(dev);
231
232 @@ -1511,8 +1552,10 @@ static void unicam_start_rx(struct unica
233 reg_write(cfg, UNICAM_MISC, val);
234
235 if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) {
236 + size = dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize;
237 unicam_enable_ed(dev);
238 - unicam_wr_dma_addr(dev, addr[METADATA_PAD], METADATA_PAD);
239 + unicam_wr_dma_addr(&dev->cfg, addr[METADATA_PAD], size,
240 + METADATA_PAD);
241 }
242
243 /* Enable peripheral */
244 @@ -1686,13 +1729,14 @@ static void unicam_stop_streaming(struct
245 unicam_runtime_put(dev);
246
247 } else if (node->pad_id == METADATA_PAD) {
248 - /* Null out the embedded data buffer address so the HW does
249 - * not use it. This is only really needed if the embedded data
250 - * pad is disabled before the image pad. The 0x3 in the top two
251 - * bits signifies uncached accesses through the Videocore
252 - * memory controller.
253 + /* Allow the hardware to spin in the dummy buffer.
254 + * This is only really needed if the embedded data pad is
255 + * disabled before the image pad. The 0x3 in the top two bits
256 + * signifies uncached accesses through the Videocore memory
257 + * controller.
258 */
259 - unicam_wr_dma_addr(dev, 0xc0000000, METADATA_PAD);
260 + unicam_wr_dma_addr(&dev->cfg, node->dummy_buf_dma_addr,
261 + DUMMY_BUF_SIZE, METADATA_PAD);
262 }
263
264 /* Clear all queued buffers for the node */
265 @@ -2321,6 +2365,15 @@ static int register_node(struct unicam_d
266 video_set_drvdata(vdev, node);
267 vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
268
269 + node->dummy_buf_cpu_addr = dma_alloc_coherent(&unicam->pdev->dev,
270 + DUMMY_BUF_SIZE,
271 + &node->dummy_buf_dma_addr,
272 + GFP_ATOMIC);
273 + if (!node->dummy_buf_cpu_addr) {
274 + unicam_err(unicam, "Unable to allocate dummy buffer.\n");
275 + return -ENOMEM;
276 + }
277 +
278 if (node->pad_id == METADATA_PAD ||
279 !v4l2_subdev_has_op(unicam->sensor, video, s_std)) {
280 v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD);
281 @@ -2376,13 +2429,20 @@ static int register_node(struct unicam_d
282
283 static void unregister_nodes(struct unicam_device *unicam)
284 {
285 - if (unicam->node[IMAGE_PAD].registered) {
286 - video_unregister_device(&unicam->node[IMAGE_PAD].video_dev);
287 - unicam->node[IMAGE_PAD].registered = 0;
288 - }
289 - if (unicam->node[METADATA_PAD].registered) {
290 - video_unregister_device(&unicam->node[METADATA_PAD].video_dev);
291 - unicam->node[METADATA_PAD].registered = 0;
292 + struct unicam_node *node;
293 + int i;
294 +
295 + for (i = 0; i < MAX_NODES; i++) {
296 + node = &unicam->node[i];
297 + if (node->dummy_buf_cpu_addr) {
298 + dma_free_coherent(&unicam->pdev->dev, DUMMY_BUF_SIZE,
299 + node->dummy_buf_cpu_addr,
300 + node->dummy_buf_dma_addr);
301 + }
302 + if (node->registered) {
303 + video_unregister_device(&node->video_dev);
304 + node->registered = 0;
305 + }
306 }
307 }
308