dm644x_ccdc.c 25.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * 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.
 *
 * 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
20 21 22
 * pre-process the Raw Bayer RGB data, before writing it to SDRAM.
 * This file is named DM644x so that other variants such DM6443
 * may be supported using the same module.
23 24 25 26 27 28 29 30 31
 *
 * 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>
32
#include <linux/gfp.h>
33
#include <linux/err.h>
34
#include <linux/module.h>
35

36 37
#include <media/davinci/dm644x_ccdc.h>
#include <media/davinci/vpss.h>
38

39 40 41 42 43 44 45
#include "dm644x_ccdc_regs.h"
#include "ccdc_hw_device.h"

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CCDC Driver for DM6446");
MODULE_AUTHOR("Texas Instruments");

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
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;
	/* 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
79 80 81 82 83 84 85 86 87 88 89 90 91
	},
};

#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};

92 93 94
/* CCDC Save/Restore context */
static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];

95 96 97
/* register access routines */
static inline u32 regr(u32 offset)
{
98
	return __raw_readl(ccdc_cfg.base_addr + offset);
99 100 101 102
}

static inline void regw(u32 val, u32 offset)
{
103
	__raw_writel(val, ccdc_cfg.base_addr + offset);
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
}

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
 */
125 126 127
static void ccdc_setwin(struct v4l2_rect *image_win,
			enum ccdc_frmfmt frm_fmt,
			int ppc)
128 129 130 131 132
{
	int horz_start, horz_nr_pixels;
	int vert_start, vert_nr_lines;
	int val = 0, mid_img = 0;

133
	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	/*
	 * 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);
172
	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
173 174 175 176 177 178 179
}

static void ccdc_readregs(void)
{
	unsigned int val = 0;

	val = regr(CCDC_ALAW);
180
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val);
181
	val = regr(CCDC_CLAMP);
182
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val);
183
	val = regr(CCDC_DCSUB);
184
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val);
185
	val = regr(CCDC_BLKCMP);
186
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val);
187
	val = regr(CCDC_FPC_ADDR);
188
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val);
189
	val = regr(CCDC_FPC);
190
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val);
191
	val = regr(CCDC_FMTCFG);
192
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val);
193
	val = regr(CCDC_COLPTN);
194
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val);
195
	val = regr(CCDC_FMT_HORZ);
196
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val);
197
	val = regr(CCDC_FMT_VERT);
198
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val);
199
	val = regr(CCDC_HSIZE_OFF);
200
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val);
201
	val = regr(CCDC_SDOFST);
202
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val);
203
	val = regr(CCDC_VP_OUT);
204
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val);
205
	val = regr(CCDC_SYN_MODE);
206
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val);
207
	val = regr(CCDC_HORZ_INFO);
208
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val);
209
	val = regr(CCDC_VERT_START);
210
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val);
211
	val = regr(CCDC_VERT_LINES);
212
	dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val);
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
}

static int ccdc_close(struct device *dev)
{
	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();
240
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
241 242 243 244 245 246 247 248 249 250 251 252 253
		ccdc_enable_vport(1);
	return 0;
}

static void ccdc_sbl_reset(void)
{
	vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
}

/*
 * ccdc_config_ycbcr()
 * This function will configure CCDC for YCbCr video capture
 */
254
static void ccdc_config_ycbcr(void)
255
{
256
	struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
257 258
	u32 syn_mode;

259
	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
	/*
	 * 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
		 */
286 287 288 289 290
		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;
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	} 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(&params->win, params->frm_fmt, 2);

	/*
	 * configure the order of y cb cr in SDRAM, and disable latch
	 * internal register on vsync
	 */
309 310 311 312 313 314 315
	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);
316 317 318

	/*
	 * configure the horizontal line offset. This should be a
L
Lucas De Marchi 已提交
319
	 * on 32 byte boundary. So clear LSB 5 bits
320 321 322 323 324 325 326 327 328
	 */
	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();
329
	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
330 331 332 333 334 335 336 337 338 339
}

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);
340
		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val);
341
		regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP);
342
		dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n");
343 344 345 346 347 348 349 350 351 352 353 354 355 356
		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);
357
	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
358 359
	/* If Black clamping is enable then make dcsub 0 */
	regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
360
	dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
}

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);
}

