diff options
Diffstat (limited to 'drivers/media/video/mx2_camera.c')
-rw-r--r-- | drivers/media/video/mx2_camera.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index 18afaeeadb7b..637bde8aca28 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -22,6 +22,7 @@ #include <linux/gcd.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/math64.h> #include <linux/mm.h> #include <linux/moduleparam.h> #include <linux/time.h> @@ -82,6 +83,7 @@ #define CSICR1_INV_DATA (1 << 3) #define CSICR1_INV_PCLK (1 << 2) #define CSICR1_REDGE (1 << 1) +#define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN) #define SHIFT_STATFF_LEVEL 22 #define SHIFT_RXFF_LEVEL 19 @@ -229,6 +231,7 @@ struct mx2_prp_cfg { u32 src_pixel; u32 ch1_pixel; u32 irq_flags; + u32 csicr1; }; /* prp resizing parameters */ @@ -329,6 +332,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { .ch1_pixel = 0x2ca00565, /* RGB565 */ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | PRP_INTR_CH1FC | PRP_INTR_LBOVF, + .csicr1 = 0, } }, { @@ -342,6 +346,21 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | PRP_INTR_CH2FC | PRP_INTR_LBOVF | PRP_INTR_CH2OVF, + .csicr1 = CSICR1_PACK_DIR, + } + }, + { + .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8, + .out_fmt = V4L2_PIX_FMT_YUV420, + .cfg = { + .channel = 2, + .in_fmt = PRP_CNTL_DATA_IN_YUV422, + .out_fmt = PRP_CNTL_CH2_OUT_YUV420, + .src_pixel = 0x22000888, /* YUV422 (YUYV) */ + .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | + PRP_INTR_CH2FC | PRP_INTR_LBOVF | + PRP_INTR_CH2OVF, + .csicr1 = CSICR1_SWAP16_EN, } }, }; @@ -525,8 +544,6 @@ static int mx2_videobuf_setup(struct vb2_queue *vq, struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); @@ -534,12 +551,9 @@ static int mx2_videobuf_setup(struct vb2_queue *vq, if (fmt != NULL) return -ENOTTY; - if (bytes_per_line < 0) - return bytes_per_line; - alloc_ctxs[0] = pcdev->alloc_ctx; - sizes[0] = bytes_per_line * icd->user_height; + sizes[0] = icd->sizeimage; if (0 == *count) *count = 32; @@ -555,16 +569,11 @@ static int mx2_videobuf_setup(struct vb2_queue *vq, static int mx2_videobuf_prepare(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); int ret = 0; dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - if (bytes_per_line < 0) - return bytes_per_line; - #ifdef DEBUG /* * This can be useful if you want to see if we actually fill @@ -574,7 +583,7 @@ static int mx2_videobuf_prepare(struct vb2_buffer *vb) 0xaa, vb2_get_plane_payload(vb, 0)); #endif - vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height); + vb2_set_plane_payload(vb, 0, icd->sizeimage); if (vb2_plane_vaddr(vb, 0) && vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { ret = -EINVAL; @@ -1024,14 +1033,14 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) return ret; } + csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1; + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) csicr1 |= CSICR1_REDGE; if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_SOF_POL; if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_HSYNC_POL; - if (pcdev->platform_flags & MX2_CAMERA_SWAP16) - csicr1 |= CSICR1_SWAP16_EN; if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) csicr1 |= CSICR1_EXT_VSYNC; if (pcdev->platform_flags & MX2_CAMERA_CCIR) @@ -1042,8 +1051,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) csicr1 |= CSICR1_GCLK_MODE; if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) csicr1 |= CSICR1_INV_DATA; - if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB) - csicr1 |= CSICR1_PACK_DIR; pcdev->csicr1 = csicr1; @@ -1118,7 +1125,8 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, return 0; } - if (code == V4L2_MBUS_FMT_YUYV8_2X8) { + if (code == V4L2_MBUS_FMT_YUYV8_2X8 || + code == V4L2_MBUS_FMT_UYVY8_2X8) { formats++; if (xlate) { /* @@ -1363,17 +1371,20 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, xlate->host_fmt); if (pix->bytesperline < 0) return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; + pix->sizeimage = soc_mbus_image_size(xlate->host_fmt, + pix->bytesperline, pix->height); /* Check against the CSIRXCNT limit */ if (pix->sizeimage > 4 * 0x3ffff) { /* Adjust geometry, preserve aspect ratio */ - unsigned int new_height = int_sqrt(4 * 0x3ffff * - pix->height / pix->bytesperline); + unsigned int new_height = int_sqrt(div_u64(0x3ffffULL * + 4 * pix->height, pix->bytesperline)); pix->width = new_height * pix->width / pix->height; pix->height = new_height; pix->bytesperline = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt); BUG_ON(pix->bytesperline < 0); + pix->sizeimage = soc_mbus_image_size(xlate->host_fmt, + pix->bytesperline, pix->height); } } @@ -1752,6 +1763,8 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) pcdev->soc_host.priv = pcdev; pcdev->soc_host.v4l2_dev.dev = &pdev->dev; pcdev->soc_host.nr = pdev->id; + if (cpu_is_mx25()) + pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE; pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); if (IS_ERR(pcdev->alloc_ctx)) { |