media: vim2m: use different framesizes for bayer formats
authorMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Thu, 28 Feb 2019 06:25:50 +0000 (01:25 -0500)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Fri, 1 Mar 2019 16:06:49 +0000 (11:06 -0500)
The only real restriction at vim2m is that width should be
multiple of two, as the copy routine always copy two pixels
each time.

However, Bayer formats are defined as having a 2x2 matrix.
So, odd vertical numbers would cause color distortions at the
last line. So, it makes sense to use step 2 for vertical alignment
on Bayer.

With this patch, the reported formats for video capture will
be:

[0]: 'RGBP' (16-bit RGB 5-6-5)
Size: Stepwise 32x32 - 640x480 with step 2/1
[1]: 'RGBR' (16-bit RGB 5-6-5 BE)
Size: Stepwise 32x32 - 640x480 with step 2/1
[2]: 'RGB3' (24-bit RGB 8-8-8)
Size: Stepwise 32x32 - 640x480 with step 2/1
[3]: 'BGR3' (24-bit BGR 8-8-8)
Size: Stepwise 32x32 - 640x480 with step 2/1
[4]: 'YUYV' (YUYV 4:2:2)
Size: Stepwise 32x32 - 640x480 with step 2/1
[5]: 'BA81' (8-bit Bayer BGBG/GRGR)
Size: Stepwise 32x32 - 640x480 with step 2/2
[6]: 'GBRG' (8-bit Bayer GBGB/RGRG)
Size: Stepwise 32x32 - 640x480 with step 2/2
[7]: 'GRBG' (8-bit Bayer GRGR/BGBG)
Size: Stepwise 32x32 - 640x480 with step 2/2
[8]: 'RGGB' (8-bit Bayer RGRG/GBGB)
Size: Stepwise 32x32 - 640x480 with step 2/2

Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/platform/vim2m.c

index 620f064..12f0f3e 100644 (file)
@@ -50,7 +50,14 @@ MODULE_PARM_DESC(default_transtime, "default transaction time in ms");
 #define MIN_H 32
 #define MAX_W 640
 #define MAX_H 480
-#define WIDTH_ALIGN 2 /* 2-byte alignment */
+
+/* Pixel alignment for non-bayer formats */
+#define WIDTH_ALIGN 2
+#define HEIGHT_ALIGN 1
+
+/* Pixel alignment for bayer formats */
+#define BAYER_WIDTH_ALIGN  2
+#define BAYER_HEIGHT_ALIGN 2
 
 /* Flags that indicate a format can be used for capture/output */
 #define MEM2MEM_CAPTURE        (1 << 0)
@@ -162,6 +169,24 @@ static struct vim2m_fmt *find_format(u32 fourcc)
        return &formats[k];
 }
 
+static void get_alignment(u32 fourcc,
+                         unsigned int *walign, unsigned int *halign)
+{
+       switch (fourcc) {
+       case V4L2_PIX_FMT_SBGGR8:
+       case V4L2_PIX_FMT_SGBRG8:
+       case V4L2_PIX_FMT_SGRBG8:
+       case V4L2_PIX_FMT_SRGGB8:
+               *walign = BAYER_WIDTH_ALIGN;
+               *halign = BAYER_HEIGHT_ALIGN;
+               return;
+       default:
+               *walign = WIDTH_ALIGN;
+               *halign = HEIGHT_ALIGN;
+               return;
+       }
+}
+
 struct vim2m_dev {
        struct v4l2_device      v4l2_dev;
        struct video_device     vfd;
@@ -691,8 +716,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
        fsize->stepwise.min_height = MIN_H;
        fsize->stepwise.max_width = MAX_W;
        fsize->stepwise.max_height = MAX_H;
-       fsize->stepwise.step_width = WIDTH_ALIGN;
-       fsize->stepwise.step_height = 1;
+
+       get_alignment(fsize->pixel_format,
+                     &fsize->stepwise.step_width,
+                     &fsize->stepwise.step_height);
        return 0;
 }
 
@@ -735,6 +762,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
 static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt)
 {
+       int walign, halign;
        /* V4L2 specification suggests the driver corrects the format struct
         * if any of the dimensions is unsupported */
        if (f->fmt.pix.height < MIN_H)
@@ -747,7 +775,9 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt)
        else if (f->fmt.pix.width > MAX_W)
                f->fmt.pix.width = MAX_W;
 
-       f->fmt.pix.width &= ~(WIDTH_ALIGN - 1);
+       get_alignment(f->fmt.pix.pixelformat, &walign, &halign);
+       f->fmt.pix.width &= ~(walign - 1);
+       f->fmt.pix.height &= ~(halign - 1);
        f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
        f->fmt.pix.field = V4L2_FIELD_NONE;