V4L/DVB (9791): pxa-camera: pixel format negotiation

Use the new format-negotiation infrastructure, support all four YUV422
packed and the planar formats.

The new translation structure enables to build the format
list with buswidth, depth, host format and camera format
checked, so that it's not done anymore on try_fmt nor
set_fmt.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Robert Jarzmik 2008-12-01 09:45:35 -03:00 committed by Mauro Carvalho Chehab
parent c2786ad271
commit 2a48fc739d

View File

@ -765,6 +765,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
return -EINVAL; return -EINVAL;
*flags |= SOCAM_DATAWIDTH_8; *flags |= SOCAM_DATAWIDTH_8;
break;
default:
return -EINVAL;
} }
return 0; return 0;
@ -823,12 +826,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
* We fix bit-per-pixel equal to data-width... */ * We fix bit-per-pixel equal to data-width... */
switch (common_flags & SOCAM_DATAWIDTH_MASK) { switch (common_flags & SOCAM_DATAWIDTH_MASK) {
case SOCAM_DATAWIDTH_10: case SOCAM_DATAWIDTH_10:
icd->buswidth = 10;
dw = 4; dw = 4;
bpp = 0x40; bpp = 0x40;
break; break;
case SOCAM_DATAWIDTH_9: case SOCAM_DATAWIDTH_9:
icd->buswidth = 9;
dw = 3; dw = 3;
bpp = 0x20; bpp = 0x20;
break; break;
@ -836,7 +837,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
/* Actually it can only be 8 now, /* Actually it can only be 8 now,
* default is just to silence compiler warnings */ * default is just to silence compiler warnings */
case SOCAM_DATAWIDTH_8: case SOCAM_DATAWIDTH_8:
icd->buswidth = 8;
dw = 2; dw = 2;
bpp = 0; bpp = 0;
} }
@ -862,7 +862,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV422P:
pcdev->channels = 3; pcdev->channels = 3;
cicr1 |= CICR1_YCBCR_F; cicr1 |= CICR1_YCBCR_F;
/*
* Normally, pxa bus wants as input UYVY format. We allow all
* reorderings of the YUV422 format, as no processing is done,
* and the YUV stream is just passed through without any
* transformation. Note that UYVY is the only format that
* should be used if pxa framebuffer Overlay2 is used.
*/
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
cicr1 |= CICR1_COLOR_SP_VAL(2); cicr1 |= CICR1_COLOR_SP_VAL(2);
break; break;
case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB555:
@ -888,13 +898,14 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
return 0; return 0;
} }
static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
unsigned char buswidth)
{ {
struct soc_camera_host *ici = struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent); to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv; struct pxa_camera_dev *pcdev = ici->priv;
unsigned long bus_flags, camera_flags; unsigned long bus_flags, camera_flags;
int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); int ret = test_platform_param(pcdev, buswidth, &bus_flags);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -904,25 +915,139 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL;
} }
static const struct soc_camera_data_format pxa_camera_formats[] = {
{
.name = "Planar YUV422 16 bit",
.depth = 16,
.fourcc = V4L2_PIX_FMT_YUV422P,
.colorspace = V4L2_COLORSPACE_JPEG,
},
};
static bool buswidth_supported(struct soc_camera_device *icd, int depth)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
switch (depth) {
case 8:
return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8);
case 9:
return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9);
case 10:
return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10);
}
return false;
}
static int required_buswidth(const struct soc_camera_data_format *fmt)
{
switch (fmt->fourcc) {
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB555:
return 8;
default:
return fmt->depth;
}
}
static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
struct soc_camera_format_xlate *xlate)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int formats = 0, buswidth, ret;
buswidth = required_buswidth(icd->formats + idx);
if (!buswidth_supported(icd, buswidth))
return 0;
ret = pxa_camera_try_bus_param(icd, buswidth);
if (ret < 0)
return 0;
switch (icd->formats[idx].fourcc) {
case V4L2_PIX_FMT_UYVY:
formats++;
if (xlate) {
xlate->host_fmt = &pxa_camera_formats[0];
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
dev_dbg(&ici->dev, "Providing format %s using %s\n",
pxa_camera_formats[0].name,
icd->formats[idx].name);
}
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB555:
formats++;
if (xlate) {
xlate->host_fmt = icd->formats + idx;
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = buswidth;
xlate++;
dev_dbg(&ici->dev, "Providing format %s packed\n",
icd->formats[idx].name);
}
break;
default:
/* Generic pass-through */
formats++;
if (xlate) {
xlate->host_fmt = icd->formats + idx;
xlate->cam_fmt = icd->formats + idx;
xlate->buswidth = icd->formats[idx].depth;
xlate++;
dev_dbg(&ici->dev,
"Providing format %s in pass-through mode\n",
icd->formats[idx].name);
}
}
return formats;
}
static int pxa_camera_set_fmt(struct soc_camera_device *icd, static int pxa_camera_set_fmt(struct soc_camera_device *icd,
__u32 pixfmt, struct v4l2_rect *rect) __u32 pixfmt, struct v4l2_rect *rect)
{ {
const struct soc_camera_data_format *cam_fmt; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int ret; const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
const struct soc_camera_format_xlate *xlate;
int ret, buswidth;
/* xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
* TODO: find a suitable supported by the SoC output format, check if (!xlate) {
* whether the sensor supports one of acceptable input formats. dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
*/ return -EINVAL;
if (pixfmt) {
cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt);
if (!cam_fmt)
return -EINVAL;
} }
ret = icd->ops->set_fmt(icd, pixfmt, rect); buswidth = xlate->buswidth;
if (pixfmt && !ret) host_fmt = xlate->host_fmt;
icd->current_fmt = cam_fmt; cam_fmt = xlate->cam_fmt;
switch (pixfmt) {
case 0: /* Only geometry change */
ret = icd->ops->set_fmt(icd, pixfmt, rect);
break;
default:
ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
}
if (ret < 0)
dev_warn(&ici->dev, "Failed to configure for format %x\n",
pixfmt);
if (pixfmt && !ret) {
icd->buswidth = buswidth;
icd->current_fmt = host_fmt;
}
return ret; return ret;
} }
@ -930,34 +1055,31 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
static int pxa_camera_try_fmt(struct soc_camera_device *icd, static int pxa_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f) struct v4l2_format *f)
{ {
const struct soc_camera_data_format *cam_fmt; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat); const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
__u32 pixfmt = pix->pixelformat;
if (ret < 0) xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
return ret; if (!xlate) {
dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
/*
* TODO: find a suitable supported by the SoC output format, check
* whether the sensor supports one of acceptable input formats.
*/
cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat);
if (!cam_fmt)
return -EINVAL; return -EINVAL;
}
/* limit to pxa hardware capabilities */ /* limit to pxa hardware capabilities */
if (f->fmt.pix.height < 32) if (pix->height < 32)
f->fmt.pix.height = 32; pix->height = 32;
if (f->fmt.pix.height > 2048) if (pix->height > 2048)
f->fmt.pix.height = 2048; pix->height = 2048;
if (f->fmt.pix.width < 48) if (pix->width < 48)
f->fmt.pix.width = 48; pix->width = 48;
if (f->fmt.pix.width > 2048) if (pix->width > 2048)
f->fmt.pix.width = 2048; pix->width = 2048;
f->fmt.pix.width &= ~0x01; pix->width &= ~0x01;
f->fmt.pix.bytesperline = f->fmt.pix.width * pix->bytesperline = pix->width *
DIV_ROUND_UP(cam_fmt->depth, 8); DIV_ROUND_UP(xlate->host_fmt->depth, 8);
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; pix->sizeimage = pix->height * pix->bytesperline;
/* limit to sensor capabilities */ /* limit to sensor capabilities */
return icd->ops->try_fmt(icd, f); return icd->ops->try_fmt(icd, f);
@ -1068,6 +1190,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.remove = pxa_camera_remove_device, .remove = pxa_camera_remove_device,
.suspend = pxa_camera_suspend, .suspend = pxa_camera_suspend,
.resume = pxa_camera_resume, .resume = pxa_camera_resume,
.get_formats = pxa_camera_get_formats,
.set_fmt = pxa_camera_set_fmt, .set_fmt = pxa_camera_set_fmt,
.try_fmt = pxa_camera_try_fmt, .try_fmt = pxa_camera_try_fmt,
.init_videobuf = pxa_camera_init_videobuf, .init_videobuf = pxa_camera_init_videobuf,