Path: blob/master/drivers/media/video/davinci/vpif_display.c
17633 views
/*1* vpif-display - VPIF display driver2* Display driver for TI DaVinci VPIF3*4* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License as8* published by the Free Software Foundation version 2.9*10* This program is distributed .as is. WITHOUT ANY WARRANTY of any11* kind, whether express or implied; without even the implied warranty12* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*/1516#include <linux/kernel.h>17#include <linux/init.h>18#include <linux/module.h>19#include <linux/errno.h>20#include <linux/fs.h>21#include <linux/mm.h>22#include <linux/interrupt.h>23#include <linux/workqueue.h>24#include <linux/string.h>25#include <linux/videodev2.h>26#include <linux/wait.h>27#include <linux/time.h>28#include <linux/i2c.h>29#include <linux/platform_device.h>30#include <linux/io.h>31#include <linux/version.h>32#include <linux/slab.h>3334#include <asm/irq.h>35#include <asm/page.h>3637#include <media/adv7343.h>38#include <media/v4l2-device.h>39#include <media/v4l2-ioctl.h>40#include <media/v4l2-chip-ident.h>4142#include <mach/dm646x.h>4344#include "vpif_display.h"45#include "vpif.h"4647MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");48MODULE_LICENSE("GPL");4950#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)5152#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)53#define vpif_dbg(level, debug, fmt, arg...) \54v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)5556static int debug = 1;57static u32 ch2_numbuffers = 3;58static u32 ch3_numbuffers = 3;59static u32 ch2_bufsize = 1920 * 1080 * 2;60static u32 ch3_bufsize = 720 * 576 * 2;6162module_param(debug, int, 0644);63module_param(ch2_numbuffers, uint, S_IRUGO);64module_param(ch3_numbuffers, uint, S_IRUGO);65module_param(ch2_bufsize, uint, S_IRUGO);66module_param(ch3_bufsize, uint, S_IRUGO);6768MODULE_PARM_DESC(debug, "Debug level 0-1");69MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)");70MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)");71MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)");72MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)");7374static struct vpif_config_params config_params = {75.min_numbuffers = 3,76.numbuffers[0] = 3,77.numbuffers[1] = 3,78.min_bufsize[0] = 720 * 480 * 2,79.min_bufsize[1] = 720 * 480 * 2,80.channel_bufsize[0] = 1920 * 1080 * 2,81.channel_bufsize[1] = 720 * 576 * 2,82};8384static struct vpif_device vpif_obj = { {NULL} };85static struct device *vpif_dev;8687/*88* vpif_uservirt_to_phys: This function is used to convert user89* space virtual address to physical address.90*/91static u32 vpif_uservirt_to_phys(u32 virtp)92{93struct mm_struct *mm = current->mm;94unsigned long physp = 0;95struct vm_area_struct *vma;9697vma = find_vma(mm, virtp);9899/* For kernel direct-mapped memory, take the easy way */100if (virtp >= PAGE_OFFSET) {101physp = virt_to_phys((void *)virtp);102} else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {103/* this will catch, kernel-allocated, mmaped-to-usermode addr */104physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);105} else {106/* otherwise, use get_user_pages() for general userland pages */107int res, nr_pages = 1;108struct page *pages;109down_read(¤t->mm->mmap_sem);110111res = get_user_pages(current, current->mm,112virtp, nr_pages, 1, 0, &pages, NULL);113up_read(¤t->mm->mmap_sem);114115if (res == nr_pages) {116physp = __pa(page_address(&pages[0]) +117(virtp & ~PAGE_MASK));118} else {119vpif_err("get_user_pages failed\n");120return 0;121}122}123124return physp;125}126127/*128* buffer_prepare: This is the callback function called from videobuf_qbuf()129* function the buffer is prepared and user space virtual address is converted130* into physical address131*/132static int vpif_buffer_prepare(struct videobuf_queue *q,133struct videobuf_buffer *vb,134enum v4l2_field field)135{136struct vpif_fh *fh = q->priv_data;137struct common_obj *common;138unsigned long addr;139140common = &fh->channel->common[VPIF_VIDEO_INDEX];141if (VIDEOBUF_NEEDS_INIT == vb->state) {142vb->width = common->width;143vb->height = common->height;144vb->size = vb->width * vb->height;145vb->field = field;146}147vb->state = VIDEOBUF_PREPARED;148149/* if user pointer memory mechanism is used, get the physical150* address of the buffer */151if (V4L2_MEMORY_USERPTR == common->memory) {152if (!vb->baddr) {153vpif_err("buffer_address is 0\n");154return -EINVAL;155}156157vb->boff = vpif_uservirt_to_phys(vb->baddr);158if (!ISALIGNED(vb->boff))159goto buf_align_exit;160}161162addr = vb->boff;163if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {164if (!ISALIGNED(addr + common->ytop_off) ||165!ISALIGNED(addr + common->ybtm_off) ||166!ISALIGNED(addr + common->ctop_off) ||167!ISALIGNED(addr + common->cbtm_off))168goto buf_align_exit;169}170return 0;171172buf_align_exit:173vpif_err("buffer offset not aligned to 8 bytes\n");174return -EINVAL;175}176177/*178* vpif_buffer_setup: This function allocates memory for the buffers179*/180static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count,181unsigned int *size)182{183struct vpif_fh *fh = q->priv_data;184struct channel_obj *ch = fh->channel;185struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];186187if (V4L2_MEMORY_MMAP != common->memory)188return 0;189190*size = config_params.channel_bufsize[ch->channel_id];191if (*count < config_params.min_numbuffers)192*count = config_params.min_numbuffers;193194return 0;195}196197/*198* vpif_buffer_queue: This function adds the buffer to DMA queue199*/200static void vpif_buffer_queue(struct videobuf_queue *q,201struct videobuf_buffer *vb)202{203struct vpif_fh *fh = q->priv_data;204struct common_obj *common;205206common = &fh->channel->common[VPIF_VIDEO_INDEX];207208/* add the buffer to the DMA queue */209list_add_tail(&vb->queue, &common->dma_queue);210vb->state = VIDEOBUF_QUEUED;211}212213/*214* vpif_buffer_release: This function is called from the videobuf layer to215* free memory allocated to the buffers216*/217static void vpif_buffer_release(struct videobuf_queue *q,218struct videobuf_buffer *vb)219{220struct vpif_fh *fh = q->priv_data;221struct channel_obj *ch = fh->channel;222struct common_obj *common;223unsigned int buf_size = 0;224225common = &ch->common[VPIF_VIDEO_INDEX];226227videobuf_dma_contig_free(q, vb);228vb->state = VIDEOBUF_NEEDS_INIT;229230if (V4L2_MEMORY_MMAP != common->memory)231return;232233buf_size = config_params.channel_bufsize[ch->channel_id];234}235236static struct videobuf_queue_ops video_qops = {237.buf_setup = vpif_buffer_setup,238.buf_prepare = vpif_buffer_prepare,239.buf_queue = vpif_buffer_queue,240.buf_release = vpif_buffer_release,241};242static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };243244static void process_progressive_mode(struct common_obj *common)245{246unsigned long addr = 0;247248/* Get the next buffer from buffer queue */249common->next_frm = list_entry(common->dma_queue.next,250struct videobuf_buffer, queue);251/* Remove that buffer from the buffer queue */252list_del(&common->next_frm->queue);253/* Mark status of the buffer as active */254common->next_frm->state = VIDEOBUF_ACTIVE;255256/* Set top and bottom field addrs in VPIF registers */257addr = videobuf_to_dma_contig(common->next_frm);258common->set_addr(addr + common->ytop_off,259addr + common->ybtm_off,260addr + common->ctop_off,261addr + common->cbtm_off);262}263264static void process_interlaced_mode(int fid, struct common_obj *common)265{266/* device field id and local field id are in sync */267/* If this is even field */268if (0 == fid) {269if (common->cur_frm == common->next_frm)270return;271272/* one frame is displayed If next frame is273* available, release cur_frm and move on */274/* Copy frame display time */275do_gettimeofday(&common->cur_frm->ts);276/* Change status of the cur_frm */277common->cur_frm->state = VIDEOBUF_DONE;278/* unlock semaphore on cur_frm */279wake_up_interruptible(&common->cur_frm->done);280/* Make cur_frm pointing to next_frm */281common->cur_frm = common->next_frm;282283} else if (1 == fid) { /* odd field */284if (list_empty(&common->dma_queue)285|| (common->cur_frm != common->next_frm)) {286return;287}288/* one field is displayed configure the next289* frame if it is available else hold on current290* frame */291/* Get next from the buffer queue */292process_progressive_mode(common);293294}295}296297/*298* vpif_channel_isr: It changes status of the displayed buffer, takes next299* buffer from the queue and sets its address in VPIF registers300*/301static irqreturn_t vpif_channel_isr(int irq, void *dev_id)302{303struct vpif_device *dev = &vpif_obj;304struct channel_obj *ch;305struct common_obj *common;306enum v4l2_field field;307int fid = -1, i;308int channel_id = 0;309310channel_id = *(int *)(dev_id);311ch = dev->dev[channel_id];312field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;313for (i = 0; i < VPIF_NUMOBJECTS; i++) {314common = &ch->common[i];315/* If streaming is started in this channel */316if (0 == common->started)317continue;318319if (1 == ch->vpifparams.std_info.frm_fmt) {320if (list_empty(&common->dma_queue))321continue;322323/* Progressive mode */324if (!channel_first_int[i][channel_id]) {325/* Mark status of the cur_frm to326* done and unlock semaphore on it */327do_gettimeofday(&common->cur_frm->ts);328common->cur_frm->state = VIDEOBUF_DONE;329wake_up_interruptible(&common->cur_frm->done);330/* Make cur_frm pointing to next_frm */331common->cur_frm = common->next_frm;332}333334channel_first_int[i][channel_id] = 0;335process_progressive_mode(common);336} else {337/* Interlaced mode */338/* If it is first interrupt, ignore it */339340if (channel_first_int[i][channel_id]) {341channel_first_int[i][channel_id] = 0;342continue;343}344345if (0 == i) {346ch->field_id ^= 1;347/* Get field id from VPIF registers */348fid = vpif_channel_getfid(ch->channel_id + 2);349/* If fid does not match with stored field id */350if (fid != ch->field_id) {351/* Make them in sync */352if (0 == fid)353ch->field_id = fid;354355return IRQ_HANDLED;356}357}358process_interlaced_mode(fid, common);359}360}361362return IRQ_HANDLED;363}364365static int vpif_update_std_info(struct channel_obj *ch)366{367struct video_obj *vid_ch = &ch->video;368struct vpif_params *vpifparams = &ch->vpifparams;369struct vpif_channel_config_params *std_info = &vpifparams->std_info;370const struct vpif_channel_config_params *config;371372int i;373374for (i = 0; i < vpif_ch_params_count; i++) {375config = &ch_params[i];376if (config->hd_sd == 0) {377vpif_dbg(2, debug, "SD format\n");378if (config->stdid & vid_ch->stdid) {379memcpy(std_info, config, sizeof(*config));380break;381}382} else {383vpif_dbg(2, debug, "HD format\n");384if (config->dv_preset == vid_ch->dv_preset) {385memcpy(std_info, config, sizeof(*config));386break;387}388}389}390391if (i == vpif_ch_params_count) {392vpif_dbg(1, debug, "Format not found\n");393return -EINVAL;394}395396return 0;397}398399static int vpif_update_resolution(struct channel_obj *ch)400{401struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];402struct video_obj *vid_ch = &ch->video;403struct vpif_params *vpifparams = &ch->vpifparams;404struct vpif_channel_config_params *std_info = &vpifparams->std_info;405406if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height)407return -EINVAL;408409if (vid_ch->stdid || vid_ch->dv_preset) {410if (vpif_update_std_info(ch))411return -EINVAL;412}413414common->fmt.fmt.pix.width = std_info->width;415common->fmt.fmt.pix.height = std_info->height;416vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",417common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);418419/* Set height and width paramateres */420common->height = std_info->height;421common->width = std_info->width;422423return 0;424}425426/*427* vpif_calculate_offsets: This function calculates buffers offset for Y and C428* in the top and bottom field429*/430static void vpif_calculate_offsets(struct channel_obj *ch)431{432struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];433struct vpif_params *vpifparams = &ch->vpifparams;434enum v4l2_field field = common->fmt.fmt.pix.field;435struct video_obj *vid_ch = &ch->video;436unsigned int hpitch, vpitch, sizeimage;437438if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {439if (ch->vpifparams.std_info.frm_fmt)440vid_ch->buf_field = V4L2_FIELD_NONE;441else442vid_ch->buf_field = V4L2_FIELD_INTERLACED;443} else {444vid_ch->buf_field = common->fmt.fmt.pix.field;445}446447if (V4L2_MEMORY_USERPTR == common->memory)448sizeimage = common->fmt.fmt.pix.sizeimage;449else450sizeimage = config_params.channel_bufsize[ch->channel_id];451452hpitch = common->fmt.fmt.pix.bytesperline;453vpitch = sizeimage / (hpitch * 2);454if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||455(V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {456common->ytop_off = 0;457common->ybtm_off = hpitch;458common->ctop_off = sizeimage / 2;459common->cbtm_off = sizeimage / 2 + hpitch;460} else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) {461common->ytop_off = 0;462common->ybtm_off = sizeimage / 4;463common->ctop_off = sizeimage / 2;464common->cbtm_off = common->ctop_off + sizeimage / 4;465} else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) {466common->ybtm_off = 0;467common->ytop_off = sizeimage / 4;468common->cbtm_off = sizeimage / 2;469common->ctop_off = common->cbtm_off + sizeimage / 4;470}471472if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||473(V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {474vpifparams->video_params.storage_mode = 1;475} else {476vpifparams->video_params.storage_mode = 0;477}478479if (ch->vpifparams.std_info.frm_fmt == 1) {480vpifparams->video_params.hpitch =481common->fmt.fmt.pix.bytesperline;482} else {483if ((field == V4L2_FIELD_ANY) ||484(field == V4L2_FIELD_INTERLACED))485vpifparams->video_params.hpitch =486common->fmt.fmt.pix.bytesperline * 2;487else488vpifparams->video_params.hpitch =489common->fmt.fmt.pix.bytesperline;490}491492ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;493}494495static void vpif_config_format(struct channel_obj *ch)496{497struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];498499common->fmt.fmt.pix.field = V4L2_FIELD_ANY;500if (config_params.numbuffers[ch->channel_id] == 0)501common->memory = V4L2_MEMORY_USERPTR;502else503common->memory = V4L2_MEMORY_MMAP;504505common->fmt.fmt.pix.sizeimage =506config_params.channel_bufsize[ch->channel_id];507common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;508common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;509}510511static int vpif_check_format(struct channel_obj *ch,512struct v4l2_pix_format *pixfmt)513{514struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];515enum v4l2_field field = pixfmt->field;516u32 sizeimage, hpitch, vpitch;517518if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)519goto invalid_fmt_exit;520521if (!(VPIF_VALID_FIELD(field)))522goto invalid_fmt_exit;523524if (pixfmt->bytesperline <= 0)525goto invalid_pitch_exit;526527if (V4L2_MEMORY_USERPTR == common->memory)528sizeimage = pixfmt->sizeimage;529else530sizeimage = config_params.channel_bufsize[ch->channel_id];531532if (vpif_update_resolution(ch))533return -EINVAL;534535hpitch = pixfmt->bytesperline;536vpitch = sizeimage / (hpitch * 2);537538/* Check for valid value of pitch */539if ((hpitch < ch->vpifparams.std_info.width) ||540(vpitch < ch->vpifparams.std_info.height))541goto invalid_pitch_exit;542543/* Check for 8 byte alignment */544if (!ISALIGNED(hpitch)) {545vpif_err("invalid pitch alignment\n");546return -EINVAL;547}548pixfmt->width = common->fmt.fmt.pix.width;549pixfmt->height = common->fmt.fmt.pix.height;550551return 0;552553invalid_fmt_exit:554vpif_err("invalid field format\n");555return -EINVAL;556557invalid_pitch_exit:558vpif_err("invalid pitch\n");559return -EINVAL;560}561562static void vpif_config_addr(struct channel_obj *ch, int muxmode)563{564struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];565566if (VPIF_CHANNEL3_VIDEO == ch->channel_id) {567common->set_addr = ch3_set_videobuf_addr;568} else {569if (2 == muxmode)570common->set_addr = ch2_set_videobuf_addr_yc_nmux;571else572common->set_addr = ch2_set_videobuf_addr;573}574}575576/*577* vpif_mmap: It is used to map kernel space buffers into user spaces578*/579static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)580{581struct vpif_fh *fh = filep->private_data;582struct channel_obj *ch = fh->channel;583struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);584585vpif_dbg(2, debug, "vpif_mmap\n");586587return videobuf_mmap_mapper(&common->buffer_queue, vma);588}589590/*591* vpif_poll: It is used for select/poll system call592*/593static unsigned int vpif_poll(struct file *filep, poll_table *wait)594{595struct vpif_fh *fh = filep->private_data;596struct channel_obj *ch = fh->channel;597struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];598599if (common->started)600return videobuf_poll_stream(filep, &common->buffer_queue, wait);601602return 0;603}604605/*606* vpif_open: It creates object of file handle structure and stores it in607* private_data member of filepointer608*/609static int vpif_open(struct file *filep)610{611struct video_device *vdev = video_devdata(filep);612struct channel_obj *ch = NULL;613struct vpif_fh *fh = NULL;614615ch = video_get_drvdata(vdev);616/* Allocate memory for the file handle object */617fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);618if (fh == NULL) {619vpif_err("unable to allocate memory for file handle object\n");620return -ENOMEM;621}622623/* store pointer to fh in private_data member of filep */624filep->private_data = fh;625fh->channel = ch;626fh->initialized = 0;627if (!ch->initialized) {628fh->initialized = 1;629ch->initialized = 1;630memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));631}632633/* Increment channel usrs counter */634atomic_inc(&ch->usrs);635/* Set io_allowed[VPIF_VIDEO_INDEX] member to false */636fh->io_allowed[VPIF_VIDEO_INDEX] = 0;637/* Initialize priority of this instance to default priority */638fh->prio = V4L2_PRIORITY_UNSET;639v4l2_prio_open(&ch->prio, &fh->prio);640641return 0;642}643644/*645* vpif_release: This function deletes buffer queue, frees the buffers and646* the vpif file handle647*/648static int vpif_release(struct file *filep)649{650struct vpif_fh *fh = filep->private_data;651struct channel_obj *ch = fh->channel;652struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];653654/* if this instance is doing IO */655if (fh->io_allowed[VPIF_VIDEO_INDEX]) {656/* Reset io_usrs member of channel object */657common->io_usrs = 0;658/* Disable channel */659if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {660enable_channel2(0);661channel2_intr_enable(0);662}663if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||664(2 == common->started)) {665enable_channel3(0);666channel3_intr_enable(0);667}668common->started = 0;669/* Free buffers allocated */670videobuf_queue_cancel(&common->buffer_queue);671videobuf_mmap_free(&common->buffer_queue);672common->numbuffers =673config_params.numbuffers[ch->channel_id];674}675676/* Decrement channel usrs counter */677atomic_dec(&ch->usrs);678/* If this file handle has initialize encoder device, reset it */679if (fh->initialized)680ch->initialized = 0;681682/* Close the priority */683v4l2_prio_close(&ch->prio, fh->prio);684filep->private_data = NULL;685fh->initialized = 0;686kfree(fh);687688return 0;689}690691/* functions implementing ioctls */692/**693* vpif_querycap() - QUERYCAP handler694* @file: file ptr695* @priv: file handle696* @cap: ptr to v4l2_capability structure697*/698static int vpif_querycap(struct file *file, void *priv,699struct v4l2_capability *cap)700{701struct vpif_display_config *config = vpif_dev->platform_data;702703cap->version = VPIF_DISPLAY_VERSION_CODE;704cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;705strlcpy(cap->driver, "vpif display", sizeof(cap->driver));706strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));707strlcpy(cap->card, config->card_name, sizeof(cap->card));708709return 0;710}711712static int vpif_enum_fmt_vid_out(struct file *file, void *priv,713struct v4l2_fmtdesc *fmt)714{715if (fmt->index != 0) {716vpif_err("Invalid format index\n");717return -EINVAL;718}719720/* Fill in the information about format */721fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;722strcpy(fmt->description, "YCbCr4:2:2 YC Planar");723fmt->pixelformat = V4L2_PIX_FMT_YUV422P;724725return 0;726}727728static int vpif_g_fmt_vid_out(struct file *file, void *priv,729struct v4l2_format *fmt)730{731struct vpif_fh *fh = priv;732struct channel_obj *ch = fh->channel;733struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];734735/* Check the validity of the buffer type */736if (common->fmt.type != fmt->type)737return -EINVAL;738739if (vpif_update_resolution(ch))740return -EINVAL;741*fmt = common->fmt;742return 0;743}744745static int vpif_s_fmt_vid_out(struct file *file, void *priv,746struct v4l2_format *fmt)747{748struct vpif_fh *fh = priv;749struct v4l2_pix_format *pixfmt;750struct channel_obj *ch = fh->channel;751struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];752int ret = 0;753754if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)755|| (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {756if (!fh->initialized) {757vpif_dbg(1, debug, "Channel Busy\n");758return -EBUSY;759}760761/* Check for the priority */762ret = v4l2_prio_check(&ch->prio, fh->prio);763if (0 != ret)764return ret;765fh->initialized = 1;766}767768if (common->started) {769vpif_dbg(1, debug, "Streaming in progress\n");770return -EBUSY;771}772773pixfmt = &fmt->fmt.pix;774/* Check for valid field format */775ret = vpif_check_format(ch, pixfmt);776if (ret)777return ret;778779/* store the pix format in the channel object */780common->fmt.fmt.pix = *pixfmt;781/* store the format in the channel object */782common->fmt = *fmt;783return 0;784}785786static int vpif_try_fmt_vid_out(struct file *file, void *priv,787struct v4l2_format *fmt)788{789struct vpif_fh *fh = priv;790struct channel_obj *ch = fh->channel;791struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];792struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;793int ret = 0;794795ret = vpif_check_format(ch, pixfmt);796if (ret) {797*pixfmt = common->fmt.fmt.pix;798pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2;799}800801return ret;802}803804static int vpif_reqbufs(struct file *file, void *priv,805struct v4l2_requestbuffers *reqbuf)806{807struct vpif_fh *fh = priv;808struct channel_obj *ch = fh->channel;809struct common_obj *common;810enum v4l2_field field;811u8 index = 0;812813/* This file handle has not initialized the channel,814It is not allowed to do settings */815if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)816|| (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {817if (!fh->initialized) {818vpif_err("Channel Busy\n");819return -EBUSY;820}821}822823if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type)824return -EINVAL;825826index = VPIF_VIDEO_INDEX;827828common = &ch->common[index];829830if (common->fmt.type != reqbuf->type)831return -EINVAL;832833if (0 != common->io_usrs)834return -EBUSY;835836if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {837if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)838field = V4L2_FIELD_INTERLACED;839else840field = common->fmt.fmt.pix.field;841} else {842field = V4L2_VBI_INTERLACED;843}844845/* Initialize videobuf queue as per the buffer type */846videobuf_queue_dma_contig_init(&common->buffer_queue,847&video_qops, NULL,848&common->irqlock,849reqbuf->type, field,850sizeof(struct videobuf_buffer), fh,851&common->lock);852853/* Set io allowed member of file handle to TRUE */854fh->io_allowed[index] = 1;855/* Increment io usrs member of channel object to 1 */856common->io_usrs = 1;857/* Store type of memory requested in channel object */858common->memory = reqbuf->memory;859INIT_LIST_HEAD(&common->dma_queue);860861/* Allocate buffers */862return videobuf_reqbufs(&common->buffer_queue, reqbuf);863}864865static int vpif_querybuf(struct file *file, void *priv,866struct v4l2_buffer *tbuf)867{868struct vpif_fh *fh = priv;869struct channel_obj *ch = fh->channel;870struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];871872if (common->fmt.type != tbuf->type)873return -EINVAL;874875return videobuf_querybuf(&common->buffer_queue, tbuf);876}877878static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)879{880881struct vpif_fh *fh = priv;882struct channel_obj *ch = fh->channel;883struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];884struct v4l2_buffer tbuf = *buf;885struct videobuf_buffer *buf1;886unsigned long addr = 0;887unsigned long flags;888int ret = 0;889890if (common->fmt.type != tbuf.type)891return -EINVAL;892893if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {894vpif_err("fh->io_allowed\n");895return -EACCES;896}897898if (!(list_empty(&common->dma_queue)) ||899(common->cur_frm != common->next_frm) ||900!(common->started) ||901(common->started && (0 == ch->field_id)))902return videobuf_qbuf(&common->buffer_queue, buf);903904/* bufferqueue is empty store buffer address in VPIF registers */905mutex_lock(&common->buffer_queue.vb_lock);906buf1 = common->buffer_queue.bufs[tbuf.index];907if (buf1->memory != tbuf.memory) {908vpif_err("invalid buffer type\n");909goto qbuf_exit;910}911912if ((buf1->state == VIDEOBUF_QUEUED) ||913(buf1->state == VIDEOBUF_ACTIVE)) {914vpif_err("invalid state\n");915goto qbuf_exit;916}917918switch (buf1->memory) {919case V4L2_MEMORY_MMAP:920if (buf1->baddr == 0)921goto qbuf_exit;922break;923924case V4L2_MEMORY_USERPTR:925if (tbuf.length < buf1->bsize)926goto qbuf_exit;927928if ((VIDEOBUF_NEEDS_INIT != buf1->state)929&& (buf1->baddr != tbuf.m.userptr)) {930vpif_buffer_release(&common->buffer_queue, buf1);931buf1->baddr = tbuf.m.userptr;932}933break;934935default:936goto qbuf_exit;937}938939local_irq_save(flags);940ret = vpif_buffer_prepare(&common->buffer_queue, buf1,941common->buffer_queue.field);942if (ret < 0) {943local_irq_restore(flags);944goto qbuf_exit;945}946947buf1->state = VIDEOBUF_ACTIVE;948addr = buf1->boff;949common->next_frm = buf1;950if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {951common->set_addr((addr + common->ytop_off),952(addr + common->ybtm_off),953(addr + common->ctop_off),954(addr + common->cbtm_off));955}956957local_irq_restore(flags);958list_add_tail(&buf1->stream, &common->buffer_queue.stream);959mutex_unlock(&common->buffer_queue.vb_lock);960return 0;961962qbuf_exit:963mutex_unlock(&common->buffer_queue.vb_lock);964return -EINVAL;965}966967static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)968{969struct vpif_fh *fh = priv;970struct channel_obj *ch = fh->channel;971struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];972int ret = 0;973974if (!(*std_id & DM646X_V4L2_STD))975return -EINVAL;976977if (common->started) {978vpif_err("streaming in progress\n");979return -EBUSY;980}981982/* Call encoder subdevice function to set the standard */983ch->video.stdid = *std_id;984ch->video.dv_preset = V4L2_DV_INVALID;985memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));986987/* Get the information about the standard */988if (vpif_update_resolution(ch))989return -EINVAL;990991if ((ch->vpifparams.std_info.width *992ch->vpifparams.std_info.height * 2) >993config_params.channel_bufsize[ch->channel_id]) {994vpif_err("invalid std for this size\n");995return -EINVAL;996}997998common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;999/* Configure the default format information */1000vpif_config_format(ch);10011002ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,1003s_std_output, *std_id);1004if (ret < 0) {1005vpif_err("Failed to set output standard\n");1006return ret;1007}10081009ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,1010s_std, *std_id);1011if (ret < 0)1012vpif_err("Failed to set standard for sub devices\n");1013return ret;1014}10151016static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)1017{1018struct vpif_fh *fh = priv;1019struct channel_obj *ch = fh->channel;10201021*std = ch->video.stdid;1022return 0;1023}10241025static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)1026{1027struct vpif_fh *fh = priv;1028struct channel_obj *ch = fh->channel;1029struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];10301031return videobuf_dqbuf(&common->buffer_queue, p,1032(file->f_flags & O_NONBLOCK));1033}10341035static int vpif_streamon(struct file *file, void *priv,1036enum v4l2_buf_type buftype)1037{1038struct vpif_fh *fh = priv;1039struct channel_obj *ch = fh->channel;1040struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1041struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];1042struct vpif_params *vpif = &ch->vpifparams;1043struct vpif_display_config *vpif_config_data =1044vpif_dev->platform_data;1045unsigned long addr = 0;1046int ret = 0;10471048if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {1049vpif_err("buffer type not supported\n");1050return -EINVAL;1051}10521053if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {1054vpif_err("fh->io_allowed\n");1055return -EACCES;1056}10571058/* If Streaming is already started, return error */1059if (common->started) {1060vpif_err("channel->started\n");1061return -EBUSY;1062}10631064if ((ch->channel_id == VPIF_CHANNEL2_VIDEO1065&& oth_ch->common[VPIF_VIDEO_INDEX].started &&1066ch->vpifparams.std_info.ycmux_mode == 0)1067|| ((ch->channel_id == VPIF_CHANNEL3_VIDEO)1068&& (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {1069vpif_err("other channel is using\n");1070return -EBUSY;1071}10721073ret = vpif_check_format(ch, &common->fmt.fmt.pix);1074if (ret < 0)1075return ret;10761077/* Call videobuf_streamon to start streaming in videobuf */1078ret = videobuf_streamon(&common->buffer_queue);1079if (ret < 0) {1080vpif_err("videobuf_streamon\n");1081return ret;1082}10831084/* If buffer queue is empty, return error */1085if (list_empty(&common->dma_queue)) {1086vpif_err("buffer queue is empty\n");1087return -EIO;1088}10891090/* Get the next frame from the buffer queue */1091common->next_frm = common->cur_frm =1092list_entry(common->dma_queue.next,1093struct videobuf_buffer, queue);10941095list_del(&common->cur_frm->queue);1096/* Mark state of the current frame to active */1097common->cur_frm->state = VIDEOBUF_ACTIVE;10981099/* Initialize field_id and started member */1100ch->field_id = 0;1101common->started = 1;1102if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {1103addr = common->cur_frm->boff;1104/* Calculate the offset for Y and C data in the buffer */1105vpif_calculate_offsets(ch);11061107if ((ch->vpifparams.std_info.frm_fmt &&1108((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)1109&& (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))1110|| (!ch->vpifparams.std_info.frm_fmt1111&& (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {1112vpif_err("conflict in field format and std format\n");1113return -EINVAL;1114}11151116/* clock settings */1117ret =1118vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,1119ch->vpifparams.std_info.hd_sd);1120if (ret < 0) {1121vpif_err("can't set clock\n");1122return ret;1123}11241125/* set the parameters and addresses */1126ret = vpif_set_video_params(vpif, ch->channel_id + 2);1127if (ret < 0)1128return ret;11291130common->started = ret;1131vpif_config_addr(ch, ret);1132common->set_addr((addr + common->ytop_off),1133(addr + common->ybtm_off),1134(addr + common->ctop_off),1135(addr + common->cbtm_off));11361137/* Set interrupt for both the fields in VPIF1138Register enable channel in VPIF register */1139if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {1140channel2_intr_assert();1141channel2_intr_enable(1);1142enable_channel2(1);1143}11441145if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)1146|| (common->started == 2)) {1147channel3_intr_assert();1148channel3_intr_enable(1);1149enable_channel3(1);1150}1151channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;1152}1153return ret;1154}11551156static int vpif_streamoff(struct file *file, void *priv,1157enum v4l2_buf_type buftype)1158{1159struct vpif_fh *fh = priv;1160struct channel_obj *ch = fh->channel;1161struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];11621163if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {1164vpif_err("buffer type not supported\n");1165return -EINVAL;1166}11671168if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {1169vpif_err("fh->io_allowed\n");1170return -EACCES;1171}11721173if (!common->started) {1174vpif_err("channel->started\n");1175return -EINVAL;1176}11771178if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {1179/* disable channel */1180if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {1181enable_channel2(0);1182channel2_intr_enable(0);1183}1184if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||1185(2 == common->started)) {1186enable_channel3(0);1187channel3_intr_enable(0);1188}1189}11901191common->started = 0;1192return videobuf_streamoff(&common->buffer_queue);1193}11941195static int vpif_cropcap(struct file *file, void *priv,1196struct v4l2_cropcap *crop)1197{1198struct vpif_fh *fh = priv;1199struct channel_obj *ch = fh->channel;1200struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1201if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type)1202return -EINVAL;12031204crop->bounds.left = crop->bounds.top = 0;1205crop->defrect.left = crop->defrect.top = 0;1206crop->defrect.height = crop->bounds.height = common->height;1207crop->defrect.width = crop->bounds.width = common->width;12081209return 0;1210}12111212static int vpif_enum_output(struct file *file, void *fh,1213struct v4l2_output *output)1214{12151216struct vpif_display_config *config = vpif_dev->platform_data;12171218if (output->index >= config->output_count) {1219vpif_dbg(1, debug, "Invalid output index\n");1220return -EINVAL;1221}12221223strcpy(output->name, config->output[output->index]);1224output->type = V4L2_OUTPUT_TYPE_ANALOG;1225output->std = DM646X_V4L2_STD;12261227return 0;1228}12291230static int vpif_s_output(struct file *file, void *priv, unsigned int i)1231{1232struct vpif_fh *fh = priv;1233struct channel_obj *ch = fh->channel;1234struct video_obj *vid_ch = &ch->video;1235struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1236int ret = 0;12371238if (common->started) {1239vpif_err("Streaming in progress\n");1240return -EBUSY;1241}12421243ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,1244s_routing, 0, i, 0);12451246if (ret < 0)1247vpif_err("Failed to set output standard\n");12481249vid_ch->output_id = i;1250return ret;1251}12521253static int vpif_g_output(struct file *file, void *priv, unsigned int *i)1254{1255struct vpif_fh *fh = priv;1256struct channel_obj *ch = fh->channel;1257struct video_obj *vid_ch = &ch->video;12581259*i = vid_ch->output_id;12601261return 0;1262}12631264static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p)1265{1266struct vpif_fh *fh = priv;1267struct channel_obj *ch = fh->channel;12681269*p = v4l2_prio_max(&ch->prio);12701271return 0;1272}12731274static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)1275{1276struct vpif_fh *fh = priv;1277struct channel_obj *ch = fh->channel;12781279return v4l2_prio_change(&ch->prio, &fh->prio, p);1280}12811282/**1283* vpif_enum_dv_presets() - ENUM_DV_PRESETS handler1284* @file: file ptr1285* @priv: file handle1286* @preset: input preset1287*/1288static int vpif_enum_dv_presets(struct file *file, void *priv,1289struct v4l2_dv_enum_preset *preset)1290{1291struct vpif_fh *fh = priv;1292struct channel_obj *ch = fh->channel;1293struct video_obj *vid_ch = &ch->video;12941295return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],1296video, enum_dv_presets, preset);1297}12981299/**1300* vpif_s_dv_presets() - S_DV_PRESETS handler1301* @file: file ptr1302* @priv: file handle1303* @preset: input preset1304*/1305static int vpif_s_dv_preset(struct file *file, void *priv,1306struct v4l2_dv_preset *preset)1307{1308struct vpif_fh *fh = priv;1309struct channel_obj *ch = fh->channel;1310struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];1311struct video_obj *vid_ch = &ch->video;1312int ret = 0;13131314if (common->started) {1315vpif_dbg(1, debug, "streaming in progress\n");1316return -EBUSY;1317}13181319ret = v4l2_prio_check(&ch->prio, fh->prio);1320if (ret != 0)1321return ret;13221323fh->initialized = 1;13241325/* Call encoder subdevice function to set the standard */1326if (mutex_lock_interruptible(&common->lock))1327return -ERESTARTSYS;13281329ch->video.dv_preset = preset->preset;1330ch->video.stdid = V4L2_STD_UNKNOWN;1331memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));13321333/* Get the information about the standard */1334if (vpif_update_resolution(ch)) {1335ret = -EINVAL;1336} else {1337/* Configure the default format information */1338vpif_config_format(ch);13391340ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],1341video, s_dv_preset, preset);1342}13431344mutex_unlock(&common->lock);13451346return ret;1347}1348/**1349* vpif_g_dv_presets() - G_DV_PRESETS handler1350* @file: file ptr1351* @priv: file handle1352* @preset: input preset1353*/1354static int vpif_g_dv_preset(struct file *file, void *priv,1355struct v4l2_dv_preset *preset)1356{1357struct vpif_fh *fh = priv;1358struct channel_obj *ch = fh->channel;13591360preset->preset = ch->video.dv_preset;13611362return 0;1363}1364/**1365* vpif_s_dv_timings() - S_DV_TIMINGS handler1366* @file: file ptr1367* @priv: file handle1368* @timings: digital video timings1369*/1370static int vpif_s_dv_timings(struct file *file, void *priv,1371struct v4l2_dv_timings *timings)1372{1373struct vpif_fh *fh = priv;1374struct channel_obj *ch = fh->channel;1375struct vpif_params *vpifparams = &ch->vpifparams;1376struct vpif_channel_config_params *std_info = &vpifparams->std_info;1377struct video_obj *vid_ch = &ch->video;1378struct v4l2_bt_timings *bt = &vid_ch->bt_timings;1379int ret;13801381if (timings->type != V4L2_DV_BT_656_1120) {1382vpif_dbg(2, debug, "Timing type not defined\n");1383return -EINVAL;1384}13851386/* Configure subdevice timings, if any */1387ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],1388video, s_dv_timings, timings);1389if (ret == -ENOIOCTLCMD) {1390vpif_dbg(2, debug, "Custom DV timings not supported by "1391"subdevice\n");1392return -EINVAL;1393}1394if (ret < 0) {1395vpif_dbg(2, debug, "Error setting custom DV timings\n");1396return ret;1397}13981399if (!(timings->bt.width && timings->bt.height &&1400(timings->bt.hbackporch ||1401timings->bt.hfrontporch ||1402timings->bt.hsync) &&1403timings->bt.vfrontporch &&1404(timings->bt.vbackporch ||1405timings->bt.vsync))) {1406vpif_dbg(2, debug, "Timings for width, height, "1407"horizontal back porch, horizontal sync, "1408"horizontal front porch, vertical back porch, "1409"vertical sync and vertical back porch "1410"must be defined\n");1411return -EINVAL;1412}14131414*bt = timings->bt;14151416/* Configure video port timings */14171418std_info->eav2sav = bt->hbackporch + bt->hfrontporch +1419bt->hsync - 8;1420std_info->sav2eav = bt->width;14211422std_info->l1 = 1;1423std_info->l3 = bt->vsync + bt->vbackporch + 1;14241425if (bt->interlaced) {1426if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {1427std_info->vsize = bt->height * 2 +1428bt->vfrontporch + bt->vsync + bt->vbackporch +1429bt->il_vfrontporch + bt->il_vsync +1430bt->il_vbackporch;1431std_info->l5 = std_info->vsize/2 -1432(bt->vfrontporch - 1);1433std_info->l7 = std_info->vsize/2 + 1;1434std_info->l9 = std_info->l7 + bt->il_vsync +1435bt->il_vbackporch + 1;1436std_info->l11 = std_info->vsize -1437(bt->il_vfrontporch - 1);1438} else {1439vpif_dbg(2, debug, "Required timing values for "1440"interlaced BT format missing\n");1441return -EINVAL;1442}1443} else {1444std_info->vsize = bt->height + bt->vfrontporch +1445bt->vsync + bt->vbackporch;1446std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);1447}1448strncpy(std_info->name, "Custom timings BT656/1120",1449VPIF_MAX_NAME);1450std_info->width = bt->width;1451std_info->height = bt->height;1452std_info->frm_fmt = bt->interlaced ? 0 : 1;1453std_info->ycmux_mode = 0;1454std_info->capture_format = 0;1455std_info->vbi_supported = 0;1456std_info->hd_sd = 1;1457std_info->stdid = 0;1458std_info->dv_preset = V4L2_DV_INVALID;14591460vid_ch->stdid = 0;1461vid_ch->dv_preset = V4L2_DV_INVALID;14621463return 0;1464}14651466/**1467* vpif_g_dv_timings() - G_DV_TIMINGS handler1468* @file: file ptr1469* @priv: file handle1470* @timings: digital video timings1471*/1472static int vpif_g_dv_timings(struct file *file, void *priv,1473struct v4l2_dv_timings *timings)1474{1475struct vpif_fh *fh = priv;1476struct channel_obj *ch = fh->channel;1477struct video_obj *vid_ch = &ch->video;1478struct v4l2_bt_timings *bt = &vid_ch->bt_timings;14791480timings->bt = *bt;14811482return 0;1483}14841485/*1486* vpif_g_chip_ident() - Identify the chip1487* @file: file ptr1488* @priv: file handle1489* @chip: chip identity1490*1491* Returns zero or -EINVAL if read operations fails.1492*/1493static int vpif_g_chip_ident(struct file *file, void *priv,1494struct v4l2_dbg_chip_ident *chip)1495{1496chip->ident = V4L2_IDENT_NONE;1497chip->revision = 0;1498if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&1499chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {1500vpif_dbg(2, debug, "match_type is invalid.\n");1501return -EINVAL;1502}15031504return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,1505g_chip_ident, chip);1506}15071508#ifdef CONFIG_VIDEO_ADV_DEBUG1509/*1510* vpif_dbg_g_register() - Read register1511* @file: file ptr1512* @priv: file handle1513* @reg: register to be read1514*1515* Debugging only1516* Returns zero or -EINVAL if read operations fails.1517*/1518static int vpif_dbg_g_register(struct file *file, void *priv,1519struct v4l2_dbg_register *reg){1520struct vpif_fh *fh = priv;1521struct channel_obj *ch = fh->channel;1522struct video_obj *vid_ch = &ch->video;15231524return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,1525g_register, reg);1526}15271528/*1529* vpif_dbg_s_register() - Write to register1530* @file: file ptr1531* @priv: file handle1532* @reg: register to be modified1533*1534* Debugging only1535* Returns zero or -EINVAL if write operations fails.1536*/1537static int vpif_dbg_s_register(struct file *file, void *priv,1538struct v4l2_dbg_register *reg){1539struct vpif_fh *fh = priv;1540struct channel_obj *ch = fh->channel;1541struct video_obj *vid_ch = &ch->video;15421543return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,1544s_register, reg);1545}1546#endif15471548/*1549* vpif_log_status() - Status information1550* @file: file ptr1551* @priv: file handle1552*1553* Returns zero.1554*/1555static int vpif_log_status(struct file *filep, void *priv)1556{1557/* status for sub devices */1558v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);15591560return 0;1561}15621563/* vpif display ioctl operations */1564static const struct v4l2_ioctl_ops vpif_ioctl_ops = {1565.vidioc_querycap = vpif_querycap,1566.vidioc_g_priority = vpif_g_priority,1567.vidioc_s_priority = vpif_s_priority,1568.vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out,1569.vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,1570.vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,1571.vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,1572.vidioc_reqbufs = vpif_reqbufs,1573.vidioc_querybuf = vpif_querybuf,1574.vidioc_qbuf = vpif_qbuf,1575.vidioc_dqbuf = vpif_dqbuf,1576.vidioc_streamon = vpif_streamon,1577.vidioc_streamoff = vpif_streamoff,1578.vidioc_s_std = vpif_s_std,1579.vidioc_g_std = vpif_g_std,1580.vidioc_enum_output = vpif_enum_output,1581.vidioc_s_output = vpif_s_output,1582.vidioc_g_output = vpif_g_output,1583.vidioc_cropcap = vpif_cropcap,1584.vidioc_enum_dv_presets = vpif_enum_dv_presets,1585.vidioc_s_dv_preset = vpif_s_dv_preset,1586.vidioc_g_dv_preset = vpif_g_dv_preset,1587.vidioc_s_dv_timings = vpif_s_dv_timings,1588.vidioc_g_dv_timings = vpif_g_dv_timings,1589.vidioc_g_chip_ident = vpif_g_chip_ident,1590#ifdef CONFIG_VIDEO_ADV_DEBUG1591.vidioc_g_register = vpif_dbg_g_register,1592.vidioc_s_register = vpif_dbg_s_register,1593#endif1594.vidioc_log_status = vpif_log_status,1595};15961597static const struct v4l2_file_operations vpif_fops = {1598.owner = THIS_MODULE,1599.open = vpif_open,1600.release = vpif_release,1601.unlocked_ioctl = video_ioctl2,1602.mmap = vpif_mmap,1603.poll = vpif_poll1604};16051606static struct video_device vpif_video_template = {1607.name = "vpif",1608.fops = &vpif_fops,1609.ioctl_ops = &vpif_ioctl_ops,1610.tvnorms = DM646X_V4L2_STD,1611.current_norm = V4L2_STD_625_50,16121613};16141615/*Configure the channels, buffer sizei, request irq */1616static int initialize_vpif(void)1617{1618int free_channel_objects_index;1619int free_buffer_channel_index;1620int free_buffer_index;1621int err = 0, i, j;16221623/* Default number of buffers should be 3 */1624if ((ch2_numbuffers > 0) &&1625(ch2_numbuffers < config_params.min_numbuffers))1626ch2_numbuffers = config_params.min_numbuffers;1627if ((ch3_numbuffers > 0) &&1628(ch3_numbuffers < config_params.min_numbuffers))1629ch3_numbuffers = config_params.min_numbuffers;16301631/* Set buffer size to min buffers size if invalid buffer size is1632* given */1633if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO])1634ch2_bufsize =1635config_params.min_bufsize[VPIF_CHANNEL2_VIDEO];1636if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO])1637ch3_bufsize =1638config_params.min_bufsize[VPIF_CHANNEL3_VIDEO];16391640config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers;16411642if (ch2_numbuffers) {1643config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] =1644ch2_bufsize;1645}1646config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers;16471648if (ch3_numbuffers) {1649config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] =1650ch3_bufsize;1651}16521653/* Allocate memory for six channel objects */1654for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {1655vpif_obj.dev[i] =1656kzalloc(sizeof(struct channel_obj), GFP_KERNEL);1657/* If memory allocation fails, return error */1658if (!vpif_obj.dev[i]) {1659free_channel_objects_index = i;1660err = -ENOMEM;1661goto vpif_init_free_channel_objects;1662}1663}16641665free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES;1666free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS;1667free_buffer_index = config_params.numbuffers[i - 1];16681669return 0;16701671vpif_init_free_channel_objects:1672for (j = 0; j < free_channel_objects_index; j++)1673kfree(vpif_obj.dev[j]);1674return err;1675}16761677/*1678* vpif_probe: This function creates device entries by register itself to the1679* V4L2 driver and initializes fields of each channel objects1680*/1681static __init int vpif_probe(struct platform_device *pdev)1682{1683struct vpif_subdev_info *subdevdata;1684struct vpif_display_config *config;1685int i, j = 0, k, q, m, err = 0;1686struct i2c_adapter *i2c_adap;1687struct common_obj *common;1688struct channel_obj *ch;1689struct video_device *vfd;1690struct resource *res;1691int subdev_count;16921693vpif_dev = &pdev->dev;16941695err = initialize_vpif();16961697if (err) {1698v4l2_err(vpif_dev->driver, "Error initializing vpif\n");1699return err;1700}17011702err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);1703if (err) {1704v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");1705return err;1706}17071708k = 0;1709while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {1710for (i = res->start; i <= res->end; i++) {1711if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,1712"DM646x_Display",1713(void *)(&vpif_obj.dev[k]->channel_id))) {1714err = -EBUSY;1715goto vpif_int_err;1716}1717}1718k++;1719}17201721for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {17221723/* Get the pointer to the channel object */1724ch = vpif_obj.dev[i];17251726/* Allocate memory for video device */1727vfd = video_device_alloc();1728if (vfd == NULL) {1729for (j = 0; j < i; j++) {1730ch = vpif_obj.dev[j];1731video_device_release(ch->video_dev);1732}1733err = -ENOMEM;1734goto vpif_int_err;1735}17361737/* Initialize field of video device */1738*vfd = vpif_video_template;1739vfd->v4l2_dev = &vpif_obj.v4l2_dev;1740vfd->release = video_device_release;1741snprintf(vfd->name, sizeof(vfd->name),1742"DM646x_VPIFDisplay_DRIVER_V%d.%d.%d",1743(VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff,1744(VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff,1745(VPIF_DISPLAY_VERSION_CODE) & 0xff);17461747/* Set video_dev to the video device */1748ch->video_dev = vfd;1749}17501751for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {1752ch = vpif_obj.dev[j];1753/* Initialize field of the channel objects */1754atomic_set(&ch->usrs, 0);1755for (k = 0; k < VPIF_NUMOBJECTS; k++) {1756ch->common[k].numbuffers = 0;1757common = &ch->common[k];1758common->io_usrs = 0;1759common->started = 0;1760spin_lock_init(&common->irqlock);1761mutex_init(&common->lock);1762common->numbuffers = 0;1763common->set_addr = NULL;1764common->ytop_off = common->ybtm_off = 0;1765common->ctop_off = common->cbtm_off = 0;1766common->cur_frm = common->next_frm = NULL;1767memset(&common->fmt, 0, sizeof(common->fmt));1768common->numbuffers = config_params.numbuffers[k];17691770}1771ch->initialized = 0;1772ch->channel_id = j;1773if (j < 2)1774ch->common[VPIF_VIDEO_INDEX].numbuffers =1775config_params.numbuffers[ch->channel_id];1776else1777ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;17781779memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));17801781/* Initialize prio member of channel object */1782v4l2_prio_init(&ch->prio);1783ch->common[VPIF_VIDEO_INDEX].fmt.type =1784V4L2_BUF_TYPE_VIDEO_OUTPUT;1785ch->video_dev->lock = &common->lock;17861787/* register video device */1788vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",1789(int)ch, (int)&ch->video_dev);17901791err = video_register_device(ch->video_dev,1792VFL_TYPE_GRABBER, (j ? 3 : 2));1793if (err < 0)1794goto probe_out;17951796video_set_drvdata(ch->video_dev, ch);1797}17981799i2c_adap = i2c_get_adapter(1);1800config = pdev->dev.platform_data;1801subdev_count = config->subdev_count;1802subdevdata = config->subdevinfo;1803vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,1804GFP_KERNEL);1805if (vpif_obj.sd == NULL) {1806vpif_err("unable to allocate memory for subdevice pointers\n");1807err = -ENOMEM;1808goto probe_out;1809}18101811for (i = 0; i < subdev_count; i++) {1812vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,1813i2c_adap,1814&subdevdata[i].board_info,1815NULL);1816if (!vpif_obj.sd[i]) {1817vpif_err("Error registering v4l2 subdevice\n");1818goto probe_subdev_out;1819}18201821if (vpif_obj.sd[i])1822vpif_obj.sd[i]->grp_id = 1 << i;1823}18241825v4l2_info(&vpif_obj.v4l2_dev,1826"DM646x VPIF display driver initialized\n");1827return 0;18281829probe_subdev_out:1830kfree(vpif_obj.sd);1831probe_out:1832for (k = 0; k < j; k++) {1833ch = vpif_obj.dev[k];1834video_unregister_device(ch->video_dev);1835video_device_release(ch->video_dev);1836ch->video_dev = NULL;1837}1838vpif_int_err:1839v4l2_device_unregister(&vpif_obj.v4l2_dev);1840vpif_err("VPIF IRQ request failed\n");1841for (q = k; k >= 0; k--) {1842for (m = i; m >= res->start; m--)1843free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));1844res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);1845m = res->end;1846}18471848return err;1849}18501851/*1852* vpif_remove: It un-register channels from V4L2 driver1853*/1854static int vpif_remove(struct platform_device *device)1855{1856struct channel_obj *ch;1857int i;18581859v4l2_device_unregister(&vpif_obj.v4l2_dev);18601861/* un-register device */1862for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {1863/* Get the pointer to the channel object */1864ch = vpif_obj.dev[i];1865/* Unregister video device */1866video_unregister_device(ch->video_dev);18671868ch->video_dev = NULL;1869}18701871return 0;1872}18731874static __refdata struct platform_driver vpif_driver = {1875.driver = {1876.name = "vpif_display",1877.owner = THIS_MODULE,1878},1879.probe = vpif_probe,1880.remove = vpif_remove,1881};18821883static __init int vpif_init(void)1884{1885return platform_driver_register(&vpif_driver);1886}18871888/*1889* vpif_cleanup: This function un-registers device and driver to the kernel,1890* frees requested irq handler and de-allocates memory allocated for channel1891* objects.1892*/1893static void vpif_cleanup(void)1894{1895struct platform_device *pdev;1896struct resource *res;1897int irq_num;1898int i = 0;18991900pdev = container_of(vpif_dev, struct platform_device, dev);19011902while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) {1903for (irq_num = res->start; irq_num <= res->end; irq_num++)1904free_irq(irq_num,1905(void *)(&vpif_obj.dev[i]->channel_id));1906i++;1907}19081909platform_driver_unregister(&vpif_driver);1910kfree(vpif_obj.sd);1911for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)1912kfree(vpif_obj.dev[i]);1913}19141915module_init(vpif_init);1916module_exit(vpif_cleanup);191719181919