dm355_ccdc.c 28 KB

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