aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-08-25 10:46:54 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:19:04 -0400
commit961801bbb3448a86f0cc93747cecbfae686d81d1 (patch)
tree29e7eb9f3779fb645473b9fb32a713bd5fc7fe74
parent4a5a5b2d620c3ec362936c4fe3799a29f8de163c (diff)
V4L/DVB (12528): sh_mobile_ceu_camera: implement host-side image scaling
Use host-side image scaling when the client fails to set the requested format. We also have to take scaling into account when performing host-side cropping. Similar to cropping we try to use client-side scaling as much as possible to preserve bus bandwidth and optimise the frame-rate. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c392
1 files changed, 321 insertions, 71 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 3fee7c01fd57..499d1a235fd7 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -95,6 +95,8 @@ struct sh_mobile_ceu_dev {
95 95
96 struct sh_mobile_ceu_info *pdata; 96 struct sh_mobile_ceu_info *pdata;
97 97
98 u32 cflcr;
99
98 unsigned int is_interlaced:1; 100 unsigned int is_interlaced:1;
99 unsigned int image_mode:1; 101 unsigned int image_mode:1;
100 unsigned int is_16bit:1; 102 unsigned int is_16bit:1;
@@ -102,6 +104,7 @@ struct sh_mobile_ceu_dev {
102 104
103struct sh_mobile_ceu_cam { 105struct sh_mobile_ceu_cam {
104 struct v4l2_rect camera_rect; 106 struct v4l2_rect camera_rect;
107 struct v4l2_rect camera_max;
105 const struct soc_camera_data_format *extra_fmt; 108 const struct soc_camera_data_format *extra_fmt;
106 const struct soc_camera_data_format *camera_fmt; 109 const struct soc_camera_data_format *camera_fmt;
107}; 110};
@@ -435,54 +438,119 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
435 pcdev->icd = NULL; 438 pcdev->icd = NULL;
436} 439}
437 440
441/*
442 * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)"
443 * in SH7722 Hardware Manual
444 */
445static unsigned int size_dst(unsigned int src, unsigned int scale)
446{
447 unsigned int mant_pre = scale >> 12;
448 if (!src || !scale)
449 return src;
450 return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) *
451 mant_pre * 4096 / scale + 1;
452}
453
454static unsigned int size_src(unsigned int dst, unsigned int scale)
455{
456 unsigned int mant_pre = scale >> 12, tmp;
457 if (!dst || !scale)
458 return dst;
459 for (tmp = ((dst - 1) * scale + 2048 * mant_pre) / 4096 + 1;
460 size_dst(tmp, scale) < dst;
461 tmp++)
462 ;
463 return tmp;
464}
465
466static u16 calc_scale(unsigned int src, unsigned int *dst)
467{
468 u16 scale;
469
470 if (src == *dst)
471 return 0;
472
473 scale = (src * 4096 / *dst) & ~7;
474
475 while (scale > 4096 && size_dst(src, scale) < *dst)
476 scale -= 8;
477
478 *dst = size_dst(src, scale);
479
480 return scale;
481}
482
483/* rect is guaranteed to not exceed the scaled camera rectangle */
438static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd, 484static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd,
439 struct v4l2_rect *rect) 485 struct v4l2_rect *rect)
440{ 486{
441 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 487 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
442 struct sh_mobile_ceu_cam *cam = icd->host_priv; 488 struct sh_mobile_ceu_cam *cam = icd->host_priv;
443 struct sh_mobile_ceu_dev *pcdev = ici->priv; 489 struct sh_mobile_ceu_dev *pcdev = ici->priv;
444 int width, height, cfszr_width, cdwdr_width; 490 int width, height, cfszr_width, cdwdr_width, in_width, in_height;
445 unsigned int left_offset, top_offset; 491 unsigned int left_offset, top_offset, left, top;
492 unsigned int hscale = pcdev->cflcr & 0xffff;
493 unsigned int vscale = (pcdev->cflcr >> 16) & 0xffff;
446 u32 camor; 494 u32 camor;
447 495
448 if (rect->left > cam->camera_rect.left) { 496 /* Switch to the camera scale */
449 left_offset = rect->left - cam->camera_rect.left; 497 left = size_src(rect->left, hscale);
498 top = size_src(rect->top, vscale);
499
500 dev_dbg(&icd->dev, "Left %u * 0x%x = %u, top %u * 0x%x = %u\n",
501 rect->left, hscale, left, rect->top, vscale, top);
502
503 if (left > cam->camera_rect.left) {
504 left_offset = left - cam->camera_rect.left;
450 } else { 505 } else {
451 left_offset = 0; 506 left_offset = 0;
452 rect->left = cam->camera_rect.left; 507 left = cam->camera_rect.left;
453 } 508 }
454 509
455 if (rect->top > cam->camera_rect.top) { 510 if (top > cam->camera_rect.top) {
456 top_offset = rect->top - cam->camera_rect.top; 511 top_offset = top - cam->camera_rect.top;
457 } else { 512 } else {
458 top_offset = 0; 513 top_offset = 0;
459 rect->top = cam->camera_rect.top; 514 top = cam->camera_rect.top;
460 } 515 }
461 516
462 dev_dbg(&icd->dev, "Offsets %u:%u\n", left_offset, top_offset); 517 dev_dbg(&icd->dev, "New left %u, top %u, offsets %u:%u\n",
518 rect->left, rect->top, left_offset, top_offset);
463 519
464 if (pcdev->image_mode) { 520 if (pcdev->image_mode) {
465 width = rect->width; 521 width = rect->width;
466 if (!pcdev->is_16bit) 522 in_width = cam->camera_rect.width;
523 if (!pcdev->is_16bit) {
467 width *= 2; 524 width *= 2;
525 in_width *= 2;
526 left_offset *= 2;
527 }
468 cfszr_width = cdwdr_width = rect->width; 528 cfszr_width = cdwdr_width = rect->width;
469 } else { 529 } else {
470 width = rect->width * 530 unsigned int w_factor = (icd->current_fmt->depth + 7) >> 3;
471 ((icd->current_fmt->depth + 7) >> 3); 531 if (!pcdev->is_16bit)
472 width = pcdev->is_16bit ? width / 2 : width; 532 w_factor *= 2;
533
534 width = rect->width * w_factor / 2;
535 in_width = cam->camera_rect.width * w_factor / 2;
536 left_offset = left_offset * w_factor / 2;
537
473 cfszr_width = pcdev->is_16bit ? width : width / 2; 538 cfszr_width = pcdev->is_16bit ? width : width / 2;
474 cdwdr_width = pcdev->is_16bit ? width * 2 : width; 539 cdwdr_width = pcdev->is_16bit ? width * 2 : width;
475 } 540 }
476 541
477 height = rect->height; 542 height = rect->height;
543 in_height = cam->camera_rect.height;
478 if (pcdev->is_interlaced) { 544 if (pcdev->is_interlaced) {
479 height /= 2; 545 height /= 2;
546 in_height /= 2;
547 top_offset /= 2;
480 cdwdr_width *= 2; 548 cdwdr_width *= 2;
481 } 549 }
482 550
483 camor = left_offset | (top_offset << 16); 551 camor = left_offset | (top_offset << 16);
484 ceu_write(pcdev, CAMOR, camor); 552 ceu_write(pcdev, CAMOR, camor);
485 ceu_write(pcdev, CAPWR, (height << 16) | width); 553 ceu_write(pcdev, CAPWR, (in_height << 16) | in_width);
486 ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width); 554 ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width);
487 ceu_write(pcdev, CDWDR, cdwdr_width); 555 ceu_write(pcdev, CDWDR, cdwdr_width);
488} 556}
@@ -556,7 +624,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
556 ceu_write(pcdev, CRCMPR, 0); 624 ceu_write(pcdev, CRCMPR, 0);
557 625
558 value = 0x00000010; /* data fetch by default */ 626 value = 0x00000010; /* data fetch by default */
559 pcdev->image_mode = yuv_lineskip = 0; 627 yuv_lineskip = 0;
560 628
561 switch (icd->current_fmt->fourcc) { 629 switch (icd->current_fmt->fourcc) {
562 case V4L2_PIX_FMT_NV12: 630 case V4L2_PIX_FMT_NV12:
@@ -565,7 +633,6 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
565 /* fall-through */ 633 /* fall-through */
566 case V4L2_PIX_FMT_NV16: 634 case V4L2_PIX_FMT_NV16:
567 case V4L2_PIX_FMT_NV61: 635 case V4L2_PIX_FMT_NV61:
568 pcdev->image_mode = 1;
569 switch (cam->camera_fmt->fourcc) { 636 switch (cam->camera_fmt->fourcc) {
570 case V4L2_PIX_FMT_UYVY: 637 case V4L2_PIX_FMT_UYVY:
571 value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ 638 value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
@@ -599,7 +666,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
599 mdelay(1); 666 mdelay(1);
600 sh_mobile_ceu_set_rect(icd, &icd->rect_current); 667 sh_mobile_ceu_set_rect(icd, &icd->rect_current);
601 668
602 ceu_write(pcdev, CFLCR, 0); /* no scaling */ 669 ceu_write(pcdev, CFLCR, pcdev->cflcr);
603 670
604 /* A few words about byte order (observed in Big Endian mode) 671 /* A few words about byte order (observed in Big Endian mode)
605 * 672 *
@@ -620,7 +687,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
620 ceu_write(pcdev, CDOCR, value); 687 ceu_write(pcdev, CDOCR, value);
621 ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ 688 ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
622 689
623 dev_dbg(&icd->dev, "S_FMT successful for %c%c%c%c %ux%u@%u.%u\n", 690 dev_dbg(&icd->dev, "S_FMT successful for %c%c%c%c %ux%u@%u:%u\n",
624 pixfmt & 0xff, (pixfmt >> 8) & 0xff, 691 pixfmt & 0xff, (pixfmt >> 8) & 0xff,
625 (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff, 692 (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
626 icd->rect_current.width, icd->rect_current.height, 693 icd->rect_current.width, icd->rect_current.height,
@@ -692,6 +759,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
692 return -ENOMEM; 759 return -ENOMEM;
693 760
694 icd->host_priv = cam; 761 icd->host_priv = cam;
762 cam->camera_max = icd->rect_max;
695 } else { 763 } else {
696 cam = icd->host_priv; 764 cam = icd->host_priv;
697 } 765 }
@@ -754,86 +822,150 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
754 icd->host_priv = NULL; 822 icd->host_priv = NULL;
755} 823}
756 824
825/* Check if any dimension of r1 is smaller than respective one of r2 */
757static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2) 826static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2)
758{ 827{
759 return r1->width < r2->width || r1->height < r2->height; 828 return r1->width < r2->width || r1->height < r2->height;
760} 829}
761 830
831/* Check if r1 fails to cover r2 */
832static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2)
833{
834 return r1->left > r2->left || r1->top > r2->top ||
835 r1->left + r1->width < r2->left + r2->width ||
836 r1->top + r1->height < r2->top + r2->height;
837}
838
839/*
840 * CEU can scale and crop, but we don't want to waste bandwidth and kill the
841 * framerate by always requesting the maximum image from the client. For
842 * cropping we also have to take care of the current scale. The common for both
843 * scaling and cropping approach is:
844 * 1. try if the client can produce exactly what requested by the user
845 * 2. if (1) failed, try to double the client image until we get one big enough
846 * 3. if (2) failed, try to request the maximum image
847 */
762static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, 848static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
763 struct v4l2_rect *rect) 849 struct v4l2_rect *rect)
764{ 850{
765 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 851 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
766 struct sh_mobile_ceu_dev *pcdev = ici->priv; 852 struct sh_mobile_ceu_dev *pcdev = ici->priv;
767 struct v4l2_rect cam_rect = *rect; 853 struct v4l2_rect cam_rect, target, cam_max;
768 struct sh_mobile_ceu_cam *cam = icd->host_priv; 854 struct sh_mobile_ceu_cam *cam = icd->host_priv;
855 unsigned int hscale = pcdev->cflcr & 0xffff;
856 unsigned int vscale = (pcdev->cflcr >> 16) & 0xffff;
769 unsigned short width, height; 857 unsigned short width, height;
770 u32 capsr; 858 u32 capsr;
771 int ret; 859 int ret;
772 860
861 /* Scale back up into client units */
862 cam_rect.left = size_src(rect->left, hscale);
863 cam_rect.width = size_src(rect->width, hscale);
864 cam_rect.top = size_src(rect->top, vscale);
865 cam_rect.height = size_src(rect->height, vscale);
866
867 target = cam_rect;
868
773 capsr = capture_save_reset(pcdev); 869 capsr = capture_save_reset(pcdev);
774 dev_dbg(&icd->dev, "CAPSR %x\n", capsr); 870 dev_dbg(&icd->dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr);
775 871
872 /* First attempt - see if the client can deliver a perfect result */
776 ret = icd->ops->set_crop(icd, &cam_rect); 873 ret = icd->ops->set_crop(icd, &cam_rect);
777 if (!ret && !memcmp(rect, &cam_rect, sizeof(*rect))) { 874 if (!ret && !memcmp(&target, &cam_rect, sizeof(target))) {
778 dev_dbg(&icd->dev, "Camera S_CROP successful for %ux%u@%u.%u\n", 875 dev_dbg(&icd->dev, "Camera S_CROP successful for %ux%u@%u:%u\n",
779 cam_rect.width, cam_rect.height, 876 cam_rect.width, cam_rect.height,
780 cam_rect.left, cam_rect.top); 877 cam_rect.left, cam_rect.top);
781 goto ceu_set_rect; 878 goto ceu_set_rect;
782 } 879 }
783 880
784 /* Try to fix cropping, that camera hasn't managed to do */ 881 /* Try to fix cropping, that camera hasn't managed to do */
785 dev_dbg(&icd->dev, "Fix camera S_CROP %d for %ux%u@%u.%u\n", 882 dev_dbg(&icd->dev, "Fix camera S_CROP %d for %ux%u@%u:%u"
883 " to %ux%u@%u:%u\n",
786 ret, cam_rect.width, cam_rect.height, 884 ret, cam_rect.width, cam_rect.height,
787 cam_rect.left, cam_rect.top); 885 cam_rect.left, cam_rect.top,
886 target.width, target.height, target.left, target.top);
788 887
789 /* 888 /*
790 * Popular special case - some cameras can only handle fixed sizes like 889 * Popular special case - some cameras can only handle fixed sizes like
791 * QVGA, VGA,... Take care to avoid infinite loop. 890 * QVGA, VGA,... Take care to avoid infinite loop.
792 */ 891 */
793 width = max(cam_rect.width, 1) * 2; 892 width = max(cam_rect.width, 1);
794 height = max(cam_rect.height, 1) * 2; 893 height = max(cam_rect.height, 1);
795 while (!ret && is_smaller(&cam_rect, rect) && 894 cam_max.width = size_src(icd->rect_max.width, hscale);
796 (icd->rect_max.width >= width && 895 cam_max.left = size_src(icd->rect_max.left, hscale);
797 icd->rect_max.height >= height)) { 896 cam_max.height = size_src(icd->rect_max.height, vscale);
897 cam_max.top = size_src(icd->rect_max.top, vscale);
898 while (!ret && (is_smaller(&cam_rect, &target) ||
899 is_inside(&cam_rect, &target)) &&
900 cam_max.width >= width && cam_max.height >= height) {
901
902 width *= 2;
903 height *= 2;
798 cam_rect.width = width; 904 cam_rect.width = width;
799 cam_rect.height = height; 905 cam_rect.height = height;
800 906
907 /* We do not know what the camera is capable of, play safe */
908 if (cam_rect.left > target.left)
909 cam_rect.left = cam_max.left;
910
911 if (cam_rect.left + cam_rect.width < target.left + target.width)
912 cam_rect.width = target.left + target.width -
913 cam_rect.left;
914
915 if (cam_rect.top > target.top)
916 cam_rect.top = cam_max.top;
917
918 if (cam_rect.top + cam_rect.height < target.top + target.height)
919 cam_rect.height = target.top + target.height -
920 cam_rect.top;
921
801 if (cam_rect.width + cam_rect.left > 922 if (cam_rect.width + cam_rect.left >
802 icd->rect_max.width + icd->rect_max.left) 923 cam_max.width + cam_max.left)
803 cam_rect.left = icd->rect_max.width + 924 cam_rect.left = max(cam_max.width + cam_max.left -
804 icd->rect_max.left - cam_rect.width; 925 cam_rect.width, cam_max.left);
805 926
806 if (cam_rect.height + cam_rect.top > 927 if (cam_rect.height + cam_rect.top >
807 icd->rect_max.height + icd->rect_max.top) 928 cam_max.height + cam_max.top)
808 cam_rect.top = icd->rect_max.height + 929 cam_rect.top = max(cam_max.height + cam_max.top -
809 icd->rect_max.top - cam_rect.height; 930 cam_rect.height, cam_max.top);
810 931
811 ret = icd->ops->set_crop(icd, &cam_rect); 932 ret = icd->ops->set_crop(icd, &cam_rect);
812 dev_dbg(&icd->dev, "Camera S_CROP %d for %ux%u@%u.%u\n", 933 dev_dbg(&icd->dev, "Camera S_CROP %d for %ux%u@%u:%u\n",
813 ret, cam_rect.width, cam_rect.height, 934 ret, cam_rect.width, cam_rect.height,
814 cam_rect.left, cam_rect.top); 935 cam_rect.left, cam_rect.top);
815 width *= 2;
816 height *= 2;
817 } 936 }
818 937
819 /* 938 /*
820 * If the camera failed to configure cropping, it should not modify the 939 * If the camera failed to configure cropping, it should not modify the
821 * rectangle 940 * rectangle
822 */ 941 */
823 if ((ret < 0 && is_smaller(&icd->rect_current, rect)) || 942 if ((ret < 0 && (is_smaller(&icd->rect_current, rect) ||
824 is_smaller(&cam_rect, rect)) { 943 is_inside(&icd->rect_current, rect))) ||
944 is_smaller(&cam_rect, &target) || is_inside(&cam_rect, &target)) {
825 /* 945 /*
826 * The camera failed to configure a suitable cropping, 946 * The camera failed to configure a suitable cropping,
827 * we cannot use the current rectangle, set to max 947 * we cannot use the current rectangle, set to max
828 */ 948 */
829 cam_rect = icd->rect_max; 949 cam_rect = cam_max;
830 ret = icd->ops->set_crop(icd, &cam_rect); 950 ret = icd->ops->set_crop(icd, &cam_rect);
831 dev_dbg(&icd->dev, "Camera S_CROP %d for max %ux%u@%u.%u\n", 951 dev_dbg(&icd->dev, "Camera S_CROP %d for max %ux%u@%u:%u\n",
832 ret, cam_rect.width, cam_rect.height, 952 ret, cam_rect.width, cam_rect.height,
833 cam_rect.left, cam_rect.top); 953 cam_rect.left, cam_rect.top);
834 if (ret < 0) 954 if (ret < 0)
835 /* All failed, hopefully resume current capture */ 955 /* All failed, hopefully resume current capture */
836 goto resume_capture; 956 goto resume_capture;
957
958 /* Finally, adjust the target rectangle */
959 if (target.width > cam_rect.width)
960 target.width = cam_rect.width;
961 if (target.height > cam_rect.height)
962 target.height = cam_rect.height;
963 if (target.left + target.width > cam_rect.left + cam_rect.width)
964 target.left = cam_rect.left + cam_rect.width -
965 target.width;
966 if (target.top + target.height > cam_rect.top + cam_rect.height)
967 target.top = cam_rect.top + cam_rect.height -
968 target.height;
837 } 969 }
838 970
839 /* We now have a rectangle, larger than requested, let's crop */ 971 /* We now have a rectangle, larger than requested, let's crop */
@@ -844,8 +976,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
844 * last before last close() _user_ rectangle, which can be different 976 * last before last close() _user_ rectangle, which can be different
845 * from camera rectangle. 977 * from camera rectangle.
846 */ 978 */
847 dev_dbg(&icd->dev, "SH S_CROP from %ux%u@%u.%u to %ux%u@%u.%u\n", 979 dev_dbg(&icd->dev,
980 "SH S_CROP from %ux%u@%u:%u to %ux%u@%u:%u, scale to %ux%u@%u:%u\n",
848 cam_rect.width, cam_rect.height, cam_rect.left, cam_rect.top, 981 cam_rect.width, cam_rect.height, cam_rect.left, cam_rect.top,
982 target.width, target.height, target.left, target.top,
849 rect->width, rect->height, rect->left, rect->top); 983 rect->width, rect->height, rect->left, rect->top);
850 984
851 ret = 0; 985 ret = 0;
@@ -853,27 +987,49 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
853ceu_set_rect: 987ceu_set_rect:
854 cam->camera_rect = cam_rect; 988 cam->camera_rect = cam_rect;
855 989
990 rect->width = size_dst(target.width, hscale);
991 rect->left = size_dst(target.left, hscale);
992 rect->height = size_dst(target.height, vscale);
993 rect->top = size_dst(target.top, vscale);
994
995 sh_mobile_ceu_set_rect(icd, rect);
996
997resume_capture:
856 /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ 998 /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
857 if (pcdev->active) 999 if (pcdev->active)
858 capsr |= 1; 1000 capsr |= 1;
859 sh_mobile_ceu_set_rect(icd, rect);
860 capture_restore(pcdev, capsr); 1001 capture_restore(pcdev, capsr);
861 1002
862resume_capture:
863
864 /* Even if only camera cropping succeeded */ 1003 /* Even if only camera cropping succeeded */
865 return ret; 1004 return ret;
866} 1005}
867 1006
1007/* Similar to set_crop multistage iterative algorithm */
868static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, 1008static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
869 struct v4l2_format *f) 1009 struct v4l2_format *f)
870{ 1010{
871 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 1011 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1012 struct sh_mobile_ceu_dev *pcdev = ici->priv;
872 struct sh_mobile_ceu_cam *cam = icd->host_priv; 1013 struct sh_mobile_ceu_cam *cam = icd->host_priv;
873 struct v4l2_pix_format *pix = &f->fmt.pix; 1014 struct v4l2_pix_format *pix = &f->fmt.pix;
874 __u32 pixfmt = pix->pixelformat; 1015 __u32 pixfmt = pix->pixelformat;
875 const struct soc_camera_format_xlate *xlate; 1016 const struct soc_camera_format_xlate *xlate;
876 int ret; 1017 unsigned int width = pix->width, height = pix->height, tmp_w, tmp_h;
1018 u16 vscale, hscale;
1019 int ret, is_interlaced;
1020
1021 switch (pix->field) {
1022 case V4L2_FIELD_INTERLACED:
1023 is_interlaced = 1;
1024 break;
1025 case V4L2_FIELD_ANY:
1026 default:
1027 pix->field = V4L2_FIELD_NONE;
1028 /* fall-through */
1029 case V4L2_FIELD_NONE:
1030 is_interlaced = 0;
1031 break;
1032 }
877 1033
878 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); 1034 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
879 if (!xlate) { 1035 if (!xlate) {
@@ -884,27 +1040,104 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
884 pix->pixelformat = xlate->cam_fmt->fourcc; 1040 pix->pixelformat = xlate->cam_fmt->fourcc;
885 ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, s_fmt, f); 1041 ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, s_fmt, f);
886 pix->pixelformat = pixfmt; 1042 pix->pixelformat = pixfmt;
887 if (!ret) { 1043 dev_dbg(&icd->dev, "Camera %d fmt %ux%u, requested %ux%u, max %ux%u\n",
888 icd->buswidth = xlate->buswidth; 1044 ret, pix->width, pix->height, width, height,
889 icd->current_fmt = xlate->host_fmt; 1045 icd->rect_max.width, icd->rect_max.height);
890 cam->camera_fmt = xlate->cam_fmt; 1046 if (ret < 0)
891 cam->camera_rect.width = pix->width; 1047 return ret;
892 cam->camera_rect.height = pix->height; 1048
893 cam->camera_rect.left = icd->rect_current.left; 1049 switch (pixfmt) {
894 cam->camera_rect.top = icd->rect_current.top; 1050 case V4L2_PIX_FMT_NV12:
1051 case V4L2_PIX_FMT_NV21:
1052 case V4L2_PIX_FMT_NV16:
1053 case V4L2_PIX_FMT_NV61:
1054 pcdev->image_mode = 1;
1055 break;
1056 default:
1057 pcdev->image_mode = 0;
895 } 1058 }
896 1059
897 return ret; 1060 if ((abs(width - pix->width) < 4 && abs(height - pix->height) < 4) ||
1061 !pcdev->image_mode || is_interlaced) {
1062 hscale = 0;
1063 vscale = 0;
1064 goto out;
1065 }
1066
1067 /* Camera set a format, but geometry is not precise, try to improve */
1068 /*
1069 * FIXME: when soc-camera is converted to implement traditional S_FMT
1070 * and S_CROP semantics, replace CEU limits with camera maxima
1071 */
1072 tmp_w = pix->width;
1073 tmp_h = pix->height;
1074 while ((width > tmp_w || height > tmp_h) &&
1075 tmp_w < 2560 && tmp_h < 1920) {
1076 tmp_w = min(2 * tmp_w, (__u32)2560);
1077 tmp_h = min(2 * tmp_h, (__u32)1920);
1078 pix->width = tmp_w;
1079 pix->height = tmp_h;
1080 pix->pixelformat = xlate->cam_fmt->fourcc;
1081 ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd,
1082 video, s_fmt, f);
1083 pix->pixelformat = pixfmt;
1084 dev_dbg(&icd->dev, "Camera scaled to %ux%u\n",
1085 pix->width, pix->height);
1086 if (ret < 0) {
1087 /* This shouldn't happen */
1088 dev_err(&icd->dev, "Client failed to set format: %d\n",
1089 ret);
1090 return ret;
1091 }
1092 }
1093
1094 /* We cannot scale up */
1095 if (width > pix->width)
1096 width = pix->width;
1097
1098 if (height > pix->height)
1099 height = pix->height;
1100
1101 /* Let's rock: scale pix->{width x height} down to width x height */
1102 hscale = calc_scale(pix->width, &width);
1103 vscale = calc_scale(pix->height, &height);
1104
1105 dev_dbg(&icd->dev, "W: %u : 0x%x = %u, H: %u : 0x%x = %u\n",
1106 pix->width, hscale, width, pix->height, vscale, height);
1107
1108out:
1109 pcdev->cflcr = hscale | (vscale << 16);
1110
1111 icd->buswidth = xlate->buswidth;
1112 icd->current_fmt = xlate->host_fmt;
1113 cam->camera_fmt = xlate->cam_fmt;
1114 cam->camera_rect.width = pix->width;
1115 cam->camera_rect.height = pix->height;
1116
1117 icd->rect_max.left = size_dst(cam->camera_max.left, hscale);
1118 icd->rect_max.width = size_dst(cam->camera_max.width, hscale);
1119 icd->rect_max.top = size_dst(cam->camera_max.top, vscale);
1120 icd->rect_max.height = size_dst(cam->camera_max.height, vscale);
1121
1122 icd->rect_current.left = icd->rect_max.left;
1123 icd->rect_current.top = icd->rect_max.top;
1124
1125 pcdev->is_interlaced = is_interlaced;
1126
1127 pix->width = width;
1128 pix->height = height;
1129
1130 return 0;
898} 1131}
899 1132
900static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, 1133static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
901 struct v4l2_format *f) 1134 struct v4l2_format *f)
902{ 1135{
903 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 1136 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
904 struct sh_mobile_ceu_dev *pcdev = ici->priv;
905 const struct soc_camera_format_xlate *xlate; 1137 const struct soc_camera_format_xlate *xlate;
906 struct v4l2_pix_format *pix = &f->fmt.pix; 1138 struct v4l2_pix_format *pix = &f->fmt.pix;
907 __u32 pixfmt = pix->pixelformat; 1139 __u32 pixfmt = pix->pixelformat;
1140 int width, height;
908 int ret; 1141 int ret;
909 1142
910 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); 1143 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
@@ -918,6 +1151,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
918 v4l_bound_align_image(&pix->width, 2, 2560, 1, 1151 v4l_bound_align_image(&pix->width, 2, 2560, 1,
919 &pix->height, 4, 1920, 2, 0); 1152 &pix->height, 4, 1920, 2, 0);
920 1153
1154 width = pix->width;
1155 height = pix->height;
1156
921 pix->bytesperline = pix->width * 1157 pix->bytesperline = pix->width *
922 DIV_ROUND_UP(xlate->host_fmt->depth, 8); 1158 DIV_ROUND_UP(xlate->host_fmt->depth, 8);
923 pix->sizeimage = pix->height * pix->bytesperline; 1159 pix->sizeimage = pix->height * pix->bytesperline;
@@ -925,24 +1161,38 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
925 pix->pixelformat = xlate->cam_fmt->fourcc; 1161 pix->pixelformat = xlate->cam_fmt->fourcc;
926 1162
927 /* limit to sensor capabilities */ 1163 /* limit to sensor capabilities */
928 ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, try_fmt, f); 1164 ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video,
1165 try_fmt, f);
929 pix->pixelformat = pixfmt; 1166 pix->pixelformat = pixfmt;
930 if (ret < 0) 1167 if (ret < 0)
931 return ret; 1168 return ret;
932 1169
933 switch (pix->field) { 1170 switch (pixfmt) {
934 case V4L2_FIELD_INTERLACED: 1171 case V4L2_PIX_FMT_NV12:
935 pcdev->is_interlaced = 1; 1172 case V4L2_PIX_FMT_NV21:
936 break; 1173 case V4L2_PIX_FMT_NV16:
937 case V4L2_FIELD_ANY: 1174 case V4L2_PIX_FMT_NV61:
938 pix->field = V4L2_FIELD_NONE; 1175 /* FIXME: check against rect_max after converting soc-camera */
939 /* fall-through */ 1176 /* We can scale precisely, need a bigger image from camera */
940 case V4L2_FIELD_NONE: 1177 if (pix->width < width || pix->height < height) {
941 pcdev->is_interlaced = 0; 1178 int tmp_w = pix->width, tmp_h = pix->height;
942 break; 1179 pix->width = 2560;
943 default: 1180 pix->height = 1920;
944 ret = -EINVAL; 1181 ret = v4l2_device_call_until_err(&ici->v4l2_dev,
945 break; 1182 (__u32)icd, video,
1183 try_fmt, f);
1184 if (ret < 0) {
1185 /* Shouldn't actually happen... */
1186 dev_err(&icd->dev,
1187 "FIXME: try_fmt() returned %d\n", ret);
1188 pix->width = tmp_w;
1189 pix->height = tmp_h;
1190 }
1191 }
1192 if (pix->width > width)
1193 pix->width = width;
1194 if (pix->height > height)
1195 pix->height = height;
946 } 1196 }
947 1197
948 return ret; 1198 return ret;