commit: http://blackfin.uclinux.org/git/?p=linux-kernel;a=commitdiff;h=ecc1011cc7350cab61ea26f7fa3248a84dce67a5 branch: http://blackfin.uclinux.org/git/?p=linux-kernel;a=shortlog;h=refs/heads/2012R1
Signed-off-by: Scott Jiang <[email protected]> --- drivers/media/video/adv7842.c | 66 ++++++++++-- drivers/media/video/blackfin/bfin_capture.c | 148 ++++++++++++++++++++++++--- drivers/media/video/blackfin/ppi.c | 35 ++++--- include/media/blackfin/bfin_capture.h | 5 +- include/media/blackfin/ppi.h | 16 ++- 5 files changed, 221 insertions(+), 49 deletions(-) diff --git a/drivers/media/video/adv7842.c b/drivers/media/video/adv7842.c index 03e4899..e82ce33 100644 --- a/drivers/media/video/adv7842.c +++ b/drivers/media/video/adv7842.c @@ -39,7 +39,7 @@ #include <media/v4l2-chip-ident.h> #include <media/adv7842.h> -static int debug; +static int debug = 3; MODULE_DESCRIPTION("Analog Devices ADV7842 video decoder driver"); MODULE_AUTHOR("Hans Verkuil <[email protected]>"); @@ -153,6 +153,11 @@ struct adv7842_state { struct v4l2_ctrl *free_run_color_ctrl; }; +static enum v4l2_mbus_pixelcode adv7842_codes[] = { + V4L2_MBUS_FMT_UYVY8_2X8, + V4L2_MBUS_FMT_UYVY8_1X16, +}; + /* ----------------------------------------------------------------------- */ static inline struct adv7842_state *to_state(struct v4l2_subdev *sd) @@ -1226,7 +1231,7 @@ static int adv7842_g_dv_timings(struct v4l2_subdev *sd, adv7842_g_input_status(sd, &status); if (status) { v4l2_dbg(1, debug, sd, "%s: chip not locked on format\n", __func__); - memset(timings, 0, sizeof(timings)); + memset(timings, 0, sizeof(*timings)); } else { struct v4l2_bt_timings *bt = &timings->bt; @@ -1467,6 +1472,50 @@ static void select_input(struct v4l2_subdev *sd, enum adv7842_prim_mode prim_mod } break; case ADV7842_PRIM_MODE_HDMI_COMP: + io_write(sd, 0x00, vid_std_select); /* video std */ + io_write(sd, 0x01, prim_mode); /* prim mode */ + + io_write(sd, 0x19, 0x83); + io_write(sd, 0x33, 0x40); + cp_write(sd, 0xba, 0x01); + cp_write(sd, 0x3e, 0x00); + cp_write(sd, 0x6c, 0x00); + afe_write(sd, 0x00, 0xff); + afe_write(sd, 0x01, 0xfe); + afe_write(sd, 0xb5, 0x01); + hdmi_write(sd, 0x00, 0x32); + hdmi_write(sd, 0xc1, 0xff); + hdmi_write(sd, 0xc2, 0xff); + hdmi_write(sd, 0xc3, 0xff); + hdmi_write(sd, 0xc4, 0xff); + hdmi_write(sd, 0xc5, 0x00); + hdmi_write(sd, 0xc6, 0x00); + hdmi_write(sd, 0xc0, 0xff); + hdmi_write(sd, 0x01, 0x18); + hdmi_write(sd, 0x0d, 0x34); + hdmi_write(sd, 0x1a, 0x8a); + hdmi_write(sd, 0x3d, 0x10); + hdmi_write(sd, 0x44, 0x85); + hdmi_write(sd, 0x46, 0x1f); + hdmi_write(sd, 0x60, 0x88); + hdmi_write(sd, 0x61, 0x88); + hdmi_write(sd, 0x6c, 0x18); + hdmi_write(sd, 0x57, 0xb6); + hdmi_write(sd, 0x58, 0x03); + hdmi_write(sd, 0x67, 0x20); + hdmi_write(sd, 0x75, 0x10); + hdmi_write(sd, 0x85, 0x1f); + hdmi_write(sd, 0x87, 0x70); + hdmi_write(sd, 0x89, 0x04); + hdmi_write(sd, 0x8a, 0x1e); + hdmi_write(sd, 0x93, 0x04); + hdmi_write(sd, 0x94, 0x1e); + hdmi_write(sd, 0x9d, 0x02); + hdmi_write(sd, 0x99, 0xa1); + hdmi_write(sd, 0x9b, 0x09); + hdmi_write(sd, 0xc9, 0x01); + v4l2_info(sd, "%s: HDMI todo\n", __func__); + break; case ADV7842_PRIM_MODE_HDMI_GR: { /* Automatic analog input muxing mode */ afe_write_and_or(sd, 0x02, 0x7f, 0x00); @@ -1586,13 +1635,10 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, static int adv7842_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - struct adv7842_state *state = to_state(sd); - if (index) + if (index >= ARRAY_SIZE(adv7842_codes)) return -EINVAL; - if (state->prim_mode == ADV7842_PRIM_MODE_SDP) - *code = V4L2_MBUS_FMT_UYVY8_2X8; - else - *code = V4L2_MBUS_FMT_FIXED; + + *code = adv7842_codes[index]; return 0; } @@ -1623,7 +1669,7 @@ static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd, err = v4l_fill_dv_preset_info(state->preset, &info); fmt->width = info.width; fmt->height = info.height; - fmt->code = V4L2_MBUS_FMT_FIXED; + fmt->code = V4L2_MBUS_FMT_UYVY8_1X16; fmt->field = V4L2_FIELD_NONE; fmt->colorspace = (state->preset <= V4L2_DV_576P50) ? V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; @@ -2650,7 +2696,7 @@ static int adv7842_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7842_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - state->preset = V4L2_DV_1080P60; + state->preset = V4L2_DV_720P60; state->connector_hdmi = pdata->connector_hdmi; state->prim_mode = pdata->prim_mode; state->pdata = pdata; diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c index 514fcf7..b42eedf 100644 --- a/drivers/media/video/blackfin/bfin_capture.c +++ b/drivers/media/video/blackfin/bfin_capture.c @@ -52,6 +52,7 @@ struct bcap_format { u32 pixelformat; enum v4l2_mbus_pixelcode mbus_code; int bpp; /* bits per pixel */ + int dlen; /* data length for ppi in bits */ }; struct bcap_buffer { @@ -76,10 +77,14 @@ struct bcap_device { unsigned int cur_input; /* current selected standard */ v4l2_std_id std; + /* current selected dv_timings */ + struct v4l2_dv_timings dv_timings; /* used to store pixel format */ struct v4l2_pix_format fmt; /* bits per pixel*/ int bpp; + /* data length for ppi in bits */ + int dlen; /* used to store sensor supported format */ struct bcap_format *sensor_formats; /* number of sensor formats array */ @@ -116,24 +121,35 @@ static const struct bcap_format bcap_formats[] = { .pixelformat = V4L2_PIX_FMT_UYVY, .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, .bpp = 16, + .dlen = 8, }, { .desc = "YCbCr 4:2:2 Interleaved YUYV", .pixelformat = V4L2_PIX_FMT_YUYV, .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, .bpp = 16, + .dlen = 8, + }, + { + .desc = "YCbCr 4:2:2 Interleaved UYVY", + .pixelformat = V4L2_PIX_FMT_UYVY, + .mbus_code = V4L2_MBUS_FMT_UYVY8_1X16, + .bpp = 16, + .dlen = 16, }, { .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, .bpp = 16, + .dlen = 8, }, { .desc = "RGB 444", .pixelformat = V4L2_PIX_FMT_RGB444, .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, .bpp = 16, + .dlen = 8, }, }; @@ -357,9 +373,39 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) params.width = bcap_dev->fmt.width; params.height = bcap_dev->fmt.height; params.bpp = bcap_dev->bpp; + params.dlen = bcap_dev->dlen; params.ppi_control = bcap_dev->cfg->ppi_control; params.int_mask = bcap_dev->cfg->int_mask; - params.blank_clocks = bcap_dev->cfg->blank_clocks; + if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities + & V4L2_IN_CAP_CUSTOM_TIMINGS) { + struct v4l2_bt_timings *bt = &bcap_dev->dv_timings.bt; + + params.hdelay = bt->hbackporch; + params.vdelay = bt->vbackporch; + params.line = bt->hfrontporch + bt->hsync + + bt->hbackporch + bt->width; + params.frame = bt->vfrontporch + bt->vsync + + bt->vbackporch + bt->height; + if (bt->interlaced) + params.frame += bt->il_vfrontporch + bt->il_vsync + + bt->il_vbackporch; + } else if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities + & V4L2_IN_CAP_STD) { + params.hdelay = 0; + params.vdelay = 0; + if (bcap_dev->std & V4L2_STD_525_60) { + params.line = 858; + params.frame = 525; + } else { + params.line = 864; + params.frame = 625; + } + } else { + params.hdelay = 0; + params.vdelay = 0; + params.line = params.width + bcap_dev->cfg->blank_pixels; + params.frame = params.height; + } ret = ppi->ops->set_params(ppi, ¶ms); if (ret < 0) { v4l2_err(&bcap_dev->v4l2_dev, @@ -593,6 +639,37 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } +static int bcap_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct bcap_device *bcap_dev = video_drvdata(file); + int ret; + + ret = v4l2_subdev_call(bcap_dev->sd, video, + g_dv_timings, timings); + if (ret < 0) + return ret; + + bcap_dev->dv_timings = *timings; + return 0; +} + +static int bcap_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct bcap_device *bcap_dev = video_drvdata(file); + int ret; + if (vb2_is_busy(&bcap_dev->buffer_queue)) + return -EBUSY; + + ret = v4l2_subdev_call(bcap_dev->sd, video, s_dv_timings, timings); + if (ret < 0) + return ret; + + bcap_dev->dv_timings = *timings; + return 0; +} + static int bcap_enum_input(struct file *file, void *priv, struct v4l2_input *input) { @@ -641,13 +718,15 @@ static int bcap_s_input(struct file *file, void *priv, unsigned int index) return ret; } bcap_dev->cur_input = index; + /* if this route has specific config, update ppi control */ + if (route->ppi_control) + config->ppi_control = route->ppi_control; return 0; } static int bcap_try_format(struct bcap_device *bcap, struct v4l2_pix_format *pixfmt, - enum v4l2_mbus_pixelcode *mbus_code, - int *bpp) + struct bcap_format *bcap_fmt) { struct bcap_format *sf = bcap->sensor_formats; struct bcap_format *fmt = NULL; @@ -662,16 +741,20 @@ static int bcap_try_format(struct bcap_device *bcap, if (i == bcap->num_sensor_formats) fmt = &sf[0]; - if (mbus_code) - *mbus_code = fmt->mbus_code; - if (bpp) - *bpp = fmt->bpp; v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code); ret = v4l2_subdev_call(bcap->sd, video, try_mbus_fmt, &mbus_fmt); if (ret < 0) return ret; v4l2_fill_pix_format(pixfmt, &mbus_fmt); + if (bcap_fmt) { + for (i = 0; i < bcap->num_sensor_formats; i++) { + fmt = &sf[i]; + if (mbus_fmt.code == fmt->mbus_code) + break; + } + *bcap_fmt = *fmt; + } pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8; pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; return 0; @@ -700,7 +783,7 @@ static int bcap_try_fmt_vid_cap(struct file *file, void *priv, struct bcap_device *bcap_dev = video_drvdata(file); struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - return bcap_try_format(bcap_dev, pixfmt, NULL, NULL); + return bcap_try_format(bcap_dev, pixfmt, NULL); } static int bcap_g_fmt_vid_cap(struct file *file, void *priv, @@ -717,24 +800,25 @@ static int bcap_s_fmt_vid_cap(struct file *file, void *priv, { struct bcap_device *bcap_dev = video_drvdata(file); struct v4l2_mbus_framefmt mbus_fmt; - enum v4l2_mbus_pixelcode mbus_code; + struct bcap_format bcap_fmt; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - int ret, bpp; + int ret; if (vb2_is_busy(&bcap_dev->buffer_queue)) return -EBUSY; /* see if format works */ - ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp); + ret = bcap_try_format(bcap_dev, pixfmt, &bcap_fmt); if (ret < 0) return ret; - v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code); + v4l2_fill_mbus_format(&mbus_fmt, pixfmt, bcap_fmt.mbus_code); ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt); if (ret < 0) return ret; bcap_dev->fmt = *pixfmt; - bcap_dev->bpp = bpp; + bcap_dev->bpp = bcap_fmt.bpp; + bcap_dev->dlen = bcap_fmt.dlen; return 0; } @@ -825,6 +909,8 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = { .vidioc_querystd = bcap_querystd, .vidioc_s_std = bcap_s_std, .vidioc_g_std = bcap_g_std, + .vidioc_s_dv_timings = bcap_s_dv_timings, + .vidioc_g_dv_timings = bcap_g_dv_timings, .vidioc_reqbufs = bcap_reqbufs, .vidioc_querybuf = bcap_querybuf, .vidioc_qbuf = bcap_qbuf, @@ -860,6 +946,7 @@ static int __devinit bcap_probe(struct platform_device *pdev) struct i2c_adapter *i2c_adap; struct bfin_capture_config *config; struct vb2_queue *q; + struct bcap_route *route; int ret; config = pdev->dev.platform_data; @@ -968,6 +1055,12 @@ static int __devinit bcap_probe(struct platform_device *pdev) NULL); if (bcap_dev->sd) { int i; + if (!config->num_inputs) { + v4l2_err(&bcap_dev->v4l2_dev, + "Unable to work without input\n"); + goto err_unreg_vdev; + } + /* update tvnorms from the sub devices */ for (i = 0; i < config->num_inputs; i++) vfd->tvnorms |= config->inputs[i].std; @@ -979,8 +1072,24 @@ static int __devinit bcap_probe(struct platform_device *pdev) v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n"); + /* + * explicitly set input, otherwise some boards + * may not work at the state as we expected + */ + route = &config->routes[0]; + ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, + route->input, route->output, 0); + if ((ret < 0) && (ret != -ENOIOCTLCMD)) { + v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); + goto err_unreg_vdev; + } + bcap_dev->cur_input = 0; + /* if this route has specific config, update ppi control */ + if (route->ppi_control) + config->ppi_control = route->ppi_control; + /* now we can probe the default state */ - if (vfd->tvnorms) { + if (config->inputs[0].capabilities & V4L2_IN_CAP_STD) { v4l2_std_id std; ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std); if (ret) { @@ -990,6 +1099,17 @@ static int __devinit bcap_probe(struct platform_device *pdev) } bcap_dev->std = std; } + if (config->inputs[0].capabilities & V4L2_IN_CAP_CUSTOM_TIMINGS) { + struct v4l2_dv_timings dv_timings; + ret = v4l2_subdev_call(bcap_dev->sd, video, + g_dv_timings, &dv_timings); + if (ret) { + v4l2_err(&bcap_dev->v4l2_dev, + "Unable to get dv timings\n"); + goto err_unreg_vdev; + } + bcap_dev->dv_timings = dv_timings; + } ret = bcap_init_sensor_formats(bcap_dev); if (ret) { v4l2_err(&bcap_dev->v4l2_dev, diff --git a/drivers/media/video/blackfin/ppi.c b/drivers/media/video/blackfin/ppi.c index 38ad9ed..8852514 100644 --- a/drivers/media/video/blackfin/ppi.c +++ b/drivers/media/video/blackfin/ppi.c @@ -191,10 +191,11 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) { const struct ppi_info *info = ppi->info; int dma32 = 0; - int dma_config, bytes_per_line, lines_per_frame; + int dma_config, hcount, bytes_per_line, samples_per_line; bytes_per_line = params->width * params->bpp / 8; - lines_per_frame = params->height; + hcount = params->width * params->bpp / params->dlen; + samples_per_line = params->line * params->bpp / params->dlen; if (params->int_mask == 0xFFFFFFFF) ppi->err_int = false; else @@ -211,8 +212,8 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) dma32 = 1; bfin_write16(®->control, ppi->ppi_control); - bfin_write16(®->count, bytes_per_line - 1); - bfin_write16(®->frame, lines_per_frame); + bfin_write16(®->count, samples_per_line - 1); + bfin_write16(®->frame, params->frame); break; } case PPI_TYPE_EPPI: @@ -224,12 +225,12 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) dma32 = 1; bfin_write32(®->control, ppi->ppi_control); - bfin_write16(®->line, bytes_per_line + params->blank_clocks); - bfin_write16(®->frame, lines_per_frame); - bfin_write16(®->hdelay, 0); - bfin_write16(®->vdelay, 0); - bfin_write16(®->hcount, bytes_per_line); - bfin_write16(®->vcount, lines_per_frame); + bfin_write16(®->line, samples_per_line); + bfin_write16(®->frame, params->frame); + bfin_write16(®->hdelay, params->hdelay); + bfin_write16(®->vdelay, params->vdelay); + bfin_write16(®->hcount, hcount); + bfin_write16(®->vcount, params->height); break; } case PPI_TYPE_EPPI3: @@ -241,12 +242,12 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) dma32 = 1; bfin_write32(®->ctl, ppi->ppi_control); - bfin_write32(®->line, bytes_per_line + params->blank_clocks); - bfin_write32(®->frame, lines_per_frame); - bfin_write32(®->hdly, 0); - bfin_write32(®->vdly, 0); - bfin_write32(®->hcnt, bytes_per_line); - bfin_write32(®->vcnt, lines_per_frame); + bfin_write32(®->line, samples_per_line); + bfin_write32(®->frame, params->frame); + bfin_write32(®->hdly, params->hdelay); + bfin_write32(®->vdly, params->vdelay); + bfin_write32(®->hcnt, hcount); + bfin_write32(®->vcnt, params->height); if (params->int_mask) bfin_write32(®->imsk, params->int_mask & 0xFF); break; @@ -266,7 +267,7 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) set_dma_x_modify(info->dma_ch, 2); set_dma_y_modify(info->dma_ch, 2); } - set_dma_y_count(info->dma_ch, lines_per_frame); + set_dma_y_count(info->dma_ch, params->height); set_dma_config(info->dma_ch, dma_config); SSYNC(); diff --git a/include/media/blackfin/bfin_capture.h b/include/media/blackfin/bfin_capture.h index 2038a8a..56b9ce4 100644 --- a/include/media/blackfin/bfin_capture.h +++ b/include/media/blackfin/bfin_capture.h @@ -9,6 +9,7 @@ struct ppi_info; struct bcap_route { u32 input; u32 output; + u32 ppi_control; }; struct bfin_capture_config { @@ -30,8 +31,8 @@ struct bfin_capture_config { unsigned long ppi_control; /* ppi interrupt mask */ u32 int_mask; - /* horizontal blanking clocks */ - int blank_clocks; + /* horizontal blanking pixels */ + int blank_pixels; }; #endif diff --git a/include/media/blackfin/ppi.h b/include/media/blackfin/ppi.h index eb8a783..a107acc 100644 --- a/include/media/blackfin/ppi.h +++ b/include/media/blackfin/ppi.h @@ -43,12 +43,16 @@ struct ppi_if; struct ppi_params { - int width; - int height; - int bpp; - unsigned long ppi_control; - u32 int_mask; - int blank_clocks; + u32 width; /* width in pixels */ + u32 height; /* height in lines */ + u32 hdelay; /* delay after the HSYNC in pixels */ + u32 vdelay; /* delay after the VSYNC in lines */ + u32 line; /* total pixels per line */ + u32 frame; /* total lines per frame */ + int bpp; /* bits per pixel */ + int dlen; /* data length for ppi in bits */ + u32 ppi_control; /* ppi configuration */ + u32 int_mask; /* interrupt mask */ }; struct ppi_ops {
_______________________________________________ Linux-kernel-commits mailing list [email protected] https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits
