diff options
Diffstat (limited to 'drivers/media/video/davinci')
-rw-r--r-- | drivers/media/video/davinci/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/video/davinci/dm355_ccdc.c | 410 | ||||
-rw-r--r-- | drivers/media/video/davinci/dm644x_ccdc.c | 361 | ||||
-rw-r--r-- | drivers/media/video/davinci/isif.c | 1172 | ||||
-rw-r--r-- | drivers/media/video/davinci/isif_regs.h | 269 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpfe_capture.c | 131 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpss.c | 289 |
7 files changed, 2172 insertions, 461 deletions
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index 1a8b8f3f182..a37955745aa 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o +obj-$(CONFIG_VIDEO_ISIF) += isif.o diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c index 31439001637..c29ac88ffd7 100644 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ b/drivers/media/video/davinci/dm355_ccdc.c @@ -37,8 +37,12 @@ #include <linux/platform_device.h> #include <linux/uaccess.h> #include <linux/videodev2.h> +#include <linux/clk.h> +#include <linux/err.h> + #include <media/davinci/dm355_ccdc.h> #include <media/davinci/vpss.h> + #include "dm355_ccdc_regs.h" #include "ccdc_hw_device.h" @@ -46,67 +50,75 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CCDC Driver for DM355"); MODULE_AUTHOR("Texas Instruments"); -static struct device *dev; - -/* Object for CCDC raw mode */ -static struct ccdc_params_raw ccdc_hw_params_raw = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = 256, - .gb_g = 256, - .gr_cy = 256, - .b_mg = 256 - }, - .config_params = { - .datasft = 2, - .data_sz = CCDC_DATA_10BITS, - .mfilt1 = CCDC_NO_MEDIAN_FILTER1, - .mfilt2 = CCDC_NO_MEDIAN_FILTER2, - .alaw = { - .gama_wd = 2, +static struct ccdc_oper_config { + struct device *dev; + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* Master clock */ + struct clk *mclk; + /* slave clock */ + struct clk *sclk; + /* ccdc base address */ + void __iomem *base_addr; +} ccdc_cfg = { + /* Raw configurations */ + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = 256, + .gb_g = 256, + .gr_cy = 256, + .b_mg = 256 }, - .blk_clamp = { - .sample_pixel = 1, - .dc_sub = 25 - }, - .col_pat_field0 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - .col_pat_field1 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED + .config_params = { + .datasft = 2, + .mfilt1 = CCDC_NO_MEDIAN_FILTER1, + .mfilt2 = CCDC_NO_MEDIAN_FILTER2, + .alaw = { + .gama_wd = 2, + }, + .blk_clamp = { + .sample_pixel = 1, + .dc_sub = 25 + }, + .col_pat_field0 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED + }, + .col_pat_field1 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED + }, }, }, + /* YCbCr configuration */ + .ycbcr = { + .win = CCDC_WIN_PAL, + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .bt656_enable = 1, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED + }, }; -/* Object for CCDC ycbcr mode */ -static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { - .win = CCDC_WIN_PAL, - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED -}; - -static enum vpfe_hw_if_type ccdc_if_type; -static void *__iomem ccdc_base_addr; -static int ccdc_addr_size; - /* Raw Bayer formats */ static u32 ccdc_raw_bayer_pix_formats[] = {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; @@ -118,18 +130,12 @@ static u32 ccdc_raw_yuv_pix_formats[] = /* register access routines */ static inline u32 regr(u32 offset) { - return __raw_readl(ccdc_base_addr + offset); + return __raw_readl(ccdc_cfg.base_addr + offset); } static inline void regw(u32 val, u32 offset) { - __raw_writel(val, ccdc_base_addr + offset); -} - -static void ccdc_set_ccdc_base(void *addr, int size) -{ - ccdc_base_addr = addr; - ccdc_addr_size = size; + __raw_writel(val, ccdc_cfg.base_addr + offset); } static void ccdc_enable(int en) @@ -153,12 +159,12 @@ static void ccdc_enable_output_to_sdram(int en) static void ccdc_config_gain_offset(void) { /* configure gain */ - regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN); - regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN); - regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN); - regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN); + regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); + regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); + regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); + regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); /* configure offset */ - regw(ccdc_hw_params_raw.ccdc_offset, OFFSET); + regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); } /* @@ -169,7 +175,7 @@ static int ccdc_restore_defaults(void) { int i; - dev_dbg(dev, "\nstarting ccdc_restore_defaults..."); + dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); /* set all registers to zero */ for (i = 0; i <= CCDC_REG_LAST; i += 4) regw(0, i); @@ -180,30 +186,29 @@ static int ccdc_restore_defaults(void) regw(CULH_DEFAULT, CULH); regw(CULV_DEFAULT, CULV); /* Set default Gain and Offset */ - ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT; - ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT; - ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT; - ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; ccdc_config_gain_offset(); regw(OUTCLIP_DEFAULT, OUTCLIP); regw(LSCCFG2_DEFAULT, LSCCFG2); /* select ccdc input */ if (vpss_select_ccdc_source(VPSS_CCDCIN)) { - dev_dbg(dev, "\ncouldn't select ccdc input source"); + dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); return -EFAULT; } /* select ccdc clock */ if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { - dev_dbg(dev, "\ncouldn't enable ccdc clock"); + dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); return -EFAULT; } - dev_dbg(dev, "\nEnd of ccdc_restore_defaults..."); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); return 0; } static int ccdc_open(struct device *device) { - dev = device; return ccdc_restore_defaults(); } @@ -226,7 +231,7 @@ static void ccdc_setwin(struct v4l2_rect *image_win, int vert_start, vert_nr_lines; int mid_img = 0; - dev_dbg(dev, "\nStarting ccdc_setwin..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); /* * ppc - per pixel count. indicates how many pixels per cell @@ -260,45 +265,46 @@ static void ccdc_setwin(struct v4l2_rect *image_win, regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); - dev_dbg(dev, "\nEnd of ccdc_setwin..."); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); } static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) { if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { - dev_dbg(dev, "Invalid value of data shift\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); return -EINVAL; } if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { - dev_dbg(dev, "Invalid value of median filter1\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); return -EINVAL; } if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { - dev_dbg(dev, "Invalid value of median filter2\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); return -EINVAL; } if ((ccdcparam->med_filt_thres < 0) || (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { - dev_dbg(dev, "Invalid value of median filter threshold\n"); + dev_dbg(ccdc_cfg.dev, + "Invalid value of median filter thresold\n"); return -EINVAL; } if (ccdcparam->data_sz < CCDC_DATA_16BITS || ccdcparam->data_sz > CCDC_DATA_8BITS) { - dev_dbg(dev, "Invalid value of data size\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); return -EINVAL; } if (ccdcparam->alaw.enable) { if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { - dev_dbg(dev, "Invalid value of ALAW\n"); + dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); return -EINVAL; } } @@ -306,12 +312,14 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) if (ccdcparam->blk_clamp.b_clamp_enable) { if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { - dev_dbg(dev, "Invalid value of sample pixel\n"); + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample pixel\n"); return -EINVAL; } if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { - dev_dbg(dev, "Invalid value of sample lines\n"); + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample lines\n"); return -EINVAL; } } @@ -325,18 +333,18 @@ static int ccdc_set_params(void __user *params) int x; /* only raw module parameters can be set through the IOCTL */ - if (ccdc_if_type != VPFE_RAW_BAYER) + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) return -EINVAL; x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); if (x) { - dev_dbg(dev, "ccdc_set_params: error in copying ccdc" + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" "params, %d\n", x); return -EFAULT; } if (!validate_ccdc_param(&ccdc_raw_params)) { - memcpy(&ccdc_hw_params_raw.config_params, + memcpy(&ccdc_cfg.bayer.config_params, &ccdc_raw_params, sizeof(ccdc_raw_params)); return 0; @@ -347,11 +355,11 @@ static int ccdc_set_params(void __user *params) /* This function will configure CCDC for YCbCr video capture */ static void ccdc_config_ycbcr(void) { - struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr; + struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; u32 temp; /* first set the CCDC power on defaults values in all registers */ - dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); ccdc_restore_defaults(); /* configure pixel format & video frame format */ @@ -403,7 +411,7 @@ static void ccdc_config_ycbcr(void) regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); } - dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); } /* @@ -483,7 +491,7 @@ int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) */ if (count) { - dev_err(dev, "defect table write timeout !!!\n"); + dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); return -1; } return 0; @@ -605,12 +613,12 @@ static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, /* This function will configure CCDC for Raw mode image capture */ static int ccdc_config_raw(void) { - struct ccdc_params_raw *params = &ccdc_hw_params_raw; + struct ccdc_params_raw *params = &ccdc_cfg.bayer; struct ccdc_config_params_raw *config_params = - &ccdc_hw_params_raw.config_params; + &ccdc_cfg.bayer.config_params; unsigned int val; - dev_dbg(dev, "\nStarting ccdc_config_raw..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); /* restore power on defaults to register */ ccdc_restore_defaults(); @@ -659,7 +667,7 @@ static int ccdc_config_raw(void) val |= (config_params->datasft & CCDC_DATASFT_MASK) << CCDC_DATASFT_SHIFT; regw(val , MODESET); - dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); /* Configure the Median Filter threshold */ regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); @@ -681,7 +689,7 @@ static int ccdc_config_raw(void) (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); regw(val, GAMMAWD); - dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); /* configure video window */ ccdc_setwin(¶ms->win, params->frm_fmt, 1); @@ -706,7 +714,7 @@ static int ccdc_config_raw(void) /* Configure the Gain & offset control */ ccdc_config_gain_offset(); - dev_dbg(dev, "\nWriting %x to COLPTN...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); /* Configure DATAOFST register */ val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << @@ -726,7 +734,7 @@ static int ccdc_config_raw(void) CCDC_HSIZE_VAL_MASK; /* adjust to multiple of 32 */ - dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", (((params->win.width) + 31) >> 5) & CCDC_HSIZE_VAL_MASK); } else { @@ -734,7 +742,7 @@ static int ccdc_config_raw(void) val |= (((params->win.width * 2) + 31) >> 5) & CCDC_HSIZE_VAL_MASK; - dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", (((params->win.width * 2) + 31) >> 5) & CCDC_HSIZE_VAL_MASK); } @@ -745,34 +753,34 @@ static int ccdc_config_raw(void) if (params->image_invert_enable) { /* For interlace inverse mode */ regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_INTERLACE_INVERSE); } else { /* For interlace non inverse mode */ regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_INTERLACE_NORMAL); } } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { if (params->image_invert_enable) { /* For progessive inverse mode */ regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_PROGRESSIVE_INVERSE); } else { /* For progessive non inverse mode */ regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); - dev_dbg(dev, "\nWriting %x to SDOFST...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", CCDC_SDOFST_PROGRESSIVE_NORMAL); } } - dev_dbg(dev, "\nend of ccdc_config_raw..."); + dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); return 0; } static int ccdc_configure(void) { - if (ccdc_if_type == VPFE_RAW_BAYER) + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) return ccdc_config_raw(); else ccdc_config_ycbcr(); @@ -781,23 +789,23 @@ static int ccdc_configure(void) static int ccdc_set_buftype(enum ccdc_buftype buf_type) { - if (ccdc_if_type == VPFE_RAW_BAYER) - ccdc_hw_params_raw.buf_type = buf_type; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_type = buf_type; else - ccdc_hw_params_ycbcr.buf_type = buf_type; + ccdc_cfg.ycbcr.buf_type = buf_type; return 0; } static enum ccdc_buftype ccdc_get_buftype(void) { - if (ccdc_if_type == VPFE_RAW_BAYER) - return ccdc_hw_params_raw.buf_type; - return ccdc_hw_params_ycbcr.buf_type; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.buf_type; + return ccdc_cfg.ycbcr.buf_type; } static int ccdc_enum_pix(u32 *pix, int i) { int ret = -EINVAL; - if (ccdc_if_type == VPFE_RAW_BAYER) { + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { *pix = ccdc_raw_bayer_pix_formats[i]; ret = 0; @@ -813,20 +821,19 @@ static int ccdc_enum_pix(u32 *pix, int i) static int ccdc_set_pixel_format(u32 pixfmt) { - struct ccdc_a_law *alaw = - &ccdc_hw_params_raw.config_params.alaw; + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - if (ccdc_if_type == VPFE_RAW_BAYER) { - ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; if (pixfmt == V4L2_PIX_FMT_SBGGR8) alaw->enable = 1; else if (pixfmt != V4L2_PIX_FMT_SBGGR16) return -EINVAL; } else { if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; else return -EINVAL; } @@ -834,17 +841,16 @@ static int ccdc_set_pixel_format(u32 pixfmt) } static u32 ccdc_get_pixel_format(void) { - struct ccdc_a_law *alaw = - &ccdc_hw_params_raw.config_params.alaw; + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; u32 pixfmt; - if (ccdc_if_type == VPFE_RAW_BAYER) + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) if (alaw->enable) pixfmt = V4L2_PIX_FMT_SBGGR8; else pixfmt = V4L2_PIX_FMT_SBGGR16; else { - if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) pixfmt = V4L2_PIX_FMT_YUYV; else pixfmt = V4L2_PIX_FMT_UYVY; @@ -853,53 +859,53 @@ static u32 ccdc_get_pixel_format(void) } static int ccdc_set_image_window(struct v4l2_rect *win) { - if (ccdc_if_type == VPFE_RAW_BAYER) - ccdc_hw_params_raw.win = *win; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.win = *win; else - ccdc_hw_params_ycbcr.win = *win; + ccdc_cfg.ycbcr.win = *win; return 0; } static void ccdc_get_image_window(struct v4l2_rect *win) { - if (ccdc_if_type == VPFE_RAW_BAYER) - *win = ccdc_hw_params_raw.win; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc_cfg.bayer.win; else - *win = ccdc_hw_params_ycbcr.win; + *win = ccdc_cfg.ycbcr.win; } static unsigned int ccdc_get_line_length(void) { struct ccdc_config_params_raw *config_params = - &ccdc_hw_params_raw.config_params; + &ccdc_cfg.bayer.config_params; unsigned int len; - if (ccdc_if_type == VPFE_RAW_BAYER) { + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { if ((config_params->alaw.enable) || (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_hw_params_raw.win.width; + len = ccdc_cfg.bayer.win.width; else - len = ccdc_hw_params_raw.win.width * 2; + len = ccdc_cfg.bayer.win.width * 2; } else - len = ccdc_hw_params_ycbcr.win.width * 2; + len = ccdc_cfg.ycbcr.win.width * 2; return ALIGN(len, 32); } static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) { - if (ccdc_if_type == VPFE_RAW_BAYER) - ccdc_hw_params_raw.frm_fmt = frm_fmt; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.frm_fmt = frm_fmt; else - ccdc_hw_params_ycbcr.frm_fmt = frm_fmt; + ccdc_cfg.ycbcr.frm_fmt = frm_fmt; return 0; } static enum ccdc_frmfmt ccdc_get_frame_format(void) { - if (ccdc_if_type == VPFE_RAW_BAYER) - return ccdc_hw_params_raw.frm_fmt; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.frm_fmt; else - return ccdc_hw_params_ycbcr.frm_fmt; + return ccdc_cfg.ycbcr.frm_fmt; } static int ccdc_getfid(void) @@ -916,14 +922,14 @@ static inline void ccdc_setfbaddr(unsigned long addr) static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) { - ccdc_if_type = params->if_type; + ccdc_cfg.if_type = params->if_type; switch (params->if_type) { case VPFE_BT656: case VPFE_YCBCR_SYNC_16: case VPFE_YCBCR_SYNC_8: - ccdc_hw_params_ycbcr.vd_pol = params->vdpol; - ccdc_hw_params_ycbcr.hd_pol = params->hdpol; + ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc_cfg.ycbcr.hd_pol = params->hdpol; break; default: /* TODO add support for raw bayer here */ @@ -938,7 +944,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { .hw_ops = { .open = ccdc_open, .close = ccdc_close, - .set_ccdc_base = ccdc_set_ccdc_base, .enable = ccdc_enable, .enable_out_to_sdram = ccdc_enable_output_to_sdram, .set_hw_if_params = ccdc_set_hw_if_params, @@ -959,19 +964,118 @@ static struct ccdc_hw_device ccdc_hw_dev = { }, }; -static int __init dm355_ccdc_init(void) +static int __init dm355_ccdc_probe(struct platform_device *pdev) { - printk(KERN_NOTICE "dm355_ccdc_init\n"); - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) - return -1; - printk(KERN_NOTICE "%s is registered with vpfe.\n", - ccdc_hw_dev.name); + void (*setup_pinmux)(void); + struct resource *res; + int status = 0; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENODEV; + goto fail_nores; + } + + res = request_mem_region(res->start, resource_size(res), res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); + if (!ccdc_cfg.base_addr) { + status = -ENOMEM; + goto fail_nomem; + } + + /* Get and enable Master clock */ + ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(ccdc_cfg.mclk)) { + status = PTR_ERR(ccdc_cfg.mclk); + goto fail_nomap; + } + if (clk_enable(ccdc_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Get and enable Slave clock */ + ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); + if (IS_ERR(ccdc_cfg.sclk)) { + status = PTR_ERR(ccdc_cfg.sclk); + goto fail_mclk; + } + if (clk_enable(ccdc_cfg.sclk)) { + status = -ENODEV; + goto fail_sclk; + } + + /* Platform data holds setup_pinmux function ptr */ + if (NULL == pdev->dev.platform_data) { + status = -ENODEV; + goto fail_sclk; + } + setup_pinmux = pdev->dev.platform_data; + /* + * setup Mux configuration for ccdc which may be different for + * different SoCs using this CCDC + */ + setup_pinmux(); + ccdc_cfg.dev = &pdev->dev; + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; +fail_sclk: + clk_put(ccdc_cfg.sclk); +fail_mclk: + clk_put(ccdc_cfg.mclk); +fail_nomap: + iounmap(ccdc_cfg.base_addr); +fail_nomem: + release_mem_region(res->start, resource_size(res)); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; } -static void __exit dm355_ccdc_exit(void) +static int dm355_ccdc_remove(struct platform_device *pdev) { + struct resource *res; + + clk_put(ccdc_cfg.mclk); + clk_put(ccdc_cfg.sclk); + iounmap(ccdc_cfg.base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static struct platform_driver dm355_ccdc_driver = { + .driver = { + .name = "dm355_ccdc", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(dm355_ccdc_remove), + .probe = dm355_ccdc_probe, +}; + +static int __init dm355_ccdc_init(void) +{ + return platform_driver_register(&dm355_ccdc_driver); +} + +static void __exit dm355_ccdc_exit(void) +{ + platform_driver_unregister(&dm355_ccdc_driver); } module_init(dm355_ccdc_init); diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c index d5fa193f32d..0c394cade22 100644 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ b/drivers/media/video/davinci/dm644x_ccdc.c @@ -37,8 +37,12 @@ #include <linux/platform_device.h> #include <linux/uaccess.h> #include <linux/videodev2.h> +#include <linux/clk.h> +#include <linux/err.h> + #include <media/davinci/dm644x_ccdc.h> #include <media/davinci/vpss.h> + #include "dm644x_ccdc_regs.h" #include "ccdc_hw_device.h" @@ -46,32 +50,44 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CCDC Driver for DM6446"); MODULE_AUTHOR("Texas Instruments"); -static struct device *dev; - -/* Object for CCDC raw mode */ -static struct ccdc_params_raw ccdc_hw_params_raw = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .config_params = { - .data_sz = CCDC_DATA_10BITS, +static struct ccdc_oper_config { + struct device *dev; + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* Master clock */ + struct clk *mclk; + /* slave clock */ + struct clk *sclk; + /* ccdc base address */ + void __iomem *base_addr; +} ccdc_cfg = { + /* Raw configurations */ + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .config_params = { + .data_sz = CCDC_DATA_10BITS, + }, + }, + .ycbcr = { + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .win = CCDC_WIN_PAL, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .bt656_enable = 1, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED }, -}; - -/* Object for CCDC ycbcr mode */ -static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = CCDC_WIN_PAL, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED }; #define CCDC_MAX_RAW_YUV_FORMATS 2 @@ -84,25 +100,15 @@ static u32 ccdc_raw_bayer_pix_formats[] = static u32 ccdc_raw_yuv_pix_formats[] = {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; -static void *__iomem ccdc_base_addr; -static int ccdc_addr_size; -static enum vpfe_hw_if_type ccdc_if_type; - /* register access routines */ static inline u32 regr(u32 offset) { - return __raw_readl(ccdc_base_addr + offset); + return __raw_readl(ccdc_cfg.base_addr + offset); } static inline void regw(u32 val, u32 offset) { - __raw_writel(val, ccdc_base_addr + offset); -} - -static void ccdc_set_ccdc_base(void *addr, int size) -{ - ccdc_base_addr = addr; - ccdc_addr_size = size; + __raw_writel(val, ccdc_cfg.base_addr + offset); } static void ccdc_enable(int flag) @@ -132,7 +138,7 @@ void ccdc_setwin(struct v4l2_rect *image_win, int vert_start, vert_nr_lines; int val = 0, mid_img = 0; - dev_dbg(dev, "\nStarting ccdc_setwin..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); /* * ppc - per pixel count. indicates how many pixels per cell * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. @@ -171,7 +177,7 @@ void ccdc_setwin(struct v4l2_rect *image_win, regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, CCDC_VERT_START); regw(vert_nr_lines, CCDC_VERT_LINES); - dev_dbg(dev, "\nEnd of ccdc_setwin..."); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); } static void ccdc_readregs(void) @@ -179,39 +185,39 @@ static void ccdc_readregs(void) unsigned int val = 0; val = regr(CCDC_ALAW); - dev_notice(dev, "\nReading 0x%x to ALAW...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); val = regr(CCDC_CLAMP); - dev_notice(dev, "\nReading 0x%x to CLAMP...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); val = regr(CCDC_DCSUB); - dev_notice(dev, "\nReading 0x%x to DCSUB...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); val = regr(CCDC_BLKCMP); - dev_notice(dev, "\nReading 0x%x to BLKCMP...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); val = regr(CCDC_FPC_ADDR); - dev_notice(dev, "\nReading 0x%x to FPC_ADDR...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); val = regr(CCDC_FPC); - dev_notice(dev, "\nReading 0x%x to FPC...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); val = regr(CCDC_FMTCFG); - dev_notice(dev, "\nReading 0x%x to FMTCFG...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); val = regr(CCDC_COLPTN); - dev_notice(dev, "\nReading 0x%x to COLPTN...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); val = regr(CCDC_FMT_HORZ); - dev_notice(dev, "\nReading 0x%x to FMT_HORZ...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); val = regr(CCDC_FMT_VERT); - dev_notice(dev, "\nReading 0x%x to FMT_VERT...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); val = regr(CCDC_HSIZE_OFF); - dev_notice(dev, "\nReading 0x%x to HSIZE_OFF...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); val = regr(CCDC_SDOFST); - dev_notice(dev, "\nReading 0x%x to SDOFST...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); val = regr(CCDC_VP_OUT); - dev_notice(dev, "\nReading 0x%x to VP_OUT...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); val = regr(CCDC_SYN_MODE); - dev_notice(dev, "\nReading 0x%x to SYN_MODE...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); val = regr(CCDC_HORZ_INFO); - dev_notice(dev, "\nReading 0x%x to HORZ_INFO...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); val = regr(CCDC_VERT_START); - dev_notice(dev, "\nReading 0x%x to VERT_START...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); val = regr(CCDC_VERT_LINES); - dev_notice(dev, "\nReading 0x%x to VERT_LINES...\n", val); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); } static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) @@ -220,7 +226,7 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { - dev_dbg(dev, "\nInvalid data line select"); + dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); return -1; } } @@ -230,7 +236,7 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) { struct ccdc_config_params_raw *config_params = - &ccdc_hw_params_raw.config_params; + &ccdc_cfg.bayer.config_params; unsigned int *fpc_virtaddr = NULL; unsigned int *fpc_physaddr = NULL; @@ -266,7 +272,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) FP_NUM_BYTES)); if (fpc_virtaddr == NULL) { - dev_dbg(dev, + dev_dbg(ccdc_cfg.dev, "\nUnable to allocate memory for FPC"); return -EFAULT; } @@ -279,7 +285,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) if (copy_from_user(fpc_virtaddr, (void __user *)raw_params->fault_pxl.fpc_table_addr, config_params->fault_pxl.fp_num * FP_NUM_BYTES)) { - dev_dbg(dev, "\n copy_from_user failed"); + dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); return -EFAULT; } config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; @@ -289,7 +295,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) static int ccdc_close(struct device *dev) { struct ccdc_config_params_raw *config_params = - &ccdc_hw_params_raw.config_params; + &ccdc_cfg.bayer.config_params; unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; @@ -323,9 +329,8 @@ static void ccdc_restore_defaults(void) static int ccdc_open(struct device *device) { - dev = device; ccdc_restore_defaults(); - if (ccdc_if_type == VPFE_RAW_BAYER) + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) ccdc_enable_vport(1); return 0; } @@ -341,12 +346,12 @@ static int ccdc_set_params(void __user *params) struct ccdc_config_params_raw ccdc_raw_params; int x; - if (ccdc_if_type != VPFE_RAW_BAYER) + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) return -EINVAL; x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); if (x) { - dev_dbg(dev, "ccdc_set_params: error in copying" + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying" "ccdc params, %d\n", x); return -EFAULT; } @@ -364,10 +369,10 @@ static int ccdc_set_params(void __user *params) */ void ccdc_config_ycbcr(void) { - struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr; + struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; u32 syn_mode; - dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); /* * first restore the CCDC registers to default values * This is important since we assume default values to be set in @@ -428,7 +433,7 @@ void ccdc_config_ycbcr(void) regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); ccdc_sbl_reset(); - dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); ccdc_readregs(); } @@ -440,9 +445,9 @@ static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) /* configure DCSub */ val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; regw(val, CCDC_DCSUB); - dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); - dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n"); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); return; } /* @@ -457,10 +462,10 @@ static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); regw(val, CCDC_CLAMP); - dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); /* If Black clamping is enable then make dcsub 0 */ regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); - dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n"); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); } static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) @@ -490,17 +495,17 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) /* Configure Fault pixel if needed */ regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); - dev_dbg(dev, "\nWriting 0x%x to FPC_ADDR...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", (fpc->fpc_table_addr)); /* Write the FPC params with FPC disable */ val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; regw(val, CCDC_FPC); - dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); /* read the FPC register */ val = regr(CCDC_FPC) | CCDC_FPC_ENABLE; regw(val, CCDC_FPC); - dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); } /* @@ -509,13 +514,13 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) */ void ccdc_config_raw(void) { - struct ccdc_params_raw *params = &ccdc_hw_params_raw; + struct ccdc_params_raw *params = &ccdc_cfg.bayer; struct ccdc_config_params_raw *config_params = - &ccdc_hw_params_raw.config_params; + &ccdc_cfg.bayer.config_params; unsigned int syn_mode = 0; unsigned int val; - dev_dbg(dev, "\nStarting ccdc_config_raw..."); + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); /* Reset CCDC */ ccdc_restore_defaults(); @@ -545,7 +550,7 @@ void ccdc_config_raw(void) val = ((config_params->alaw.gama_wd & CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); regw(val, CCDC_ALAW); - dev_dbg(dev, "\nWriting 0x%x to ALAW...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); } /* Configure video window */ @@ -582,11 +587,11 @@ void ccdc_config_raw(void) /* Write value in FMTCFG */ regw(val, CCDC_FMTCFG); - dev_dbg(dev, "\nWriting 0x%x to FMTCFG...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); /* Configure the color pattern according to mt9t001 sensor */ regw(CCDC_COLPTN_VAL, CCDC_COLPTN); - dev_dbg(dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); + dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); /* * Configure Data formatter(Video port) pixel selection * (FMT_HORZ, FMT_VERT) @@ -596,7 +601,7 @@ void ccdc_config_raw(void) (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); regw(val, CCDC_FMT_HORZ); - dev_dbg(dev, "\nWriting 0x%x to FMT_HORZ...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) << CCDC_FMT_VERT_FMTSLV_SHIFT; if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) @@ -604,13 +609,13 @@ void ccdc_config_raw(void) else val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; - dev_dbg(dev, "\nparams->win.height 0x%x ...\n", + dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", params->win.height); regw(val, CCDC_FMT_VERT); - dev_dbg(dev, "\nWriting 0x%x to FMT_VERT...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); - dev_dbg(dev, "\nbelow regw(val, FMT_VERT)..."); + dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); /* * Configure Horizontal offset register. If pack 8 is enabled then @@ -631,17 +636,17 @@ void ccdc_config_raw(void) if (params->image_invert_enable) { /* For intelace inverse mode */ regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n"); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); } else { /* For intelace non inverse mode */ regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(dev, "\nWriting 0x0249 to SDOFST...\n"); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); } } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n"); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n"); } /* @@ -662,18 +667,18 @@ void ccdc_config_raw(void) val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; regw(val, CCDC_VP_OUT); - dev_dbg(dev, "\nWriting 0x%x to VP_OUT...\n", val); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); regw(syn_mode, CCDC_SYN_MODE); - dev_dbg(dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); ccdc_sbl_reset(); - dev_dbg(dev, "\nend of ccdc_config_raw..."); + dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); ccdc_readregs(); } static int ccdc_configure(void) { - if (ccdc_if_type == VPFE_RAW_BAYER) + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) ccdc_config_raw(); else ccdc_config_ycbcr(); @@ -682,24 +687,24 @@ static int ccdc_configure(void) static int ccdc_set_buftype(enum ccdc_buftype buf_type) { - if (ccdc_if_type == VPFE_RAW_BAYER) - ccdc_hw_params_raw.buf_type = buf_type; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_type = buf_type; else - ccdc_hw_params_ycbcr.buf_type = buf_type; + ccdc_cfg.ycbcr.buf_type = buf_type; return 0; } static enum ccdc_buftype ccdc_get_buftype(void) { - if (ccdc_if_type == VPFE_RAW_BAYER) - return ccdc_hw_params_raw.buf_type; - return ccdc_hw_params_ycbcr.buf_type; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.buf_type; + return ccdc_cfg.ycbcr.buf_type; } static int ccdc_enum_pix(u32 *pix, int i) { int ret = -EINVAL; - if (ccdc_if_type == VPFE_RAW_BAYER) { + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { *pix = ccdc_raw_bayer_pix_formats[i]; ret = 0; @@ -715,17 +720,17 @@ static int ccdc_enum_pix(u32 *pix, int i) static int ccdc_set_pixel_format(u32 pixfmt) { - if (ccdc_if_type == VPFE_RAW_BAYER) { - ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; if (pixfmt == V4L2_PIX_FMT_SBGGR8) - ccdc_hw_params_raw.config_params.alaw.enable = 1; + ccdc_cfg.bayer.config_params.alaw.enable = 1; else if (pixfmt != V4L2_PIX_FMT_SBGGR16) return -EINVAL; } else { if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; else return -EINVAL; } @@ -734,17 +739,16 @@ static int ccdc_set_pixel_format(u32 pixfmt) static u32 ccdc_get_pixel_format(void) { - struct ccdc_a_law *alaw = - &ccdc_hw_params_raw.config_params.alaw; + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; u32 pixfmt; - if (ccdc_if_type == VPFE_RAW_BAYER) + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) if (alaw->enable) pixfmt = V4L2_PIX_FMT_SBGGR8; else pixfmt = V4L2_PIX_FMT_SBGGR16; else { - if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) pixfmt = V4L2_PIX_FMT_YUYV; else pixfmt = V4L2_PIX_FMT_UYVY; @@ -754,53 +758,53 @@ static u32 ccdc_get_pixel_format(void) static int ccdc_set_image_window(struct v4l2_rect *win) { - if (ccdc_if_type == VPFE_RAW_BAYER) - ccdc_hw_params_raw.win = *win; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.win = *win; else - ccdc_hw_params_ycbcr.win = *win; + ccdc_cfg.ycbcr.win = *win; return 0; } static void ccdc_get_image_window(struct v4l2_rect *win) { - if (ccdc_if_type == VPFE_RAW_BAYER) - *win = ccdc_hw_params_raw.win; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc_cfg.bayer.win; else - *win = ccdc_hw_params_ycbcr.win; + *win = ccdc_cfg.ycbcr.win; } static unsigned int ccdc_get_line_length(void) { struct ccdc_config_params_raw *config_params = - &ccdc_hw_params_raw.config_params; + &ccdc_cfg.bayer.config_params; unsigned int len; - if (ccdc_if_type == VPFE_RAW_BAYER) { + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { if ((config_params->alaw.enable) || (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_hw_params_raw.win.width; + len = ccdc_cfg.bayer.win.width; else - len = ccdc_hw_params_raw.win.width * 2; + len = ccdc_cfg.bayer.win.width * 2; } else - len = ccdc_hw_params_ycbcr.win.width * 2; + len = ccdc_cfg.ycbcr.win.width * 2; return ALIGN(len, 32); } static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) { - if (ccdc_if_type == VPFE_RAW_BAYER) - ccdc_hw_params_raw.frm_fmt = frm_fmt; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.frm_fmt = frm_fmt; else - ccdc_hw_params_ycbcr.frm_fmt = frm_fmt; + ccdc_cfg.ycbcr.frm_fmt = frm_fmt; return 0; } static enum ccdc_frmfmt ccdc_get_frame_format(void) { - if (ccdc_if_type == VPFE_RAW_BAYER) - return ccdc_hw_params_raw.frm_fmt; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.frm_fmt; else - return ccdc_hw_params_ycbcr.frm_fmt; + return ccdc_cfg.ycbcr.frm_fmt; } static int ccdc_getfid(void) @@ -816,14 +820,14 @@ static inline void ccdc_setfbaddr(unsigned long addr) static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) { - ccdc_if_type = params->if_type; + ccdc_cfg.if_type = params->if_type; switch (params->if_type) { case VPFE_BT656: case VPFE_YCBCR_SYNC_16: case VPFE_YCBCR_SYNC_8: - ccdc_hw_params_ycbcr.vd_pol = params->vdpol; - ccdc_hw_params_ycbcr.hd_pol = params->hdpol; + ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc_cfg.ycbcr.hd_pol = params->hdpol; break; default: /* TODO add support for raw bayer here */ @@ -838,7 +842,6 @@ static struct ccdc_hw_device ccdc_hw_dev = { .hw_ops = { .open = ccdc_open, .close = ccdc_close, - .set_ccdc_base = ccdc_set_ccdc_base, .reset = ccdc_sbl_reset, .enable = ccdc_enable, .set_hw_if_params = ccdc_set_hw_if_params, @@ -859,19 +862,105 @@ static struct ccdc_hw_device ccdc_hw_dev = { }, }; -static int __init dm644x_ccdc_init(void) +static int __init dm644x_ccdc_probe(struct platform_device *pdev) { - printk(KERN_NOTICE "dm644x_ccdc_init\n"); - if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0) - return -1; - printk(KERN_NOTICE "%s is registered with vpfe.\n", - ccdc_hw_dev.name); + struct resource *res; + int status = 0; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENODEV; + goto fail_nores; + } + + res = request_mem_region(res->start, resource_size(res), res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); + if (!ccdc_cfg.base_addr) { + status = -ENOMEM; + goto fail_nomem; + } + + /* Get and enable Master clock */ + ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(ccdc_cfg.mclk)) { + status = PTR_ERR(ccdc_cfg.mclk); + goto fail_nomap; + } + if (clk_enable(ccdc_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Get and enable Slave clock */ + ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); + if (IS_ERR(ccdc_cfg.sclk)) { + status = PTR_ERR(ccdc_cfg.sclk); + goto fail_mclk; + } + if (clk_enable(ccdc_cfg.sclk)) { + status = -ENODEV; + goto fail_sclk; + } + ccdc_cfg.dev = &pdev->dev; + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; +fail_sclk: + clk_put(ccdc_cfg.sclk); +fail_mclk: + clk_put(ccdc_cfg.mclk); +fail_nomap: + iounmap(ccdc_cfg.base_addr); +fail_nomem: + release_mem_region(res->start, resource_size(res)); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; } -static void __exit dm644x_ccdc_exit(void) +static int dm644x_ccdc_remove(struct platform_device *pdev) { + struct resource *res; + + clk_put(ccdc_cfg.mclk); + clk_put(ccdc_cfg.sclk); + iounmap(ccdc_cfg.base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static struct platform_driver dm644x_ccdc_driver = { + .driver = { + .name = "dm644x_ccdc", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(dm644x_ccdc_remove), + .probe = dm644x_ccdc_probe, +}; + +static int __init dm644x_ccdc_init(void) +{ + return platform_driver_register(&dm644x_ccdc_driver); +} + +static void __exit dm644x_ccdc_exit(void) +{ + platform_driver_unregister(&dm644x_ccdc_driver); } module_init(dm644x_ccdc_init); diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c new file mode 100644 index 00000000000..29c29c66859 --- /dev/null +++ b/drivers/media/video/davinci/isif.c @@ -0,0 +1,1172 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Image Sensor Interface (ISIF) driver + * + * This driver is for configuring the ISIF IP available on DM365 or any other + * TI SoCs. This is used for capturing yuv or bayer video or image data + * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 + * and DM6446, but with enhanced or additional ip blocks. The driver + * configures the ISIF upon commands from the vpfe bridge driver through + * ccdc_hw_device interface. + * + * TODO: 1) Raw bayer parameter settings and bayer capture + * 2) Add support for control ioctl + */ +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/videodev2.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <mach/mux.h> + +#include <media/davinci/isif.h> +#include <media/davinci/vpss.h> + +#include "isif_regs.h" +#include "ccdc_hw_device.h" + +/* Defaults for module configuration parameters */ +static struct isif_config_params_raw isif_config_defaults = { + .linearize = { + .en = 0, + .corr_shft = ISIF_NO_SHIFT, + .scale_fact = {1, 0}, + }, + .df_csc = { + .df_or_csc = 0, + .csc = { + .en = 0, + }, + }, + .dfc = { + .en = 0, + }, + .bclamp = { + .en = 0, + }, + .gain_offset = { + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + }, + .culling = { + .hcpat_odd = 0xff, + .hcpat_even = 0xff, + .vcpat = 0xff, + }, + .compress = { + .alg = ISIF_ALAW, + }, +}; + +/* ISIF operation configuration */ +static struct isif_oper_config { + struct device *dev; + enum vpfe_hw_if_type if_type; + struct isif_ycbcr_config ycbcr; + struct isif_params_raw bayer; + enum isif_data_pack data_pack; + /* Master clock */ + struct clk *mclk; + /* ISIF base address */ + void __iomem *base_addr; + /* ISIF Linear Table 0 */ + void __iomem *linear_tbl0_addr; + /* ISIF Linear Table 1 */ + void __iomem *linear_tbl1_addr; +} isif_cfg = { + .ycbcr = { + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .win = ISIF_WIN_NTSC, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, + }, + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = ISIF_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + .cfa_pat = ISIF_CFA_PAT_MOSAIC, + .data_msb = ISIF_BIT_MSB_11, + .config_params = { + .data_shift = ISIF_NO_SHIFT, + .col_pat_field0 = { + .olop = ISIF_GREEN_BLUE, + .olep = ISIF_BLUE, + .elop = ISIF_RED, + .elep = ISIF_GREEN_RED, + }, + .col_pat_field1 = { + .olop = ISIF_GREEN_BLUE, + .olep = ISIF_BLUE, + .elop = ISIF_RED, + .elep = ISIF_GREEN_RED, + }, + .test_pat_gen = 0, + }, + }, + .data_pack = ISIF_DATA_PACK8, +}; + +/* Raw Bayer formats */ +static const u32 isif_raw_bayer_pix_formats[] = { + V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; + +/* Raw YUV formats */ +static const u32 isif_raw_yuv_pix_formats[] = { + V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(isif_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, isif_cfg.base_addr + offset); +} + +/* reg_modify() - read, modify and write register */ +static inline u32 reg_modify(u32 mask, u32 val, u32 offset) +{ + u32 new_val = (regr(offset) & ~mask) | (val & mask); + + regw(new_val, offset); + return new_val; +} + +static inline void regw_lin_tbl(u32 val, u32 offset, int i) +{ + if (!i) + __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); + else + __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); +} + +static void isif_disable_all_modules(void) +{ + /* disable BC */ + regw(0, CLAMPCFG); + /* disable vdfc */ + regw(0, DFCCTL); + /* disable CSC */ + regw(0, CSCCTL); + /* disable linearization */ + regw(0, LINCFG0); + /* disable other modules here as they are supported */ +} + +static void isif_enable(int en) +{ + if (!en) { + /* Before disable isif, disable all ISIF modules */ + isif_disable_all_modules(); + /* + * wait for next VD. Assume lowest scan rate is 12 Hz. So + * 100 msec delay is good enough + */ + msleep(100); + } + reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); +} + +static void isif_enable_output_to_sdram(int en) +{ + reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); +} + +static void isif_config_culling(struct isif_cul *cul) +{ + u32 val; + + /* Horizontal pattern */ + val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; + regw(val, CULH); + + /* vertical pattern */ + regw(cul->vcpat, CULV); + + /* LPF */ + reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, + cul->en_lpf << ISIF_LPF_SHIFT, MODESET); +} + +static void isif_config_gain_offset(void) +{ + struct isif_gain_offsets_adj *gain_off_p = + &isif_cfg.bayer.config_params.gain_offset; + u32 val; + + val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | + (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | + (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | + (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | + (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | + (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); + + reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); + + val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.r_ye.decimal; + regw(val, CRGAIN); + + val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.gr_cy.decimal; + regw(val, CGRGAIN); + + val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.gb_g.decimal; + regw(val, CGBGAIN); + + val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.b_mg.decimal; + regw(val, CBGAIN); + + regw(gain_off_p->offset, COFSTA); +} + +static void isif_restore_defaults(void) +{ + enum vpss_ccdc_source_sel source = VPSS_CCDCIN; + + dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); + isif_cfg.bayer.config_params = isif_config_defaults; + /* Enable clock to ISIF, IPIPEIF and BL */ + vpss_enable_clock(VPSS_CCDC_CLOCK, 1); + vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); + vpss_enable_clock(VPSS_BL_CLOCK, 1); + /* Set default offset and gain */ + isif_config_gain_offset(); + vpss_select_ccdc_source(source); + dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); +} + +static int isif_open(struct device *device) +{ + isif_restore_defaults(); + return 0; +} + +/* This function will configure the window size to be capture in ISIF reg */ +static void isif_setwin(struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, int ppc) +{ + int horz_start, horz_nr_pixels; + int vert_start, vert_nr_lines; + int mid_img = 0; + + dev_dbg(isif_cfg.dev, "\nStarting isif_setwin..."); + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + horz_start = image_win->left << (ppc - 1); + horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; + + /* Writing the horizontal info into the registers */ + regw(horz_start & START_PX_HOR_MASK, SPH); + regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + } else { + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* configure VDINT0 and VDINT1 */ + mid_img = vert_start + (image_win->height / 2); + regw(mid_img, VDINT1); + } + + regw(0, VDINT0); + regw(vert_start & START_VER_ONE_MASK, SLV0); + regw(vert_start & START_VER_TWO_MASK, SLV1); + regw(vert_nr_lines & NUM_LINES_VER, LNV); +} + +static void isif_config_bclamp(struct isif_black_clamp *bc) +{ + u32 val; + + /* + * DC Offset is always added to image data irrespective of bc enable + * status + */ + regw(bc->dc_offset, CLDCOFST); + + if (bc->en) { + val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; + + /* Enable BC and horizontal clamp caculation paramaters */ + val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); + + regw(val, CLAMPCFG); + + if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { + /* + * Window count for calculation + * Base window selection + * pixel limit + * Horizontal size of window + * vertical size of the window + * Horizontal start position of the window + * Vertical start position of the window + */ + val = bc->horz.win_count_calc | + ((!!bc->horz.base_win_sel_calc) << + ISIF_HORZ_BC_WIN_SEL_SHIFT) | + ((!!bc->horz.clamp_pix_limit) << + ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | + (bc->horz.win_h_sz_calc << + ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | + (bc->horz.win_v_sz_calc << + ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); + regw(val, CLHWIN0); + + regw(bc->horz.win_start_h_calc, CLHWIN1); + regw(bc->horz.win_start_v_calc, CLHWIN2); + } + + /* vertical clamp caculation paramaters */ + + /* Reset clamp value sel for previous line */ + val |= + (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | + (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); + regw(val, CLVWIN0); + + /* Optical Black horizontal start position */ + regw(bc->vert.ob_start_h, CLVWIN1); + /* Optical Black vertical start position */ + regw(bc->vert.ob_start_v, CLVWIN2); + /* Optical Black vertical size for calculation */ + regw(bc->vert.ob_v_sz_calc, CLVWIN3); + /* Vertical start position for BC subtraction */ + regw(bc->vert_start_sub, CLSV); + } +} + +static void isif_config_linearization(struct isif_linearize *linearize) +{ + u32 val, i; + + if (!linearize->en) { + regw(0, LINCFG0); + return; + } + + /* shift value for correction & enable linearization (set lsb) */ + val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; + regw(val, LINCFG0); + + /* Scale factor */ + val = ((!!linearize->scale_fact.integer) << + ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | + linearize->scale_fact.decimal; + regw(val, LINCFG1); + + for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { + if (i % 2) + regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); + else + regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); + } +} + +static int isif_config_dfc(struct isif_dfc *vdfc) +{ + /* initialize retries to loop for max ~ 250 usec */ + u32 val, count, retries = loops_per_jiffy / (4000/HZ); + int i; + + if (!vdfc->en) + return 0; + + /* Correction mode */ + val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); + + /* Correct whole line or partial */ + if (vdfc->corr_whole_line) + val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; + + /* level shift value */ + val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; + + regw(val, DFCCTL); + + /* Defect saturation level */ + regw(vdfc->def_sat_level, VDFSATLV); + + regw(vdfc->table[0].pos_vert, DFCMEM0); + regw(vdfc->table[0].pos_horz, DFCMEM1); + if (vdfc->corr_mode == ISIF_VDFC_NORMAL || + vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[0].level_at_pos, DFCMEM2); + regw(vdfc->table[0].level_up_pixels, DFCMEM3); + regw(vdfc->table[0].level_low_pixels, DFCMEM4); + } + + /* set DFCMARST and set DFCMWR */ + val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; + regw(val, DFCMEMCTL); + + count = retries; + while (count && (regr(DFCMEMCTL) & 0x1)) + count--; + + if (!count) { + dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); + return -1; + } + + for (i = 1; i < vdfc->num_vdefects; i++) { + regw(vdfc->table[i].pos_vert, DFCMEM0); + regw(vdfc->table[i].pos_horz, DFCMEM1); + if (vdfc->corr_mode == ISIF_VDFC_NORMAL || + vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[i].level_at_pos, DFCMEM2); + regw(vdfc->table[i].level_up_pixels, DFCMEM3); + regw(vdfc->table[i].level_low_pixels, DFCMEM4); + } + val = regr(DFCMEMCTL); + /* clear DFCMARST and set DFCMWR */ + val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); + val |= 1; + regw(val, DFCMEMCTL); + + count = retries; + while (count && (regr(DFCMEMCTL) & 0x1)) + count--; + + if (!count) { + dev_err(isif_cfg.dev, + "defect table write timeout !!!\n"); + return -1; + } + } + if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { + /* Extra cycle needed */ + regw(0, DFCMEM0); + regw(0x1FFF, DFCMEM1); + regw(1, DFCMEMCTL); + } + + /* enable VDFC */ + reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), + DFCCTL); + return 0; +} + +static void isif_config_csc(struct isif_df_csc *df_csc) +{ + u32 val1 = 0, val2 = 0, i; + + if (!df_csc->csc.en) { + regw(0, CSCCTL); + return; + } + for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { + if ((i % 2) == 0) { + /* CSCM - LSB */ + val1 = (df_csc->csc.coeff[i].integer << + ISIF_CSC_COEF_INTEG_SHIFT) | + df_csc->csc.coeff[i].decimal; + } else { + + /* CSCM - MSB */ + val2 = (df_csc->csc.coeff[i].integer << + ISIF_CSC_COEF_INTEG_SHIFT) | + df_csc->csc.coeff[i].decimal; + val2 <<= ISIF_CSCM_MSB_SHIFT; + val2 |= val1; + regw(val2, (CSCM0 + ((i - 1) << 1))); + } + } + + /* program the active area */ + regw(df_csc->start_pix, FMTSPH); + /* + * one extra pixel as required for CSC. Actually number of + * pixel - 1 should be configured in this register. So we + * need to subtract 1 before writing to FMTSPH, but we will + * not do this since csc requires one extra pixel + */ + regw(df_csc->num_pixels, FMTLNH); + regw(df_csc->start_line, FMTSLV); + /* + * one extra line as required for CSC. See reason documented for + * num_pixels + */ + regw(df_csc->num_lines, FMTLNV); + + /* Enable CSC */ + regw(1, CSCCTL); +} + +static int isif_config_raw(void) +{ + struct isif_params_raw *params = &isif_cfg.bayer; + struct isif_config_params_raw *module_params = + &isif_cfg.bayer.config_params; + struct vpss_pg_frame_size frame_size; + struct vpss_sync_pol sync; + u32 val; + + dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); + + /* + * Configure CCDCFG register:- + * Set CCD Not to swap input since input is RAW data + * Set FID detection function to Latch at V-Sync + * Set WENLOG - isif valid area + * Set TRGSEL + * Set EXTRG + * Packed to 8 or 16 bits + */ + + val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | + ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | + ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; + + dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); + regw(val, CCDCFG); + + /* + * Configure the vertical sync polarity(MODESET.VDPOL) + * Configure the horizontal sync polarity (MODESET.HDPOL) + * Configure frame id polarity (MODESET.FLDPOL) + * Configure data polarity + * Configure External WEN Selection + * Configure frame format(progressive or interlace) + * Configure pixel format (Input mode) + * Configure the data shift + */ + + val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | + (params->hd_pol << ISIF_HD_POL_SHIFT) | + (params->fid_pol << ISIF_FID_POL_SHIFT) | + (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | + (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | + (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | + (params->pix_fmt << ISIF_INPUT_SHIFT) | + (params->config_params.data_shift << ISIF_DATASFT_SHIFT); + + regw(val, MODESET); + dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); + + /* + * Configure GAMMAWD register + * CFA pattern setting + */ + val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; + + /* Gamma msb */ + if (module_params->compress.alg == ISIF_ALAW) + val |= ISIF_ALAW_ENABLE; + + val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); + regw(val, CGAMMAWD); + + /* Configure DPCM compression settings */ + if (module_params->compress.alg == ISIF_DPCM) { + val = BIT(ISIF_DPCM_EN_SHIFT) | + (module_params->compress.pred << + ISIF_DPCM_PREDICTOR_SHIFT); + } + + regw(val, MISC); + + /* Configure Gain & Offset */ + isif_config_gain_offset(); + + /* Configure Color pattern */ + val = (params->config_params.col_pat_field0.olop) | + (params->config_params.col_pat_field0.olep << 2) | + (params->config_params.col_pat_field0.elop << 4) | + (params->config_params.col_pat_field0.elep << 6) | + (params->config_params.col_pat_field1.olop << 8) | + (params->config_params.col_pat_field1.olep << 10) | + (params->config_params.col_pat_field1.elop << 12) | + (params->config_params.col_pat_field1.elep << 14); + regw(val, CCOLP); + dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); + + /* Configure HSIZE register */ + val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; + + /* calculate line offset in 32 bytes based on pack value */ + if (isif_cfg.data_pack == ISIF_PACK_8BIT) + val |= ((params->win.width + 31) >> 5); + else if (isif_cfg.data_pack == ISIF_PACK_12BIT) + val |= (((params->win.width + + (params->win.width >> 2)) + 31) >> 5); + else + val |= (((params->win.width * 2) + 31) >> 5); + regw(val, HSIZE); + + /* Configure SDOFST register */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_en) { + /* For interlace inverse mode */ + regw(0x4B6D, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); + } else { + /* For interlace non inverse mode */ + regw(0x0B6D, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + if (params->image_invert_en) { + /* For progressive inverse mode */ + regw(0x4000, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); + } else { + /* For progressive non inverse mode */ + regw(0x0000, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); + } + } + + /* Configure video window */ + isif_setwin(¶ms->win, params->frm_fmt, 1); + + /* Configure Black Clamp */ + isif_config_bclamp(&module_params->bclamp); + + /* Configure Vertical Defection Pixel Correction */ + if (isif_config_dfc(&module_params->dfc) < 0) + return -EFAULT; + + if (!module_params->df_csc.df_or_csc) + /* Configure Color Space Conversion */ + isif_config_csc(&module_params->df_csc); + + isif_config_linearization(&module_params->linearize); + + /* Configure Culling */ + isif_config_culling(&module_params->culling); + + /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ + regw(module_params->horz_offset, DATAHOFST); + regw(module_params->vert_offset, DATAVOFST); + + /* Setup test pattern if enabled */ + if (params->config_params.test_pat_gen) { + /* Use the HD/VD pol settings from user */ + sync.ccdpg_hdpol = params->hd_pol; + sync.ccdpg_vdpol = params->vd_pol; + dm365_vpss_set_sync_pol(sync); + frame_size.hlpfr = isif_cfg.bayer.win.width; + frame_size.pplen = isif_cfg.bayer.win.height; + dm365_vpss_set_pg_frame_size(frame_size); + vpss_select_ccdc_source(VPSS_PGLPBK); + } + + dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); + return 0; +} + +static int isif_set_buftype(enum ccdc_buftype buf_type) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + isif_cfg.bayer.buf_type = buf_type; + else + isif_cfg.ycbcr.buf_type = buf_type; + + return 0; + +} +static enum ccdc_buftype isif_get_buftype(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_cfg.bayer.buf_type; + + return isif_cfg.ycbcr.buf_type; +} + +static int isif_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { + *pix = isif_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { + *pix = isif_raw_yuv_pix_formats[i]; + ret = 0; + } + } + + return ret; +} + +static int isif_set_pixel_format(unsigned int pixfmt) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (pixfmt == V4L2_PIX_FMT_SBGGR8) { + if ((isif_cfg.bayer.config_params.compress.alg != + ISIF_ALAW) && + (isif_cfg.bayer.config_params.compress.alg != + ISIF_DPCM)) { + dev_dbg(isif_cfg.dev, + "Either configure A-Law or DPCM\n"); + return -EINVAL; + } + isif_cfg.data_pack = ISIF_PACK_8BIT; + } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { + isif_cfg.bayer.config_params.compress.alg = + ISIF_NO_COMPRESSION; + isif_cfg.data_pack = ISIF_PACK_16BIT; + } else + return -EINVAL; + isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + isif_cfg.data_pack = ISIF_PACK_8BIT; + } + return 0; +} + +static u32 isif_get_pixel_format(void) +{ + u32 pixfmt; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) + if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || + isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} + +static int isif_set_image_window(struct v4l2_rect *win) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + isif_cfg.bayer.win.top = win->top; + isif_cfg.bayer.win.left = win->left; + isif_cfg.bayer.win.width = win->width; + isif_cfg.bayer.win.height = win->height; + } else { + isif_cfg.ycbcr.win.top = win->top; + isif_cfg.ycbcr.win.left = win->left; + isif_cfg.ycbcr.win.width = win->width; + isif_cfg.ycbcr.win.height = win->height; + } + return 0; +} + +static void isif_get_image_window(struct v4l2_rect *win) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + *win = isif_cfg.bayer.win; + else + *win = isif_cfg.ycbcr.win; +} + +static unsigned int isif_get_line_length(void) +{ + unsigned int len; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (isif_cfg.data_pack == ISIF_PACK_8BIT) + len = ((isif_cfg.bayer.win.width)); + else if (isif_cfg.data_pack == ISIF_PACK_12BIT) + len = (((isif_cfg.bayer.win.width * 2) + + (isif_cfg.bayer.win.width >> 2))); + else + len = (((isif_cfg.bayer.win.width * 2))); + } else + len = (((isif_cfg.ycbcr.win.width * 2))); + return ALIGN(len, 32); +} + +static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + isif_cfg.bayer.frm_fmt = frm_fmt; + else + isif_cfg.ycbcr.frm_fmt = frm_fmt; + return 0; +} +static enum ccdc_frmfmt isif_get_frame_format(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_cfg.bayer.frm_fmt; + return isif_cfg.ycbcr.frm_fmt; +} + +static int isif_getfid(void) +{ + return (regr(MODESET) >> 15) & 0x1; +} + +/* misc operations */ +static void isif_setfbaddr(unsigned long addr) +{ + regw((addr >> 21) & 0x07ff, CADU); + regw((addr >> 5) & 0x0ffff, CADL); +} + +static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) +{ + isif_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_BT656_10BIT: + case VPFE_YCBCR_SYNC_8: + isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_BT1120: + case VPFE_YCBCR_SYNC_16: + isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_RAW_BAYER: + isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + break; + default: + dev_dbg(isif_cfg.dev, "Invalid interface type\n"); + return -EINVAL; + } + + return 0; +} + +/* This function will configure ISIF for YCbCr parameters. */ +static int isif_config_ycbcr(void) +{ + struct isif_ycbcr_config *params = &isif_cfg.ycbcr; + struct vpss_pg_frame_size frame_size; + u32 modeset = 0, ccdcfg = 0; + struct vpss_sync_pol sync; + + dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); + + /* configure pixel format or input mode */ + modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | + (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | + (params->fid_pol << ISIF_FID_POL_SHIFT) | + (params->hd_pol << ISIF_HD_POL_SHIFT) | + (params->vd_pol << ISIF_VD_POL_SHIFT); + + /* pack the data to 8-bit ISIFCFG */ + switch (isif_cfg.if_type) { + case VPFE_BT656: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); + regw(3, REC656IF); + ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; + break; + case VPFE_BT656_10BIT: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + /* setup BT.656, embedded sync */ + regw(3, REC656IF); + /* enable 10 bit mode in ccdcfg */ + ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | + ISIF_BW656_ENABLE; + break; + case VPFE_BT1120: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + regw(3, REC656IF); + break; + + case VPFE_YCBCR_SYNC_8: + ccdcfg |= ISIF_DATA_PACK8; + ccdcfg |= ISIF_YCINSWP_YCBCR; + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + case VPFE_YCBCR_SYNC_16: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + default: + /* should never come here */ + dev_dbg(isif_cfg.dev, "Invalid interface type\n"); + return -EINVAL; + } + + regw(modeset, MODESET); + + /* Set up pix order */ + ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; + + regw(ccdcfg, CCDCFG); + + /* configure video window */ + if ((isif_cfg.if_type == VPFE_BT1120) || + (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) + isif_setwin(¶ms->win, params->frm_fmt, 1); + else + isif_setwin(¶ms->win, params->frm_fmt, 2); + + /* + * configure the horizontal line offset + * this is done by rounding up width to a multiple of 16 pixels + * and multiply by two to account for y:cb:cr 4:2:2 data + */ + regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); + + /* configure the memory line offset */ + if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && + (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) + /* two fields are interleaved in memory */ + regw(0x00000249, SDOFST); + + /* Setup test pattern if enabled */ + if (isif_cfg.bayer.config_params.test_pat_gen) { + sync.ccdpg_hdpol = params->hd_pol; + sync.ccdpg_vdpol = params->vd_pol; + dm365_vpss_set_sync_pol(sync); + dm365_vpss_set_pg_frame_size(frame_size); + } + return 0; +} + +static int isif_configure(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_config_raw(); + return isif_config_ycbcr(); +} + +static int isif_close(struct device *device) +{ + /* copy defaults to module params */ + isif_cfg.bayer.config_params = isif_config_defaults; + return 0; +} + +static struct ccdc_hw_device isif_hw_dev = { + .name = "ISIF", + .owner = THIS_MODULE, + .hw_ops = { + .open = isif_open, + .close = isif_close, + .enable = isif_enable, + .enable_out_to_sdram = isif_enable_output_to_sdram, + .set_hw_if_params = isif_set_hw_if_params, + .configure = isif_configure, + .set_buftype = isif_set_buftype, + .get_buftype = isif_get_buftype, + .enum_pix = isif_enum_pix, + .set_pixel_format = isif_set_pixel_format, + .get_pixel_format = isif_get_pixel_format, + .set_frame_format = isif_set_frame_format, + .get_frame_format = isif_get_frame_format, + .set_image_window = isif_set_image_window, + .get_image_window = isif_get_image_window, + .get_line_length = isif_get_line_length, + .setfbaddr = isif_setfbaddr, + .getfid = isif_getfid, + }, +}; + +static int __init isif_probe(struct platform_device *pdev) +{ + void (*setup_pinmux)(void); + struct resource *res; + void *__iomem addr; + int status = 0, i; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&isif_hw_dev); + if (status < 0) + return status; + + /* Get and enable Master clock */ + isif_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(isif_cfg.mclk)) { + status = PTR_ERR(isif_cfg.mclk); + goto fail_mclk; + } + if (clk_enable(isif_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Platform data holds setup_pinmux function ptr */ + if (NULL == pdev->dev.platform_data) { + status = -ENODEV; + goto fail_mclk; + } + setup_pinmux = pdev->dev.platform_data; + /* + * setup Mux configuration for ccdc which may be different for + * different SoCs using this CCDC + */ + setup_pinmux(); + + i = 0; + /* Get the ISIF base address, linearization table0 and table1 addr. */ + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) { + status = -ENODEV; + goto fail_nobase_res; + } + res = request_mem_region(res->start, resource_size(res), + res->name); + if (!res) { + status = -EBUSY; + goto fail_nobase_res; + } + addr = ioremap_nocache(res->start, resource_size(res)); + if (!addr) { + status = -ENOMEM; + goto fail_base_iomap; + } + switch (i) { + case 0: + /* ISIF base address */ + isif_cfg.base_addr = addr; + break; + case 1: + /* ISIF linear tbl0 address */ + isif_cfg.linear_tbl0_addr = addr; + break; + default: + /* ISIF linear tbl0 address */ + isif_cfg.linear_tbl1_addr = addr; + break; + } + i++; + } + isif_cfg.dev = &pdev->dev; + + printk(KERN_NOTICE "%s is registered with vpfe.\n", + isif_hw_dev.name); + return 0; +fail_base_iomap: + release_mem_region(res->start, resource_size(res)); + i--; +fail_nobase_res: + if (isif_cfg.base_addr) + iounmap(isif_cfg.base_addr); + if (isif_cfg.linear_tbl0_addr) + iounmap(isif_cfg.linear_tbl0_addr); + + while (i >= 0) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + release_mem_region(res->start, resource_size(res)); + i--; + } +fail_mclk: + clk_put(isif_cfg.mclk); + vpfe_unregister_ccdc_device(&isif_hw_dev); + return status; +} + +static int isif_remove(struct platform_device *pdev) +{ + struct resource *res; + int i = 0; + + iounmap(isif_cfg.base_addr); + iounmap(isif_cfg.linear_tbl0_addr); + iounmap(isif_cfg.linear_tbl1_addr); + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (res) + release_mem_region(res->start, resource_size(res)); + i++; + } + vpfe_unregister_ccdc_device(&isif_hw_dev); + return 0; +} + +static struct platform_driver isif_driver = { + .driver = { + .name = "isif", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(isif_remove), + .probe = isif_probe, +}; + +static int __init isif_init(void) +{ + return platform_driver_register(&isif_driver); +} + +static void isif_exit(void) +{ + platform_driver_unregister(&isif_driver); +} + +module_init(isif_init); +module_exit(isif_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/isif_regs.h b/drivers/media/video/davinci/isif_regs.h new file mode 100644 index 00000000000..f7b8893a295 --- /dev/null +++ b/drivers/media/video/davinci/isif_regs.h @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ISIF_REGS_H +#define _ISIF_REGS_H + +/* ISIF registers relative offsets */ +#define SYNCEN 0x00 +#define MODESET 0x04 +#define HDW 0x08 +#define VDW 0x0c +#define PPLN 0x10 +#define LPFR 0x14 +#define SPH 0x18 +#define LNH 0x1c +#define SLV0 0x20 +#define SLV1 0x24 +#define LNV 0x28 +#define CULH 0x2c +#define CULV 0x30 +#define HSIZE 0x34 +#define SDOFST 0x38 +#define CADU 0x3c +#define CADL 0x40 +#define LINCFG0 0x44 +#define LINCFG1 0x48 +#define CCOLP 0x4c +#define CRGAIN 0x50 +#define CGRGAIN 0x54 +#define CGBGAIN 0x58 +#define CBGAIN 0x5c +#define COFSTA 0x60 +#define FLSHCFG0 0x64 +#define FLSHCFG1 0x68 +#define FLSHCFG2 0x6c +#define VDINT0 0x70 +#define VDINT1 0x74 +#define VDINT2 0x78 +#define MISC 0x7c +#define CGAMMAWD 0x80 +#define REC656IF 0x84 +#define CCDCFG 0x88 +/***************************************************** +* Defect Correction registers +*****************************************************/ +#define DFCCTL 0x8c +#define VDFSATLV 0x90 +#define DFCMEMCTL 0x94 +#define DFCMEM0 0x98 +#define DFCMEM1 0x9c +#define DFCMEM2 0xa0 +#define DFCMEM3 0xa4 +#define DFCMEM4 0xa8 +/**************************************************** +* Black Clamp registers +****************************************************/ +#define CLAMPCFG 0xac +#define CLDCOFST 0xb0 +#define CLSV 0xb4 +#define CLHWIN0 0xb8 +#define CLHWIN1 0xbc +#define CLHWIN2 0xc0 +#define CLVRV 0xc4 +#define CLVWIN0 0xc8 +#define CLVWIN1 0xcc +#define CLVWIN2 0xd0 +#define CLVWIN3 0xd4 +/**************************************************** +* Lense Shading Correction +****************************************************/ +#define DATAHOFST 0xd8 +#define DATAVOFST 0xdc +#define LSCHVAL 0xe0 +#define LSCVVAL 0xe4 +#define TWODLSCCFG 0xe8 +#define TWODLSCOFST 0xec +#define TWODLSCINI 0xf0 +#define TWODLSCGRBU 0xf4 +#define TWODLSCGRBL 0xf8 +#define TWODLSCGROF 0xfc +#define TWODLSCORBU 0x100 +#define TWODLSCORBL 0x104 +#define TWODLSCOROF 0x108 +#define TWODLSCIRQEN 0x10c +#define TWODLSCIRQST 0x110 +/**************************************************** +* Data formatter +****************************************************/ +#define FMTCFG 0x114 +#define FMTPLEN 0x118 +#define FMTSPH 0x11c +#define FMTLNH 0x120 +#define FMTSLV 0x124 +#define FMTLNV 0x128 +#define FMTRLEN 0x12c +#define FMTHCNT 0x130 +#define FMTAPTR_BASE 0x134 +/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ +#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) +#define FMTPGMVF0 0x174 +#define FMTPGMVF1 0x178 +#define FMTPGMAPU0 0x17c +#define FMTPGMAPU1 0x180 +#define FMTPGMAPS0 0x184 +#define FMTPGMAPS1 0x188 +#define FMTPGMAPS2 0x18c +#define FMTPGMAPS3 0x190 +#define FMTPGMAPS4 0x194 +#define FMTPGMAPS5 0x198 +#define FMTPGMAPS6 0x19c +#define FMTPGMAPS7 0x1a0 +/************************************************ +* Color Space Converter +************************************************/ +#define CSCCTL 0x1a4 +#define CSCM0 0x1a8 +#define CSCM1 0x1ac +#define CSCM2 0x1b0 +#define CSCM3 0x1b4 +#define CSCM4 0x1b8 +#define CSCM5 0x1bc +#define CSCM6 0x1c0 +#define CSCM7 0x1c4 +#define OBWIN0 0x1c8 +#define OBWIN1 0x1cc +#define OBWIN2 0x1d0 +#define OBWIN3 0x1d4 +#define OBVAL0 0x1d8 +#define OBVAL1 0x1dc +#define OBVAL2 0x1e0 +#define OBVAL3 0x1e4 +#define OBVAL4 0x1e8 +#define OBVAL5 0x1ec +#define OBVAL6 0x1f0 +#define OBVAL7 0x1f4 +#define CLKCTL 0x1f8 + +/* Masks & Shifts below */ +#define START_PX_HOR_MASK 0x7FFF +#define NUM_PX_HOR_MASK 0x7FFF +#define START_VER_ONE_MASK 0x7FFF +#define START_VER_TWO_MASK 0x7FFF +#define NUM_LINES_VER 0x7FFF + +/* gain - offset masks */ +#define GAIN_INTEGER_SHIFT 9 +#define OFFSET_MASK 0xFFF +#define GAIN_SDRAM_EN_SHIFT 12 +#define GAIN_IPIPE_EN_SHIFT 13 +#define GAIN_H3A_EN_SHIFT 14 +#define OFST_SDRAM_EN_SHIFT 8 +#define OFST_IPIPE_EN_SHIFT 9 +#define OFST_H3A_EN_SHIFT 10 +#define GAIN_OFFSET_EN_MASK 0x7700 + +/* Culling */ +#define CULL_PAT_EVEN_LINE_SHIFT 8 + +/* CCDCFG register */ +#define ISIF_YCINSWP_RAW (0x00 << 4) +#define ISIF_YCINSWP_YCBCR (0x01 << 4) +#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) +#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) +#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) +#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) +#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) +#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) +#define ISIF_DATA_PACK_MASK 3 +#define ISIF_DATA_PACK16 0 +#define ISIF_DATA_PACK12 1 +#define ISIF_DATA_PACK8 2 +#define ISIF_PIX_ORDER_SHIFT 11 +#define ISIF_BW656_ENABLE (0x01 << 5) + +/* MODESET registers */ +#define ISIF_VDHDOUT_INPUT (0x00 << 0) +#define ISIF_INPUT_SHIFT 12 +#define ISIF_RAW_INPUT_MODE 0 +#define ISIF_FID_POL_SHIFT 4 +#define ISIF_HD_POL_SHIFT 3 +#define ISIF_VD_POL_SHIFT 2 +#define ISIF_DATAPOL_NORMAL 0 +#define ISIF_DATAPOL_SHIFT 6 +#define ISIF_EXWEN_DISABLE 0 +#define ISIF_EXWEN_SHIFT 5 +#define ISIF_FRM_FMT_SHIFT 7 +#define ISIF_DATASFT_SHIFT 8 +#define ISIF_LPF_SHIFT 14 +#define ISIF_LPF_MASK 1 + +/* GAMMAWD registers */ +#define ISIF_ALAW_GAMA_WD_MASK 0xF +#define ISIF_ALAW_GAMA_WD_SHIFT 1 +#define ISIF_ALAW_ENABLE 1 +#define ISIF_GAMMAWD_CFA_SHIFT 5 + +/* HSIZE registers */ +#define ISIF_HSIZE_FLIP_MASK 1 +#define ISIF_HSIZE_FLIP_SHIFT 12 + +/* MISC registers */ +#define ISIF_DPCM_EN_SHIFT 12 +#define ISIF_DPCM_PREDICTOR_SHIFT 13 + +/* Black clamp related */ +#define ISIF_BC_MODE_COLOR_SHIFT 4 +#define ISIF_HORZ_BC_MODE_SHIFT 1 +#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 +#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 +#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 +#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 +#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 +#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 + +/* VDFC registers */ +#define ISIF_VDFC_EN_SHIFT 4 +#define ISIF_VDFC_CORR_MOD_SHIFT 5 +#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 +#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 +#define ISIF_VDFC_POS_MASK 0x1FFF +#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 + +/* CSC registers */ +#define ISIF_CSC_COEF_INTEG_MASK 7 +#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f +#define ISIF_CSC_COEF_INTEG_SHIFT 5 +#define ISIF_CSCM_MSB_SHIFT 8 +#define ISIF_DF_CSC_SPH_MASK 0x1FFF +#define ISIF_DF_CSC_LNH_MASK 0x1FFF +#define ISIF_DF_CSC_SLV_MASK 0x1FFF +#define ISIF_DF_CSC_LNV_MASK 0x1FFF +#define ISIF_DF_NUMLINES 0x7FFF +#define ISIF_DF_NUMPIX 0x1FFF + +/* Offsets for LSC/DFC/Gain */ +#define ISIF_DATA_H_OFFSET_MASK 0x1FFF +#define ISIF_DATA_V_OFFSET_MASK 0x1FFF + +/* Linearization */ +#define ISIF_LIN_CORRSFT_SHIFT 4 +#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 + + +/* Pattern registers */ +#define ISIF_PG_EN (1 << 3) +#define ISIF_SEL_PG_SRC (3 << 4) +#define ISIF_PG_VD_POL_SHIFT 0 +#define ISIF_PG_HD_POL_SHIFT 1 + +/*random other junk*/ +#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) +#define ISIF_SYNCEN_WEN_MASK (1 << 1) +#define ISIF_SYNCEN_WEN_SHIFT 1 + +#endif diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index de22bc9faf2..885cd54499c 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -107,9 +107,6 @@ struct ccdc_config { int vpfe_probed; /* name of ccdc device */ char name[32]; - /* for storing mem maps for CCDC */ - int ccdc_addr_size; - void *__iomem ccdc_addr; }; /* data structures */ @@ -229,7 +226,6 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) BUG_ON(!dev->hw_ops.set_image_window); BUG_ON(!dev->hw_ops.get_image_window); BUG_ON(!dev->hw_ops.get_line_length); - BUG_ON(!dev->hw_ops.setfbaddr); BUG_ON(!dev->hw_ops.getfid); mutex_lock(&ccdc_lock); @@ -240,25 +236,23 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) * walk through it during vpfe probe */ printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -1; + ret = -EFAULT; goto unlock; } if (strcmp(dev->name, ccdc_cfg->name)) { /* ignore this ccdc */ - ret = -1; + ret = -EINVAL; goto unlock; } if (ccdc_dev) { printk(KERN_ERR "ccdc already registered\n"); - ret = -1; + ret = -EINVAL; goto unlock; } ccdc_dev = dev; - dev->hw_ops.set_ccdc_base(ccdc_cfg->ccdc_addr, - ccdc_cfg->ccdc_addr_size); unlock: mutex_unlock(&ccdc_lock); return ret; @@ -1786,61 +1780,6 @@ static struct vpfe_device *vpfe_initialize(void) return vpfe_dev; } -static void vpfe_disable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - - clk_disable(vpfe_cfg->vpssclk); - clk_put(vpfe_cfg->vpssclk); - clk_disable(vpfe_cfg->slaveclk); - clk_put(vpfe_cfg->slaveclk); - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master & slave clocks disabled\n"); -} - -static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int ret = -ENOENT; - - vpfe_cfg->vpssclk = clk_get(vpfe_dev->pdev, "vpss_master"); - if (NULL == vpfe_cfg->vpssclk) { - v4l2_err(vpfe_dev->pdev->driver, "No clock defined for" - "vpss_master\n"); - return ret; - } - - if (clk_enable(vpfe_cfg->vpssclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss master clock not enabled\n"); - goto out; - } - v4l2_info(vpfe_dev->pdev->driver, - "vpfe vpss master clock enabled\n"); - - vpfe_cfg->slaveclk = clk_get(vpfe_dev->pdev, "vpss_slave"); - if (NULL == vpfe_cfg->slaveclk) { - v4l2_err(vpfe_dev->pdev->driver, - "No clock defined for vpss slave\n"); - goto out; - } - - if (clk_enable(vpfe_cfg->slaveclk)) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe vpss slave clock not enabled\n"); - goto out; - } - v4l2_info(vpfe_dev->pdev->driver, "vpfe vpss slave clock enabled\n"); - return 0; -out: - if (vpfe_cfg->vpssclk) - clk_put(vpfe_cfg->vpssclk); - if (vpfe_cfg->slaveclk) - clk_put(vpfe_cfg->slaveclk); - - return -1; -} - /* * vpfe_probe : This function creates device entries by register * itself to the V4L2 driver and initializes fields of each @@ -1870,7 +1809,7 @@ static __init int vpfe_probe(struct platform_device *pdev) if (NULL == pdev->dev.platform_data) { v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENOENT; + ret = -ENODEV; goto probe_free_dev_mem; } @@ -1884,18 +1823,13 @@ static __init int vpfe_probe(struct platform_device *pdev) goto probe_free_dev_mem; } - /* enable vpss clocks */ - ret = vpfe_enable_clock(vpfe_dev); - if (ret) - goto probe_free_dev_mem; - mutex_lock(&ccdc_lock); /* Allocate memory for ccdc configuration */ ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); if (NULL == ccdc_cfg) { v4l2_err(pdev->dev.driver, "Memory allocation failed for ccdc_cfg\n"); - goto probe_disable_clock; + goto probe_free_dev_mem; } strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); @@ -1904,61 +1838,34 @@ static __init int vpfe_probe(struct platform_device *pdev) if (!res1) { v4l2_err(pdev->dev.driver, "Unable to get interrupt for VINT0\n"); - ret = -ENOENT; - goto probe_disable_clock; + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; } vpfe_dev->ccdc_irq0 = res1->start; /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, - IORESOURCE_IRQ, 1); + res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (!res1) { v4l2_err(pdev->dev.driver, "Unable to get interrupt for VINT1\n"); - ret = -ENOENT; - goto probe_disable_clock; + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; } vpfe_dev->ccdc_irq1 = res1->start; - /* Get address base of CCDC */ - res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get register address map\n"); - ret = -ENOENT; - goto probe_disable_clock; - } - - ccdc_cfg->ccdc_addr_size = res1->end - res1->start + 1; - if (!request_mem_region(res1->start, ccdc_cfg->ccdc_addr_size, - pdev->dev.driver->name)) { - v4l2_err(pdev->dev.driver, - "Failed request_mem_region for ccdc base\n"); - ret = -ENXIO; - goto probe_disable_clock; - } - ccdc_cfg->ccdc_addr = ioremap_nocache(res1->start, - ccdc_cfg->ccdc_addr_size); - if (!ccdc_cfg->ccdc_addr) { - v4l2_err(pdev->dev.driver, "Unable to ioremap ccdc addr\n"); - ret = -ENXIO; - goto probe_out_release_mem1; - } - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, "vpfe_capture0", vpfe_dev); if (0 != ret) { v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); - goto probe_out_unmap1; + goto probe_free_ccdc_cfg_mem; } /* Allocate memory for video device */ vfd = video_device_alloc(); if (NULL == vfd) { ret = -ENOMEM; - v4l2_err(pdev->dev.driver, - "Unable to alloc video device\n"); + v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); goto probe_out_release_irq; } @@ -2073,12 +1980,7 @@ probe_out_video_release: video_device_release(vpfe_dev->video_dev); probe_out_release_irq: free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); -probe_out_unmap1: - iounmap(ccdc_cfg->ccdc_addr); -probe_out_release_mem1: - release_mem_region(res1->start, res1->end - res1->start + 1); -probe_disable_clock: - vpfe_disable_clock(vpfe_dev); +probe_free_ccdc_cfg_mem: mutex_unlock(&ccdc_lock); kfree(ccdc_cfg); probe_free_dev_mem: @@ -2092,7 +1994,6 @@ probe_free_dev_mem: static int __devexit vpfe_remove(struct platform_device *pdev) { struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - struct resource *res; v4l2_info(pdev->dev.driver, "vpfe_remove\n"); @@ -2100,12 +2001,6 @@ static int __devexit vpfe_remove(struct platform_device *pdev) kfree(vpfe_dev->sd); v4l2_device_unregister(&vpfe_dev->v4l2_dev); video_unregister_device(vpfe_dev->video_dev); - mutex_lock(&ccdc_lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); - iounmap(ccdc_cfg->ccdc_addr); - mutex_unlock(&ccdc_lock); - vpfe_disable_clock(vpfe_dev); kfree(vpfe_dev); kfree(ccdc_cfg); return 0; diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c index 7ee72ecd3d8..7918680917d 100644 --- a/drivers/media/video/davinci/vpss.c +++ b/drivers/media/video/davinci/vpss.c @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * common vpss driver for all video drivers. + * common vpss system module platform driver for all video drivers. */ #include <linux/kernel.h> #include <linux/sched.h> @@ -35,12 +35,52 @@ MODULE_AUTHOR("Texas Instruments"); /* DM644x defines */ #define DM644X_SBL_PCR_VPSS (4) +#define DM355_VPSSBL_INTSEL 0x10 +#define DM355_VPSSBL_EVTSEL 0x14 /* vpss BL register offsets */ #define DM355_VPSSBL_CCDCMUX 0x1c /* vpss CLK register offsets */ #define DM355_VPSSCLK_CLKCTRL 0x04 /* masks and shifts */ #define VPSS_HSSISEL_SHIFT 4 +/* + * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, + * IPIPE_INT1_SDR - vpss_int5 + */ +#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 +/* VENCINT - vpss_int8 */ +#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 + +#define DM365_ISP5_PCCR 0x04 +#define DM365_ISP5_INTSEL1 0x10 +#define DM365_ISP5_INTSEL2 0x14 +#define DM365_ISP5_INTSEL3 0x18 +#define DM365_ISP5_CCDCMUX 0x20 +#define DM365_ISP5_PG_FRAME_SIZE 0x28 +#define DM365_VPBE_CLK_CTRL 0x00 +/* + * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, + * AF - vpss_int3 + */ +#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 +/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ +#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f +/* VENC - vpss_int8 */ +#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 + +/* masks and shifts for DM365*/ +#define DM365_CCDC_PG_VD_POL_SHIFT 0 +#define DM365_CCDC_PG_HD_POL_SHIFT 1 + +#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) +#define CCD_SRC_SEL_SHIFT 4 + +/* Different SoC platforms supported by this driver */ +enum vpss_platform_type { + DM644X, + DM355, + DM365, +}; /* * vpss operations. Depends on platform. Not all functions are available @@ -59,13 +99,9 @@ struct vpss_hw_ops { /* vpss configuration */ struct vpss_oper_config { - __iomem void *vpss_bl_regs_base; - __iomem void *vpss_regs_base; - struct resource *r1; - resource_size_t len1; - struct resource *r2; - resource_size_t len2; - char vpss_name[32]; + __iomem void *vpss_regs_base0; + __iomem void *vpss_regs_base1; + enum vpss_platform_type platform; spinlock_t vpss_lock; struct vpss_hw_ops hw_ops; }; @@ -75,22 +111,46 @@ static struct vpss_oper_config oper_cfg; /* register access routines */ static inline u32 bl_regr(u32 offset) { - return __raw_readl(oper_cfg.vpss_bl_regs_base + offset); + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); } static inline void bl_regw(u32 val, u32 offset) { - __raw_writel(val, oper_cfg.vpss_bl_regs_base + offset); + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); } static inline u32 vpss_regr(u32 offset) { - return __raw_readl(oper_cfg.vpss_regs_base + offset); + return __raw_readl(oper_cfg.vpss_regs_base1 + offset); } static inline void vpss_regw(u32 val, u32 offset) { - __raw_writel(val, oper_cfg.vpss_regs_base + offset); + __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); +} + +/* For DM365 only */ +static inline u32 isp5_read(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); +} + +/* For DM365 only */ +static inline void isp5_write(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); +} + +static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; + + /* if we are using pattern generator, enable it */ + if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) + temp |= 0x08; + + temp |= (src_sel << CCD_SRC_SEL_SHIFT); + isp5_write(temp, DM365_ISP5_CCDCMUX); } static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) @@ -101,9 +161,9 @@ static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) { if (!oper_cfg.hw_ops.select_ccdc_source) - return -1; + return -EINVAL; - dm355_select_ccdc_source(src_sel); + oper_cfg.hw_ops.select_ccdc_source(src_sel); return 0; } EXPORT_SYMBOL(vpss_select_ccdc_source); @@ -114,7 +174,7 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) if (wbl_sel < VPSS_PCR_AEW_WBL_0 || wbl_sel > VPSS_PCR_CCDC_WBL_O) - return -1; + return -EINVAL; /* writing a 0 clear the overflow */ mask = ~(mask << wbl_sel); @@ -126,7 +186,7 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) { if (!oper_cfg.hw_ops.clear_wbl_overflow) - return -1; + return -EINVAL; return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); } @@ -166,7 +226,7 @@ static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) default: printk(KERN_ERR "dm355_enable_clock:" " Invalid selector: %d\n", clock_sel); - return -1; + return -EINVAL; } spin_lock_irqsave(&oper_cfg.vpss_lock, flags); @@ -181,100 +241,221 @@ static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) return 0; } +static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + unsigned long flags; + u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; + u32 (*read)(u32 offset) = isp5_read; + void(*write)(u32 val, u32 offset) = isp5_write; + + switch (clock_sel) { + case VPSS_BL_CLOCK: + break; + case VPSS_CCDC_CLOCK: + shift = 1; + break; + case VPSS_H3A_CLOCK: + shift = 2; + break; + case VPSS_RSZ_CLOCK: + shift = 3; + break; + case VPSS_IPIPE_CLOCK: + shift = 4; + break; + case VPSS_IPIPEIF_CLOCK: + shift = 5; + break; + case VPSS_PCLK_INTERNAL: + shift = 6; + break; + case VPSS_PSYNC_CLOCK_SEL: + shift = 7; + break; + case VPSS_VPBE_CLOCK: + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_VENC_CLOCK_SEL: + shift = 2; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK: + shift = 3; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_FDIF_CLOCK: + shift = 4; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_OSD_CLOCK_SEL: + shift = 6; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK_SEL: + shift = 7; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + default: + printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", + clock_sel); + return -1; + } + + spin_lock_irqsave(&oper_cfg.vpss_lock, flags); + utemp = read(offset); + if (!en) { + mask = ~mask; + utemp &= (mask << shift); + } else + utemp |= (mask << shift); + + write(utemp, offset); + spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); + + return 0; +} + int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) { if (!oper_cfg.hw_ops.enable_clock) - return -1; + return -EINVAL; return oper_cfg.hw_ops.enable_clock(clock_sel, en); } EXPORT_SYMBOL(vpss_enable_clock); +void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) +{ + int val = 0; + val = isp5_read(DM365_ISP5_CCDCMUX); + + val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); + val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); + + isp5_write(val, DM365_ISP5_CCDCMUX); +} +EXPORT_SYMBOL(dm365_vpss_set_sync_pol); + +void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) +{ + int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; + + current_reg |= (frame_size.pplen - 1); + isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); +} +EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); + static int __init vpss_probe(struct platform_device *pdev) { - int status, dm355 = 0; + struct resource *r1, *r2; + char *platform_name; + int status; if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "no platform data\n"); return -ENOENT; } - strcpy(oper_cfg.vpss_name, pdev->dev.platform_data); - if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) - dm355 = 1; - else if (strcmp(oper_cfg.vpss_name, "dm644x_vpss")) { + platform_name = pdev->dev.platform_data; + if (!strcmp(platform_name, "dm355_vpss")) + oper_cfg.platform = DM355; + else if (!strcmp(platform_name, "dm365_vpss")) + oper_cfg.platform = DM365; + else if (!strcmp(platform_name, "dm644x_vpss")) + oper_cfg.platform = DM644X; + else { dev_err(&pdev->dev, "vpss driver not supported on" " this platform\n"); return -ENODEV; } - dev_info(&pdev->dev, "%s vpss probed\n", oper_cfg.vpss_name); - oper_cfg.r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!oper_cfg.r1) + dev_info(&pdev->dev, "%s vpss probed\n", platform_name); + r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r1) return -ENOENT; - oper_cfg.len1 = oper_cfg.r1->end - oper_cfg.r1->start + 1; - - oper_cfg.r1 = request_mem_region(oper_cfg.r1->start, oper_cfg.len1, - oper_cfg.r1->name); - if (!oper_cfg.r1) + r1 = request_mem_region(r1->start, resource_size(r1), r1->name); + if (!r1) return -EBUSY; - oper_cfg.vpss_bl_regs_base = ioremap(oper_cfg.r1->start, oper_cfg.len1); - if (!oper_cfg.vpss_bl_regs_base) { + oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1)); + if (!oper_cfg.vpss_regs_base0) { status = -EBUSY; goto fail1; } - if (dm355) { - oper_cfg.r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!oper_cfg.r2) { + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!r2) { status = -ENOENT; goto fail2; } - oper_cfg.len2 = oper_cfg.r2->end - oper_cfg.r2->start + 1; - oper_cfg.r2 = request_mem_region(oper_cfg.r2->start, - oper_cfg.len2, - oper_cfg.r2->name); - if (!oper_cfg.r2) { + r2 = request_mem_region(r2->start, resource_size(r2), r2->name); + if (!r2) { status = -EBUSY; goto fail2; } - oper_cfg.vpss_regs_base = ioremap(oper_cfg.r2->start, - oper_cfg.len2); - if (!oper_cfg.vpss_regs_base) { + oper_cfg.vpss_regs_base1 = ioremap(r2->start, + resource_size(r2)); + if (!oper_cfg.vpss_regs_base1) { status = -EBUSY; goto fail3; } } - if (dm355) { + if (oper_cfg.platform == DM355) { oper_cfg.hw_ops.enable_clock = dm355_enable_clock; oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; + /* Setup vpss interrupts */ + bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); + bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); + } else if (oper_cfg.platform == DM365) { + oper_cfg.hw_ops.enable_clock = dm365_enable_clock; + oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; + /* Setup vpss interrupts */ + isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); + isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); + isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); } else oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; spin_lock_init(&oper_cfg.vpss_lock); - dev_info(&pdev->dev, "%s vpss probe success\n", oper_cfg.vpss_name); + dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); return 0; fail3: - release_mem_region(oper_cfg.r2->start, oper_cfg.len2); + release_mem_region(r2->start, resource_size(r2)); fail2: - iounmap(oper_cfg.vpss_bl_regs_base); + iounmap(oper_cfg.vpss_regs_base0); fail1: - release_mem_region(oper_cfg.r1->start, oper_cfg.len1); + release_mem_region(r1->start, resource_size(r1)); return status; } static int __devexit vpss_remove(struct platform_device *pdev) { - iounmap(oper_cfg.vpss_bl_regs_base); - release_mem_region(oper_cfg.r1->start, oper_cfg.len1); - if (!strcmp(oper_cfg.vpss_name, "dm355_vpss")) { - iounmap(oper_cfg.vpss_regs_base); - release_mem_region(oper_cfg.r2->start, oper_cfg.len2); + struct resource *res; + + iounmap(oper_cfg.vpss_regs_base0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + iounmap(oper_cfg.vpss_regs_base1); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(res->start, resource_size(res)); } return 0; } |