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