dm355_ccdc.c 25 KB

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