diff options
Diffstat (limited to 'drivers/media/video/sh_mobile_ceu_camera.c')
-rw-r--r-- | drivers/media/video/sh_mobile_ceu_camera.c | 520 |
1 files changed, 319 insertions, 201 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 961e4484d721..d69363f0d8c9 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <media/soc_camera.h> | 38 | #include <media/soc_camera.h> |
39 | #include <media/sh_mobile_ceu.h> | 39 | #include <media/sh_mobile_ceu.h> |
40 | #include <media/videobuf-dma-contig.h> | 40 | #include <media/videobuf-dma-contig.h> |
41 | #include <media/v4l2-mediabus.h> | ||
42 | #include <media/soc_mediabus.h> | ||
41 | 43 | ||
42 | /* register offsets for sh7722 / sh7723 */ | 44 | /* register offsets for sh7722 / sh7723 */ |
43 | 45 | ||
@@ -85,7 +87,7 @@ | |||
85 | /* per video frame buffer */ | 87 | /* per video frame buffer */ |
86 | struct sh_mobile_ceu_buffer { | 88 | struct sh_mobile_ceu_buffer { |
87 | struct videobuf_buffer vb; /* v4l buffer must be first */ | 89 | struct videobuf_buffer vb; /* v4l buffer must be first */ |
88 | const struct soc_camera_data_format *fmt; | 90 | enum v4l2_mbus_pixelcode code; |
89 | }; | 91 | }; |
90 | 92 | ||
91 | struct sh_mobile_ceu_dev { | 93 | struct sh_mobile_ceu_dev { |
@@ -105,7 +107,8 @@ struct sh_mobile_ceu_dev { | |||
105 | 107 | ||
106 | u32 cflcr; | 108 | u32 cflcr; |
107 | 109 | ||
108 | unsigned int is_interlaced:1; | 110 | enum v4l2_field field; |
111 | |||
109 | unsigned int image_mode:1; | 112 | unsigned int image_mode:1; |
110 | unsigned int is_16bit:1; | 113 | unsigned int is_16bit:1; |
111 | }; | 114 | }; |
@@ -114,8 +117,8 @@ struct sh_mobile_ceu_cam { | |||
114 | struct v4l2_rect ceu_rect; | 117 | struct v4l2_rect ceu_rect; |
115 | unsigned int cam_width; | 118 | unsigned int cam_width; |
116 | unsigned int cam_height; | 119 | unsigned int cam_height; |
117 | const struct soc_camera_data_format *extra_fmt; | 120 | const struct soc_mbus_pixelfmt *extra_fmt; |
118 | const struct soc_camera_data_format *camera_fmt; | 121 | enum v4l2_mbus_pixelcode code; |
119 | }; | 122 | }; |
120 | 123 | ||
121 | static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) | 124 | static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) |
@@ -197,16 +200,19 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, | |||
197 | struct soc_camera_device *icd = vq->priv_data; | 200 | struct soc_camera_device *icd = vq->priv_data; |
198 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 201 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
199 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 202 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
200 | int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3; | 203 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
204 | icd->current_fmt->host_fmt); | ||
205 | |||
206 | if (bytes_per_line < 0) | ||
207 | return bytes_per_line; | ||
201 | 208 | ||
202 | *size = PAGE_ALIGN(icd->user_width * icd->user_height * | 209 | *size = bytes_per_line * icd->user_height; |
203 | bytes_per_pixel); | ||
204 | 210 | ||
205 | if (0 == *count) | 211 | if (0 == *count) |
206 | *count = 2; | 212 | *count = 2; |
207 | 213 | ||
208 | if (pcdev->video_limit) { | 214 | if (pcdev->video_limit) { |
209 | while (*size * *count > pcdev->video_limit) | 215 | while (PAGE_ALIGN(*size) * *count > pcdev->video_limit) |
210 | (*count)--; | 216 | (*count)--; |
211 | } | 217 | } |
212 | 218 | ||
@@ -249,10 +255,13 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
249 | { | 255 | { |
250 | struct soc_camera_device *icd = pcdev->icd; | 256 | struct soc_camera_device *icd = pcdev->icd; |
251 | dma_addr_t phys_addr_top, phys_addr_bottom; | 257 | dma_addr_t phys_addr_top, phys_addr_bottom; |
258 | unsigned long top1, top2; | ||
259 | unsigned long bottom1, bottom2; | ||
252 | u32 status; | 260 | u32 status; |
253 | int ret = 0; | 261 | int ret = 0; |
254 | 262 | ||
255 | /* The hardware is _very_ picky about this sequence. Especially | 263 | /* |
264 | * The hardware is _very_ picky about this sequence. Especially | ||
256 | * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge | 265 | * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge |
257 | * several not-so-well documented interrupt sources in CETCR. | 266 | * several not-so-well documented interrupt sources in CETCR. |
258 | */ | 267 | */ |
@@ -276,25 +285,36 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
276 | if (!pcdev->active) | 285 | if (!pcdev->active) |
277 | return ret; | 286 | return ret; |
278 | 287 | ||
288 | if (V4L2_FIELD_INTERLACED_BT == pcdev->field) { | ||
289 | top1 = CDBYR; | ||
290 | top2 = CDBCR; | ||
291 | bottom1 = CDAYR; | ||
292 | bottom2 = CDACR; | ||
293 | } else { | ||
294 | top1 = CDAYR; | ||
295 | top2 = CDACR; | ||
296 | bottom1 = CDBYR; | ||
297 | bottom2 = CDBCR; | ||
298 | } | ||
299 | |||
279 | phys_addr_top = videobuf_to_dma_contig(pcdev->active); | 300 | phys_addr_top = videobuf_to_dma_contig(pcdev->active); |
280 | ceu_write(pcdev, CDAYR, phys_addr_top); | 301 | ceu_write(pcdev, top1, phys_addr_top); |
281 | if (pcdev->is_interlaced) { | 302 | if (V4L2_FIELD_NONE != pcdev->field) { |
282 | phys_addr_bottom = phys_addr_top + icd->user_width; | 303 | phys_addr_bottom = phys_addr_top + icd->user_width; |
283 | ceu_write(pcdev, CDBYR, phys_addr_bottom); | 304 | ceu_write(pcdev, bottom1, phys_addr_bottom); |
284 | } | 305 | } |
285 | 306 | ||
286 | switch (icd->current_fmt->fourcc) { | 307 | switch (icd->current_fmt->host_fmt->fourcc) { |
287 | case V4L2_PIX_FMT_NV12: | 308 | case V4L2_PIX_FMT_NV12: |
288 | case V4L2_PIX_FMT_NV21: | 309 | case V4L2_PIX_FMT_NV21: |
289 | case V4L2_PIX_FMT_NV16: | 310 | case V4L2_PIX_FMT_NV16: |
290 | case V4L2_PIX_FMT_NV61: | 311 | case V4L2_PIX_FMT_NV61: |
291 | phys_addr_top += icd->user_width * | 312 | phys_addr_top += icd->user_width * |
292 | icd->user_height; | 313 | icd->user_height; |
293 | ceu_write(pcdev, CDACR, phys_addr_top); | 314 | ceu_write(pcdev, top2, phys_addr_top); |
294 | if (pcdev->is_interlaced) { | 315 | if (V4L2_FIELD_NONE != pcdev->field) { |
295 | phys_addr_bottom = phys_addr_top + | 316 | phys_addr_bottom = phys_addr_top + icd->user_width; |
296 | icd->user_width; | 317 | ceu_write(pcdev, bottom2, phys_addr_bottom); |
297 | ceu_write(pcdev, CDBCR, phys_addr_bottom); | ||
298 | } | 318 | } |
299 | } | 319 | } |
300 | 320 | ||
@@ -310,8 +330,13 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, | |||
310 | { | 330 | { |
311 | struct soc_camera_device *icd = vq->priv_data; | 331 | struct soc_camera_device *icd = vq->priv_data; |
312 | struct sh_mobile_ceu_buffer *buf; | 332 | struct sh_mobile_ceu_buffer *buf; |
333 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
334 | icd->current_fmt->host_fmt); | ||
313 | int ret; | 335 | int ret; |
314 | 336 | ||
337 | if (bytes_per_line < 0) | ||
338 | return bytes_per_line; | ||
339 | |||
315 | buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); | 340 | buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); |
316 | 341 | ||
317 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, | 342 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, |
@@ -321,25 +346,27 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, | |||
321 | WARN_ON(!list_empty(&vb->queue)); | 346 | WARN_ON(!list_empty(&vb->queue)); |
322 | 347 | ||
323 | #ifdef DEBUG | 348 | #ifdef DEBUG |
324 | /* This can be useful if you want to see if we actually fill | 349 | /* |
325 | * the buffer with something */ | 350 | * This can be useful if you want to see if we actually fill |
351 | * the buffer with something | ||
352 | */ | ||
326 | memset((void *)vb->baddr, 0xaa, vb->bsize); | 353 | memset((void *)vb->baddr, 0xaa, vb->bsize); |
327 | #endif | 354 | #endif |
328 | 355 | ||
329 | BUG_ON(NULL == icd->current_fmt); | 356 | BUG_ON(NULL == icd->current_fmt); |
330 | 357 | ||
331 | if (buf->fmt != icd->current_fmt || | 358 | if (buf->code != icd->current_fmt->code || |
332 | vb->width != icd->user_width || | 359 | vb->width != icd->user_width || |
333 | vb->height != icd->user_height || | 360 | vb->height != icd->user_height || |
334 | vb->field != field) { | 361 | vb->field != field) { |
335 | buf->fmt = icd->current_fmt; | 362 | buf->code = icd->current_fmt->code; |
336 | vb->width = icd->user_width; | 363 | vb->width = icd->user_width; |
337 | vb->height = icd->user_height; | 364 | vb->height = icd->user_height; |
338 | vb->field = field; | 365 | vb->field = field; |
339 | vb->state = VIDEOBUF_NEEDS_INIT; | 366 | vb->state = VIDEOBUF_NEEDS_INIT; |
340 | } | 367 | } |
341 | 368 | ||
342 | vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); | 369 | vb->size = vb->height * bytes_per_line; |
343 | if (0 != vb->baddr && vb->bsize < vb->size) { | 370 | if (0 != vb->baddr && vb->bsize < vb->size) { |
344 | ret = -EINVAL; | 371 | ret = -EINVAL; |
345 | goto out; | 372 | goto out; |
@@ -456,6 +483,7 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
456 | { | 483 | { |
457 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 484 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
458 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 485 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
486 | int ret; | ||
459 | 487 | ||
460 | if (pcdev->icd) | 488 | if (pcdev->icd) |
461 | return -EBUSY; | 489 | return -EBUSY; |
@@ -466,9 +494,11 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
466 | 494 | ||
467 | pm_runtime_get_sync(ici->v4l2_dev.dev); | 495 | pm_runtime_get_sync(ici->v4l2_dev.dev); |
468 | 496 | ||
469 | pcdev->icd = icd; | 497 | ret = sh_mobile_ceu_soft_reset(pcdev); |
498 | if (!ret) | ||
499 | pcdev->icd = icd; | ||
470 | 500 | ||
471 | return sh_mobile_ceu_soft_reset(pcdev); | 501 | return ret; |
472 | } | 502 | } |
473 | 503 | ||
474 | /* Called with .video_lock held */ | 504 | /* Called with .video_lock held */ |
@@ -558,24 +588,35 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd, | |||
558 | in_width *= 2; | 588 | in_width *= 2; |
559 | left_offset *= 2; | 589 | left_offset *= 2; |
560 | } | 590 | } |
561 | width = cdwdr_width = out_width; | 591 | width = out_width; |
592 | cdwdr_width = out_width; | ||
562 | } else { | 593 | } else { |
563 | unsigned int w_factor = (icd->current_fmt->depth + 7) >> 3; | 594 | int bytes_per_line = soc_mbus_bytes_per_line(out_width, |
595 | icd->current_fmt->host_fmt); | ||
596 | unsigned int w_factor; | ||
564 | 597 | ||
565 | width = out_width * w_factor / 2; | 598 | width = out_width; |
566 | 599 | ||
567 | if (!pcdev->is_16bit) | 600 | switch (icd->current_fmt->host_fmt->packing) { |
568 | w_factor *= 2; | 601 | case SOC_MBUS_PACKING_2X8_PADHI: |
602 | w_factor = 2; | ||
603 | break; | ||
604 | default: | ||
605 | w_factor = 1; | ||
606 | } | ||
569 | 607 | ||
570 | in_width = rect->width * w_factor / 2; | 608 | in_width = rect->width * w_factor; |
571 | left_offset = left_offset * w_factor / 2; | 609 | left_offset = left_offset * w_factor; |
572 | 610 | ||
573 | cdwdr_width = width * 2; | 611 | if (bytes_per_line < 0) |
612 | cdwdr_width = out_width; | ||
613 | else | ||
614 | cdwdr_width = bytes_per_line; | ||
574 | } | 615 | } |
575 | 616 | ||
576 | height = out_height; | 617 | height = out_height; |
577 | in_height = rect->height; | 618 | in_height = rect->height; |
578 | if (pcdev->is_interlaced) { | 619 | if (V4L2_FIELD_NONE != pcdev->field) { |
579 | height /= 2; | 620 | height /= 2; |
580 | in_height /= 2; | 621 | in_height /= 2; |
581 | top_offset /= 2; | 622 | top_offset /= 2; |
@@ -646,6 +687,23 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
646 | if (!common_flags) | 687 | if (!common_flags) |
647 | return -EINVAL; | 688 | return -EINVAL; |
648 | 689 | ||
690 | /* Make choises, based on platform preferences */ | ||
691 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | ||
692 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | ||
693 | if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) | ||
694 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | ||
695 | else | ||
696 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | ||
697 | } | ||
698 | |||
699 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | ||
700 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | ||
701 | if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) | ||
702 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | ||
703 | else | ||
704 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | ||
705 | } | ||
706 | |||
649 | ret = icd->ops->set_bus_param(icd, common_flags); | 707 | ret = icd->ops->set_bus_param(icd, common_flags); |
650 | if (ret < 0) | 708 | if (ret < 0) |
651 | return ret; | 709 | return ret; |
@@ -667,24 +725,24 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
667 | value = 0x00000010; /* data fetch by default */ | 725 | value = 0x00000010; /* data fetch by default */ |
668 | yuv_lineskip = 0; | 726 | yuv_lineskip = 0; |
669 | 727 | ||
670 | switch (icd->current_fmt->fourcc) { | 728 | switch (icd->current_fmt->host_fmt->fourcc) { |
671 | case V4L2_PIX_FMT_NV12: | 729 | case V4L2_PIX_FMT_NV12: |
672 | case V4L2_PIX_FMT_NV21: | 730 | case V4L2_PIX_FMT_NV21: |
673 | yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ | 731 | yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ |
674 | /* fall-through */ | 732 | /* fall-through */ |
675 | case V4L2_PIX_FMT_NV16: | 733 | case V4L2_PIX_FMT_NV16: |
676 | case V4L2_PIX_FMT_NV61: | 734 | case V4L2_PIX_FMT_NV61: |
677 | switch (cam->camera_fmt->fourcc) { | 735 | switch (cam->code) { |
678 | case V4L2_PIX_FMT_UYVY: | 736 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: |
679 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ | 737 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ |
680 | break; | 738 | break; |
681 | case V4L2_PIX_FMT_VYUY: | 739 | case V4L2_MBUS_FMT_YVYU8_2X8_BE: |
682 | value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ | 740 | value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ |
683 | break; | 741 | break; |
684 | case V4L2_PIX_FMT_YUYV: | 742 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
685 | value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ | 743 | value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ |
686 | break; | 744 | break; |
687 | case V4L2_PIX_FMT_YVYU: | 745 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
688 | value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ | 746 | value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ |
689 | break; | 747 | break; |
690 | default: | 748 | default: |
@@ -692,8 +750,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
692 | } | 750 | } |
693 | } | 751 | } |
694 | 752 | ||
695 | if (icd->current_fmt->fourcc == V4L2_PIX_FMT_NV21 || | 753 | if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV21 || |
696 | icd->current_fmt->fourcc == V4L2_PIX_FMT_NV61) | 754 | icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) |
697 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ | 755 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ |
698 | 756 | ||
699 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | 757 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
@@ -702,14 +760,27 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
702 | ceu_write(pcdev, CAMCR, value); | 760 | ceu_write(pcdev, CAMCR, value); |
703 | 761 | ||
704 | ceu_write(pcdev, CAPCR, 0x00300000); | 762 | ceu_write(pcdev, CAPCR, 0x00300000); |
705 | ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); | 763 | |
764 | switch (pcdev->field) { | ||
765 | case V4L2_FIELD_INTERLACED_TB: | ||
766 | value = 0x101; | ||
767 | break; | ||
768 | case V4L2_FIELD_INTERLACED_BT: | ||
769 | value = 0x102; | ||
770 | break; | ||
771 | default: | ||
772 | value = 0; | ||
773 | break; | ||
774 | } | ||
775 | ceu_write(pcdev, CAIFR, value); | ||
706 | 776 | ||
707 | sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height); | 777 | sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height); |
708 | mdelay(1); | 778 | mdelay(1); |
709 | 779 | ||
710 | ceu_write(pcdev, CFLCR, pcdev->cflcr); | 780 | ceu_write(pcdev, CFLCR, pcdev->cflcr); |
711 | 781 | ||
712 | /* A few words about byte order (observed in Big Endian mode) | 782 | /* |
783 | * A few words about byte order (observed in Big Endian mode) | ||
713 | * | 784 | * |
714 | * In data fetch mode bytes are received in chunks of 8 bytes. | 785 | * In data fetch mode bytes are received in chunks of 8 bytes. |
715 | * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) | 786 | * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) |
@@ -739,7 +810,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
739 | return 0; | 810 | return 0; |
740 | } | 811 | } |
741 | 812 | ||
742 | static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd) | 813 | static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, |
814 | unsigned char buswidth) | ||
743 | { | 815 | { |
744 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 816 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
745 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 817 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
@@ -748,48 +820,75 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd) | |||
748 | camera_flags = icd->ops->query_bus_param(icd); | 820 | camera_flags = icd->ops->query_bus_param(icd); |
749 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 821 | common_flags = soc_camera_bus_param_compatible(camera_flags, |
750 | make_bus_param(pcdev)); | 822 | make_bus_param(pcdev)); |
751 | if (!common_flags) | 823 | if (!common_flags || buswidth > 16 || |
824 | (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16))) | ||
752 | return -EINVAL; | 825 | return -EINVAL; |
753 | 826 | ||
754 | return 0; | 827 | return 0; |
755 | } | 828 | } |
756 | 829 | ||
757 | static const struct soc_camera_data_format sh_mobile_ceu_formats[] = { | 830 | static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { |
758 | { | ||
759 | .name = "NV12", | ||
760 | .depth = 12, | ||
761 | .fourcc = V4L2_PIX_FMT_NV12, | ||
762 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
763 | }, | ||
764 | { | ||
765 | .name = "NV21", | ||
766 | .depth = 12, | ||
767 | .fourcc = V4L2_PIX_FMT_NV21, | ||
768 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
769 | }, | ||
770 | { | ||
771 | .name = "NV16", | ||
772 | .depth = 16, | ||
773 | .fourcc = V4L2_PIX_FMT_NV16, | ||
774 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
775 | }, | ||
776 | { | 831 | { |
777 | .name = "NV61", | 832 | .fourcc = V4L2_PIX_FMT_NV12, |
778 | .depth = 16, | 833 | .name = "NV12", |
779 | .fourcc = V4L2_PIX_FMT_NV61, | 834 | .bits_per_sample = 12, |
780 | .colorspace = V4L2_COLORSPACE_JPEG, | 835 | .packing = SOC_MBUS_PACKING_NONE, |
836 | .order = SOC_MBUS_ORDER_LE, | ||
837 | }, { | ||
838 | .fourcc = V4L2_PIX_FMT_NV21, | ||
839 | .name = "NV21", | ||
840 | .bits_per_sample = 12, | ||
841 | .packing = SOC_MBUS_PACKING_NONE, | ||
842 | .order = SOC_MBUS_ORDER_LE, | ||
843 | }, { | ||
844 | .fourcc = V4L2_PIX_FMT_NV16, | ||
845 | .name = "NV16", | ||
846 | .bits_per_sample = 16, | ||
847 | .packing = SOC_MBUS_PACKING_NONE, | ||
848 | .order = SOC_MBUS_ORDER_LE, | ||
849 | }, { | ||
850 | .fourcc = V4L2_PIX_FMT_NV61, | ||
851 | .name = "NV61", | ||
852 | .bits_per_sample = 16, | ||
853 | .packing = SOC_MBUS_PACKING_NONE, | ||
854 | .order = SOC_MBUS_ORDER_LE, | ||
781 | }, | 855 | }, |
782 | }; | 856 | }; |
783 | 857 | ||
858 | /* This will be corrected as we get more formats */ | ||
859 | static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
860 | { | ||
861 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
862 | (fmt->bits_per_sample == 8 && | ||
863 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
864 | (fmt->bits_per_sample > 8 && | ||
865 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
866 | } | ||
867 | |||
784 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | 868 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, |
785 | struct soc_camera_format_xlate *xlate) | 869 | struct soc_camera_format_xlate *xlate) |
786 | { | 870 | { |
871 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
787 | struct device *dev = icd->dev.parent; | 872 | struct device *dev = icd->dev.parent; |
788 | int ret, k, n; | 873 | int ret, k, n; |
789 | int formats = 0; | 874 | int formats = 0; |
790 | struct sh_mobile_ceu_cam *cam; | 875 | struct sh_mobile_ceu_cam *cam; |
876 | enum v4l2_mbus_pixelcode code; | ||
877 | const struct soc_mbus_pixelfmt *fmt; | ||
791 | 878 | ||
792 | ret = sh_mobile_ceu_try_bus_param(icd); | 879 | ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); |
880 | if (ret < 0) | ||
881 | /* No more formats */ | ||
882 | return 0; | ||
883 | |||
884 | fmt = soc_mbus_get_fmtdesc(code); | ||
885 | if (!fmt) { | ||
886 | dev_err(icd->dev.parent, | ||
887 | "Invalid format code #%d: %d\n", idx, code); | ||
888 | return -EINVAL; | ||
889 | } | ||
890 | |||
891 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); | ||
793 | if (ret < 0) | 892 | if (ret < 0) |
794 | return 0; | 893 | return 0; |
795 | 894 | ||
@@ -807,13 +906,13 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
807 | if (!idx) | 906 | if (!idx) |
808 | cam->extra_fmt = NULL; | 907 | cam->extra_fmt = NULL; |
809 | 908 | ||
810 | switch (icd->formats[idx].fourcc) { | 909 | switch (code) { |
811 | case V4L2_PIX_FMT_UYVY: | 910 | case V4L2_MBUS_FMT_YUYV8_2X8_BE: |
812 | case V4L2_PIX_FMT_VYUY: | 911 | case V4L2_MBUS_FMT_YVYU8_2X8_BE: |
813 | case V4L2_PIX_FMT_YUYV: | 912 | case V4L2_MBUS_FMT_YUYV8_2X8_LE: |
814 | case V4L2_PIX_FMT_YVYU: | 913 | case V4L2_MBUS_FMT_YVYU8_2X8_LE: |
815 | if (cam->extra_fmt) | 914 | if (cam->extra_fmt) |
816 | goto add_single_format; | 915 | break; |
817 | 916 | ||
818 | /* | 917 | /* |
819 | * Our case is simple so far: for any of the above four camera | 918 | * Our case is simple so far: for any of the above four camera |
@@ -824,32 +923,31 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
824 | * the host_priv pointer and check whether the format you're | 923 | * the host_priv pointer and check whether the format you're |
825 | * going to add now is already there. | 924 | * going to add now is already there. |
826 | */ | 925 | */ |
827 | cam->extra_fmt = (void *)sh_mobile_ceu_formats; | 926 | cam->extra_fmt = sh_mobile_ceu_formats; |
828 | 927 | ||
829 | n = ARRAY_SIZE(sh_mobile_ceu_formats); | 928 | n = ARRAY_SIZE(sh_mobile_ceu_formats); |
830 | formats += n; | 929 | formats += n; |
831 | for (k = 0; xlate && k < n; k++) { | 930 | for (k = 0; xlate && k < n; k++) { |
832 | xlate->host_fmt = &sh_mobile_ceu_formats[k]; | 931 | xlate->host_fmt = &sh_mobile_ceu_formats[k]; |
833 | xlate->cam_fmt = icd->formats + idx; | 932 | xlate->code = code; |
834 | xlate->buswidth = icd->formats[idx].depth; | ||
835 | xlate++; | 933 | xlate++; |
836 | dev_dbg(dev, "Providing format %s using %s\n", | 934 | dev_dbg(dev, "Providing format %s using code %d\n", |
837 | sh_mobile_ceu_formats[k].name, | 935 | sh_mobile_ceu_formats[k].name, code); |
838 | icd->formats[idx].name); | ||
839 | } | 936 | } |
937 | break; | ||
840 | default: | 938 | default: |
841 | add_single_format: | 939 | if (!sh_mobile_ceu_packing_supported(fmt)) |
842 | /* Generic pass-through */ | 940 | return 0; |
843 | formats++; | 941 | } |
844 | if (xlate) { | 942 | |
845 | xlate->host_fmt = icd->formats + idx; | 943 | /* Generic pass-through */ |
846 | xlate->cam_fmt = icd->formats + idx; | 944 | formats++; |
847 | xlate->buswidth = icd->formats[idx].depth; | 945 | if (xlate) { |
848 | xlate++; | 946 | xlate->host_fmt = fmt; |
849 | dev_dbg(dev, | 947 | xlate->code = code; |
850 | "Providing format %s in pass-through mode\n", | 948 | xlate++; |
851 | icd->formats[idx].name); | 949 | dev_dbg(dev, "Providing format %s in pass-through mode\n", |
852 | } | 950 | xlate->host_fmt->name); |
853 | } | 951 | } |
854 | 952 | ||
855 | return formats; | 953 | return formats; |
@@ -1029,17 +1127,15 @@ static int client_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop, | |||
1029 | static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect, | 1127 | static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect, |
1030 | unsigned int *scale_h, unsigned int *scale_v) | 1128 | unsigned int *scale_h, unsigned int *scale_v) |
1031 | { | 1129 | { |
1032 | struct v4l2_format f; | 1130 | struct v4l2_mbus_framefmt mf; |
1033 | int ret; | 1131 | int ret; |
1034 | 1132 | ||
1035 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1133 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); |
1036 | |||
1037 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
1038 | if (ret < 0) | 1134 | if (ret < 0) |
1039 | return ret; | 1135 | return ret; |
1040 | 1136 | ||
1041 | *scale_h = calc_generic_scale(rect->width, f.fmt.pix.width); | 1137 | *scale_h = calc_generic_scale(rect->width, mf.width); |
1042 | *scale_v = calc_generic_scale(rect->height, f.fmt.pix.height); | 1138 | *scale_v = calc_generic_scale(rect->height, mf.height); |
1043 | 1139 | ||
1044 | return 0; | 1140 | return 0; |
1045 | } | 1141 | } |
@@ -1054,32 +1150,29 @@ static int get_camera_subwin(struct soc_camera_device *icd, | |||
1054 | if (!ceu_rect->width) { | 1150 | if (!ceu_rect->width) { |
1055 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1151 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1056 | struct device *dev = icd->dev.parent; | 1152 | struct device *dev = icd->dev.parent; |
1057 | struct v4l2_format f; | 1153 | struct v4l2_mbus_framefmt mf; |
1058 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
1059 | int ret; | 1154 | int ret; |
1060 | /* First time */ | 1155 | /* First time */ |
1061 | 1156 | ||
1062 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1157 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); |
1063 | |||
1064 | ret = v4l2_subdev_call(sd, video, g_fmt, &f); | ||
1065 | if (ret < 0) | 1158 | if (ret < 0) |
1066 | return ret; | 1159 | return ret; |
1067 | 1160 | ||
1068 | dev_geo(dev, "camera fmt %ux%u\n", pix->width, pix->height); | 1161 | dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height); |
1069 | 1162 | ||
1070 | if (pix->width > 2560) { | 1163 | if (mf.width > 2560) { |
1071 | ceu_rect->width = 2560; | 1164 | ceu_rect->width = 2560; |
1072 | ceu_rect->left = (pix->width - 2560) / 2; | 1165 | ceu_rect->left = (mf.width - 2560) / 2; |
1073 | } else { | 1166 | } else { |
1074 | ceu_rect->width = pix->width; | 1167 | ceu_rect->width = mf.width; |
1075 | ceu_rect->left = 0; | 1168 | ceu_rect->left = 0; |
1076 | } | 1169 | } |
1077 | 1170 | ||
1078 | if (pix->height > 1920) { | 1171 | if (mf.height > 1920) { |
1079 | ceu_rect->height = 1920; | 1172 | ceu_rect->height = 1920; |
1080 | ceu_rect->top = (pix->height - 1920) / 2; | 1173 | ceu_rect->top = (mf.height - 1920) / 2; |
1081 | } else { | 1174 | } else { |
1082 | ceu_rect->height = pix->height; | 1175 | ceu_rect->height = mf.height; |
1083 | ceu_rect->top = 0; | 1176 | ceu_rect->top = 0; |
1084 | } | 1177 | } |
1085 | 1178 | ||
@@ -1096,13 +1189,12 @@ static int get_camera_subwin(struct soc_camera_device *icd, | |||
1096 | return 0; | 1189 | return 0; |
1097 | } | 1190 | } |
1098 | 1191 | ||
1099 | static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, | 1192 | static int client_s_fmt(struct soc_camera_device *icd, |
1100 | bool ceu_can_scale) | 1193 | struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) |
1101 | { | 1194 | { |
1102 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1195 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1103 | struct device *dev = icd->dev.parent; | 1196 | struct device *dev = icd->dev.parent; |
1104 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1197 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; |
1105 | unsigned int width = pix->width, height = pix->height, tmp_w, tmp_h; | ||
1106 | unsigned int max_width, max_height; | 1198 | unsigned int max_width, max_height; |
1107 | struct v4l2_cropcap cap; | 1199 | struct v4l2_cropcap cap; |
1108 | int ret; | 1200 | int ret; |
@@ -1116,29 +1208,29 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, | |||
1116 | max_width = min(cap.bounds.width, 2560); | 1208 | max_width = min(cap.bounds.width, 2560); |
1117 | max_height = min(cap.bounds.height, 1920); | 1209 | max_height = min(cap.bounds.height, 1920); |
1118 | 1210 | ||
1119 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | 1211 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); |
1120 | if (ret < 0) | 1212 | if (ret < 0) |
1121 | return ret; | 1213 | return ret; |
1122 | 1214 | ||
1123 | dev_geo(dev, "camera scaled to %ux%u\n", pix->width, pix->height); | 1215 | dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); |
1124 | 1216 | ||
1125 | if ((width == pix->width && height == pix->height) || !ceu_can_scale) | 1217 | if ((width == mf->width && height == mf->height) || !ceu_can_scale) |
1126 | return 0; | 1218 | return 0; |
1127 | 1219 | ||
1128 | /* Camera set a format, but geometry is not precise, try to improve */ | 1220 | /* Camera set a format, but geometry is not precise, try to improve */ |
1129 | tmp_w = pix->width; | 1221 | tmp_w = mf->width; |
1130 | tmp_h = pix->height; | 1222 | tmp_h = mf->height; |
1131 | 1223 | ||
1132 | /* width <= max_width && height <= max_height - guaranteed by try_fmt */ | 1224 | /* width <= max_width && height <= max_height - guaranteed by try_fmt */ |
1133 | while ((width > tmp_w || height > tmp_h) && | 1225 | while ((width > tmp_w || height > tmp_h) && |
1134 | tmp_w < max_width && tmp_h < max_height) { | 1226 | tmp_w < max_width && tmp_h < max_height) { |
1135 | tmp_w = min(2 * tmp_w, max_width); | 1227 | tmp_w = min(2 * tmp_w, max_width); |
1136 | tmp_h = min(2 * tmp_h, max_height); | 1228 | tmp_h = min(2 * tmp_h, max_height); |
1137 | pix->width = tmp_w; | 1229 | mf->width = tmp_w; |
1138 | pix->height = tmp_h; | 1230 | mf->height = tmp_h; |
1139 | ret = v4l2_subdev_call(sd, video, s_fmt, f); | 1231 | ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); |
1140 | dev_geo(dev, "Camera scaled to %ux%u\n", | 1232 | dev_geo(dev, "Camera scaled to %ux%u\n", |
1141 | pix->width, pix->height); | 1233 | mf->width, mf->height); |
1142 | if (ret < 0) { | 1234 | if (ret < 0) { |
1143 | /* This shouldn't happen */ | 1235 | /* This shouldn't happen */ |
1144 | dev_err(dev, "Client failed to set format: %d\n", ret); | 1236 | dev_err(dev, "Client failed to set format: %d\n", ret); |
@@ -1156,27 +1248,26 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, | |||
1156 | */ | 1248 | */ |
1157 | static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, | 1249 | static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, |
1158 | struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect, | 1250 | struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect, |
1159 | struct v4l2_format *f, bool ceu_can_scale) | 1251 | struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) |
1160 | { | 1252 | { |
1161 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1253 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1162 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1254 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1163 | struct device *dev = icd->dev.parent; | 1255 | struct device *dev = icd->dev.parent; |
1164 | struct v4l2_format f_tmp = *f; | 1256 | struct v4l2_mbus_framefmt mf_tmp = *mf; |
1165 | struct v4l2_pix_format *pix_tmp = &f_tmp.fmt.pix; | ||
1166 | unsigned int scale_h, scale_v; | 1257 | unsigned int scale_h, scale_v; |
1167 | int ret; | 1258 | int ret; |
1168 | 1259 | ||
1169 | /* 5. Apply iterative camera S_FMT for camera user window. */ | 1260 | /* 5. Apply iterative camera S_FMT for camera user window. */ |
1170 | ret = client_s_fmt(icd, &f_tmp, ceu_can_scale); | 1261 | ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale); |
1171 | if (ret < 0) | 1262 | if (ret < 0) |
1172 | return ret; | 1263 | return ret; |
1173 | 1264 | ||
1174 | dev_geo(dev, "5: camera scaled to %ux%u\n", | 1265 | dev_geo(dev, "5: camera scaled to %ux%u\n", |
1175 | pix_tmp->width, pix_tmp->height); | 1266 | mf_tmp.width, mf_tmp.height); |
1176 | 1267 | ||
1177 | /* 6. Retrieve camera output window (g_fmt) */ | 1268 | /* 6. Retrieve camera output window (g_fmt) */ |
1178 | 1269 | ||
1179 | /* unneeded - it is already in "f_tmp" */ | 1270 | /* unneeded - it is already in "mf_tmp" */ |
1180 | 1271 | ||
1181 | /* 7. Calculate new camera scales. */ | 1272 | /* 7. Calculate new camera scales. */ |
1182 | ret = get_camera_scales(sd, rect, &scale_h, &scale_v); | 1273 | ret = get_camera_scales(sd, rect, &scale_h, &scale_v); |
@@ -1185,10 +1276,11 @@ static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, | |||
1185 | 1276 | ||
1186 | dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v); | 1277 | dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v); |
1187 | 1278 | ||
1188 | cam->cam_width = pix_tmp->width; | 1279 | cam->cam_width = mf_tmp.width; |
1189 | cam->cam_height = pix_tmp->height; | 1280 | cam->cam_height = mf_tmp.height; |
1190 | f->fmt.pix.width = pix_tmp->width; | 1281 | mf->width = mf_tmp.width; |
1191 | f->fmt.pix.height = pix_tmp->height; | 1282 | mf->height = mf_tmp.height; |
1283 | mf->colorspace = mf_tmp.colorspace; | ||
1192 | 1284 | ||
1193 | /* | 1285 | /* |
1194 | * 8. Calculate new CEU crop - apply camera scales to previously | 1286 | * 8. Calculate new CEU crop - apply camera scales to previously |
@@ -1252,8 +1344,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1252 | struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect; | 1344 | struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect; |
1253 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1345 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1254 | struct device *dev = icd->dev.parent; | 1346 | struct device *dev = icd->dev.parent; |
1255 | struct v4l2_format f; | 1347 | struct v4l2_mbus_framefmt mf; |
1256 | struct v4l2_pix_format *pix = &f.fmt.pix; | ||
1257 | unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v, | 1348 | unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v, |
1258 | out_width, out_height; | 1349 | out_width, out_height; |
1259 | u32 capsr, cflcr; | 1350 | u32 capsr, cflcr; |
@@ -1302,26 +1393,25 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1302 | * 5. Using actual input window and calculated combined scales calculate | 1393 | * 5. Using actual input window and calculated combined scales calculate |
1303 | * camera target output window. | 1394 | * camera target output window. |
1304 | */ | 1395 | */ |
1305 | pix->width = scale_down(cam_rect->width, scale_comb_h); | 1396 | mf.width = scale_down(cam_rect->width, scale_comb_h); |
1306 | pix->height = scale_down(cam_rect->height, scale_comb_v); | 1397 | mf.height = scale_down(cam_rect->height, scale_comb_v); |
1307 | 1398 | ||
1308 | dev_geo(dev, "5: camera target %ux%u\n", pix->width, pix->height); | 1399 | dev_geo(dev, "5: camera target %ux%u\n", mf.width, mf.height); |
1309 | 1400 | ||
1310 | /* 6. - 9. */ | 1401 | /* 6. - 9. */ |
1311 | pix->pixelformat = cam->camera_fmt->fourcc; | 1402 | mf.code = cam->code; |
1312 | pix->colorspace = cam->camera_fmt->colorspace; | 1403 | mf.field = pcdev->field; |
1313 | 1404 | ||
1314 | capsr = capture_save_reset(pcdev); | 1405 | capsr = capture_save_reset(pcdev); |
1315 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); | 1406 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); |
1316 | 1407 | ||
1317 | /* Make relative to camera rectangle */ | 1408 | /* Make relative to camera rectangle */ |
1318 | rect->left -= cam_rect->left; | 1409 | rect->left -= cam_rect->left; |
1319 | rect->top -= cam_rect->top; | 1410 | rect->top -= cam_rect->top; |
1320 | 1411 | ||
1321 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1412 | ret = client_scale(icd, cam_rect, rect, ceu_rect, &mf, |
1322 | 1413 | pcdev->image_mode && | |
1323 | ret = client_scale(icd, cam_rect, rect, ceu_rect, &f, | 1414 | V4L2_FIELD_NONE == pcdev->field); |
1324 | pcdev->image_mode && !pcdev->is_interlaced); | ||
1325 | 1415 | ||
1326 | dev_geo(dev, "6-9: %d\n", ret); | 1416 | dev_geo(dev, "6-9: %d\n", ret); |
1327 | 1417 | ||
@@ -1368,8 +1458,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1368 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 1458 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
1369 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1459 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1370 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1460 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1371 | struct v4l2_format cam_f = *f; | 1461 | struct v4l2_mbus_framefmt mf; |
1372 | struct v4l2_pix_format *cam_pix = &cam_f.fmt.pix; | ||
1373 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1462 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1374 | struct device *dev = icd->dev.parent; | 1463 | struct device *dev = icd->dev.parent; |
1375 | __u32 pixfmt = pix->pixelformat; | 1464 | __u32 pixfmt = pix->pixelformat; |
@@ -1379,18 +1468,20 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1379 | unsigned int scale_cam_h, scale_cam_v; | 1468 | unsigned int scale_cam_h, scale_cam_v; |
1380 | u16 scale_v, scale_h; | 1469 | u16 scale_v, scale_h; |
1381 | int ret; | 1470 | int ret; |
1382 | bool is_interlaced, image_mode; | 1471 | bool image_mode; |
1472 | enum v4l2_field field; | ||
1383 | 1473 | ||
1384 | switch (pix->field) { | 1474 | switch (pix->field) { |
1385 | case V4L2_FIELD_INTERLACED: | ||
1386 | is_interlaced = true; | ||
1387 | break; | ||
1388 | case V4L2_FIELD_ANY: | ||
1389 | default: | 1475 | default: |
1390 | pix->field = V4L2_FIELD_NONE; | 1476 | pix->field = V4L2_FIELD_NONE; |
1391 | /* fall-through */ | 1477 | /* fall-through */ |
1478 | case V4L2_FIELD_INTERLACED_TB: | ||
1479 | case V4L2_FIELD_INTERLACED_BT: | ||
1392 | case V4L2_FIELD_NONE: | 1480 | case V4L2_FIELD_NONE: |
1393 | is_interlaced = false; | 1481 | field = pix->field; |
1482 | break; | ||
1483 | case V4L2_FIELD_INTERLACED: | ||
1484 | field = V4L2_FIELD_INTERLACED_TB; | ||
1394 | break; | 1485 | break; |
1395 | } | 1486 | } |
1396 | 1487 | ||
@@ -1438,9 +1529,11 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1438 | * 4. Calculate camera output window by applying combined scales to real | 1529 | * 4. Calculate camera output window by applying combined scales to real |
1439 | * input window. | 1530 | * input window. |
1440 | */ | 1531 | */ |
1441 | cam_pix->width = scale_down(cam_rect->width, scale_h); | 1532 | mf.width = scale_down(cam_rect->width, scale_h); |
1442 | cam_pix->height = scale_down(cam_rect->height, scale_v); | 1533 | mf.height = scale_down(cam_rect->height, scale_v); |
1443 | cam_pix->pixelformat = xlate->cam_fmt->fourcc; | 1534 | mf.field = pix->field; |
1535 | mf.colorspace = pix->colorspace; | ||
1536 | mf.code = xlate->code; | ||
1444 | 1537 | ||
1445 | switch (pixfmt) { | 1538 | switch (pixfmt) { |
1446 | case V4L2_PIX_FMT_NV12: | 1539 | case V4L2_PIX_FMT_NV12: |
@@ -1453,51 +1546,61 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1453 | image_mode = false; | 1546 | image_mode = false; |
1454 | } | 1547 | } |
1455 | 1548 | ||
1456 | dev_geo(dev, "4: camera output %ux%u\n", | 1549 | dev_geo(dev, "4: camera output %ux%u\n", mf.width, mf.height); |
1457 | cam_pix->width, cam_pix->height); | ||
1458 | 1550 | ||
1459 | /* 5. - 9. */ | 1551 | /* 5. - 9. */ |
1460 | ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &cam_f, | 1552 | ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &mf, |
1461 | image_mode && !is_interlaced); | 1553 | image_mode && V4L2_FIELD_NONE == field); |
1462 | 1554 | ||
1463 | dev_geo(dev, "5-9: client scale %d\n", ret); | 1555 | dev_geo(dev, "5-9: client scale %d\n", ret); |
1464 | 1556 | ||
1465 | /* Done with the camera. Now see if we can improve the result */ | 1557 | /* Done with the camera. Now see if we can improve the result */ |
1466 | 1558 | ||
1467 | dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n", | 1559 | dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n", |
1468 | ret, cam_pix->width, cam_pix->height, pix->width, pix->height); | 1560 | ret, mf.width, mf.height, pix->width, pix->height); |
1469 | if (ret < 0) | 1561 | if (ret < 0) |
1470 | return ret; | 1562 | return ret; |
1471 | 1563 | ||
1564 | if (mf.code != xlate->code) | ||
1565 | return -EINVAL; | ||
1566 | |||
1472 | /* 10. Use CEU scaling to scale to the requested user window. */ | 1567 | /* 10. Use CEU scaling to scale to the requested user window. */ |
1473 | 1568 | ||
1474 | /* We cannot scale up */ | 1569 | /* We cannot scale up */ |
1475 | if (pix->width > cam_pix->width) | 1570 | if (pix->width > mf.width) |
1476 | pix->width = cam_pix->width; | 1571 | pix->width = mf.width; |
1477 | if (pix->width > ceu_rect.width) | 1572 | if (pix->width > ceu_rect.width) |
1478 | pix->width = ceu_rect.width; | 1573 | pix->width = ceu_rect.width; |
1479 | 1574 | ||
1480 | if (pix->height > cam_pix->height) | 1575 | if (pix->height > mf.height) |
1481 | pix->height = cam_pix->height; | 1576 | pix->height = mf.height; |
1482 | if (pix->height > ceu_rect.height) | 1577 | if (pix->height > ceu_rect.height) |
1483 | pix->height = ceu_rect.height; | 1578 | pix->height = ceu_rect.height; |
1484 | 1579 | ||
1485 | /* Let's rock: scale pix->{width x height} down to width x height */ | 1580 | pix->colorspace = mf.colorspace; |
1486 | scale_h = calc_scale(ceu_rect.width, &pix->width); | 1581 | |
1487 | scale_v = calc_scale(ceu_rect.height, &pix->height); | 1582 | if (image_mode) { |
1583 | /* Scale pix->{width x height} down to width x height */ | ||
1584 | scale_h = calc_scale(ceu_rect.width, &pix->width); | ||
1585 | scale_v = calc_scale(ceu_rect.height, &pix->height); | ||
1586 | |||
1587 | pcdev->cflcr = scale_h | (scale_v << 16); | ||
1588 | } else { | ||
1589 | pix->width = ceu_rect.width; | ||
1590 | pix->height = ceu_rect.height; | ||
1591 | scale_h = scale_v = 0; | ||
1592 | pcdev->cflcr = 0; | ||
1593 | } | ||
1488 | 1594 | ||
1489 | dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", | 1595 | dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", |
1490 | ceu_rect.width, scale_h, pix->width, | 1596 | ceu_rect.width, scale_h, pix->width, |
1491 | ceu_rect.height, scale_v, pix->height); | 1597 | ceu_rect.height, scale_v, pix->height); |
1492 | 1598 | ||
1493 | pcdev->cflcr = scale_h | (scale_v << 16); | 1599 | cam->code = xlate->code; |
1600 | cam->ceu_rect = ceu_rect; | ||
1601 | icd->current_fmt = xlate; | ||
1494 | 1602 | ||
1495 | icd->buswidth = xlate->buswidth; | 1603 | pcdev->field = field; |
1496 | icd->current_fmt = xlate->host_fmt; | ||
1497 | cam->camera_fmt = xlate->cam_fmt; | ||
1498 | cam->ceu_rect = ceu_rect; | ||
1499 | |||
1500 | pcdev->is_interlaced = is_interlaced; | ||
1501 | pcdev->image_mode = image_mode; | 1604 | pcdev->image_mode = image_mode; |
1502 | 1605 | ||
1503 | return 0; | 1606 | return 0; |
@@ -1509,6 +1612,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1509 | const struct soc_camera_format_xlate *xlate; | 1612 | const struct soc_camera_format_xlate *xlate; |
1510 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1613 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1511 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1614 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1615 | struct v4l2_mbus_framefmt mf; | ||
1512 | __u32 pixfmt = pix->pixelformat; | 1616 | __u32 pixfmt = pix->pixelformat; |
1513 | int width, height; | 1617 | int width, height; |
1514 | int ret; | 1618 | int ret; |
@@ -1527,18 +1631,27 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1527 | width = pix->width; | 1631 | width = pix->width; |
1528 | height = pix->height; | 1632 | height = pix->height; |
1529 | 1633 | ||
1530 | pix->bytesperline = pix->width * | 1634 | pix->bytesperline = soc_mbus_bytes_per_line(width, xlate->host_fmt); |
1531 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); | 1635 | if (pix->bytesperline < 0) |
1532 | pix->sizeimage = pix->height * pix->bytesperline; | 1636 | return pix->bytesperline; |
1533 | 1637 | pix->sizeimage = height * pix->bytesperline; | |
1534 | pix->pixelformat = xlate->cam_fmt->fourcc; | ||
1535 | 1638 | ||
1536 | /* limit to sensor capabilities */ | 1639 | /* limit to sensor capabilities */ |
1537 | ret = v4l2_subdev_call(sd, video, try_fmt, f); | 1640 | mf.width = pix->width; |
1538 | pix->pixelformat = pixfmt; | 1641 | mf.height = pix->height; |
1642 | mf.field = pix->field; | ||
1643 | mf.code = xlate->code; | ||
1644 | mf.colorspace = pix->colorspace; | ||
1645 | |||
1646 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
1539 | if (ret < 0) | 1647 | if (ret < 0) |
1540 | return ret; | 1648 | return ret; |
1541 | 1649 | ||
1650 | pix->width = mf.width; | ||
1651 | pix->height = mf.height; | ||
1652 | pix->field = mf.field; | ||
1653 | pix->colorspace = mf.colorspace; | ||
1654 | |||
1542 | switch (pixfmt) { | 1655 | switch (pixfmt) { |
1543 | case V4L2_PIX_FMT_NV12: | 1656 | case V4L2_PIX_FMT_NV12: |
1544 | case V4L2_PIX_FMT_NV21: | 1657 | case V4L2_PIX_FMT_NV21: |
@@ -1547,21 +1660,25 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1547 | /* FIXME: check against rect_max after converting soc-camera */ | 1660 | /* FIXME: check against rect_max after converting soc-camera */ |
1548 | /* We can scale precisely, need a bigger image from camera */ | 1661 | /* We can scale precisely, need a bigger image from camera */ |
1549 | if (pix->width < width || pix->height < height) { | 1662 | if (pix->width < width || pix->height < height) { |
1550 | int tmp_w = pix->width, tmp_h = pix->height; | 1663 | /* |
1551 | pix->width = 2560; | 1664 | * We presume, the sensor behaves sanely, i.e., if |
1552 | pix->height = 1920; | 1665 | * requested a bigger rectangle, it will not return a |
1553 | ret = v4l2_subdev_call(sd, video, try_fmt, f); | 1666 | * smaller one. |
1667 | */ | ||
1668 | mf.width = 2560; | ||
1669 | mf.height = 1920; | ||
1670 | ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); | ||
1554 | if (ret < 0) { | 1671 | if (ret < 0) { |
1555 | /* Shouldn't actually happen... */ | 1672 | /* Shouldn't actually happen... */ |
1556 | dev_err(icd->dev.parent, | 1673 | dev_err(icd->dev.parent, |
1557 | "FIXME: try_fmt() returned %d\n", ret); | 1674 | "FIXME: client try_fmt() = %d\n", ret); |
1558 | pix->width = tmp_w; | 1675 | return ret; |
1559 | pix->height = tmp_h; | ||
1560 | } | 1676 | } |
1561 | } | 1677 | } |
1562 | if (pix->width > width) | 1678 | /* We will scale exactly */ |
1679 | if (mf.width > width) | ||
1563 | pix->width = width; | 1680 | pix->width = width; |
1564 | if (pix->height > height) | 1681 | if (mf.height > height) |
1565 | pix->height = height; | 1682 | pix->height = height; |
1566 | } | 1683 | } |
1567 | 1684 | ||
@@ -1573,10 +1690,12 @@ static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, | |||
1573 | { | 1690 | { |
1574 | int i; | 1691 | int i; |
1575 | 1692 | ||
1576 | /* This is for locking debugging only. I removed spinlocks and now I | 1693 | /* |
1694 | * This is for locking debugging only. I removed spinlocks and now I | ||
1577 | * check whether .prepare is ever called on a linked buffer, or whether | 1695 | * check whether .prepare is ever called on a linked buffer, or whether |
1578 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | 1696 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now |
1579 | * it hadn't triggered */ | 1697 | * it hadn't triggered |
1698 | */ | ||
1580 | for (i = 0; i < p->count; i++) { | 1699 | for (i = 0; i < p->count; i++) { |
1581 | struct sh_mobile_ceu_buffer *buf; | 1700 | struct sh_mobile_ceu_buffer *buf; |
1582 | 1701 | ||
@@ -1624,8 +1743,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, | |||
1624 | &sh_mobile_ceu_videobuf_ops, | 1743 | &sh_mobile_ceu_videobuf_ops, |
1625 | icd->dev.parent, &pcdev->lock, | 1744 | icd->dev.parent, &pcdev->lock, |
1626 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 1745 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
1627 | pcdev->is_interlaced ? | 1746 | pcdev->field, |
1628 | V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, | ||
1629 | sizeof(struct sh_mobile_ceu_buffer), | 1747 | sizeof(struct sh_mobile_ceu_buffer), |
1630 | icd); | 1748 | icd); |
1631 | } | 1749 | } |
@@ -1654,7 +1772,7 @@ static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, | |||
1654 | 1772 | ||
1655 | switch (ctrl->id) { | 1773 | switch (ctrl->id) { |
1656 | case V4L2_CID_SHARPNESS: | 1774 | case V4L2_CID_SHARPNESS: |
1657 | switch (icd->current_fmt->fourcc) { | 1775 | switch (icd->current_fmt->host_fmt->fourcc) { |
1658 | case V4L2_PIX_FMT_NV12: | 1776 | case V4L2_PIX_FMT_NV12: |
1659 | case V4L2_PIX_FMT_NV21: | 1777 | case V4L2_PIX_FMT_NV21: |
1660 | case V4L2_PIX_FMT_NV16: | 1778 | case V4L2_PIX_FMT_NV16: |
@@ -1836,7 +1954,7 @@ static struct platform_driver sh_mobile_ceu_driver = { | |||
1836 | .pm = &sh_mobile_ceu_dev_pm_ops, | 1954 | .pm = &sh_mobile_ceu_dev_pm_ops, |
1837 | }, | 1955 | }, |
1838 | .probe = sh_mobile_ceu_probe, | 1956 | .probe = sh_mobile_ceu_probe, |
1839 | .remove = __exit_p(sh_mobile_ceu_remove), | 1957 | .remove = __devexit_p(sh_mobile_ceu_remove), |
1840 | }; | 1958 | }; |
1841 | 1959 | ||
1842 | static int __init sh_mobile_ceu_init(void) | 1960 | static int __init sh_mobile_ceu_init(void) |