dm355_ccdc.c 29 KB

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