1 From 38f3cd5564a466e5251fc2ff47e0504148922304 Mon Sep 17 00:00:00 2001
2 From: Vaibhav Hiremath <vaibhav@psp-nfs-02.india.ti.com>
3 Date: Wed, 29 Apr 2009 17:18:56 +0530
4 Subject: [PATCH 23/26] OMAP-Resizer: Basic Resizer refreshed with latest gitorious tree
6 This is same resizer driver patch posted by Sergio onto
7 mailing list quite a some time back. This commit refreshes
8 the same patch on top of latest gitorious.org tree.
10 List of New/Modified files:
11 modified: drivers/media/video/Kconfig
12 modified: drivers/media/video/isp/Makefile
13 modified: drivers/media/video/isp/isp.c
14 modified: drivers/media/video/isp/ispreg.h
15 new file: drivers/media/video/isp/omap_resizer.c
16 new file: include/linux/omap_resizer.h
19 - Resizer driver needs to be independent from camera and ISP
20 - Custom patches implemented ontop of PSP1.0.2 release
21 to fix some V4L2-buf layer issues.
24 drivers/media/video/Kconfig | 7 +
25 drivers/media/video/isp/Makefile | 4 +
26 drivers/media/video/isp/isp.c | 15 +
27 drivers/media/video/isp/omap_resizer.c | 1634 ++++++++++++++++++++++++++++++++
28 include/linux/omap_resizer.h | 136 +++
29 5 files changed, 1796 insertions(+), 0 deletions(-)
30 create mode 100644 drivers/media/video/isp/omap_resizer.c
31 create mode 100644 include/linux/omap_resizer.h
33 diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
34 index 3cdb5a4..d2b4ae1 100644
35 --- a/drivers/media/video/Kconfig
36 +++ b/drivers/media/video/Kconfig
37 @@ -720,6 +720,13 @@ config VIDEO_OMAP3
39 Driver for an OMAP 3 camera controller.
41 +config VIDEO_OMAP34XX_ISP_RESIZER
42 + tristate "OMAP ISP Resizer"
43 + depends on VIDEO_V4L2 && ARCH_OMAP34XX
45 + select VIDEOBUF_DMA_SG
49 tristate "SoC camera support"
50 depends on VIDEO_V4L2 && HAS_DMA
51 diff --git a/drivers/media/video/isp/Makefile b/drivers/media/video/isp/Makefile
52 index f14d617..d171fb9 100644
53 --- a/drivers/media/video/isp/Makefile
54 +++ b/drivers/media/video/isp/Makefile
57 isp.o ispccdc.o ispmmu.o \
58 isppreview.o ispresizer.o isph3a.o isphist.o isp_af.o ispcsi2.o
60 +obj-$(CONFIG_VIDEO_OMAP34XX_ISP_RESIZER) += \
65 obj-$(CONFIG_VIDEO_OMAP3) += isp-mod.o
66 diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c
67 index 54c839b..f1f92b4 100644
68 --- a/drivers/media/video/isp/isp.c
69 +++ b/drivers/media/video/isp/isp.c
70 @@ -505,6 +505,12 @@ int isp_set_callback(enum isp_callback_type type, isp_callback_t callback,
71 isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
72 IRQ0ENABLE_PRV_DONE_IRQ);
75 + isp_reg_writel(IRQ0ENABLE_RSZ_DONE_IRQ,
76 + OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
77 + isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
78 + IRQ0ENABLE_RSZ_DONE_IRQ);
83 @@ -556,6 +562,10 @@ int isp_unset_callback(enum isp_callback_type type)
84 isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
85 ~IRQ0ENABLE_PRV_DONE_IRQ);
88 + isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
89 + ~IRQ0ENABLE_RSZ_DONE_IRQ);
94 @@ -938,6 +948,11 @@ static irqreturn_t omap34xx_isp_isr(int irq, void *_isp)
95 if (!ispresizer_busy())
96 ispresizer_config_shadow_registers();
97 isp_buf_process(bufs);
99 + if (irqdis->isp_callbk[CBK_RESZ_DONE])
100 + irqdis->isp_callbk[CBK_RESZ_DONE](RESZ_DONE,
101 + irqdis->isp_callbk_arg1[CBK_RESZ_DONE],
102 + irqdis->isp_callbk_arg2[CBK_RESZ_DONE]);
106 diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c
108 index 0000000..54bc425
110 +++ b/drivers/media/video/isp/omap_resizer.c
113 + * drivers/media/video/isp/omap_resizer.c
115 + * Wrapper for Resizer module in TI's OMAP3430 ISP
117 + * Copyright (C) 2008 Texas Instruments, Inc.
120 + * Sergio Aguirre <saaguirre@ti.com>
121 + * Troy Laramy <t-laramy@ti.com>
123 + * This package is free software; you can redistribute it and/or modify
124 + * it under the terms of the GNU General Public License version 2 as
125 + * published by the Free Software Foundation.
127 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
128 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
129 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
132 +#include <linux/mutex.h>
133 +#include <linux/cdev.h>
134 +#include <linux/delay.h>
135 +#include <linux/device.h>
136 +#include <linux/fs.h>
137 +#include <linux/mm.h>
138 +#include <linux/module.h>
139 +#include <linux/platform_device.h>
140 +#include <linux/io.h>
141 +#include <linux/uaccess.h>
142 +#include <media/v4l2-dev.h>
143 +#include <asm/cacheflush.h>
148 +#include "ispresizer.h"
149 +#include <linux/omap_resizer.h>
151 +#define OMAP_REZR_NAME "omap-resizer"
153 +/* Defines and Constants*/
154 +#define MAX_CHANNELS 16
155 +#define MAX_IMAGE_WIDTH 2047
156 +#define MAX_IMAGE_WIDTH_HIGH 2047
157 +#define ALIGNMENT 16
158 +#define CHANNEL_BUSY 1
159 +#define CHANNEL_FREE 0
160 +#define PIXEL_EVEN 2
161 +#define RATIO_MULTIPLIER 256
162 +/* Bit position Macro */
163 +/* macro for bit set and clear */
164 +#define BITSET(variable, bit) ((variable) | (1 << bit))
165 +#define BITRESET(variable, bit) ((variable) & ~(0x00000001 << (bit)))
166 +#define SET_BIT_INPUTRAM 28
167 +#define SET_BIT_CBLIN 29
168 +#define SET_BIT_INPTYP 27
169 +#define SET_BIT_YCPOS 26
171 +#define UP_RSZ_RATIO 64
172 +#define DOWN_RSZ_RATIO 512
173 +#define UP_RSZ_RATIO1 513
174 +#define DOWN_RSZ_RATIO1 1024
175 +#define RSZ_IN_SIZE_VERT_SHIFT 16
176 +#define MAX_HORZ_PIXEL_8BIT 31
177 +#define MAX_HORZ_PIXEL_16BIT 15
178 +#define NUM_PHASES 8
180 +#define NUM_D2PH 4 /* for downsampling * 2+x ~ 4x,
183 +#define NUM_D2TAPS 7 /* for downsampling * 2+x ~ 4x,
187 +#define MAX_COEF_COUNTER 16
188 +#define COEFF_ADDRESS_OFFSET 0x04
190 +/* Global structure which contains information about number of channels
191 + and protection variables */
192 +struct device_params {
194 + unsigned char opened; /* state of the device */
195 + struct completion compl_isr; /* Completion for interrupt */
196 + struct mutex reszwrap_mutex; /* Semaphore for array */
198 + struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */
201 +/* Register mapped structure which contains the every register
203 +struct resizer_config {
204 + u32 rsz_pcr; /* pcr register mapping
207 + u32 rsz_in_start; /* in_start register mapping
210 + u32 rsz_in_size; /* in_size register mapping
213 + u32 rsz_out_size; /* out_size register mapping
216 + u32 rsz_cnt; /* rsz_cnt register mapping
219 + u32 rsz_sdr_inadd; /* sdr_inadd register mapping
222 + u32 rsz_sdr_inoff; /* sdr_inoff register mapping
225 + u32 rsz_sdr_outadd; /* sdr_outadd register mapping
228 + u32 rsz_sdr_outoff; /* sdr_outbuff register
229 + * mapping variable.
231 + u32 rsz_coeff_horz[16]; /* horizontal coefficients
234 + u32 rsz_coeff_vert[16]; /* vertical coefficients
237 + u32 rsz_yehn; /* yehn(luma)register mapping
243 + int in_hsize; /* input frame horizontal
246 + int in_vsize; /* input frame vertical size.
248 + int out_hsize; /* output frame horizontal
251 + int out_vsize; /* output frame vertical
254 + int in_pitch; /* offset between two rows of
257 + int out_pitch; /* offset between two rows of
262 + int num_htap; /* 0 = 7tap; 1 = 4tap */
263 + int num_vtap; /* 0 = 7tap; 1 = 4tap */
268 + int hstph; /* for specifying horizontal
272 + int pix_fmt; /* # defined, UYVY or YUYV. */
273 + int cbilin; /* # defined, filter with luma
276 + u16 tap4filt_coeffs[32]; /* horizontal filter
279 + u16 tap7filt_coeffs[32]; /* vertical filter
283 +/* Channel specific structure contains information regarding
284 + the every channel */
285 +struct channel_config {
286 + struct resizer_config register_config; /* Instance of register set
287 + * mapping structure
289 + int status; /* Specifies whether the
290 + * channel is busy or not
292 + struct mutex chanprotection_mutex;
293 + enum config_done config_state;
294 + u8 input_buf_index;
295 + u8 output_buf_index;
299 +/* per-filehandle data structure */
301 + struct rsz_params *params;
302 + struct channel_config *config;
303 + struct rsz_mult *multipass; /* Multipass to support
304 + * resizing ration outside
307 + spinlock_t vbq_lock; /* spinlock for videobuf
310 + enum v4l2_buf_type type;
311 + struct videobuf_queue vbq;
312 + struct device_params *device;
314 + dma_addr_t isp_addr_read; /* Input/Output address */
315 + dma_addr_t isp_addr_write; /* Input/Output address */
316 + u32 rsz_bufsize; /* channel specific buffersize
320 +static struct device_params *device_config;
321 +static struct device *rsz_device;
322 +static int rsz_major = -1;
323 +/* functions declaration */
324 +static void rsz_hardware_setup(struct channel_config *rsz_conf_chan);
325 +static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *,
326 + struct channel_config *);
327 +static int rsz_get_params(struct rsz_params *, struct channel_config *);
328 +static void rsz_copy_data(struct rsz_mult *multipass,
329 + struct rsz_params *params);
330 +static void rsz_isr(unsigned long status, isp_vbq_callback_ptr arg1,
332 +static void rsz_calculate_crop(struct channel_config *rsz_conf_chan,
333 + struct rsz_cropsize *cropsize);
334 +static int rsz_set_multipass(struct rsz_mult *multipass,
335 + struct channel_config *rsz_conf_chan);
336 +static int rsz_set_ratio(struct rsz_mult *multipass,
337 + struct channel_config *rsz_conf_chan);
338 +static void rsz_config_ratio(struct rsz_mult *multipass,
339 + struct channel_config *rsz_conf_chan);
342 + * rsz_hardware_setup - Sets hardware configuration registers
343 + * @rsz_conf_chan: Structure containing channel configuration
345 + * Set hardware configuration registers
347 +static void rsz_hardware_setup(struct channel_config *rsz_conf_chan)
350 + int coeffoffset = 0;
352 + omap_writel(rsz_conf_chan->register_config.rsz_cnt,
353 + OMAP3ISP_RESZ_REG(ISPRSZ_CNT));
355 + omap_writel(rsz_conf_chan->register_config.rsz_in_start,
356 + OMAP3ISP_RESZ_REG(ISPRSZ_IN_START));
357 + omap_writel(rsz_conf_chan->register_config.rsz_in_size,
358 + OMAP3ISP_RESZ_REG(ISPRSZ_IN_SIZE));
360 + omap_writel(rsz_conf_chan->register_config.rsz_out_size,
361 + OMAP3ISP_RESZ_REG(ISPRSZ_OUT_SIZE));
362 + omap_writel(rsz_conf_chan->register_config.rsz_sdr_inadd,
363 + OMAP3ISP_RESZ_REG(ISPRSZ_SDR_INADD));
364 + omap_writel(rsz_conf_chan->register_config.rsz_sdr_inoff,
365 + OMAP3ISP_RESZ_REG(ISPRSZ_SDR_INOFF));
366 + omap_writel(rsz_conf_chan->register_config.rsz_sdr_outadd,
367 + OMAP3ISP_RESZ_REG(ISPRSZ_SDR_OUTADD));
368 + omap_writel(rsz_conf_chan->register_config.rsz_sdr_outoff,
369 + OMAP3ISP_RESZ_REG(ISPRSZ_SDR_OUTOFF));
370 + omap_writel(rsz_conf_chan->register_config.rsz_yehn, OMAP3ISP_RESZ_REG(ISPRSZ_YENH));
372 + for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
374 + omap_writel(rsz_conf_chan->register_config.
375 + rsz_coeff_horz[coeffcounter],
376 + OMAP3ISP_RESZ_REG(ISPRSZ_HFILT10
379 + omap_writel(rsz_conf_chan->register_config.
380 + rsz_coeff_vert[coeffcounter],
381 + OMAP3ISP_RESZ_REG(ISPRSZ_VFILT10
383 + coeffoffset = coeffoffset + COEFF_ADDRESS_OFFSET;
388 + * rsz_start - Enables Resizer Wrapper
389 + * @arg: Currently not used.
390 + * @device: Structure containing ISP resizer wrapper global information
392 + * Submits a resizing task specified by the rsz_resize structure. The call can
393 + * either be blocked until the task is completed or returned immediately based
394 + * on the value of the blocking argument in the rsz_resize structure. If it is
395 + * blocking, the status of the task can be checked by calling ioctl
396 + * RSZ_G_STATUS. Only one task can be outstanding for each logical channel.
398 + * Returns 0 if successful, or -EINVAL if could not set callback for RSZR IRQ
399 + * event or the state of the channel is not configured.
401 +int rsz_start(int *arg, struct rsz_fh *fh)
403 + struct channel_config *rsz_conf_chan = fh->config;
404 + struct rsz_mult *multipass = fh->multipass;
405 + struct videobuf_queue *q = &fh->vbq;
408 + if (rsz_conf_chan->config_state) {
409 + dev_err(rsz_device, "State not configured \n");
413 + rsz_conf_chan->status = CHANNEL_BUSY;
415 + rsz_hardware_setup(rsz_conf_chan);
417 + if (isp_set_callback(CBK_RESZ_DONE, rsz_isr, (void *) NULL,
419 + dev_err(rsz_device, "No callback for RSZR\n");
423 + device_config->compl_isr.done = 0;
425 + ispresizer_enable(1);
427 + ret = wait_for_completion_interruptible(&device_config->compl_isr);
429 + dev_dbg(rsz_device, "Unexpected exit from "
430 + "wait_for_completion_interruptible\n");
431 + wait_for_completion(&device_config->compl_isr);
434 + if (multipass->active) {
435 + rsz_set_multipass(multipass, rsz_conf_chan);
439 + if (fh->isp_addr_read) {
440 + ispmmu_unmap(fh->isp_addr_read);
441 + fh->isp_addr_read = 0;
443 + if (fh->isp_addr_write) {
444 + ispmmu_unmap(fh->isp_addr_write);
445 + fh->isp_addr_write = 0;
448 + rsz_conf_chan->status = CHANNEL_FREE;
449 + q->bufs[rsz_conf_chan->input_buf_index]->state = VIDEOBUF_NEEDS_INIT;
450 + q->bufs[rsz_conf_chan->output_buf_index]->state = VIDEOBUF_NEEDS_INIT;
451 + rsz_conf_chan->register_config.rsz_sdr_outadd = 0;
452 + rsz_conf_chan->register_config.rsz_sdr_inadd = 0;
454 + /* Unmap and free the DMA memory allocated for buffers */
455 + videobuf_dma_unmap(q, videobuf_to_dma(
456 + q->bufs[rsz_conf_chan->input_buf_index]));
457 + videobuf_dma_unmap(q, videobuf_to_dma(
458 + q->bufs[rsz_conf_chan->output_buf_index]));
459 + videobuf_dma_free(videobuf_to_dma(
460 + q->bufs[rsz_conf_chan->input_buf_index]));
461 + videobuf_dma_free(videobuf_to_dma(
462 + q->bufs[rsz_conf_chan->output_buf_index]));
464 + isp_unset_callback(CBK_RESZ_DONE);
472 + * rsz_set_multipass - Set resizer multipass
473 + * @rsz_conf_chan: Structure containing channel configuration
477 +static int rsz_set_multipass(struct rsz_mult *multipass,
478 + struct channel_config *rsz_conf_chan)
480 + multipass->in_hsize = multipass->out_hsize;
481 + multipass->in_vsize = multipass->out_vsize;
482 + multipass->out_hsize = multipass->end_hsize;
483 + multipass->out_vsize = multipass->end_vsize;
485 + multipass->out_pitch = (multipass->inptyp ? multipass->out_hsize
486 + : (multipass->out_hsize * 2));
487 + multipass->in_pitch = (multipass->inptyp ? multipass->in_hsize
488 + : (multipass->in_hsize * 2));
490 + rsz_set_ratio(multipass, rsz_conf_chan);
491 + rsz_config_ratio(multipass, rsz_conf_chan);
492 + rsz_hardware_setup(rsz_conf_chan);
497 + * rsz_copy_data - Copy data
498 + * @params: Structure containing the Resizer Wrapper parameters
502 +static void rsz_copy_data(struct rsz_mult *multipass, struct rsz_params *params)
505 + multipass->in_hsize = params->in_hsize;
506 + multipass->in_vsize = params->in_vsize;
507 + multipass->out_hsize = params->out_hsize;
508 + multipass->out_vsize = params->out_vsize;
509 + multipass->end_hsize = params->out_hsize;
510 + multipass->end_vsize = params->out_vsize;
511 + multipass->in_pitch = params->in_pitch;
512 + multipass->out_pitch = params->out_pitch;
513 + multipass->hstph = params->hstph;
514 + multipass->vstph = params->vstph;
515 + multipass->inptyp = params->inptyp;
516 + multipass->pix_fmt = params->pix_fmt;
517 + multipass->cbilin = params->cbilin;
519 + for (i = 0; i < 32; i++) {
520 + multipass->tap4filt_coeffs[i] = params->tap4filt_coeffs[i];
521 + multipass->tap7filt_coeffs[i] = params->tap7filt_coeffs[i];
526 + * rsz_set_params - Set parameters for resizer wrapper
527 + * @params: Structure containing the Resizer Wrapper parameters
528 + * @rsz_conf_chan: Structure containing channel configuration
530 + * Used to set the parameters of the Resizer hardware, including input and
531 + * output image size, horizontal and vertical poly-phase filter coefficients,
532 + * luma enchancement filter coefficients, etc.
534 +static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *params,
535 + struct channel_config *rsz_conf_chan)
538 + if ((params->yenh_params.type < 0) || (params->yenh_params.type > 2)) {
539 + dev_err(rsz_device, "rsz_set_params: Wrong yenh type\n");
542 + if ((params->in_vsize <= 0) || (params->in_hsize <= 0) ||
543 + (params->out_vsize <= 0) || (params->out_hsize <= 0) ||
544 + (params->in_pitch <= 0) || (params->out_pitch <= 0)) {
545 + dev_err(rsz_device, "rsz_set_params: Invalid size params\n");
548 + if ((params->inptyp != RSZ_INTYPE_YCBCR422_16BIT) &&
549 + (params->inptyp != RSZ_INTYPE_PLANAR_8BIT)) {
550 + dev_err(rsz_device, "rsz_set_params: Invalid input type\n");
553 + if ((params->pix_fmt != RSZ_PIX_FMT_UYVY) &&
554 + (params->pix_fmt != RSZ_PIX_FMT_YUYV)) {
555 + dev_err(rsz_device, "rsz_set_params: Invalid pixel format\n");
558 + if (params->inptyp == RSZ_INTYPE_YCBCR422_16BIT)
562 + if (params->in_pitch < (params->in_hsize * mul)) {
563 + dev_err(rsz_device, "rsz_set_params: Pitch is incorrect\n");
566 + if (params->out_pitch < (params->out_hsize * mul)) {
567 + dev_err(rsz_device, "rsz_set_params: Out pitch cannot be less"
568 + " than out hsize\n");
571 + /* Output H size should be even */
572 + if ((params->out_hsize % PIXEL_EVEN) != 0) {
573 + dev_err(rsz_device, "rsz_set_params: Output H size should"
577 + if (params->horz_starting_pixel < 0) {
578 + dev_err(rsz_device, "rsz_set_params: Horz start pixel cannot"
579 + " be less than zero\n");
583 + rsz_copy_data(multipass, params);
584 + if (0 != rsz_set_ratio(multipass, rsz_conf_chan))
587 + if (params->yenh_params.type) {
588 + if ((multipass->num_htap && multipass->out_hsize >
590 + (!multipass->num_htap && multipass->out_hsize >
596 + params->vert_starting_pixel = 0;
598 + rsz_conf_chan->register_config.rsz_in_start =
599 + (params->vert_starting_pixel
600 + << ISPRSZ_IN_SIZE_VERT_SHIFT)
601 + & ISPRSZ_IN_SIZE_VERT_MASK;
603 + if (params->inptyp == RSZ_INTYPE_PLANAR_8BIT) {
604 + if (params->horz_starting_pixel > MAX_HORZ_PIXEL_8BIT)
607 + if (params->inptyp == RSZ_INTYPE_YCBCR422_16BIT) {
608 + if (params->horz_starting_pixel > MAX_HORZ_PIXEL_16BIT)
612 + rsz_conf_chan->register_config.rsz_in_start |=
613 + params->horz_starting_pixel
614 + & ISPRSZ_IN_START_HORZ_ST_MASK;
616 + rsz_conf_chan->register_config.rsz_yehn =
617 + (params->yenh_params.type
618 + << ISPRSZ_YENH_ALGO_SHIFT)
619 + & ISPRSZ_YENH_ALGO_MASK;
621 + if (params->yenh_params.type) {
622 + rsz_conf_chan->register_config.rsz_yehn |=
623 + params->yenh_params.core
624 + & ISPRSZ_YENH_CORE_MASK;
626 + rsz_conf_chan->register_config.rsz_yehn |=
627 + (params->yenh_params.gain
628 + << ISPRSZ_YENH_GAIN_SHIFT)
629 + & ISPRSZ_YENH_GAIN_MASK;
631 + rsz_conf_chan->register_config.rsz_yehn |=
632 + (params->yenh_params.slop
633 + << ISPRSZ_YENH_SLOP_SHIFT)
634 + & ISPRSZ_YENH_SLOP_MASK;
637 + rsz_config_ratio(multipass, rsz_conf_chan);
639 + rsz_conf_chan->config_state = STATE_CONFIGURED;
647 + * rsz_set_ratio - Set ratio
648 + * @rsz_conf_chan: Structure containing channel configuration
650 + * Returns 0 if successful, -EINVAL if invalid output size, upscaling ratio is
651 + * being requested, or other ratio configuration value is out of bounds
653 +static int rsz_set_ratio(struct rsz_mult *multipass,
654 + struct channel_config *rsz_conf_chan)
658 + rsz_conf_chan->register_config.rsz_cnt = 0;
660 + if ((multipass->out_hsize > MAX_IMAGE_WIDTH) ||
661 + (multipass->out_vsize > MAX_IMAGE_WIDTH)) {
662 + dev_err(rsz_device, "Invalid output size!");
665 + if (multipass->cbilin) {
666 + rsz_conf_chan->register_config.rsz_cnt =
667 + BITSET(rsz_conf_chan->register_config.rsz_cnt,
671 + rsz_conf_chan->register_config.rsz_cnt =
672 + BITSET(rsz_conf_chan->register_config.rsz_cnt,
675 + if (multipass->inptyp == RSZ_INTYPE_PLANAR_8BIT) {
676 + rsz_conf_chan->register_config.rsz_cnt =
677 + BITSET(rsz_conf_chan->register_config.rsz_cnt,
680 + rsz_conf_chan->register_config.rsz_cnt =
681 + BITRESET(rsz_conf_chan->register_config.
682 + rsz_cnt, SET_BIT_INPTYP);
684 + if (multipass->pix_fmt == RSZ_PIX_FMT_UYVY) {
685 + rsz_conf_chan->register_config.rsz_cnt =
686 + BITRESET(rsz_conf_chan->register_config.
687 + rsz_cnt, SET_BIT_YCPOS);
688 + } else if (multipass->pix_fmt == RSZ_PIX_FMT_YUYV) {
689 + rsz_conf_chan->register_config.rsz_cnt =
690 + BITSET(rsz_conf_chan->register_config.
691 + rsz_cnt, SET_BIT_YCPOS);
696 + (multipass->in_vsize * RATIO_MULTIPLIER) / multipass->out_vsize;
698 + (multipass->in_hsize * RATIO_MULTIPLIER) / multipass->out_hsize;
699 + if (UP_RSZ_RATIO > multipass->vrsz || UP_RSZ_RATIO > multipass->hrsz) {
700 + dev_err(rsz_device, "Upscaling ratio not supported!");
703 + multipass->vrsz = (multipass->in_vsize - NUM_D2TAPS) * RATIO_MULTIPLIER
704 + / (multipass->out_vsize - 1);
705 + multipass->hrsz = ((multipass->in_hsize - NUM_D2TAPS)
706 + * RATIO_MULTIPLIER) /
707 + (multipass->out_hsize - 1);
709 + if (multipass->hrsz <= 512) {
710 + multipass->hrsz = (multipass->in_hsize - NUM_TAPS)
712 + / (multipass->out_hsize - 1);
713 + if (multipass->hrsz < 64)
714 + multipass->hrsz = 64;
715 + if (multipass->hrsz > 512)
716 + multipass->hrsz = 512;
717 + if (multipass->hstph > NUM_PHASES)
719 + multipass->num_htap = 1;
720 + } else if (multipass->hrsz >= 513 && multipass->hrsz <= 1024) {
721 + if (multipass->hstph > NUM_D2PH)
723 + multipass->num_htap = 0;
726 + if (multipass->vrsz <= 512) {
727 + multipass->vrsz = (multipass->in_vsize - NUM_TAPS)
729 + / (multipass->out_vsize - 1);
730 + if (multipass->vrsz < 64)
731 + multipass->vrsz = 64;
732 + if (multipass->vrsz > 512)
733 + multipass->vrsz = 512;
734 + if (multipass->vstph > NUM_PHASES)
736 + multipass->num_vtap = 1;
737 + } else if (multipass->vrsz >= 513 && multipass->vrsz <= 1024) {
738 + if (multipass->vstph > NUM_D2PH)
740 + multipass->num_vtap = 0;
743 + if ((multipass->in_pitch) % ALIGN32) {
744 + dev_err(rsz_device, "Invalid input pitch: %d \n",
745 + multipass->in_pitch);
748 + if ((multipass->out_pitch) % ALIGN32) {
749 + dev_err(rsz_device, "Invalid output pitch %d \n",
750 + multipass->out_pitch);
754 + if (multipass->vrsz < 256 &&
755 + (multipass->in_vsize < multipass->out_vsize)) {
756 + if (multipass->inptyp == RSZ_INTYPE_PLANAR_8BIT)
757 + alignment = ALIGNMENT;
758 + else if (multipass->inptyp == RSZ_INTYPE_YCBCR422_16BIT)
759 + alignment = (ALIGNMENT / 2);
761 + dev_err(rsz_device, "Invalid input type\n");
763 + if (!(((multipass->out_hsize % PIXEL_EVEN) == 0)
764 + && (multipass->out_hsize % alignment) == 0)) {
765 + dev_err(rsz_device, "wrong hsize\n");
769 + if (multipass->hrsz >= 64 && multipass->hrsz <= 1024) {
770 + if (multipass->out_hsize > MAX_IMAGE_WIDTH) {
771 + dev_err(rsz_device, "wrong width\n");
774 + multipass->active = 0;
776 + } else if (multipass->hrsz > 1024) {
777 + if (multipass->out_hsize > MAX_IMAGE_WIDTH) {
778 + dev_err(rsz_device, "wrong width\n");
781 + if (multipass->hstph > NUM_D2PH)
783 + multipass->num_htap = 0;
784 + multipass->out_hsize = multipass->in_hsize * 256 / 1024;
785 + if (multipass->out_hsize % ALIGN32) {
786 + multipass->out_hsize +=
787 + abs((multipass->out_hsize % ALIGN32) - ALIGN32);
789 + multipass->out_pitch = ((multipass->inptyp) ?
790 + multipass->out_hsize :
791 + (multipass->out_hsize * 2));
792 + multipass->hrsz = ((multipass->in_hsize - NUM_D2TAPS)
793 + * RATIO_MULTIPLIER)
794 + / (multipass->out_hsize - 1);
795 + multipass->active = 1;
799 + if (multipass->vrsz > 1024) {
800 + if (multipass->out_vsize > MAX_IMAGE_WIDTH_HIGH) {
801 + dev_err(rsz_device, "wrong width\n");
805 + multipass->out_vsize = multipass->in_vsize * 256 / 1024;
806 + multipass->vrsz = ((multipass->in_vsize - NUM_D2TAPS)
807 + * RATIO_MULTIPLIER)
808 + / (multipass->out_vsize - 1);
809 + multipass->active = 1;
810 + multipass->num_vtap = 0;
813 + rsz_conf_chan->register_config.rsz_out_size =
814 + multipass->out_hsize
815 + & ISPRSZ_OUT_SIZE_HORZ_MASK;
817 + rsz_conf_chan->register_config.rsz_out_size |=
818 + (multipass->out_vsize
819 + << ISPRSZ_OUT_SIZE_VERT_SHIFT)
820 + & ISPRSZ_OUT_SIZE_VERT_MASK;
822 + rsz_conf_chan->register_config.rsz_sdr_inoff =
823 + multipass->in_pitch
824 + & ISPRSZ_SDR_INOFF_OFFSET_MASK;
826 + rsz_conf_chan->register_config.rsz_sdr_outoff =
827 + multipass->out_pitch
828 + & ISPRSZ_SDR_OUTOFF_OFFSET_MASK;
830 + if (multipass->hrsz >= 64 && multipass->hrsz <= 512) {
831 + if (multipass->hstph > NUM_PHASES)
833 + } else if (multipass->hrsz >= 64 && multipass->hrsz <= 512) {
834 + if (multipass->hstph > NUM_D2PH)
838 + rsz_conf_chan->register_config.rsz_cnt |=
840 + << ISPRSZ_CNT_HSTPH_SHIFT)
841 + & ISPRSZ_CNT_HSTPH_MASK;
843 + if (multipass->vrsz >= 64 && multipass->hrsz <= 512) {
844 + if (multipass->vstph > NUM_PHASES)
846 + } else if (multipass->vrsz >= 64 && multipass->vrsz <= 512) {
847 + if (multipass->vstph > NUM_D2PH)
851 + rsz_conf_chan->register_config.rsz_cnt |=
853 + << ISPRSZ_CNT_VSTPH_SHIFT)
854 + & ISPRSZ_CNT_VSTPH_MASK;
856 + rsz_conf_chan->register_config.rsz_cnt |=
857 + (multipass->hrsz - 1)
858 + & ISPRSZ_CNT_HRSZ_MASK;
860 + rsz_conf_chan->register_config.rsz_cnt |=
861 + ((multipass->vrsz - 1)
862 + << ISPRSZ_CNT_VRSZ_SHIFT)
863 + & ISPRSZ_CNT_VRSZ_MASK;
871 + * rsz_config_ratio - Configure ratio
872 + * @rsz_conf_chan: Structure containing channel configuration
876 +static void rsz_config_ratio(struct rsz_mult *multipass,
877 + struct channel_config *rsz_conf_chan)
883 + if (multipass->hrsz <= 512) {
884 + hsize = ((32 * multipass->hstph + (multipass->out_hsize - 1)
885 + * multipass->hrsz + 16) >> 8) + 7;
887 + hsize = ((64 * multipass->hstph + (multipass->out_hsize - 1)
888 + * multipass->hrsz + 32) >> 8) + 7;
890 + if (multipass->vrsz <= 512) {
891 + vsize = ((32 * multipass->vstph + (multipass->out_vsize - 1)
892 + * multipass->vrsz + 16) >> 8) + 4;
894 + vsize = ((64 * multipass->vstph + (multipass->out_vsize - 1)
895 + * multipass->vrsz + 32) >> 8) + 7;
897 + rsz_conf_chan->register_config.rsz_in_size = hsize;
899 + rsz_conf_chan->register_config.rsz_in_size |=
900 + ((vsize << ISPRSZ_IN_SIZE_VERT_SHIFT)
901 + & ISPRSZ_IN_SIZE_VERT_MASK);
903 + for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
905 + if (multipass->num_htap) {
906 + rsz_conf_chan->register_config.
907 + rsz_coeff_horz[coeffcounter] =
908 + (multipass->tap4filt_coeffs[2
910 + & ISPRSZ_HFILT10_COEF0_MASK);
911 + rsz_conf_chan->register_config.
912 + rsz_coeff_horz[coeffcounter] |=
913 + ((multipass->tap4filt_coeffs[2
914 + * coeffcounter + 1]
915 + << ISPRSZ_HFILT10_COEF1_SHIFT)
916 + & ISPRSZ_HFILT10_COEF1_MASK);
918 + rsz_conf_chan->register_config.
919 + rsz_coeff_horz[coeffcounter] =
920 + (multipass->tap7filt_coeffs[2
922 + & ISPRSZ_HFILT10_COEF0_MASK);
924 + rsz_conf_chan->register_config.
925 + rsz_coeff_horz[coeffcounter] |=
926 + ((multipass->tap7filt_coeffs[2
927 + * coeffcounter + 1]
928 + << ISPRSZ_HFILT10_COEF1_SHIFT)
929 + & ISPRSZ_HFILT10_COEF1_MASK);
932 + if (multipass->num_vtap) {
933 + rsz_conf_chan->register_config.
934 + rsz_coeff_vert[coeffcounter] =
935 + (multipass->tap4filt_coeffs[2
937 + & ISPRSZ_VFILT10_COEF0_MASK);
939 + rsz_conf_chan->register_config.
940 + rsz_coeff_vert[coeffcounter] |=
941 + ((multipass->tap4filt_coeffs[2
942 + * coeffcounter + 1]
943 + << ISPRSZ_VFILT10_COEF1_SHIFT) &
944 + ISPRSZ_VFILT10_COEF1_MASK);
946 + rsz_conf_chan->register_config.
947 + rsz_coeff_vert[coeffcounter] =
948 + (multipass->tap7filt_coeffs[2
950 + & ISPRSZ_VFILT10_COEF0_MASK);
951 + rsz_conf_chan->register_config.
952 + rsz_coeff_vert[coeffcounter] |=
953 + ((multipass->tap7filt_coeffs[2
954 + * coeffcounter + 1]
955 + << ISPRSZ_VFILT10_COEF1_SHIFT)
956 + & ISPRSZ_VFILT10_COEF1_MASK);
962 + * rsz_get_params - Gets the parameter values
963 + * @params: Structure containing the Resizer Wrapper parameters
964 + * @rsz_conf_chan: Structure containing channel configuration
966 + * Used to get the Resizer hardware settings associated with the
967 + * current logical channel represented by fd.
969 +static int rsz_get_params(struct rsz_params *params,
970 + struct channel_config *rsz_conf_chan)
974 + if (rsz_conf_chan->config_state) {
975 + dev_err(rsz_device, "state not configured\n");
979 + params->in_hsize = rsz_conf_chan->register_config.rsz_in_size
980 + & ISPRSZ_IN_SIZE_HORZ_MASK;
981 + params->in_vsize = (rsz_conf_chan->register_config.rsz_in_size
982 + & ISPRSZ_IN_SIZE_VERT_MASK)
983 + >> ISPRSZ_IN_SIZE_VERT_SHIFT;
985 + params->in_pitch = rsz_conf_chan->register_config.rsz_sdr_inoff
986 + & ISPRSZ_SDR_INOFF_OFFSET_MASK;
988 + params->out_hsize = rsz_conf_chan->register_config.rsz_out_size
989 + & ISPRSZ_OUT_SIZE_HORZ_MASK;
991 + params->out_vsize = (rsz_conf_chan->register_config.rsz_out_size
992 + & ISPRSZ_OUT_SIZE_VERT_MASK)
993 + >> ISPRSZ_OUT_SIZE_VERT_SHIFT;
995 + params->out_pitch = rsz_conf_chan->register_config.rsz_sdr_outoff
996 + & ISPRSZ_SDR_OUTOFF_OFFSET_MASK;
998 + params->cbilin = (rsz_conf_chan->register_config.rsz_cnt
999 + & SET_BIT_CBLIN) >> SET_BIT_CBLIN;
1001 + params->inptyp = (rsz_conf_chan->register_config.rsz_cnt
1002 + & ISPRSZ_CNT_INPTYP_MASK)
1003 + >> SET_BIT_INPTYP;
1004 + params->horz_starting_pixel = ((rsz_conf_chan->register_config.
1006 + & ISPRSZ_IN_START_HORZ_ST_MASK));
1007 + params->vert_starting_pixel = ((rsz_conf_chan->register_config.
1009 + & ISPRSZ_IN_START_VERT_ST_MASK)
1010 + >> ISPRSZ_IN_START_VERT_ST_SHIFT);
1012 + params->hstph = ((rsz_conf_chan->register_config.rsz_cnt
1013 + & ISPRSZ_CNT_HSTPH_MASK
1014 + >> ISPRSZ_CNT_HSTPH_SHIFT));
1015 + params->vstph = ((rsz_conf_chan->register_config.rsz_cnt
1016 + & ISPRSZ_CNT_VSTPH_MASK
1017 + >> ISPRSZ_CNT_VSTPH_SHIFT));
1019 + for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
1021 + params->tap4filt_coeffs[2 * coeffcounter] =
1022 + rsz_conf_chan->register_config.
1023 + rsz_coeff_horz[coeffcounter]
1024 + & ISPRSZ_HFILT10_COEF0_MASK;
1026 + params->tap4filt_coeffs[2 * coeffcounter + 1] =
1027 + (rsz_conf_chan->register_config.
1028 + rsz_coeff_horz[coeffcounter]
1029 + & ISPRSZ_HFILT10_COEF1_MASK)
1030 + >> ISPRSZ_HFILT10_COEF1_SHIFT;
1032 + params->tap7filt_coeffs[2 * coeffcounter] =
1033 + rsz_conf_chan->register_config.
1034 + rsz_coeff_vert[coeffcounter]
1035 + & ISPRSZ_VFILT10_COEF0_MASK;
1037 + params->tap7filt_coeffs[2 * coeffcounter + 1] =
1038 + (rsz_conf_chan->register_config.
1039 + rsz_coeff_vert[coeffcounter]
1040 + & ISPRSZ_VFILT10_COEF1_MASK)
1041 + >> ISPRSZ_VFILT10_COEF1_SHIFT;
1045 + params->yenh_params.type = (rsz_conf_chan->register_config.rsz_yehn
1046 + & ISPRSZ_YENH_ALGO_MASK)
1047 + >> ISPRSZ_YENH_ALGO_SHIFT;
1049 + params->yenh_params.core = rsz_conf_chan->register_config.rsz_yehn
1050 + & ISPRSZ_YENH_CORE_MASK;
1052 + params->yenh_params.gain = (rsz_conf_chan->register_config.rsz_yehn
1053 + & ISPRSZ_YENH_GAIN_MASK)
1054 + >> ISPRSZ_YENH_GAIN_SHIFT;
1056 + params->yenh_params.slop = (rsz_conf_chan->register_config.rsz_yehn
1057 + & ISPRSZ_YENH_SLOP_MASK)
1058 + >> ISPRSZ_YENH_SLOP_SHIFT;
1060 + params->pix_fmt = ((rsz_conf_chan->register_config.rsz_cnt
1061 + & ISPRSZ_CNT_PIXFMT_MASK)
1062 + >> SET_BIT_YCPOS);
1064 + if (params->pix_fmt)
1065 + params->pix_fmt = RSZ_PIX_FMT_UYVY;
1067 + params->pix_fmt = RSZ_PIX_FMT_YUYV;
1073 + * rsz_calculate_crop - Calculate Crop values
1074 + * @rsz_conf_chan: Structure containing channel configuration
1075 + * @cropsize: Structure containing crop parameters
1077 + * Calculate Crop values
1079 +static void rsz_calculate_crop(struct channel_config *rsz_conf_chan,
1080 + struct rsz_cropsize *cropsize)
1084 + cropsize->hcrop = 0;
1085 + cropsize->vcrop = 0;
1087 + luma_enable = (rsz_conf_chan->register_config.rsz_yehn
1088 + & ISPRSZ_YENH_ALGO_MASK)
1089 + >> ISPRSZ_YENH_ALGO_SHIFT;
1092 + cropsize->hcrop += 2;
1096 + * rsz_vbq_release - Videobuffer queue release
1097 + * @q: Structure containing the videobuffer queue file handle, and device
1098 + * structure which contains the actual configuration.
1099 + * @vb: Structure containing the videobuffer used for resizer processing.
1101 +static void rsz_vbq_release(struct videobuf_queue *q,
1102 + struct videobuf_buffer *vb)
1105 + struct rsz_fh *fh = q->priv_data;
1107 + for (i = 0; i < VIDEO_MAX_FRAME; i++) {
1108 + struct videobuf_dmabuf *dma = NULL;
1111 + if (q->bufs[i]->memory != V4L2_MEMORY_MMAP)
1113 + dma = videobuf_to_dma(q->bufs[i]);
1114 + videobuf_dma_unmap(q, dma);
1115 + videobuf_dma_free(dma);
1118 + ispmmu_unmap(fh->isp_addr_read);
1119 + ispmmu_unmap(fh->isp_addr_write);
1120 + fh->isp_addr_read = 0;
1121 + fh->isp_addr_write = 0;
1122 + spin_lock(&fh->vbq_lock);
1123 + vb->state = VIDEOBUF_NEEDS_INIT;
1124 + spin_unlock(&fh->vbq_lock);
1129 + * rsz_vbq_setup - Sets up the videobuffer size and validates count.
1130 + * @q: Structure containing the videobuffer queue file handle, and device
1131 + * structure which contains the actual configuration.
1132 + * @cnt: Number of buffers requested
1133 + * @size: Size in bytes of the buffer used for previewing
1135 + * Always returns 0.
1137 +static int rsz_vbq_setup(struct videobuf_queue *q, unsigned int *cnt,
1138 + unsigned int *size)
1140 + struct rsz_fh *fh = q->priv_data;
1141 + struct rsz_mult *multipass = fh->multipass;
1142 + u32 insize, outsize;
1144 + spin_lock(&fh->vbq_lock);
1146 + *cnt = VIDEO_MAX_FRAME;
1148 + if (*cnt > VIDEO_MAX_FRAME)
1149 + *cnt = VIDEO_MAX_FRAME;
1151 + outsize = multipass->out_pitch * multipass->out_vsize;
1152 + insize = multipass->in_pitch * multipass->in_vsize;
1153 + if (*cnt == 1 && (outsize > insize)) {
1154 + dev_err(rsz_device, "2 buffers are required for Upscaling "
1158 + if (!fh->params->in_hsize || !fh->params->in_vsize) {
1159 + dev_err(rsz_device, "Can't setup buffer size\n");
1162 + if (outsize > insize)
1167 + fh->rsz_bufsize = *size;
1169 + spin_unlock(&fh->vbq_lock);
1173 + spin_unlock(&fh->vbq_lock);
1178 + * rsz_vbq_prepare - Videobuffer is prepared and mmapped.
1179 + * @q: Structure containing the videobuffer queue file handle, and device
1180 + * structure which contains the actual configuration.
1181 + * @vb: Structure containing the videobuffer used for resizer processing.
1182 + * @field: Type of field to set in videobuffer device.
1184 + * Returns 0 if successful, or -EINVAL if buffer couldn't get allocated, or
1185 + * -EIO if the ISP MMU mapping fails
1187 +static int rsz_vbq_prepare(struct videobuf_queue *q,
1188 + struct videobuf_buffer *vb,
1189 + enum v4l2_field field)
1191 + struct rsz_fh *fh = q->priv_data;
1192 + struct channel_config *rsz_conf_chan = fh->config;
1193 + struct rsz_mult *multipass = fh->multipass;
1195 + unsigned int isp_addr, insize, outsize;
1196 + struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
1198 + spin_lock(&fh->vbq_lock);
1200 + vb->size = fh->rsz_bufsize;
1201 + vb->bsize = fh->rsz_bufsize;
1203 + spin_unlock(&fh->vbq_lock);
1204 + dev_err(rsz_device, "No user buffer allocated\n");
1208 + vb->width = fh->params->out_hsize;
1209 + vb->height = fh->params->out_vsize;
1211 + vb->width = fh->params->in_hsize;
1212 + vb->height = fh->params->in_vsize;
1215 + vb->field = field;
1216 + spin_unlock(&fh->vbq_lock);
1218 + if (vb->state == VIDEOBUF_NEEDS_INIT) {
1219 + err = videobuf_iolock(q, vb, NULL);
1221 + isp_addr = ispmmu_map_sg(dma->sglist, dma->sglen);
1226 + rsz_conf_chan->register_config.
1229 + fh->isp_addr_write = isp_addr;
1230 + rsz_conf_chan->output_buf_index = vb->i;
1232 + rsz_conf_chan->register_config.
1235 + rsz_conf_chan->input_buf_index = vb->i;
1236 + outsize = multipass->out_pitch *
1237 + multipass->out_vsize;
1238 + insize = multipass->in_pitch *
1239 + multipass->in_vsize;
1240 + if (outsize < insize) {
1241 + rsz_conf_chan->register_config.
1245 + output_buf_index =
1249 + fh->isp_addr_read = isp_addr;
1257 + spin_lock(&fh->vbq_lock);
1258 + vb->state = VIDEOBUF_PREPARED;
1259 + spin_unlock(&fh->vbq_lock);
1260 + flush_cache_user_range(NULL, vb->baddr, (vb->baddr
1263 + rsz_vbq_release(q, vb);
1269 +static void rsz_vbq_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1275 + * rsz_open - Initializes and opens the Resizer Wrapper
1276 + * @inode: Inode structure associated with the Resizer Wrapper
1277 + * @filp: File structure associated with the Resizer Wrapper
1279 + * Returns 0 if successful, -EBUSY if its already opened or the ISP module is
1280 + * not available, or -ENOMEM if its unable to allocate the device in kernel
1283 +static int rsz_open(struct inode *inode, struct file *filp)
1286 + struct channel_config *rsz_conf_chan;
1287 + struct rsz_fh *fh;
1288 + struct device_params *device = device_config;
1289 + struct rsz_params *params;
1290 + struct rsz_mult *multipass;
1292 + if ((filp->f_flags & O_NONBLOCK) == O_NONBLOCK) {
1293 + printk(KERN_DEBUG "omap-resizer: Device is opened in "
1294 + "non blocking mode\n");
1296 + printk(KERN_DEBUG "omap-resizer: Device is opened in blocking "
1299 + fh = kzalloc(sizeof(struct rsz_fh), GFP_KERNEL);
1305 + rsz_conf_chan = kzalloc(sizeof(struct channel_config), GFP_KERNEL);
1306 + if (rsz_conf_chan == NULL) {
1307 + dev_err(rsz_device, "\n cannot allocate memory to config");
1311 + params = kzalloc(sizeof(struct rsz_params), GFP_KERNEL);
1312 + if (params == NULL) {
1313 + dev_err(rsz_device, "\n cannot allocate memory to params");
1317 + multipass = kzalloc(sizeof(struct rsz_mult), GFP_KERNEL);
1318 + if (multipass == NULL) {
1319 + dev_err(rsz_device, "\n cannot allocate memory to multipass");
1324 + fh->multipass = multipass;
1325 + fh->params = params;
1326 + fh->config = rsz_conf_chan;
1328 + if (mutex_lock_interruptible(&device->reszwrap_mutex)) {
1333 + mutex_unlock(&device->reszwrap_mutex);
1335 + rsz_conf_chan->config_state = STATE_NOT_CONFIGURED;
1336 + rsz_conf_chan->status = CHANNEL_FREE;
1338 + filp->private_data = fh;
1339 + fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1340 + fh->device = device;
1342 + videobuf_queue_sg_init(&fh->vbq, &device->vbq_ops, NULL,
1343 + &fh->vbq_lock, fh->type,
1345 + sizeof(struct videobuf_buffer), fh);
1347 + spin_lock_init(&fh->vbq_lock);
1348 + mutex_init(&rsz_conf_chan->chanprotection_mutex);
1354 + kfree(rsz_conf_chan);
1361 + * rsz_release - Releases Resizer Wrapper and frees up allocated memory
1362 + * @inode: Inode structure associated with the Resizer Wrapper
1363 + * @filp: File structure associated with the Resizer Wrapper
1365 + * Returns 0 if successful, or -EBUSY if channel is being used.
1367 +static int rsz_release(struct inode *inode, struct file *filp)
1370 + struct rsz_fh *fh = filp->private_data;
1371 + struct channel_config *rsz_conf_chan = fh->config;
1372 + struct rsz_params *params = fh->params;
1373 + struct rsz_mult *multipass = fh->multipass;
1374 + struct videobuf_queue *q = &fh->vbq;
1376 + while ((rsz_conf_chan->status != CHANNEL_FREE) && (timeout < 20)) {
1380 + if (mutex_lock_interruptible(&device_config->reszwrap_mutex))
1382 + device_config->opened--;
1383 + mutex_unlock(&device_config->reszwrap_mutex);
1384 + /* This will Free memory allocated to the buffers,
1385 + * and flushes the queue
1387 + videobuf_queue_cancel(q);
1388 + fh->params = NULL;
1389 + fh->config = NULL;
1391 + fh->rsz_bufsize = 0;
1392 + filp->private_data = NULL;
1394 + kfree(rsz_conf_chan);
1405 + * rsz_mmap - Memory maps the Resizer Wrapper module.
1406 + * @file: File structure associated with the Resizer Wrapper
1407 + * @vma: Virtual memory area structure.
1409 + * Returns 0 if successful, or returned value by the videobuf_mmap_mapper()
1412 +static int rsz_mmap(struct file *file, struct vm_area_struct *vma)
1414 + struct rsz_fh *fh = file->private_data;
1416 + return videobuf_mmap_mapper(&fh->vbq, vma);
1420 + * rsz_ioctl - I/O control function for Resizer Wrapper
1421 + * @inode: Inode structure associated with the Resizer Wrapper.
1422 + * @file: File structure associated with the Resizer Wrapper.
1423 + * @cmd: Type of command to execute.
1424 + * @arg: Argument to send to requested command.
1426 + * Returns 0 if successful, -EBUSY if channel is being used, -1 if bad command
1427 + * passed or access is denied, -EFAULT if copy_from_user() or copy_to_user()
1428 + * fails, -EINVAL if parameter validation fails or parameter structure is not
1431 +static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
1432 + unsigned long arg)
1435 + struct rsz_fh *fh = file->private_data;
1436 + struct device_params *device = fh->device;
1437 + struct channel_config *rsz_conf_chan = fh->config;
1439 + if ((_IOC_TYPE(cmd) != RSZ_IOC_BASE)
1440 + || (_IOC_NR(cmd) > RSZ_IOC_MAXNR)) {
1441 + dev_err(rsz_device, "Bad command value \n");
1445 + if (_IOC_DIR(cmd) & _IOC_READ)
1446 + ret = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
1447 + else if (_IOC_DIR(cmd) & _IOC_WRITE)
1448 + ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
1451 + dev_err(rsz_device, "Access denied\n");
1458 + struct v4l2_requestbuffers req_buf;
1459 + if (copy_from_user(&req_buf, (struct v4l2_requestbuffers *)arg,
1460 + sizeof(struct v4l2_requestbuffers))) {
1463 + if (mutex_lock_interruptible(&rsz_conf_chan->
1464 + chanprotection_mutex))
1466 + ret = videobuf_reqbufs(&fh->vbq, (void *)&req_buf);
1467 + mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
1470 + case RSZ_QUERYBUF:
1472 + struct v4l2_buffer buf;
1473 + if (copy_from_user(&buf, (struct v4l2_buffer *)arg,
1474 + sizeof(struct v4l2_buffer))) {
1477 + if (mutex_lock_interruptible(&rsz_conf_chan->
1478 + chanprotection_mutex))
1480 + ret = videobuf_querybuf(&fh->vbq, (void *)&buf);
1481 + mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
1482 + if (copy_to_user((struct v4l2_buffer *)arg, &buf,
1483 + sizeof(struct v4l2_buffer)))
1487 + case RSZ_QUEUEBUF:
1489 + struct v4l2_buffer buf;
1490 + if (copy_from_user(&buf, (struct v4l2_buffer *)arg,
1491 + sizeof(struct v4l2_buffer))) {
1494 + if (mutex_lock_interruptible(&rsz_conf_chan->
1495 + chanprotection_mutex))
1497 + ret = videobuf_qbuf(&fh->vbq, (void *)&buf);
1498 + mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
1503 + struct rsz_params *params = fh->params;
1504 + if (copy_from_user(params, (struct rsz_params *)arg,
1505 + sizeof(struct rsz_params))) {
1508 + if (mutex_lock_interruptible(&rsz_conf_chan->
1509 + chanprotection_mutex))
1511 + ret = rsz_set_params(fh->multipass, params, rsz_conf_chan);
1512 + mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
1516 + ret = rsz_get_params((struct rsz_params *)arg, rsz_conf_chan);
1519 + case RSZ_G_STATUS:
1521 + struct rsz_status *status;
1522 + status = (struct rsz_status *)arg;
1523 + status->chan_busy = rsz_conf_chan->status;
1524 + status->hw_busy = ispresizer_busy();
1525 + status->src = INPUT_RAM;
1529 + if (file->f_flags & O_NONBLOCK) {
1530 + if (ispresizer_busy())
1533 + if (!mutex_trylock(&device->reszwrap_mutex))
1537 + if (mutex_lock_interruptible(&device->reszwrap_mutex))
1540 + ret = rsz_start((int *)arg, fh);
1541 + mutex_unlock(&device->reszwrap_mutex);
1543 + case RSZ_GET_CROPSIZE:
1544 + rsz_calculate_crop(rsz_conf_chan, (struct rsz_cropsize *)arg);
1548 + dev_err(rsz_device, "resizer_ioctl: Invalid Command Value");
1555 +static struct file_operations rsz_fops = {
1556 + .owner = THIS_MODULE,
1558 + .release = rsz_release,
1560 + .unlocked_ioctl = rsz_unlocked_ioctl,
1564 + * rsz_isr - Interrupt Service Routine for Resizer wrapper
1565 + * @status: ISP IRQ0STATUS register value
1566 + * @arg1: Currently not used
1567 + * @arg2: Currently not used
1569 + * Interrupt Service Routine for Resizer wrapper
1571 +static void rsz_isr(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2)
1574 + if ((status & RESZ_DONE) != RESZ_DONE)
1577 + complete(&(device_config->compl_isr));
1582 + * resizer_platform_release - Acts when Reference count is zero
1583 + * @device: Structure containing ISP resizer wrapper global information
1585 + * This is called when the reference count goes to zero.
1587 +static void resizer_platform_release(struct device *device)
1592 + * resizer_probe - Checks for device presence
1593 + * @device: Structure containing details of the current device.
1595 + * Always returns 0.
1597 +static int __init resizer_probe(struct platform_device *device)
1603 + * resizer_remove - Handles the removal of the driver
1604 + * @omap_resizer_device: Structure containing details of the current device.
1606 + * Always returns 0.
1608 +static int resizer_remove(struct platform_device *omap_resizer_device)
1613 +static struct class *rsz_class;
1614 +static struct cdev c_dev;
1616 +static struct platform_device omap_resizer_device = {
1617 + .name = OMAP_REZR_NAME,
1620 + .release = resizer_platform_release,}
1623 +static struct platform_driver omap_resizer_driver = {
1624 + .probe = resizer_probe,
1625 + .remove = resizer_remove,
1627 + .bus = &platform_bus_type,
1628 + .name = OMAP_REZR_NAME,
1633 + * omap_rsz_init - Initialization of Resizer Wrapper
1635 + * Returns 0 if successful, -ENOMEM if could not allocate memory, -ENODEV if
1636 + * could not register the wrapper as a character device, or other errors if the
1637 + * device or driver can't register.
1639 +static int __init omap_rsz_init(void)
1642 + struct device_params *device;
1643 + device = kzalloc(sizeof(struct device_params), GFP_KERNEL);
1645 + dev_err(rsz_device, OMAP_REZR_NAME ": could not allocate "
1650 + ret = alloc_chrdev_region(&dev, 0, 1, OMAP_REZR_NAME);
1652 + dev_err(rsz_device, OMAP_REZR_NAME ": intialization failed. "
1653 + "Could not allocate region "
1654 + "for character device\n");
1659 + /* Register the driver in the kernel */
1660 + /* Initialize of character device */
1661 + cdev_init(&c_dev, &rsz_fops);
1662 + c_dev.owner = THIS_MODULE;
1663 + c_dev.ops = &rsz_fops;
1665 + /* Addding character device */
1666 + ret = cdev_add(&c_dev, dev, 1);
1668 + dev_err(rsz_device, OMAP_REZR_NAME ": Error adding "
1669 + "device - %d\n", ret);
1672 + rsz_major = MAJOR(dev);
1674 + /* register driver as a platform driver */
1675 + ret = platform_driver_register(&omap_resizer_driver);
1677 + dev_err(rsz_device, OMAP_REZR_NAME
1678 + ": Failed to register platform driver!\n");
1682 + /* Register the drive as a platform device */
1683 + ret = platform_device_register(&omap_resizer_device);
1685 + dev_err(rsz_device, OMAP_REZR_NAME
1686 + ": Failed to register platform device!\n");
1690 + rsz_class = class_create(THIS_MODULE, OMAP_REZR_NAME);
1692 + dev_err(rsz_device, OMAP_REZR_NAME
1693 + ": Failed to create class!\n");
1697 + /* make entry in the devfs */
1698 + rsz_device = device_create(rsz_class, rsz_device,
1699 + MKDEV(rsz_major, 0), NULL,
1701 + dev_dbg(rsz_device, OMAP_REZR_NAME ": Registered Resizer Wrapper\n");
1702 + device->opened = 0;
1704 + device->vbq_ops.buf_setup = rsz_vbq_setup;
1705 + device->vbq_ops.buf_prepare = rsz_vbq_prepare;
1706 + device->vbq_ops.buf_release = rsz_vbq_release;
1707 + device->vbq_ops.buf_queue = rsz_vbq_queue;
1708 + init_completion(&device->compl_isr);
1709 + mutex_init(&device->reszwrap_mutex);
1711 + device_config = device;
1715 + platform_device_unregister(&omap_resizer_device);
1717 + platform_driver_unregister(&omap_resizer_driver);
1721 + unregister_chrdev_region(dev, 1);
1727 + * omap_rsz_exit - Close of Resizer Wrapper
1729 +void __exit omap_rsz_exit(void)
1731 + device_destroy(rsz_class, dev);
1732 + class_destroy(rsz_class);
1733 + platform_device_unregister(&omap_resizer_device);
1734 + platform_driver_unregister(&omap_resizer_driver);
1736 + unregister_chrdev_region(dev, 1);
1737 + kfree(device_config);
1740 +module_init(omap_rsz_init)
1741 +module_exit(omap_rsz_exit)
1743 +MODULE_AUTHOR("Texas Instruments");
1744 +MODULE_DESCRIPTION("OMAP ISP Resizer");
1745 +MODULE_LICENSE("GPL");
1746 diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h
1747 new file mode 100644
1748 index 0000000..5ac0c88
1750 +++ b/include/linux/omap_resizer.h
1753 + * drivers/media/video/isp/omap_resizer.h
1755 + * Include file for Resizer module wrapper in TI's OMAP3430 ISP
1757 + * Copyright (C) 2008 Texas Instruments, Inc.
1759 + * This package is free software; you can redistribute it and/or modify
1760 + * it under the terms of the GNU General Public License version 2 as
1761 + * published by the Free Software Foundation.
1763 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1764 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1765 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1768 +#ifndef OMAP_RESIZER_H
1769 +#define OMAP_RESIZER_H
1771 +#include <linux/types.h>
1773 +/* ioctls definition */
1774 +#define RSZ_IOC_BASE 'R'
1775 +#define RSZ_IOC_MAXNR 8
1777 +/*Ioctl options which are to be passed while calling the ioctl*/
1778 +#define RSZ_REQBUF _IOWR(RSZ_IOC_BASE, 1,\
1779 + struct v4l2_requestbuffers)
1780 +#define RSZ_QUERYBUF _IOWR(RSZ_IOC_BASE, 2, struct v4l2_buffer)
1781 +#define RSZ_S_PARAM _IOWR(RSZ_IOC_BASE, 3, struct rsz_params)
1782 +#define RSZ_G_PARAM _IOWR(RSZ_IOC_BASE, 4, struct rsz_params)
1783 +#define RSZ_RESIZE _IOWR(RSZ_IOC_BASE, 5, __s32)
1784 +#define RSZ_G_STATUS _IOWR(RSZ_IOC_BASE, 6, struct rsz_status)
1785 +#define RSZ_QUEUEBUF _IOWR(RSZ_IOC_BASE, 7, struct v4l2_buffer)
1786 +#define RSZ_GET_CROPSIZE _IOWR(RSZ_IOC_BASE, 8, struct rsz_cropsize)
1788 +#define RSZ_INTYPE_YCBCR422_16BIT 0
1789 +#define RSZ_INTYPE_PLANAR_8BIT 1
1790 +#define RSZ_PIX_FMT_UYVY 1 /* cb:y:cr:y */
1791 +#define RSZ_PIX_FMT_YUYV 0 /* y:cb:y:cr */
1794 + STATE_CONFIGURED, /* Resizer driver configured
1797 + STATE_NOT_CONFIGURED /* Resizer driver not
1798 + * configured by application.
1802 +/* Structure Definitions */
1804 +/* used to luma enhancement options */
1807 + __s32 type; /* represents luma enable or
1810 + __u8 gain; /* represents gain. */
1811 + __u8 slop; /* represents slop. */
1812 + __u8 core; /* Represents core value. */
1815 +/* Conatins all the parameters for resizing. This structure
1816 + * is used to configure resiser parameters
1818 +struct rsz_params {
1819 + __s32 in_hsize; /* input frame horizontal
1822 + __s32 in_vsize; /* input frame vertical size */
1823 + __s32 in_pitch; /* offset between two rows of
1826 + __s32 inptyp; /* for determining 16 bit or
1829 + __s32 vert_starting_pixel; /* for specifying vertical
1830 + * starting pixel in input.
1832 + __s32 horz_starting_pixel; /* for specyfing horizontal
1833 + * starting pixel in input.
1835 + __s32 cbilin; /* # defined, filter with luma
1836 + * or bi-linear interpolation.
1838 + __s32 pix_fmt; /* # defined, UYVY or YUYV */
1839 + __s32 out_hsize; /* output frame horizontal
1842 + __s32 out_vsize; /* output frame vertical
1845 + __s32 out_pitch; /* offset between two rows of
1848 + __s32 hstph; /* for specifying horizontal
1851 + __s32 vstph; /* for specifying vertical
1854 + __u16 tap4filt_coeffs[32]; /* horizontal filter
1857 + __u16 tap7filt_coeffs[32]; /* vertical filter
1860 + struct rsz_yenh yenh_params;
1863 +/* Contains the status of hardware and channel */
1864 +struct rsz_status {
1865 + __s32 chan_busy; /* 1: channel is busy,
1866 + * 0: channel is not busy
1868 + __s32 hw_busy; /* 1: hardware is busy,
1869 + * 0: hardware is not busy
1871 + __s32 src; /* # defined, can be either
1872 + * SD-RAM or CCDC/PREVIEWER
1876 +/* Passed by application for getting crop size */
1877 +struct rsz_cropsize {
1878 + __u32 hcrop; /* Number of pixels per line
1879 + * cropped in output image.
1882 + __u32 vcrop; /* Number of lines cropped
1883 + * in output image.