2009-06-19 14:18:14 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2006-2009 Texas Instruments Inc
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* CCDC hardware module for DM6446
|
|
|
|
* ------------------------------
|
|
|
|
*
|
|
|
|
* This module is for configuring CCD controller of DM6446 VPFE to capture
|
|
|
|
* Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
|
|
|
|
* such as Defect Pixel Correction, Color Space Conversion etc to
|
|
|
|
* pre-process the Raw Bayer RGB data, before writing it to SDRAM. This
|
|
|
|
* module also allows application to configure individual
|
|
|
|
* module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
|
|
|
|
* To do so, application includes dm644x_ccdc.h and vpfe_capture.h header
|
|
|
|
* files. The setparams() API is called by vpfe_capture driver
|
|
|
|
* to configure module parameters. This file is named DM644x so that other
|
|
|
|
* variants such DM6443 may be supported using the same module.
|
|
|
|
*
|
|
|
|
* TODO: Test Raw bayer parameter settings and bayer capture
|
|
|
|
* Split module parameter structure to module specific ioctl structs
|
|
|
|
* investigate if enum used for user space type definition
|
|
|
|
* to be replaced by #defines or integer
|
|
|
|
*/
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <linux/videodev2.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 09:04:11 +01:00
|
|
|
#include <linux/gfp.h>
|
2010-01-14 00:27:07 +01:00
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
|
2009-06-19 14:18:14 +02:00
|
|
|
#include <media/davinci/dm644x_ccdc.h>
|
|
|
|
#include <media/davinci/vpss.h>
|
2010-01-14 00:27:07 +01:00
|
|
|
|
2009-06-19 14:18:14 +02:00
|
|
|
#include "dm644x_ccdc_regs.h"
|
|
|
|
#include "ccdc_hw_device.h"
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_DESCRIPTION("CCDC Driver for DM6446");
|
|
|
|
MODULE_AUTHOR("Texas Instruments");
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
static struct ccdc_oper_config {
|
|
|
|
struct device *dev;
|
|
|
|
/* CCDC interface type */
|
|
|
|
enum vpfe_hw_if_type if_type;
|
|
|
|
/* Raw Bayer configuration */
|
|
|
|
struct ccdc_params_raw bayer;
|
|
|
|
/* YCbCr configuration */
|
|
|
|
struct ccdc_params_ycbcr ycbcr;
|
|
|
|
/* Master clock */
|
|
|
|
struct clk *mclk;
|
|
|
|
/* slave clock */
|
|
|
|
struct clk *sclk;
|
|
|
|
/* ccdc base address */
|
|
|
|
void __iomem *base_addr;
|
|
|
|
} ccdc_cfg = {
|
|
|
|
/* Raw configurations */
|
|
|
|
.bayer = {
|
|
|
|
.pix_fmt = CCDC_PIXFMT_RAW,
|
|
|
|
.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
|
|
|
|
.win = CCDC_WIN_VGA,
|
|
|
|
.fid_pol = VPFE_PINPOL_POSITIVE,
|
|
|
|
.vd_pol = VPFE_PINPOL_POSITIVE,
|
|
|
|
.hd_pol = VPFE_PINPOL_POSITIVE,
|
|
|
|
.config_params = {
|
|
|
|
.data_sz = CCDC_DATA_10BITS,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.ycbcr = {
|
|
|
|
.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
|
|
|
|
.frm_fmt = CCDC_FRMFMT_INTERLACED,
|
|
|
|
.win = CCDC_WIN_PAL,
|
|
|
|
.fid_pol = VPFE_PINPOL_POSITIVE,
|
|
|
|
.vd_pol = VPFE_PINPOL_POSITIVE,
|
|
|
|
.hd_pol = VPFE_PINPOL_POSITIVE,
|
|
|
|
.bt656_enable = 1,
|
|
|
|
.pix_order = CCDC_PIXORDER_CBYCRY,
|
|
|
|
.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
|
2009-06-19 14:18:14 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
#define CCDC_MAX_RAW_YUV_FORMATS 2
|
|
|
|
|
|
|
|
/* Raw Bayer formats */
|
|
|
|
static u32 ccdc_raw_bayer_pix_formats[] =
|
|
|
|
{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
|
|
|
|
|
|
|
|
/* Raw YUV formats */
|
|
|
|
static u32 ccdc_raw_yuv_pix_formats[] =
|
|
|
|
{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
|
|
|
|
|
|
|
|
/* register access routines */
|
|
|
|
static inline u32 regr(u32 offset)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
return __raw_readl(ccdc_cfg.base_addr + offset);
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void regw(u32 val, u32 offset)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
__raw_writel(val, ccdc_cfg.base_addr + offset);
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_enable(int flag)
|
|
|
|
{
|
|
|
|
regw(flag, CCDC_PCR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_enable_vport(int flag)
|
|
|
|
{
|
|
|
|
if (flag)
|
|
|
|
/* enable video port */
|
|
|
|
regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
|
|
|
|
else
|
|
|
|
regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ccdc_setwin()
|
|
|
|
* This function will configure the window size
|
|
|
|
* to be capture in CCDC reg
|
|
|
|
*/
|
|
|
|
void ccdc_setwin(struct v4l2_rect *image_win,
|
|
|
|
enum ccdc_frmfmt frm_fmt,
|
|
|
|
int ppc)
|
|
|
|
{
|
|
|
|
int horz_start, horz_nr_pixels;
|
|
|
|
int vert_start, vert_nr_lines;
|
|
|
|
int val = 0, mid_img = 0;
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
|
2009-06-19 14:18:14 +02:00
|
|
|
/*
|
|
|
|
* ppc - per pixel count. indicates how many pixels per cell
|
|
|
|
* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
|
|
|
|
* raw capture this is 1
|
|
|
|
*/
|
|
|
|
horz_start = image_win->left << (ppc - 1);
|
|
|
|
horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
|
|
|
|
regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
|
|
|
|
CCDC_HORZ_INFO);
|
|
|
|
|
|
|
|
vert_start = image_win->top;
|
|
|
|
|
|
|
|
if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
|
|
|
|
vert_nr_lines = (image_win->height >> 1) - 1;
|
|
|
|
vert_start >>= 1;
|
|
|
|
/* Since first line doesn't have any data */
|
|
|
|
vert_start += 1;
|
|
|
|
/* configure VDINT0 */
|
|
|
|
val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
|
|
|
|
regw(val, CCDC_VDINT);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* Since first line doesn't have any data */
|
|
|
|
vert_start += 1;
|
|
|
|
vert_nr_lines = image_win->height - 1;
|
|
|
|
/*
|
|
|
|
* configure VDINT0 and VDINT1. VDINT1 will be at half
|
|
|
|
* of image height
|
|
|
|
*/
|
|
|
|
mid_img = vert_start + (image_win->height / 2);
|
|
|
|
val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
|
|
|
|
(mid_img & CCDC_VDINT_VDINT1_MASK);
|
|
|
|
regw(val, CCDC_VDINT);
|
|
|
|
|
|
|
|
}
|
|
|
|
regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
|
|
|
|
CCDC_VERT_START);
|
|
|
|
regw(vert_nr_lines, CCDC_VERT_LINES);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_readregs(void)
|
|
|
|
{
|
|
|
|
unsigned int val = 0;
|
|
|
|
|
|
|
|
val = regr(CCDC_ALAW);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_CLAMP);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_DCSUB);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_BLKCMP);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_FPC_ADDR);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_FPC);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_FMTCFG);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_COLPTN);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_FMT_HORZ);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_FMT_VERT);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_HSIZE_OFF);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_SDOFST);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_VP_OUT);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_SYN_MODE);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_HORZ_INFO);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_VERT_START);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = regr(CCDC_VERT_LINES);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
|
|
|
|
{
|
|
|
|
if (ccdcparam->alaw.enable) {
|
|
|
|
if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
|
|
|
|
(ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
|
|
|
|
(ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nInvalid data line select");
|
2009-06-19 14:18:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
|
|
|
|
{
|
|
|
|
struct ccdc_config_params_raw *config_params =
|
2010-01-14 00:27:07 +01:00
|
|
|
&ccdc_cfg.bayer.config_params;
|
2009-06-19 14:18:14 +02:00
|
|
|
unsigned int *fpc_virtaddr = NULL;
|
|
|
|
unsigned int *fpc_physaddr = NULL;
|
|
|
|
|
|
|
|
memcpy(config_params, raw_params, sizeof(*raw_params));
|
|
|
|
/*
|
|
|
|
* allocate memory for fault pixel table and copy the user
|
|
|
|
* values to the table
|
|
|
|
*/
|
|
|
|
if (!config_params->fault_pxl.enable)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
|
|
|
|
fpc_virtaddr = (unsigned int *)phys_to_virt(
|
|
|
|
(unsigned long)fpc_physaddr);
|
|
|
|
/*
|
|
|
|
* Allocate memory for FPC table if current
|
|
|
|
* FPC table buffer is not big enough to
|
|
|
|
* accomodate FPC Number requested
|
|
|
|
*/
|
|
|
|
if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {
|
|
|
|
if (fpc_physaddr != NULL) {
|
|
|
|
free_pages((unsigned long)fpc_physaddr,
|
|
|
|
get_order
|
|
|
|
(config_params->fault_pxl.fp_num *
|
|
|
|
FP_NUM_BYTES));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate memory for FPC table */
|
|
|
|
fpc_virtaddr =
|
|
|
|
(unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,
|
|
|
|
get_order(raw_params->
|
|
|
|
fault_pxl.fp_num *
|
|
|
|
FP_NUM_BYTES));
|
|
|
|
|
|
|
|
if (fpc_virtaddr == NULL) {
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev,
|
2009-06-19 14:18:14 +02:00
|
|
|
"\nUnable to allocate memory for FPC");
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
fpc_physaddr =
|
|
|
|
(unsigned int *)virt_to_phys((void *)fpc_virtaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy number of fault pixels and FPC table */
|
|
|
|
config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;
|
|
|
|
if (copy_from_user(fpc_virtaddr,
|
|
|
|
(void __user *)raw_params->fault_pxl.fpc_table_addr,
|
|
|
|
config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
|
2009-06-19 14:18:14 +02:00
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_close(struct device *dev)
|
|
|
|
{
|
|
|
|
struct ccdc_config_params_raw *config_params =
|
2010-01-14 00:27:07 +01:00
|
|
|
&ccdc_cfg.bayer.config_params;
|
2009-06-19 14:18:14 +02:00
|
|
|
unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;
|
|
|
|
|
|
|
|
fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;
|
|
|
|
|
|
|
|
if (fpc_physaddr != NULL) {
|
|
|
|
fpc_virtaddr = (unsigned int *)
|
|
|
|
phys_to_virt((unsigned long)fpc_physaddr);
|
|
|
|
free_pages((unsigned long)fpc_virtaddr,
|
|
|
|
get_order(config_params->fault_pxl.fp_num *
|
|
|
|
FP_NUM_BYTES));
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ccdc_restore_defaults()
|
|
|
|
* This function will write defaults to all CCDC registers
|
|
|
|
*/
|
|
|
|
static void ccdc_restore_defaults(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* disable CCDC */
|
|
|
|
ccdc_enable(0);
|
|
|
|
/* set all registers to default value */
|
|
|
|
for (i = 4; i <= 0x94; i += 4)
|
|
|
|
regw(0, i);
|
|
|
|
regw(CCDC_NO_CULLING, CCDC_CULLING);
|
|
|
|
regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_open(struct device *device)
|
|
|
|
{
|
|
|
|
ccdc_restore_defaults();
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
2009-06-19 14:18:14 +02:00
|
|
|
ccdc_enable_vport(1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_sbl_reset(void)
|
|
|
|
{
|
|
|
|
vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parameter operations */
|
|
|
|
static int ccdc_set_params(void __user *params)
|
|
|
|
{
|
|
|
|
struct ccdc_config_params_raw ccdc_raw_params;
|
|
|
|
int x;
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
|
2009-06-19 14:18:14 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
|
|
|
|
if (x) {
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying"
|
2009-06-19 14:18:14 +02:00
|
|
|
"ccdc params, %d\n", x);
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!validate_ccdc_param(&ccdc_raw_params)) {
|
|
|
|
if (!ccdc_update_raw_params(&ccdc_raw_params))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ccdc_config_ycbcr()
|
|
|
|
* This function will configure CCDC for YCbCr video capture
|
|
|
|
*/
|
|
|
|
void ccdc_config_ycbcr(void)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
|
2009-06-19 14:18:14 +02:00
|
|
|
u32 syn_mode;
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
|
2009-06-19 14:18:14 +02:00
|
|
|
/*
|
|
|
|
* first restore the CCDC registers to default values
|
|
|
|
* This is important since we assume default values to be set in
|
|
|
|
* a lot of registers that we didn't touch
|
|
|
|
*/
|
|
|
|
ccdc_restore_defaults();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* configure pixel format, frame format, configure video frame
|
|
|
|
* format, enable output to SDRAM, enable internal timing generator
|
|
|
|
* and 8bit pack mode
|
|
|
|
*/
|
|
|
|
syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
|
|
|
|
CCDC_SYN_MODE_INPMOD_SHIFT) |
|
|
|
|
((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
|
|
|
|
CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
|
|
|
|
CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
|
|
|
|
|
|
|
|
/* setup BT.656 sync mode */
|
|
|
|
if (params->bt656_enable) {
|
|
|
|
regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* configure the FID, VD, HD pin polarity,
|
|
|
|
* fld,hd pol positive, vd negative, 8-bit data
|
|
|
|
*/
|
2010-03-27 13:37:12 +01:00
|
|
|
syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;
|
|
|
|
if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
|
|
|
|
syn_mode |= CCDC_SYN_MODE_10BITS;
|
|
|
|
else
|
|
|
|
syn_mode |= CCDC_SYN_MODE_8BITS;
|
2009-06-19 14:18:14 +02:00
|
|
|
} else {
|
|
|
|
/* y/c external sync mode */
|
|
|
|
syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
|
|
|
|
CCDC_FID_POL_SHIFT) |
|
|
|
|
((params->hd_pol & CCDC_HD_POL_MASK) <<
|
|
|
|
CCDC_HD_POL_SHIFT) |
|
|
|
|
((params->vd_pol & CCDC_VD_POL_MASK) <<
|
|
|
|
CCDC_VD_POL_SHIFT));
|
|
|
|
}
|
|
|
|
regw(syn_mode, CCDC_SYN_MODE);
|
|
|
|
|
|
|
|
/* configure video window */
|
|
|
|
ccdc_setwin(¶ms->win, params->frm_fmt, 2);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* configure the order of y cb cr in SDRAM, and disable latch
|
|
|
|
* internal register on vsync
|
|
|
|
*/
|
2010-03-27 13:37:12 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
|
|
|
|
regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
|
|
|
|
CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,
|
|
|
|
CCDC_CCDCFG);
|
|
|
|
else
|
|
|
|
regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
|
|
|
|
CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
|
2009-06-19 14:18:14 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* configure the horizontal line offset. This should be a
|
|
|
|
* on 32 byte bondary. So clear LSB 5 bits
|
|
|
|
*/
|
|
|
|
regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);
|
|
|
|
|
|
|
|
/* configure the memory line offset */
|
|
|
|
if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
|
|
|
|
/* two fields are interleaved in memory */
|
|
|
|
regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
|
|
|
|
|
|
|
|
ccdc_sbl_reset();
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
|
|
|
|
{
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
if (!bclamp->enable) {
|
|
|
|
/* configure DCSub */
|
|
|
|
val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
|
|
|
|
regw(val, CCDC_DCSUB);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");
|
2009-06-19 14:18:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Configure gain, Start pixel, No of line to be avg,
|
|
|
|
* No of pixel/line to be avg, & Enable the Black clamping
|
|
|
|
*/
|
|
|
|
val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
|
|
|
|
((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
|
|
|
|
CCDC_BLK_ST_PXL_SHIFT) |
|
|
|
|
((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
|
|
|
|
CCDC_BLK_SAMPLE_LINE_SHIFT) |
|
|
|
|
((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
|
|
|
|
CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
|
|
|
|
regw(val, CCDC_CLAMP);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
/* If Black clamping is enable then make dcsub 0 */
|
|
|
|
regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
|
|
|
|
{
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
|
|
|
|
((bcomp->gb & CCDC_BLK_COMP_MASK) <<
|
|
|
|
CCDC_BLK_COMP_GB_COMP_SHIFT) |
|
|
|
|
((bcomp->gr & CCDC_BLK_COMP_MASK) <<
|
|
|
|
CCDC_BLK_COMP_GR_COMP_SHIFT) |
|
|
|
|
((bcomp->r & CCDC_BLK_COMP_MASK) <<
|
|
|
|
CCDC_BLK_COMP_R_COMP_SHIFT));
|
|
|
|
regw(val, CCDC_BLKCMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
|
|
|
|
{
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
/* Initially disable FPC */
|
|
|
|
val = CCDC_FPC_DISABLE;
|
|
|
|
regw(val, CCDC_FPC);
|
|
|
|
|
|
|
|
if (!fpc->enable)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Configure Fault pixel if needed */
|
|
|
|
regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
|
2009-06-19 14:18:14 +02:00
|
|
|
(fpc->fpc_table_addr));
|
|
|
|
/* Write the FPC params with FPC disable */
|
|
|
|
val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
|
|
|
|
regw(val, CCDC_FPC);
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
/* read the FPC register */
|
|
|
|
val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;
|
|
|
|
regw(val, CCDC_FPC);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ccdc_config_raw()
|
|
|
|
* This function will configure CCDC for Raw capture mode
|
|
|
|
*/
|
|
|
|
void ccdc_config_raw(void)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
struct ccdc_params_raw *params = &ccdc_cfg.bayer;
|
2009-06-19 14:18:14 +02:00
|
|
|
struct ccdc_config_params_raw *config_params =
|
2010-01-14 00:27:07 +01:00
|
|
|
&ccdc_cfg.bayer.config_params;
|
2009-06-19 14:18:14 +02:00
|
|
|
unsigned int syn_mode = 0;
|
|
|
|
unsigned int val;
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
|
2009-06-19 14:18:14 +02:00
|
|
|
|
|
|
|
/* Reset CCDC */
|
|
|
|
ccdc_restore_defaults();
|
|
|
|
|
|
|
|
/* Disable latching function registers on VSYNC */
|
|
|
|
regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure the vertical sync polarity(SYN_MODE.VDPOL),
|
|
|
|
* horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
|
|
|
|
* (SYN_MODE.FLDPOL), frame format(progressive or interlace),
|
|
|
|
* data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
|
|
|
|
* SDRAM, enable internal timing generator
|
|
|
|
*/
|
|
|
|
syn_mode =
|
|
|
|
(((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
|
|
|
|
((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
|
|
|
|
((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
|
|
|
|
((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
|
|
|
|
((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
|
|
|
|
CCDC_DATA_SZ_SHIFT) |
|
|
|
|
((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
|
|
|
|
CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
|
|
|
|
|
|
|
|
/* Enable and configure aLaw register if needed */
|
|
|
|
if (config_params->alaw.enable) {
|
|
|
|
val = ((config_params->alaw.gama_wd &
|
|
|
|
CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
|
|
|
|
regw(val, CCDC_ALAW);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Configure video window */
|
|
|
|
ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW);
|
|
|
|
|
|
|
|
/* Configure Black Clamp */
|
|
|
|
ccdc_config_black_clamp(&config_params->blk_clamp);
|
|
|
|
|
|
|
|
/* Configure Black level compensation */
|
|
|
|
ccdc_config_black_compense(&config_params->blk_comp);
|
|
|
|
|
|
|
|
/* Configure Fault Pixel Correction */
|
|
|
|
ccdc_config_fpc(&config_params->fault_pxl);
|
|
|
|
|
|
|
|
/* If data size is 8 bit then pack the data */
|
|
|
|
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
|
|
|
|
config_params->alaw.enable)
|
|
|
|
syn_mode |= CCDC_DATA_PACK_ENABLE;
|
|
|
|
|
|
|
|
#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
|
|
|
|
/* enable video port */
|
|
|
|
val = CCDC_ENABLE_VIDEO_PORT;
|
|
|
|
#else
|
|
|
|
/* disable video port */
|
|
|
|
val = CCDC_DISABLE_VIDEO_PORT;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (config_params->data_sz == CCDC_DATA_8BITS)
|
|
|
|
val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
|
|
|
|
<< CCDC_FMTCFG_VPIN_SHIFT;
|
|
|
|
else
|
|
|
|
val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
|
|
|
|
<< CCDC_FMTCFG_VPIN_SHIFT;
|
|
|
|
/* Write value in FMTCFG */
|
|
|
|
regw(val, CCDC_FMTCFG);
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
/* Configure the color pattern according to mt9t001 sensor */
|
|
|
|
regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
|
2009-06-19 14:18:14 +02:00
|
|
|
/*
|
|
|
|
* Configure Data formatter(Video port) pixel selection
|
|
|
|
* (FMT_HORZ, FMT_VERT)
|
|
|
|
*/
|
|
|
|
val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
|
|
|
|
CCDC_FMT_HORZ_FMTSPH_SHIFT) |
|
|
|
|
(params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
|
|
|
|
regw(val, CCDC_FMT_HORZ);
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
|
|
|
|
<< CCDC_FMT_VERT_FMTSLV_SHIFT;
|
|
|
|
if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
|
|
|
|
val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
|
|
|
|
else
|
|
|
|
val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n",
|
2009-06-19 14:18:14 +02:00
|
|
|
params->win.height);
|
|
|
|
regw(val, CCDC_FMT_VERT);
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");
|
2009-06-19 14:18:14 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure Horizontal offset register. If pack 8 is enabled then
|
|
|
|
* 1 pixel will take 1 byte
|
|
|
|
*/
|
|
|
|
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
|
|
|
|
config_params->alaw.enable)
|
|
|
|
regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
|
|
|
|
CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
|
|
|
|
else
|
|
|
|
/* else one pixel will take 2 byte */
|
|
|
|
regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
|
|
|
|
CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
|
|
|
|
CCDC_HSIZE_OFF);
|
|
|
|
|
|
|
|
/* Set value for SDOFST */
|
|
|
|
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
|
|
|
|
if (params->image_invert_enable) {
|
|
|
|
/* For intelace inverse mode */
|
|
|
|
regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
/* For intelace non inverse mode */
|
|
|
|
regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
|
|
|
|
regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure video port pixel selection (VPOUT)
|
|
|
|
* Here -1 is to make the height value less than FMT_VERT.FMTLNV
|
|
|
|
*/
|
|
|
|
if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
|
|
|
|
val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
|
|
|
|
<< CCDC_VP_OUT_VERT_NUM_SHIFT;
|
|
|
|
else
|
|
|
|
val =
|
|
|
|
((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
|
|
|
|
1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
|
|
|
|
CCDC_VP_OUT_VERT_NUM_SHIFT;
|
|
|
|
|
|
|
|
val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
|
|
|
|
<< CCDC_VP_OUT_HORZ_NUM_SHIFT;
|
|
|
|
val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
|
|
|
|
regw(val, CCDC_VP_OUT);
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);
|
2009-06-19 14:18:14 +02:00
|
|
|
regw(syn_mode, CCDC_SYN_MODE);
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
|
2009-06-19 14:18:14 +02:00
|
|
|
|
|
|
|
ccdc_sbl_reset();
|
2010-01-14 00:27:07 +01:00
|
|
|
dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
|
2009-06-19 14:18:14 +02:00
|
|
|
ccdc_readregs();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_configure(void)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
2009-06-19 14:18:14 +02:00
|
|
|
ccdc_config_raw();
|
|
|
|
else
|
|
|
|
ccdc_config_ycbcr();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_set_buftype(enum ccdc_buftype buf_type)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
|
|
|
ccdc_cfg.bayer.buf_type = buf_type;
|
2009-06-19 14:18:14 +02:00
|
|
|
else
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.ycbcr.buf_type = buf_type;
|
2009-06-19 14:18:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum ccdc_buftype ccdc_get_buftype(void)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
|
|
|
return ccdc_cfg.bayer.buf_type;
|
|
|
|
return ccdc_cfg.ycbcr.buf_type;
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_enum_pix(u32 *pix, int i)
|
|
|
|
{
|
|
|
|
int ret = -EINVAL;
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
|
2009-06-19 14:18:14 +02:00
|
|
|
if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
|
|
|
|
*pix = ccdc_raw_bayer_pix_formats[i];
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
|
|
|
|
*pix = ccdc_raw_yuv_pix_formats[i];
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_set_pixel_format(u32 pixfmt)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
|
|
|
|
ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
|
2009-06-19 14:18:14 +02:00
|
|
|
if (pixfmt == V4L2_PIX_FMT_SBGGR8)
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.bayer.config_params.alaw.enable = 1;
|
2009-06-19 14:18:14 +02:00
|
|
|
else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
|
|
|
|
return -EINVAL;
|
|
|
|
} else {
|
|
|
|
if (pixfmt == V4L2_PIX_FMT_YUYV)
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
|
2009-06-19 14:18:14 +02:00
|
|
|
else if (pixfmt == V4L2_PIX_FMT_UYVY)
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
|
2009-06-19 14:18:14 +02:00
|
|
|
else
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 ccdc_get_pixel_format(void)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
|
2009-06-19 14:18:14 +02:00
|
|
|
u32 pixfmt;
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
2009-06-19 14:18:14 +02:00
|
|
|
if (alaw->enable)
|
|
|
|
pixfmt = V4L2_PIX_FMT_SBGGR8;
|
|
|
|
else
|
|
|
|
pixfmt = V4L2_PIX_FMT_SBGGR16;
|
|
|
|
else {
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
|
2009-06-19 14:18:14 +02:00
|
|
|
pixfmt = V4L2_PIX_FMT_YUYV;
|
|
|
|
else
|
|
|
|
pixfmt = V4L2_PIX_FMT_UYVY;
|
|
|
|
}
|
|
|
|
return pixfmt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_set_image_window(struct v4l2_rect *win)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
|
|
|
ccdc_cfg.bayer.win = *win;
|
2009-06-19 14:18:14 +02:00
|
|
|
else
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.ycbcr.win = *win;
|
2009-06-19 14:18:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ccdc_get_image_window(struct v4l2_rect *win)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
|
|
|
*win = ccdc_cfg.bayer.win;
|
2009-06-19 14:18:14 +02:00
|
|
|
else
|
2010-01-14 00:27:07 +01:00
|
|
|
*win = ccdc_cfg.ycbcr.win;
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int ccdc_get_line_length(void)
|
|
|
|
{
|
|
|
|
struct ccdc_config_params_raw *config_params =
|
2010-01-14 00:27:07 +01:00
|
|
|
&ccdc_cfg.bayer.config_params;
|
2009-06-19 14:18:14 +02:00
|
|
|
unsigned int len;
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
|
2009-06-19 14:18:14 +02:00
|
|
|
if ((config_params->alaw.enable) ||
|
|
|
|
(config_params->data_sz == CCDC_DATA_8BITS))
|
2010-01-14 00:27:07 +01:00
|
|
|
len = ccdc_cfg.bayer.win.width;
|
2009-06-19 14:18:14 +02:00
|
|
|
else
|
2010-01-14 00:27:07 +01:00
|
|
|
len = ccdc_cfg.bayer.win.width * 2;
|
2009-06-19 14:18:14 +02:00
|
|
|
} else
|
2010-01-14 00:27:07 +01:00
|
|
|
len = ccdc_cfg.ycbcr.win.width * 2;
|
2009-06-19 14:18:14 +02:00
|
|
|
return ALIGN(len, 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
|
|
|
ccdc_cfg.bayer.frm_fmt = frm_fmt;
|
2009-06-19 14:18:14 +02:00
|
|
|
else
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
|
2009-06-19 14:18:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum ccdc_frmfmt ccdc_get_frame_format(void)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
|
|
|
|
return ccdc_cfg.bayer.frm_fmt;
|
2009-06-19 14:18:14 +02:00
|
|
|
else
|
2010-01-14 00:27:07 +01:00
|
|
|
return ccdc_cfg.ycbcr.frm_fmt;
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_getfid(void)
|
|
|
|
{
|
|
|
|
return (regr(CCDC_SYN_MODE) >> 15) & 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* misc operations */
|
|
|
|
static inline void ccdc_setfbaddr(unsigned long addr)
|
|
|
|
{
|
|
|
|
regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
|
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.if_type = params->if_type;
|
2009-06-19 14:18:14 +02:00
|
|
|
|
|
|
|
switch (params->if_type) {
|
|
|
|
case VPFE_BT656:
|
|
|
|
case VPFE_YCBCR_SYNC_16:
|
|
|
|
case VPFE_YCBCR_SYNC_8:
|
2010-03-27 13:37:12 +01:00
|
|
|
case VPFE_BT656_10BIT:
|
2010-01-14 00:27:07 +01:00
|
|
|
ccdc_cfg.ycbcr.vd_pol = params->vdpol;
|
|
|
|
ccdc_cfg.ycbcr.hd_pol = params->hdpol;
|
2009-06-19 14:18:14 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* TODO add support for raw bayer here */
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ccdc_hw_device ccdc_hw_dev = {
|
|
|
|
.name = "DM6446 CCDC",
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.hw_ops = {
|
|
|
|
.open = ccdc_open,
|
|
|
|
.close = ccdc_close,
|
|
|
|
.reset = ccdc_sbl_reset,
|
|
|
|
.enable = ccdc_enable,
|
|
|
|
.set_hw_if_params = ccdc_set_hw_if_params,
|
|
|
|
.set_params = ccdc_set_params,
|
|
|
|
.configure = ccdc_configure,
|
|
|
|
.set_buftype = ccdc_set_buftype,
|
|
|
|
.get_buftype = ccdc_get_buftype,
|
|
|
|
.enum_pix = ccdc_enum_pix,
|
|
|
|
.set_pixel_format = ccdc_set_pixel_format,
|
|
|
|
.get_pixel_format = ccdc_get_pixel_format,
|
|
|
|
.set_frame_format = ccdc_set_frame_format,
|
|
|
|
.get_frame_format = ccdc_get_frame_format,
|
|
|
|
.set_image_window = ccdc_set_image_window,
|
|
|
|
.get_image_window = ccdc_get_image_window,
|
|
|
|
.get_line_length = ccdc_get_line_length,
|
|
|
|
.setfbaddr = ccdc_setfbaddr,
|
|
|
|
.getfid = ccdc_getfid,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
static int __init dm644x_ccdc_probe(struct platform_device *pdev)
|
2009-06-19 14:18:14 +02:00
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
struct resource *res;
|
|
|
|
int status = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* first try to register with vpfe. If not correct platform, then we
|
|
|
|
* don't have to iomap
|
|
|
|
*/
|
|
|
|
status = vpfe_register_ccdc_device(&ccdc_hw_dev);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
|
if (!res) {
|
|
|
|
status = -ENODEV;
|
|
|
|
goto fail_nores;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = request_mem_region(res->start, resource_size(res), res->name);
|
|
|
|
if (!res) {
|
|
|
|
status = -EBUSY;
|
|
|
|
goto fail_nores;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
|
|
|
|
if (!ccdc_cfg.base_addr) {
|
|
|
|
status = -ENOMEM;
|
|
|
|
goto fail_nomem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get and enable Master clock */
|
|
|
|
ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
|
|
|
|
if (IS_ERR(ccdc_cfg.mclk)) {
|
|
|
|
status = PTR_ERR(ccdc_cfg.mclk);
|
|
|
|
goto fail_nomap;
|
|
|
|
}
|
|
|
|
if (clk_enable(ccdc_cfg.mclk)) {
|
|
|
|
status = -ENODEV;
|
|
|
|
goto fail_mclk;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get and enable Slave clock */
|
|
|
|
ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
|
|
|
|
if (IS_ERR(ccdc_cfg.sclk)) {
|
|
|
|
status = PTR_ERR(ccdc_cfg.sclk);
|
|
|
|
goto fail_mclk;
|
|
|
|
}
|
|
|
|
if (clk_enable(ccdc_cfg.sclk)) {
|
|
|
|
status = -ENODEV;
|
|
|
|
goto fail_sclk;
|
|
|
|
}
|
|
|
|
ccdc_cfg.dev = &pdev->dev;
|
|
|
|
printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
|
2009-06-19 14:18:14 +02:00
|
|
|
return 0;
|
2010-01-14 00:27:07 +01:00
|
|
|
fail_sclk:
|
|
|
|
clk_put(ccdc_cfg.sclk);
|
|
|
|
fail_mclk:
|
|
|
|
clk_put(ccdc_cfg.mclk);
|
|
|
|
fail_nomap:
|
|
|
|
iounmap(ccdc_cfg.base_addr);
|
|
|
|
fail_nomem:
|
|
|
|
release_mem_region(res->start, resource_size(res));
|
|
|
|
fail_nores:
|
|
|
|
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
|
|
|
|
return status;
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
2010-01-14 00:27:07 +01:00
|
|
|
static int dm644x_ccdc_remove(struct platform_device *pdev)
|
2009-06-19 14:18:14 +02:00
|
|
|
{
|
2010-01-14 00:27:07 +01:00
|
|
|
struct resource *res;
|
|
|
|
|
|
|
|
clk_put(ccdc_cfg.mclk);
|
|
|
|
clk_put(ccdc_cfg.sclk);
|
|
|
|
iounmap(ccdc_cfg.base_addr);
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
|
if (res)
|
|
|
|
release_mem_region(res->start, resource_size(res));
|
2009-06-19 14:18:14 +02:00
|
|
|
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
|
2010-01-14 00:27:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct platform_driver dm644x_ccdc_driver = {
|
|
|
|
.driver = {
|
|
|
|
.name = "dm644x_ccdc",
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
},
|
|
|
|
.remove = __devexit_p(dm644x_ccdc_remove),
|
|
|
|
.probe = dm644x_ccdc_probe,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init dm644x_ccdc_init(void)
|
|
|
|
{
|
|
|
|
return platform_driver_register(&dm644x_ccdc_driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit dm644x_ccdc_exit(void)
|
|
|
|
{
|
|
|
|
platform_driver_unregister(&dm644x_ccdc_driver);
|
2009-06-19 14:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(dm644x_ccdc_init);
|
|
|
|
module_exit(dm644x_ccdc_exit);
|