/*
 * ccdc_config_raw()
 * This function will configure CCDC for Raw capture mode
 */
381
static void ccdc_config_raw(void)
382
{
383
	struct ccdc_params_raw *params = &ccdc_cfg.bayer;
384
	struct ccdc_config_params_raw *config_params =
385
				&ccdc_cfg.bayer.config_params;
386 387 388
	unsigned int syn_mode = 0;
	unsigned int val;

389
	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415

	/*      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) {
416 417
		val = ((config_params->alaw.gamma_wd &
		      CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE);
418
		regw(val, CCDC_ALAW);
419
		dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	}

	/* Configure video window */
	ccdc_setwin(&params->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);

	/* 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;

	/* disable video port */
	val = CCDC_DISABLE_VIDEO_PORT;

	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);

448
	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
449 450 451
	/* Configure the color pattern according to mt9t001 sensor */
	regw(CCDC_COLPTN_VAL, CCDC_COLPTN);

452
	dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
453 454 455 456 457 458 459 460 461
	/*
	 * 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);

462
	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
463 464 465 466 467 468 469
	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;

470
	dev_dbg(ccdc_cfg.dev, "\nparams->win.height  0x%x ...\n",
471 472 473
	       params->win.height);
	regw(val, CCDC_FMT_VERT);

474
	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val);
475

476
	dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)...");
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496

	/*
	 * 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);
497
			dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
498 499 500 501 502
		}

		else {
			/* For intelace non inverse mode */
			regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
503
			dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
504 505 506
		}
	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
		regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
507
		dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
	}

	/*
	 * 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);

528
	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val);
529
	regw(syn_mode, CCDC_SYN_MODE);
530
	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode);
531 532

	ccdc_sbl_reset();
533
	dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
534 535 536 537 538
	ccdc_readregs();
}

static int ccdc_configure(void)
{
539
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
540 541 542 543 544 545 546 547
		ccdc_config_raw();
	else
		ccdc_config_ycbcr();
	return 0;
}

static int ccdc_set_buftype(enum ccdc_buftype buf_type)
{
548 549
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
		ccdc_cfg.bayer.buf_type = buf_type;
550
	else
551
		ccdc_cfg.ycbcr.buf_type = buf_type;
552 553 554 555 556
	return 0;
}

static enum ccdc_buftype ccdc_get_buftype(void)
{
557 558 559
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
		return ccdc_cfg.bayer.buf_type;
	return ccdc_cfg.ycbcr.buf_type;
560 561 562 563 564
}

static int ccdc_enum_pix(u32 *pix, int i)
{
	int ret = -EINVAL;
565
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
		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)
{
581 582
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
		ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
583
		if (pixfmt == V4L2_PIX_FMT_SBGGR8)
584
			ccdc_cfg.bayer.config_params.alaw.enable = 1;
585 586 587 588
		else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
			return -EINVAL;
	} else {
		if (pixfmt == V4L2_PIX_FMT_YUYV)
589
			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
590
		else if (pixfmt == V4L2_PIX_FMT_UYVY)
591
			ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
592 593 594 595 596 597 598 599
		else
			return -EINVAL;
	}
	return 0;
}

static u32 ccdc_get_pixel_format(void)
{
600
	struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
601 602
	u32 pixfmt;

603
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
604 605 606 607 608
		if (alaw->enable)
			pixfmt = V4L2_PIX_FMT_SBGGR8;
		else
			pixfmt = V4L2_PIX_FMT_SBGGR16;
	else {
609
		if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
610 611 612 613 614 615 616 617 618
			pixfmt = V4L2_PIX_FMT_YUYV;
		else
			pixfmt = V4L2_PIX_FMT_UYVY;
	}
	return pixfmt;
}

static int ccdc_set_image_window(struct v4l2_rect *win)
{
619 620
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
		ccdc_cfg.bayer.win = *win;
621
	else
622
		ccdc_cfg.ycbcr.win = *win;
623 624 625 626 627
	return 0;
}

static void ccdc_get_image_window(struct v4l2_rect *win)
{
628 629
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
		*win = ccdc_cfg.bayer.win;
630
	else
631
		*win = ccdc_cfg.ycbcr.win;
632 633 634 635 636
}

static unsigned int ccdc_get_line_length(void)
{
	struct ccdc_config_params_raw *config_params =
637
				&ccdc_cfg.bayer.config_params;
638 639
	unsigned int len;

640
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
641 642
		if ((config_params->alaw.enable) ||
		    (config_params->data_sz == CCDC_DATA_8BITS))
643
			len = ccdc_cfg.bayer.win.width;
644
		else
645
			len = ccdc_cfg.bayer.win.width * 2;
646
	} else
647
		len = ccdc_cfg.ycbcr.win.width * 2;
648 649 650 651 652
	return ALIGN(len, 32);
}

static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
{
653 654
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
		ccdc_cfg.bayer.frm_fmt = frm_fmt;
655
	else
656
		ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
657 658 659 660 661
	return 0;
}

static enum ccdc_frmfmt ccdc_get_frame_format(void)
{
662 663
	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
		return ccdc_cfg.bayer.frm_fmt;
664
	else
665
		return ccdc_cfg.ycbcr.frm_fmt;
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
}

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)
{
681
	ccdc_cfg.if_type = params->if_type;
682 683 684 685 686

	switch (params->if_type) {
	case VPFE_BT656:
	case VPFE_YCBCR_SYNC_16:
	case VPFE_YCBCR_SYNC_8:
687
	case VPFE_BT656_10BIT:
688 689
		ccdc_cfg.ycbcr.vd_pol = params->vdpol;
		ccdc_cfg.ycbcr.hd_pol = params->hdpol;
690 691 692 693 694 695 696 697
		break;
	default:
		/* TODO add support for raw bayer here */
		return -EINVAL;
	}
	return 0;
}

