Path: blob/master/drivers/media/video/davinci/isif.c
17621 views
/*1* Copyright (C) 2008-2009 Texas Instruments Inc2*3* This program is free software; you can redistribute it and/or modify4* it under the terms of the GNU General Public License as published by5* the Free Software Foundation; either version 2 of the License, or6* (at your option) any later version.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*13* You should have received a copy of the GNU General Public License14* along with this program; if not, write to the Free Software15* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA16*17* Image Sensor Interface (ISIF) driver18*19* This driver is for configuring the ISIF IP available on DM365 or any other20* TI SoCs. This is used for capturing yuv or bayer video or image data21* from a decoder or sensor. This IP is similar to the CCDC IP on DM35522* and DM6446, but with enhanced or additional ip blocks. The driver23* configures the ISIF upon commands from the vpfe bridge driver through24* ccdc_hw_device interface.25*26* TODO: 1) Raw bayer parameter settings and bayer capture27* 2) Add support for control ioctl28*/29#include <linux/delay.h>30#include <linux/platform_device.h>31#include <linux/uaccess.h>32#include <linux/io.h>33#include <linux/videodev2.h>34#include <linux/clk.h>35#include <linux/err.h>3637#include <mach/mux.h>3839#include <media/davinci/isif.h>40#include <media/davinci/vpss.h>4142#include "isif_regs.h"43#include "ccdc_hw_device.h"4445/* Defaults for module configuration parameters */46static struct isif_config_params_raw isif_config_defaults = {47.linearize = {48.en = 0,49.corr_shft = ISIF_NO_SHIFT,50.scale_fact = {1, 0},51},52.df_csc = {53.df_or_csc = 0,54.csc = {55.en = 0,56},57},58.dfc = {59.en = 0,60},61.bclamp = {62.en = 0,63},64.gain_offset = {65.gain = {66.r_ye = {1, 0},67.gr_cy = {1, 0},68.gb_g = {1, 0},69.b_mg = {1, 0},70},71},72.culling = {73.hcpat_odd = 0xff,74.hcpat_even = 0xff,75.vcpat = 0xff,76},77.compress = {78.alg = ISIF_ALAW,79},80};8182/* ISIF operation configuration */83static struct isif_oper_config {84struct device *dev;85enum vpfe_hw_if_type if_type;86struct isif_ycbcr_config ycbcr;87struct isif_params_raw bayer;88enum isif_data_pack data_pack;89/* Master clock */90struct clk *mclk;91/* ISIF base address */92void __iomem *base_addr;93/* ISIF Linear Table 0 */94void __iomem *linear_tbl0_addr;95/* ISIF Linear Table 1 */96void __iomem *linear_tbl1_addr;97} isif_cfg = {98.ycbcr = {99.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,100.frm_fmt = CCDC_FRMFMT_INTERLACED,101.win = ISIF_WIN_NTSC,102.fid_pol = VPFE_PINPOL_POSITIVE,103.vd_pol = VPFE_PINPOL_POSITIVE,104.hd_pol = VPFE_PINPOL_POSITIVE,105.pix_order = CCDC_PIXORDER_CBYCRY,106.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,107},108.bayer = {109.pix_fmt = CCDC_PIXFMT_RAW,110.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,111.win = ISIF_WIN_VGA,112.fid_pol = VPFE_PINPOL_POSITIVE,113.vd_pol = VPFE_PINPOL_POSITIVE,114.hd_pol = VPFE_PINPOL_POSITIVE,115.gain = {116.r_ye = {1, 0},117.gr_cy = {1, 0},118.gb_g = {1, 0},119.b_mg = {1, 0},120},121.cfa_pat = ISIF_CFA_PAT_MOSAIC,122.data_msb = ISIF_BIT_MSB_11,123.config_params = {124.data_shift = ISIF_NO_SHIFT,125.col_pat_field0 = {126.olop = ISIF_GREEN_BLUE,127.olep = ISIF_BLUE,128.elop = ISIF_RED,129.elep = ISIF_GREEN_RED,130},131.col_pat_field1 = {132.olop = ISIF_GREEN_BLUE,133.olep = ISIF_BLUE,134.elop = ISIF_RED,135.elep = ISIF_GREEN_RED,136},137.test_pat_gen = 0,138},139},140.data_pack = ISIF_DATA_PACK8,141};142143/* Raw Bayer formats */144static const u32 isif_raw_bayer_pix_formats[] = {145V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};146147/* Raw YUV formats */148static const u32 isif_raw_yuv_pix_formats[] = {149V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};150151/* register access routines */152static inline u32 regr(u32 offset)153{154return __raw_readl(isif_cfg.base_addr + offset);155}156157static inline void regw(u32 val, u32 offset)158{159__raw_writel(val, isif_cfg.base_addr + offset);160}161162/* reg_modify() - read, modify and write register */163static inline u32 reg_modify(u32 mask, u32 val, u32 offset)164{165u32 new_val = (regr(offset) & ~mask) | (val & mask);166167regw(new_val, offset);168return new_val;169}170171static inline void regw_lin_tbl(u32 val, u32 offset, int i)172{173if (!i)174__raw_writel(val, isif_cfg.linear_tbl0_addr + offset);175else176__raw_writel(val, isif_cfg.linear_tbl1_addr + offset);177}178179static void isif_disable_all_modules(void)180{181/* disable BC */182regw(0, CLAMPCFG);183/* disable vdfc */184regw(0, DFCCTL);185/* disable CSC */186regw(0, CSCCTL);187/* disable linearization */188regw(0, LINCFG0);189/* disable other modules here as they are supported */190}191192static void isif_enable(int en)193{194if (!en) {195/* Before disable isif, disable all ISIF modules */196isif_disable_all_modules();197/*198* wait for next VD. Assume lowest scan rate is 12 Hz. So199* 100 msec delay is good enough200*/201msleep(100);202}203reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);204}205206static void isif_enable_output_to_sdram(int en)207{208reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);209}210211static void isif_config_culling(struct isif_cul *cul)212{213u32 val;214215/* Horizontal pattern */216val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;217regw(val, CULH);218219/* vertical pattern */220regw(cul->vcpat, CULV);221222/* LPF */223reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,224cul->en_lpf << ISIF_LPF_SHIFT, MODESET);225}226227static void isif_config_gain_offset(void)228{229struct isif_gain_offsets_adj *gain_off_p =230&isif_cfg.bayer.config_params.gain_offset;231u32 val;232233val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |234(!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |235(!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |236(!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |237(!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |238(!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);239240reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);241242val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |243gain_off_p->gain.r_ye.decimal;244regw(val, CRGAIN);245246val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |247gain_off_p->gain.gr_cy.decimal;248regw(val, CGRGAIN);249250val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |251gain_off_p->gain.gb_g.decimal;252regw(val, CGBGAIN);253254val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |255gain_off_p->gain.b_mg.decimal;256regw(val, CBGAIN);257258regw(gain_off_p->offset, COFSTA);259}260261static void isif_restore_defaults(void)262{263enum vpss_ccdc_source_sel source = VPSS_CCDCIN;264265dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");266isif_cfg.bayer.config_params = isif_config_defaults;267/* Enable clock to ISIF, IPIPEIF and BL */268vpss_enable_clock(VPSS_CCDC_CLOCK, 1);269vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);270vpss_enable_clock(VPSS_BL_CLOCK, 1);271/* Set default offset and gain */272isif_config_gain_offset();273vpss_select_ccdc_source(source);274dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");275}276277static int isif_open(struct device *device)278{279isif_restore_defaults();280return 0;281}282283/* This function will configure the window size to be capture in ISIF reg */284static void isif_setwin(struct v4l2_rect *image_win,285enum ccdc_frmfmt frm_fmt, int ppc)286{287int horz_start, horz_nr_pixels;288int vert_start, vert_nr_lines;289int mid_img = 0;290291dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");292/*293* ppc - per pixel count. indicates how many pixels per cell294* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.295* raw capture this is 1296*/297horz_start = image_win->left << (ppc - 1);298horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;299300/* Writing the horizontal info into the registers */301regw(horz_start & START_PX_HOR_MASK, SPH);302regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);303vert_start = image_win->top;304305if (frm_fmt == CCDC_FRMFMT_INTERLACED) {306vert_nr_lines = (image_win->height >> 1) - 1;307vert_start >>= 1;308/* To account for VD since line 0 doesn't have any data */309vert_start += 1;310} else {311/* To account for VD since line 0 doesn't have any data */312vert_start += 1;313vert_nr_lines = image_win->height - 1;314/* configure VDINT0 and VDINT1 */315mid_img = vert_start + (image_win->height / 2);316regw(mid_img, VDINT1);317}318319regw(0, VDINT0);320regw(vert_start & START_VER_ONE_MASK, SLV0);321regw(vert_start & START_VER_TWO_MASK, SLV1);322regw(vert_nr_lines & NUM_LINES_VER, LNV);323}324325static void isif_config_bclamp(struct isif_black_clamp *bc)326{327u32 val;328329/*330* DC Offset is always added to image data irrespective of bc enable331* status332*/333regw(bc->dc_offset, CLDCOFST);334335if (bc->en) {336val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;337338/* Enable BC and horizontal clamp caculation paramaters */339val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);340341regw(val, CLAMPCFG);342343if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {344/*345* Window count for calculation346* Base window selection347* pixel limit348* Horizontal size of window349* vertical size of the window350* Horizontal start position of the window351* Vertical start position of the window352*/353val = bc->horz.win_count_calc |354((!!bc->horz.base_win_sel_calc) <<355ISIF_HORZ_BC_WIN_SEL_SHIFT) |356((!!bc->horz.clamp_pix_limit) <<357ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |358(bc->horz.win_h_sz_calc <<359ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |360(bc->horz.win_v_sz_calc <<361ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);362regw(val, CLHWIN0);363364regw(bc->horz.win_start_h_calc, CLHWIN1);365regw(bc->horz.win_start_v_calc, CLHWIN2);366}367368/* vertical clamp caculation paramaters */369370/* Reset clamp value sel for previous line */371val |=372(bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |373(bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);374regw(val, CLVWIN0);375376/* Optical Black horizontal start position */377regw(bc->vert.ob_start_h, CLVWIN1);378/* Optical Black vertical start position */379regw(bc->vert.ob_start_v, CLVWIN2);380/* Optical Black vertical size for calculation */381regw(bc->vert.ob_v_sz_calc, CLVWIN3);382/* Vertical start position for BC subtraction */383regw(bc->vert_start_sub, CLSV);384}385}386387static void isif_config_linearization(struct isif_linearize *linearize)388{389u32 val, i;390391if (!linearize->en) {392regw(0, LINCFG0);393return;394}395396/* shift value for correction & enable linearization (set lsb) */397val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;398regw(val, LINCFG0);399400/* Scale factor */401val = ((!!linearize->scale_fact.integer) <<402ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |403linearize->scale_fact.decimal;404regw(val, LINCFG1);405406for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {407if (i % 2)408regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);409else410regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);411}412}413414static int isif_config_dfc(struct isif_dfc *vdfc)415{416/* initialize retries to loop for max ~ 250 usec */417u32 val, count, retries = loops_per_jiffy / (4000/HZ);418int i;419420if (!vdfc->en)421return 0;422423/* Correction mode */424val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);425426/* Correct whole line or partial */427if (vdfc->corr_whole_line)428val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;429430/* level shift value */431val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;432433regw(val, DFCCTL);434435/* Defect saturation level */436regw(vdfc->def_sat_level, VDFSATLV);437438regw(vdfc->table[0].pos_vert, DFCMEM0);439regw(vdfc->table[0].pos_horz, DFCMEM1);440if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||441vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {442regw(vdfc->table[0].level_at_pos, DFCMEM2);443regw(vdfc->table[0].level_up_pixels, DFCMEM3);444regw(vdfc->table[0].level_low_pixels, DFCMEM4);445}446447/* set DFCMARST and set DFCMWR */448val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;449regw(val, DFCMEMCTL);450451count = retries;452while (count && (regr(DFCMEMCTL) & 0x1))453count--;454455if (!count) {456dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");457return -1;458}459460for (i = 1; i < vdfc->num_vdefects; i++) {461regw(vdfc->table[i].pos_vert, DFCMEM0);462regw(vdfc->table[i].pos_horz, DFCMEM1);463if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||464vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {465regw(vdfc->table[i].level_at_pos, DFCMEM2);466regw(vdfc->table[i].level_up_pixels, DFCMEM3);467regw(vdfc->table[i].level_low_pixels, DFCMEM4);468}469val = regr(DFCMEMCTL);470/* clear DFCMARST and set DFCMWR */471val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);472val |= 1;473regw(val, DFCMEMCTL);474475count = retries;476while (count && (regr(DFCMEMCTL) & 0x1))477count--;478479if (!count) {480dev_err(isif_cfg.dev,481"defect table write timeout !!!\n");482return -1;483}484}485if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {486/* Extra cycle needed */487regw(0, DFCMEM0);488regw(0x1FFF, DFCMEM1);489regw(1, DFCMEMCTL);490}491492/* enable VDFC */493reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),494DFCCTL);495return 0;496}497498static void isif_config_csc(struct isif_df_csc *df_csc)499{500u32 val1 = 0, val2 = 0, i;501502if (!df_csc->csc.en) {503regw(0, CSCCTL);504return;505}506for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {507if ((i % 2) == 0) {508/* CSCM - LSB */509val1 = (df_csc->csc.coeff[i].integer <<510ISIF_CSC_COEF_INTEG_SHIFT) |511df_csc->csc.coeff[i].decimal;512} else {513514/* CSCM - MSB */515val2 = (df_csc->csc.coeff[i].integer <<516ISIF_CSC_COEF_INTEG_SHIFT) |517df_csc->csc.coeff[i].decimal;518val2 <<= ISIF_CSCM_MSB_SHIFT;519val2 |= val1;520regw(val2, (CSCM0 + ((i - 1) << 1)));521}522}523524/* program the active area */525regw(df_csc->start_pix, FMTSPH);526/*527* one extra pixel as required for CSC. Actually number of528* pixel - 1 should be configured in this register. So we529* need to subtract 1 before writing to FMTSPH, but we will530* not do this since csc requires one extra pixel531*/532regw(df_csc->num_pixels, FMTLNH);533regw(df_csc->start_line, FMTSLV);534/*535* one extra line as required for CSC. See reason documented for536* num_pixels537*/538regw(df_csc->num_lines, FMTLNV);539540/* Enable CSC */541regw(1, CSCCTL);542}543544static int isif_config_raw(void)545{546struct isif_params_raw *params = &isif_cfg.bayer;547struct isif_config_params_raw *module_params =548&isif_cfg.bayer.config_params;549struct vpss_pg_frame_size frame_size;550struct vpss_sync_pol sync;551u32 val;552553dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");554555/*556* Configure CCDCFG register:-557* Set CCD Not to swap input since input is RAW data558* Set FID detection function to Latch at V-Sync559* Set WENLOG - isif valid area560* Set TRGSEL561* Set EXTRG562* Packed to 8 or 16 bits563*/564565val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |566ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |567ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;568569dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);570regw(val, CCDCFG);571572/*573* Configure the vertical sync polarity(MODESET.VDPOL)574* Configure the horizontal sync polarity (MODESET.HDPOL)575* Configure frame id polarity (MODESET.FLDPOL)576* Configure data polarity577* Configure External WEN Selection578* Configure frame format(progressive or interlace)579* Configure pixel format (Input mode)580* Configure the data shift581*/582583val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |584(params->hd_pol << ISIF_HD_POL_SHIFT) |585(params->fid_pol << ISIF_FID_POL_SHIFT) |586(ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |587(ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |588(params->frm_fmt << ISIF_FRM_FMT_SHIFT) |589(params->pix_fmt << ISIF_INPUT_SHIFT) |590(params->config_params.data_shift << ISIF_DATASFT_SHIFT);591592regw(val, MODESET);593dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);594595/*596* Configure GAMMAWD register597* CFA pattern setting598*/599val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;600601/* Gamma msb */602if (module_params->compress.alg == ISIF_ALAW)603val |= ISIF_ALAW_ENABLE;604605val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);606regw(val, CGAMMAWD);607608/* Configure DPCM compression settings */609if (module_params->compress.alg == ISIF_DPCM) {610val = BIT(ISIF_DPCM_EN_SHIFT) |611(module_params->compress.pred <<612ISIF_DPCM_PREDICTOR_SHIFT);613}614615regw(val, MISC);616617/* Configure Gain & Offset */618isif_config_gain_offset();619620/* Configure Color pattern */621val = (params->config_params.col_pat_field0.olop) |622(params->config_params.col_pat_field0.olep << 2) |623(params->config_params.col_pat_field0.elop << 4) |624(params->config_params.col_pat_field0.elep << 6) |625(params->config_params.col_pat_field1.olop << 8) |626(params->config_params.col_pat_field1.olep << 10) |627(params->config_params.col_pat_field1.elop << 12) |628(params->config_params.col_pat_field1.elep << 14);629regw(val, CCOLP);630dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);631632/* Configure HSIZE register */633val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;634635/* calculate line offset in 32 bytes based on pack value */636if (isif_cfg.data_pack == ISIF_PACK_8BIT)637val |= ((params->win.width + 31) >> 5);638else if (isif_cfg.data_pack == ISIF_PACK_12BIT)639val |= (((params->win.width +640(params->win.width >> 2)) + 31) >> 5);641else642val |= (((params->win.width * 2) + 31) >> 5);643regw(val, HSIZE);644645/* Configure SDOFST register */646if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {647if (params->image_invert_en) {648/* For interlace inverse mode */649regw(0x4B6D, SDOFST);650dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");651} else {652/* For interlace non inverse mode */653regw(0x0B6D, SDOFST);654dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");655}656} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {657if (params->image_invert_en) {658/* For progressive inverse mode */659regw(0x4000, SDOFST);660dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");661} else {662/* For progressive non inverse mode */663regw(0x0000, SDOFST);664dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");665}666}667668/* Configure video window */669isif_setwin(¶ms->win, params->frm_fmt, 1);670671/* Configure Black Clamp */672isif_config_bclamp(&module_params->bclamp);673674/* Configure Vertical Defection Pixel Correction */675if (isif_config_dfc(&module_params->dfc) < 0)676return -EFAULT;677678if (!module_params->df_csc.df_or_csc)679/* Configure Color Space Conversion */680isif_config_csc(&module_params->df_csc);681682isif_config_linearization(&module_params->linearize);683684/* Configure Culling */685isif_config_culling(&module_params->culling);686687/* Configure horizontal and vertical offsets(DFC,LSC,Gain) */688regw(module_params->horz_offset, DATAHOFST);689regw(module_params->vert_offset, DATAVOFST);690691/* Setup test pattern if enabled */692if (params->config_params.test_pat_gen) {693/* Use the HD/VD pol settings from user */694sync.ccdpg_hdpol = params->hd_pol;695sync.ccdpg_vdpol = params->vd_pol;696dm365_vpss_set_sync_pol(sync);697frame_size.hlpfr = isif_cfg.bayer.win.width;698frame_size.pplen = isif_cfg.bayer.win.height;699dm365_vpss_set_pg_frame_size(frame_size);700vpss_select_ccdc_source(VPSS_PGLPBK);701}702703dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");704return 0;705}706707static int isif_set_buftype(enum ccdc_buftype buf_type)708{709if (isif_cfg.if_type == VPFE_RAW_BAYER)710isif_cfg.bayer.buf_type = buf_type;711else712isif_cfg.ycbcr.buf_type = buf_type;713714return 0;715716}717static enum ccdc_buftype isif_get_buftype(void)718{719if (isif_cfg.if_type == VPFE_RAW_BAYER)720return isif_cfg.bayer.buf_type;721722return isif_cfg.ycbcr.buf_type;723}724725static int isif_enum_pix(u32 *pix, int i)726{727int ret = -EINVAL;728729if (isif_cfg.if_type == VPFE_RAW_BAYER) {730if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {731*pix = isif_raw_bayer_pix_formats[i];732ret = 0;733}734} else {735if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {736*pix = isif_raw_yuv_pix_formats[i];737ret = 0;738}739}740741return ret;742}743744static int isif_set_pixel_format(unsigned int pixfmt)745{746if (isif_cfg.if_type == VPFE_RAW_BAYER) {747if (pixfmt == V4L2_PIX_FMT_SBGGR8) {748if ((isif_cfg.bayer.config_params.compress.alg !=749ISIF_ALAW) &&750(isif_cfg.bayer.config_params.compress.alg !=751ISIF_DPCM)) {752dev_dbg(isif_cfg.dev,753"Either configure A-Law or DPCM\n");754return -EINVAL;755}756isif_cfg.data_pack = ISIF_PACK_8BIT;757} else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {758isif_cfg.bayer.config_params.compress.alg =759ISIF_NO_COMPRESSION;760isif_cfg.data_pack = ISIF_PACK_16BIT;761} else762return -EINVAL;763isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;764} else {765if (pixfmt == V4L2_PIX_FMT_YUYV)766isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;767else if (pixfmt == V4L2_PIX_FMT_UYVY)768isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;769else770return -EINVAL;771isif_cfg.data_pack = ISIF_PACK_8BIT;772}773return 0;774}775776static u32 isif_get_pixel_format(void)777{778u32 pixfmt;779780if (isif_cfg.if_type == VPFE_RAW_BAYER)781if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||782isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)783pixfmt = V4L2_PIX_FMT_SBGGR8;784else785pixfmt = V4L2_PIX_FMT_SBGGR16;786else {787if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)788pixfmt = V4L2_PIX_FMT_YUYV;789else790pixfmt = V4L2_PIX_FMT_UYVY;791}792return pixfmt;793}794795static int isif_set_image_window(struct v4l2_rect *win)796{797if (isif_cfg.if_type == VPFE_RAW_BAYER) {798isif_cfg.bayer.win.top = win->top;799isif_cfg.bayer.win.left = win->left;800isif_cfg.bayer.win.width = win->width;801isif_cfg.bayer.win.height = win->height;802} else {803isif_cfg.ycbcr.win.top = win->top;804isif_cfg.ycbcr.win.left = win->left;805isif_cfg.ycbcr.win.width = win->width;806isif_cfg.ycbcr.win.height = win->height;807}808return 0;809}810811static void isif_get_image_window(struct v4l2_rect *win)812{813if (isif_cfg.if_type == VPFE_RAW_BAYER)814*win = isif_cfg.bayer.win;815else816*win = isif_cfg.ycbcr.win;817}818819static unsigned int isif_get_line_length(void)820{821unsigned int len;822823if (isif_cfg.if_type == VPFE_RAW_BAYER) {824if (isif_cfg.data_pack == ISIF_PACK_8BIT)825len = ((isif_cfg.bayer.win.width));826else if (isif_cfg.data_pack == ISIF_PACK_12BIT)827len = (((isif_cfg.bayer.win.width * 2) +828(isif_cfg.bayer.win.width >> 2)));829else830len = (((isif_cfg.bayer.win.width * 2)));831} else832len = (((isif_cfg.ycbcr.win.width * 2)));833return ALIGN(len, 32);834}835836static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)837{838if (isif_cfg.if_type == VPFE_RAW_BAYER)839isif_cfg.bayer.frm_fmt = frm_fmt;840else841isif_cfg.ycbcr.frm_fmt = frm_fmt;842return 0;843}844static enum ccdc_frmfmt isif_get_frame_format(void)845{846if (isif_cfg.if_type == VPFE_RAW_BAYER)847return isif_cfg.bayer.frm_fmt;848return isif_cfg.ycbcr.frm_fmt;849}850851static int isif_getfid(void)852{853return (regr(MODESET) >> 15) & 0x1;854}855856/* misc operations */857static void isif_setfbaddr(unsigned long addr)858{859regw((addr >> 21) & 0x07ff, CADU);860regw((addr >> 5) & 0x0ffff, CADL);861}862863static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)864{865isif_cfg.if_type = params->if_type;866867switch (params->if_type) {868case VPFE_BT656:869case VPFE_BT656_10BIT:870case VPFE_YCBCR_SYNC_8:871isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;872isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;873break;874case VPFE_BT1120:875case VPFE_YCBCR_SYNC_16:876isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;877isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;878break;879case VPFE_RAW_BAYER:880isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;881break;882default:883dev_dbg(isif_cfg.dev, "Invalid interface type\n");884return -EINVAL;885}886887return 0;888}889890/* This function will configure ISIF for YCbCr parameters. */891static int isif_config_ycbcr(void)892{893struct isif_ycbcr_config *params = &isif_cfg.ycbcr;894struct vpss_pg_frame_size frame_size;895u32 modeset = 0, ccdcfg = 0;896struct vpss_sync_pol sync;897898dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");899900/* configure pixel format or input mode */901modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |902(params->frm_fmt << ISIF_FRM_FMT_SHIFT) |903(params->fid_pol << ISIF_FID_POL_SHIFT) |904(params->hd_pol << ISIF_HD_POL_SHIFT) |905(params->vd_pol << ISIF_VD_POL_SHIFT);906907/* pack the data to 8-bit ISIFCFG */908switch (isif_cfg.if_type) {909case VPFE_BT656:910if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {911dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");912return -EINVAL;913}914modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);915regw(3, REC656IF);916ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;917break;918case VPFE_BT656_10BIT:919if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {920dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");921return -EINVAL;922}923/* setup BT.656, embedded sync */924regw(3, REC656IF);925/* enable 10 bit mode in ccdcfg */926ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |927ISIF_BW656_ENABLE;928break;929case VPFE_BT1120:930if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {931dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");932return -EINVAL;933}934regw(3, REC656IF);935break;936937case VPFE_YCBCR_SYNC_8:938ccdcfg |= ISIF_DATA_PACK8;939ccdcfg |= ISIF_YCINSWP_YCBCR;940if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {941dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");942return -EINVAL;943}944break;945case VPFE_YCBCR_SYNC_16:946if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {947dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");948return -EINVAL;949}950break;951default:952/* should never come here */953dev_dbg(isif_cfg.dev, "Invalid interface type\n");954return -EINVAL;955}956957regw(modeset, MODESET);958959/* Set up pix order */960ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;961962regw(ccdcfg, CCDCFG);963964/* configure video window */965if ((isif_cfg.if_type == VPFE_BT1120) ||966(isif_cfg.if_type == VPFE_YCBCR_SYNC_16))967isif_setwin(¶ms->win, params->frm_fmt, 1);968else969isif_setwin(¶ms->win, params->frm_fmt, 2);970971/*972* configure the horizontal line offset973* this is done by rounding up width to a multiple of 16 pixels974* and multiply by two to account for y:cb:cr 4:2:2 data975*/976regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);977978/* configure the memory line offset */979if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&980(params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))981/* two fields are interleaved in memory */982regw(0x00000249, SDOFST);983984/* Setup test pattern if enabled */985if (isif_cfg.bayer.config_params.test_pat_gen) {986sync.ccdpg_hdpol = params->hd_pol;987sync.ccdpg_vdpol = params->vd_pol;988dm365_vpss_set_sync_pol(sync);989dm365_vpss_set_pg_frame_size(frame_size);990}991return 0;992}993994static int isif_configure(void)995{996if (isif_cfg.if_type == VPFE_RAW_BAYER)997return isif_config_raw();998return isif_config_ycbcr();999}10001001static int isif_close(struct device *device)1002{1003/* copy defaults to module params */1004isif_cfg.bayer.config_params = isif_config_defaults;1005return 0;1006}10071008static struct ccdc_hw_device isif_hw_dev = {1009.name = "ISIF",1010.owner = THIS_MODULE,1011.hw_ops = {1012.open = isif_open,1013.close = isif_close,1014.enable = isif_enable,1015.enable_out_to_sdram = isif_enable_output_to_sdram,1016.set_hw_if_params = isif_set_hw_if_params,1017.configure = isif_configure,1018.set_buftype = isif_set_buftype,1019.get_buftype = isif_get_buftype,1020.enum_pix = isif_enum_pix,1021.set_pixel_format = isif_set_pixel_format,1022.get_pixel_format = isif_get_pixel_format,1023.set_frame_format = isif_set_frame_format,1024.get_frame_format = isif_get_frame_format,1025.set_image_window = isif_set_image_window,1026.get_image_window = isif_get_image_window,1027.get_line_length = isif_get_line_length,1028.setfbaddr = isif_setfbaddr,1029.getfid = isif_getfid,1030},1031};10321033static int __init isif_probe(struct platform_device *pdev)1034{1035void (*setup_pinmux)(void);1036struct resource *res;1037void *__iomem addr;1038int status = 0, i;10391040/*1041* first try to register with vpfe. If not correct platform, then we1042* don't have to iomap1043*/1044status = vpfe_register_ccdc_device(&isif_hw_dev);1045if (status < 0)1046return status;10471048/* Get and enable Master clock */1049isif_cfg.mclk = clk_get(&pdev->dev, "master");1050if (IS_ERR(isif_cfg.mclk)) {1051status = PTR_ERR(isif_cfg.mclk);1052goto fail_mclk;1053}1054if (clk_enable(isif_cfg.mclk)) {1055status = -ENODEV;1056goto fail_mclk;1057}10581059/* Platform data holds setup_pinmux function ptr */1060if (NULL == pdev->dev.platform_data) {1061status = -ENODEV;1062goto fail_mclk;1063}1064setup_pinmux = pdev->dev.platform_data;1065/*1066* setup Mux configuration for ccdc which may be different for1067* different SoCs using this CCDC1068*/1069setup_pinmux();10701071i = 0;1072/* Get the ISIF base address, linearization table0 and table1 addr. */1073while (i < 3) {1074res = platform_get_resource(pdev, IORESOURCE_MEM, i);1075if (!res) {1076status = -ENODEV;1077goto fail_nobase_res;1078}1079res = request_mem_region(res->start, resource_size(res),1080res->name);1081if (!res) {1082status = -EBUSY;1083goto fail_nobase_res;1084}1085addr = ioremap_nocache(res->start, resource_size(res));1086if (!addr) {1087status = -ENOMEM;1088goto fail_base_iomap;1089}1090switch (i) {1091case 0:1092/* ISIF base address */1093isif_cfg.base_addr = addr;1094break;1095case 1:1096/* ISIF linear tbl0 address */1097isif_cfg.linear_tbl0_addr = addr;1098break;1099default:1100/* ISIF linear tbl0 address */1101isif_cfg.linear_tbl1_addr = addr;1102break;1103}1104i++;1105}1106isif_cfg.dev = &pdev->dev;11071108printk(KERN_NOTICE "%s is registered with vpfe.\n",1109isif_hw_dev.name);1110return 0;1111fail_base_iomap:1112release_mem_region(res->start, resource_size(res));1113i--;1114fail_nobase_res:1115if (isif_cfg.base_addr)1116iounmap(isif_cfg.base_addr);1117if (isif_cfg.linear_tbl0_addr)1118iounmap(isif_cfg.linear_tbl0_addr);11191120while (i >= 0) {1121res = platform_get_resource(pdev, IORESOURCE_MEM, i);1122release_mem_region(res->start, resource_size(res));1123i--;1124}1125fail_mclk:1126clk_put(isif_cfg.mclk);1127vpfe_unregister_ccdc_device(&isif_hw_dev);1128return status;1129}11301131static int isif_remove(struct platform_device *pdev)1132{1133struct resource *res;1134int i = 0;11351136iounmap(isif_cfg.base_addr);1137iounmap(isif_cfg.linear_tbl0_addr);1138iounmap(isif_cfg.linear_tbl1_addr);1139while (i < 3) {1140res = platform_get_resource(pdev, IORESOURCE_MEM, i);1141if (res)1142release_mem_region(res->start, resource_size(res));1143i++;1144}1145vpfe_unregister_ccdc_device(&isif_hw_dev);1146return 0;1147}11481149static struct platform_driver isif_driver = {1150.driver = {1151.name = "isif",1152.owner = THIS_MODULE,1153},1154.remove = __devexit_p(isif_remove),1155.probe = isif_probe,1156};11571158static int __init isif_init(void)1159{1160return platform_driver_register(&isif_driver);1161}11621163static void isif_exit(void)1164{1165platform_driver_unregister(&isif_driver);1166}11671168module_init(isif_init);1169module_exit(isif_exit);11701171MODULE_LICENSE("GPL");117211731174