Commit bad3fa56 authored by 吴智聪(John Wu)'s avatar 吴智聪(John Wu)

vpfe support component input

add progressive buffer logic to vpfe buffer system,
support dynamic choose the input port,
support ccdc configure for component input port,
add some component standard for v4l2 interface
parent 00d2c3e5
......@@ -23,102 +23,124 @@
#define debug_print(x...) //printk(x)
void ccdc_reset()
{
int i;
/* disable CCDC */
ccdc_enable(0);
/* set all registers to default value */
for (i = 0; i <= 0x94; i += 4) {
regw(0, i);
}
regw(0, PCR);
regw(0, SYN_MODE);
regw(0, HD_VD_WID);
regw(0, PIX_LINES);
regw(0, HORZ_INFO);
regw(0, VERT_START);
regw(0, VERT_LINES);
regw(0xffff00ff, CULLING);
regw(0, HSIZE_OFF);
regw(0, SDOFST);
regw(0, SDR_ADDR);
regw(0, VDINT);
regw(0, REC656IF);
regw(0, CCDCFG);
regw(0, FMTCFG);
regw(0, VP_OUT);
int i;
/* disable CCDC */
ccdc_enable(0);
/* set all registers to default value */
for (i = 0; i <= 0x94; i += 4)
{
regw(0, i);
}
regw(0, PCR);
regw(0, SYN_MODE);
regw(0, HD_VD_WID);
regw(0, PIX_LINES);
regw(0, HORZ_INFO);
regw(0, VERT_START);
regw(0, VERT_LINES);
regw(0xffff00ff, CULLING);
regw(0, HSIZE_OFF);
regw(0, SDOFST);
regw(0, SDR_ADDR);
regw(0, VDINT);
regw(0, REC656IF);
regw(0, CCDCFG);
regw(0, FMTCFG);
regw(0, VP_OUT);
}
void ccdc_setwin(ccdc_params_ycbcr * params)
{
int horz_start, horz_nr_pixels;
int vert_start, vert_nr_lines;
/* configure horizonal and vertical starts and sizes */
horz_start = params->win.left << 1;
horz_nr_pixels = (params->win.width <<1) - 1;
regw((horz_start << 16) | horz_nr_pixels, HORZ_INFO);
vert_start = params->win.top;
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
vert_nr_lines = (params->win.height >> 1) - 1;
vert_start >>= 1;
} else {
vert_nr_lines = params->win.height - 1;
}
regw((vert_start << 16) | vert_start, VERT_START);
regw(vert_nr_lines, VERT_LINES);
int horz_start, horz_nr_pixels;
int vert_start, vert_nr_lines;
/* configure horizonal and vertical starts and sizes */
horz_start = params->win.left << 1;
horz_nr_pixels = (params->win.width <<1) - 1;
regw((horz_start << 16) | horz_nr_pixels, HORZ_INFO);
vert_start = params->win.top;
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED)
{
vert_nr_lines = (params->win.height >> 1) - 1;
vert_start >>= 1;
}
else
{
vert_nr_lines = params->win.height - 1;
}
regw((vert_start << 16) | vert_start, VERT_START);
regw(vert_nr_lines, VERT_LINES);
}
void ccdc_config_ycbcr(ccdc_params_ycbcr * params)
{
u32 syn_mode;
/* first reset the CCDC */
/* all registers have default values after reset */
/* This is important since we assume default values to be set in */
/* a lot of registers that we didn't touch */
ccdc_reset();
/* configure pixel format */
syn_mode = (params->pix_fmt & 0x3) << 12;
/* configure video frame format */
syn_mode |= (params->frm_fmt & 0x1) << 7;
/* setup BT.656 sync mode */
if (params->bt656_enable) {
regw(3, REC656IF);
/* configure the FID, VD, HD pin polarity */
/* fld,hd pol positive, vd negative, 8-bit pack mode */
syn_mode |= 0x00000F04;
} else {/* y/c external sync mode */
syn_mode |= ((params->fid_pol & 0x1) << 4);
syn_mode |= ((params->hd_pol & 0x1) << 3);
syn_mode |= ((params->vd_pol & 0x1) << 2);
}
/* configure video window */
ccdc_setwin(params);
/* configure the order of y cb cr in SD-RAM */
regw((params->pix_order << 11) | 0x8000, CCDCFG);
/* configure the horizontal line offset */
/* this is done by rounding up width to a multiple of 16 pixels */
/* and multiply by two to account for y:cb:cr 4:2:2 data */
regw(((params->win.width * 2) + 31) & 0xffffffe0, HSIZE_OFF);
/* configure the memory line offset */
if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
/* two fields are interleaved in memory */
regw(0x00000249, SDOFST);
}
/* enable output to SDRAM */
syn_mode |= (0x1 << 17);
/* enable internal timing generator */
syn_mode |= (0x1 << 16);
regw(syn_mode, SYN_MODE);
u32 syn_mode;
/* first reset the CCDC */
/* all registers have default values after reset */
/* This is important since we assume default values to be set in */
/* a lot of registers that we didn't touch */
ccdc_reset();
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED)
{
/* configure ccdc register for interlace mode */
/* configure pixel format */
syn_mode = (params->pix_fmt & 0x3) << 12;
/* configure video frame format */
syn_mode |= (params->frm_fmt & 0x1) << 7;
/* setup BT.656 sync mode */
if (params->bt656_enable)
{
regw(3, REC656IF);
/* configure the FID, VD, HD pin polarity */
/* fld,hd pol positive, vd negative, 8-bit pack mode */
syn_mode |= 0x00000F04;
}
else
{/* y/c external sync mode */
syn_mode |= ((params->fid_pol & 0x1) << 4);
syn_mode |= ((params->hd_pol & 0x1) << 3);
syn_mode |= ((params->vd_pol & 0x1) << 2);
}
/* configure video window */
ccdc_setwin(params);
/* configure the order of y cb cr in SD-RAM */
regw((params->pix_order << 11) | 0x8000, CCDCFG);
/* configure the horizontal line offset */
/* this is done by rounding up width to a multiple of 16 pixels */
/* and multiply by two to account for y:cb:cr 4:2:2 data */
regw(((params->win.width * 2) + 31) & 0xffffffe0, HSIZE_OFF);
/* configure the memory line offset */
if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
{
/* two fields are interleaved in memory */
regw(0x00000249, SDOFST);
}
/* enable output to SDRAM */
syn_mode |= (0x1 << 17);
/* enable internal timing generator */
syn_mode |= (0x1 << 16);
regw(syn_mode, SYN_MODE);
}
else
{
/* configure ccdc register for progressive mode */
regw(0x5a0,HSIZE_OFF);
ccdc_setwin(params);
regw((params->pix_order << 11) | 0x8000, CCDCFG);
regw((0x00031000)|(0x1 << 17)|(0x1 << 16)|(0x1 << 3)|(0x1 << 4), SYN_MODE);
}
}
......@@ -89,6 +89,9 @@ static struct v4l2_fract ntsc_aspect = VPFE_PIXELASPECT_NTSC;
static struct v4l2_fract pal_aspect = VPFE_PIXELASPECT_PAL;
static struct v4l2_rect ntscsp_bounds = VPFE_WIN_NTSC_SP;
static struct v4l2_rect palsp_bounds = VPFE_WIN_PAL_SP;
static struct v4l2_rect hd_480p_bounds = VPFE_WIN_HD480P;
static struct v4l2_rect hd_720p_bounds = VPFE_WIN_HD720P;
static struct v4l2_rect hd_1080i_bounds = VPFE_WIN_HD1080I;
static struct v4l2_fract sp_aspect = VPFE_PIXELASPECT_NTSC_SP;
#define NTOSD_INPUTS 2
......@@ -140,55 +143,70 @@ static irqreturn_t vpfe_isr(int irq, void *dev_id)
vpfe_obj *vpfe = &vpfe_device;
int fid;
/* check which field we are in hardware */
fid = ccdc_getfid();
vpfe->field_id ^= 1; /* switch the software maintained field id */
debug_print(KERN_INFO "field id = %x:%x.\n", fid, vpfe->field_id);
if (fid == vpfe->field_id) { /* we are in-sync here, continue */
if (fid == 0) {
/* One frame is just being captured. If the next frame
is available, release the current frame and move on */
if (vpfe->curFrm != vpfe->nextFrm) {
vpfe->curFrm->state = STATE_DONE;
wake_up_interruptible(&vpfe->curFrm->done);
vpfe->curFrm = vpfe->nextFrm;
}
/* based on whether the two fields are stored interleavely */
/* or separately in memory, reconfigure the CCDC memory address */
if (vpfe->field == V4L2_FIELD_SEQ_TB) {
u32 addr = vpfe->curFrm->boff + vpfe->field_offset;
ccdc_setfbaddr((unsigned long)addr);
}
} else if (fid == 1) {
/* if one field is just being captured */
/* configure the next frame */
/* get the next frame from the empty queue */
/* if no frame is available, hold on to the current buffer */
if (!list_empty(&vpfe->dma_queue)
&& vpfe->curFrm == vpfe->nextFrm) {
vpfe->nextFrm = list_entry(vpfe->dma_queue.next,
struct videobuf_buffer, queue);
list_del(&vpfe->nextFrm->queue);
vpfe->nextFrm->state = STATE_ACTIVE;
ccdc_setfbaddr((unsigned long)vpfe->nextFrm->boff);
}
if (vpfe->mode_changed) {
ccdc_setwin(&vpfe->ccdc_params);
/* update the field offset */
vpfe->field_offset = (vpfe->vwin.height - 2) * vpfe->vwin.width;
vpfe->mode_changed = FALSE;
}
}
} else if (fid == 0) {
/* recover from any hardware out-of-sync due to */
/* possible switch of video source */
/* for fid == 0, sync up the two fids */
/* for fid == 1, no action, one bad frame will */
/* go out, but it is not a big deal */
vpfe->field_id = fid;
}
debug_print(KERN_INFO "interrupt returned.\n");
return IRQ_RETVAL(1);
if (ccdc_getfidmode()) // interlace mode
{
/* check which field we are in hardware */
fid = ccdc_getfid();
vpfe->field_id ^= 1; /* switch the software maintained field id */
debug_print(KERN_INFO "field id = %x:%x.\n", fid, vpfe->field_id);
if (fid == vpfe->field_id) { /* we are in-sync here, continue */
if (fid == 0) {
/* One frame is just being captured. If the next frame
is available, release the current frame and move on */
if (vpfe->curFrm != vpfe->nextFrm) {
vpfe->curFrm->state = STATE_DONE;
wake_up_interruptible(&vpfe->curFrm->done);
vpfe->curFrm = vpfe->nextFrm;
}
/* based on whether the two fields are stored interleavely */
/* or separately in memory, reconfigure the CCDC memory address */
if (vpfe->field == V4L2_FIELD_SEQ_TB) {
u32 addr = vpfe->curFrm->boff + vpfe->field_offset;
ccdc_setfbaddr((unsigned long)addr);
}
} else if (fid == 1) {
/* if one field is just being captured */
/* configure the next frame */
/* get the next frame from the empty queue */
/* if no frame is available, hold on to the current buffer */
if (!list_empty(&vpfe->dma_queue)
&& vpfe->curFrm == vpfe->nextFrm) {
vpfe->nextFrm = list_entry(vpfe->dma_queue.next,
struct videobuf_buffer, queue);
list_del(&vpfe->nextFrm->queue);
vpfe->nextFrm->state = STATE_ACTIVE;
ccdc_setfbaddr((unsigned long)vpfe->nextFrm->boff);
}
if (vpfe->mode_changed) {
ccdc_setwin(&vpfe->ccdc_params);
/* update the field offset */
vpfe->field_offset = (vpfe->vwin.height - 2) * vpfe->vwin.width;
vpfe->mode_changed = FALSE;
}
}
} else if (fid == 0) {
/* recover from any hardware out-of-sync due to */
/* possible switch of video source */
/* for fid == 0, sync up the two fids */
/* for fid == 1, no action, one bad frame will */
/* go out, but it is not a big deal */
vpfe->field_id = fid;
}
}
else // progressive mode
{
vpfe->curFrm->state = STATE_DONE;
wake_up_interruptible(&vpfe->curFrm->done);
if (!list_empty(&vpfe->dma_queue))
{
vpfe->curFrm = list_entry(vpfe->dma_queue.next, struct videobuf_buffer, queue);
list_del(&vpfe->curFrm->queue);
vpfe->curFrm->state = STATE_ACTIVE;
ccdc_setfbaddr((unsigned long)vpfe->curFrm->boff);
}
}
debug_print(KERN_INFO "interrupt returned.\n");
return IRQ_RETVAL(1);
}
/* this is the callback function called from videobuf_qbuf() function */
......@@ -332,16 +350,15 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
int ret = 0;
switch (cmd) {
case VIDIOC_S_CTRL:
case VIDIOC_S_CROP:
case VIDIOC_S_FMT:
case VIDIOC_S_STD:
case VIDIOC_S_CROP:
ret = v4l2_prio_check(&vpfe->prio, &fh->prio);
if (0 != ret) {
return ret;
}
}
break;
}
}
switch (cmd) {
case VIDIOC_QUERYCAP:
{
......@@ -483,16 +500,21 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
vpfe->bounds = vpfe->vwin = pal_bounds;
vpfe->pixelaspect = pal_aspect;
vpfe->ccdc_params.win = pal_bounds;
vpfe->ccdc_params.frm_fmt = CCDC_FRMFMT_INTERLACED;
vpfe->ccdc_params.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
} else if (id & V4L2_STD_525_60) {
vpfe->std = id;
vpfe->bounds = vpfe->vwin = ntsc_bounds;
vpfe->pixelaspect = ntsc_aspect;
vpfe->ccdc_params.win = ntsc_bounds;
vpfe->ccdc_params.frm_fmt = CCDC_FRMFMT_INTERLACED;
vpfe->ccdc_params.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
} else if (id & VPFE_STD_625_50_SQP) {
vpfe->std = id;
vpfe->bounds = vpfe->vwin = palsp_bounds;
vpfe->pixelaspect = sp_aspect;
vpfe->ccdc_params.frm_fmt = CCDC_FRMFMT_INTERLACED;
vpfe->ccdc_params.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
sqp = 1;
id >>= 32;
} else if (id & VPFE_STD_525_60_SQP) {
......@@ -503,17 +525,29 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
vpfe->bounds = vpfe->vwin = ntscsp_bounds;
vpfe->pixelaspect = sp_aspect;
vpfe->ccdc_params.win = ntscsp_bounds;
vpfe->ccdc_params.frm_fmt = CCDC_FRMFMT_INTERLACED;
vpfe->ccdc_params.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
} else if (id & VPFE_STD_AUTO) {
vpfe->bounds = vpfe->vwin = pal_bounds;
vpfe->pixelaspect = pal_aspect;
vpfe->ccdc_params.win = pal_bounds;
vpfe->ccdc_params.frm_fmt = CCDC_FRMFMT_INTERLACED;
vpfe->ccdc_params.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
vpfe->std = id;
} else if (id & VPFE_STD_AUTO_SQP) {
vpfe->std = id;
vpfe->bounds = vpfe->vwin = palsp_bounds;
vpfe->pixelaspect = sp_aspect;
vpfe->ccdc_params.frm_fmt = CCDC_FRMFMT_INTERLACED;
vpfe->ccdc_params.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
sqp = 1;
} else if (id & V4L2_STD_HD_480P) {
vpfe->std = id;
vpfe->bounds = vpfe->vwin = hd_480p_bounds;
vpfe->pixelaspect = sp_aspect;
vpfe->ccdc_params.win = hd_480p_bounds;
vpfe->ccdc_params.frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
vpfe->ccdc_params.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
} else {
ret = -EINVAL;
}
......@@ -596,7 +630,6 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
case VIDIOC_S_INPUT:
{
int *index = (int *)arg;
if (*index == VPFE_AMUX_COMPOSITE0 || *index == VPFE_AMUX_COMPOSITE1)
vpfe_select_capture_device(VPFE_CAPTURE_ID_TVP5150);
else if (*index == VPFE_AMUX_COMPONENT)
......@@ -742,7 +775,7 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
case VIDIOC_QUERYBUF:
ret = videobuf_querybuf(&vpfe->bufqueue, arg);
break;
case VIDIOC_QBUF:
case VIDIOC_QBUF:
if (!fh->io_allowed)
ret = -EACCES;
else
......
......@@ -824,11 +824,11 @@ static int tvp5150_command(struct i2c_client *c,
{
int input = *(int *)arg;
if (input == 0)
decoder->route.input = TVP5150_COMPOSITE0;
decoder->route.input = VPFE_AMUX_COMPOSITE0;
else if (input == 1)
decoder->route.input = TVP5150_COMPOSITE1;
decoder->route.input = VPFE_AMUX_COMPOSITE1;
else
decoder->route.input = TVP5150_SVIDEO;
return -EINVAL;
tvp5150_selmux(c);
break;
}
......@@ -1156,8 +1156,11 @@ static struct vpfe_capture_device tvp5150_device = {
static int __init tvp5150_init(void)
{
int ret;
i2c_add_driver(&driver);
return vpfe_capture_device_register(&tvp5150_device);
ret = vpfe_capture_device_register(&tvp5150_device);
tvp5150_device_deactive();
return ret;
}
static void __exit tvp5150_exit(void)
......
......@@ -723,6 +723,12 @@ typedef __u64 v4l2_std_id;
#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
/*FOR COMPONENT*/
#define V4L2_STD_HD_480P ((v4l2_std_id)0x04000000)
#define V4L2_STD_HD_576P ((v4l2_std_id)0x08000000)
#define V4L2_STD_HD_720P ((v4l2_std_id)0x10000000)
#define V4L2_STD_HD_1080I ((v4l2_std_id)0x20000000)
/* FIXME:
Although std_id is 64 bits, there is an issue on PPC32 architecture that
makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
......
......@@ -139,6 +139,12 @@ static inline int ccdc_getfid(void)
int fid = (regr(SYN_MODE) >> 15) & 0x1;
return fid;
}
static inline int ccdc_getfidmode(void)
{
int fid = (regr(SYN_MODE) >> 7) & 0x1;
return fid;
}
#endif
#endif /* CCDC_DAVINCI_H */
......@@ -53,6 +53,9 @@
#define VPFE_WIN_QCIF {0,0,176,144}
#define VPFE_WIN_QVGA {0,0,320,240}
#define VPFE_WIN_SIF {0,0,352,240}
#define VPFE_WIN_HD480P {0,0,720,480}
#define VPFE_WIN_HD720P {0,0,1280,720}
#define VPFE_WIN_HD1080I {0,0,1920,1080}
#define VPFE_CAPTURE_ID_TVP5150 0
#define VPFE_CAPTURE_ID_TVP7000 1
......
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