• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008-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  * Image Sensor Interface (ISIF) driver
15  *
16  * This driver is for configuring the ISIF IP available on DM365 or any other
17  * TI SoCs. This is used for capturing yuv or bayer video or image data
18  * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
19  * and DM6446, but with enhanced or additional ip blocks. The driver
20  * configures the ISIF upon commands from the vpfe bridge driver through
21  * ccdc_hw_device interface.
22  *
23  * TODO: 1) Raw bayer parameter settings and bayer capture
24  *	 2) Add support for control ioctl
25  */
26 #include <linux/delay.h>
27 #include <linux/platform_device.h>
28 #include <linux/uaccess.h>
29 #include <linux/io.h>
30 #include <linux/videodev2.h>
31 #include <linux/err.h>
32 #include <linux/module.h>
33 
34 #include <media/davinci/isif.h>
35 #include <media/davinci/vpss.h>
36 
37 #include "isif_regs.h"
38 #include "ccdc_hw_device.h"
39 
40 /* Defaults for module configuration parameters */
41 static struct isif_config_params_raw isif_config_defaults = {
42 	.linearize = {
43 		.en = 0,
44 		.corr_shft = ISIF_NO_SHIFT,
45 		.scale_fact = {1, 0},
46 	},
47 	.df_csc = {
48 		.df_or_csc = 0,
49 		.csc = {
50 			.en = 0,
51 		},
52 	},
53 	.dfc = {
54 		.en = 0,
55 	},
56 	.bclamp = {
57 		.en = 0,
58 	},
59 	.gain_offset = {
60 		.gain = {
61 			.r_ye = {1, 0},
62 			.gr_cy = {1, 0},
63 			.gb_g = {1, 0},
64 			.b_mg = {1, 0},
65 		},
66 	},
67 	.culling = {
68 		.hcpat_odd = 0xff,
69 		.hcpat_even = 0xff,
70 		.vcpat = 0xff,
71 	},
72 	.compress = {
73 		.alg = ISIF_ALAW,
74 	},
75 };
76 
77 /* ISIF operation configuration */
78 static struct isif_oper_config {
79 	struct device *dev;
80 	enum vpfe_hw_if_type if_type;
81 	struct isif_ycbcr_config ycbcr;
82 	struct isif_params_raw bayer;
83 	enum isif_data_pack data_pack;
84 	/* ISIF base address */
85 	void __iomem *base_addr;
86 	/* ISIF Linear Table 0 */
87 	void __iomem *linear_tbl0_addr;
88 	/* ISIF Linear Table 1 */
89 	void __iomem *linear_tbl1_addr;
90 } isif_cfg = {
91 	.ycbcr = {
92 		.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
93 		.frm_fmt = CCDC_FRMFMT_INTERLACED,
94 		.win = ISIF_WIN_NTSC,
95 		.fid_pol = VPFE_PINPOL_POSITIVE,
96 		.vd_pol = VPFE_PINPOL_POSITIVE,
97 		.hd_pol = VPFE_PINPOL_POSITIVE,
98 		.pix_order = CCDC_PIXORDER_CBYCRY,
99 		.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
100 	},
101 	.bayer = {
102 		.pix_fmt = CCDC_PIXFMT_RAW,
103 		.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
104 		.win = ISIF_WIN_VGA,
105 		.fid_pol = VPFE_PINPOL_POSITIVE,
106 		.vd_pol = VPFE_PINPOL_POSITIVE,
107 		.hd_pol = VPFE_PINPOL_POSITIVE,
108 		.gain = {
109 			.r_ye = {1, 0},
110 			.gr_cy = {1, 0},
111 			.gb_g = {1, 0},
112 			.b_mg = {1, 0},
113 		},
114 		.cfa_pat = ISIF_CFA_PAT_MOSAIC,
115 		.data_msb = ISIF_BIT_MSB_11,
116 		.config_params = {
117 			.data_shift = ISIF_NO_SHIFT,
118 			.col_pat_field0 = {
119 				.olop = ISIF_GREEN_BLUE,
120 				.olep = ISIF_BLUE,
121 				.elop = ISIF_RED,
122 				.elep = ISIF_GREEN_RED,
123 			},
124 			.col_pat_field1 = {
125 				.olop = ISIF_GREEN_BLUE,
126 				.olep = ISIF_BLUE,
127 				.elop = ISIF_RED,
128 				.elep = ISIF_GREEN_RED,
129 			},
130 			.test_pat_gen = 0,
131 		},
132 	},
133 	.data_pack = ISIF_DATA_PACK8,
134 };
135 
136 /* Raw Bayer formats */
137 static const u32 isif_raw_bayer_pix_formats[] = {
138 	V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
139 
140 /* Raw YUV formats */
141 static const u32 isif_raw_yuv_pix_formats[] = {
142 	V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
143 
144 /* register access routines */
regr(u32 offset)145 static inline u32 regr(u32 offset)
146 {
147 	return __raw_readl(isif_cfg.base_addr + offset);
148 }
149 
regw(u32 val,u32 offset)150 static inline void regw(u32 val, u32 offset)
151 {
152 	__raw_writel(val, isif_cfg.base_addr + offset);
153 }
154 
155 /* reg_modify() - read, modify and write register */
reg_modify(u32 mask,u32 val,u32 offset)156 static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
157 {
158 	u32 new_val = (regr(offset) & ~mask) | (val & mask);
159 
160 	regw(new_val, offset);
161 	return new_val;
162 }
163 
regw_lin_tbl(u32 val,u32 offset,int i)164 static inline void regw_lin_tbl(u32 val, u32 offset, int i)
165 {
166 	if (!i)
167 		__raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
168 	else
169 		__raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
170 }
171 
isif_disable_all_modules(void)172 static void isif_disable_all_modules(void)
173 {
174 	/* disable BC */
175 	regw(0, CLAMPCFG);
176 	/* disable vdfc */
177 	regw(0, DFCCTL);
178 	/* disable CSC */
179 	regw(0, CSCCTL);
180 	/* disable linearization */
181 	regw(0, LINCFG0);
182 	/* disable other modules here as they are supported */
183 }
184 
isif_enable(int en)185 static void isif_enable(int en)
186 {
187 	if (!en) {
188 		/* Before disable isif, disable all ISIF modules */
189 		isif_disable_all_modules();
190 		/*
191 		 * wait for next VD. Assume lowest scan rate is 12 Hz. So
192 		 * 100 msec delay is good enough
193 		 */
194 		msleep(100);
195 	}
196 	reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
197 }
198 
isif_enable_output_to_sdram(int en)199 static void isif_enable_output_to_sdram(int en)
200 {
201 	reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
202 }
203 
isif_config_culling(struct isif_cul * cul)204 static void isif_config_culling(struct isif_cul *cul)
205 {
206 	u32 val;
207 
208 	/* Horizontal pattern */
209 	val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
210 	regw(val, CULH);
211 
212 	/* vertical pattern */
213 	regw(cul->vcpat, CULV);
214 
215 	/* LPF */
216 	reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
217 		  cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
218 }
219 
isif_config_gain_offset(void)220 static void isif_config_gain_offset(void)
221 {
222 	struct isif_gain_offsets_adj *gain_off_p =
223 		&isif_cfg.bayer.config_params.gain_offset;
224 	u32 val;
225 
226 	val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
227 	      (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
228 	      (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
229 	      (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
230 	      (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
231 	      (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
232 
233 	reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
234 
235 	val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
236 	       gain_off_p->gain.r_ye.decimal;
237 	regw(val, CRGAIN);
238 
239 	val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
240 	       gain_off_p->gain.gr_cy.decimal;
241 	regw(val, CGRGAIN);
242 
243 	val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
244 	       gain_off_p->gain.gb_g.decimal;
245 	regw(val, CGBGAIN);
246 
247 	val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
248 	       gain_off_p->gain.b_mg.decimal;
249 	regw(val, CBGAIN);
250 
251 	regw(gain_off_p->offset, COFSTA);
252 }
253 
isif_restore_defaults(void)254 static void isif_restore_defaults(void)
255 {
256 	enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
257 
258 	dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
259 	isif_cfg.bayer.config_params = isif_config_defaults;
260 	/* Enable clock to ISIF, IPIPEIF and BL */
261 	vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
262 	vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
263 	vpss_enable_clock(VPSS_BL_CLOCK, 1);
264 	/* Set default offset and gain */
265 	isif_config_gain_offset();
266 	vpss_select_ccdc_source(source);
267 	dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
268 }
269 
isif_open(struct device * device)270 static int isif_open(struct device *device)
271 {
272 	isif_restore_defaults();
273 	return 0;
274 }
275 
276 /* This function will configure the window size to be capture in ISIF reg */
isif_setwin(struct v4l2_rect * image_win,enum ccdc_frmfmt frm_fmt,int ppc)277 static void isif_setwin(struct v4l2_rect *image_win,
278 			enum ccdc_frmfmt frm_fmt, int ppc)
279 {
280 	int horz_start, horz_nr_pixels;
281 	int vert_start, vert_nr_lines;
282 	int mid_img = 0;
283 
284 	dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
285 	/*
286 	 * ppc - per pixel count. indicates how many pixels per cell
287 	 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
288 	 * raw capture this is 1
289 	 */
290 	horz_start = image_win->left << (ppc - 1);
291 	horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
292 
293 	/* Writing the horizontal info into the registers */
294 	regw(horz_start & START_PX_HOR_MASK, SPH);
295 	regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
296 	vert_start = image_win->top;
297 
298 	if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
299 		vert_nr_lines = (image_win->height >> 1) - 1;
300 		vert_start >>= 1;
301 		/* To account for VD since line 0 doesn't have any data */
302 		vert_start += 1;
303 	} else {
304 		/* To account for VD since line 0 doesn't have any data */
305 		vert_start += 1;
306 		vert_nr_lines = image_win->height - 1;
307 		/* configure VDINT0 and VDINT1 */
308 		mid_img = vert_start + (image_win->height / 2);
309 		regw(mid_img, VDINT1);
310 	}
311 
312 	regw(0, VDINT0);
313 	regw(vert_start & START_VER_ONE_MASK, SLV0);
314 	regw(vert_start & START_VER_TWO_MASK, SLV1);
315 	regw(vert_nr_lines & NUM_LINES_VER, LNV);
316 }
317 
isif_config_bclamp(struct isif_black_clamp * bc)318 static void isif_config_bclamp(struct isif_black_clamp *bc)
319 {
320 	u32 val;
321 
322 	/*
323 	 * DC Offset is always added to image data irrespective of bc enable
324 	 * status
325 	 */
326 	regw(bc->dc_offset, CLDCOFST);
327 
328 	if (bc->en) {
329 		val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
330 
331 		/* Enable BC and horizontal clamp caculation paramaters */
332 		val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
333 
334 		regw(val, CLAMPCFG);
335 
336 		if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
337 			/*
338 			 * Window count for calculation
339 			 * Base window selection
340 			 * pixel limit
341 			 * Horizontal size of window
342 			 * vertical size of the window
343 			 * Horizontal start position of the window
344 			 * Vertical start position of the window
345 			 */
346 			val = bc->horz.win_count_calc |
347 			      ((!!bc->horz.base_win_sel_calc) <<
348 				ISIF_HORZ_BC_WIN_SEL_SHIFT) |
349 			      ((!!bc->horz.clamp_pix_limit) <<
350 				ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
351 			      (bc->horz.win_h_sz_calc <<
352 				ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
353 			      (bc->horz.win_v_sz_calc <<
354 				ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
355 			regw(val, CLHWIN0);
356 
357 			regw(bc->horz.win_start_h_calc, CLHWIN1);
358 			regw(bc->horz.win_start_v_calc, CLHWIN2);
359 		}
360 
361 		/* vertical clamp caculation paramaters */
362 
363 		/* Reset clamp value sel for previous line */
364 		val |=
365 		(bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
366 		(bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
367 		regw(val, CLVWIN0);
368 
369 		/* Optical Black horizontal start position */
370 		regw(bc->vert.ob_start_h, CLVWIN1);
371 		/* Optical Black vertical start position */
372 		regw(bc->vert.ob_start_v, CLVWIN2);
373 		/* Optical Black vertical size for calculation */
374 		regw(bc->vert.ob_v_sz_calc, CLVWIN3);
375 		/* Vertical start position for BC subtraction */
376 		regw(bc->vert_start_sub, CLSV);
377 	}
378 }
379 
isif_config_linearization(struct isif_linearize * linearize)380 static void isif_config_linearization(struct isif_linearize *linearize)
381 {
382 	u32 val, i;
383 
384 	if (!linearize->en) {
385 		regw(0, LINCFG0);
386 		return;
387 	}
388 
389 	/* shift value for correction & enable linearization (set lsb) */
390 	val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
391 	regw(val, LINCFG0);
392 
393 	/* Scale factor */
394 	val = ((!!linearize->scale_fact.integer) <<
395 	       ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
396 	       linearize->scale_fact.decimal;
397 	regw(val, LINCFG1);
398 
399 	for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
400 		if (i % 2)
401 			regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
402 		else
403 			regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
404 	}
405 }
406 
isif_config_dfc(struct isif_dfc * vdfc)407 static int isif_config_dfc(struct isif_dfc *vdfc)
408 {
409 	/* initialize retries to loop for max ~ 250 usec */
410 	u32 val, count, retries = loops_per_jiffy / (4000/HZ);
411 	int i;
412 
413 	if (!vdfc->en)
414 		return 0;
415 
416 	/* Correction mode */
417 	val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
418 
419 	/* Correct whole line or partial */
420 	if (vdfc->corr_whole_line)
421 		val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
422 
423 	/* level shift value */
424 	val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
425 
426 	regw(val, DFCCTL);
427 
428 	/* Defect saturation level */
429 	regw(vdfc->def_sat_level, VDFSATLV);
430 
431 	regw(vdfc->table[0].pos_vert, DFCMEM0);
432 	regw(vdfc->table[0].pos_horz, DFCMEM1);
433 	if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
434 	    vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
435 		regw(vdfc->table[0].level_at_pos, DFCMEM2);
436 		regw(vdfc->table[0].level_up_pixels, DFCMEM3);
437 		regw(vdfc->table[0].level_low_pixels, DFCMEM4);
438 	}
439 
440 	/* set DFCMARST and set DFCMWR */
441 	val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
442 	regw(val, DFCMEMCTL);
443 
444 	count = retries;
445 	while (count && (regr(DFCMEMCTL) & 0x1))
446 		count--;
447 
448 	if (!count) {
449 		dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
450 		return -1;
451 	}
452 
453 	for (i = 1; i < vdfc->num_vdefects; i++) {
454 		regw(vdfc->table[i].pos_vert, DFCMEM0);
455 		regw(vdfc->table[i].pos_horz, DFCMEM1);
456 		if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
457 		    vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
458 			regw(vdfc->table[i].level_at_pos, DFCMEM2);
459 			regw(vdfc->table[i].level_up_pixels, DFCMEM3);
460 			regw(vdfc->table[i].level_low_pixels, DFCMEM4);
461 		}
462 		val = regr(DFCMEMCTL);
463 		/* clear DFCMARST and set DFCMWR */
464 		val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
465 		val |= 1;
466 		regw(val, DFCMEMCTL);
467 
468 		count = retries;
469 		while (count && (regr(DFCMEMCTL) & 0x1))
470 			count--;
471 
472 		if (!count) {
473 			dev_err(isif_cfg.dev,
474 				"defect table write timeout !!!\n");
475 			return -1;
476 		}
477 	}
478 	if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
479 		/* Extra cycle needed */
480 		regw(0, DFCMEM0);
481 		regw(0x1FFF, DFCMEM1);
482 		regw(1, DFCMEMCTL);
483 	}
484 
485 	/* enable VDFC */
486 	reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
487 		   DFCCTL);
488 	return 0;
489 }
490 
isif_config_csc(struct isif_df_csc * df_csc)491 static void isif_config_csc(struct isif_df_csc *df_csc)
492 {
493 	u32 val1 = 0, val2 = 0, i;
494 
495 	if (!df_csc->csc.en) {
496 		regw(0, CSCCTL);
497 		return;
498 	}
499 	for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
500 		if ((i % 2) == 0) {
501 			/* CSCM - LSB */
502 			val1 = (df_csc->csc.coeff[i].integer <<
503 				ISIF_CSC_COEF_INTEG_SHIFT) |
504 				df_csc->csc.coeff[i].decimal;
505 		} else {
506 
507 			/* CSCM - MSB */
508 			val2 = (df_csc->csc.coeff[i].integer <<
509 				ISIF_CSC_COEF_INTEG_SHIFT) |
510 				df_csc->csc.coeff[i].decimal;
511 			val2 <<= ISIF_CSCM_MSB_SHIFT;
512 			val2 |= val1;
513 			regw(val2, (CSCM0 + ((i - 1) << 1)));
514 		}
515 	}
516 
517 	/* program the active area */
518 	regw(df_csc->start_pix, FMTSPH);
519 	/*
520 	 * one extra pixel as required for CSC. Actually number of
521 	 * pixel - 1 should be configured in this register. So we
522 	 * need to subtract 1 before writing to FMTSPH, but we will
523 	 * not do this since csc requires one extra pixel
524 	 */
525 	regw(df_csc->num_pixels, FMTLNH);
526 	regw(df_csc->start_line, FMTSLV);
527 	/*
528 	 * one extra line as required for CSC. See reason documented for
529 	 * num_pixels
530 	 */
531 	regw(df_csc->num_lines, FMTLNV);
532 
533 	/* Enable CSC */
534 	regw(1, CSCCTL);
535 }
536 
isif_config_raw(void)537 static int isif_config_raw(void)
538 {
539 	struct isif_params_raw *params = &isif_cfg.bayer;
540 	struct isif_config_params_raw *module_params =
541 		&isif_cfg.bayer.config_params;
542 	struct vpss_pg_frame_size frame_size;
543 	struct vpss_sync_pol sync;
544 	u32 val;
545 
546 	dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
547 
548 	/*
549 	 * Configure CCDCFG register:-
550 	 * Set CCD Not to swap input since input is RAW data
551 	 * Set FID detection function to Latch at V-Sync
552 	 * Set WENLOG - isif valid area
553 	 * Set TRGSEL
554 	 * Set EXTRG
555 	 * Packed to 8 or 16 bits
556 	 */
557 
558 	val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
559 		ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
560 		ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
561 
562 	dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
563 	regw(val, CCDCFG);
564 
565 	/*
566 	 * Configure the vertical sync polarity(MODESET.VDPOL)
567 	 * Configure the horizontal sync polarity (MODESET.HDPOL)
568 	 * Configure frame id polarity (MODESET.FLDPOL)
569 	 * Configure data polarity
570 	 * Configure External WEN Selection
571 	 * Configure frame format(progressive or interlace)
572 	 * Configure pixel format (Input mode)
573 	 * Configure the data shift
574 	 */
575 
576 	val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
577 		(params->hd_pol << ISIF_HD_POL_SHIFT) |
578 		(params->fid_pol << ISIF_FID_POL_SHIFT) |
579 		(ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
580 		(ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
581 		(params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
582 		(params->pix_fmt << ISIF_INPUT_SHIFT) |
583 		(params->config_params.data_shift << ISIF_DATASFT_SHIFT);
584 
585 	regw(val, MODESET);
586 	dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
587 
588 	/*
589 	 * Configure GAMMAWD register
590 	 * CFA pattern setting
591 	 */
592 	val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
593 
594 	/* Gamma msb */
595 	if (module_params->compress.alg == ISIF_ALAW)
596 		val |= ISIF_ALAW_ENABLE;
597 
598 	val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT);
599 	regw(val, CGAMMAWD);
600 
601 	/* Configure DPCM compression settings */
602 	if (module_params->compress.alg == ISIF_DPCM) {
603 		val =  BIT(ISIF_DPCM_EN_SHIFT) |
604 		       (module_params->compress.pred <<
605 		       ISIF_DPCM_PREDICTOR_SHIFT);
606 	}
607 
608 	regw(val, MISC);
609 
610 	/* Configure Gain & Offset */
611 	isif_config_gain_offset();
612 
613 	/* Configure Color pattern */
614 	val = (params->config_params.col_pat_field0.olop) |
615 	      (params->config_params.col_pat_field0.olep << 2) |
616 	      (params->config_params.col_pat_field0.elop << 4) |
617 	      (params->config_params.col_pat_field0.elep << 6) |
618 	      (params->config_params.col_pat_field1.olop << 8) |
619 	      (params->config_params.col_pat_field1.olep << 10) |
620 	      (params->config_params.col_pat_field1.elop << 12) |
621 	      (params->config_params.col_pat_field1.elep << 14);
622 	regw(val, CCOLP);
623 	dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
624 
625 	/* Configure HSIZE register  */
626 	val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
627 
628 	/* calculate line offset in 32 bytes based on pack value */
629 	if (isif_cfg.data_pack == ISIF_PACK_8BIT)
630 		val |= ((params->win.width + 31) >> 5);
631 	else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
632 		val |= (((params->win.width +
633 		       (params->win.width >> 2)) + 31) >> 5);
634 	else
635 		val |= (((params->win.width * 2) + 31) >> 5);
636 	regw(val, HSIZE);
637 
638 	/* Configure SDOFST register  */
639 	if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
640 		if (params->image_invert_en) {
641 			/* For interlace inverse mode */
642 			regw(0x4B6D, SDOFST);
643 			dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
644 		} else {
645 			/* For interlace non inverse mode */
646 			regw(0x0B6D, SDOFST);
647 			dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
648 		}
649 	} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
650 		if (params->image_invert_en) {
651 			/* For progressive inverse mode */
652 			regw(0x4000, SDOFST);
653 			dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
654 		} else {
655 			/* For progressive non inverse mode */
656 			regw(0x0000, SDOFST);
657 			dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
658 		}
659 	}
660 
661 	/* Configure video window */
662 	isif_setwin(&params->win, params->frm_fmt, 1);
663 
664 	/* Configure Black Clamp */
665 	isif_config_bclamp(&module_params->bclamp);
666 
667 	/* Configure Vertical Defection Pixel Correction */
668 	if (isif_config_dfc(&module_params->dfc) < 0)
669 		return -EFAULT;
670 
671 	if (!module_params->df_csc.df_or_csc)
672 		/* Configure Color Space Conversion */
673 		isif_config_csc(&module_params->df_csc);
674 
675 	isif_config_linearization(&module_params->linearize);
676 
677 	/* Configure Culling */
678 	isif_config_culling(&module_params->culling);
679 
680 	/* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
681 	regw(module_params->horz_offset, DATAHOFST);
682 	regw(module_params->vert_offset, DATAVOFST);
683 
684 	/* Setup test pattern if enabled */
685 	if (params->config_params.test_pat_gen) {
686 		/* Use the HD/VD pol settings from user */
687 		sync.ccdpg_hdpol = params->hd_pol;
688 		sync.ccdpg_vdpol = params->vd_pol;
689 		dm365_vpss_set_sync_pol(sync);
690 		frame_size.hlpfr = isif_cfg.bayer.win.width;
691 		frame_size.pplen = isif_cfg.bayer.win.height;
692 		dm365_vpss_set_pg_frame_size(frame_size);
693 		vpss_select_ccdc_source(VPSS_PGLPBK);
694 	}
695 
696 	dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
697 	return 0;
698 }
699 
isif_set_buftype(enum ccdc_buftype buf_type)700 static int isif_set_buftype(enum ccdc_buftype buf_type)
701 {
702 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
703 		isif_cfg.bayer.buf_type = buf_type;
704 	else
705 		isif_cfg.ycbcr.buf_type = buf_type;
706 
707 	return 0;
708 
709 }
isif_get_buftype(void)710 static enum ccdc_buftype isif_get_buftype(void)
711 {
712 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
713 		return isif_cfg.bayer.buf_type;
714 
715 	return isif_cfg.ycbcr.buf_type;
716 }
717 
isif_enum_pix(u32 * pix,int i)718 static int isif_enum_pix(u32 *pix, int i)
719 {
720 	int ret = -EINVAL;
721 
722 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
723 		if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
724 			*pix = isif_raw_bayer_pix_formats[i];
725 			ret = 0;
726 		}
727 	} else {
728 		if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
729 			*pix = isif_raw_yuv_pix_formats[i];
730 			ret = 0;
731 		}
732 	}
733 
734 	return ret;
735 }
736 
isif_set_pixel_format(unsigned int pixfmt)737 static int isif_set_pixel_format(unsigned int pixfmt)
738 {
739 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
740 		if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
741 			if ((isif_cfg.bayer.config_params.compress.alg !=
742 			     ISIF_ALAW) &&
743 			    (isif_cfg.bayer.config_params.compress.alg !=
744 			     ISIF_DPCM)) {
745 				dev_dbg(isif_cfg.dev,
746 					"Either configure A-Law or DPCM\n");
747 				return -EINVAL;
748 			}
749 			isif_cfg.data_pack = ISIF_PACK_8BIT;
750 		} else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
751 			isif_cfg.bayer.config_params.compress.alg =
752 					ISIF_NO_COMPRESSION;
753 			isif_cfg.data_pack = ISIF_PACK_16BIT;
754 		} else
755 			return -EINVAL;
756 		isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
757 	} else {
758 		if (pixfmt == V4L2_PIX_FMT_YUYV)
759 			isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
760 		else if (pixfmt == V4L2_PIX_FMT_UYVY)
761 			isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
762 		else
763 			return -EINVAL;
764 		isif_cfg.data_pack = ISIF_PACK_8BIT;
765 	}
766 	return 0;
767 }
768 
isif_get_pixel_format(void)769 static u32 isif_get_pixel_format(void)
770 {
771 	u32 pixfmt;
772 
773 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
774 		if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
775 		    isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
776 			pixfmt = V4L2_PIX_FMT_SBGGR8;
777 		else
778 			pixfmt = V4L2_PIX_FMT_SBGGR16;
779 	else {
780 		if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
781 			pixfmt = V4L2_PIX_FMT_YUYV;
782 		else
783 			pixfmt = V4L2_PIX_FMT_UYVY;
784 	}
785 	return pixfmt;
786 }
787 
isif_set_image_window(struct v4l2_rect * win)788 static int isif_set_image_window(struct v4l2_rect *win)
789 {
790 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
791 		isif_cfg.bayer.win.top = win->top;
792 		isif_cfg.bayer.win.left = win->left;
793 		isif_cfg.bayer.win.width = win->width;
794 		isif_cfg.bayer.win.height = win->height;
795 	} else {
796 		isif_cfg.ycbcr.win.top = win->top;
797 		isif_cfg.ycbcr.win.left = win->left;
798 		isif_cfg.ycbcr.win.width = win->width;
799 		isif_cfg.ycbcr.win.height = win->height;
800 	}
801 	return 0;
802 }
803 
isif_get_image_window(struct v4l2_rect * win)804 static void isif_get_image_window(struct v4l2_rect *win)
805 {
806 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
807 		*win = isif_cfg.bayer.win;
808 	else
809 		*win = isif_cfg.ycbcr.win;
810 }
811 
isif_get_line_length(void)812 static unsigned int isif_get_line_length(void)
813 {
814 	unsigned int len;
815 
816 	if (isif_cfg.if_type == VPFE_RAW_BAYER) {
817 		if (isif_cfg.data_pack == ISIF_PACK_8BIT)
818 			len = ((isif_cfg.bayer.win.width));
819 		else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
820 			len = (((isif_cfg.bayer.win.width * 2) +
821 				 (isif_cfg.bayer.win.width >> 2)));
822 		else
823 			len = (((isif_cfg.bayer.win.width * 2)));
824 	} else
825 		len = (((isif_cfg.ycbcr.win.width * 2)));
826 	return ALIGN(len, 32);
827 }
828 
isif_set_frame_format(enum ccdc_frmfmt frm_fmt)829 static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
830 {
831 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
832 		isif_cfg.bayer.frm_fmt = frm_fmt;
833 	else
834 		isif_cfg.ycbcr.frm_fmt = frm_fmt;
835 	return 0;
836 }
isif_get_frame_format(void)837 static enum ccdc_frmfmt isif_get_frame_format(void)
838 {
839 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
840 		return isif_cfg.bayer.frm_fmt;
841 	return isif_cfg.ycbcr.frm_fmt;
842 }
843 
isif_getfid(void)844 static int isif_getfid(void)
845 {
846 	return (regr(MODESET) >> 15) & 0x1;
847 }
848 
849 /* misc operations */
isif_setfbaddr(unsigned long addr)850 static void isif_setfbaddr(unsigned long addr)
851 {
852 	regw((addr >> 21) & 0x07ff, CADU);
853 	regw((addr >> 5) & 0x0ffff, CADL);
854 }
855 
isif_set_hw_if_params(struct vpfe_hw_if_param * params)856 static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
857 {
858 	isif_cfg.if_type = params->if_type;
859 
860 	switch (params->if_type) {
861 	case VPFE_BT656:
862 	case VPFE_BT656_10BIT:
863 	case VPFE_YCBCR_SYNC_8:
864 		isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
865 		isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
866 		break;
867 	case VPFE_BT1120:
868 	case VPFE_YCBCR_SYNC_16:
869 		isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
870 		isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
871 		break;
872 	case VPFE_RAW_BAYER:
873 		isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
874 		break;
875 	default:
876 		dev_dbg(isif_cfg.dev, "Invalid interface type\n");
877 		return -EINVAL;
878 	}
879 
880 	return 0;
881 }
882 
883 /* This function will configure ISIF for YCbCr parameters. */
isif_config_ycbcr(void)884 static int isif_config_ycbcr(void)
885 {
886 	struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
887 	u32 modeset = 0, ccdcfg = 0;
888 
889 	dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
890 
891 	/* configure pixel format or input mode */
892 	modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
893 		  (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
894 		  (params->fid_pol << ISIF_FID_POL_SHIFT) |
895 		  (params->hd_pol << ISIF_HD_POL_SHIFT) |
896 		  (params->vd_pol << ISIF_VD_POL_SHIFT);
897 
898 	/* pack the data to 8-bit ISIFCFG */
899 	switch (isif_cfg.if_type) {
900 	case VPFE_BT656:
901 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
902 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
903 			return -EINVAL;
904 		}
905 		modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
906 		regw(3, REC656IF);
907 		ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
908 		break;
909 	case VPFE_BT656_10BIT:
910 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
911 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
912 			return -EINVAL;
913 		}
914 		/* setup BT.656, embedded sync  */
915 		regw(3, REC656IF);
916 		/* enable 10 bit mode in ccdcfg */
917 		ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
918 			ISIF_BW656_ENABLE;
919 		break;
920 	case VPFE_BT1120:
921 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
922 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
923 			return -EINVAL;
924 		}
925 		regw(3, REC656IF);
926 		break;
927 
928 	case VPFE_YCBCR_SYNC_8:
929 		ccdcfg |= ISIF_DATA_PACK8;
930 		ccdcfg |= ISIF_YCINSWP_YCBCR;
931 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
932 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
933 			return -EINVAL;
934 		}
935 		break;
936 	case VPFE_YCBCR_SYNC_16:
937 		if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
938 			dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
939 			return -EINVAL;
940 		}
941 		break;
942 	default:
943 		/* should never come here */
944 		dev_dbg(isif_cfg.dev, "Invalid interface type\n");
945 		return -EINVAL;
946 	}
947 
948 	regw(modeset, MODESET);
949 
950 	/* Set up pix order */
951 	ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
952 
953 	regw(ccdcfg, CCDCFG);
954 
955 	/* configure video window */
956 	if ((isif_cfg.if_type == VPFE_BT1120) ||
957 	    (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
958 		isif_setwin(&params->win, params->frm_fmt, 1);
959 	else
960 		isif_setwin(&params->win, params->frm_fmt, 2);
961 
962 	/*
963 	 * configure the horizontal line offset
964 	 * this is done by rounding up width to a multiple of 16 pixels
965 	 * and multiply by two to account for y:cb:cr 4:2:2 data
966 	 */
967 	regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
968 
969 	/* configure the memory line offset */
970 	if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
971 	    (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
972 		/* two fields are interleaved in memory */
973 		regw(0x00000249, SDOFST);
974 
975 	return 0;
976 }
977 
isif_configure(void)978 static int isif_configure(void)
979 {
980 	if (isif_cfg.if_type == VPFE_RAW_BAYER)
981 		return isif_config_raw();
982 	return isif_config_ycbcr();
983 }
984 
isif_close(struct device * device)985 static int isif_close(struct device *device)
986 {
987 	/* copy defaults to module params */
988 	isif_cfg.bayer.config_params = isif_config_defaults;
989 	return 0;
990 }
991 
992 static const struct ccdc_hw_device isif_hw_dev = {
993 	.name = "ISIF",
994 	.owner = THIS_MODULE,
995 	.hw_ops = {
996 		.open = isif_open,
997 		.close = isif_close,
998 		.enable = isif_enable,
999 		.enable_out_to_sdram = isif_enable_output_to_sdram,
1000 		.set_hw_if_params = isif_set_hw_if_params,
1001 		.configure = isif_configure,
1002 		.set_buftype = isif_set_buftype,
1003 		.get_buftype = isif_get_buftype,
1004 		.enum_pix = isif_enum_pix,
1005 		.set_pixel_format = isif_set_pixel_format,
1006 		.get_pixel_format = isif_get_pixel_format,
1007 		.set_frame_format = isif_set_frame_format,
1008 		.get_frame_format = isif_get_frame_format,
1009 		.set_image_window = isif_set_image_window,
1010 		.get_image_window = isif_get_image_window,
1011 		.get_line_length = isif_get_line_length,
1012 		.setfbaddr = isif_setfbaddr,
1013 		.getfid = isif_getfid,
1014 	},
1015 };
1016 
isif_probe(struct platform_device * pdev)1017 static int isif_probe(struct platform_device *pdev)
1018 {
1019 	void (*setup_pinmux)(void);
1020 	struct resource	*res;
1021 	void __iomem *addr;
1022 	int status = 0, i;
1023 
1024 	/* Platform data holds setup_pinmux function ptr */
1025 	if (!pdev->dev.platform_data)
1026 		return -ENODEV;
1027 
1028 	/*
1029 	 * first try to register with vpfe. If not correct platform, then we
1030 	 * don't have to iomap
1031 	 */
1032 	status = vpfe_register_ccdc_device(&isif_hw_dev);
1033 	if (status < 0)
1034 		return status;
1035 
1036 	setup_pinmux = pdev->dev.platform_data;
1037 	/*
1038 	 * setup Mux configuration for ccdc which may be different for
1039 	 * different SoCs using this CCDC
1040 	 */
1041 	setup_pinmux();
1042 
1043 	i = 0;
1044 	/* Get the ISIF base address, linearization table0 and table1 addr. */
1045 	while (i < 3) {
1046 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1047 		if (!res) {
1048 			status = -ENODEV;
1049 			goto fail_nobase_res;
1050 		}
1051 		res = request_mem_region(res->start, resource_size(res),
1052 					 res->name);
1053 		if (!res) {
1054 			status = -EBUSY;
1055 			goto fail_nobase_res;
1056 		}
1057 		addr = ioremap_nocache(res->start, resource_size(res));
1058 		if (!addr) {
1059 			status = -ENOMEM;
1060 			goto fail_base_iomap;
1061 		}
1062 		switch (i) {
1063 		case 0:
1064 			/* ISIF base address */
1065 			isif_cfg.base_addr = addr;
1066 			break;
1067 		case 1:
1068 			/* ISIF linear tbl0 address */
1069 			isif_cfg.linear_tbl0_addr = addr;
1070 			break;
1071 		default:
1072 			/* ISIF linear tbl0 address */
1073 			isif_cfg.linear_tbl1_addr = addr;
1074 			break;
1075 		}
1076 		i++;
1077 	}
1078 	isif_cfg.dev = &pdev->dev;
1079 
1080 	printk(KERN_NOTICE "%s is registered with vpfe.\n",
1081 		isif_hw_dev.name);
1082 	return 0;
1083 fail_base_iomap:
1084 	release_mem_region(res->start, resource_size(res));
1085 	i--;
1086 fail_nobase_res:
1087 	if (isif_cfg.base_addr)
1088 		iounmap(isif_cfg.base_addr);
1089 	if (isif_cfg.linear_tbl0_addr)
1090 		iounmap(isif_cfg.linear_tbl0_addr);
1091 
1092 	while (i >= 0) {
1093 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1094 		if (res)
1095 			release_mem_region(res->start, resource_size(res));
1096 		i--;
1097 	}
1098 	vpfe_unregister_ccdc_device(&isif_hw_dev);
1099 	return status;
1100 }
1101 
isif_remove(struct platform_device * pdev)1102 static int isif_remove(struct platform_device *pdev)
1103 {
1104 	struct resource	*res;
1105 	int i = 0;
1106 
1107 	iounmap(isif_cfg.base_addr);
1108 	iounmap(isif_cfg.linear_tbl0_addr);
1109 	iounmap(isif_cfg.linear_tbl1_addr);
1110 	while (i < 3) {
1111 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1112 		if (res)
1113 			release_mem_region(res->start, resource_size(res));
1114 		i++;
1115 	}
1116 	vpfe_unregister_ccdc_device(&isif_hw_dev);
1117 	return 0;
1118 }
1119 
1120 static struct platform_driver isif_driver = {
1121 	.driver = {
1122 		.name	= "isif",
1123 	},
1124 	.remove = isif_remove,
1125 	.probe = isif_probe,
1126 };
1127 
1128 module_platform_driver(isif_driver);
1129 
1130 MODULE_LICENSE("GPL");
1131