cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

isif.c (29594B)


      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 */
     32static 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 */
     69static 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 */
    128static const u32 isif_raw_bayer_pix_formats[] = {
    129	V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
    130
    131/* Raw YUV formats */
    132static const u32 isif_raw_yuv_pix_formats[] = {
    133	V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
    134
    135/* register access routines */
    136static inline u32 regr(u32 offset)
    137{
    138	return __raw_readl(isif_cfg.base_addr + offset);
    139}
    140
    141static 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 */
    147static 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
    155static 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
    163static 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
    176static 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
    190static void isif_enable_output_to_sdram(int en)
    191{
    192	reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
    193}
    194
    195static 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
    211static 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
    245static 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
    261static 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 */
    268static 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
    309static 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
    371static 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
    398static 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
    482static 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
    528static 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
    691static 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}
    701static 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
    709static 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
    728static 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
    760static 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
    779static 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
    795static 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
    803static 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
    820static 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}
    828static 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
    835static int isif_getfid(void)
    836{
    837	return (regr(MODESET) >> 15) & 0x1;
    838}
    839
    840/* misc operations */
    841static void isif_setfbaddr(unsigned long addr)
    842{
    843	regw((addr >> 21) & 0x07ff, CADU);
    844	regw((addr >> 5) & 0x0ffff, CADL);
    845}
    846
    847static 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. */
    875static 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
    969static 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
    976static 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
    983static 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
   1008static 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;
   1074fail_base_iomap:
   1075	release_mem_region(res->start, resource_size(res));
   1076	i--;
   1077fail_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
   1097static 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		release_mem_region(res->start, resource_size(res));
   1111		i++;
   1112	}
   1113	vpfe_unregister_ccdc_device(&isif_hw_dev);
   1114	return 0;
   1115}
   1116
   1117static struct platform_driver isif_driver = {
   1118	.driver = {
   1119		.name	= "isif",
   1120	},
   1121	.remove = isif_remove,
   1122	.probe = isif_probe,
   1123};
   1124
   1125module_platform_driver(isif_driver);
   1126
   1127MODULE_LICENSE("GPL");