diff options
Diffstat (limited to 'drivers/media/video/mx2_camera.c')
-rw-r--r-- | drivers/media/video/mx2_camera.c | 78 |
1 files changed, 58 insertions, 20 deletions
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index 18afaeeadb7b..ded26b7286fa 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/gcd.h> | 22 | #include <linux/gcd.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/math64.h> | ||
25 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
26 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
27 | #include <linux/time.h> | 28 | #include <linux/time.h> |
@@ -344,6 +345,19 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { | |||
344 | PRP_INTR_CH2OVF, | 345 | PRP_INTR_CH2OVF, |
345 | } | 346 | } |
346 | }, | 347 | }, |
348 | { | ||
349 | .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8, | ||
350 | .out_fmt = V4L2_PIX_FMT_YUV420, | ||
351 | .cfg = { | ||
352 | .channel = 2, | ||
353 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
354 | .out_fmt = PRP_CNTL_CH2_OUT_YUV420, | ||
355 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
356 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | | ||
357 | PRP_INTR_CH2FC | PRP_INTR_LBOVF | | ||
358 | PRP_INTR_CH2OVF, | ||
359 | } | ||
360 | }, | ||
347 | }; | 361 | }; |
348 | 362 | ||
349 | static struct mx2_fmt_cfg *mx27_emma_prp_get_format( | 363 | static struct mx2_fmt_cfg *mx27_emma_prp_get_format( |
@@ -525,8 +539,6 @@ static int mx2_videobuf_setup(struct vb2_queue *vq, | |||
525 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | 539 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); |
526 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 540 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
527 | struct mx2_camera_dev *pcdev = ici->priv; | 541 | struct mx2_camera_dev *pcdev = ici->priv; |
528 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
529 | icd->current_fmt->host_fmt); | ||
530 | 542 | ||
531 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); | 543 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); |
532 | 544 | ||
@@ -534,12 +546,9 @@ static int mx2_videobuf_setup(struct vb2_queue *vq, | |||
534 | if (fmt != NULL) | 546 | if (fmt != NULL) |
535 | return -ENOTTY; | 547 | return -ENOTTY; |
536 | 548 | ||
537 | if (bytes_per_line < 0) | ||
538 | return bytes_per_line; | ||
539 | |||
540 | alloc_ctxs[0] = pcdev->alloc_ctx; | 549 | alloc_ctxs[0] = pcdev->alloc_ctx; |
541 | 550 | ||
542 | sizes[0] = bytes_per_line * icd->user_height; | 551 | sizes[0] = icd->sizeimage; |
543 | 552 | ||
544 | if (0 == *count) | 553 | if (0 == *count) |
545 | *count = 32; | 554 | *count = 32; |
@@ -555,16 +564,11 @@ static int mx2_videobuf_setup(struct vb2_queue *vq, | |||
555 | static int mx2_videobuf_prepare(struct vb2_buffer *vb) | 564 | static int mx2_videobuf_prepare(struct vb2_buffer *vb) |
556 | { | 565 | { |
557 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | 566 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); |
558 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
559 | icd->current_fmt->host_fmt); | ||
560 | int ret = 0; | 567 | int ret = 0; |
561 | 568 | ||
562 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | 569 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
563 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | 570 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
564 | 571 | ||
565 | if (bytes_per_line < 0) | ||
566 | return bytes_per_line; | ||
567 | |||
568 | #ifdef DEBUG | 572 | #ifdef DEBUG |
569 | /* | 573 | /* |
570 | * This can be useful if you want to see if we actually fill | 574 | * This can be useful if you want to see if we actually fill |
@@ -574,7 +578,7 @@ static int mx2_videobuf_prepare(struct vb2_buffer *vb) | |||
574 | 0xaa, vb2_get_plane_payload(vb, 0)); | 578 | 0xaa, vb2_get_plane_payload(vb, 0)); |
575 | #endif | 579 | #endif |
576 | 580 | ||
577 | vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height); | 581 | vb2_set_plane_payload(vb, 0, icd->sizeimage); |
578 | if (vb2_plane_vaddr(vb, 0) && | 582 | if (vb2_plane_vaddr(vb, 0) && |
579 | vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { | 583 | vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { |
580 | ret = -EINVAL; | 584 | ret = -EINVAL; |
@@ -980,6 +984,7 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | |||
980 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 984 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
981 | struct mx2_camera_dev *pcdev = ici->priv; | 985 | struct mx2_camera_dev *pcdev = ici->priv; |
982 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | 986 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
987 | const struct soc_camera_format_xlate *xlate; | ||
983 | unsigned long common_flags; | 988 | unsigned long common_flags; |
984 | int ret; | 989 | int ret; |
985 | int bytesperline; | 990 | int bytesperline; |
@@ -1024,14 +1029,31 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | |||
1024 | return ret; | 1029 | return ret; |
1025 | } | 1030 | } |
1026 | 1031 | ||
1032 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1033 | if (!xlate) { | ||
1034 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
1035 | return -EINVAL; | ||
1036 | } | ||
1037 | |||
1038 | if (xlate->code == V4L2_MBUS_FMT_YUYV8_2X8) { | ||
1039 | csicr1 |= CSICR1_PACK_DIR; | ||
1040 | csicr1 &= ~CSICR1_SWAP16_EN; | ||
1041 | dev_dbg(icd->parent, "already yuyv format, don't convert\n"); | ||
1042 | } else if (xlate->code == V4L2_MBUS_FMT_UYVY8_2X8) { | ||
1043 | csicr1 &= ~CSICR1_PACK_DIR; | ||
1044 | csicr1 |= CSICR1_SWAP16_EN; | ||
1045 | dev_dbg(icd->parent, "convert uyvy mbus format into yuyv\n"); | ||
1046 | } else { | ||
1047 | dev_warn(icd->parent, "mbus format not supported\n"); | ||
1048 | return -EINVAL; | ||
1049 | } | ||
1050 | |||
1027 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | 1051 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
1028 | csicr1 |= CSICR1_REDGE; | 1052 | csicr1 |= CSICR1_REDGE; |
1029 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) | 1053 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
1030 | csicr1 |= CSICR1_SOF_POL; | 1054 | csicr1 |= CSICR1_SOF_POL; |
1031 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) | 1055 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) |
1032 | csicr1 |= CSICR1_HSYNC_POL; | 1056 | csicr1 |= CSICR1_HSYNC_POL; |
1033 | if (pcdev->platform_flags & MX2_CAMERA_SWAP16) | ||
1034 | csicr1 |= CSICR1_SWAP16_EN; | ||
1035 | if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) | 1057 | if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) |
1036 | csicr1 |= CSICR1_EXT_VSYNC; | 1058 | csicr1 |= CSICR1_EXT_VSYNC; |
1037 | if (pcdev->platform_flags & MX2_CAMERA_CCIR) | 1059 | if (pcdev->platform_flags & MX2_CAMERA_CCIR) |
@@ -1042,8 +1064,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | |||
1042 | csicr1 |= CSICR1_GCLK_MODE; | 1064 | csicr1 |= CSICR1_GCLK_MODE; |
1043 | if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) | 1065 | if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) |
1044 | csicr1 |= CSICR1_INV_DATA; | 1066 | csicr1 |= CSICR1_INV_DATA; |
1045 | if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB) | ||
1046 | csicr1 |= CSICR1_PACK_DIR; | ||
1047 | 1067 | ||
1048 | pcdev->csicr1 = csicr1; | 1068 | pcdev->csicr1 = csicr1; |
1049 | 1069 | ||
@@ -1118,7 +1138,8 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, | |||
1118 | return 0; | 1138 | return 0; |
1119 | } | 1139 | } |
1120 | 1140 | ||
1121 | if (code == V4L2_MBUS_FMT_YUYV8_2X8) { | 1141 | if (code == V4L2_MBUS_FMT_YUYV8_2X8 || |
1142 | code == V4L2_MBUS_FMT_UYVY8_2X8) { | ||
1122 | formats++; | 1143 | formats++; |
1123 | if (xlate) { | 1144 | if (xlate) { |
1124 | /* | 1145 | /* |
@@ -1134,6 +1155,18 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, | |||
1134 | } | 1155 | } |
1135 | } | 1156 | } |
1136 | 1157 | ||
1158 | if (code == V4L2_MBUS_FMT_UYVY8_2X8) { | ||
1159 | formats++; | ||
1160 | if (xlate) { | ||
1161 | xlate->host_fmt = | ||
1162 | soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8); | ||
1163 | xlate->code = code; | ||
1164 | dev_dbg(dev, "Providing host format %s for sensor code %d\n", | ||
1165 | xlate->host_fmt->name, code); | ||
1166 | xlate++; | ||
1167 | } | ||
1168 | } | ||
1169 | |||
1137 | /* Generic pass-trough */ | 1170 | /* Generic pass-trough */ |
1138 | formats++; | 1171 | formats++; |
1139 | if (xlate) { | 1172 | if (xlate) { |
@@ -1363,17 +1396,20 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, | |||
1363 | xlate->host_fmt); | 1396 | xlate->host_fmt); |
1364 | if (pix->bytesperline < 0) | 1397 | if (pix->bytesperline < 0) |
1365 | return pix->bytesperline; | 1398 | return pix->bytesperline; |
1366 | pix->sizeimage = pix->height * pix->bytesperline; | 1399 | pix->sizeimage = soc_mbus_image_size(xlate->host_fmt, |
1400 | pix->bytesperline, pix->height); | ||
1367 | /* Check against the CSIRXCNT limit */ | 1401 | /* Check against the CSIRXCNT limit */ |
1368 | if (pix->sizeimage > 4 * 0x3ffff) { | 1402 | if (pix->sizeimage > 4 * 0x3ffff) { |
1369 | /* Adjust geometry, preserve aspect ratio */ | 1403 | /* Adjust geometry, preserve aspect ratio */ |
1370 | unsigned int new_height = int_sqrt(4 * 0x3ffff * | 1404 | unsigned int new_height = int_sqrt(div_u64(0x3ffffULL * |
1371 | pix->height / pix->bytesperline); | 1405 | 4 * pix->height, pix->bytesperline)); |
1372 | pix->width = new_height * pix->width / pix->height; | 1406 | pix->width = new_height * pix->width / pix->height; |
1373 | pix->height = new_height; | 1407 | pix->height = new_height; |
1374 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, | 1408 | pix->bytesperline = soc_mbus_bytes_per_line(pix->width, |
1375 | xlate->host_fmt); | 1409 | xlate->host_fmt); |
1376 | BUG_ON(pix->bytesperline < 0); | 1410 | BUG_ON(pix->bytesperline < 0); |
1411 | pix->sizeimage = soc_mbus_image_size(xlate->host_fmt, | ||
1412 | pix->bytesperline, pix->height); | ||
1377 | } | 1413 | } |
1378 | } | 1414 | } |
1379 | 1415 | ||
@@ -1752,6 +1788,8 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1752 | pcdev->soc_host.priv = pcdev; | 1788 | pcdev->soc_host.priv = pcdev; |
1753 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | 1789 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; |
1754 | pcdev->soc_host.nr = pdev->id; | 1790 | pcdev->soc_host.nr = pdev->id; |
1791 | if (cpu_is_mx25()) | ||
1792 | pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE; | ||
1755 | 1793 | ||
1756 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | 1794 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); |
1757 | if (IS_ERR(pcdev->alloc_ctx)) { | 1795 | if (IS_ERR(pcdev->alloc_ctx)) { |