cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dm355_ccdc.c (25199B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2005-2009 Texas Instruments Inc
      4 *
      5 * CCDC hardware module for DM355
      6 * ------------------------------
      7 *
      8 * This module is for configuring DM355 CCD controller of VPFE to capture
      9 * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
     10 * such as Defect Pixel Correction, Color Space Conversion etc to
     11 * pre-process the Bayer RGB data, before writing it to SDRAM.
     12 *
     13 * TODO: 1) Raw bayer parameter settings and bayer capture
     14 *	 2) Split module parameter structure to module specific ioctl structs
     15 *	 3) add support for lense shading correction
     16 *	 4) investigate if enum used for user space type definition
     17 *	    to be replaced by #defines or integer
     18 */
     19#include <linux/platform_device.h>
     20#include <linux/uaccess.h>
     21#include <linux/videodev2.h>
     22#include <linux/err.h>
     23#include <linux/module.h>
     24
     25#include <media/davinci/dm355_ccdc.h>
     26#include <media/davinci/vpss.h>
     27
     28#include "dm355_ccdc_regs.h"
     29#include "ccdc_hw_device.h"
     30
     31MODULE_LICENSE("GPL");
     32MODULE_DESCRIPTION("CCDC Driver for DM355");
     33MODULE_AUTHOR("Texas Instruments");
     34
     35static struct ccdc_oper_config {
     36	struct device *dev;
     37	/* CCDC interface type */
     38	enum vpfe_hw_if_type if_type;
     39	/* Raw Bayer configuration */
     40	struct ccdc_params_raw bayer;
     41	/* YCbCr configuration */
     42	struct ccdc_params_ycbcr ycbcr;
     43	/* ccdc base address */
     44	void __iomem *base_addr;
     45} ccdc_cfg = {
     46	/* Raw configurations */
     47	.bayer = {
     48		.pix_fmt = CCDC_PIXFMT_RAW,
     49		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
     50		.win = CCDC_WIN_VGA,
     51		.fid_pol = VPFE_PINPOL_POSITIVE,
     52		.vd_pol = VPFE_PINPOL_POSITIVE,
     53		.hd_pol = VPFE_PINPOL_POSITIVE,
     54		.gain = {
     55			.r_ye = 256,
     56			.gb_g = 256,
     57			.gr_cy = 256,
     58			.b_mg = 256
     59		},
     60		.config_params = {
     61			.datasft = 2,
     62			.mfilt1 = CCDC_NO_MEDIAN_FILTER1,
     63			.mfilt2 = CCDC_NO_MEDIAN_FILTER2,
     64			.alaw = {
     65				.gamma_wd = 2,
     66			},
     67			.blk_clamp = {
     68				.sample_pixel = 1,
     69				.dc_sub = 25
     70			},
     71			.col_pat_field0 = {
     72				.olop = CCDC_GREEN_BLUE,
     73				.olep = CCDC_BLUE,
     74				.elop = CCDC_RED,
     75				.elep = CCDC_GREEN_RED
     76			},
     77			.col_pat_field1 = {
     78				.olop = CCDC_GREEN_BLUE,
     79				.olep = CCDC_BLUE,
     80				.elop = CCDC_RED,
     81				.elep = CCDC_GREEN_RED
     82			},
     83		},
     84	},
     85	/* YCbCr configuration */
     86	.ycbcr = {
     87		.win = CCDC_WIN_PAL,
     88		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
     89		.frm_fmt = CCDC_FRMFMT_INTERLACED,
     90		.fid_pol = VPFE_PINPOL_POSITIVE,
     91		.vd_pol = VPFE_PINPOL_POSITIVE,
     92		.hd_pol = VPFE_PINPOL_POSITIVE,
     93		.bt656_enable = 1,
     94		.pix_order = CCDC_PIXORDER_CBYCRY,
     95		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
     96	},
     97};
     98
     99
    100/* Raw Bayer formats */
    101static u32 ccdc_raw_bayer_pix_formats[] =
    102		{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
    103
    104/* Raw YUV formats */
    105static u32 ccdc_raw_yuv_pix_formats[] =
    106		{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
    107
    108/* register access routines */
    109static inline u32 regr(u32 offset)
    110{
    111	return __raw_readl(ccdc_cfg.base_addr + offset);
    112}
    113
    114static inline void regw(u32 val, u32 offset)
    115{
    116	__raw_writel(val, ccdc_cfg.base_addr + offset);
    117}
    118
    119static void ccdc_enable(int en)
    120{
    121	unsigned int temp;
    122	temp = regr(SYNCEN);
    123	temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
    124	temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
    125	regw(temp, SYNCEN);
    126}
    127
    128static void ccdc_enable_output_to_sdram(int en)
    129{
    130	unsigned int temp;
    131	temp = regr(SYNCEN);
    132	temp &= (~(CCDC_SYNCEN_WEN_MASK));
    133	temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
    134	regw(temp, SYNCEN);
    135}
    136
    137static void ccdc_config_gain_offset(void)
    138{
    139	/* configure gain */
    140	regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN);
    141	regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN);
    142	regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN);
    143	regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN);
    144	/* configure offset */
    145	regw(ccdc_cfg.bayer.ccdc_offset, OFFSET);
    146}
    147
    148/*
    149 * ccdc_restore_defaults()
    150 * This function restore power on defaults in the ccdc registers
    151 */
    152static int ccdc_restore_defaults(void)
    153{
    154	int i;
    155
    156	dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults...");
    157	/* set all registers to zero */
    158	for (i = 0; i <= CCDC_REG_LAST; i += 4)
    159		regw(0, i);
    160
    161	/* now override the values with power on defaults in registers */
    162	regw(MODESET_DEFAULT, MODESET);
    163	/* no culling support */
    164	regw(CULH_DEFAULT, CULH);
    165	regw(CULV_DEFAULT, CULV);
    166	/* Set default Gain and Offset */
    167	ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT;
    168	ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT;
    169	ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT;
    170	ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT;
    171	ccdc_config_gain_offset();
    172	regw(OUTCLIP_DEFAULT, OUTCLIP);
    173	regw(LSCCFG2_DEFAULT, LSCCFG2);
    174	/* select ccdc input */
    175	if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
    176		dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source");
    177		return -EFAULT;
    178	}
    179	/* select ccdc clock */
    180	if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
    181		dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock");
    182		return -EFAULT;
    183	}
    184	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults...");
    185	return 0;
    186}
    187
    188static int ccdc_open(struct device *device)
    189{
    190	return ccdc_restore_defaults();
    191}
    192
    193static int ccdc_close(struct device *device)
    194{
    195	/* disable clock */
    196	vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
    197	/* do nothing for now */
    198	return 0;
    199}
    200/*
    201 * ccdc_setwin()
    202 * This function will configure the window size to
    203 * be capture in CCDC reg.
    204 */
    205static void ccdc_setwin(struct v4l2_rect *image_win,
    206			enum ccdc_frmfmt frm_fmt, int ppc)
    207{
    208	int horz_start, horz_nr_pixels;
    209	int vert_start, vert_nr_lines;
    210	int mid_img = 0;
    211
    212	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
    213
    214	/*
    215	 * ppc - per pixel count. indicates how many pixels per cell
    216	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
    217	 * raw capture this is 1
    218	 */
    219	horz_start = image_win->left << (ppc - 1);
    220	horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
    221
    222	/* Writing the horizontal info into the registers */
    223	regw(horz_start, SPH);
    224	regw(horz_nr_pixels, NPH);
    225	vert_start = image_win->top;
    226
    227	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
    228		vert_nr_lines = (image_win->height >> 1) - 1;
    229		vert_start >>= 1;
    230		/* Since first line doesn't have any data */
    231		vert_start += 1;
    232		/* configure VDINT0 and VDINT1 */
    233		regw(vert_start, VDINT0);
    234	} else {
    235		/* Since first line doesn't have any data */
    236		vert_start += 1;
    237		vert_nr_lines = image_win->height - 1;
    238		/* configure VDINT0 and VDINT1 */
    239		mid_img = vert_start + (image_win->height / 2);
    240		regw(vert_start, VDINT0);
    241		regw(mid_img, VDINT1);
    242	}
    243	regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
    244	regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
    245	regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
    246	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
    247}
    248
    249/* This function will configure CCDC for YCbCr video capture */
    250static void ccdc_config_ycbcr(void)
    251{
    252	struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
    253	u32 temp;
    254
    255	/* first set the CCDC power on defaults values in all registers */
    256	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
    257	ccdc_restore_defaults();
    258
    259	/* configure pixel format & video frame format */
    260	temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
    261		CCDC_INPUT_MODE_SHIFT) |
    262		((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
    263		CCDC_FRM_FMT_SHIFT));
    264
    265	/* setup BT.656 sync mode */
    266	if (params->bt656_enable) {
    267		regw(CCDC_REC656IF_BT656_EN, REC656IF);
    268		/*
    269		 * configure the FID, VD, HD pin polarity fld,hd pol positive,
    270		 * vd negative, 8-bit pack mode
    271		 */
    272		temp |= CCDC_VD_POL_NEGATIVE;
    273	} else {		/* y/c external sync mode */
    274		temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
    275			CCDC_FID_POL_SHIFT) |
    276			((params->hd_pol & CCDC_HD_POL_MASK) <<
    277			CCDC_HD_POL_SHIFT) |
    278			((params->vd_pol & CCDC_VD_POL_MASK) <<
    279			CCDC_VD_POL_SHIFT));
    280	}
    281
    282	/* pack the data to 8-bit */
    283	temp |= CCDC_DATA_PACK_ENABLE;
    284
    285	regw(temp, MODESET);
    286
    287	/* configure video window */
    288	ccdc_setwin(&params->win, params->frm_fmt, 2);
    289
    290	/* configure the order of y cb cr in SD-RAM */
    291	temp = (params->pix_order << CCDC_Y8POS_SHIFT);
    292	temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
    293	regw(temp, CCDCFG);
    294
    295	/*
    296	 * configure the horizontal line offset. This is done by rounding up
    297	 * width to a multiple of 16 pixels and multiply by two to account for
    298	 * y:cb:cr 4:2:2 data
    299	 */
    300	regw(((params->win.width * 2 + 31) >> 5), HSIZE);
    301
    302	/* configure the memory line offset */
    303	if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
    304		/* two fields are interleaved in memory */
    305		regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
    306	}
    307
    308	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
    309}
    310
    311/*
    312 * ccdc_config_black_clamp()
    313 * configure parameters for Optical Black Clamp
    314 */
    315static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
    316{
    317	u32 val;
    318
    319	if (!bclamp->b_clamp_enable) {
    320		/* configure DCSub */
    321		regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
    322		regw(0x0000, CLAMP);
    323		return;
    324	}
    325	/* Enable the Black clamping, set sample lines and pixels */
    326	val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
    327	      ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
    328		CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
    329	regw(val, CLAMP);
    330
    331	/* If Black clamping is enable then make dcsub 0 */
    332	val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
    333			<< CCDC_NUM_LINE_CALC_SHIFT;
    334	regw(val, DCSUB);
    335}
    336
    337/*
    338 * ccdc_config_black_compense()
    339 * configure parameters for Black Compensation
    340 */
    341static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
    342{
    343	u32 val;
    344
    345	val = (bcomp->b & CCDC_BLK_COMP_MASK) |
    346		((bcomp->gb & CCDC_BLK_COMP_MASK) <<
    347		CCDC_BLK_COMP_GB_COMP_SHIFT);
    348	regw(val, BLKCMP1);
    349
    350	val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
    351		CCDC_BLK_COMP_GR_COMP_SHIFT) |
    352		((bcomp->r & CCDC_BLK_COMP_MASK) <<
    353		CCDC_BLK_COMP_R_COMP_SHIFT);
    354	regw(val, BLKCMP0);
    355}
    356
    357/*
    358 * ccdc_write_dfc_entry()
    359 * write an entry in the dfc table.
    360 */
    361static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
    362{
    363/* TODO This is to be re-visited and adjusted */
    364#define DFC_WRITE_WAIT_COUNT	1000
    365	u32 val, count = DFC_WRITE_WAIT_COUNT;
    366
    367	regw(dfc->dft_corr_vert[index], DFCMEM0);
    368	regw(dfc->dft_corr_horz[index], DFCMEM1);
    369	regw(dfc->dft_corr_sub1[index], DFCMEM2);
    370	regw(dfc->dft_corr_sub2[index], DFCMEM3);
    371	regw(dfc->dft_corr_sub3[index], DFCMEM4);
    372	/* set WR bit to write */
    373	val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
    374	regw(val, DFCMEMCTL);
    375
    376	/*
    377	 * Assume, it is very short. If we get an error, we need to
    378	 * adjust this value
    379	 */
    380	while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
    381		count--;
    382	/*
    383	 * TODO We expect the count to be non-zero to be successful. Adjust
    384	 * the count if write requires more time
    385	 */
    386
    387	if (count) {
    388		dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n");
    389		return -1;
    390	}
    391	return 0;
    392}
    393
    394/*
    395 * ccdc_config_vdfc()
    396 * configure parameters for Vertical Defect Correction
    397 */
    398static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
    399{
    400	u32 val;
    401	int i;
    402
    403	/* Configure General Defect Correction. The table used is from IPIPE */
    404	val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
    405
    406	/* Configure Vertical Defect Correction if needed */
    407	if (!dfc->ver_dft_en) {
    408		/* Enable only General Defect Correction */
    409		regw(val, DFCCTL);
    410		return 0;
    411	}
    412
    413	if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
    414		return -EINVAL;
    415
    416	val |= CCDC_DFCCTL_VDFC_DISABLE;
    417	val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
    418		CCDC_DFCCTL_VDFCSL_SHIFT;
    419	val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
    420		CCDC_DFCCTL_VDFCUDA_SHIFT;
    421	val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
    422		CCDC_DFCCTL_VDFLSFT_SHIFT;
    423	regw(val , DFCCTL);
    424
    425	/* clear address ptr to offset 0 */
    426	val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
    427
    428	/* write defect table entries */
    429	for (i = 0; i < dfc->table_size; i++) {
    430		/* increment address for non zero index */
    431		if (i != 0)
    432			val = CCDC_DFCMEMCTL_INC_ADDR;
    433		regw(val, DFCMEMCTL);
    434		if (ccdc_write_dfc_entry(i, dfc) < 0)
    435			return -EFAULT;
    436	}
    437
    438	/* update saturation level and enable dfc */
    439	regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
    440	val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
    441			CCDC_DFCCTL_VDFCEN_SHIFT);
    442	regw(val, DFCCTL);
    443	return 0;
    444}
    445
    446/*
    447 * ccdc_config_csc()
    448 * configure parameters for color space conversion
    449 * Each register CSCM0-7 has two values in S8Q5 format.
    450 */
    451static void ccdc_config_csc(struct ccdc_csc *csc)
    452{
    453	u32 val1 = 0, val2;
    454	int i;
    455
    456	if (!csc->enable)
    457		return;
    458
    459	/* Enable the CSC sub-module */
    460	regw(CCDC_CSC_ENABLE, CSCCTL);
    461
    462	/* Converting the co-eff as per the format of the register */
    463	for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
    464		if ((i % 2) == 0) {
    465			/* CSCM - LSB */
    466			val1 = (csc->coeff[i].integer &
    467				CCDC_CSC_COEF_INTEG_MASK)
    468				<< CCDC_CSC_COEF_INTEG_SHIFT;
    469			/*
    470			 * convert decimal part to binary. Use 2 decimal
    471			 * precision, user values range from .00 - 0.99
    472			 */
    473			val1 |= (((csc->coeff[i].decimal &
    474				CCDC_CSC_COEF_DECIMAL_MASK) *
    475				CCDC_CSC_DEC_MAX) / 100);
    476		} else {
    477
    478			/* CSCM - MSB */
    479			val2 = (csc->coeff[i].integer &
    480				CCDC_CSC_COEF_INTEG_MASK)
    481				<< CCDC_CSC_COEF_INTEG_SHIFT;
    482			val2 |= (((csc->coeff[i].decimal &
    483				 CCDC_CSC_COEF_DECIMAL_MASK) *
    484				 CCDC_CSC_DEC_MAX) / 100);
    485			val2 <<= CCDC_CSCM_MSB_SHIFT;
    486			val2 |= val1;
    487			regw(val2, (CSCM0 + ((i - 1) << 1)));
    488		}
    489	}
    490}
    491
    492/*
    493 * ccdc_config_color_patterns()
    494 * configure parameters for color patterns
    495 */
    496static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
    497				       struct ccdc_col_pat *pat1)
    498{
    499	u32 val;
    500
    501	val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
    502		(pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
    503		(pat1->elop << 12) | (pat1->elep << 14));
    504	regw(val, COLPTN);
    505}
    506
    507/* This function will configure CCDC for Raw mode image capture */
    508static int ccdc_config_raw(void)
    509{
    510	struct ccdc_params_raw *params = &ccdc_cfg.bayer;
    511	struct ccdc_config_params_raw *config_params =
    512					&ccdc_cfg.bayer.config_params;
    513	unsigned int val;
    514
    515	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
    516
    517	/* restore power on defaults to register */
    518	ccdc_restore_defaults();
    519
    520	/* CCDCFG register:
    521	 * set CCD Not to swap input since input is RAW data
    522	 * set FID detection function to Latch at V-Sync
    523	 * set WENLOG - ccdc valid area to AND
    524	 * set TRGSEL to WENBIT
    525	 * set EXTRG to DISABLE
    526	 * disable latching function on VSYNC - shadowed registers
    527	 */
    528	regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
    529	     CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
    530	     CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
    531
    532	/*
    533	 * Set VDHD direction to input,  input type to raw input
    534	 * normal data polarity, do not use external WEN
    535	 */
    536	val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
    537		CCDC_EXWEN_DISABLE);
    538
    539	/*
    540	 * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
    541	 * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
    542	 * frame format(progressive or interlace), & pixel format (Input mode)
    543	 */
    544	val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
    545		((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
    546		((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
    547		((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
    548		((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
    549
    550	/* set pack for alaw compression */
    551	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
    552	     config_params->alaw.enable)
    553		val |= CCDC_DATA_PACK_ENABLE;
    554
    555	/* Configure for LPF */
    556	if (config_params->lpf_enable)
    557		val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
    558			CCDC_LPF_SHIFT;
    559
    560	/* Configure the data shift */
    561	val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
    562		CCDC_DATASFT_SHIFT;
    563	regw(val , MODESET);
    564	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val);
    565
    566	/* Configure the Median Filter threshold */
    567	regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
    568
    569	/* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
    570	val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
    571		CCDC_CFA_MOSAIC;
    572
    573	/* Enable and configure aLaw register if needed */
    574	if (config_params->alaw.enable) {
    575		val |= (CCDC_ALAW_ENABLE |
    576			((config_params->alaw.gamma_wd &
    577			CCDC_ALAW_GAMMA_WD_MASK) <<
    578			CCDC_GAMMAWD_INPUT_SHIFT));
    579	}
    580
    581	/* Configure Median filter1 & filter2 */
    582	val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
    583		(config_params->mfilt2 << CCDC_MFILT2_SHIFT));
    584
    585	regw(val, GAMMAWD);
    586	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val);
    587
    588	/* configure video window */
    589	ccdc_setwin(&params->win, params->frm_fmt, 1);
    590
    591	/* Optical Clamp Averaging */
    592	ccdc_config_black_clamp(&config_params->blk_clamp);
    593
    594	/* Black level compensation */
    595	ccdc_config_black_compense(&config_params->blk_comp);
    596
    597	/* Vertical Defect Correction if needed */
    598	if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
    599		return -EFAULT;
    600
    601	/* color space conversion */
    602	ccdc_config_csc(&config_params->csc);
    603
    604	/* color pattern */
    605	ccdc_config_color_patterns(&config_params->col_pat_field0,
    606				   &config_params->col_pat_field1);
    607
    608	/* Configure the Gain  & offset control */
    609	ccdc_config_gain_offset();
    610
    611	dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val);
    612
    613	/* Configure DATAOFST  register */
    614	val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
    615		CCDC_DATAOFST_H_SHIFT;
    616	val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
    617		CCDC_DATAOFST_V_SHIFT;
    618	regw(val, DATAOFST);
    619
    620	/* configuring HSIZE register */
    621	val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
    622		CCDC_HSIZE_FLIP_SHIFT;
    623
    624	/* If pack 8 is enable then 1 pixel will take 1 byte */
    625	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
    626	     config_params->alaw.enable) {
    627		val |= (((params->win.width) + 31) >> 5) &
    628			CCDC_HSIZE_VAL_MASK;
    629
    630		/* adjust to multiple of 32 */
    631		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
    632		       (((params->win.width) + 31) >> 5) &
    633			CCDC_HSIZE_VAL_MASK);
    634	} else {
    635		/* else one pixel will take 2 byte */
    636		val |= (((params->win.width * 2) + 31) >> 5) &
    637			CCDC_HSIZE_VAL_MASK;
    638
    639		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
    640		       (((params->win.width * 2) + 31) >> 5) &
    641			CCDC_HSIZE_VAL_MASK);
    642	}
    643	regw(val, HSIZE);
    644
    645	/* Configure SDOFST register */
    646	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
    647		if (params->image_invert_enable) {
    648			/* For interlace inverse mode */
    649			regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
    650			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
    651				CCDC_SDOFST_INTERLACE_INVERSE);
    652		} else {
    653			/* For interlace non inverse mode */
    654			regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
    655			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
    656				CCDC_SDOFST_INTERLACE_NORMAL);
    657		}
    658	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
    659		if (params->image_invert_enable) {
    660			/* For progessive inverse mode */
    661			regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
    662			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
    663				CCDC_SDOFST_PROGRESSIVE_INVERSE);
    664		} else {
    665			/* For progessive non inverse mode */
    666			regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
    667			dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
    668				CCDC_SDOFST_PROGRESSIVE_NORMAL);
    669		}
    670	}
    671	dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
    672	return 0;
    673}
    674
    675static int ccdc_configure(void)
    676{
    677	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    678		return ccdc_config_raw();
    679	else
    680		ccdc_config_ycbcr();
    681	return 0;
    682}
    683
    684static int ccdc_set_buftype(enum ccdc_buftype buf_type)
    685{
    686	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    687		ccdc_cfg.bayer.buf_type = buf_type;
    688	else
    689		ccdc_cfg.ycbcr.buf_type = buf_type;
    690	return 0;
    691}
    692static enum ccdc_buftype ccdc_get_buftype(void)
    693{
    694	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    695		return ccdc_cfg.bayer.buf_type;
    696	return ccdc_cfg.ycbcr.buf_type;
    697}
    698
    699static int ccdc_enum_pix(u32 *pix, int i)
    700{
    701	int ret = -EINVAL;
    702	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
    703		if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
    704			*pix = ccdc_raw_bayer_pix_formats[i];
    705			ret = 0;
    706		}
    707	} else {
    708		if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
    709			*pix = ccdc_raw_yuv_pix_formats[i];
    710			ret = 0;
    711		}
    712	}
    713	return ret;
    714}
    715
    716static int ccdc_set_pixel_format(u32 pixfmt)
    717{
    718	struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
    719
    720	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
    721		ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
    722		if (pixfmt == V4L2_PIX_FMT_SBGGR8)
    723			alaw->enable = 1;
    724		else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
    725			return -EINVAL;
    726	} else {
    727		if (pixfmt == V4L2_PIX_FMT_YUYV)
    728			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
    729		else if (pixfmt == V4L2_PIX_FMT_UYVY)
    730			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
    731		else
    732			return -EINVAL;
    733	}
    734	return 0;
    735}
    736static u32 ccdc_get_pixel_format(void)
    737{
    738	struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
    739	u32 pixfmt;
    740
    741	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    742		if (alaw->enable)
    743			pixfmt = V4L2_PIX_FMT_SBGGR8;
    744		else
    745			pixfmt = V4L2_PIX_FMT_SBGGR16;
    746	else {
    747		if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
    748			pixfmt = V4L2_PIX_FMT_YUYV;
    749		else
    750			pixfmt = V4L2_PIX_FMT_UYVY;
    751	}
    752	return pixfmt;
    753}
    754static int ccdc_set_image_window(struct v4l2_rect *win)
    755{
    756	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    757		ccdc_cfg.bayer.win = *win;
    758	else
    759		ccdc_cfg.ycbcr.win = *win;
    760	return 0;
    761}
    762
    763static void ccdc_get_image_window(struct v4l2_rect *win)
    764{
    765	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    766		*win = ccdc_cfg.bayer.win;
    767	else
    768		*win = ccdc_cfg.ycbcr.win;
    769}
    770
    771static unsigned int ccdc_get_line_length(void)
    772{
    773	struct ccdc_config_params_raw *config_params =
    774				&ccdc_cfg.bayer.config_params;
    775	unsigned int len;
    776
    777	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
    778		if ((config_params->alaw.enable) ||
    779		    (config_params->data_sz == CCDC_DATA_8BITS))
    780			len = ccdc_cfg.bayer.win.width;
    781		else
    782			len = ccdc_cfg.bayer.win.width * 2;
    783	} else
    784		len = ccdc_cfg.ycbcr.win.width * 2;
    785	return ALIGN(len, 32);
    786}
    787
    788static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
    789{
    790	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    791		ccdc_cfg.bayer.frm_fmt = frm_fmt;
    792	else
    793		ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
    794	return 0;
    795}
    796
    797static enum ccdc_frmfmt ccdc_get_frame_format(void)
    798{
    799	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
    800		return ccdc_cfg.bayer.frm_fmt;
    801	else
    802		return ccdc_cfg.ycbcr.frm_fmt;
    803}
    804
    805static int ccdc_getfid(void)
    806{
    807	return  (regr(MODESET) >> 15) & 1;
    808}
    809
    810/* misc operations */
    811static inline void ccdc_setfbaddr(unsigned long addr)
    812{
    813	regw((addr >> 21) & 0x007f, STADRH);
    814	regw((addr >> 5) & 0x0ffff, STADRL);
    815}
    816
    817static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
    818{
    819	ccdc_cfg.if_type = params->if_type;
    820
    821	switch (params->if_type) {
    822	case VPFE_BT656:
    823	case VPFE_YCBCR_SYNC_16:
    824	case VPFE_YCBCR_SYNC_8:
    825		ccdc_cfg.ycbcr.vd_pol = params->vdpol;
    826		ccdc_cfg.ycbcr.hd_pol = params->hdpol;
    827		break;
    828	default:
    829		/* TODO add support for raw bayer here */
    830		return -EINVAL;
    831	}
    832	return 0;
    833}
    834
    835static const struct ccdc_hw_device ccdc_hw_dev = {
    836	.name = "DM355 CCDC",
    837	.owner = THIS_MODULE,
    838	.hw_ops = {
    839		.open = ccdc_open,
    840		.close = ccdc_close,
    841		.enable = ccdc_enable,
    842		.enable_out_to_sdram = ccdc_enable_output_to_sdram,
    843		.set_hw_if_params = ccdc_set_hw_if_params,
    844		.configure = ccdc_configure,
    845		.set_buftype = ccdc_set_buftype,
    846		.get_buftype = ccdc_get_buftype,
    847		.enum_pix = ccdc_enum_pix,
    848		.set_pixel_format = ccdc_set_pixel_format,
    849		.get_pixel_format = ccdc_get_pixel_format,
    850		.set_frame_format = ccdc_set_frame_format,
    851		.get_frame_format = ccdc_get_frame_format,
    852		.set_image_window = ccdc_set_image_window,
    853		.get_image_window = ccdc_get_image_window,
    854		.get_line_length = ccdc_get_line_length,
    855		.setfbaddr = ccdc_setfbaddr,
    856		.getfid = ccdc_getfid,
    857	},
    858};
    859
    860static int dm355_ccdc_probe(struct platform_device *pdev)
    861{
    862	void (*setup_pinmux)(void);
    863	struct resource	*res;
    864	int status = 0;
    865
    866	/*
    867	 * first try to register with vpfe. If not correct platform, then we
    868	 * don't have to iomap
    869	 */
    870	status = vpfe_register_ccdc_device(&ccdc_hw_dev);
    871	if (status < 0)
    872		return status;
    873
    874	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    875	if (!res) {
    876		status = -ENODEV;
    877		goto fail_nores;
    878	}
    879
    880	res = request_mem_region(res->start, resource_size(res), res->name);
    881	if (!res) {
    882		status = -EBUSY;
    883		goto fail_nores;
    884	}
    885
    886	ccdc_cfg.base_addr = ioremap(res->start, resource_size(res));
    887	if (!ccdc_cfg.base_addr) {
    888		status = -ENOMEM;
    889		goto fail_nomem;
    890	}
    891
    892	/* Platform data holds setup_pinmux function ptr */
    893	if (NULL == pdev->dev.platform_data) {
    894		status = -ENODEV;
    895		goto fail_nomap;
    896	}
    897	setup_pinmux = pdev->dev.platform_data;
    898	/*
    899	 * setup Mux configuration for ccdc which may be different for
    900	 * different SoCs using this CCDC
    901	 */
    902	setup_pinmux();
    903	ccdc_cfg.dev = &pdev->dev;
    904	printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
    905	return 0;
    906fail_nomap:
    907	iounmap(ccdc_cfg.base_addr);
    908fail_nomem:
    909	release_mem_region(res->start, resource_size(res));
    910fail_nores:
    911	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
    912	return status;
    913}
    914
    915static int dm355_ccdc_remove(struct platform_device *pdev)
    916{
    917	struct resource	*res;
    918
    919	iounmap(ccdc_cfg.base_addr);
    920	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    921	release_mem_region(res->start, resource_size(res));
    922	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
    923	return 0;
    924}
    925
    926static struct platform_driver dm355_ccdc_driver = {
    927	.driver = {
    928		.name	= "dm355_ccdc",
    929	},
    930	.remove = dm355_ccdc_remove,
    931	.probe = dm355_ccdc_probe,
    932};
    933
    934module_platform_driver(dm355_ccdc_driver);