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