Commit ccab8a29 authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mauro Carvalho Chehab

V4L/DVB (10089): Add interlace support to sh_mobile_ceu_camera.c

Signed-off-by: default avatarKuninori Morimoto <morimoto.kuninori@renesas.com>
Acked-by: default avatarMagnus Damm <damm@igel.co.jp>
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 7a1a8164
...@@ -94,6 +94,7 @@ struct sh_mobile_ceu_dev { ...@@ -94,6 +94,7 @@ struct sh_mobile_ceu_dev {
spinlock_t lock; spinlock_t lock;
struct list_head capture; struct list_head capture;
struct videobuf_buffer *active; struct videobuf_buffer *active;
int is_interlace;
struct sh_mobile_ceu_info *pdata; struct sh_mobile_ceu_info *pdata;
...@@ -163,7 +164,7 @@ static void free_buffer(struct videobuf_queue *vq, ...@@ -163,7 +164,7 @@ static void free_buffer(struct videobuf_queue *vq,
static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
{ {
struct soc_camera_device *icd = pcdev->icd; struct soc_camera_device *icd = pcdev->icd;
dma_addr_t phys_addr; dma_addr_t phys_addr_top, phys_addr_bottom;
/* The hardware is _very_ picky about this sequence. Especially /* The hardware is _very_ picky about this sequence. Especially
* the CEU_CETCR_MAGIC value. It seems like we need to acknowledge * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
...@@ -178,16 +179,24 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) ...@@ -178,16 +179,24 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
if (!pcdev->active) if (!pcdev->active)
return; return;
phys_addr = videobuf_to_dma_contig(pcdev->active); phys_addr_top = videobuf_to_dma_contig(pcdev->active);
ceu_write(pcdev, CDAYR, phys_addr); ceu_write(pcdev, CDAYR, phys_addr_top);
if (pcdev->is_interlace) {
phys_addr_bottom = phys_addr_top + icd->width;
ceu_write(pcdev, CDBYR, phys_addr_bottom);
}
switch (icd->current_fmt->fourcc) { switch (icd->current_fmt->fourcc) {
case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV61:
phys_addr += icd->width * icd->height; phys_addr_top += icd->width * icd->height;
ceu_write(pcdev, CDACR, phys_addr); ceu_write(pcdev, CDACR, phys_addr_top);
if (pcdev->is_interlace) {
phys_addr_bottom = phys_addr_top + icd->width;
ceu_write(pcdev, CDBCR, phys_addr_bottom);
}
} }
pcdev->active->state = VIDEOBUF_ACTIVE; pcdev->active->state = VIDEOBUF_ACTIVE;
...@@ -381,7 +390,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ...@@ -381,7 +390,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
{ {
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv; struct sh_mobile_ceu_dev *pcdev = ici->priv;
int ret, buswidth, width, cfszr_width, cdwdr_width; int ret, buswidth, width, height, cfszr_width, cdwdr_width;
unsigned long camera_flags, common_flags, value; unsigned long camera_flags, common_flags, value;
int yuv_mode, yuv_lineskip; int yuv_mode, yuv_lineskip;
...@@ -448,7 +457,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ...@@ -448,7 +457,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
ceu_write(pcdev, CAMCR, value); ceu_write(pcdev, CAMCR, value);
ceu_write(pcdev, CAPCR, 0x00300000); ceu_write(pcdev, CAPCR, 0x00300000);
ceu_write(pcdev, CAIFR, 0); ceu_write(pcdev, CAIFR, (pcdev->is_interlace) ? 0x101 : 0);
mdelay(1); mdelay(1);
...@@ -463,10 +472,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ...@@ -463,10 +472,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
cdwdr_width = buswidth == 16 ? width * 2 : width; cdwdr_width = buswidth == 16 ? width * 2 : width;
} }
height = icd->height;
if (pcdev->is_interlace) {
height /= 2;
cdwdr_width *= 2;
}
ceu_write(pcdev, CAMOR, 0); ceu_write(pcdev, CAMOR, 0);
ceu_write(pcdev, CAPWR, (icd->height << 16) | width); ceu_write(pcdev, CAPWR, (height << 16) | width);
ceu_write(pcdev, CFLCR, 0); /* no scaling */ ceu_write(pcdev, CFLCR, 0); /* no scaling */
ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width); ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width);
ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */ ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */
/* A few words about byte order (observed in Big Endian mode) /* A few words about byte order (observed in Big Endian mode)
...@@ -615,8 +630,10 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, ...@@ -615,8 +630,10 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
const struct soc_camera_format_xlate *xlate; const struct soc_camera_format_xlate *xlate;
__u32 pixfmt = f->fmt.pix.pixelformat; __u32 pixfmt = f->fmt.pix.pixelformat;
int ret;
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) { if (!xlate) {
...@@ -642,7 +659,26 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, ...@@ -642,7 +659,26 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
/* limit to sensor capabilities */ /* limit to sensor capabilities */
return icd->ops->try_fmt(icd, f); ret = icd->ops->try_fmt(icd, f);
if (ret < 0)
return ret;
switch (f->fmt.pix.field) {
case V4L2_FIELD_INTERLACED:
pcdev->is_interlace = 1;
break;
case V4L2_FIELD_ANY:
f->fmt.pix.field = V4L2_FIELD_NONE;
/* fall-through */
case V4L2_FIELD_NONE:
pcdev->is_interlace = 0;
break;
default:
ret = -EINVAL;
break;
}
return ret;
} }
static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment