blackfin: add display support in ppi driver
PATCH 1/2 blackfin: add display support in ppi driver
--- drivers/media/platform/blackfin/ppi.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)
drivers/media/platform/blackfin/ppi.c +12 -0
@@ -266,6 +266,18 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)bfin_write32 (®->vcnt, params->height);if (params->int_mask)bfin_write32 (®->imsk, params->int_mask &0xFF ); +if (ppi->ppi_control &PORT_DIR ) { +u32 hsync_width, vsync_width, vsync_period; + + hsync_width = params->hsync + * params->bpp / params->dlen; + vsync_width = params->vsync * samples_per_line; + vsync_period = samples_per_line * params->frame; +bfin_write32 (®->fs1_wlhb, hsync_width); +bfin_write32 (®->fs1_paspl, samples_per_line); +bfin_write32 (®->fs2_wlvb, vsync_width); +bfin_write32 (®->fs2_palpf, vsync_period); + }break ; }default :
Signature · 1 line
1.7.0.4
PATCH 2/2 bfin_capture: add query_dv_timings/enum_dv_timings support
More dv_timings ioctl ops are introduced in video core. Add query_dv_timings/enum_dv_timings accordingly.
--- drivers/media/platform/blackfin/bfin_capture.c | 28 ++++++++++++++++++------ 1 files changed, 21 insertions(+), 7 deletions(-)
drivers/media/platform/blackfin/bfin_capture.c +21 -7
@@ -649,18 +649,30 @@ 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, +static int bcap_enum_dv_timings (struct file *file,void *priv, +struct v4l2_enum_dv_timings *timings) +{ +struct bcap_device *bcap_dev =video_drvdata (file); + +return v4l2_subdev_call (bcap_dev->sd, video, + enum_dv_timings, timings); +} + +static int bcap_query_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; +return v4l2_subdev_call (bcap_dev->sd, video, + query_dv_timings, timings); +} - bcap_dev->dv_timings = *timings; +static int bcap_g_dv_timings (struct file *file,void *priv, +struct v4l2_dv_timings *timings) +{ +struct bcap_device *bcap_dev =video_drvdata (file); + + *timings = bcap_dev->dv_timings;return 0 ; }
@@ -921,6 +933,8 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = { .vidioc_g_std = bcap_g_std, .vidioc_s_dv_timings = bcap_s_dv_timings, .vidioc_g_dv_timings = bcap_g_dv_timings, + .vidioc_query_dv_timings = bcap_query_dv_timings, + .vidioc_enum_dv_timings = bcap_enum_dv_timings, .vidioc_reqbufs = bcap_reqbufs, .vidioc_querybuf = bcap_querybuf, .vidioc_qbuf = bcap_qbuf,
Signature · 1 line
1.7.0.4
RFC PATCH 1/1 blackfin: add video display driver
In reply to Scott JiangThis is a bridge driver for blackfin diplay device. It can work with ppi or eppi interface. DV timings are supported.
--- drivers/media/platform/blackfin/Kconfig | 15 +- drivers/media/platform/blackfin/Makefile | 1 + drivers/media/platform/blackfin/bfin_display.c | 1151 ++++++++++++++++++++++++ include/media/blackfin/bfin_display.h | 38 + 4 files changed, 1203 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/blackfin/bfin_display.c create mode 100644 include/media/blackfin/bfin_display.h
drivers/media/platform/blackfin/Kconfig +13 -2
@@ -9,7 +9,18 @@ config VIDEO_BLACKFIN_CAPTURE To compile this driver as a module, choose M here: the module will be called bfin_capture. +config VIDEO_BLACKFIN_DISPLAY + tristate "Blackfin Video Display Driver" + depends on VIDEO_V4L2 && BLACKFIN && I2C + select VIDEOBUF2_DMA_CONTIG + help + V4L2 bridge driver for Blackfin video display device. + Choose PPI or EPPI as its interface. + + To compile this driver as a module, choose M here: the + module will be called bfin_display. + config VIDEO_BLACKFIN_PPI tristate - depends on VIDEO_BLACKFIN_CAPTURE - default VIDEO_BLACKFIN_CAPTURE + depends on VIDEO_BLACKFIN_CAPTURE || VIDEO_BLACKFIN_DISPLAY + default VIDEO_BLACKFIN_CAPTURE || VIDEO_BLACKFIN_DISPLAY
drivers/media/platform/blackfin/Makefile +1 -0
@@ -1,2 +1,3 @@ obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_capture.o +obj-$(CONFIG_VIDEO_BLACKFIN_DISPLAY) += bfin_display.o obj-$(CONFIG_VIDEO_BLACKFIN_PPI) += ppi.o
drivers/media/platform/blackfin/bfin_display.c new file +1151 -0
1,151 lines not on this page · raw message
include/media/blackfin/bfin_display.h new file +38 -0
@@ -0,0 +1,38 @@ +#ifndef _BFIN_DISPLAY_H_ +#define _BFIN_DISPLAY_H_ + +#include <linux/i2c.h> + +struct v4l2_output ; +struct ppi_info ; + +struct disp_route { +u32 output; +u32 config; +u32 ppi_control; +}; + +struct bfin_display_config { +/* card name */ +char *card_name; +/* outputs available at the sub device */ +struct v4l2_output *outputs; +/* number of outputs supported */ +int num_outputs; +/* routing information for each output */ +struct disp_route *routes; +/* i2c bus adapter no */ +int i2c_adapter_id; +/* i2c subdevice board info */ +struct i2c_board_info board_info; +/* ppi board info */ +const struct ppi_info *ppi_info; +/* ppi control */ +u32 ppi_control; +/* ppi interrupt mask */ +u32 int_mask; +/* horizontal blanking pixels */ +int blank_pixels; +}; + +#endif
Signature · 1 line
1.7.0.4
Re: [PATCH RFC] [media] blackfin: add video display driver
Hello,
Quoted 19 lines · Scott Jiang
This is a bridge driver for blackfin diplay device. It can work with ppi or eppi interface. DV timings are supported.
Signed-off-by Scott Jiang<[email protected]>--- drivers/media/platform/blackfin/Kconfig | 15 +- drivers/media/platform/blackfin/Makefile | 1 + drivers/media/platform/blackfin/bfin_display.c | 1151 ++++++++++++++++++++++++ include/media/blackfin/bfin_display.h | 38 + 4 files changed, 1203 insertions(+), 2 deletions(-)create mode 100644
drivers/media/platform/blackfin/bfin_display.ccreate mode 100644include/media/blackfin/bfin_display.hdrivers/media/platform/blackfin/Kconfig +0
-0
drivers/media/platform/blackfin/Kconfig config VIDEO_BLACKFIN_CAPTURE · line 17
Quoted 9 lines
drivers/media/platform/blackfin/Kconfig +6
-0@@ -9,7 +9,18 @@ config VIDEO_BLACKFIN_CAPTURE To compile this driver as a module, choose M here: the module will be called bfin_capture. +config VIDEO_BLACKFIN_DISPLAY + tristate "Blackfin Video Display Driver" + depends on VIDEO_V4L2&& BLACKFIN&& I2C + select VIDEOBUF2_DMA_CONTIG + help + V4L2 bridge driver for Blackfin video display device.
Shouldn't it just be "V4L2 output driver", why are you calling it "bridge" ?
Quoted 25 lines
drivers/media/platform/blackfin/Kconfig +7
-2+ Choose PPI or EPPI as its interface. + + To compile this driver as a module, choose M here: the + module will be called bfin_display. + config VIDEO_BLACKFIN_PPI tristate - depends on VIDEO_BLACKFIN_CAPTURE - default VIDEO_BLACKFIN_CAPTURE + depends on VIDEO_BLACKFIN_CAPTURE || VIDEO_BLACKFIN_DISPLAY + default VIDEO_BLACKFIN_CAPTURE || VIDEO_BLACKFIN_DISPLAYdrivers/media/platform/blackfin/Makefile +1
-0@@ -1,2 +1,3 @@ obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_capture.o +obj-$(CONFIG_VIDEO_BLACKFIN_DISPLAY) += bfin_display.o obj-$(CONFIG_VIDEO_BLACKFIN_PPI) += ppi.odrivers/media/platform/blackfin/bfin_display.c new file +0
-0
drivers/media/platform/blackfin/bfin_display.c line 2
Quoted 2 lines
drivers/media/platform/blackfin/bfin_display.c new file +2
-0@@ -0,0 +1,1151 @@ +/* +* Analog Devices video display driver
Sounds a bit too generic.
drivers/media/platform/blackfin/bfin_display.c line 4
Quoted 2 lines
drivers/media/platform/blackfin/bfin_display.c new file +2
-0+* +* Copyright (c) 2011 Analog Devices Inc.
2011 - 2013 ?
Quoted 46 lines
drivers/media/platform/blackfin/bfin_display.c new file +46
-0+* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> + +#include <asm/dma.h> + +#include <media/blackfin/bfin_display.h> +#include <media/blackfin/ppi.h> + +#define DISPLAY_DRV_NAME "bfin_display" +#define DISP_MIN_NUM_BUF 2 + +struct disp_format { +char *desc; +u32 pixelformat; +enum v4l2_mbus_pixelcode mbus_code; +int bpp;/* bits per pixel */
drivers/media/platform/blackfin/bfin_display.c line 60
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+int dlen;/* data length for ppi in bits */ +}; + +struct disp_buffer { +struct vb2_buffer vb; +struct list_head list; +}; + +struct disp_device { +/* capture device instance */
Shouldn't it be "output device..." ?
drivers/media/platform/blackfin/bfin_display.c line 63
Quoted 3 lines
drivers/media/platform/blackfin/bfin_display.c new file +3
-0+struct v4l2_device v4l2_dev; +/* v4l2 control handler */ +struct v4l2_ctrl_handler ctrl_handler;
This handler seems to be unused, I couldn't find any code adding controls to it. Any initialization of this handler is a dead code now. You probably want to move that bits to a patch actually adding any controls.
Quoted 33 lines
drivers/media/platform/blackfin/bfin_display.c new file +33
-0+/* device node data */ +struct video_device *video_dev; +/* sub device instance */ +struct v4l2_subdev *sd; +/* capture config */ +struct bfin_display_config *cfg; +/* ppi interface */ +struct ppi_if *ppi; +/* current output */ +unsigned int cur_output; +/* 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 encoder supported format */ +struct disp_format *enc_formats; +/* number of encoder formats array */ +int num_enc_formats; +/* pointing to current video buffer */ +struct disp_buffer *cur_frm; +/* buffer queue used in videobuf2 */ +struct vb2_queue buffer_queue; +/* allocator-specific contexts for each plane */ +struct vb2_alloc_ctx *alloc_ctx; +/* queue of filled frames */ +struct list_head dma_queue; +/* used in videobuf2 callback */
drivers/media/platform/blackfin/bfin_display.c line 106
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+spinlock_t lock; +/* used to access display device */ +struct mutex mutex; +}; + +struct disp_fh { +struct v4l2_fh fh; +/* indicates whether this file handle is doing IO */ +bool io_allowed; +};
This structure should not be needed when you use the vb2 helpers. Please see below for more details.
Quoted 31 lines
drivers/media/platform/blackfin/bfin_display.c new file +31
-0+static const struct disp_format disp_formats[] = { + { + .desc ="YCbCr 4:2:2 Interleaved UYVY 8bits" , + .pixelformat =V4L2_PIX_FMT_UYVY , + .mbus_code =V4L2_MBUS_FMT_UYVY8_2X8 , + .bpp =16 , + .dlen =8 , + }, + { + .desc ="YCbCr 4:2:2 Interleaved YUYV 8bits" , + .pixelformat =V4L2_PIX_FMT_YUYV , + .mbus_code =V4L2_MBUS_FMT_YUYV8_2X8 , + .bpp =16 , + .dlen =8 , + }, + { + .desc ="YCbCr 4:2:2 Interleaved UYVY 16bits" , + .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" ,
drivers/media/platform/blackfin/bfin_display.c line 148
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ .pixelformat = V4L2_PIX_FMT_RGB444, + .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, + .bpp = 16, + .dlen = 8, + }, + +}; +#define DISP_MAX_FMTS ARRAY_SIZE(disp_formats) + +static irqreturn_t disp_isr (int irq,void *dev_id);
Couldn't the functions be reordered so this declaration can be avoided ?
Quoted 5 lines
drivers/media/platform/blackfin/bfin_display.c new file +5
-0+static int disp_open (struct file *file) +{ +struct disp_device *disp =video_drvdata (file); +struct video_device *vfd = disp->video_dev; +struct disp_fh *disp_fh;
drivers/media/platform/blackfin/bfin_display.c line 211
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +if (!disp->sd) { +v4l2_err (&disp->v4l2_dev,"No sub device registered\n" ); +return -ENODEV ; + } + + disp_fh =kzalloc (sizeof (*disp_fh),GFP_KERNEL ); +if (!disp_fh) { +v4l2_err (&disp->v4l2_dev, +"unable to allocate memory for file handle object\n" );
k*alloc functions already log any errors, you could just return -ENOMEM, without printing anything. There is similar occurrence in disp_probe.
Also it might be a good idea to make your function and data structure names more specific to this device, e.g. s/disp_*/bfin_disp_*.
Quoted 52 lines
drivers/media/platform/blackfin/bfin_display.c new file +51
-0+return -ENOMEM ; + } + +v4l2_fh_init (&disp_fh->fh, vfd); + +/* store pointer to v4l2_fh in private_data member of file */ + file->private_data =&disp_fh->fh; +v4l2_fh_add (&disp_fh->fh); + disp_fh->io_allowed = false; +return 0 ; +} +static int disp_reqbufs (struct file *file,void *priv, +struct v4l2_requestbuffers *req_buf) +{ +struct disp_device *disp =video_drvdata (file); +struct vb2_queue *vq =&disp->buffer_queue; +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +if (vb2_is_busy (vq)) +return -EBUSY ; + + disp_fh->io_allowed = true; + +return vb2_reqbufs (vq, req_buf); +} + +static int disp_querybuf (struct file *file,void *priv, +struct v4l2_buffer *buf) +{ +struct disp_device *disp =video_drvdata (file); + +return vb2_querybuf (&disp->buffer_queue, buf); +} + +static int disp_qbuf (struct file *file,void *priv, +struct v4l2_buffer *buf) +{ +struct disp_device *disp =video_drvdata (file); +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +if (!disp_fh->io_allowed) +return -EBUSY ; + +return vb2_qbuf (&disp->buffer_queue, buf); +} + +static int disp_dqbuf (struct file *file,void *priv, +struct v4l2_buffer *buf) +{
drivers/media/platform/blackfin/bfin_display.c line 322
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+struct disp_device *disp =video_drvdata (file); +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +if (!disp_fh->io_allowed) +return -EBUSY ; + +return vb2_dqbuf (&disp->buffer_queue, + buf, file->f_flags&O_NONBLOCK ); +}
I would suggest you have a look at the videobuf2 ioctl/fop helpers. Lots of boilerplate code can be removed when you use them. For an example see:
http://git.linuxtv.org/snawrocki/samsung.git/commitdiff/38b7d67224965bf09eaa3ce147bbebc7fa089411
Quoted 29 lines
drivers/media/platform/blackfin/bfin_display.c new file +29
-0+static int disp_probe (struct platform_device *pdev) +{ +struct disp_device *disp; +struct video_device *vfd; +struct i2c_adapter *i2c_adap; +struct bfin_display_config *config; +struct vb2_queue *q; +struct disp_route *route; +int ret; + + config = pdev->dev.platform_data; +if (!config) { +v4l2_err (pdev->dev.driver,"Unable to get board config\n" ); +return -ENODEV ; + } + + disp =kzalloc (sizeof (*disp),GFP_KERNEL ); +if (!disp) { +v4l2_err (pdev->dev.driver,"Unable to alloc disp\n" ); +return -ENOMEM ; + } + + disp->cfg = config; + + disp->ppi =ppi_create_instance (config->ppi_info); +if (!disp->ppi) { +v4l2_err (pdev->dev.driver,"Unable to create ppi\n" ); + ret = -ENODEV ; + goto err_free_dev;
drivers/media/platform/blackfin/bfin_display.c line 959
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ } + disp->ppi->priv = disp; + + disp->alloc_ctx =vb2_dma_contig_init_ctx (&pdev->dev); +if (IS_ERR (disp->alloc_ctx)) { + ret =PTR_ERR (disp->alloc_ctx); + goto err_free_ppi; + } + + vfd =video_device_alloc ();
Instead of this allocation you could embed struct video_device instance in struct disp_device...
drivers/media/platform/blackfin/bfin_display.c line 967
Quoted 8 lines
drivers/media/platform/blackfin/bfin_display.c new file +8
-0+if (!vfd) { + ret = -ENOMEM ; +v4l2_err (pdev->dev.driver,"Unable to alloc video device\n" ); + goto err_cleanup_ctx; + } + +/* initialize field of video device */ + vfd->release = video_device_release;
..and make this
vfd->release = video_device_release_empty;
Quoted 41 lines
drivers/media/platform/blackfin/bfin_display.c new file +41
-0+ vfd->fops =&disp_fops; + vfd->ioctl_ops =&disp_ioctl_ops; + vfd->tvnorms =0 ; + vfd->v4l2_dev =&disp->v4l2_dev; + vfd->vfl_dir =VFL_DIR_TX ; +set_bit (V4L2_FL_USE_FH_PRIO ,&vfd->flags); +strncpy (vfd->name,DISPLAY_DRV_NAME ,sizeof (vfd->name)); + disp->video_dev = vfd; + + ret =v4l2_device_register (&pdev->dev,&disp->v4l2_dev); +if (ret) { +v4l2_err (pdev->dev.driver, +"Unable to register v4l2 device\n" ); + goto err_release_vdev; + } +v4l2_info (&disp->v4l2_dev,"v4l2 device registered\n" ); + + disp->v4l2_dev.ctrl_handler =&disp->ctrl_handler; + ret =v4l2_ctrl_handler_init (&disp->ctrl_handler,0 ); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to init control handler\n" ); + goto err_unreg_v4l2; + } + +spin_lock_init (&disp->lock); +/* initialize queue */ + q =&disp->buffer_queue; + q->type =V4L2_BUF_TYPE_VIDEO_OUTPUT ; + q->io_modes =VB2_MMAP ; + q->drv_priv = disp; + q->buf_struct_size =sizeof (struct disp_buffer ); + q->ops =&disp_video_qops; + q->mem_ops =&vb2_dma_contig_memops; + + ret =vb2_queue_init (q); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to init videobuf2 queue\n" ); + goto err_free_handler; + }
drivers/media/platform/blackfin/bfin_display.c line 1018
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +mutex_init (&disp->mutex); + +/* init video dma queues */ +INIT_LIST_HEAD (&disp->dma_queue); + + vfd->lock =&disp->mutex; + +/* register video device */ + ret =video_register_device (disp->video_dev,VFL_TYPE_GRABBER ,-1 );
The video device should be registered as a last step, only when all resources it uses are already initialized.
Quoted 11 lines
drivers/media/platform/blackfin/bfin_display.c new file +11
-0+if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to register video device\n" ); + goto err_free_handler; + } +video_set_drvdata (disp->video_dev, disp); +v4l2_info (&disp->v4l2_dev,"video device registered as: %s\n" , +video_device_node_name (vfd)); + +/* load up the subdevice */ + i2c_adap =i2c_get_adapter (config->i2c_adapter_id);
drivers/media/platform/blackfin/bfin_display.c line 1039
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+if (!i2c_adap) { +v4l2_err (&disp->v4l2_dev, +"Unable to find i2c adapter\n" ); + goto err_unreg_vdev; + + } + disp->sd =v4l2_i2c_new_subdev_board (&disp->v4l2_dev, + i2c_adap, + &config->board_info, +NULL );
nit: I bit strange indentation, you could probably just fit it in 2 lines.
Quoted 72 lines
drivers/media/platform/blackfin/bfin_display.c new file +72
-0+if (disp->sd) { +int i; +if (!config->num_outputs) { +v4l2_err (&disp->v4l2_dev, +"Unable to work without output\n" ); + goto err_unreg_vdev; + } + +/* update tvnorms from the sub devices */ +for (i =0 ; i< config->num_outputs; i++) + vfd->tvnorms |= config->outputs[i].std; + }else { +v4l2_err (&disp->v4l2_dev, +"Unable to register sub device\n" ); + goto err_unreg_vdev; + } + +v4l2_info (&disp->v4l2_dev,"v4l2 sub device registered\n" ); + +/* +* explicitly set output, otherwise some boards +* may not work at the state as we expected +*/ + route =&config->routes[0 ]; + ret =v4l2_subdev_call (disp->sd, video, s_routing, + route->output, route->output,0 ); +if ((ret<0 )&& (ret != -ENOIOCTLCMD )) { +v4l2_err (&disp->v4l2_dev,"Failed to set output\n" ); + goto err_unreg_vdev; + } + disp->cur_output =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 (config->outputs[0 ].capabilities&V4L2_IN_CAP_STD ) { +v4l2_std_id std; + ret =v4l2_subdev_call (disp->sd, core, g_std,&std); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to get std\n" ); + goto err_unreg_vdev; + } + disp->std = std; + } +if (config->outputs[0 ].capabilities&V4L2_IN_CAP_CUSTOM_TIMINGS ) { +struct v4l2_dv_timings dv_timings; + ret =v4l2_subdev_call (disp->sd, video, + g_dv_timings,&dv_timings); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to get dv timings\n" ); + goto err_unreg_vdev; + } + disp->dv_timings = dv_timings; + } + ret =disp_init_encoder_formats (disp); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to create encoder formats table\n" ); + goto err_unreg_vdev; + } +return 0 ; +err_unreg_vdev: +video_unregister_device (disp->video_dev); + disp->video_dev =NULL ; +err_free_handler: +v4l2_ctrl_handler_free (&disp->ctrl_handler); +err_unreg_v4l2: +v4l2_device_unregister (&disp->v4l2_dev); +err_release_vdev:
drivers/media/platform/blackfin/bfin_display.c line 1121
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+if (disp->video_dev) +video_device_release (disp->video_dev); +err_cleanup_ctx: +vb2_dma_contig_cleanup_ctx (disp->alloc_ctx); +err_free_ppi: +ppi_delete_instance (disp->ppi); +err_free_dev: +kfree (disp); +return ret; +}
Regards,
Sylwester
Re: [PATCH RFC] [media] blackfin: add video display driver
Hi Sylwester ,
Quoted 4 lines
Quoted 4 lines
drivers/media/platform/blackfin/Kconfig +0
-0@@ -9,7 +9,18 @@ config VIDEO_BLACKFIN_CAPTURE To compile this driver as a module, choose M here: the module will be called bfin_capture.
Quoted 10 lines
drivers/media/platform/blackfin/Kconfig config VIDEO_BLACKFIN_CAPTURE · line 17
Quoted 6 lines
drivers/media/platform/blackfin/Kconfig +6
-0+config VIDEO_BLACKFIN_DISPLAY + tristate "Blackfin Video Display Driver" + depends on VIDEO_V4L2&& BLACKFIN&& I2C + select VIDEOBUF2_DMA_CONTIG + help + V4L2 bridge driver for Blackfin video display device.Shouldn't it just be "V4L2 output driver", why are you calling it "bridge" ?
Hmm, capture<->display, input<->output, right?
The kernel docs called it bridge, may "host" sounds better.
Quoted 4 lines
drivers/media/platform/blackfin/bfin_display.c line 2
Quoted 2 lines
drivers/media/platform/blackfin/bfin_display.c new file +2
-0+/* +* Analog Devices video display driver
Quoted 8 lines
Sounds a bit too generic.
drivers/media/platform/blackfin/bfin_display.c line 4
Quoted 2 lines
drivers/media/platform/blackfin/bfin_display.c new file +2
-0+* +* Copyright (c) 2011 Analog Devices Inc. 2011 - 2013 ?
Written in 2011.
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c line 106
Quoted 5 lines
drivers/media/platform/blackfin/bfin_display.c new file +5
-0+struct disp_fh { +struct v4l2_fh fh; +/* indicates whether this file handle is doing IO */ +bool io_allowed; +};This structure should not be needed when you use the vb2 helpers. Please see below for more details.
The only question is how the core deal with the permission that which file handle can
stream off the output. I want to impose a rule that only IO handle can stop IO. I refer to priority, but current kernel driver export this to user space and let user decide it.
Re: [PATCH RFC] [media] blackfin: add video display driver
Hi Scott,
Quoted 16 lines · Scott Jiang
Hi Sylwester ,
Quoted 4 lines
Quoted 4 lines
drivers/media/platform/blackfin/Kconfig +0
-0@@ -9,7 +9,18 @@ config VIDEO_BLACKFIN_CAPTURE To compile this driver as a module, choose M here: the module will be called bfin_capture.Quoted 10 lines
drivers/media/platform/blackfin/Kconfig config VIDEO_BLACKFIN_CAPTURE · line 17
Quoted 6 lines
drivers/media/platform/blackfin/Kconfig +6
-0+config VIDEO_BLACKFIN_DISPLAY + tristate "Blackfin Video Display Driver" + depends on VIDEO_V4L2&& BLACKFIN&& I2C + select VIDEOBUF2_DMA_CONTIG + help + V4L2 bridge driver for Blackfin video display device.Shouldn't it just be "V4L2 output driver", why are you calling it "bridge" ?
Quoted 1 line
Hmm, capture<->display, input<->output, right?
Yes, input/output from user space POV.
Quoted 1 line
The kernel docs called it bridge, may "host" sounds better.
I suggested "output" as referring to the "V4L2 output interface" [1]. I guess bridge/host could just be skipped and we could simply put it as:
"V4L2 driver for Blackfin video display (E)PPI interface."
Quoted 6 lines
Quoted 6 lines
drivers/media/platform/blackfin/bfin_display.c line 2
Quoted 2 lines
drivers/media/platform/blackfin/bfin_display.c new file +2
-0+/* +* Analog Devices video display driver Sounds a bit too generic.
Quoted 7 lines
Quoted 6 lines
drivers/media/platform/blackfin/bfin_display.c line 4
Quoted 2 lines
drivers/media/platform/blackfin/bfin_display.c new file +2
-0+* +* Copyright (c) 2011 Analog Devices Inc. 2011 - 2013 ?
Written in 2011.
Since you're still actively working on it I would say it makes sense to put it as 2011 - 2013. At least this is what most people do AFAICS. But I don't really mind, it's up to you!
Quoted 10 lines
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c line 106
Quoted 5 lines
drivers/media/platform/blackfin/bfin_display.c new file +5
-0+struct disp_fh { +struct v4l2_fh fh; +/* indicates whether this file handle is doing IO */ +bool io_allowed; +};This structure should not be needed when you use the vb2 helpers. Please see below for more details.
Quoted 5 lines
The only question is how the core deal with the permission that which file handle can
stream off the output. I want to impose a rule that only IO handle can stop IO. I refer to priority, but current kernel driver export this to user space and let user decide it.
As far as I can see there would be no change in behaviour if you used the helpers. For instance, vidioc_streamon/streamoff ioctls
/* From videobuf2-core.c */
/* The queue is busy if there is a owner and you are not that owner. */ static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file)
{
return vdev->queue->owner && vdev->queue->owner != file->private_data;
}/* vb2 ioctl helpers */
int vb2_ioctl_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
struct video_device *vdev = video_devdata(file);
int res = __verify_memory_type(vdev->queue, p->memory, p->type);
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
res = __reqbufs(vdev->queue, p);
/* If count == 0, then the owner has released all buffers and he
is no longer owner of the queue. Otherwise we have a new owner. */
if (res == 0)
vdev->queue->owner = p->count ? file->private_data : NULL;
return res;
}int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
return vb2_streamon(vdev->queue, i);
}int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
return vb2_streamoff(vdev->queue, i);
}And in your code:
+static int disp_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req_buf)
+{
+ struct disp_device *disp = video_drvdata(file);
+ struct vb2_queue *vq = &disp->buffer_queue;
+ struct v4l2_fh *fh = file->private_data;
+ struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh);
+
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ disp_fh->io_allowed = true;
+
+ return vb2_reqbufs(vq, req_buf);
+}
+static int disp_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct disp_device *disp = video_drvdata(file);
+ struct disp_fh *fh = file->private_data;
+ struct ppi_if *ppi = disp->ppi;
+ dma_addr_t addr;
+ int ret;
+
+ if (!fh->io_allowed)
+ return -EBUSY;
+
+ /* call streamon to start streaming in videobuf */
+ ret = vb2_streamon(&disp->buffer_queue, buf_type);
+ if (ret)
+ return ret;
+
...
+}
+static int disp_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct disp_device *disp = video_drvdata(file);
+ struct disp_fh *fh = file->private_data;
+
+ if (!fh->io_allowed)
+ return -EBUSY;
+
+ return vb2_streamoff(&disp->buffer_queue, buf_type);
+}
Please note that you really should be setting io_allowed to true only if vb2_reqbufs() succeeds.
Hence I wouldn't hesitate to use the core implementation. This way we get more consistent behaviour across all drivers, which is in line with what you have currently implemented AFAICT.
[1] http://linuxtv.org/downloads/v4l-dvb-apis/devices.html#output
Thanks,
Sylwester
Re: [PATCH RFC] [media] blackfin: add video display driver
In reply to Sylwester NawrockiHi Sylwester,
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c line 63
Quoted 4 lines
drivers/media/platform/blackfin/bfin_display.c new file +3
-0+struct v4l2_device v4l2_dev; +/* v4l2 control handler */ +struct v4l2_ctrl_handler ctrl_handler;This handler seems to be unused, I couldn't find any code adding controls to it. Any initialization of this handler is a dead code now. You probably want to move that bits to a patch actually adding any controls.
This host driver doesn't support any control but without it subdev controls can't be accessed.v4l2_ctrl_add_handler should just return 0 if v4l2_dev->ctrl_handler is NULL.
Re: [PATCH RFC] [media] blackfin: add video display driver
Hi Scott,
Quoted 6 lines · Scott Jiang
Quoted 6 lines
Quoted 4 lines
drivers/media/platform/blackfin/bfin_display.c new file +3
-0+struct v4l2_device v4l2_dev; +/* v4l2 control handler */ +struct v4l2_ctrl_handler ctrl_handler;
Quoted 8 lines
Quoted 4 lines
This handler seems to be unused, I couldn't find any code adding controls to it. Any initialization of this handler is a dead code now. You probably want to move that bits to a patch actually adding any controls.
This host driver doesn't support any control but without it subdev controls can't be accessed.
v4l2_ctrl_add_handlershould just return 0 ifv4l2_dev->ctrl_handleris NULL.
You're right, I missed the point that a video device could expose just controls inherited from subdevs. And for that its control handler need to be initialized. So I didn't help you too much with that comment, please just ignore it.
Regards,
Sylwester
Re: [PATCH RFC] [media] blackfin: add video display driver
In reply to Scott JiangHi Scott!
Quoted 3 lines · On Sat April 13 2013 01:52:58 Scott Jiang wrote:
This is a bridge driver for blackfin diplay device. It can work with ppi or eppi interface. DV timings are supported.
Thanks for the patch. There are a number of comments below. For the most part you can save a lot of code by making a few fairly small changes.
Quoted 50 lines
Signed-off-by Scott Jiang <[email protected]>--- drivers/media/platform/blackfin/Kconfig | 15 +- drivers/media/platform/blackfin/Makefile | 1 + drivers/media/platform/blackfin/bfin_display.c | 1151 ++++++++++++++++++++++++ include/media/blackfin/bfin_display.h | 38 + 4 files changed, 1203 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/blackfin/bfin_display.c create mode 100644 include/media/blackfin/bfin_display.hdrivers/media/platform/blackfin/Kconfig +13
-2@@ -9,7 +9,18 @@ config VIDEO_BLACKFIN_CAPTURE To compile this driver as a module, choose M here: the module will be called bfin_capture. +config VIDEO_BLACKFIN_DISPLAY + tristate "Blackfin Video Display Driver" + depends on VIDEO_V4L2 && BLACKFIN && I2C + select VIDEOBUF2_DMA_CONTIG + help + V4L2 bridge driver for Blackfin video display device. + Choose PPI or EPPI as its interface. + + To compile this driver as a module, choose M here: the + module will be called bfin_display. + config VIDEO_BLACKFIN_PPI tristate - depends on VIDEO_BLACKFIN_CAPTURE - default VIDEO_BLACKFIN_CAPTURE + depends on VIDEO_BLACKFIN_CAPTURE || VIDEO_BLACKFIN_DISPLAY + default VIDEO_BLACKFIN_CAPTURE || VIDEO_BLACKFIN_DISPLAYdrivers/media/platform/blackfin/Makefile +1
-0@@ -1,2 +1,3 @@ obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_capture.o +obj-$(CONFIG_VIDEO_BLACKFIN_DISPLAY) += bfin_display.o obj-$(CONFIG_VIDEO_BLACKFIN_PPI) += ppi.odrivers/media/platform/blackfin/bfin_display.c new file +0
-0
drivers/media/platform/blackfin/bfin_display.c line 4
Quoted 4 lines
drivers/media/platform/blackfin/bfin_display.c new file +4
-0@@ -0,0 +1,1151 @@ +/* +* Analog Devices video display driver +* +* Copyright (c) 2011 Analog Devices Inc.
Analog Devices? What has this to do with Analog Devices?
Quoted 191 lines
drivers/media/platform/blackfin/bfin_display.c new file +191
-0+* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> + +#include <asm/dma.h> + +#include <media/blackfin/bfin_display.h> +#include <media/blackfin/ppi.h> + +#define DISPLAY_DRV_NAME "bfin_display" +#define DISP_MIN_NUM_BUF 2 + +struct disp_format { +char *desc; +u32 pixelformat; +enum v4l2_mbus_pixelcode mbus_code; +int bpp;/* bits per pixel */ +int dlen;/* data length for ppi in bits */ +}; + +struct disp_buffer { +struct vb2_buffer vb; +struct list_head list; +}; + +struct disp_device { +/* capture device instance */ +struct v4l2_device v4l2_dev; +/* v4l2 control handler */ +struct v4l2_ctrl_handler ctrl_handler; +/* device node data */ +struct video_device *video_dev; +/* sub device instance */ +struct v4l2_subdev *sd; +/* capture config */ +struct bfin_display_config *cfg; +/* ppi interface */ +struct ppi_if *ppi; +/* current output */ +unsigned int cur_output; +/* 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 encoder supported format */ +struct disp_format *enc_formats; +/* number of encoder formats array */ +int num_enc_formats; +/* pointing to current video buffer */ +struct disp_buffer *cur_frm; +/* buffer queue used in videobuf2 */ +struct vb2_queue buffer_queue; +/* allocator-specific contexts for each plane */ +struct vb2_alloc_ctx *alloc_ctx; +/* queue of filled frames */ +struct list_head dma_queue; +/* used in videobuf2 callback */ +spinlock_t lock; +/* used to access display device */ +struct mutex mutex; +}; + +struct disp_fh { +struct v4l2_fh fh; +/* indicates whether this file handle is doing IO */ +bool io_allowed; +}; + +static const struct disp_format disp_formats[] = { + { + .desc ="YCbCr 4:2:2 Interleaved UYVY 8bits" , + .pixelformat =V4L2_PIX_FMT_UYVY , + .mbus_code =V4L2_MBUS_FMT_UYVY8_2X8 , + .bpp =16 , + .dlen =8 , + }, + { + .desc ="YCbCr 4:2:2 Interleaved YUYV 8bits" , + .pixelformat =V4L2_PIX_FMT_YUYV , + .mbus_code =V4L2_MBUS_FMT_YUYV8_2X8 , + .bpp =16 , + .dlen =8 , + }, + { + .desc ="YCbCr 4:2:2 Interleaved UYVY 16bits" , + .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 , + }, + +}; +#define DISP_MAX_FMTS ARRAY_SIZE(disp_formats) + +static irqreturn_t disp_isr (int irq,void *dev_id); + +static struct disp_buffer *to_disp_vb (struct vb2_buffer *vb) +{ + return container_of(vb, struct disp_buffer, vb); +} + +static int disp_init_encoder_formats (struct disp_device *disp) +{ +enum v4l2_mbus_pixelcode code; +struct disp_format *df; +unsigned int num_formats =0 ; +int i, j; + +while (!v4l2_subdev_call (disp->sd, video, + enum_mbus_fmt, num_formats, &code)) + num_formats++; +if (!num_formats) +return -ENXIO ; + + df =kzalloc (num_formats *sizeof (*df),GFP_KERNEL ); +if (!df) +return -ENOMEM ; + +for (i =0 ; i < num_formats; i++) { +v4l2_subdev_call (disp->sd, video, + enum_mbus_fmt, i, &code); +for (j =0 ; j <DISP_MAX_FMTS ; j++) +if (code == disp_formats[j].mbus_code) +break ; +if (j ==DISP_MAX_FMTS ) { +/* we don't allow this encoder working with our bridge */ +kfree (df); +return -EINVAL ; + } + df[i] = disp_formats[j]; + } + disp->enc_formats = df; + disp->num_enc_formats = num_formats; +return 0 ; +} + +static void disp_free_encoder_formats (struct disp_device *disp) +{ + disp->num_enc_formats =0 ; +kfree (disp->enc_formats); + disp->enc_formats =NULL ; +}
drivers/media/platform/blackfin/bfin_display.c line 205
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +static int disp_open (struct file *file) +{ +struct disp_device *disp =video_drvdata (file); +struct video_device *vfd = disp->video_dev; +struct disp_fh *disp_fh; + +if (!disp->sd) { +v4l2_err (&disp->v4l2_dev,"No sub device registered\n" ); +return -ENODEV ;
You know at probe time whether there are subdevices or not. If not, then just don't register the video node at all.
Quoted 69 lines
drivers/media/platform/blackfin/bfin_display.c new file +69
-0+ } + + disp_fh =kzalloc (sizeof (*disp_fh),GFP_KERNEL ); +if (!disp_fh) { +v4l2_err (&disp->v4l2_dev, +"unable to allocate memory for file handle object\n" ); +return -ENOMEM ; + } + +v4l2_fh_init (&disp_fh->fh, vfd); + +/* store pointer to v4l2_fh in private_data member of file */ + file->private_data = &disp_fh->fh; +v4l2_fh_add (&disp_fh->fh); + disp_fh->io_allowed = false; +return 0 ; +} + +static int disp_release (struct file *file) +{ +struct disp_device *disp =video_drvdata (file); +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +/* if this instance is doing IO */ +if (disp_fh->io_allowed) +vb2_queue_release (&disp->buffer_queue); + + file->private_data =NULL ; +v4l2_fh_del (&disp_fh->fh); +v4l2_fh_exit (&disp_fh->fh); +kfree (disp_fh); +return 0 ; +} + +static int disp_mmap (struct file *file,struct vm_area_struct *vma) +{ +struct disp_device *disp =video_drvdata (file); +int ret; + +if (mutex_lock_interruptible (&disp->mutex)) +return -ERESTARTSYS ; + ret =vb2_mmap (&disp->buffer_queue, vma); +mutex_unlock (&disp->mutex); +return ret; +} + +#ifndef CONFIG_MMU +static unsigned long disp_get_unmapped_area (struct file *file, +unsigned long addr, +unsigned long len, +unsigned long pgoff, +unsigned long flags) +{ +struct disp_device *disp =video_drvdata (file); +int ret; + +if (mutex_lock_interruptible (&disp->mutex)) +return -ERESTARTSYS ; + ret =vb2_get_unmapped_area (&disp->buffer_queue, + addr, + len, + pgoff, + flags); +mutex_unlock (&disp->mutex); +return ret; +} +#endif +
drivers/media/platform/blackfin/bfin_display.c line 284
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+static unsigned int disp_poll (struct file *file,poll_table *wait) +{ +struct disp_device *disp =video_drvdata (file); +int ret; + +mutex_lock (&disp->mutex); + ret =vb2_poll (&disp->buffer_queue, file, wait); +mutex_unlock (&disp->mutex); +return ret; +}
Use the helper functions in media/videobuf2-core.h for these file ops.
Quoted 66 lines
drivers/media/platform/blackfin/bfin_display.c new file +66
-0+ +static int disp_queue_setup (struct vb2_queue *vq, +const struct v4l2_format *fmt, +unsigned int *nbuffers,unsigned int *nplanes, +unsigned int sizes[],void *alloc_ctxs[]) +{ +struct disp_device *disp =vb2_get_drv_priv (vq); + +if (*nbuffers <DISP_MIN_NUM_BUF ) + *nbuffers =DISP_MIN_NUM_BUF ; + + *nplanes =1 ; + sizes[0 ] = disp->fmt.sizeimage; + alloc_ctxs[0 ] = disp->alloc_ctx; + +return 0 ; +} + +static int disp_buffer_init (struct vb2_buffer *vb) +{ +struct disp_buffer *buf =to_disp_vb (vb); + +INIT_LIST_HEAD (&buf->list); +return 0 ; +} + +static int disp_buffer_prepare (struct vb2_buffer *vb) +{ +struct disp_device *disp =vb2_get_drv_priv (vb->vb2_queue); +struct disp_buffer *buf =to_disp_vb (vb); +unsigned long size; + + size = disp->fmt.sizeimage; +if (vb2_plane_size (vb,0 ) < size) { +v4l2_err (&disp->v4l2_dev,"buffer too small (%lu < %lu)\n" , +vb2_plane_size (vb,0 ), size); +return -EINVAL ; + } +vb2_set_plane_payload (&buf->vb,0 , size); + +return 0 ; +} + +static void disp_buffer_queue (struct vb2_buffer *vb) +{ +struct disp_device *disp =vb2_get_drv_priv (vb->vb2_queue); +struct disp_buffer *buf =to_disp_vb (vb); +unsigned long flags; + +spin_lock_irqsave (&disp->lock, flags); +list_add_tail (&buf->list, &disp->dma_queue); +spin_unlock_irqrestore (&disp->lock, flags); +} + +static void disp_buffer_cleanup (struct vb2_buffer *vb) +{ +struct disp_device *disp =vb2_get_drv_priv (vb->vb2_queue); +struct disp_buffer *buf =to_disp_vb (vb); +unsigned long flags; + +spin_lock_irqsave (&disp->lock, flags); +list_del_init (&buf->list); +spin_unlock_irqrestore (&disp->lock, flags); +} + +static void disp_lock (struct vb2_queue *vq)
drivers/media/platform/blackfin/bfin_display.c line 360
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+{ +struct disp_device *disp =vb2_get_drv_priv (vq); +mutex_lock (&disp->mutex); +} + +static void disp_unlock (struct vb2_queue *vq) +{ +struct disp_device *disp =vb2_get_drv_priv (vq); +mutex_unlock (&disp->mutex); +}
Use helper functions for this.
Quoted 14 lines
drivers/media/platform/blackfin/bfin_display.c new file +14
-0+ +static int disp_start_streaming (struct vb2_queue *vq,unsigned int count) +{ +struct disp_device *disp =vb2_get_drv_priv (vq); +struct ppi_if *ppi = disp->ppi; +struct ppi_params params; +int ret; + +/* enable streamon on the sub device */ + ret =v4l2_subdev_call (disp->sd, video, s_stream,1 ); +if (ret && (ret != -ENOIOCTLCMD )) { +v4l2_err (&disp->v4l2_dev,"stream on failed in subdev\n" ); +return ret; + }
drivers/media/platform/blackfin/bfin_display.c line 384
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +/* set ppi params */ + params.width = disp->fmt.width; + params.height = disp->fmt.height; + params.bpp = disp->bpp; + params.dlen = disp->dlen; + params.ppi_control = disp->cfg->ppi_control; + params.int_mask = disp->cfg->int_mask; +if (disp->cfg->outputs[disp->cur_output].capabilities + &V4L2_IN_CAP_CUSTOM_TIMINGS ) {
_CUSTOM_TIMINGS has been renamed to _DV_TIMINGS.
Quoted 91 lines
drivers/media/platform/blackfin/bfin_display.c new file +91
-0+struct v4l2_bt_timings *bt = &disp->dv_timings.bt; + + params.hdelay = bt->hsync + bt->hbackporch; + params.vdelay = bt->vsync + 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; + params.hsync = bt->hsync; + params.vsync = bt->vsync; + }else if (disp->cfg->outputs[disp->cur_output].capabilities + &V4L2_IN_CAP_STD ) { + params.hdelay =0 ; + params.vdelay =0 ; +if (disp->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 + disp->cfg->blank_pixels; + params.frame = params.height; + } + ret = ppi->ops->set_params (ppi, ¶ms); +if (ret <0 ) { +v4l2_err (&disp->v4l2_dev, +"Error in setting ppi params\n" ); +return ret; + } + +/* attach ppi DMA irq handler */ + ret = ppi->ops->attach_irq (ppi, disp_isr); +if (ret <0 ) { +v4l2_err (&disp->v4l2_dev, +"Error in attaching interrupt handler\n" ); +return ret; + } + +return 0 ; +} + +static int disp_stop_streaming (struct vb2_queue *vq) +{ +struct disp_device *disp =vb2_get_drv_priv (vq); +struct ppi_if *ppi = disp->ppi; +unsigned long flags; +int ret; + +if (!vb2_is_streaming (vq)) +return 0 ; + + ppi->ops->stop (ppi); + ppi->ops->detach_irq (ppi); + ret =v4l2_subdev_call (disp->sd, video, s_stream,0 ); +if (ret && (ret != -ENOIOCTLCMD )) +v4l2_err (&disp->v4l2_dev, +"stream off failed in subdev\n" ); + +spin_lock_irqsave (&disp->lock, flags); +/* release all active buffers */ +while (!list_empty (&disp->dma_queue)) { + disp->cur_frm =list_entry (disp->dma_queue.next, + struct disp_buffer, list); +list_del (&disp->cur_frm->list); +vb2_buffer_done (&disp->cur_frm->vb,VB2_BUF_STATE_ERROR ); + } +spin_unlock_irqrestore (&disp->lock, flags); +return 0 ; +} + +static struct vb2_ops disp_video_qops = { + .queue_setup = disp_queue_setup, + .buf_init = disp_buffer_init, + .buf_prepare = disp_buffer_prepare, + .buf_cleanup = disp_buffer_cleanup, + .buf_queue = disp_buffer_queue, + .wait_prepare = disp_unlock, + .wait_finish = disp_lock, + .start_streaming = disp_start_streaming, + .stop_streaming = disp_stop_streaming, +}; + +static int disp_reqbufs (struct file *file,void *priv, +struct v4l2_requestbuffers *req_buf)
drivers/media/platform/blackfin/bfin_display.c line 485
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+{ +struct disp_device *disp =video_drvdata (file); +struct vb2_queue *vq = &disp->buffer_queue; +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +if (vb2_is_busy (vq)) +return -EBUSY ; + + disp_fh->io_allowed = true;
There is no need for io_allowed. The vb2_is_busy() function does the same thing. It saves a lot of code since you now can just use v4l2_fh instead of disp_fh, which allows you to use even more helper functions (v4l2_fh_open and v4l2_fh_release for starters).
In fact, you can use all the vb2 ioctl helpers saving you a lot of code.
Quoted 42 lines
drivers/media/platform/blackfin/bfin_display.c new file +42
-0+ +return vb2_reqbufs (vq, req_buf); +} + +static int disp_querybuf (struct file *file,void *priv, +struct v4l2_buffer *buf) +{ +struct disp_device *disp =video_drvdata (file); + +return vb2_querybuf (&disp->buffer_queue, buf); +} + +static int disp_qbuf (struct file *file,void *priv, +struct v4l2_buffer *buf) +{ +struct disp_device *disp =video_drvdata (file); +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +if (!disp_fh->io_allowed) +return -EBUSY ; + +return vb2_qbuf (&disp->buffer_queue, buf); +} + +static int disp_dqbuf (struct file *file,void *priv, +struct v4l2_buffer *buf) +{ +struct disp_device *disp =video_drvdata (file); +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +if (!disp_fh->io_allowed) +return -EBUSY ; + +return vb2_dqbuf (&disp->buffer_queue, + buf, file->f_flags &O_NONBLOCK ); +} + +static irqreturn_t disp_isr (int irq,void *dev_id) +{ +struct ppi_if *ppi = dev_id;
drivers/media/platform/blackfin/bfin_display.c line 537
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+struct disp_device *disp = ppi->priv; +struct timeval timevalue; +struct vb2_buffer *vb = &disp->cur_frm->vb; +dma_addr_t addr; + +spin_lock (&disp->lock); + +if (!list_empty (&disp->dma_queue)) { +do_gettimeofday (&timevalue); + vb->v4l2_buf.timestamp = timevalue;
NACK. Use v4l2_get_timestamp and set vb2_queue's 'timestamp_type' field to V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC.
Quoted 41 lines
drivers/media/platform/blackfin/bfin_display.c new file +41
-0+vb2_buffer_done (vb,VB2_BUF_STATE_DONE ); + disp->cur_frm =list_entry (disp->dma_queue.next, + struct disp_buffer, list); +list_del (&disp->cur_frm->list); + } + +clear_dma_irqstat (ppi->info->dma_ch); + + addr =vb2_dma_contig_plane_dma_addr (&disp->cur_frm->vb,0 ); + ppi->ops->update_addr (ppi, (unsigned long )addr); + ppi->ops->start (ppi); + +spin_unlock (&disp->lock); + +return IRQ_HANDLED ; +} + +static int disp_streamon (struct file *file,void *priv, +enum v4l2_buf_type buf_type) +{ +struct disp_device *disp =video_drvdata (file); +struct disp_fh *fh = file->private_data; +struct ppi_if *ppi = disp->ppi; +dma_addr_t addr; +int ret; + +if (!fh->io_allowed) +return -EBUSY ; + +/* call streamon to start streaming in videobuf */ + ret =vb2_streamon (&disp->buffer_queue, buf_type); +if (ret) +return ret; + +/* if dma queue is empty, return error */ +if (list_empty (&disp->dma_queue)) { +v4l2_err (&disp->v4l2_dev,"dma queue is empty\n" ); + ret = -EINVAL ; + goto err; + } +
drivers/media/platform/blackfin/bfin_display.c line 588
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+/* get the next frame from the dma queue */ + disp->cur_frm =list_entry (disp->dma_queue.next, + struct disp_buffer, list); +/* remove buffer from the dma queue */ +list_del (&disp->cur_frm->list); + addr =vb2_dma_contig_plane_dma_addr (&disp->cur_frm->vb,0 ); +/* update DMA address */ + ppi->ops->update_addr (ppi, (unsigned long )addr); +/* enable ppi */ + ppi->ops->start (ppi);
All this belongs in the start_streaming vb2_op.
Quoted 13 lines
drivers/media/platform/blackfin/bfin_display.c new file +13
-0+ +return 0 ; +err: +vb2_streamoff (&disp->buffer_queue, buf_type); +return ret; +} + +static int disp_streamoff (struct file *file,void *priv, +enum v4l2_buf_type buf_type) +{ +struct disp_device *disp =video_drvdata (file); +struct disp_fh *fh = file->private_data; +
drivers/media/platform/blackfin/bfin_display.c line 611
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+if (!fh->io_allowed) +return -EBUSY ; + +return vb2_streamoff (&disp->buffer_queue, buf_type); +} + +static int disp_g_std (struct file *file,void *priv,v4l2_std_id *std) +{ +struct disp_device *disp =video_drvdata (file); +
Check if the current output supports STD and if not, return -ENODATA. Ditto for S_STD.
Quoted 16 lines
drivers/media/platform/blackfin/bfin_display.c new file +16
-0+ *std = disp->std; +return 0 ; +} + +static int disp_s_std (struct file *file,void *priv,v4l2_std_id *std) +{ +struct disp_device *disp =video_drvdata (file); +int ret; + +if (vb2_is_busy (&disp->buffer_queue)) +return -EBUSY ; + + ret =v4l2_subdev_call (disp->sd, video, s_std_output, *std); +if (ret <0 ) +return ret; +
drivers/media/platform/blackfin/bfin_display.c line 637
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ disp->std = *std; +return 0 ; +} + +static int disp_g_dv_timings (struct file *file,void *priv, +struct v4l2_dv_timings *timings) +{ +struct disp_device *disp =video_drvdata (file); +int ret; +
Check if this output supports DV_TIMINGS, and if not return -ENODATA. Ditto for s_dv_timings.
Quoted 109 lines
drivers/media/platform/blackfin/bfin_display.c new file +109
-0+ ret =v4l2_subdev_call (disp->sd, video, + g_dv_timings, timings); +if (ret <0 ) +return ret; + + disp->dv_timings = *timings; +return 0 ; +} + +static int disp_s_dv_timings (struct file *file,void *priv, +struct v4l2_dv_timings *timings) +{ +struct disp_device *disp =video_drvdata (file); +int ret; +if (vb2_is_busy (&disp->buffer_queue)) +return -EBUSY ; + + ret =v4l2_subdev_call (disp->sd, video, s_dv_timings, timings); +if (ret <0 ) +return ret; + + disp->dv_timings = *timings; +return 0 ; +} + +static int disp_enum_output (struct file *file,void *priv, +struct v4l2_output *output) +{ +struct disp_device *disp =video_drvdata (file); +struct bfin_display_config *config = disp->cfg; + +if (output->index >= config->num_outputs) +return -EINVAL ; + + *output = config->outputs[output->index]; +return 0 ; +} + +static int disp_g_output (struct file *file,void *priv,unsigned int *index) +{ +struct disp_device *disp =video_drvdata (file); + + *index = disp->cur_output; +return 0 ; +} + +static int disp_s_output (struct file *file,void *priv,unsigned int index) +{ +struct disp_device *disp =video_drvdata (file); +struct bfin_display_config *config = disp->cfg; +struct disp_route *route; +int ret; + +if (vb2_is_busy (&disp->buffer_queue)) +return -EBUSY ; + +if (index >= config->num_outputs) +return -EINVAL ; + + route = &config->routes[index]; + ret =v4l2_subdev_call (disp->sd, video, s_routing, +0 , route->output, route->config); +if ((ret <0 ) && (ret != -ENOIOCTLCMD )) { +v4l2_err (&disp->v4l2_dev,"Failed to set output\n" ); +return ret; + } + disp->cur_output = index; +/* if this route has specific config, update ppi control */ +if (route->ppi_control) + config->ppi_control = route->ppi_control; +return 0 ; +} + +static int disp_try_format (struct disp_device *disp, +struct v4l2_pix_format *pixfmt, +struct disp_format *disp_fmt) +{ +struct disp_format *df = disp->enc_formats; +struct disp_format *fmt =NULL ; +struct v4l2_mbus_framefmt mbus_fmt; +int ret, i; + +for (i =0 ; i < disp->num_enc_formats; i++) { + fmt = &df[i]; +if (pixfmt->pixelformat == fmt->pixelformat) +break ; + } +if (i == disp->num_enc_formats) + fmt = &df[0 ]; + +v4l2_fill_mbus_format (&mbus_fmt, pixfmt, fmt->mbus_code); + ret =v4l2_subdev_call (disp->sd, video, + try_mbus_fmt, &mbus_fmt); +if (ret <0 ) +return ret; +v4l2_fill_pix_format (pixfmt, &mbus_fmt); +if (disp_fmt) { +for (i =0 ; i < disp->num_enc_formats; i++) { + fmt = &df[i]; +if (mbus_fmt.code == fmt->mbus_code) +break ; + } + *disp_fmt = *fmt; + } + pixfmt->bytesperline = pixfmt->width * fmt->bpp /8 ; + pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; +return 0 ; +} +
drivers/media/platform/blackfin/bfin_display.c line 756
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+static int disp_enum_fmt_vid_out (struct file *file,void *priv, +struct v4l2_fmtdesc *fmt) +{ +struct disp_device *disp =video_drvdata (file); +struct disp_format *df = disp->enc_formats; + +if (fmt->index >= disp->num_enc_formats) +return -EINVAL ; + + fmt->type =V4L2_BUF_TYPE_VIDEO_OUTPUT ;
Not necessary, type will always be V4L2_BUF_TYPE_VIDEO_OUTPUT.
Quoted 51 lines
drivers/media/platform/blackfin/bfin_display.c new file +51
-0+strlcpy (fmt->description, + df[fmt->index].desc, +sizeof (fmt->description)); + fmt->pixelformat = df[fmt->index].pixelformat; +return 0 ; +} + +static int disp_try_fmt_vid_out (struct file *file,void *priv, +struct v4l2_format *fmt) +{ +struct disp_device *disp =video_drvdata (file); +struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + +return disp_try_format (disp, pixfmt,NULL ); +} + +static int disp_g_fmt_vid_out (struct file *file,void *priv, +struct v4l2_format *fmt) +{ +struct disp_device *disp =video_drvdata (file); + + fmt->fmt.pix = disp->fmt; +return 0 ; +} + +static int disp_s_fmt_vid_out (struct file *file,void *priv, +struct v4l2_format *fmt) +{ +struct disp_device *disp =video_drvdata (file); +struct v4l2_mbus_framefmt mbus_fmt; +struct disp_format disp_fmt; +struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; +int ret; + +if (vb2_is_busy (&disp->buffer_queue)) +return -EBUSY ; + +/* see if format works */ + ret =disp_try_format (disp, pixfmt, &disp_fmt); +if (ret <0 ) +return ret; + +v4l2_fill_mbus_format (&mbus_fmt, pixfmt, disp_fmt.mbus_code); + ret =v4l2_subdev_call (disp->sd, video, s_mbus_fmt, &mbus_fmt); +if (ret <0 ) +return ret; + disp->fmt = *pixfmt; + disp->bpp = disp_fmt.bpp; + disp->dlen = disp_fmt.dlen; +return 0 ; +}
drivers/media/platform/blackfin/bfin_display.c line 817
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +static int disp_querycap (struct file *file,void *priv, +struct v4l2_capability *cap) +{ +struct disp_device *disp =video_drvdata (file); + + cap->capabilities =V4L2_CAP_VIDEO_OUTPUT |V4L2_CAP_STREAMING ; +strlcpy (cap->driver,DISPLAY_DRV_NAME ,sizeof (cap->driver)); +strlcpy (cap->bus_info,"Blackfin Platform" ,sizeof (cap->bus_info)); +strlcpy (cap->card, disp->cfg->card_name,sizeof (cap->card));
Please set cap->device_caps:
cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Quoted 23 lines
drivers/media/platform/blackfin/bfin_display.c new file +23
-0+return 0 ; +} + +static int disp_g_parm (struct file *file,void *fh, +struct v4l2_streamparm *a) +{ +struct disp_device *disp =video_drvdata (file); + +return v4l2_subdev_call (disp->sd, video, g_parm, a); +} + +static int disp_s_parm (struct file *file,void *fh, +struct v4l2_streamparm *a) +{ +struct disp_device *disp =video_drvdata (file); + +return v4l2_subdev_call (disp->sd, video, s_parm, a); +} + +static int disp_g_chip_ident (struct file *file,void *priv, +struct v4l2_dbg_chip_ident *chip) +{ +struct disp_device *disp =video_drvdata (file);
drivers/media/platform/blackfin/bfin_display.c line 850
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ + chip->ident =V4L2_IDENT_NONE ; + chip->revision =0 ; +if (chip->match.type !=V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match.type !=V4L2_CHIP_MATCH_I2C_ADDR ) +return -EINVAL ; + +return v4l2_subdev_call (disp->sd, core, + g_chip_ident, chip); +}
You can drop chip_ident: it's no longer needed since VIDIOC_DBG_G_CHIP_INFO was added.
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int disp_dbg_g_register (struct file *file,void *priv, +struct v4l2_dbg_register *reg) +{ +struct disp_device *disp =video_drvdata (file); + +return v4l2_subdev_call (disp->sd, core, + g_register, reg); +}
drivers/media/platform/blackfin/bfin_display.c line 870
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +static int disp_dbg_s_register (struct file *file,void *priv, +struct v4l2_dbg_register *reg) +{ +struct disp_device *disp =video_drvdata (file); + +return v4l2_subdev_call (disp->sd, core, + s_register, reg); +} +#endif
Ditto for these g/s_register calls. The core now takes care of that.
Quoted 138 lines
drivers/media/platform/blackfin/bfin_display.c new file +138
-0+ +static int disp_log_status (struct file *file,void *priv) +{ +struct disp_device *disp =video_drvdata (file); +/* status for sub devices */ +v4l2_device_call_all (&disp->v4l2_dev,0 , core, log_status); +return 0 ; +} + +static const struct v4l2_ioctl_ops disp_ioctl_ops = { + .vidioc_querycap = disp_querycap, + .vidioc_g_fmt_vid_out = disp_g_fmt_vid_out, + .vidioc_enum_fmt_vid_out = disp_enum_fmt_vid_out, + .vidioc_s_fmt_vid_out = disp_s_fmt_vid_out, + .vidioc_try_fmt_vid_out = disp_try_fmt_vid_out, + .vidioc_enum_output = disp_enum_output, + .vidioc_g_output = disp_g_output, + .vidioc_s_output = disp_s_output, + .vidioc_s_std = disp_s_std, + .vidioc_g_std = disp_g_std, + .vidioc_s_dv_timings = disp_s_dv_timings, + .vidioc_g_dv_timings = disp_g_dv_timings, + .vidioc_reqbufs = disp_reqbufs, + .vidioc_querybuf = disp_querybuf, + .vidioc_qbuf = disp_qbuf, + .vidioc_dqbuf = disp_dqbuf, + .vidioc_streamon = disp_streamon, + .vidioc_streamoff = disp_streamoff, + .vidioc_g_parm = disp_g_parm, + .vidioc_s_parm = disp_s_parm, + .vidioc_g_chip_ident = disp_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = disp_dbg_g_register, + .vidioc_s_register = disp_dbg_s_register, +#endif + .vidioc_log_status = disp_log_status, +}; + +static struct v4l2_file_operations disp_fops = { + .owner =THIS_MODULE , + .open = disp_open, + .release = disp_release, + .unlocked_ioctl = video_ioctl2, + .mmap = disp_mmap, +#ifndef CONFIG_MMU + .get_unmapped_area = disp_get_unmapped_area, +#endif + .poll = disp_poll +}; + +static int disp_probe (struct platform_device *pdev) +{ +struct disp_device *disp; +struct video_device *vfd; +struct i2c_adapter *i2c_adap; +struct bfin_display_config *config; +struct vb2_queue *q; +struct disp_route *route; +int ret; + + config = pdev->dev.platform_data; +if (!config) { +v4l2_err (pdev->dev.driver,"Unable to get board config\n" ); +return -ENODEV ; + } + + disp =kzalloc (sizeof (*disp),GFP_KERNEL ); +if (!disp) { +v4l2_err (pdev->dev.driver,"Unable to alloc disp\n" ); +return -ENOMEM ; + } + + disp->cfg = config; + + disp->ppi =ppi_create_instance (config->ppi_info); +if (!disp->ppi) { +v4l2_err (pdev->dev.driver,"Unable to create ppi\n" ); + ret = -ENODEV ; + goto err_free_dev; + } + disp->ppi->priv = disp; + + disp->alloc_ctx =vb2_dma_contig_init_ctx (&pdev->dev); +if (IS_ERR (disp->alloc_ctx)) { + ret =PTR_ERR (disp->alloc_ctx); + goto err_free_ppi; + } + + vfd =video_device_alloc (); +if (!vfd) { + ret = -ENOMEM ; +v4l2_err (pdev->dev.driver,"Unable to alloc video device\n" ); + goto err_cleanup_ctx; + } + +/* initialize field of video device */ + vfd->release = video_device_release; + vfd->fops = &disp_fops; + vfd->ioctl_ops = &disp_ioctl_ops; + vfd->tvnorms =0 ; + vfd->v4l2_dev = &disp->v4l2_dev; + vfd->vfl_dir =VFL_DIR_TX ; +set_bit (V4L2_FL_USE_FH_PRIO , &vfd->flags); +strncpy (vfd->name,DISPLAY_DRV_NAME ,sizeof (vfd->name)); + disp->video_dev = vfd; + + ret =v4l2_device_register (&pdev->dev, &disp->v4l2_dev); +if (ret) { +v4l2_err (pdev->dev.driver, +"Unable to register v4l2 device\n" ); + goto err_release_vdev; + } +v4l2_info (&disp->v4l2_dev,"v4l2 device registered\n" ); + + disp->v4l2_dev.ctrl_handler = &disp->ctrl_handler; + ret =v4l2_ctrl_handler_init (&disp->ctrl_handler,0 ); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to init control handler\n" ); + goto err_unreg_v4l2; + } + +spin_lock_init (&disp->lock); +/* initialize queue */ + q = &disp->buffer_queue; + q->type =V4L2_BUF_TYPE_VIDEO_OUTPUT ; + q->io_modes =VB2_MMAP ; + q->drv_priv = disp; + q->buf_struct_size =sizeof (struct disp_buffer ); + q->ops = &disp_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + + ret =vb2_queue_init (q); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to init videobuf2 queue\n" ); + goto err_free_handler; + }
drivers/media/platform/blackfin/bfin_display.c line 1018
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+ +mutex_init (&disp->mutex); + +/* init video dma queues */ +INIT_LIST_HEAD (&disp->dma_queue); + + vfd->lock = &disp->mutex; + +/* register video device */ + ret =video_register_device (disp->video_dev,VFL_TYPE_GRABBER ,-1 );
This should be done last after everything else is set up.
Quoted 22 lines
drivers/media/platform/blackfin/bfin_display.c new file +22
-0+if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to register video device\n" ); + goto err_free_handler; + } +video_set_drvdata (disp->video_dev, disp); +v4l2_info (&disp->v4l2_dev,"video device registered as: %s\n" , +video_device_node_name (vfd)); + +/* load up the subdevice */ + i2c_adap =i2c_get_adapter (config->i2c_adapter_id); +if (!i2c_adap) { +v4l2_err (&disp->v4l2_dev, +"Unable to find i2c adapter\n" ); + goto err_unreg_vdev; + + } + disp->sd =v4l2_i2c_new_subdev_board (&disp->v4l2_dev, + i2c_adap, + &config->board_info, +NULL ); +if (disp->sd) {
drivers/media/platform/blackfin/bfin_display.c line 1050
Quoted 10 lines
drivers/media/platform/blackfin/bfin_display.c new file +10
-0+int i; +if (!config->num_outputs) { +v4l2_err (&disp->v4l2_dev, +"Unable to work without output\n" ); + goto err_unreg_vdev; + } + +/* update tvnorms from the sub devices */ +for (i =0 ; i < config->num_outputs; i++) + vfd->tvnorms |= config->outputs[i].std;
No. vfd->tvnorms should be the std value for the current output, not that of all outputs combined.
Quoted 136 lines
drivers/media/platform/blackfin/bfin_display.c new file +101
-0+ }else { +v4l2_err (&disp->v4l2_dev, +"Unable to register sub device\n" ); + goto err_unreg_vdev; + } + +v4l2_info (&disp->v4l2_dev,"v4l2 sub device registered\n" ); + +/* +* explicitly set output, otherwise some boards +* may not work at the state as we expected +*/ + route = &config->routes[0 ]; + ret =v4l2_subdev_call (disp->sd, video, s_routing, + route->output, route->output,0 ); +if ((ret <0 ) && (ret != -ENOIOCTLCMD )) { +v4l2_err (&disp->v4l2_dev,"Failed to set output\n" ); + goto err_unreg_vdev; + } + disp->cur_output =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 (config->outputs[0 ].capabilities &V4L2_IN_CAP_STD ) { +v4l2_std_id std; + ret =v4l2_subdev_call (disp->sd, core, g_std, &std); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to get std\n" ); + goto err_unreg_vdev; + } + disp->std = std; + } +if (config->outputs[0 ].capabilities &V4L2_IN_CAP_CUSTOM_TIMINGS ) { +struct v4l2_dv_timings dv_timings; + ret =v4l2_subdev_call (disp->sd, video, + g_dv_timings, &dv_timings); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to get dv timings\n" ); + goto err_unreg_vdev; + } + disp->dv_timings = dv_timings; + } + ret =disp_init_encoder_formats (disp); +if (ret) { +v4l2_err (&disp->v4l2_dev, +"Unable to create encoder formats table\n" ); + goto err_unreg_vdev; + } +return 0 ; +err_unreg_vdev: +video_unregister_device (disp->video_dev); + disp->video_dev =NULL ; +err_free_handler: +v4l2_ctrl_handler_free (&disp->ctrl_handler); +err_unreg_v4l2: +v4l2_device_unregister (&disp->v4l2_dev); +err_release_vdev: +if (disp->video_dev) +video_device_release (disp->video_dev); +err_cleanup_ctx: +vb2_dma_contig_cleanup_ctx (disp->alloc_ctx); +err_free_ppi: +ppi_delete_instance (disp->ppi); +err_free_dev: +kfree (disp); +return ret; +} + +static int disp_remove (struct platform_device *pdev) +{ +struct v4l2_device *v4l2_dev =platform_get_drvdata (pdev); +struct disp_device *disp =container_of (v4l2_dev, + struct disp_device, v4l2_dev); + +disp_free_encoder_formats (disp); +video_unregister_device (disp->video_dev); +v4l2_ctrl_handler_free (&disp->ctrl_handler); +v4l2_device_unregister (v4l2_dev); +vb2_dma_contig_cleanup_ctx (disp->alloc_ctx); +ppi_delete_instance (disp->ppi); +kfree (disp); +return 0 ; +} + +static struct platform_driver disp_driver = { + .driver = { + .name =DISPLAY_DRV_NAME , + .owner =THIS_MODULE , + }, + .probe = disp_probe, + .remove = disp_remove, +}; +module_platform_driver (disp_driver); + +MODULE_DESCRIPTION ("Analog Devices blackfin video display driver" ); +MODULE_AUTHOR ("Scott Jiang <[email protected]>" ); +MODULE_LICENSE ("GPL v2" );include/media/blackfin/bfin_display.h new file +28
-0@@ -0,0 +1,38 @@ +#ifndef _BFIN_DISPLAY_H_ +#define _BFIN_DISPLAY_H_ + +#include <linux/i2c.h> + +struct v4l2_output; +struct ppi_info; + +struct disp_route { + u32 output; + u32 config; + u32 ppi_control; +}; + +struct bfin_display_config { + /* card name */ + char *card_name; + /* outputs available at the sub device */ + struct v4l2_output *outputs; + /* number of outputs supported */ + int num_outputs; + /* routing information for each output */ + struct disp_route *routes; + /* i2c bus adapter no */ + int i2c_adapter_id; + /* i2c subdevice board info */ + struct i2c_board_info board_info; + /* ppi board info */
include/media/blackfin/bfin_display.h line 38
Quoted 10 lines
include/media/blackfin/bfin_display.h new file +10
-0+const struct ppi_info *ppi_info; +/* ppi control */ +u32 ppi_control; +/* ppi interrupt mask */ +u32 int_mask; +/* horizontal blanking pixels */ + int blank_pixels; +}; + +#endif
Regards,
Hans
Re: [PATCH RFC] [media] blackfin: add video display driver
Hi Hans,
Quoted 7 lines
Quoted 4 lines
+/*
+ * Analog Devices video display driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.Analog Devices? What has this to do with Analog Devices?
I wrote this driver for Analog Devices Blackfin.
Quoted 39 lines
Quoted 39 lines
drivers/media/platform/blackfin/bfin_display.c new file +39
-0+ +static int disp_mmap (struct file *file,struct vm_area_struct *vma) +{ +struct disp_device *disp =video_drvdata (file); +int ret; + +if (mutex_lock_interruptible (&disp->mutex)) +return -ERESTARTSYS ; + ret =vb2_mmap (&disp->buffer_queue, vma); +mutex_unlock (&disp->mutex); +return ret; +} + +#ifndef CONFIG_MMU +static unsigned long disp_get_unmapped_area (struct file *file, +unsigned long addr, +unsigned long len, +unsigned long pgoff, +unsigned long flags) +{ +struct disp_device *disp =video_drvdata (file); +int ret; + +if (mutex_lock_interruptible (&disp->mutex)) +return -ERESTARTSYS ; + ret =vb2_get_unmapped_area (&disp->buffer_queue, + addr, + len, + pgoff, + flags); +mutex_unlock (&disp->mutex); +return ret; +} +#endif + +static unsigned int disp_poll (struct file *file,poll_table *wait) +{ +struct disp_device *disp =video_drvdata (file); +int ret;
Quoted 9 lines
drivers/media/platform/blackfin/bfin_display.c line 284
Quoted 6 lines
drivers/media/platform/blackfin/bfin_display.c new file +6
-0+ +mutex_lock (&disp->mutex); + ret =vb2_poll (&disp->buffer_queue, file, wait); +mutex_unlock (&disp->mutex); +return ret; +}Use the helper functions in
media/videobuf2-core.hfor these file ops.
OK, I will use vb2_fop_mmap. But I'm not sure if I need to lock it.
Quoted 18 lines
drivers/media/platform/blackfin/bfin_display.c line 485
Quoted 12 lines
drivers/media/platform/blackfin/bfin_display.c new file +12
-0+static int disp_reqbufs (struct file *file,void *priv, +struct v4l2_requestbuffers *req_buf) +{ +struct disp_device *disp =video_drvdata (file); +struct vb2_queue *vq = &disp->buffer_queue; +struct v4l2_fh *fh = file->private_data; + struct disp_fh *disp_fh = container_of(fh, struct disp_fh, fh); + +if (vb2_is_busy (vq)) +return -EBUSY ; + + disp_fh->io_allowed = true;There is no need for
io_allowed. Thevb2_is_busy()function does the same thing. It saves a lot of code since you now can just usev4l2_fhinstead ofdisp_fh, which allows you to use even more helper functions (v4l2_fh_openandv4l2_fh_releasefor starters).
Quoted 2 lines
In fact, you can use all the vb2 ioctl helpers saving you a lot of code.
I don't think so. vb2_is_busy can't check if this file instance has the right to stream off output.
Quoted 1 line · On Sat April 13 2013 01:52:57 Scott Jiang wrote:
Signed-off-by Scott Jiang <[email protected]>
Is it OK if I postpone these two patches for 3.11? They don't make sense AFAICT without the new display driver, and that will definitely not make it for 3.10.
Regards,
Hans
Quoted 28 lines
--- drivers/media/platform/blackfin/ppi.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)drivers/media/platform/blackfin/ppi.c +12
-0@@ -266,6 +266,18 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)bfin_write32 (®->vcnt, params->height);if (params->int_mask)bfin_write32 (®->imsk, params->int_mask &0xFF ); +if (ppi->ppi_control &PORT_DIR ) { +u32 hsync_width, vsync_width, vsync_period; + + hsync_width = params->hsync + * params->bpp / params->dlen; + vsync_width = params->vsync * samples_per_line; + vsync_period = samples_per_line * params->frame; +bfin_write32 (®->fs1_wlhb, hsync_width); +bfin_write32 (®->fs1_paspl, samples_per_line); +bfin_write32 (®->fs2_wlvb, vsync_width); +bfin_write32 (®->fs2_palpf, vsync_period); + }break ; }default :
2013/4/12 Hans Verkuil <[email protected]>:
Quoted 7 lines · On Sat April 13 2013 01:52:57 Scott Jiang wrote:
Quoted 1 line
Signed-off-by Scott Jiang <[email protected]>Is it OK if I postpone these two patches for 3.11? They don't make sense AFAICT without the new display driver, and that will definitely not make it for 3.10.
OK.
Scott