aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pxa_camera.c
diff options
context:
space:
mode:
authorRobert Jarzmik <robert.jarzmik@free.fr>2009-03-31 02:44:21 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-04-06 20:43:45 -0400
commit37f5aefd537d5f98b3fa9726362effeccf1d2161 (patch)
treec9a27e6f7f5ada15c3774b79b394030552bd4798 /drivers/media/video/pxa_camera.c
parent92a8337b380f0978ac81f096d6324d3ad689f83e (diff)
V4L/DVB (11320): pxa_camera: Remove YUV planar formats hole
All planes were PAGE aligned (ie. 4096 bytes aligned). This is not consistent with YUV422 format, which requires Y, U and V planes glued together. The new implementation forces the alignement on 8 bytes (DMA requirement), which is almost always the case (granted by width x height being a multiple of 8). The test cases include tests in both YUV422 and RGB565 : - a picture of size 111 x 111 (cross RAM pages example) - a picture of size 1023 x 4 in (under 1 RAM page) - a picture of size 1024 x 4 in (exactly 1 RAM page) - a picture of size 1025 x 4 in (over 1 RAM page) - a picture of size 1280 x 1024 (many RAM pages) Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r--drivers/media/video/pxa_camera.c143
1 files changed, 105 insertions, 38 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 5f57e4018849..07f792b659d9 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -287,19 +287,63 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
287 buf->vb.state = VIDEOBUF_NEEDS_INIT; 287 buf->vb.state = VIDEOBUF_NEEDS_INIT;
288} 288}
289 289
290static int calculate_dma_sglen(struct scatterlist *sglist, int sglen,
291 int sg_first_ofs, int size)
292{
293 int i, offset, dma_len, xfer_len;
294 struct scatterlist *sg;
295
296 offset = sg_first_ofs;
297 for_each_sg(sglist, sg, sglen, i) {
298 dma_len = sg_dma_len(sg);
299
300 /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
301 xfer_len = roundup(min(dma_len - offset, size), 8);
302
303 size = max(0, size - xfer_len);
304 offset = 0;
305 if (size == 0)
306 break;
307 }
308
309 BUG_ON(size != 0);
310 return i + 1;
311}
312
313/**
314 * pxa_init_dma_channel - init dma descriptors
315 * @pcdev: pxa camera device
316 * @buf: pxa buffer to find pxa dma channel
317 * @dma: dma video buffer
318 * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V')
319 * @cibr: camera Receive Buffer Register
320 * @size: bytes to transfer
321 * @sg_first: first element of sg_list
322 * @sg_first_ofs: offset in first element of sg_list
323 *
324 * Prepares the pxa dma descriptors to transfer one camera channel.
325 * Beware sg_first and sg_first_ofs are both input and output parameters.
326 *
327 * Returns 0 or -ENOMEM if no coherent memory is available
328 */
290static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, 329static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
291 struct pxa_buffer *buf, 330 struct pxa_buffer *buf,
292 struct videobuf_dmabuf *dma, int channel, 331 struct videobuf_dmabuf *dma, int channel,
293 int sglen, int sg_start, int cibr, 332 int cibr, int size,
294 unsigned int size) 333 struct scatterlist **sg_first, int *sg_first_ofs)
295{ 334{
296 struct pxa_cam_dma *pxa_dma = &buf->dmas[channel]; 335 struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
297 int i; 336 struct scatterlist *sg;
337 int i, offset, sglen;
338 int dma_len = 0, xfer_len = 0;
298 339
299 if (pxa_dma->sg_cpu) 340 if (pxa_dma->sg_cpu)
300 dma_free_coherent(pcdev->dev, pxa_dma->sg_size, 341 dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
301 pxa_dma->sg_cpu, pxa_dma->sg_dma); 342 pxa_dma->sg_cpu, pxa_dma->sg_dma);
302 343
344 sglen = calculate_dma_sglen(*sg_first, dma->sglen,
345 *sg_first_ofs, size);
346
303 pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); 347 pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
304 pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size, 348 pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
305 &pxa_dma->sg_dma, GFP_KERNEL); 349 &pxa_dma->sg_dma, GFP_KERNEL);
@@ -307,28 +351,54 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
307 return -ENOMEM; 351 return -ENOMEM;
308 352
309 pxa_dma->sglen = sglen; 353 pxa_dma->sglen = sglen;
354 offset = *sg_first_ofs;
310 355
311 for (i = 0; i < sglen; i++) { 356 dev_dbg(pcdev->dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
312 int sg_i = sg_start + i; 357 *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
313 struct scatterlist *sg = dma->sglist;
314 unsigned int dma_len = sg_dma_len(&sg[sg_i]), xfer_len;
315 358
316 pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr; 359
317 pxa_dma->sg_cpu[i].dtadr = sg_dma_address(&sg[sg_i]); 360 for_each_sg(*sg_first, sg, sglen, i) {
361 dma_len = sg_dma_len(sg);
318 362
319 /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */ 363 /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
320 xfer_len = (min(dma_len, size) + 7) & ~7; 364 xfer_len = roundup(min(dma_len - offset, size), 8);
321 365
366 size = max(0, size - xfer_len);
367
368 pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
369 pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset;
322 pxa_dma->sg_cpu[i].dcmd = 370 pxa_dma->sg_cpu[i].dcmd =
323 DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len; 371 DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
324 size -= dma_len;
325 pxa_dma->sg_cpu[i].ddadr = 372 pxa_dma->sg_cpu[i].ddadr =
326 pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); 373 pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
374
375 dev_vdbg(pcdev->dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
376 pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
377 sg_dma_address(sg) + offset, xfer_len);
378 offset = 0;
379
380 if (size == 0)
381 break;
327 } 382 }
328 383
329 pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP; 384 pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP;
330 pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN; 385 pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN;
331 386
387 /*
388 * Handle 1 special case :
389 * - in 3 planes (YUV422P format), we might finish with xfer_len equal
390 * to dma_len (end on PAGE boundary). In this case, the sg element
391 * for next plane should be the next after the last used to store the
392 * last scatter gather RAM page
393 */
394 if (xfer_len >= dma_len) {
395 *sg_first_ofs = xfer_len - dma_len;
396 *sg_first = sg_next(sg);
397 } else {
398 *sg_first_ofs = xfer_len;
399 *sg_first = sg;
400 }
401
332 return 0; 402 return 0;
333} 403}
334 404
@@ -340,7 +410,6 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
340 struct pxa_camera_dev *pcdev = ici->priv; 410 struct pxa_camera_dev *pcdev = ici->priv;
341 struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); 411 struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
342 int ret; 412 int ret;
343 int sglen_y, sglen_yu = 0, sglen_u = 0, sglen_v = 0;
344 int size_y, size_u = 0, size_v = 0; 413 int size_y, size_u = 0, size_v = 0;
345 414
346 dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, 415 dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
@@ -379,53 +448,51 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
379 } 448 }
380 449
381 if (vb->state == VIDEOBUF_NEEDS_INIT) { 450 if (vb->state == VIDEOBUF_NEEDS_INIT) {
382 unsigned int size = vb->size; 451 int size = vb->size;
452 int next_ofs = 0;
383 struct videobuf_dmabuf *dma = videobuf_to_dma(vb); 453 struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
454 struct scatterlist *sg;
384 455
385 ret = videobuf_iolock(vq, vb, NULL); 456 ret = videobuf_iolock(vq, vb, NULL);
386 if (ret) 457 if (ret)
387 goto fail; 458 goto fail;
388 459
389 if (pcdev->channels == 3) { 460 if (pcdev->channels == 3) {
390 /* FIXME the calculations should be more precise */
391 sglen_y = dma->sglen / 2;
392 sglen_u = sglen_v = dma->sglen / 4 + 1;
393 sglen_yu = sglen_y + sglen_u;
394 size_y = size / 2; 461 size_y = size / 2;
395 size_u = size_v = size / 4; 462 size_u = size_v = size / 4;
396 } else { 463 } else {
397 sglen_y = dma->sglen;
398 size_y = size; 464 size_y = size;
399 } 465 }
400 466
401 /* init DMA for Y channel */ 467 sg = dma->sglist;
402 ret = pxa_init_dma_channel(pcdev, buf, dma, 0, sglen_y,
403 0, 0x28, size_y);
404 468
469 /* init DMA for Y channel */
470 ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
471 &sg, &next_ofs);
405 if (ret) { 472 if (ret) {
406 dev_err(pcdev->dev, 473 dev_err(pcdev->dev,
407 "DMA initialization for Y/RGB failed\n"); 474 "DMA initialization for Y/RGB failed\n");
408 goto fail; 475 goto fail;
409 } 476 }
410 477
411 if (pcdev->channels == 3) { 478 /* init DMA for U channel */
412 /* init DMA for U channel */ 479 if (size_u)
413 ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u, 480 ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
414 sglen_y, 0x30, size_u); 481 size_u, &sg, &next_ofs);
415 if (ret) { 482 if (ret) {
416 dev_err(pcdev->dev, 483 dev_err(pcdev->dev,
417 "DMA initialization for U failed\n"); 484 "DMA initialization for U failed\n");
418 goto fail_u; 485 goto fail_u;
419 } 486 }
420 487
421 /* init DMA for V channel */ 488 /* init DMA for V channel */
422 ret = pxa_init_dma_channel(pcdev, buf, dma, 2, sglen_v, 489 if (size_v)
423 sglen_yu, 0x38, size_v); 490 ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
424 if (ret) { 491 size_v, &sg, &next_ofs);
425 dev_err(pcdev->dev, 492 if (ret) {
426 "DMA initialization for V failed\n"); 493 dev_err(pcdev->dev,
427 goto fail_v; 494 "DMA initialization for V failed\n");
428 } 495 goto fail_v;
429 } 496 }
430 497
431 vb->state = VIDEOBUF_PREPARED; 498 vb->state = VIDEOBUF_PREPARED;