From patchwork Mon Aug 17 23:19:27 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: m-karicheri2@ti.com X-Patchwork-Id: 1514 Return-path: Envelope-to: mchehab@infradead.org Delivery-date: Mon, 17 Aug 2009 23:19:52 +0000 Received: from bombadil.infradead.org [18.85.46.34] by pedra.chehab.org with IMAP (fetchmail-6.3.6) for (single-drop); Mon, 17 Aug 2009 20:29:09 -0300 (BRT) Received: from vger.kernel.org ([209.132.176.167]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1MdBUW-0000ag-7h; Mon, 17 Aug 2009 23:19:52 +0000 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753071AbZHQXTe (ORCPT + 1 other); Mon, 17 Aug 2009 19:19:34 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1757791AbZHQXTe (ORCPT ); Mon, 17 Aug 2009 19:19:34 -0400 Received: from arroyo.ext.ti.com ([192.94.94.40]:38091 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753071AbZHQXTc (ORCPT ); Mon, 17 Aug 2009 19:19:32 -0400 Received: from dlep33.itg.ti.com ([157.170.170.112]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id n7HNJSxR007876; Mon, 17 Aug 2009 18:19:33 -0500 Received: from legion.dal.design.ti.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id n7HNJS2H023912; Mon, 17 Aug 2009 18:19:28 -0500 (CDT) Received: from gt516km11.gt.design.ti.com (gt516km11.gt.design.ti.com [158.218.100.179]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id n7HNJRZ04918; Mon, 17 Aug 2009 18:19:27 -0500 (CDT) Received: from gt516km11.gt.design.ti.com (localhost.localdomain [127.0.0.1]) by gt516km11.gt.design.ti.com (8.13.1/8.13.1) with ESMTP id n7HNJRix032601; Mon, 17 Aug 2009 19:19:27 -0400 Received: (from a0868495@localhost) by gt516km11.gt.design.ti.com (8.13.1/8.13.1/Submit) id n7HNJRJ7032598; Mon, 17 Aug 2009 19:19:27 -0400 From: m-karicheri2@ti.com To: linux-media@vger.kernel.org Cc: davinci-linux-open-source@linux.davincidsp.com, hverkuil@xs4all.nl, Muralidharan Karicheri Subject: [PATCH 4/5 - v3] V4L-vpfe capture driver - adding support for camera capture Date: Mon, 17 Aug 2009 19:19:27 -0400 Message-Id: <1250551167-32577-1-git-send-email-m-karicheri2@ti.com> X-Mailer: git-send-email 1.6.0.4 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Muralidharan Karicheri Recreating this patch to apply cleanly and compile. v2 of the patch incorporated following comments received against v1 patch series. 1) retained vpfe_g_std() since for vbi support g_std handling in v4l2 framework is not sufficient. 2) rename name field in vpfe_subdev_info to module_name and camera to is_camera. also grouped bit field variables Additional features added on top v1 patch:- 2) vpfe_enable/disable_clock restructered to allow configuration of required clocks in vpfe_capture configuration. This is required for upcoming DM365 support. Reviewed-by: Hans Verkuil Signed-off-by: Muralidharan Karicheri --- Applies to V4L-DVB linux-next repository drivers/media/video/davinci/vpfe_capture.c | 545 +++++++++++++++++++++------- include/media/davinci/vpfe_capture.h | 5 - 2 files changed, 413 insertions(+), 137 deletions(-) diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 402ce43..ff43446 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -59,10 +59,8 @@ * TODO list * - Support multiple REQBUF after open * - Support for de-allocating buffers through REQBUF - * - Support for Raw Bayer RGB capture * - Support for chaining Image Processor * - Support for static allocation of buffers - * - Support for USERPTR IO * - Support for STREAMON before QBUF * - Support for control ioctls */ @@ -79,11 +77,24 @@ static int debug; static u32 numbuffers = 3; static u32 bufsize = (720 * 576 * 2); +static int interface; +module_param(interface, bool, S_IRUGO); module_param(numbuffers, uint, S_IRUGO); module_param(bufsize, uint, S_IRUGO); -module_param(debug, int, 0644); - +module_param(debug, bool, 0644); + +/** + * VPFE capture can be used for capturing video such as from TVP5146 or TVP7002 + * and for capture raw bayer data from camera sensors such as MT9T031. At this + * point there is problem in co-existence of mt9t031 and tvp5146 due to i2c + * address collision. So set the variable below from bootargs to do either video + * capture or camera capture. + * interface = 0 - video capture (from TVP514x or such), + * interface = 1 - Camera capture (from MT9T031 or such) + * Re-visit this when we fix the co-existence issue + */ +MODULE_PARM_DESC(interface, "interface 0-1 (default:0)"); MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); MODULE_PARM_DESC(debug, "Debug level 0-1"); @@ -143,6 +154,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { .pixelformat = V4L2_PIX_FMT_SBGGR8, }, .bpp = 1, + .subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10, }, { .fmtdesc = { @@ -152,6 +164,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { .pixelformat = V4L2_PIX_FMT_SBGGR16, }, .bpp = 2, + .subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10, }, { .fmtdesc = { @@ -161,6 +174,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, }, .bpp = 1, + .subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10, }, { .fmtdesc = { @@ -170,6 +184,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { .pixelformat = V4L2_PIX_FMT_UYVY, }, .bpp = 2, + .subdev_pix_fmt = V4L2_PIX_FMT_UYVY, }, { .fmtdesc = { @@ -179,6 +194,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { .pixelformat = V4L2_PIX_FMT_YUYV, }, .bpp = 2, + .subdev_pix_fmt = V4L2_PIX_FMT_UYVY, }, { .fmtdesc = { @@ -188,12 +204,15 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = { .pixelformat = V4L2_PIX_FMT_NV12, }, .bpp = 1, + .subdev_pix_fmt = V4L2_PIX_FMT_UYVY, }, }; -/* - * vpfe_lookup_pix_format() - * lookup an entry in the vpfe pix format table based on pix_format +/** + * vpfe_lookup_pix_format() - lookup an entry in the vpfe pix format table + * @pix_format: v4l pix format + * This function lookup an entry in the vpfe pix format table based on + * pix_format */ static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) { @@ -241,19 +260,19 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) * walk through it during vpfe probe */ printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -1; + ret = -EFAULT; goto unlock; } if (strcmp(dev->name, ccdc_cfg->name)) { /* ignore this ccdc */ - ret = -1; + ret = -EINVAL; goto unlock; } if (ccdc_dev) { printk(KERN_ERR "ccdc already registered\n"); - ret = -1; + ret = -EINVAL; goto unlock; } @@ -293,6 +312,45 @@ void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) EXPORT_SYMBOL(vpfe_unregister_ccdc_device); /* + * vpfe_get_camera_frame_params() + * Get the image parameters such as max height and width, frame format + * etc and update the stdinfo accordingly. This is a work around to get + * the maximum width, height and frame format since camera driver doesn't + * support s_std. + */ +static int vpfe_get_camera_frame_params(struct vpfe_device *vpfe_dev) +{ + struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; + struct v4l2_format sd_fmt; + int ret; + + /* TODO: Currently there is no support for setting timings + * in sensor similar to S_STD. So get the limits of width and height + * using try format. In future we should be able to set + * timings for a specific resolution and fps. In that case + * we know the limits for the specific timing and this code + * would require change. + */ + memset(&sd_fmt, 0, sizeof(sd_fmt)); + sd_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + /* hard code it to match that of mt9t031 sensor */ + sd_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGRBG10; + /* use a value big enough */ + sd_fmt.fmt.pix.width = 1 << 31; + sd_fmt.fmt.pix.height = 1 << 31; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, + sdinfo->grp_id, video, try_fmt, &sd_fmt); + + if (!ret) { + vpfe_dev->std_info.active_pixels = sd_fmt.fmt.pix.width; + vpfe_dev->std_info.active_lines = sd_fmt.fmt.pix.height; + /* hard code the frame format to be progressive always. */ + vpfe_dev->std_info.frame_format = 0; + } + return ret; +} + +/* * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings */ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, @@ -302,9 +360,13 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, enum ccdc_buftype buf_type; enum ccdc_frmfmt frm_fmt; + vpfe_dev->crop.top = 0; + vpfe_dev->crop.left = 0; memset(f, 0, sizeof(*f)); f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ccdc_dev->hw_ops.get_image_window(&image_win); + vpfe_dev->crop.width = image_win.width; + vpfe_dev->crop.height = image_win.height; f->fmt.pix.width = image_win.width; f->fmt.pix.height = image_win.height; f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); @@ -386,8 +448,10 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, const v4l2_std_id *std_id) { struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; + struct v4l2_format sd_fmt; int i, ret = 0; + /* configure the ccdc based on standard */ for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { if (vpfe_standards[i].std_id & *std_id) { vpfe_dev->std_info.active_pixels = @@ -424,16 +488,17 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; } + sd_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* if sub device supports g_fmt, override the defaults */ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt); + sdinfo->grp_id, video, g_fmt, &sd_fmt); if (ret && ret != -ENOIOCTLCMD) { v4l2_err(&vpfe_dev->v4l2_dev, "error in getting g_fmt from sub device\n"); return ret; } - + vpfe_dev->fmt = sd_fmt; /* Sets the values in CCDC */ ret = vpfe_config_ccdc_image_format(vpfe_dev); if (ret) @@ -456,13 +521,29 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) /* set first input of current subdevice as the current input */ vpfe_dev->current_input = 0; + /* + * set default standard. For camera device, we cannot set standard. + * So we set it to -1. Otherwise, first entry in the standard is the + * is the default + */ + if (vpfe_dev->current_subdev->is_camera) { + vpfe_dev->std_index = -1; + /* + * Configure the vpfe default format information based on ccdc + * defaults + */ + ret = vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt); + /* Get max width and height available for capture from camera */ + if (!ret) + ret = vpfe_get_camera_frame_params(vpfe_dev); - /* set default standard */ - vpfe_dev->std_index = 0; - - /* Configure the default format information */ - ret = vpfe_config_image_format(vpfe_dev, + } else { + vpfe_dev->std_index = 0; + /* Configure the default format information */ + ret = vpfe_config_image_format(vpfe_dev, &vpfe_standards[vpfe_dev->std_index].std_id); + } + if (ret) return ret; @@ -540,7 +621,22 @@ static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) struct videobuf_buffer, queue); list_del(&vpfe_dev->next_frm->queue); vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; - addr = videobuf_to_dma_contig(vpfe_dev->next_frm); + if (V4L2_MEMORY_USERPTR == vpfe_dev->memory) + addr = vpfe_dev->cur_frm->boff; + else + addr = videobuf_to_dma_contig(vpfe_dev->next_frm); + ccdc_dev->hw_ops.setfbaddr(addr); +} + +static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) +{ + unsigned long addr; + + if (V4L2_MEMORY_USERPTR == vpfe_dev->memory) + addr = vpfe_dev->cur_frm->boff; + else + addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); + addr += vpfe_dev->field_off; ccdc_dev->hw_ops.setfbaddr(addr); } @@ -561,7 +657,6 @@ static irqreturn_t vpfe_isr(int irq, void *dev_id) { struct vpfe_device *vpfe_dev = dev_id; enum v4l2_field field; - unsigned long addr; int fid; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); @@ -605,12 +700,9 @@ static irqreturn_t vpfe_isr(int irq, void *dev_id) * interleavely or separately in memory, reconfigure * the CCDC memory address */ - if (field == V4L2_FIELD_SEQ_TB) { - addr = - videobuf_to_dma_contig(vpfe_dev->cur_frm); - addr += vpfe_dev->field_off; - ccdc_dev->hw_ops.setfbaddr(addr); - } + if (field == V4L2_FIELD_SEQ_TB) + vpfe_schedule_bottom_field(vpfe_dev); + return IRQ_HANDLED; } /* @@ -709,7 +801,7 @@ static int vpfe_release(struct file *file) video, s_stream, 0); if (ret && (ret != -ENOIOCTLCMD)) v4l2_err(&vpfe_dev->v4l2_dev, - "stream off failed in subdev\n"); + "stream off failed in subdev\n"); vpfe_stop_ccdc_capture(vpfe_dev); vpfe_detach_irq(vpfe_dev); videobuf_streamoff(&vpfe_dev->buffer_queue); @@ -960,6 +1052,8 @@ static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, { struct vpfe_device *vpfe_dev = video_drvdata(file); const struct vpfe_pixel_format *pix_fmts; + struct vpfe_subdev_info *sdinfo; + struct v4l2_format sd_fmt; int ret = 0; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); @@ -981,11 +1075,31 @@ static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; - /* First detach any IRQ if currently attached */ - vpfe_detach_irq(vpfe_dev); - vpfe_dev->fmt = *fmt; - /* set image capture parameters in the ccdc */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); + sdinfo = vpfe_dev->current_subdev; + if (sdinfo->is_camera) { + /* + * Current implementation of camera sub device calculates + * sensor timing values based on S_FMT. So we need to + * explicitely call S_FMT first and make sure it succeeds before + * setting capture parameters in ccdc + */ + sd_fmt = *fmt; + sd_fmt.fmt.pix.pixelformat = pix_fmts->subdev_pix_fmt; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, + sdinfo->grp_id, + video, s_fmt, &sd_fmt); + + if (!ret) { + vpfe_dev->crop.width = fmt->fmt.pix.width; + vpfe_dev->crop.height = fmt->fmt.pix.height; + } + } + + if (!ret) { + vpfe_dev->fmt = *fmt; + /* set image capture parameters in the ccdc */ + ret = vpfe_config_ccdc_image_format(vpfe_dev); + } mutex_unlock(&vpfe_dev->lock); return ret; } @@ -1043,9 +1157,10 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, for (i = 0; i < cfg->num_subdevs; i++) { sdinfo = &cfg->sub_devs[i]; - if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { + if (!strcmp(sdinfo->module_name, + vpfe_dev->current_subdev->module_name)) { if (vpfe_dev->current_input >= sdinfo->num_inputs) - return -1; + return -EINVAL; *app_input_index = j + vpfe_dev->current_input; return 0; } @@ -1059,10 +1174,11 @@ static int vpfe_enum_input(struct file *file, void *priv, { struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_subdev_info *sdinfo; - int subdev, index ; + int subdev, index, temp_index; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); + temp_index = inp->index; if (vpfe_get_subdev_input_index(vpfe_dev, &subdev, &index, @@ -1073,6 +1189,7 @@ static int vpfe_enum_input(struct file *file, void *priv, } sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); + inp->index = temp_index; return 0; } @@ -1090,7 +1207,7 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) { struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_subdev_info *sdinfo; - int subdev_index, inp_index; + int subdev_index, subdev_inp_index; struct vpfe_route *route; u32 input = 0, output = 0; int ret = -EINVAL; @@ -1113,31 +1230,48 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) if (vpfe_get_subdev_input_index(vpfe_dev, &subdev_index, - &inp_index, + &subdev_inp_index, index) < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); goto unlock_out; } sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; - route = &sdinfo->routes[inp_index]; + + if (!sdinfo->registered) { + ret = -EINVAL; + goto unlock_out; + } + + if (vpfe_dev->cfg->setup_input) { + if (vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) { + ret = -EFAULT; + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "couldn't setup input for %s\n", + sdinfo->module_name); + goto unlock_out; + } + } + + route = &sdinfo->routes[subdev_inp_index]; if (route && sdinfo->can_route) { input = route->input; output = route->output; - } + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, + sdinfo->grp_id, video, + s_routing, input, output, 0); - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_routing, input, output, 0); - - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "vpfe_doioctl:error in setting input in decoder\n"); - ret = -EINVAL; - goto unlock_out; + if (ret) { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "vpfe_doioctl:error in setting input in" + " decoder \n"); + ret = -EINVAL; + goto unlock_out; + } } + vpfe_dev->current_subdev = sdinfo; - vpfe_dev->current_input = index; - vpfe_dev->std_index = 0; + vpfe_dev->current_input = subdev_inp_index; /* set the bus/interface parameter for the sub device in ccdc */ ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); @@ -1145,8 +1279,22 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) goto unlock_out; /* set the default image parameters in the device */ - ret = vpfe_config_image_format(vpfe_dev, + if (vpfe_dev->current_subdev->is_camera) + vpfe_dev->std_index = -1; + /* for camera, use ccdc default parameters */ + ret = vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt); + /* Get max width and height available for capture from camera */ + if (!ret) + ret = vpfe_get_camera_frame_params(vpfe_dev); + else { + vpfe_dev->std_index = 0; + /* + * For non-camera sub device, use standard to configure vpfe + * default + */ + ret = vpfe_config_image_format(vpfe_dev, &vpfe_standards[vpfe_dev->std_index].std_id); + } unlock_out: mutex_unlock(&vpfe_dev->lock); return ret; @@ -1211,9 +1359,15 @@ static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); + if (vpfe_dev->std_index < 0 || + vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) { + v4l2_err(&vpfe_dev->v4l2_dev, "Standard not supported\n"); + return -EINVAL; + } *std_id = vpfe_standards[vpfe_dev->std_index].std_id; return 0; } + /* * Videobuf operations */ @@ -1225,15 +1379,65 @@ static int vpfe_videobuf_setup(struct videobuf_queue *vq, struct vpfe_device *vpfe_dev = fh->vpfe_dev; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); - *size = config_params.device_bufsize; + + /* + * if we are using mmap, check the size of the allocated buffer is less + * than or equal to the maximum specified in the driver. Assume here the + * user has called S_FMT and sizeimage has been calculated. + */ + *size = vpfe_dev->fmt.fmt.pix.sizeimage; + if (vpfe_dev->memory == V4L2_MEMORY_MMAP && + vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) + *size = config_params.device_bufsize; if (*count < config_params.min_numbuffers) *count = config_params.min_numbuffers; + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "count=%d, size=%d\n", *count, *size); return 0; } +/* + * vpfe_uservirt_to_phys: This function is used to convert user + * space virtual address to physical address. + */ +static u32 vpfe_uservirt_to_phys(struct vpfe_device *vpfe_dev, u32 virtp) +{ + struct mm_struct *mm = current->mm; + unsigned long physp = 0; + struct vm_area_struct *vma; + + vma = find_vma(mm, virtp); + + /* For kernel direct-mapped memory, take the easy way */ + if (virtp >= PAGE_OFFSET) + physp = virt_to_phys((void *)virtp); + else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) + /* this will catch, kernel-allocated, mmaped-to-usermode addr */ + physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); + else { + /* otherwise, use get_user_pages() for general userland pages */ + int res, nr_pages = 1; + struct page *pages; + down_read(¤t->mm->mmap_sem); + + res = get_user_pages(current, current->mm, + virtp, nr_pages, 1, 0, &pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (res == nr_pages) + physp = __pa(page_address(&pages[0]) + + (virtp & ~PAGE_MASK)); + else { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "get_user_pages failed\n"); + return 0; + } + } + return physp; +} + static int vpfe_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) @@ -1250,6 +1454,18 @@ static int vpfe_videobuf_prepare(struct videobuf_queue *vq, vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; vb->field = field; } + + if (V4L2_MEMORY_USERPTR == vpfe_dev->memory) { + if (!vb->baddr) { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "buffer address is 0\n"); + return -EINVAL; + } + vb->boff = vpfe_uservirt_to_phys(vpfe_dev, vb->baddr); + /* Make sure user addresses are aligned to 32 bytes */ + if (!ALIGN(vb->boff, 32)) + return -EINVAL; + } vb->state = VIDEOBUF_PREPARED; return 0; } @@ -1318,13 +1534,6 @@ static int vpfe_reqbufs(struct file *file, void *priv, return -EINVAL; } - if (V4L2_MEMORY_USERPTR == req_buf->memory) { - /* we don't support user ptr IO */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs:" - " USERPTR IO not supported\n"); - return -EINVAL; - } - ret = mutex_lock_interruptible(&vpfe_dev->lock); if (ret) return ret; @@ -1497,7 +1706,10 @@ static int vpfe_streamon(struct file *file, void *priv, vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; /* Initialize field_id and started member */ vpfe_dev->field_id = 0; - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); + if (V4L2_MEMORY_USERPTR == vpfe_dev->memory) + addr = vpfe_dev->cur_frm->boff; + else + addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); /* Calculate field offset */ vpfe_calculate_offsets(vpfe_dev); @@ -1574,19 +1786,36 @@ static int vpfe_cropcap(struct file *file, void *priv, struct v4l2_cropcap *crop) { struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); - if (vpfe_dev->std_index > ARRAY_SIZE(vpfe_standards)) - return -EINVAL; - memset(crop, 0, sizeof(struct v4l2_cropcap)); crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - crop->bounds.width = crop->defrect.width = - vpfe_standards[vpfe_dev->std_index].width; - crop->bounds.height = crop->defrect.height = - vpfe_standards[vpfe_dev->std_index].height; - crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; + sdinfo = vpfe_dev->current_subdev; + + if (!sdinfo->is_camera) { + + if (vpfe_dev->std_index < 0 || + vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) + return -EINVAL; + + crop->bounds.width = vpfe_standards[vpfe_dev->std_index].width; + crop->defrect.width = crop->bounds.width; + crop->bounds.height = + vpfe_standards[vpfe_dev->std_index].height; + crop->defrect.height = crop->bounds.height; + crop->pixelaspect = + vpfe_standards[vpfe_dev->std_index].pixelaspect; + } else { + /* camera interface */ + crop->bounds.width = vpfe_dev->std_info.active_pixels; + crop->defrect.width = crop->bounds.width; + crop->bounds.height = vpfe_dev->std_info.active_lines; + crop->defrect.height = crop->bounds.height; + crop->pixelaspect.numerator = 1; + crop->pixelaspect.denominator = 1; + } return 0; } @@ -1752,62 +1981,83 @@ static struct vpfe_device *vpfe_initialize(void) static void vpfe_disable_clock(struct vpfe_device *vpfe_dev) { struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; + int i; - clk_disable(vpfe_cfg->vpssclk); - clk_put(vpfe_cfg->vpssclk); - clk_disable(vpfe_cfg->slaveclk); - clk_put(vpfe_cfg->slaveclk); - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master & slave clocks disabled\n"); + for (i = 0; i < vpfe_cfg->num_clocks; i++) { + clk_disable(vpfe_dev->clks[i]); + clk_put(vpfe_dev->clks[i]); + } + kfree(vpfe_dev->clks); + v4l2_info(vpfe_dev->pdev->driver, "vpfe capture clocks disabled\n"); } +/** + * vpfe_enable_clock() - Enable clocks for vpfe capture driver + * @vpfe_dev - ptr to vpfe capture device + * + * Enables clocks defined in vpfe configuration. The function + * assumes that at least one clock is to be defined which is + * true as of now. re-visit this if this assumption is not true + */ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) { struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int ret = -ENOENT; + int ret = -EFAULT, i; - vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master"); - if (NULL == vpfe_cfg->vpssclk) { - v4l2_err(vpfe_dev->pdev->driver, "No clock defined for" - "vpss_master\n"); - return ret; - } + if (!vpfe_cfg->num_clocks) + return 0; - if (clk_enable(vpfe_cfg->vpssclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss master clock not enabled\n"); - goto out; - } - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master clock enabled\n"); + vpfe_dev->clks = kzalloc(vpfe_cfg->num_clocks * + sizeof(struct clock *), GFP_KERNEL); - vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave"); - if (NULL == vpfe_cfg->slaveclk) { - v4l2_err(vpfe_dev->pdev->driver, - "No clock defined for vpss slave\n"); - goto out; + if (NULL == vpfe_dev->clks) { + v4l2_err(vpfe_dev->pdev->driver, "Memory allocation failed\n"); + return -ENOMEM; } - if (clk_enable(vpfe_cfg->slaveclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss slave clock not enabled\n"); - goto out; + for (i = 0; i < vpfe_cfg->num_clocks; i++) { + if (NULL == vpfe_cfg->clocks[i]) { + v4l2_err(vpfe_dev->pdev->driver, + "clock %s is not defined in vpfe config\n", + vpfe_cfg->clocks[i]); + goto out; + } + + vpfe_dev->clks[i] = clk_get(vpfe_dev->pdev, + vpfe_cfg->clocks[i]); + if (NULL == vpfe_dev->clks[i]) { + v4l2_err(vpfe_dev->pdev->driver, + "Failed to get clock %s\n", + vpfe_cfg->clocks[i]); + goto out; + } + + if (clk_enable(vpfe_dev->clks[i])) { + v4l2_err(vpfe_dev->pdev->driver, + "vpfe clock %s not enabled\n", + vpfe_cfg->clocks[i]); + goto out; + } + + v4l2_info(vpfe_dev->pdev->driver, "vpss clock %s enabled", + vpfe_cfg->clocks[i]); } - v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n"); return 0; out: - if (vpfe_cfg->vpssclk) - clk_put(vpfe_cfg->vpssclk); - if (vpfe_cfg->slaveclk) - clk_put(vpfe_cfg->slaveclk); - - return -1; + for (i = 0; i < vpfe_cfg->num_clocks; i++) { + if (vpfe_dev->clks[i]) + clk_put(vpfe_dev->clks[i]); + } + kfree(vpfe_dev->clks); + return ret; } -/* - * vpfe_probe : This function creates device entries by register - * itself to the V4L2 driver and initializes fields of each - * device objects +/** + * vpfe_probe : vpfe probe function + * @pdev: platform device pointer + * + * This function creates device entries by register itself to the V4L2 driver + * and initializes fields of each device objects */ static __init int vpfe_probe(struct platform_device *pdev) { @@ -1931,7 +2181,7 @@ static __init int vpfe_probe(struct platform_device *pdev) vfd->ioctl_ops = &vpfe_ioctl_ops; vfd->minor = -1; vfd->tvnorms = 0; - vfd->current_norm = V4L2_STD_PAL; + vfd->current_norm = V4L2_STD_NTSC; vfd->v4l2_dev = &vpfe_dev->v4l2_dev; snprintf(vfd->name, sizeof(vfd->name), "%s_V%d.%d.%d", @@ -1994,34 +2244,65 @@ static __init int vpfe_probe(struct platform_device *pdev) struct v4l2_input *inps; sdinfo = &vpfe_cfg->sub_devs[i]; - - /* Load up the subdevice */ - vpfe_dev->sd[i] = - v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, - i2c_adap, - sdinfo->name, - &sdinfo->board_info, - NULL); - if (vpfe_dev->sd[i]) { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - sdinfo->name); - vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; - /* update tvnorms from the sub devices */ - for (j = 0; j < sdinfo->num_inputs; j++) { - inps = &sdinfo->inputs[j]; - vfd->tvnorms |= inps->std; + /** + * register subdevices based on interface setting. Currently + * tvp5146 and mt9t031 cannot co-exists due to i2c address + * conflicts. So only one of them is registered. Re-visit this + * once we have support for i2c switch handling in i2c driver + * framework + */ + if (interface == sdinfo->is_camera) { + /* setup input path */ + if (vpfe_cfg->setup_input) { + if (vpfe_cfg->setup_input(sdinfo->grp_id) < 0) { + ret = -EFAULT; + v4l2_info(&vpfe_dev->v4l2_dev, "could" + " not setup input for %s\n", + sdinfo->module_name); + goto probe_sd_out; + } + } + /* Load up the subdevice */ + vpfe_dev->sd[i] = + v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, + i2c_adap, + sdinfo->module_name, + &sdinfo->board_info, + NULL); + if (vpfe_dev->sd[i]) { + v4l2_info(&vpfe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + sdinfo->module_name); + vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; + /* update tvnorms from the sub devices */ + for (j = 0; j < sdinfo->num_inputs; j++) { + inps = &sdinfo->inputs[j]; + vfd->tvnorms |= inps->std; + } + sdinfo->registered = 1; + } else { + v4l2_info(&vpfe_dev->v4l2_dev, + "v4l2 sub device %s register fails\n", + sdinfo->module_name); } - } else { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s register fails\n", - sdinfo->name); - goto probe_sd_out; } } - /* set first sub device as current one */ - vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; + /* We need at least one sub device to do capture */ + for (i = 0; i < num_subdevs; i++) { + sdinfo = &vpfe_cfg->sub_devs[i]; + if (sdinfo->registered) { + /* set this as the current sub device */ + vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[i]; + break; + } + } + + /* if we don't have any sub device registered, return error */ + if (i == num_subdevs) { + printk(KERN_NOTICE "No sub devices registered\n"); + goto probe_sd_out; + } /* We have at least one sub device to work with */ mutex_unlock(&ccdc_lock); @@ -2112,7 +2393,7 @@ static __init int vpfe_init(void) return platform_driver_register(&vpfe_driver); } -/* +/** * vpfe_cleanup : This function un-registers device driver */ static void vpfe_cleanup(void) diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h index 196245e..e8272d1 100644 --- a/include/media/davinci/vpfe_capture.h +++ b/include/media/davinci/vpfe_capture.h @@ -69,8 +69,6 @@ enum vpfe_subdev_id { }; struct vpfe_subdev_info { - /* Deprecated. Will be removed in the next patch */ - char name[32]; /* Sub device module name */ char module_name[32]; /* Sub device group id */ @@ -102,9 +100,6 @@ struct vpfe_config { char *card_name; /* ccdc name */ char *ccdc; - /* vpfe clock */ - struct clk *vpssclk; - struct clk *slaveclk; /* setup function for the input path */ int (*setup_input)(enum vpfe_subdev_id id); /* number of clocks */