diff options
author | Mike Rapoport <mike@compulab.co.il> | 2008-04-22 09:36:32 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:09:45 -0400 |
commit | a5462e5be3c1cec7e00e6af9985ff31bf4ef8aa0 (patch) | |
tree | 70f73b03fe40b47e6dea2a3ab2494f42cbb676ee /drivers | |
parent | 587df9fca6496f4236c526b2c83f068a63cfd769 (diff) |
V4L/DVB (7669): pxa_camera: Add support for YUV modes
This patch adds support for YUV packed and planar capture for pxa_camera.
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/pxa_camera.c | 416 |
1 files changed, 304 insertions, 112 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 936db67a5b0f..b999bda23c48 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -49,6 +49,9 @@ | |||
49 | 49 | ||
50 | #define CICR1_DW_VAL(x) ((x) & CICR1_DW) /* Data bus width */ | 50 | #define CICR1_DW_VAL(x) ((x) & CICR1_DW) /* Data bus width */ |
51 | #define CICR1_PPL_VAL(x) (((x) << 15) & CICR1_PPL) /* Pixels per line */ | 51 | #define CICR1_PPL_VAL(x) (((x) << 15) & CICR1_PPL) /* Pixels per line */ |
52 | #define CICR1_COLOR_SP_VAL(x) (((x) << 3) & CICR1_COLOR_SP) /* color space */ | ||
53 | #define CICR1_RGB_BPP_VAL(x) (((x) << 7) & CICR1_RGB_BPP) /* bpp for rgb */ | ||
54 | #define CICR1_RGBT_CONV_VAL(x) (((x) << 29) & CICR1_RGBT_CONV) /* rgbt conv */ | ||
52 | 55 | ||
53 | #define CICR2_BLW_VAL(x) (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */ | 56 | #define CICR2_BLW_VAL(x) (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */ |
54 | #define CICR2_ELW_VAL(x) (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */ | 57 | #define CICR2_ELW_VAL(x) (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */ |
@@ -70,6 +73,19 @@ static DEFINE_MUTEX(camera_lock); | |||
70 | /* | 73 | /* |
71 | * Structures | 74 | * Structures |
72 | */ | 75 | */ |
76 | enum pxa_camera_active_dma { | ||
77 | DMA_Y = 0x1, | ||
78 | DMA_U = 0x2, | ||
79 | DMA_V = 0x4, | ||
80 | }; | ||
81 | |||
82 | /* descriptor needed for the PXA DMA engine */ | ||
83 | struct pxa_cam_dma { | ||
84 | dma_addr_t sg_dma; | ||
85 | struct pxa_dma_desc *sg_cpu; | ||
86 | size_t sg_size; | ||
87 | int sglen; | ||
88 | }; | ||
73 | 89 | ||
74 | /* buffer for one video frame */ | 90 | /* buffer for one video frame */ |
75 | struct pxa_buffer { | 91 | struct pxa_buffer { |
@@ -78,11 +94,12 @@ struct pxa_buffer { | |||
78 | 94 | ||
79 | const struct soc_camera_data_format *fmt; | 95 | const struct soc_camera_data_format *fmt; |
80 | 96 | ||
81 | /* our descriptor list needed for the PXA DMA engine */ | 97 | /* our descriptor lists for Y, U and V channels */ |
82 | dma_addr_t sg_dma; | 98 | struct pxa_cam_dma dmas[3]; |
83 | struct pxa_dma_desc *sg_cpu; | 99 | |
84 | size_t sg_size; | ||
85 | int inwork; | 100 | int inwork; |
101 | |||
102 | enum pxa_camera_active_dma active_dma; | ||
86 | }; | 103 | }; |
87 | 104 | ||
88 | struct pxa_framebuffer_queue { | 105 | struct pxa_framebuffer_queue { |
@@ -100,7 +117,8 @@ struct pxa_camera_dev { | |||
100 | 117 | ||
101 | unsigned int irq; | 118 | unsigned int irq; |
102 | void __iomem *base; | 119 | void __iomem *base; |
103 | unsigned int dma_chan_y; | 120 | |
121 | unsigned int dma_chans[3]; | ||
104 | 122 | ||
105 | struct pxacamera_platform_data *pdata; | 123 | struct pxacamera_platform_data *pdata; |
106 | struct resource *res; | 124 | struct resource *res; |
@@ -128,7 +146,15 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
128 | 146 | ||
129 | dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); | 147 | dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); |
130 | 148 | ||
131 | *size = icd->width * icd->height * ((icd->current_fmt->depth + 7) >> 3); | 149 | /* planar capture requires Y, U and V buffers to be page aligned */ |
150 | if (icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P) { | ||
151 | *size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */ | ||
152 | *size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */ | ||
153 | *size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */ | ||
154 | } else { | ||
155 | *size = icd->width * icd->height * | ||
156 | ((icd->current_fmt->depth + 7) >> 3); | ||
157 | } | ||
132 | 158 | ||
133 | if (0 == *count) | 159 | if (0 == *count) |
134 | *count = 32; | 160 | *count = 32; |
@@ -145,6 +171,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) | |||
145 | to_soc_camera_host(icd->dev.parent); | 171 | to_soc_camera_host(icd->dev.parent); |
146 | struct pxa_camera_dev *pcdev = ici->priv; | 172 | struct pxa_camera_dev *pcdev = ici->priv; |
147 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | 173 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); |
174 | int i; | ||
148 | 175 | ||
149 | BUG_ON(in_interrupt()); | 176 | BUG_ON(in_interrupt()); |
150 | 177 | ||
@@ -157,14 +184,62 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) | |||
157 | videobuf_dma_unmap(vq, dma); | 184 | videobuf_dma_unmap(vq, dma); |
158 | videobuf_dma_free(dma); | 185 | videobuf_dma_free(dma); |
159 | 186 | ||
160 | if (buf->sg_cpu) | 187 | for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { |
161 | dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu, | 188 | if (buf->dmas[i].sg_cpu) |
162 | buf->sg_dma); | 189 | dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size, |
163 | buf->sg_cpu = NULL; | 190 | buf->dmas[i].sg_cpu, |
191 | buf->dmas[i].sg_dma); | ||
192 | buf->dmas[i].sg_cpu = NULL; | ||
193 | } | ||
164 | 194 | ||
165 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | 195 | buf->vb.state = VIDEOBUF_NEEDS_INIT; |
166 | } | 196 | } |
167 | 197 | ||
198 | static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | ||
199 | struct pxa_buffer *buf, | ||
200 | struct videobuf_dmabuf *dma, int channel, | ||
201 | int sglen, int sg_start, int cibr, | ||
202 | unsigned int size) | ||
203 | { | ||
204 | struct pxa_cam_dma *pxa_dma = &buf->dmas[channel]; | ||
205 | int i; | ||
206 | |||
207 | if (pxa_dma->sg_cpu) | ||
208 | dma_free_coherent(pcdev->dev, pxa_dma->sg_size, | ||
209 | pxa_dma->sg_cpu, pxa_dma->sg_dma); | ||
210 | |||
211 | pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); | ||
212 | pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size, | ||
213 | &pxa_dma->sg_dma, GFP_KERNEL); | ||
214 | if (!pxa_dma->sg_cpu) | ||
215 | return -ENOMEM; | ||
216 | |||
217 | pxa_dma->sglen = sglen; | ||
218 | |||
219 | for (i = 0; i < sglen; i++) { | ||
220 | int sg_i = sg_start + i; | ||
221 | struct scatterlist *sg = dma->sglist; | ||
222 | unsigned int dma_len = sg_dma_len(&sg[sg_i]), xfer_len; | ||
223 | |||
224 | pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr; | ||
225 | pxa_dma->sg_cpu[i].dtadr = sg_dma_address(&sg[sg_i]); | ||
226 | |||
227 | /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */ | ||
228 | xfer_len = (min(dma_len, size) + 7) & ~7; | ||
229 | |||
230 | pxa_dma->sg_cpu[i].dcmd = | ||
231 | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len; | ||
232 | size -= dma_len; | ||
233 | pxa_dma->sg_cpu[i].ddadr = | ||
234 | pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); | ||
235 | } | ||
236 | |||
237 | pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP; | ||
238 | pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
168 | static int pxa_videobuf_prepare(struct videobuf_queue *vq, | 243 | static int pxa_videobuf_prepare(struct videobuf_queue *vq, |
169 | struct videobuf_buffer *vb, enum v4l2_field field) | 244 | struct videobuf_buffer *vb, enum v4l2_field field) |
170 | { | 245 | { |
@@ -173,7 +248,9 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
173 | to_soc_camera_host(icd->dev.parent); | 248 | to_soc_camera_host(icd->dev.parent); |
174 | struct pxa_camera_dev *pcdev = ici->priv; | 249 | struct pxa_camera_dev *pcdev = ici->priv; |
175 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 250 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
176 | int i, ret; | 251 | int ret; |
252 | int sglen_y, sglen_yu = 0, sglen_u = 0, sglen_v = 0; | ||
253 | int size_y, size_u = 0, size_v = 0; | ||
177 | 254 | ||
178 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 255 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
179 | vb, vb->baddr, vb->bsize); | 256 | vb, vb->baddr, vb->bsize); |
@@ -218,49 +295,64 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
218 | if (ret) | 295 | if (ret) |
219 | goto fail; | 296 | goto fail; |
220 | 297 | ||
221 | if (buf->sg_cpu) | 298 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) { |
222 | dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu, | 299 | /* FIXME the calculations should be more precise */ |
223 | buf->sg_dma); | 300 | sglen_y = dma->sglen / 2; |
301 | sglen_u = sglen_v = dma->sglen / 4 + 1; | ||
302 | sglen_yu = sglen_y + sglen_u; | ||
303 | size_y = size / 2; | ||
304 | size_u = size_v = size / 4; | ||
305 | } else { | ||
306 | sglen_y = dma->sglen; | ||
307 | size_y = size; | ||
308 | } | ||
309 | |||
310 | /* init DMA for Y channel */ | ||
311 | ret = pxa_init_dma_channel(pcdev, buf, dma, 0, sglen_y, | ||
312 | 0, 0x28, size_y); | ||
224 | 313 | ||
225 | buf->sg_size = (dma->sglen + 1) * sizeof(struct pxa_dma_desc); | 314 | if (ret) { |
226 | buf->sg_cpu = dma_alloc_coherent(pcdev->dev, buf->sg_size, | 315 | dev_err(pcdev->dev, |
227 | &buf->sg_dma, GFP_KERNEL); | 316 | "DMA initialization for Y/RGB failed\n"); |
228 | if (!buf->sg_cpu) { | ||
229 | ret = -ENOMEM; | ||
230 | goto fail; | 317 | goto fail; |
231 | } | 318 | } |
232 | 319 | ||
233 | dev_dbg(&icd->dev, "nents=%d size: %d sg=0x%p\n", | 320 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) { |
234 | dma->sglen, size, dma->sglist); | 321 | /* init DMA for U channel */ |
235 | for (i = 0; i < dma->sglen; i++) { | 322 | ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u, |
236 | struct scatterlist *sg = dma->sglist; | 323 | sglen_y, 0x30, size_u); |
237 | unsigned int dma_len = sg_dma_len(&sg[i]), xfer_len; | 324 | if (ret) { |
238 | 325 | dev_err(pcdev->dev, | |
239 | /* CIBR0 */ | 326 | "DMA initialization for U failed\n"); |
240 | buf->sg_cpu[i].dsadr = pcdev->res->start + 0x28; | 327 | goto fail_u; |
241 | buf->sg_cpu[i].dtadr = sg_dma_address(&sg[i]); | 328 | } |
242 | /* PXA270 Developer's Manual 27.4.4.1: | 329 | |
243 | * round up to 8 bytes */ | 330 | /* init DMA for V channel */ |
244 | xfer_len = (min(dma_len, size) + 7) & ~7; | 331 | ret = pxa_init_dma_channel(pcdev, buf, dma, 2, sglen_v, |
245 | if (xfer_len & 7) | 332 | sglen_yu, 0x38, size_v); |
246 | dev_err(&icd->dev, "Unaligned buffer: " | 333 | if (ret) { |
247 | "dma_len %u, size %u\n", dma_len, size); | 334 | dev_err(pcdev->dev, |
248 | buf->sg_cpu[i].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | | 335 | "DMA initialization for V failed\n"); |
249 | DCMD_INCTRGADDR | xfer_len; | 336 | goto fail_v; |
250 | size -= dma_len; | 337 | } |
251 | buf->sg_cpu[i].ddadr = buf->sg_dma + (i + 1) * | ||
252 | sizeof(struct pxa_dma_desc); | ||
253 | } | 338 | } |
254 | buf->sg_cpu[dma->sglen - 1].ddadr = DDADR_STOP; | ||
255 | buf->sg_cpu[dma->sglen - 1].dcmd |= DCMD_ENDIRQEN; | ||
256 | 339 | ||
257 | vb->state = VIDEOBUF_PREPARED; | 340 | vb->state = VIDEOBUF_PREPARED; |
258 | } | 341 | } |
259 | 342 | ||
260 | buf->inwork = 0; | 343 | buf->inwork = 0; |
344 | buf->active_dma = DMA_Y; | ||
345 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) | ||
346 | buf->active_dma |= DMA_U | DMA_V; | ||
261 | 347 | ||
262 | return 0; | 348 | return 0; |
263 | 349 | ||
350 | fail_v: | ||
351 | dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size, | ||
352 | buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); | ||
353 | fail_u: | ||
354 | dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size, | ||
355 | buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); | ||
264 | fail: | 356 | fail: |
265 | free_buffer(vq, buf); | 357 | free_buffer(vq, buf); |
266 | out: | 358 | out: |
@@ -277,8 +369,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
277 | struct pxa_camera_dev *pcdev = ici->priv; | 369 | struct pxa_camera_dev *pcdev = ici->priv; |
278 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 370 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
279 | struct pxa_buffer *active; | 371 | struct pxa_buffer *active; |
280 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
281 | int nents = dma->sglen; | ||
282 | unsigned long flags; | 372 | unsigned long flags; |
283 | 373 | ||
284 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 374 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
@@ -292,59 +382,86 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
292 | 382 | ||
293 | if (!active) { | 383 | if (!active) { |
294 | CIFR |= CIFR_RESET_F; | 384 | CIFR |= CIFR_RESET_F; |
295 | DDADR(pcdev->dma_chan_y) = buf->sg_dma; | 385 | DDADR(pcdev->dma_chans[0]) = buf->dmas[0].sg_dma; |
296 | DCSR(pcdev->dma_chan_y) = DCSR_RUN; | 386 | DCSR(pcdev->dma_chans[0]) = DCSR_RUN; |
387 | |||
388 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) { | ||
389 | DDADR(pcdev->dma_chans[1]) = buf->dmas[1].sg_dma; | ||
390 | DCSR(pcdev->dma_chans[1]) = DCSR_RUN; | ||
391 | |||
392 | DDADR(pcdev->dma_chans[2]) = buf->dmas[2].sg_dma; | ||
393 | DCSR(pcdev->dma_chans[2]) = DCSR_RUN; | ||
394 | } | ||
395 | |||
297 | pcdev->active = buf; | 396 | pcdev->active = buf; |
298 | CICR0 |= CICR0_ENB; | 397 | CICR0 |= CICR0_ENB; |
299 | } else { | 398 | } else { |
300 | struct videobuf_dmabuf *active_dma = | 399 | struct pxa_cam_dma *buf_dma; |
301 | videobuf_to_dma(&active->vb); | 400 | struct pxa_cam_dma *act_dma; |
302 | /* Stop DMA engine */ | 401 | int channels = 1; |
303 | DCSR(pcdev->dma_chan_y) = 0; | 402 | int nents; |
304 | 403 | int i; | |
305 | /* Add the descriptors we just initialized to the currently | 404 | |
306 | * running chain | 405 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) |
307 | */ | 406 | channels = 3; |
308 | active->sg_cpu[active_dma->sglen - 1].ddadr = buf->sg_dma; | 407 | |
309 | 408 | for (i = 0; i < channels; i++) { | |
310 | /* Setup a dummy descriptor with the DMA engines current | 409 | buf_dma = &buf->dmas[i]; |
311 | * state | 410 | act_dma = &active->dmas[i]; |
312 | */ | 411 | nents = buf_dma->sglen; |
313 | /* CIBR0 */ | 412 | |
314 | buf->sg_cpu[nents].dsadr = pcdev->res->start + 0x28; | 413 | /* Stop DMA engine */ |
315 | buf->sg_cpu[nents].dtadr = DTADR(pcdev->dma_chan_y); | 414 | DCSR(pcdev->dma_chans[i]) = 0; |
316 | buf->sg_cpu[nents].dcmd = DCMD(pcdev->dma_chan_y); | 415 | |
317 | 416 | /* Add the descriptors we just initialized to | |
318 | if (DDADR(pcdev->dma_chan_y) == DDADR_STOP) { | 417 | the currently running chain */ |
319 | /* The DMA engine is on the last descriptor, set the | 418 | act_dma->sg_cpu[act_dma->sglen - 1].ddadr = |
320 | * next descriptors address to the descriptors | 419 | buf_dma->sg_dma; |
321 | * we just initialized | 420 | |
421 | /* Setup a dummy descriptor with the DMA engines current | ||
422 | * state | ||
322 | */ | 423 | */ |
323 | buf->sg_cpu[nents].ddadr = buf->sg_dma; | 424 | buf_dma->sg_cpu[nents].dsadr = |
324 | } else { | 425 | pcdev->res->start + 0x28 + i*8; /* CIBRx */ |
325 | buf->sg_cpu[nents].ddadr = DDADR(pcdev->dma_chan_y); | 426 | buf_dma->sg_cpu[nents].dtadr = |
427 | DTADR(pcdev->dma_chans[i]); | ||
428 | buf_dma->sg_cpu[nents].dcmd = | ||
429 | DCMD(pcdev->dma_chans[i]); | ||
430 | |||
431 | if (DDADR(pcdev->dma_chans[i]) == DDADR_STOP) { | ||
432 | /* The DMA engine is on the last | ||
433 | descriptor, set the next descriptors | ||
434 | address to the descriptors we just | ||
435 | initialized */ | ||
436 | buf_dma->sg_cpu[nents].ddadr = buf_dma->sg_dma; | ||
437 | } else { | ||
438 | buf_dma->sg_cpu[nents].ddadr = | ||
439 | DDADR(pcdev->dma_chans[i]); | ||
440 | } | ||
441 | |||
442 | /* The next descriptor is the dummy descriptor */ | ||
443 | DDADR(pcdev->dma_chans[i]) = buf_dma->sg_dma + nents * | ||
444 | sizeof(struct pxa_dma_desc); | ||
445 | |||
446 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | ||
326 | } | 447 | } |
327 | |||
328 | /* The next descriptor is the dummy descriptor */ | ||
329 | DDADR(pcdev->dma_chan_y) = buf->sg_dma + nents * | ||
330 | sizeof(struct pxa_dma_desc); | ||
331 | |||
332 | #ifdef DEBUG | 448 | #ifdef DEBUG |
333 | if (CISR & CISR_IFO_0) { | 449 | if (CISR & (CISR_IFO_0 | CISR_IFO_1 | CISR_IFO_2)) { |
334 | dev_warn(pcdev->dev, "FIFO overrun\n"); | 450 | dev_warn(pcdev->dev, "FIFO overrun\n"); |
335 | DDADR(pcdev->dma_chan_y) = pcdev->active->sg_dma; | 451 | for (i = 0; i < channels; i++) |
452 | DDADR(pcdev->dma_chans[i]) = | ||
453 | pcdev->active->dmas[i].sg_dma; | ||
336 | 454 | ||
337 | CICR0 &= ~CICR0_ENB; | 455 | CICR0 &= ~CICR0_ENB; |
338 | CIFR |= CIFR_RESET_F; | 456 | CIFR |= CIFR_RESET_F; |
339 | DCSR(pcdev->dma_chan_y) = DCSR_RUN; | 457 | for (i = 0; i < channels; i++) |
458 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | ||
340 | CICR0 |= CICR0_ENB; | 459 | CICR0 |= CICR0_ENB; |
341 | } else | 460 | } |
342 | #endif | 461 | #endif |
343 | DCSR(pcdev->dma_chan_y) = DCSR_RUN; | ||
344 | } | 462 | } |
345 | 463 | ||
346 | spin_unlock_irqrestore(&pcdev->lock, flags); | 464 | spin_unlock_irqrestore(&pcdev->lock, flags); |
347 | |||
348 | } | 465 | } |
349 | 466 | ||
350 | static void pxa_videobuf_release(struct videobuf_queue *vq, | 467 | static void pxa_videobuf_release(struct videobuf_queue *vq, |
@@ -376,9 +493,33 @@ static void pxa_videobuf_release(struct videobuf_queue *vq, | |||
376 | free_buffer(vq, buf); | 493 | free_buffer(vq, buf); |
377 | } | 494 | } |
378 | 495 | ||
379 | static void pxa_camera_dma_irq_y(int channel, void *data) | 496 | static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, |
497 | struct videobuf_buffer *vb, | ||
498 | struct pxa_buffer *buf) | ||
499 | { | ||
500 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ | ||
501 | list_del_init(&vb->queue); | ||
502 | vb->state = VIDEOBUF_DONE; | ||
503 | do_gettimeofday(&vb->ts); | ||
504 | vb->field_count++; | ||
505 | wake_up(&vb->done); | ||
506 | |||
507 | if (list_empty(&pcdev->capture)) { | ||
508 | pcdev->active = NULL; | ||
509 | DCSR(pcdev->dma_chans[0]) = 0; | ||
510 | DCSR(pcdev->dma_chans[1]) = 0; | ||
511 | DCSR(pcdev->dma_chans[2]) = 0; | ||
512 | CICR0 &= ~CICR0_ENB; | ||
513 | return; | ||
514 | } | ||
515 | |||
516 | pcdev->active = list_entry(pcdev->capture.next, | ||
517 | struct pxa_buffer, vb.queue); | ||
518 | } | ||
519 | |||
520 | static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | ||
521 | enum pxa_camera_active_dma act_dma) | ||
380 | { | 522 | { |
381 | struct pxa_camera_dev *pcdev = data; | ||
382 | struct pxa_buffer *buf; | 523 | struct pxa_buffer *buf; |
383 | unsigned long flags; | 524 | unsigned long flags; |
384 | unsigned int status; | 525 | unsigned int status; |
@@ -386,8 +527,8 @@ static void pxa_camera_dma_irq_y(int channel, void *data) | |||
386 | 527 | ||
387 | spin_lock_irqsave(&pcdev->lock, flags); | 528 | spin_lock_irqsave(&pcdev->lock, flags); |
388 | 529 | ||
389 | status = DCSR(pcdev->dma_chan_y); | 530 | status = DCSR(channel); |
390 | DCSR(pcdev->dma_chan_y) = status; | 531 | DCSR(channel) = status | DCSR_ENDINTR; |
391 | 532 | ||
392 | if (status & DCSR_BUSERR) { | 533 | if (status & DCSR_BUSERR) { |
393 | dev_err(pcdev->dev, "DMA Bus Error IRQ!\n"); | 534 | dev_err(pcdev->dev, "DMA Bus Error IRQ!\n"); |
@@ -411,27 +552,32 @@ static void pxa_camera_dma_irq_y(int channel, void *data) | |||
411 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 552 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
412 | vb, vb->baddr, vb->bsize); | 553 | vb, vb->baddr, vb->bsize); |
413 | 554 | ||
414 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ | 555 | buf->active_dma &= ~act_dma; |
415 | list_del_init(&vb->queue); | 556 | if (!buf->active_dma) |
416 | vb->state = VIDEOBUF_DONE; | 557 | pxa_camera_wakeup(pcdev, vb, buf); |
417 | do_gettimeofday(&vb->ts); | ||
418 | vb->field_count++; | ||
419 | wake_up(&vb->done); | ||
420 | |||
421 | if (list_empty(&pcdev->capture)) { | ||
422 | pcdev->active = NULL; | ||
423 | DCSR(pcdev->dma_chan_y) = 0; | ||
424 | CICR0 &= ~CICR0_ENB; | ||
425 | goto out; | ||
426 | } | ||
427 | |||
428 | pcdev->active = list_entry(pcdev->capture.next, struct pxa_buffer, | ||
429 | vb.queue); | ||
430 | 558 | ||
431 | out: | 559 | out: |
432 | spin_unlock_irqrestore(&pcdev->lock, flags); | 560 | spin_unlock_irqrestore(&pcdev->lock, flags); |
433 | } | 561 | } |
434 | 562 | ||
563 | static void pxa_camera_dma_irq_y(int channel, void *data) | ||
564 | { | ||
565 | struct pxa_camera_dev *pcdev = data; | ||
566 | pxa_camera_dma_irq(channel, pcdev, DMA_Y); | ||
567 | } | ||
568 | |||
569 | static void pxa_camera_dma_irq_u(int channel, void *data) | ||
570 | { | ||
571 | struct pxa_camera_dev *pcdev = data; | ||
572 | pxa_camera_dma_irq(channel, pcdev, DMA_U); | ||
573 | } | ||
574 | |||
575 | static void pxa_camera_dma_irq_v(int channel, void *data) | ||
576 | { | ||
577 | struct pxa_camera_dev *pcdev = data; | ||
578 | pxa_camera_dma_irq(channel, pcdev, DMA_V); | ||
579 | } | ||
580 | |||
435 | static struct videobuf_queue_ops pxa_videobuf_ops = { | 581 | static struct videobuf_queue_ops pxa_videobuf_ops = { |
436 | .buf_setup = pxa_videobuf_setup, | 582 | .buf_setup = pxa_videobuf_setup, |
437 | .buf_prepare = pxa_videobuf_prepare, | 583 | .buf_prepare = pxa_videobuf_prepare, |
@@ -525,7 +671,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) | |||
525 | dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status); | 671 | dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status); |
526 | 672 | ||
527 | CISR = status; | 673 | CISR = status; |
528 | |||
529 | return IRQ_HANDLED; | 674 | return IRQ_HANDLED; |
530 | } | 675 | } |
531 | 676 | ||
@@ -571,8 +716,11 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd) | |||
571 | 716 | ||
572 | /* disable capture, disable interrupts */ | 717 | /* disable capture, disable interrupts */ |
573 | CICR0 = 0x3ff; | 718 | CICR0 = 0x3ff; |
719 | |||
574 | /* Stop DMA engine */ | 720 | /* Stop DMA engine */ |
575 | DCSR(pcdev->dma_chan_y) = 0; | 721 | DCSR(pcdev->dma_chans[0]) = 0; |
722 | DCSR(pcdev->dma_chans[1]) = 0; | ||
723 | DCSR(pcdev->dma_chans[2]) = 0; | ||
576 | 724 | ||
577 | icd->ops->release(icd); | 725 | icd->ops->release(icd); |
578 | 726 | ||
@@ -625,7 +773,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
625 | to_soc_camera_host(icd->dev.parent); | 773 | to_soc_camera_host(icd->dev.parent); |
626 | struct pxa_camera_dev *pcdev = ici->priv; | 774 | struct pxa_camera_dev *pcdev = ici->priv; |
627 | unsigned long dw, bpp, bus_flags, camera_flags, common_flags; | 775 | unsigned long dw, bpp, bus_flags, camera_flags, common_flags; |
628 | u32 cicr0, cicr4 = 0; | 776 | u32 cicr0, cicr1, cicr4 = 0; |
629 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); | 777 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); |
630 | 778 | ||
631 | if (ret < 0) | 779 | if (ret < 0) |
@@ -702,7 +850,25 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
702 | cicr0 = CICR0; | 850 | cicr0 = CICR0; |
703 | if (cicr0 & CICR0_ENB) | 851 | if (cicr0 & CICR0_ENB) |
704 | CICR0 = cicr0 & ~CICR0_ENB; | 852 | CICR0 = cicr0 & ~CICR0_ENB; |
705 | CICR1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw; | 853 | |
854 | cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw; | ||
855 | |||
856 | switch (pixfmt) { | ||
857 | case V4L2_PIX_FMT_YUV422P: | ||
858 | cicr1 |= CICR1_YCBCR_F; | ||
859 | case V4L2_PIX_FMT_YUYV: | ||
860 | cicr1 |= CICR1_COLOR_SP_VAL(2); | ||
861 | break; | ||
862 | case V4L2_PIX_FMT_RGB555: | ||
863 | cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) | | ||
864 | CICR1_TBIT | CICR1_COLOR_SP_VAL(1); | ||
865 | break; | ||
866 | case V4L2_PIX_FMT_RGB565: | ||
867 | cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2); | ||
868 | break; | ||
869 | } | ||
870 | |||
871 | CICR1 = cicr1; | ||
706 | CICR2 = 0; | 872 | CICR2 = 0; |
707 | CICR3 = CICR3_LPF_VAL(icd->height - 1) | | 873 | CICR3 = CICR3_LPF_VAL(icd->height - 1) | |
708 | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); | 874 | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); |
@@ -905,16 +1071,36 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
905 | pcdev->dev = &pdev->dev; | 1071 | pcdev->dev = &pdev->dev; |
906 | 1072 | ||
907 | /* request dma */ | 1073 | /* request dma */ |
908 | pcdev->dma_chan_y = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, | 1074 | pcdev->dma_chans[0] = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, |
909 | pxa_camera_dma_irq_y, pcdev); | 1075 | pxa_camera_dma_irq_y, pcdev); |
910 | if (pcdev->dma_chan_y < 0) { | 1076 | if (pcdev->dma_chans[0] < 0) { |
911 | dev_err(pcdev->dev, "Can't request DMA for Y\n"); | 1077 | dev_err(pcdev->dev, "Can't request DMA for Y\n"); |
912 | err = -ENOMEM; | 1078 | err = -ENOMEM; |
913 | goto exit_iounmap; | 1079 | goto exit_iounmap; |
914 | } | 1080 | } |
915 | dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan_y); | 1081 | dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); |
1082 | |||
1083 | pcdev->dma_chans[1] = pxa_request_dma("CI_U", DMA_PRIO_HIGH, | ||
1084 | pxa_camera_dma_irq_u, pcdev); | ||
1085 | if (pcdev->dma_chans[1] < 0) { | ||
1086 | dev_err(pcdev->dev, "Can't request DMA for U\n"); | ||
1087 | err = -ENOMEM; | ||
1088 | goto exit_free_dma_y; | ||
1089 | } | ||
1090 | dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); | ||
1091 | |||
1092 | pcdev->dma_chans[2] = pxa_request_dma("CI_V", DMA_PRIO_HIGH, | ||
1093 | pxa_camera_dma_irq_v, pcdev); | ||
1094 | if (pcdev->dma_chans[0] < 0) { | ||
1095 | dev_err(pcdev->dev, "Can't request DMA for V\n"); | ||
1096 | err = -ENOMEM; | ||
1097 | goto exit_free_dma_u; | ||
1098 | } | ||
1099 | dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); | ||
916 | 1100 | ||
917 | DRCMR68 = pcdev->dma_chan_y | DRCMR_MAPVLD; | 1101 | DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD; |
1102 | DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD; | ||
1103 | DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD; | ||
918 | 1104 | ||
919 | /* request irq */ | 1105 | /* request irq */ |
920 | err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, | 1106 | err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, |
@@ -936,7 +1122,11 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
936 | exit_free_irq: | 1122 | exit_free_irq: |
937 | free_irq(pcdev->irq, pcdev); | 1123 | free_irq(pcdev->irq, pcdev); |
938 | exit_free_dma: | 1124 | exit_free_dma: |
939 | pxa_free_dma(pcdev->dma_chan_y); | 1125 | pxa_free_dma(pcdev->dma_chans[2]); |
1126 | exit_free_dma_u: | ||
1127 | pxa_free_dma(pcdev->dma_chans[1]); | ||
1128 | exit_free_dma_y: | ||
1129 | pxa_free_dma(pcdev->dma_chans[0]); | ||
940 | exit_iounmap: | 1130 | exit_iounmap: |
941 | iounmap(base); | 1131 | iounmap(base); |
942 | exit_release: | 1132 | exit_release: |
@@ -956,7 +1146,9 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev) | |||
956 | 1146 | ||
957 | clk_put(pcdev->clk); | 1147 | clk_put(pcdev->clk); |
958 | 1148 | ||
959 | pxa_free_dma(pcdev->dma_chan_y); | 1149 | pxa_free_dma(pcdev->dma_chans[0]); |
1150 | pxa_free_dma(pcdev->dma_chans[1]); | ||
1151 | pxa_free_dma(pcdev->dma_chans[2]); | ||
960 | free_irq(pcdev->irq, pcdev); | 1152 | free_irq(pcdev->irq, pcdev); |
961 | 1153 | ||
962 | soc_camera_host_unregister(&pxa_soc_camera_host); | 1154 | soc_camera_host_unregister(&pxa_soc_camera_host); |