• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006-2009 Texas Instruments Inc
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * CCDC hardware module for DM6446
15  * ------------------------------
16  *
17  * This module is for configuring CCD controller of DM6446 VPFE to capture
18  * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
19  * such as Defect Pixel Correction, Color Space Conversion etc to
20  * pre-process the Raw Bayer RGB data, before writing it to SDRAM.
21  * This file is named DM644x so that other variants such DM6443
22  * may be supported using the same module.
23  *
24  * TODO: Test Raw bayer parameter settings and bayer capture
25  *	 Split module parameter structure to module specific ioctl structs
26  *	 investigate if enum used for user space type definition
27  *	 to be replaced by #defines or integer
28  */
29 #include <linux/platform_device.h>
30 #include <linux/uaccess.h>
31 #include <linux/videodev2.h>
32 #include <linux/gfp.h>
33 #include <linux/err.h>
34 #include <linux/module.h>
35 
36 #include <media/davinci/dm644x_ccdc.h>
37 #include <media/davinci/vpss.h>
38 
39 #include "dm644x_ccdc_regs.h"
40 #include "ccdc_hw_device.h"
41 
42 MODULE_LICENSE("GPL");
43 MODULE_DESCRIPTION("CCDC Driver for DM6446");
44 MODULE_AUTHOR("Texas Instruments");
45 
46 static struct ccdc_oper_config {
47 	struct device *dev;
48 	/* CCDC interface type */
49 	enum vpfe_hw_if_type if_type;
50 	/* Raw Bayer configuration */
51 	struct ccdc_params_raw bayer;
52 	/* YCbCr configuration */
53 	struct ccdc_params_ycbcr ycbcr;
54 	/* ccdc base address */
55 	void __iomem *base_addr;
56 } ccdc_cfg = {
57 	/* Raw configurations */
58 	.bayer = {
59 		.pix_fmt = CCDC_PIXFMT_RAW,
60 		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
61 		.win = CCDC_WIN_VGA,
62 		.fid_pol = VPFE_PINPOL_POSITIVE,
63 		.vd_pol = VPFE_PINPOL_POSITIVE,
64 		.hd_pol = VPFE_PINPOL_POSITIVE,
65 		.config_params = {
66 			.data_sz = CCDC_DATA_10BITS,
67 		},
68 	},
69 	.ycbcr = {
70 		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
71 		.frm_fmt = CCDC_FRMFMT_INTERLACED,
72 		.win = CCDC_WIN_PAL,
73 		.fid_pol = VPFE_PINPOL_POSITIVE,
74 		.vd_pol = VPFE_PINPOL_POSITIVE,
75 		.hd_pol = VPFE_PINPOL_POSITIVE,
76 		.bt656_enable = 1,
77 		.pix_order = CCDC_PIXORDER_CBYCRY,
78 		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
79 	},
80 };
81 
82 #define CCDC_MAX_RAW_YUV_FORMATS	2
83 
84 /* Raw Bayer formats */
85 static u32 ccdc_raw_bayer_pix_formats[] =
86 	{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
87 
88 /* Raw YUV formats */
89 static u32 ccdc_raw_yuv_pix_formats[] =
90 	{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
91 
92 /* CCDC Save/Restore context */
93 static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)];
94 
95 /* register access routines */
regr(u32 offset)96 static inline u32 regr(u32 offset)
97 {
98 	return __raw_readl(ccdc_cfg.base_addr + offset);
99 }
100 
regw(u32 val,u32 offset)101 static inline void regw(u32 val, u32 offset)
102 {
103 	__raw_writel(val, ccdc_cfg.base_addr + offset);
104 }
105 
ccdc_enable(int flag)106 static void ccdc_enable(int flag)
107 {
108 	regw(flag, CCDC_PCR);
109 }
110 
ccdc_enable_vport(int flag)111 static void ccdc_enable_vport(int flag)
112 {
113 	if (flag)
114 		/* enable video port */
115 		regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG);
116 	else
117 		regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG);
118 }
119 
120 /*
121  * ccdc_setwin()
122  * This function will configure the window size
123  * to be capture in CCDC reg
124  */
ccdc_setwin(struct v4l2_rect * image_win,enum ccdc_frmfmt frm_fmt,int ppc)125 static void ccdc_setwin(struct v4l2_rect *image_win,
126 			enum ccdc_frmfmt frm_fmt,
127 			int ppc)
128 {
129 	int horz_start, horz_nr_pixels;
130 	int vert_start, vert_nr_lines;
131 	int val = 0, mid_img = 0;
132 
133 	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
134 	/*
135 	 * ppc - per pixel count. indicates how many pixels per cell
136 	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
137 	 * raw capture this is 1
138 	 */
139 	horz_start = image_win->left << (ppc - 1);
140 	horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
141 	regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels,
142 	     CCDC_HORZ_INFO);
143 
144 	vert_start = image_win->top;
145 
146 	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
147 		vert_nr_lines = (image_win->height >> 1) - 1;
148 		vert_start >>= 1;
149 		/* Since first line doesn't have any data */
150 		vert_start += 1;
151 		/* configure VDINT0 */
152 		val = (vert_start << CCDC_VDINT_VDINT0_SHIFT);
153 		regw(val, CCDC_VDINT);
154 
155 	} else {
156 		/* Since first line doesn't have any data */
157 		vert_start += 1;
158 		vert_nr_lines = image_win->height - 1;
159 		/*
160 		 * configure VDINT0 and VDINT1. VDINT1 will be at half
161 		 * of image height
162 		 */
163 		mid_img = vert_start + (image_win->height / 2);
164 		val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) |
165 		    (mid_img & CCDC_VDINT_VDINT1_MASK);
166 		regw(val, CCDC_VDINT);
167 
168 	}
169 	regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start,
170 	     CCDC_VERT_START);
171 	regw(vert_nr_lines, CCDC_VERT_LINES);
172 	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
173 }
174 
ccdc_readregs(void)175 static void ccdc_readregs(void)
176 {
177 	unsigned int val = 0;
178 
179 	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 
ccdc_close(struct device * dev)215 static int ccdc_close(struct device *dev)
216 {
217 	return 0;
218 }
219 
220 /*
221  * ccdc_restore_defaults()
222  * This function will write defaults to all CCDC registers
223  */
ccdc_restore_defaults(void)224 static void ccdc_restore_defaults(void)
225 {
226 	int i;
227 
228 	/* disable CCDC */
229 	ccdc_enable(0);
230 	/* set all registers to default value */
231 	for (i = 4; i <= 0x94; i += 4)
232 		regw(0,  i);
233 	regw(CCDC_NO_CULLING, CCDC_CULLING);
234 	regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW);
235 }
236 
ccdc_open(struct device * device)237 static int ccdc_open(struct device *device)
238 {
239 	ccdc_restore_defaults();
240 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
241 		ccdc_enable_vport(1);
242 	return 0;
243 }
244 
ccdc_sbl_reset(void)245 static void ccdc_sbl_reset(void)
246 {
247 	vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O);
248 }
249 
250 /*
251  * ccdc_config_ycbcr()
252  * This function will configure CCDC for YCbCr video capture
253  */
ccdc_config_ycbcr(void)254 static void ccdc_config_ycbcr(void)
255 {
256 	struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
257 	u32 syn_mode;
258 
259 	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
260 	/*
261 	 * first restore the CCDC registers to default values
262 	 * This is important since we assume default values to be set in
263 	 * a lot of registers that we didn't touch
264 	 */
265 	ccdc_restore_defaults();
266 
267 	/*
268 	 * configure pixel format, frame format, configure video frame
269 	 * format, enable output to SDRAM, enable internal timing generator
270 	 * and 8bit pack mode
271 	 */
272 	syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) <<
273 		    CCDC_SYN_MODE_INPMOD_SHIFT) |
274 		    ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) <<
275 		    CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE |
276 		    CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE);
277 
278 	/* setup BT.656 sync mode */
279 	if (params->bt656_enable) {
280 		regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF);
281 
282 		/*
283 		 * configure the FID, VD, HD pin polarity,
284 		 * fld,hd pol positive, vd negative, 8-bit data
285 		 */
286 		syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE;
287 		if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
288 			syn_mode |= CCDC_SYN_MODE_10BITS;
289 		else
290 			syn_mode |= CCDC_SYN_MODE_8BITS;
291 	} else {
292 		/* y/c external sync mode */
293 		syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
294 			     CCDC_FID_POL_SHIFT) |
295 			     ((params->hd_pol & CCDC_HD_POL_MASK) <<
296 			     CCDC_HD_POL_SHIFT) |
297 			     ((params->vd_pol & CCDC_VD_POL_MASK) <<
298 			     CCDC_VD_POL_SHIFT));
299 	}
300 	regw(syn_mode, CCDC_SYN_MODE);
301 
302 	/* configure video window */
303 	ccdc_setwin(&params->win, params->frm_fmt, 2);
304 
305 	/*
306 	 * configure the order of y cb cr in SDRAM, and disable latch
307 	 * internal register on vsync
308 	 */
309 	if (ccdc_cfg.if_type == VPFE_BT656_10BIT)
310 		regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
311 			CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT,
312 			CCDC_CCDCFG);
313 	else
314 		regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) |
315 			CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
316 
317 	/*
318 	 * configure the horizontal line offset. This should be a
319 	 * on 32 byte boundary. So clear LSB 5 bits
320 	 */
321 	regw(((params->win.width * 2  + 31) & ~0x1f), CCDC_HSIZE_OFF);
322 
323 	/* configure the memory line offset */
324 	if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
325 		/* two fields are interleaved in memory */
326 		regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST);
327 
328 	ccdc_sbl_reset();
329 	dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
330 }
331 
ccdc_config_black_clamp(struct ccdc_black_clamp * bclamp)332 static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
333 {
334 	u32 val;
335 
336 	if (!bclamp->enable) {
337 		/* configure DCSub */
338 		val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK;
339 		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 		return;
344 	}
345 	/*
346 	 * Configure gain,  Start pixel, No of line to be avg,
347 	 * No of pixel/line to be avg, & Enable the Black clamping
348 	 */
349 	val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) |
350 	       ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) <<
351 		CCDC_BLK_ST_PXL_SHIFT) |
352 	       ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) <<
353 		CCDC_BLK_SAMPLE_LINE_SHIFT) |
354 	       ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
355 		CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE);
356 	regw(val, CCDC_CLAMP);
357 	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val);
358 	/* If Black clamping is enable then make dcsub 0 */
359 	regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB);
360 	dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n");
361 }
362 
ccdc_config_black_compense(struct ccdc_black_compensation * bcomp)363 static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
364 {
365 	u32 val;
366 
367 	val = ((bcomp->b & CCDC_BLK_COMP_MASK) |
368 	      ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
369 	       CCDC_BLK_COMP_GB_COMP_SHIFT) |
370 	      ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
371 	       CCDC_BLK_COMP_GR_COMP_SHIFT) |
372 	      ((bcomp->r & CCDC_BLK_COMP_MASK) <<
373 	       CCDC_BLK_COMP_R_COMP_SHIFT));
374 	regw(val, CCDC_BLKCMP);
375 }
376 
377 /*
378  * ccdc_config_raw()
379  * This function will configure CCDC for Raw capture mode
380  */
ccdc_config_raw(void)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 	unsigned int syn_mode = 0;
387 	unsigned int val;
388 
389 	dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
390 
391 	/*      Reset CCDC */
392 	ccdc_restore_defaults();
393 
394 	/* Disable latching function registers on VSYNC  */
395 	regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG);
396 
397 	/*
398 	 * Configure the vertical sync polarity(SYN_MODE.VDPOL),
399 	 * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
400 	 * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
401 	 * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
402 	 * SDRAM, enable internal timing generator
403 	 */
404 	syn_mode =
405 		(((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
406 		((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
407 		((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
408 		((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
409 		((config_params->data_sz & CCDC_DATA_SZ_MASK) <<
410 		CCDC_DATA_SZ_SHIFT) |
411 		((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) |
412 		CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE);
413 
414 	/* Enable and configure aLaw register if needed */
415 	if (config_params->alaw.enable) {
416 		val = ((config_params->alaw.gamma_wd &
417 		      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 	/* Configure video window */
423 	ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW);
424 
425 	/* Configure Black Clamp */
426 	ccdc_config_black_clamp(&config_params->blk_clamp);
427 
428 	/* Configure Black level compensation */
429 	ccdc_config_black_compense(&config_params->blk_comp);
430 
431 	/* If data size is 8 bit then pack the data */
432 	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
433 	     config_params->alaw.enable)
434 		syn_mode |= CCDC_DATA_PACK_ENABLE;
435 
436 	/* disable video port */
437 	val = CCDC_DISABLE_VIDEO_PORT;
438 
439 	if (config_params->data_sz == CCDC_DATA_8BITS)
440 		val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
441 		    << CCDC_FMTCFG_VPIN_SHIFT;
442 	else
443 		val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK)
444 		    << CCDC_FMTCFG_VPIN_SHIFT;
445 	/* Write value in FMTCFG */
446 	regw(val, CCDC_FMTCFG);
447 
448 	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val);
449 	/* Configure the color pattern according to mt9t001 sensor */
450 	regw(CCDC_COLPTN_VAL, CCDC_COLPTN);
451 
452 	dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n");
453 	/*
454 	 * Configure Data formatter(Video port) pixel selection
455 	 * (FMT_HORZ, FMT_VERT)
456 	 */
457 	val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) <<
458 	      CCDC_FMT_HORZ_FMTSPH_SHIFT) |
459 	      (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK);
460 	regw(val, CCDC_FMT_HORZ);
461 
462 	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val);
463 	val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK)
464 	    << CCDC_FMT_VERT_FMTSLV_SHIFT;
465 	if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
466 		val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK;
467 	else
468 		val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK;
469 
470 	dev_dbg(ccdc_cfg.dev, "\nparams->win.height  0x%x ...\n",
471 	       params->win.height);
472 	regw(val, CCDC_FMT_VERT);
473 
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 	 * Configure Horizontal offset register. If pack 8 is enabled then
480 	 * 1 pixel will take 1 byte
481 	 */
482 	if ((config_params->data_sz == CCDC_DATA_8BITS) ||
483 	    config_params->alaw.enable)
484 		regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) &
485 		    CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF);
486 	else
487 		/* else one pixel will take 2 byte */
488 		regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) +
489 		    CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK,
490 		    CCDC_HSIZE_OFF);
491 
492 	/* Set value for SDOFST */
493 	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
494 		if (params->image_invert_enable) {
495 			/* For intelace inverse mode */
496 			regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST);
497 			dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n");
498 		}
499 
500 		else {
501 			/* For intelace non inverse mode */
502 			regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST);
503 			dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n");
504 		}
505 	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
506 		regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST);
507 		dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n");
508 	}
509 
510 	/*
511 	 * Configure video port pixel selection (VPOUT)
512 	 * Here -1 is to make the height value less than FMT_VERT.FMTLNV
513 	 */
514 	if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE)
515 		val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK))
516 		    << CCDC_VP_OUT_VERT_NUM_SHIFT;
517 	else
518 		val =
519 		    ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) -
520 		     1) & CCDC_VP_OUT_VERT_NUM_MASK)) <<
521 		    CCDC_VP_OUT_VERT_NUM_SHIFT;
522 
523 	val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK)
524 	    << CCDC_VP_OUT_HORZ_NUM_SHIFT;
525 	val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK;
526 	regw(val, CCDC_VP_OUT);
527 
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 	ccdc_readregs();
535 }
536 
ccdc_configure(void)537 static int ccdc_configure(void)
538 {
539 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
540 		ccdc_config_raw();
541 	else
542 		ccdc_config_ycbcr();
543 	return 0;
544 }
545 
ccdc_set_buftype(enum ccdc_buftype buf_type)546 static int ccdc_set_buftype(enum ccdc_buftype buf_type)
547 {
548 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
549 		ccdc_cfg.bayer.buf_type = buf_type;
550 	else
551 		ccdc_cfg.ycbcr.buf_type = buf_type;
552 	return 0;
553 }
554 
ccdc_get_buftype(void)555 static enum ccdc_buftype ccdc_get_buftype(void)
556 {
557 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
558 		return ccdc_cfg.bayer.buf_type;
559 	return ccdc_cfg.ycbcr.buf_type;
560 }
561 
ccdc_enum_pix(u32 * pix,int i)562 static int ccdc_enum_pix(u32 *pix, int i)
563 {
564 	int ret = -EINVAL;
565 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
566 		if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
567 			*pix = ccdc_raw_bayer_pix_formats[i];
568 			ret = 0;
569 		}
570 	} else {
571 		if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
572 			*pix = ccdc_raw_yuv_pix_formats[i];
573 			ret = 0;
574 		}
575 	}
576 	return ret;
577 }
578 
ccdc_set_pixel_format(u32 pixfmt)579 static int ccdc_set_pixel_format(u32 pixfmt)
580 {
581 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
582 		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 		else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
586 			return -EINVAL;
587 	} else {
588 		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 		else
593 			return -EINVAL;
594 	}
595 	return 0;
596 }
597 
ccdc_get_pixel_format(void)598 static u32 ccdc_get_pixel_format(void)
599 {
600 	struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
601 	u32 pixfmt;
602 
603 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
604 		if (alaw->enable)
605 			pixfmt = V4L2_PIX_FMT_SBGGR8;
606 		else
607 			pixfmt = V4L2_PIX_FMT_SBGGR16;
608 	else {
609 		if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
610 			pixfmt = V4L2_PIX_FMT_YUYV;
611 		else
612 			pixfmt = V4L2_PIX_FMT_UYVY;
613 	}
614 	return pixfmt;
615 }
616 
ccdc_set_image_window(struct v4l2_rect * win)617 static int ccdc_set_image_window(struct v4l2_rect *win)
618 {
619 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
620 		ccdc_cfg.bayer.win = *win;
621 	else
622 		ccdc_cfg.ycbcr.win = *win;
623 	return 0;
624 }
625 
ccdc_get_image_window(struct v4l2_rect * win)626 static void ccdc_get_image_window(struct v4l2_rect *win)
627 {
628 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
629 		*win = ccdc_cfg.bayer.win;
630 	else
631 		*win = ccdc_cfg.ycbcr.win;
632 }
633 
ccdc_get_line_length(void)634 static unsigned int ccdc_get_line_length(void)
635 {
636 	struct ccdc_config_params_raw *config_params =
637 				&ccdc_cfg.bayer.config_params;
638 	unsigned int len;
639 
640 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
641 		if ((config_params->alaw.enable) ||
642 		    (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 	return ALIGN(len, 32);
649 }
650 
ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)651 static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
652 {
653 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
654 		ccdc_cfg.bayer.frm_fmt = frm_fmt;
655 	else
656 		ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
657 	return 0;
658 }
659 
ccdc_get_frame_format(void)660 static enum ccdc_frmfmt ccdc_get_frame_format(void)
661 {
662 	if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
663 		return ccdc_cfg.bayer.frm_fmt;
664 	else
665 		return ccdc_cfg.ycbcr.frm_fmt;
666 }
667 
ccdc_getfid(void)668 static int ccdc_getfid(void)
669 {
670 	return (regr(CCDC_SYN_MODE) >> 15) & 1;
671 }
672 
673 /* misc operations */
ccdc_setfbaddr(unsigned long addr)674 static inline void ccdc_setfbaddr(unsigned long addr)
675 {
676 	regw(addr & 0xffffffe0, CCDC_SDR_ADDR);
677 }
678 
ccdc_set_hw_if_params(struct vpfe_hw_if_param * params)679 static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
680 {
681 	ccdc_cfg.if_type = params->if_type;
682 
683 	switch (params->if_type) {
684 	case VPFE_BT656:
685 	case VPFE_YCBCR_SYNC_16:
686 	case VPFE_YCBCR_SYNC_8:
687 	case VPFE_BT656_10BIT:
688 		ccdc_cfg.ycbcr.vd_pol = params->vdpol;
689 		ccdc_cfg.ycbcr.hd_pol = params->hdpol;
690 		break;
691 	default:
692 		/* TODO add support for raw bayer here */
693 		return -EINVAL;
694 	}
695 	return 0;
696 }
697 
ccdc_save_context(void)698 static void ccdc_save_context(void)
699 {
700 	ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR);
701 	ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE);
702 	ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID);
703 	ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES);
704 	ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO);
705 	ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START);
706 	ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES);
707 	ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING);
708 	ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF);
709 	ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST);
710 	ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR);
711 	ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP);
712 	ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB);
713 	ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN);
714 	ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP);
715 	ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC);
716 	ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR);
717 	ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT);
718 	ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW);
719 	ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF);
720 	ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG);
721 	ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG);
722 	ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ);
723 	ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT);
724 	ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0);
725 	ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1);
726 	ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2);
727 	ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3);
728 	ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4);
729 	ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5);
730 	ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6);
731 	ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7);
732 	ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0);
733 	ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1);
734 	ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0);
735 	ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1);
736 	ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT);
737 }
738 
ccdc_restore_context(void)739 static void ccdc_restore_context(void)
740 {
741 	regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE);
742 	regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID);
743 	regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES);
744 	regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO);
745 	regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START);
746 	regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES);
747 	regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING);
748 	regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF);
749 	regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST);
750 	regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR);
751 	regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP);
752 	regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB);
753 	regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN);
754 	regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP);
755 	regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC);
756 	regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR);
757 	regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT);
758 	regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW);
759 	regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF);
760 	regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG);
761 	regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG);
762 	regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ);
763 	regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT);
764 	regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0);
765 	regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1);
766 	regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2);
767 	regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3);
768 	regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4);
769 	regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5);
770 	regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6);
771 	regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7);
772 	regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0);
773 	regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1);
774 	regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0);
775 	regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1);
776 	regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT);
777 	regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR);
778 }
779 static const struct ccdc_hw_device ccdc_hw_dev = {
780 	.name = "DM6446 CCDC",
781 	.owner = THIS_MODULE,
782 	.hw_ops = {
783 		.open = ccdc_open,
784 		.close = ccdc_close,
785 		.reset = ccdc_sbl_reset,
786 		.enable = ccdc_enable,
787 		.set_hw_if_params = ccdc_set_hw_if_params,
788 		.configure = ccdc_configure,
789 		.set_buftype = ccdc_set_buftype,
790 		.get_buftype = ccdc_get_buftype,
791 		.enum_pix = ccdc_enum_pix,
792 		.set_pixel_format = ccdc_set_pixel_format,
793 		.get_pixel_format = ccdc_get_pixel_format,
794 		.set_frame_format = ccdc_set_frame_format,
795 		.get_frame_format = ccdc_get_frame_format,
796 		.set_image_window = ccdc_set_image_window,
797 		.get_image_window = ccdc_get_image_window,
798 		.get_line_length = ccdc_get_line_length,
799 		.setfbaddr = ccdc_setfbaddr,
800 		.getfid = ccdc_getfid,
801 	},
802 };
803 
dm644x_ccdc_probe(struct platform_device * pdev)804 static int dm644x_ccdc_probe(struct platform_device *pdev)
805 {
806 	struct resource	*res;
807 	int status = 0;
808 
809 	/*
810 	 * first try to register with vpfe. If not correct platform, then we
811 	 * don't have to iomap
812 	 */
813 	status = vpfe_register_ccdc_device(&ccdc_hw_dev);
814 	if (status < 0)
815 		return status;
816 
817 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
818 	if (!res) {
819 		status = -ENODEV;
820 		goto fail_nores;
821 	}
822 
823 	res = request_mem_region(res->start, resource_size(res), res->name);
824 	if (!res) {
825 		status = -EBUSY;
826 		goto fail_nores;
827 	}
828 
829 	ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
830 	if (!ccdc_cfg.base_addr) {
831 		status = -ENOMEM;
832 		goto fail_nomem;
833 	}
834 
835 	ccdc_cfg.dev = &pdev->dev;
836 	printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
837 	return 0;
838 fail_nomem:
839 	release_mem_region(res->start, resource_size(res));
840 fail_nores:
841 	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
842 	return status;
843 }
844 
dm644x_ccdc_remove(struct platform_device * pdev)845 static int dm644x_ccdc_remove(struct platform_device *pdev)
846 {
847 	struct resource	*res;
848 
849 	iounmap(ccdc_cfg.base_addr);
850 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
851 	if (res)
852 		release_mem_region(res->start, resource_size(res));
853 	vpfe_unregister_ccdc_device(&ccdc_hw_dev);
854 	return 0;
855 }
856 
dm644x_ccdc_suspend(struct device * dev)857 static int dm644x_ccdc_suspend(struct device *dev)
858 {
859 	/* Save CCDC context */
860 	ccdc_save_context();
861 	/* Disable CCDC */
862 	ccdc_enable(0);
863 
864 	return 0;
865 }
866 
dm644x_ccdc_resume(struct device * dev)867 static int dm644x_ccdc_resume(struct device *dev)
868 {
869 	/* Restore CCDC context */
870 	ccdc_restore_context();
871 
872 	return 0;
873 }
874 
875 static const struct dev_pm_ops dm644x_ccdc_pm_ops = {
876 	.suspend = dm644x_ccdc_suspend,
877 	.resume = dm644x_ccdc_resume,
878 };
879 
880 static struct platform_driver dm644x_ccdc_driver = {
881 	.driver = {
882 		.name	= "dm644x_ccdc",
883 		.pm = &dm644x_ccdc_pm_ops,
884 	},
885 	.remove = dm644x_ccdc_remove,
886 	.probe = dm644x_ccdc_probe,
887 };
888 
889 module_platform_driver(dm644x_ccdc_driver);
890