698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
static void ccdc_save_context(void)
{
	ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);
	ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);
	ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);
	ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);
	ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);
	ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);
	ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);
	ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);
	ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);
	ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);
	ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);
	ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);
	ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);
	ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);
	ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);
	ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);
	ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);
	ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);
	ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);
	ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);
	ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);
	ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);
	ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);
	ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);
	ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);
	ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);
	ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);
	ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);
	ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);
	ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);
	ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);
	ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);
	ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);
	ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);
	ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);
	ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);
	ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);
}

static void ccdc_restore_context(void)
{
	regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);
	regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);
	regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);
	regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);
	regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);
	regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);
	regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);
	regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);
	regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);
	regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);
	regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);
	regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);
	regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);
	regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);
	regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);
	regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);
	regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);
	regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);
	regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);
	regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);
	regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);
	regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);
	regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);
	regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);
	regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);
	regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);
	regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);
	regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);
	regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);
	regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);
	regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);
	regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);
	regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);
	regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);
	regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);
	regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);
	regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);
}
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
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,
		.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,
	},
};

804
static int dm644x_ccdc_probe(struct platform_device *pdev)
805
{
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
	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;
	}

	ccdc_cfg.dev = &pdev->dev;
	printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
837
	return 0;
838 839 840 841 842
fail_nomem:
	release_mem_region(res->start, resource_size(res));
fail_nores:
	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
	return status;
843 844
}

845
static int dm644x_ccdc_remove(struct platform_device *pdev)
846
{
847 848 849 850 851 852
	struct resource	*res;

	iounmap(ccdc_cfg.base_addr);
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res)
		release_mem_region(res->start, resource_size(res));
853
	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
854 855 856
	return 0;
}

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
static int dm644x_ccdc_suspend(struct device *dev)
{
	/* Save CCDC context */
	ccdc_save_context();
	/* Disable CCDC */
	ccdc_enable(0);

	return 0;
}

static int dm644x_ccdc_resume(struct device *dev)
{
	/* Restore CCDC context */
	ccdc_restore_context();

	return 0;
}

static const struct dev_pm_ops dm644x_ccdc_pm_ops = {
	.suspend = dm644x_ccdc_suspend,
	.resume = dm644x_ccdc_resume,
};

880
static struct platform_driver dm644x_ccdc_driver = {
881 882
	.driver = {
		.name	= "dm644x_ccdc",
883
		.pm = &dm644x_ccdc_pm_ops,
884
	},
885
	.remove = dm644x_ccdc_remove,
886 887 888
	.probe = dm644x_ccdc_probe,
};

889
module_platform_driver(dm644x_ccdc_driver);