dm355_ccdc.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /*
  2. * Copyright (C) 2005-2009 Texas Instruments Inc
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. * CCDC hardware module for DM355
  19. * ------------------------------
  20. *
  21. * This module is for configuring DM355 CCD controller of VPFE to capture
  22. * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
  23. * such as Defect Pixel Correction, Color Space Conversion etc to
  24. * pre-process the Bayer RGB data, before writing it to SDRAM. This
  25. * module also allows application to configure individual
  26. * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
  27. * To do so, application include dm355_ccdc.h and vpfe_capture.h header
  28. * files. The setparams() API is called by vpfe_capture driver
  29. * to configure module parameters
  30. *
  31. * TODO: 1) Raw bayer parameter settings and bayer capture
  32. * 2) Split module parameter structure to module specific ioctl structs
  33. * 3) add support for lense shading correction
  34. * 4) investigate if enum used for user space type definition
  35. * to be replaced by #defines or integer
  36. */
  37. #include <linux/platform_device.h>
  38. #include <linux/uaccess.h>
  39. #include <linux/videodev2.h>
  40. #include <media/davinci/dm355_ccdc.h>
  41. #include <media/davinci/vpss.h>
  42. #include "dm355_ccdc_regs.h"
  43. #include "ccdc_hw_device.h"
  44. MODULE_LICENSE("GPL");
  45. MODULE_DESCRIPTION("CCDC Driver for DM355");
  46. MODULE_AUTHOR("Texas Instruments");
  47. static struct device *dev;
  48. /* Object for CCDC raw mode */
  49. static struct ccdc_params_raw ccdc_hw_params_raw = {
  50. .pix_fmt = CCDC_PIXFMT_RAW,
  51. .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
  52. .win = CCDC_WIN_VGA,
  53. .fid_pol = VPFE_PINPOL_POSITIVE,
  54. .vd_pol = VPFE_PINPOL_POSITIVE,
  55. .hd_pol = VPFE_PINPOL_POSITIVE,
  56. .gain = {
  57. .r_ye = 256,
  58. .gb_g = 256,
  59. .gr_cy = 256,
  60. .b_mg = 256
  61. },
  62. .config_params = {
  63. .datasft = 2,
  64. .data_sz = CCDC_DATA_10BITS,
  65. .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
  66. .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
  67. .alaw = {
  68. .gama_wd = 2,
  69. },
  70. .blk_clamp = {
  71. .sample_pixel = 1,
  72. .dc_sub = 25
  73. },
  74. .col_pat_field0 = {
  75. .olop = CCDC_GREEN_BLUE,
  76. .olep = CCDC_BLUE,
  77. .elop = CCDC_RED,
  78. .elep = CCDC_GREEN_RED
  79. },
  80. .col_pat_field1 = {
  81. .olop = CCDC_GREEN_BLUE,
  82. .olep = CCDC_BLUE,
  83. .elop = CCDC_RED,
  84. .elep = CCDC_GREEN_RED
  85. },
  86. },
  87. };
  88. /* Object for CCDC ycbcr mode */
  89. static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
  90. .win = CCDC_WIN_PAL,
  91. .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
  92. .frm_fmt = CCDC_FRMFMT_INTERLACED,
  93. .fid_pol = VPFE_PINPOL_POSITIVE,
  94. .vd_pol = VPFE_PINPOL_POSITIVE,
  95. .hd_pol = VPFE_PINPOL_POSITIVE,
  96. .bt656_enable = 1,
  97. .pix_order = CCDC_PIXORDER_CBYCRY,
  98. .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
  99. };
  100. static enum vpfe_hw_if_type ccdc_if_type;
  101. static void *__iomem ccdc_base_addr;
  102. static int ccdc_addr_size;
  103. /* Raw Bayer formats */
  104. static u32 ccdc_raw_bayer_pix_formats[] =
  105. {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
  106. /* Raw YUV formats */
  107. static u32 ccdc_raw_yuv_pix_formats[] =
  108. {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
  109. /* register access routines */
  110. static inline u32 regr(u32 offset)
  111. {
  112. return __raw_readl(ccdc_base_addr + offset);
  113. }
  114. static inline void regw(u32 val, u32 offset)
  115. {
  116. __raw_writel(val, ccdc_base_addr + offset);
  117. }
  118. static void ccdc_set_ccdc_base(void *addr, int size)
  119. {
  120. ccdc_base_addr = addr;
  121. ccdc_addr_size = size;
  122. }
  123. static void ccdc_enable(int en)
  124. {
  125. unsigned int temp;
  126. temp = regr(SYNCEN);
  127. temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
  128. temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
  129. regw(temp, SYNCEN);
  130. }
  131. static void ccdc_enable_output_to_sdram(int en)
  132. {
  133. unsigned int temp;
  134. temp = regr(SYNCEN);
  135. temp &= (~(CCDC_SYNCEN_WEN_MASK));
  136. temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
  137. regw(temp, SYNCEN);
  138. }
  139. static void ccdc_config_gain_offset(void)
  140. {
  141. /* configure gain */
  142. regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN);
  143. regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN);
  144. regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN);
  145. regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN);
  146. /* configure offset */
  147. regw(ccdc_hw_params_raw.ccdc_offset, OFFSET);
  148. }
  149. /*
  150. * ccdc_restore_defaults()
  151. * This function restore power on defaults in the ccdc registers
  152. */
  153. static int ccdc_restore_defaults(void)
  154. {
  155. int i;
  156. dev_dbg(dev, "\nstarting ccdc_restore_defaults...");
  157. /* set all registers to zero */
  158. for (i = 0; i <= CCDC_REG_LAST; i += 4)
  159. regw(0, i);
  160. /* now override the values with power on defaults in registers */
  161. regw(MODESET_DEFAULT, MODESET);
  162. /* no culling support */
  163. regw(CULH_DEFAULT, CULH);
  164. regw(CULV_DEFAULT, CULV);
  165. /* Set default Gain and Offset */
  166. ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT;
  167. ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT;
  168. ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT;
  169. ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT;
  170. ccdc_config_gain_offset();
  171. regw(OUTCLIP_DEFAULT, OUTCLIP);
  172. regw(LSCCFG2_DEFAULT, LSCCFG2);
  173. /* select ccdc input */
  174. if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
  175. dev_dbg(dev, "\ncouldn't select ccdc input source");
  176. return -EFAULT;
  177. }
  178. /* select ccdc clock */
  179. if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
  180. dev_dbg(dev, "\ncouldn't enable ccdc clock");
  181. return -EFAULT;
  182. }
  183. dev_dbg(dev, "\nEnd of ccdc_restore_defaults...");
  184. return 0;
  185. }
  186. static int ccdc_open(struct device *device)
  187. {
  188. dev = device;
  189. return ccdc_restore_defaults();
  190. }
  191. static int ccdc_close(struct device *device)
  192. {
  193. /* disable clock */
  194. vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
  195. /* do nothing for now */
  196. return 0;
  197. }
  198. /*
  199. * ccdc_setwin()
  200. * This function will configure the window size to
  201. * be capture in CCDC reg.
  202. */
  203. static void ccdc_setwin(struct v4l2_rect *image_win,
  204. enum ccdc_frmfmt frm_fmt, int ppc)
  205. {
  206. int horz_start, horz_nr_pixels;
  207. int vert_start, vert_nr_lines;
  208. int mid_img = 0;
  209. dev_dbg(dev, "\nStarting ccdc_setwin...");
  210. /*
  211. * ppc - per pixel count. indicates how many pixels per cell
  212. * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
  213. * raw capture this is 1
  214. */
  215. horz_start = image_win->left << (ppc - 1);
  216. horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
  217. /* Writing the horizontal info into the registers */
  218. regw(horz_start, SPH);
  219. regw(horz_nr_pixels, NPH);
  220. vert_start = image_win->top;
  221. if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
  222. vert_nr_lines = (image_win->height >> 1) - 1;
  223. vert_start >>= 1;
  224. /* Since first line doesn't have any data */
  225. vert_start += 1;
  226. /* configure VDINT0 and VDINT1 */
  227. regw(vert_start, VDINT0);
  228. } else {
  229. /* Since first line doesn't have any data */
  230. vert_start += 1;
  231. vert_nr_lines = image_win->height - 1;
  232. /* configure VDINT0 and VDINT1 */
  233. mid_img = vert_start + (image_win->height / 2);
  234. regw(vert_start, VDINT0);
  235. regw(mid_img, VDINT1);
  236. }
  237. regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
  238. regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
  239. regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
  240. dev_dbg(dev, "\nEnd of ccdc_setwin...");
  241. }
  242. static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
  243. {
  244. if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
  245. ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
  246. dev_dbg(dev, "Invalid value of data shift\n");
  247. return -EINVAL;
  248. }
  249. if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
  250. ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
  251. dev_dbg(dev, "Invalid value of median filter1\n");
  252. return -EINVAL;
  253. }
  254. if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
  255. ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
  256. dev_dbg(dev, "Invalid value of median filter2\n");
  257. return -EINVAL;
  258. }
  259. if ((ccdcparam->med_filt_thres < 0) ||
  260. (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
  261. dev_dbg(dev, "Invalid value of median filter threshold\n");
  262. return -EINVAL;
  263. }
  264. if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
  265. ccdcparam->data_sz > CCDC_DATA_8BITS) {
  266. dev_dbg(dev, "Invalid value of data size\n");
  267. return -EINVAL;
  268. }
  269. if (ccdcparam->alaw.enable) {
  270. if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
  271. ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
  272. dev_dbg(dev, "Invalid value of ALAW\n");
  273. return -EINVAL;
  274. }
  275. }
  276. if (ccdcparam->blk_clamp.b_clamp_enable) {
  277. if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
  278. ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
  279. dev_dbg(dev, "Invalid value of sample pixel\n");
  280. return -EINVAL;
  281. }
  282. if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
  283. ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
  284. dev_dbg(dev, "Invalid value of sample lines\n");
  285. return -EINVAL;
  286. }
  287. }
  288. return 0;
  289. }
  290. /* Parameter operations */
  291. static int ccdc_set_params(void __user *params)
  292. {
  293. struct ccdc_config_params_raw ccdc_raw_params;
  294. int x;
  295. /* only raw module parameters can be set through the IOCTL */
  296. if (ccdc_if_type != VPFE_RAW_BAYER)
  297. return -EINVAL;
  298. x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
  299. if (x) {
  300. dev_dbg(dev, "ccdc_set_params: error in copying ccdc"
  301. "params, %d\n", x);
  302. return -EFAULT;
  303. }
  304. if (!validate_ccdc_param(&ccdc_raw_params)) {
  305. memcpy(&ccdc_hw_params_raw.config_params,
  306. &ccdc_raw_params,
  307. sizeof(ccdc_raw_params));
  308. return 0;
  309. }
  310. return -EINVAL;
  311. }
  312. /* This function will configure CCDC for YCbCr video capture */
  313. static void ccdc_config_ycbcr(void)
  314. {
  315. struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
  316. u32 temp;
  317. /* first set the CCDC power on defaults values in all registers */
  318. dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
  319. ccdc_restore_defaults();
  320. /* configure pixel format & video frame format */
  321. temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
  322. CCDC_INPUT_MODE_SHIFT) |
  323. ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
  324. CCDC_FRM_FMT_SHIFT));
  325. /* setup BT.656 sync mode */
  326. if (params->bt656_enable) {
  327. regw(CCDC_REC656IF_BT656_EN, REC656IF);
  328. /*
  329. * configure the FID, VD, HD pin polarity fld,hd pol positive,
  330. * vd negative, 8-bit pack mode
  331. */
  332. temp |= CCDC_VD_POL_NEGATIVE;
  333. } else { /* y/c external sync mode */
  334. temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
  335. CCDC_FID_POL_SHIFT) |
  336. ((params->hd_pol & CCDC_HD_POL_MASK) <<
  337. CCDC_HD_POL_SHIFT) |
  338. ((params->vd_pol & CCDC_VD_POL_MASK) <<
  339. CCDC_VD_POL_SHIFT));
  340. }
  341. /* pack the data to 8-bit */
  342. temp |= CCDC_DATA_PACK_ENABLE;
  343. regw(temp, MODESET);
  344. /* configure video window */
  345. ccdc_setwin(&params->win, params->frm_fmt, 2);
  346. /* configure the order of y cb cr in SD-RAM */
  347. temp = (params->pix_order << CCDC_Y8POS_SHIFT);
  348. temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
  349. regw(temp, CCDCFG);
  350. /*
  351. * configure the horizontal line offset. This is done by rounding up
  352. * width to a multiple of 16 pixels and multiply by two to account for
  353. * y:cb:cr 4:2:2 data
  354. */
  355. regw(((params->win.width * 2 + 31) >> 5), HSIZE);
  356. /* configure the memory line offset */
  357. if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
  358. /* two fields are interleaved in memory */
  359. regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
  360. }
  361. dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
  362. }
  363. /*
  364. * ccdc_config_black_clamp()
  365. * configure parameters for Optical Black Clamp
  366. */
  367. static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
  368. {
  369. u32 val;
  370. if (!bclamp->b_clamp_enable) {
  371. /* configure DCSub */
  372. regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
  373. regw(0x0000, CLAMP);
  374. return;
  375. }
  376. /* Enable the Black clamping, set sample lines and pixels */
  377. val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
  378. ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
  379. CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
  380. regw(val, CLAMP);
  381. /* If Black clamping is enable then make dcsub 0 */
  382. val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
  383. << CCDC_NUM_LINE_CALC_SHIFT;
  384. regw(val, DCSUB);
  385. }
  386. /*
  387. * ccdc_config_black_compense()
  388. * configure parameters for Black Compensation
  389. */
  390. static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
  391. {
  392. u32 val;
  393. val = (bcomp->b & CCDC_BLK_COMP_MASK) |
  394. ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
  395. CCDC_BLK_COMP_GB_COMP_SHIFT);
  396. regw(val, BLKCMP1);
  397. val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
  398. CCDC_BLK_COMP_GR_COMP_SHIFT) |
  399. ((bcomp->r & CCDC_BLK_COMP_MASK) <<
  400. CCDC_BLK_COMP_R_COMP_SHIFT);
  401. regw(val, BLKCMP0);
  402. }
  403. /*
  404. * ccdc_write_dfc_entry()
  405. * write an entry in the dfc table.
  406. */
  407. int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
  408. {
  409. /* TODO This is to be re-visited and adjusted */
  410. #define DFC_WRITE_WAIT_COUNT 1000
  411. u32 val, count = DFC_WRITE_WAIT_COUNT;
  412. regw(dfc->dft_corr_vert[index], DFCMEM0);
  413. regw(dfc->dft_corr_horz[index], DFCMEM1);
  414. regw(dfc->dft_corr_sub1[index], DFCMEM2);
  415. regw(dfc->dft_corr_sub2[index], DFCMEM3);
  416. regw(dfc->dft_corr_sub3[index], DFCMEM4);
  417. /* set WR bit to write */
  418. val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
  419. regw(val, DFCMEMCTL);
  420. /*
  421. * Assume, it is very short. If we get an error, we need to
  422. * adjust this value
  423. */
  424. while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
  425. count--;
  426. /*
  427. * TODO We expect the count to be non-zero to be successful. Adjust
  428. * the count if write requires more time
  429. */
  430. if (count) {
  431. dev_err(dev, "defect table write timeout !!!\n");
  432. return -1;
  433. }
  434. return 0;
  435. }
  436. /*
  437. * ccdc_config_vdfc()
  438. * configure parameters for Vertical Defect Correction
  439. */
  440. static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
  441. {
  442. u32 val;
  443. int i;
  444. /* Configure General Defect Correction. The table used is from IPIPE */
  445. val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
  446. /* Configure Vertical Defect Correction if needed */
  447. if (!dfc->ver_dft_en) {
  448. /* Enable only General Defect Correction */
  449. regw(val, DFCCTL);
  450. return 0;
  451. }
  452. if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
  453. return -EINVAL;
  454. val |= CCDC_DFCCTL_VDFC_DISABLE;
  455. val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
  456. CCDC_DFCCTL_VDFCSL_SHIFT;
  457. val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
  458. CCDC_DFCCTL_VDFCUDA_SHIFT;
  459. val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
  460. CCDC_DFCCTL_VDFLSFT_SHIFT;
  461. regw(val , DFCCTL);
  462. /* clear address ptr to offset 0 */
  463. val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
  464. /* write defect table entries */
  465. for (i = 0; i < dfc->table_size; i++) {
  466. /* increment address for non zero index */
  467. if (i != 0)
  468. val = CCDC_DFCMEMCTL_INC_ADDR;
  469. regw(val, DFCMEMCTL);
  470. if (ccdc_write_dfc_entry(i, dfc) < 0)
  471. return -EFAULT;
  472. }
  473. /* update saturation level and enable dfc */
  474. regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
  475. val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
  476. CCDC_DFCCTL_VDFCEN_SHIFT);
  477. regw(val, DFCCTL);
  478. return 0;
  479. }
  480. /*
  481. * ccdc_config_csc()
  482. * configure parameters for color space conversion
  483. * Each register CSCM0-7 has two values in S8Q5 format.
  484. */
  485. static void ccdc_config_csc(struct ccdc_csc *csc)
  486. {
  487. u32 val1, val2;
  488. int i;
  489. if (!csc->enable)
  490. return;
  491. /* Enable the CSC sub-module */
  492. regw(CCDC_CSC_ENABLE, CSCCTL);
  493. /* Converting the co-eff as per the format of the register */
  494. for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
  495. if ((i % 2) == 0) {
  496. /* CSCM - LSB */
  497. val1 = (csc->coeff[i].integer &
  498. CCDC_CSC_COEF_INTEG_MASK)
  499. << CCDC_CSC_COEF_INTEG_SHIFT;
  500. /*
  501. * convert decimal part to binary. Use 2 decimal
  502. * precision, user values range from .00 - 0.99
  503. */
  504. val1 |= (((csc->coeff[i].decimal &
  505. CCDC_CSC_COEF_DECIMAL_MASK) *
  506. CCDC_CSC_DEC_MAX) / 100);
  507. } else {
  508. /* CSCM - MSB */
  509. val2 = (csc->coeff[i].integer &
  510. CCDC_CSC_COEF_INTEG_MASK)
  511. << CCDC_CSC_COEF_INTEG_SHIFT;
  512. val2 |= (((csc->coeff[i].decimal &
  513. CCDC_CSC_COEF_DECIMAL_MASK) *
  514. CCDC_CSC_DEC_MAX) / 100);
  515. val2 <<= CCDC_CSCM_MSB_SHIFT;
  516. val2 |= val1;
  517. regw(val2, (CSCM0 + ((i - 1) << 1)));
  518. }
  519. }
  520. }
  521. /*
  522. * ccdc_config_color_patterns()
  523. * configure parameters for color patterns
  524. */
  525. static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
  526. struct ccdc_col_pat *pat1)
  527. {
  528. u32 val;
  529. val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
  530. (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
  531. (pat1->elop << 12) | (pat1->elep << 14));
  532. regw(val, COLPTN);
  533. }
  534. /* This function will configure CCDC for Raw mode image capture */
  535. static int ccdc_config_raw(void)
  536. {
  537. struct ccdc_params_raw *params = &ccdc_hw_params_raw;
  538. struct ccdc_config_params_raw *config_params =
  539. &ccdc_hw_params_raw.config_params;
  540. unsigned int val;
  541. dev_dbg(dev, "\nStarting ccdc_config_raw...");
  542. /* restore power on defaults to register */
  543. ccdc_restore_defaults();
  544. /* CCDCFG register:
  545. * set CCD Not to swap input since input is RAW data
  546. * set FID detection function to Latch at V-Sync
  547. * set WENLOG - ccdc valid area to AND
  548. * set TRGSEL to WENBIT
  549. * set EXTRG to DISABLE
  550. * disable latching function on VSYNC - shadowed registers
  551. */
  552. regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
  553. CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
  554. CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
  555. /*
  556. * Set VDHD direction to input, input type to raw input
  557. * normal data polarity, do not use external WEN
  558. */
  559. val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
  560. CCDC_EXWEN_DISABLE);
  561. /*
  562. * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
  563. * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
  564. * frame format(progressive or interlace), & pixel format (Input mode)
  565. */
  566. val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
  567. ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
  568. ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
  569. ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
  570. ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
  571. /* set pack for alaw compression */
  572. if ((config_params->data_sz == CCDC_DATA_8BITS) ||
  573. config_params->alaw.enable)
  574. val |= CCDC_DATA_PACK_ENABLE;
  575. /* Configure for LPF */
  576. if (config_params->lpf_enable)
  577. val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
  578. CCDC_LPF_SHIFT;
  579. /* Configure the data shift */
  580. val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
  581. CCDC_DATASFT_SHIFT;
  582. regw(val , MODESET);
  583. dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val);
  584. /* Configure the Median Filter threshold */
  585. regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
  586. /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
  587. val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
  588. CCDC_CFA_MOSAIC;
  589. /* Enable and configure aLaw register if needed */
  590. if (config_params->alaw.enable) {
  591. val |= (CCDC_ALAW_ENABLE |
  592. ((config_params->alaw.gama_wd &
  593. CCDC_ALAW_GAMA_WD_MASK) <<
  594. CCDC_GAMMAWD_INPUT_SHIFT));
  595. }
  596. /* Configure Median filter1 & filter2 */
  597. val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
  598. (config_params->mfilt2 << CCDC_MFILT2_SHIFT));
  599. regw(val, GAMMAWD);
  600. dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val);
  601. /* configure video window */
  602. ccdc_setwin(&params->win, params->frm_fmt, 1);
  603. /* Optical Clamp Averaging */
  604. ccdc_config_black_clamp(&config_params->blk_clamp);
  605. /* Black level compensation */
  606. ccdc_config_black_compense(&config_params->blk_comp);
  607. /* Vertical Defect Correction if needed */
  608. if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
  609. return -EFAULT;
  610. /* color space conversion */
  611. ccdc_config_csc(&config_params->csc);
  612. /* color pattern */
  613. ccdc_config_color_patterns(&config_params->col_pat_field0,
  614. &config_params->col_pat_field1);
  615. /* Configure the Gain & offset control */
  616. ccdc_config_gain_offset();
  617. dev_dbg(dev, "\nWriting %x to COLPTN...\n", val);
  618. /* Configure DATAOFST register */
  619. val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
  620. CCDC_DATAOFST_H_SHIFT;
  621. val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
  622. CCDC_DATAOFST_V_SHIFT;
  623. regw(val, DATAOFST);
  624. /* configuring HSIZE register */
  625. val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
  626. CCDC_HSIZE_FLIP_SHIFT;
  627. /* If pack 8 is enable then 1 pixel will take 1 byte */
  628. if ((config_params->data_sz == CCDC_DATA_8BITS) ||
  629. config_params->alaw.enable) {
  630. val |= (((params->win.width) + 31) >> 5) &
  631. CCDC_HSIZE_VAL_MASK;
  632. /* adjust to multiple of 32 */
  633. dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
  634. (((params->win.width) + 31) >> 5) &
  635. CCDC_HSIZE_VAL_MASK);
  636. } else {
  637. /* else one pixel will take 2 byte */
  638. val |= (((params->win.width * 2) + 31) >> 5) &
  639. CCDC_HSIZE_VAL_MASK;
  640. dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
  641. (((params->win.width * 2) + 31) >> 5) &
  642. CCDC_HSIZE_VAL_MASK);
  643. }
  644. regw(val, HSIZE);
  645. /* Configure SDOFST register */
  646. if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
  647. if (params->image_invert_enable) {
  648. /* For interlace inverse mode */
  649. regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
  650. dev_dbg(dev, "\nWriting %x to SDOFST...\n",
  651. CCDC_SDOFST_INTERLACE_INVERSE);
  652. } else {
  653. /* For interlace non inverse mode */
  654. regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
  655. dev_dbg(dev, "\nWriting %x to SDOFST...\n",
  656. CCDC_SDOFST_INTERLACE_NORMAL);
  657. }
  658. } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
  659. if (params->image_invert_enable) {
  660. /* For progessive inverse mode */
  661. regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
  662. dev_dbg(dev, "\nWriting %x to SDOFST...\n",
  663. CCDC_SDOFST_PROGRESSIVE_INVERSE);
  664. } else {
  665. /* For progessive non inverse mode */
  666. regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
  667. dev_dbg(dev, "\nWriting %x to SDOFST...\n",
  668. CCDC_SDOFST_PROGRESSIVE_NORMAL);
  669. }
  670. }
  671. dev_dbg(dev, "\nend of ccdc_config_raw...");
  672. return 0;
  673. }
  674. static int ccdc_configure(void)
  675. {
  676. if (ccdc_if_type == VPFE_RAW_BAYER)
  677. return ccdc_config_raw();
  678. else
  679. ccdc_config_ycbcr();
  680. return 0;
  681. }
  682. static int ccdc_set_buftype(enum ccdc_buftype buf_type)
  683. {
  684. if (ccdc_if_type == VPFE_RAW_BAYER)
  685. ccdc_hw_params_raw.buf_type = buf_type;
  686. else
  687. ccdc_hw_params_ycbcr.buf_type = buf_type;
  688. return 0;
  689. }
  690. static enum ccdc_buftype ccdc_get_buftype(void)
  691. {
  692. if (ccdc_if_type == VPFE_RAW_BAYER)
  693. return ccdc_hw_params_raw.buf_type;
  694. return ccdc_hw_params_ycbcr.buf_type;
  695. }
  696. static int ccdc_enum_pix(u32 *pix, int i)
  697. {
  698. int ret = -EINVAL;
  699. if (ccdc_if_type == VPFE_RAW_BAYER) {
  700. if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
  701. *pix = ccdc_raw_bayer_pix_formats[i];
  702. ret = 0;
  703. }
  704. } else {
  705. if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
  706. *pix = ccdc_raw_yuv_pix_formats[i];
  707. ret = 0;
  708. }
  709. }
  710. return ret;
  711. }
  712. static int ccdc_set_pixel_format(u32 pixfmt)
  713. {
  714. struct ccdc_a_law *alaw =
  715. &ccdc_hw_params_raw.config_params.alaw;
  716. if (ccdc_if_type == VPFE_RAW_BAYER) {
  717. ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
  718. if (pixfmt == V4L2_PIX_FMT_SBGGR8)
  719. alaw->enable = 1;
  720. else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
  721. return -EINVAL;
  722. } else {
  723. if (pixfmt == V4L2_PIX_FMT_YUYV)
  724. ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
  725. else if (pixfmt == V4L2_PIX_FMT_UYVY)
  726. ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
  727. else
  728. return -EINVAL;
  729. }
  730. return 0;
  731. }
  732. static u32 ccdc_get_pixel_format(void)
  733. {
  734. struct ccdc_a_law *alaw =
  735. &ccdc_hw_params_raw.config_params.alaw;
  736. u32 pixfmt;
  737. if (ccdc_if_type == VPFE_RAW_BAYER)
  738. if (alaw->enable)
  739. pixfmt = V4L2_PIX_FMT_SBGGR8;
  740. else
  741. pixfmt = V4L2_PIX_FMT_SBGGR16;
  742. else {
  743. if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
  744. pixfmt = V4L2_PIX_FMT_YUYV;
  745. else
  746. pixfmt = V4L2_PIX_FMT_UYVY;
  747. }
  748. return pixfmt;
  749. }
  750. static int ccdc_set_image_window(struct v4l2_rect *win)
  751. {
  752. if (ccdc_if_type == VPFE_RAW_BAYER)
  753. ccdc_hw_params_raw.win = *win;
  754. else
  755. ccdc_hw_params_ycbcr.win = *win;
  756. return 0;
  757. }
  758. static void ccdc_get_image_window(struct v4l2_rect *win)
  759. {
  760. if (ccdc_if_type == VPFE_RAW_BAYER)
  761. *win = ccdc_hw_params_raw.win;
  762. else
  763. *win = ccdc_hw_params_ycbcr.win;
  764. }
  765. static unsigned int ccdc_get_line_length(void)
  766. {
  767. struct ccdc_config_params_raw *config_params =
  768. &ccdc_hw_params_raw.config_params;
  769. unsigned int len;
  770. if (ccdc_if_type == VPFE_RAW_BAYER) {
  771. if ((config_params->alaw.enable) ||
  772. (config_params->data_sz == CCDC_DATA_8BITS))
  773. len = ccdc_hw_params_raw.win.width;
  774. else
  775. len = ccdc_hw_params_raw.win.width * 2;
  776. } else
  777. len = ccdc_hw_params_ycbcr.win.width * 2;
  778. return ALIGN(len, 32);
  779. }
  780. static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
  781. {
  782. if (ccdc_if_type == VPFE_RAW_BAYER)
  783. ccdc_hw_params_raw.frm_fmt = frm_fmt;
  784. else
  785. ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
  786. return 0;
  787. }
  788. static enum ccdc_frmfmt ccdc_get_frame_format(void)
  789. {
  790. if (ccdc_if_type == VPFE_RAW_BAYER)
  791. return ccdc_hw_params_raw.frm_fmt;
  792. else
  793. return ccdc_hw_params_ycbcr.frm_fmt;
  794. }
  795. static int ccdc_getfid(void)
  796. {
  797. return (regr(MODESET) >> 15) & 1;
  798. }
  799. /* misc operations */
  800. static inline void ccdc_setfbaddr(unsigned long addr)
  801. {
  802. regw((addr >> 21) & 0x007f, STADRH);
  803. regw((addr >> 5) & 0x0ffff, STADRL);
  804. }
  805. static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
  806. {
  807. ccdc_if_type = params->if_type;
  808. switch (params->if_type) {
  809. case VPFE_BT656:
  810. case VPFE_YCBCR_SYNC_16:
  811. case VPFE_YCBCR_SYNC_8:
  812. ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
  813. ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
  814. break;
  815. default:
  816. /* TODO add support for raw bayer here */
  817. return -EINVAL;
  818. }
  819. return 0;
  820. }
  821. static struct ccdc_hw_device ccdc_hw_dev = {
  822. .name = "DM355 CCDC",
  823. .owner = THIS_MODULE,
  824. .hw_ops = {
  825. .open = ccdc_open,
  826. .close = ccdc_close,
  827. .set_ccdc_base = ccdc_set_ccdc_base,
  828. .enable = ccdc_enable,
  829. .enable_out_to_sdram = ccdc_enable_output_to_sdram,
  830. .set_hw_if_params = ccdc_set_hw_if_params,
  831. .set_params = ccdc_set_params,
  832. .configure = ccdc_configure,
  833. .set_buftype = ccdc_set_buftype,
  834. .get_buftype = ccdc_get_buftype,
  835. .enum_pix = ccdc_enum_pix,
  836. .set_pixel_format = ccdc_set_pixel_format,
  837. .get_pixel_format = ccdc_get_pixel_format,
  838. .set_frame_format = ccdc_set_frame_format,
  839. .get_frame_format = ccdc_get_frame_format,
  840. .set_image_window = ccdc_set_image_window,
  841. .get_image_window = ccdc_get_image_window,
  842. .get_line_length = ccdc_get_line_length,
  843. .setfbaddr = ccdc_setfbaddr,
  844. .getfid = ccdc_getfid,
  845. },
  846. };
  847. static int __init dm355_ccdc_init(void)
  848. {
  849. printk(KERN_NOTICE "dm355_ccdc_init\n");
  850. if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
  851. return -1;
  852. printk(KERN_NOTICE "%s is registered with vpfe.\n",
  853. ccdc_hw_dev.name);
  854. return 0;
  855. }
  856. static void __exit dm355_ccdc_exit(void)
  857. {
  858. vpfe_unregister_ccdc_device(&ccdc_hw_dev);
  859. }
  860. module_init(dm355_ccdc_init);
  861. module_exit(dm355_ccdc_exit);