Path: blob/master/drivers/media/video/davinci/dm644x_ccdc.c
17689 views
/*1* Copyright (C) 2006-2009 Texas Instruments Inc2*3* This program is free software; you can redistribute it and/or modify4* it under the terms of the GNU General Public License as published by5* the Free Software Foundation; either version 2 of the License, or6* (at your option) any later version.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*13* You should have received a copy of the GNU General Public License14* along with this program; if not, write to the Free Software15* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA16*17* CCDC hardware module for DM644618* ------------------------------19*20* This module is for configuring CCD controller of DM6446 VPFE to capture21* Raw yuv or Bayer RGB data from a decoder. CCDC has several modules22* such as Defect Pixel Correction, Color Space Conversion etc to23* pre-process the Raw Bayer RGB data, before writing it to SDRAM. This24* module also allows application to configure individual25* module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.26* To do so, application includes dm644x_ccdc.h and vpfe_capture.h header27* files. The setparams() API is called by vpfe_capture driver28* to configure module parameters. This file is named DM644x so that other29* variants such DM6443 may be supported using the same module.30*31* TODO: Test Raw bayer parameter settings and bayer capture32* Split module parameter structure to module specific ioctl structs33* investigate if enum used for user space type definition34* to be replaced by #defines or integer35*/36#include <linux/platform_device.h>37#include <linux/uaccess.h>38#include <linux/videodev2.h>39#include <linux/gfp.h>40#include <linux/clk.h>41#include <linux/err.h>4243#include <media/davinci/dm644x_ccdc.h>44#include <media/davinci/vpss.h>4546#include "dm644x_ccdc_regs.h"47#include "ccdc_hw_device.h"4849MODULE_LICENSE("GPL");50MODULE_DESCRIPTION("CCDC Driver for DM6446");51MODULE_AUTHOR("Texas Instruments");5253static struct ccdc_oper_config {54struct device *dev;55/* CCDC interface type */56enum vpfe_hw_if_type if_type;57/* Raw Bayer configuration */58struct ccdc_params_raw bayer;59/* YCbCr configuration */60struct ccdc_params_ycbcr ycbcr;61/* Master clock */62struct clk *mclk;63/* slave clock */64struct clk *sclk;65/* ccdc base address */66void __iomem *base_addr;67} ccdc_cfg = {68/* Raw configurations */69.bayer = {70.pix_fmt = CCDC_PIXFMT_RAW,71.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,72.win = CCDC_WIN_VGA,73.fid_pol = VPFE_PINPOL_POSITIVE,74.vd_pol = VPFE_PINPOL_POSITIVE,75.hd_pol = VPFE_PINPOL_POSITIVE,76.config_params = {77.data_sz = CCDC_DATA_10BITS,78},79},80.ycbcr = {81.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,82.frm_fmt = CCDC_FRMFMT_INTERLACED,83.win = CCDC_WIN_PAL,84.fid_pol = VPFE_PINPOL_POSITIVE,85.vd_pol = VPFE_PINPOL_POSITIVE,86.hd_pol = VPFE_PINPOL_POSITIVE,87.bt656_enable = 1,88.pix_order = CCDC_PIXORDER_CBYCRY,89.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED90},91};9293#define CCDC_MAX_RAW_YUV_FORMATS 29495/* Raw Bayer formats */96static u32 ccdc_raw_bayer_pix_formats[] =97{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};9899/* Raw YUV formats */100static u32 ccdc_raw_yuv_pix_formats[] =101{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};102103/* CCDC Save/Restore context */104static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];105106/* register access routines */107static inline u32 regr(u32 offset)108{109return __raw_readl(ccdc_cfg.base_addr + offset);110}111112static inline void regw(u32 val, u32 offset)113{114__raw_writel(val, ccdc_cfg.base_addr + offset);115}116117static void ccdc_enable(int flag)118{119regw(flag, CCDC_PCR);120}121122static void ccdc_enable_vport(int flag)123{124if (flag)125/* enable video port */126regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);127else128regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);129}130131/*132* ccdc_setwin()133* This function will configure the window size134* to be capture in CCDC reg135*/136void ccdc_setwin(struct v4l2_rect *image_win,137enum ccdc_frmfmt frm_fmt,138int ppc)139{140int horz_start, horz_nr_pixels;141int vert_start, vert_nr_lines;142int val = 0, mid_img = 0;143144dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");145/*146* ppc - per pixel count. indicates how many pixels per cell147* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.148* raw capture this is 1149*/150horz_start = image_win->left << (ppc - 1);151horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;152regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,153CCDC_HORZ_INFO);154155vert_start = image_win->top;156157if (frm_fmt == CCDC_FRMFMT_INTERLACED) {158vert_nr_lines = (image_win->height >> 1) - 1;159vert_start >>= 1;160/* Since first line doesn't have any data */161vert_start += 1;162/* configure VDINT0 */163val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);164regw(val, CCDC_VDINT);165166} else {167/* Since first line doesn't have any data */168vert_start += 1;169vert_nr_lines = image_win->height - 1;170/*171* configure VDINT0 and VDINT1. VDINT1 will be at half172* of image height173*/174mid_img = vert_start + (image_win->height / 2);175val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |176(mid_img & CCDC_VDINT_VDINT1_MASK);177regw(val, CCDC_VDINT);178179}180regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,181CCDC_VERT_START);182regw(vert_nr_lines, CCDC_VERT_LINES);183dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");184}185186static void ccdc_readregs(void)187{188unsigned int val = 0;189190val = regr(CCDC_ALAW);191dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);192val = regr(CCDC_CLAMP);193dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);194val = regr(CCDC_DCSUB);195dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);196val = regr(CCDC_BLKCMP);197dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);198val = regr(CCDC_FPC_ADDR);199dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);200val = regr(CCDC_FPC);201dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);202val = regr(CCDC_FMTCFG);203dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);204val = regr(CCDC_COLPTN);205dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);206val = regr(CCDC_FMT_HORZ);207dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);208val = regr(CCDC_FMT_VERT);209dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);210val = regr(CCDC_HSIZE_OFF);211dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);212val = regr(CCDC_SDOFST);213dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);214val = regr(CCDC_VP_OUT);215dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);216val = regr(CCDC_SYN_MODE);217dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);218val = regr(CCDC_HORZ_INFO);219dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);220val = regr(CCDC_VERT_START);221dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);222val = regr(CCDC_VERT_LINES);223dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);224}225226static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)227{228if (ccdcparam->alaw.enable) {229if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||230(ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||231(ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {232dev_dbg(ccdc_cfg.dev, "\nInvalid data line select");233return -1;234}235}236return 0;237}238239static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)240{241struct ccdc_config_params_raw *config_params =242&ccdc_cfg.bayer.config_params;243unsigned int *fpc_virtaddr = NULL;244unsigned int *fpc_physaddr = NULL;245246memcpy(config_params, raw_params, sizeof(*raw_params));247/*248* allocate memory for fault pixel table and copy the user249* values to the table250*/251if (!config_params->fault_pxl.enable)252return 0;253254fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;255fpc_virtaddr = (unsigned int *)phys_to_virt(256(unsigned long)fpc_physaddr);257/*258* Allocate memory for FPC table if current259* FPC table buffer is not big enough to260* accommodate FPC Number requested261*/262if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) {263if (fpc_physaddr != NULL) {264free_pages((unsigned long)fpc_physaddr,265get_order266(config_params->fault_pxl.fp_num *267FP_NUM_BYTES));268}269270/* Allocate memory for FPC table */271fpc_virtaddr =272(unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA,273get_order(raw_params->274fault_pxl.fp_num *275FP_NUM_BYTES));276277if (fpc_virtaddr == NULL) {278dev_dbg(ccdc_cfg.dev,279"\nUnable to allocate memory for FPC");280return -EFAULT;281}282fpc_physaddr =283(unsigned int *)virt_to_phys((void *)fpc_virtaddr);284}285286/* Copy number of fault pixels and FPC table */287config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num;288if (copy_from_user(fpc_virtaddr,289(void __user *)raw_params->fault_pxl.fpc_table_addr,290config_params->fault_pxl.fp_num * FP_NUM_BYTES)) {291dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");292return -EFAULT;293}294config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;295return 0;296}297298static int ccdc_close(struct device *dev)299{300struct ccdc_config_params_raw *config_params =301&ccdc_cfg.bayer.config_params;302unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL;303304fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr;305306if (fpc_physaddr != NULL) {307fpc_virtaddr = (unsigned int *)308phys_to_virt((unsigned long)fpc_physaddr);309free_pages((unsigned long)fpc_virtaddr,310get_order(config_params->fault_pxl.fp_num *311FP_NUM_BYTES));312}313return 0;314}315316/*317* ccdc_restore_defaults()318* This function will write defaults to all CCDC registers319*/320static void ccdc_restore_defaults(void)321{322int i;323324/* disable CCDC */325ccdc_enable(0);326/* set all registers to default value */327for (i = 4; i <= 0x94; i += 4)328regw(0, i);329regw(CCDC_NO_CULLING, CCDC_CULLING);330regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);331}332333static int ccdc_open(struct device *device)334{335ccdc_restore_defaults();336if (ccdc_cfg.if_type == VPFE_RAW_BAYER)337ccdc_enable_vport(1);338return 0;339}340341static void ccdc_sbl_reset(void)342{343vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);344}345346/* Parameter operations */347static int ccdc_set_params(void __user *params)348{349struct ccdc_config_params_raw ccdc_raw_params;350int x;351352if (ccdc_cfg.if_type != VPFE_RAW_BAYER)353return -EINVAL;354355x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));356if (x) {357dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying"358"ccdc params, %d\n", x);359return -EFAULT;360}361362if (!validate_ccdc_param(&ccdc_raw_params)) {363if (!ccdc_update_raw_params(&ccdc_raw_params))364return 0;365}366return -EINVAL;367}368369/*370* ccdc_config_ycbcr()371* This function will configure CCDC for YCbCr video capture372*/373void ccdc_config_ycbcr(void)374{375struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;376u32 syn_mode;377378dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");379/*380* first restore the CCDC registers to default values381* This is important since we assume default values to be set in382* a lot of registers that we didn't touch383*/384ccdc_restore_defaults();385386/*387* configure pixel format, frame format, configure video frame388* format, enable output to SDRAM, enable internal timing generator389* and 8bit pack mode390*/391syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<392CCDC_SYN_MODE_INPMOD_SHIFT) |393((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<394CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |395CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);396397/* setup BT.656 sync mode */398if (params->bt656_enable) {399regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);400401/*402* configure the FID, VD, HD pin polarity,403* fld,hd pol positive, vd negative, 8-bit data404*/405syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;406if (ccdc_cfg.if_type == VPFE_BT656_10BIT)407syn_mode |= CCDC_SYN_MODE_10BITS;408else409syn_mode |= CCDC_SYN_MODE_8BITS;410} else {411/* y/c external sync mode */412syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<413CCDC_FID_POL_SHIFT) |414((params->hd_pol & CCDC_HD_POL_MASK) <<415CCDC_HD_POL_SHIFT) |416((params->vd_pol & CCDC_VD_POL_MASK) <<417CCDC_VD_POL_SHIFT));418}419regw(syn_mode, CCDC_SYN_MODE);420421/* configure video window */422ccdc_setwin(¶ms->win, params->frm_fmt, 2);423424/*425* configure the order of y cb cr in SDRAM, and disable latch426* internal register on vsync427*/428if (ccdc_cfg.if_type == VPFE_BT656_10BIT)429regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |430CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,431CCDC_CCDCFG);432else433regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |434CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);435436/*437* configure the horizontal line offset. This should be a438* on 32 byte boundary. So clear LSB 5 bits439*/440regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF);441442/* configure the memory line offset */443if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)444/* two fields are interleaved in memory */445regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);446447ccdc_sbl_reset();448dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");449}450451static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)452{453u32 val;454455if (!bclamp->enable) {456/* configure DCSub */457val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;458regw(val, CCDC_DCSUB);459dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);460regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);461dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");462return;463}464/*465* Configure gain, Start pixel, No of line to be avg,466* No of pixel/line to be avg, & Enable the Black clamping467*/468val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |469((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<470CCDC_BLK_ST_PXL_SHIFT) |471((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<472CCDC_BLK_SAMPLE_LINE_SHIFT) |473((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<474CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);475regw(val, CCDC_CLAMP);476dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);477/* If Black clamping is enable then make dcsub 0 */478regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);479dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");480}481482static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)483{484u32 val;485486val = ((bcomp->b & CCDC_BLK_COMP_MASK) |487((bcomp->gb & CCDC_BLK_COMP_MASK) <<488CCDC_BLK_COMP_GB_COMP_SHIFT) |489((bcomp->gr & CCDC_BLK_COMP_MASK) <<490CCDC_BLK_COMP_GR_COMP_SHIFT) |491((bcomp->r & CCDC_BLK_COMP_MASK) <<492CCDC_BLK_COMP_R_COMP_SHIFT));493regw(val, CCDC_BLKCMP);494}495496static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)497{498u32 val;499500/* Initially disable FPC */501val = CCDC_FPC_DISABLE;502regw(val, CCDC_FPC);503504if (!fpc->enable)505return;506507/* Configure Fault pixel if needed */508regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);509dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",510(fpc->fpc_table_addr));511/* Write the FPC params with FPC disable */512val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;513regw(val, CCDC_FPC);514515dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);516/* read the FPC register */517val = regr(CCDC_FPC) | CCDC_FPC_ENABLE;518regw(val, CCDC_FPC);519dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val);520}521522/*523* ccdc_config_raw()524* This function will configure CCDC for Raw capture mode525*/526void ccdc_config_raw(void)527{528struct ccdc_params_raw *params = &ccdc_cfg.bayer;529struct ccdc_config_params_raw *config_params =530&ccdc_cfg.bayer.config_params;531unsigned int syn_mode = 0;532unsigned int val;533534dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");535536/* Reset CCDC */537ccdc_restore_defaults();538539/* Disable latching function registers on VSYNC */540regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);541542/*543* Configure the vertical sync polarity(SYN_MODE.VDPOL),544* horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity545* (SYN_MODE.FLDPOL), frame format(progressive or interlace),546* data size(SYNMODE.DATSIZ), &pixel format (Input mode), output547* SDRAM, enable internal timing generator548*/549syn_mode =550(((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |551((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |552((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |553((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |554((config_params->data_sz & CCDC_DATA_SZ_MASK) <<555CCDC_DATA_SZ_SHIFT) |556((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |557CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);558559/* Enable and configure aLaw register if needed */560if (config_params->alaw.enable) {561val = ((config_params->alaw.gama_wd &562CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);563regw(val, CCDC_ALAW);564dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);565}566567/* Configure video window */568ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW);569570/* Configure Black Clamp */571ccdc_config_black_clamp(&config_params->blk_clamp);572573/* Configure Black level compensation */574ccdc_config_black_compense(&config_params->blk_comp);575576/* Configure Fault Pixel Correction */577ccdc_config_fpc(&config_params->fault_pxl);578579/* If data size is 8 bit then pack the data */580if ((config_params->data_sz == CCDC_DATA_8BITS) ||581config_params->alaw.enable)582syn_mode |= CCDC_DATA_PACK_ENABLE;583584#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE585/* enable video port */586val = CCDC_ENABLE_VIDEO_PORT;587#else588/* disable video port */589val = CCDC_DISABLE_VIDEO_PORT;590#endif591592if (config_params->data_sz == CCDC_DATA_8BITS)593val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)594<< CCDC_FMTCFG_VPIN_SHIFT;595else596val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)597<< CCDC_FMTCFG_VPIN_SHIFT;598/* Write value in FMTCFG */599regw(val, CCDC_FMTCFG);600601dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);602/* Configure the color pattern according to mt9t001 sensor */603regw(CCDC_COLPTN_VAL, CCDC_COLPTN);604605dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");606/*607* Configure Data formatter(Video port) pixel selection608* (FMT_HORZ, FMT_VERT)609*/610val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<611CCDC_FMT_HORZ_FMTSPH_SHIFT) |612(params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);613regw(val, CCDC_FMT_HORZ);614615dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);616val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)617<< CCDC_FMT_VERT_FMTSLV_SHIFT;618if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)619val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;620else621val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;622623dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n",624params->win.height);625regw(val, CCDC_FMT_VERT);626627dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);628629dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");630631/*632* Configure Horizontal offset register. If pack 8 is enabled then633* 1 pixel will take 1 byte634*/635if ((config_params->data_sz == CCDC_DATA_8BITS) ||636config_params->alaw.enable)637regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &638CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);639else640/* else one pixel will take 2 byte */641regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +642CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,643CCDC_HSIZE_OFF);644645/* Set value for SDOFST */646if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {647if (params->image_invert_enable) {648/* For intelace inverse mode */649regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);650dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");651}652653else {654/* For intelace non inverse mode */655regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);656dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");657}658} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {659regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);660dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");661}662663/*664* Configure video port pixel selection (VPOUT)665* Here -1 is to make the height value less than FMT_VERT.FMTLNV666*/667if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)668val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))669<< CCDC_VP_OUT_VERT_NUM_SHIFT;670else671val =672((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -6731) & CCDC_VP_OUT_VERT_NUM_MASK)) <<674CCDC_VP_OUT_VERT_NUM_SHIFT;675676val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)677<< CCDC_VP_OUT_HORZ_NUM_SHIFT;678val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;679regw(val, CCDC_VP_OUT);680681dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);682regw(syn_mode, CCDC_SYN_MODE);683dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);684685ccdc_sbl_reset();686dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");687ccdc_readregs();688}689690static int ccdc_configure(void)691{692if (ccdc_cfg.if_type == VPFE_RAW_BAYER)693ccdc_config_raw();694else695ccdc_config_ycbcr();696return 0;697}698699static int ccdc_set_buftype(enum ccdc_buftype buf_type)700{701if (ccdc_cfg.if_type == VPFE_RAW_BAYER)702ccdc_cfg.bayer.buf_type = buf_type;703else704ccdc_cfg.ycbcr.buf_type = buf_type;705return 0;706}707708static enum ccdc_buftype ccdc_get_buftype(void)709{710if (ccdc_cfg.if_type == VPFE_RAW_BAYER)711return ccdc_cfg.bayer.buf_type;712return ccdc_cfg.ycbcr.buf_type;713}714715static int ccdc_enum_pix(u32 *pix, int i)716{717int ret = -EINVAL;718if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {719if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {720*pix = ccdc_raw_bayer_pix_formats[i];721ret = 0;722}723} else {724if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {725*pix = ccdc_raw_yuv_pix_formats[i];726ret = 0;727}728}729return ret;730}731732static int ccdc_set_pixel_format(u32 pixfmt)733{734if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {735ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;736if (pixfmt == V4L2_PIX_FMT_SBGGR8)737ccdc_cfg.bayer.config_params.alaw.enable = 1;738else if (pixfmt != V4L2_PIX_FMT_SBGGR16)739return -EINVAL;740} else {741if (pixfmt == V4L2_PIX_FMT_YUYV)742ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;743else if (pixfmt == V4L2_PIX_FMT_UYVY)744ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;745else746return -EINVAL;747}748return 0;749}750751static u32 ccdc_get_pixel_format(void)752{753struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;754u32 pixfmt;755756if (ccdc_cfg.if_type == VPFE_RAW_BAYER)757if (alaw->enable)758pixfmt = V4L2_PIX_FMT_SBGGR8;759else760pixfmt = V4L2_PIX_FMT_SBGGR16;761else {762if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)763pixfmt = V4L2_PIX_FMT_YUYV;764else765pixfmt = V4L2_PIX_FMT_UYVY;766}767return pixfmt;768}769770static int ccdc_set_image_window(struct v4l2_rect *win)771{772if (ccdc_cfg.if_type == VPFE_RAW_BAYER)773ccdc_cfg.bayer.win = *win;774else775ccdc_cfg.ycbcr.win = *win;776return 0;777}778779static void ccdc_get_image_window(struct v4l2_rect *win)780{781if (ccdc_cfg.if_type == VPFE_RAW_BAYER)782*win = ccdc_cfg.bayer.win;783else784*win = ccdc_cfg.ycbcr.win;785}786787static unsigned int ccdc_get_line_length(void)788{789struct ccdc_config_params_raw *config_params =790&ccdc_cfg.bayer.config_params;791unsigned int len;792793if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {794if ((config_params->alaw.enable) ||795(config_params->data_sz == CCDC_DATA_8BITS))796len = ccdc_cfg.bayer.win.width;797else798len = ccdc_cfg.bayer.win.width * 2;799} else800len = ccdc_cfg.ycbcr.win.width * 2;801return ALIGN(len, 32);802}803804static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)805{806if (ccdc_cfg.if_type == VPFE_RAW_BAYER)807ccdc_cfg.bayer.frm_fmt = frm_fmt;808else809ccdc_cfg.ycbcr.frm_fmt = frm_fmt;810return 0;811}812813static enum ccdc_frmfmt ccdc_get_frame_format(void)814{815if (ccdc_cfg.if_type == VPFE_RAW_BAYER)816return ccdc_cfg.bayer.frm_fmt;817else818return ccdc_cfg.ycbcr.frm_fmt;819}820821static int ccdc_getfid(void)822{823return (regr(CCDC_SYN_MODE) >> 15) & 1;824}825826/* misc operations */827static inline void ccdc_setfbaddr(unsigned long addr)828{829regw(addr & 0xffffffe0, CCDC_SDR_ADDR);830}831832static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)833{834ccdc_cfg.if_type = params->if_type;835836switch (params->if_type) {837case VPFE_BT656:838case VPFE_YCBCR_SYNC_16:839case VPFE_YCBCR_SYNC_8:840case VPFE_BT656_10BIT:841ccdc_cfg.ycbcr.vd_pol = params->vdpol;842ccdc_cfg.ycbcr.hd_pol = params->hdpol;843break;844default:845/* TODO add support for raw bayer here */846return -EINVAL;847}848return 0;849}850851static void ccdc_save_context(void)852{853ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);854ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);855ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);856ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);857ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);858ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);859ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);860ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);861ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);862ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);863ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);864ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);865ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);866ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);867ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);868ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);869ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);870ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);871ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);872ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);873ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);874ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);875ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);876ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);877ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);878ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);879ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);880ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);881ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);882ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);883ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);884ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);885ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);886ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);887ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);888ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);889ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);890}891892static void ccdc_restore_context(void)893{894regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);895regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);896regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);897regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);898regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);899regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);900regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);901regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);902regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);903regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);904regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);905regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);906regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);907regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);908regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);909regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);910regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);911regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);912regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);913regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);914regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);915regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);916regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);917regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);918regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);919regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);920regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);921regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);922regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);923regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);924regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);925regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);926regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);927regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);928regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);929regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);930regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);931}932static struct ccdc_hw_device ccdc_hw_dev = {933.name = "DM6446 CCDC",934.owner = THIS_MODULE,935.hw_ops = {936.open = ccdc_open,937.close = ccdc_close,938.reset = ccdc_sbl_reset,939.enable = ccdc_enable,940.set_hw_if_params = ccdc_set_hw_if_params,941.set_params = ccdc_set_params,942.configure = ccdc_configure,943.set_buftype = ccdc_set_buftype,944.get_buftype = ccdc_get_buftype,945.enum_pix = ccdc_enum_pix,946.set_pixel_format = ccdc_set_pixel_format,947.get_pixel_format = ccdc_get_pixel_format,948.set_frame_format = ccdc_set_frame_format,949.get_frame_format = ccdc_get_frame_format,950.set_image_window = ccdc_set_image_window,951.get_image_window = ccdc_get_image_window,952.get_line_length = ccdc_get_line_length,953.setfbaddr = ccdc_setfbaddr,954.getfid = ccdc_getfid,955},956};957958static int __init dm644x_ccdc_probe(struct platform_device *pdev)959{960struct resource *res;961int status = 0;962963/*964* first try to register with vpfe. If not correct platform, then we965* don't have to iomap966*/967status = vpfe_register_ccdc_device(&ccdc_hw_dev);968if (status < 0)969return status;970971res = platform_get_resource(pdev, IORESOURCE_MEM, 0);972if (!res) {973status = -ENODEV;974goto fail_nores;975}976977res = request_mem_region(res->start, resource_size(res), res->name);978if (!res) {979status = -EBUSY;980goto fail_nores;981}982983ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));984if (!ccdc_cfg.base_addr) {985status = -ENOMEM;986goto fail_nomem;987}988989/* Get and enable Master clock */990ccdc_cfg.mclk = clk_get(&pdev->dev, "master");991if (IS_ERR(ccdc_cfg.mclk)) {992status = PTR_ERR(ccdc_cfg.mclk);993goto fail_nomap;994}995if (clk_enable(ccdc_cfg.mclk)) {996status = -ENODEV;997goto fail_mclk;998}9991000/* Get and enable Slave clock */1001ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");1002if (IS_ERR(ccdc_cfg.sclk)) {1003status = PTR_ERR(ccdc_cfg.sclk);1004goto fail_mclk;1005}1006if (clk_enable(ccdc_cfg.sclk)) {1007status = -ENODEV;1008goto fail_sclk;1009}1010ccdc_cfg.dev = &pdev->dev;1011printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);1012return 0;1013fail_sclk:1014clk_put(ccdc_cfg.sclk);1015fail_mclk:1016clk_put(ccdc_cfg.mclk);1017fail_nomap:1018iounmap(ccdc_cfg.base_addr);1019fail_nomem:1020release_mem_region(res->start, resource_size(res));1021fail_nores:1022vpfe_unregister_ccdc_device(&ccdc_hw_dev);1023return status;1024}10251026static int dm644x_ccdc_remove(struct platform_device *pdev)1027{1028struct resource *res;10291030clk_put(ccdc_cfg.mclk);1031clk_put(ccdc_cfg.sclk);1032iounmap(ccdc_cfg.base_addr);1033res = platform_get_resource(pdev, IORESOURCE_MEM, 0);1034if (res)1035release_mem_region(res->start, resource_size(res));1036vpfe_unregister_ccdc_device(&ccdc_hw_dev);1037return 0;1038}10391040static int dm644x_ccdc_suspend(struct device *dev)1041{1042/* Save CCDC context */1043ccdc_save_context();1044/* Disable CCDC */1045ccdc_enable(0);1046/* Disable both master and slave clock */1047clk_disable(ccdc_cfg.mclk);1048clk_disable(ccdc_cfg.sclk);10491050return 0;1051}10521053static int dm644x_ccdc_resume(struct device *dev)1054{1055/* Enable both master and slave clock */1056clk_enable(ccdc_cfg.mclk);1057clk_enable(ccdc_cfg.sclk);1058/* Restore CCDC context */1059ccdc_restore_context();10601061return 0;1062}10631064static const struct dev_pm_ops dm644x_ccdc_pm_ops = {1065.suspend = dm644x_ccdc_suspend,1066.resume = dm644x_ccdc_resume,1067};10681069static struct platform_driver dm644x_ccdc_driver = {1070.driver = {1071.name = "dm644x_ccdc",1072.owner = THIS_MODULE,1073.pm = &dm644x_ccdc_pm_ops,1074},1075.remove = __devexit_p(dm644x_ccdc_remove),1076.probe = dm644x_ccdc_probe,1077};10781079static int __init dm644x_ccdc_init(void)1080{1081return platform_driver_register(&dm644x_ccdc_driver);1082}10831084static void __exit dm644x_ccdc_exit(void)1085{1086platform_driver_unregister(&dm644x_ccdc_driver);1087}10881089module_init(dm644x_ccdc_init);1090module_exit(dm644x_ccdc_exit);109110921093