isif.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /*
  2. * Copyright (C) 2008-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. * Image Sensor Interface (ISIF) driver
  15. *
  16. * This driver is for configuring the ISIF IP available on DM365 or any other
  17. * TI SoCs. This is used for capturing yuv or bayer video or image data
  18. * from a decoder or sensor. This IP is similar to the CCDC IP on DM355
  19. * and DM6446, but with enhanced or additional ip blocks. The driver
  20. * configures the ISIF upon commands from the vpfe bridge driver through
  21. * ccdc_hw_device interface.
  22. *
  23. * TODO: 1) Raw bayer parameter settings and bayer capture
  24. * 2) Add support for control ioctl
  25. */
  26. #include <linux/delay.h>
  27. #include <linux/platform_device.h>
  28. #include <linux/uaccess.h>
  29. #include <linux/io.h>
  30. #include <linux/videodev2.h>
  31. #include <linux/err.h>
  32. #include <linux/module.h>
  33. #include <mach/mux.h>
  34. #include <media/davinci/isif.h>
  35. #include <media/davinci/vpss.h>
  36. #include "isif_regs.h"
  37. #include "ccdc_hw_device.h"
  38. /* Defaults for module configuration parameters */
  39. static struct isif_config_params_raw isif_config_defaults = {
  40. .linearize = {
  41. .en = 0,
  42. .corr_shft = ISIF_NO_SHIFT,
  43. .scale_fact = {1, 0},
  44. },
  45. .df_csc = {
  46. .df_or_csc = 0,
  47. .csc = {
  48. .en = 0,
  49. },
  50. },
  51. .dfc = {
  52. .en = 0,
  53. },
  54. .bclamp = {
  55. .en = 0,
  56. },
  57. .gain_offset = {
  58. .gain = {
  59. .r_ye = {1, 0},
  60. .gr_cy = {1, 0},
  61. .gb_g = {1, 0},
  62. .b_mg = {1, 0},
  63. },
  64. },
  65. .culling = {
  66. .hcpat_odd = 0xff,
  67. .hcpat_even = 0xff,
  68. .vcpat = 0xff,
  69. },
  70. .compress = {
  71. .alg = ISIF_ALAW,
  72. },
  73. };
  74. /* ISIF operation configuration */
  75. static struct isif_oper_config {
  76. struct device *dev;
  77. enum vpfe_hw_if_type if_type;
  78. struct isif_ycbcr_config ycbcr;
  79. struct isif_params_raw bayer;
  80. enum isif_data_pack data_pack;
  81. /* ISIF base address */
  82. void __iomem *base_addr;
  83. /* ISIF Linear Table 0 */
  84. void __iomem *linear_tbl0_addr;
  85. /* ISIF Linear Table 1 */
  86. void __iomem *linear_tbl1_addr;
  87. } isif_cfg = {
  88. .ycbcr = {
  89. .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
  90. .frm_fmt = CCDC_FRMFMT_INTERLACED,
  91. .win = ISIF_WIN_NTSC,
  92. .fid_pol = VPFE_PINPOL_POSITIVE,
  93. .vd_pol = VPFE_PINPOL_POSITIVE,
  94. .hd_pol = VPFE_PINPOL_POSITIVE,
  95. .pix_order = CCDC_PIXORDER_CBYCRY,
  96. .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
  97. },
  98. .bayer = {
  99. .pix_fmt = CCDC_PIXFMT_RAW,
  100. .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
  101. .win = ISIF_WIN_VGA,
  102. .fid_pol = VPFE_PINPOL_POSITIVE,
  103. .vd_pol = VPFE_PINPOL_POSITIVE,
  104. .hd_pol = VPFE_PINPOL_POSITIVE,
  105. .gain = {
  106. .r_ye = {1, 0},
  107. .gr_cy = {1, 0},
  108. .gb_g = {1, 0},
  109. .b_mg = {1, 0},
  110. },
  111. .cfa_pat = ISIF_CFA_PAT_MOSAIC,
  112. .data_msb = ISIF_BIT_MSB_11,
  113. .config_params = {
  114. .data_shift = ISIF_NO_SHIFT,
  115. .col_pat_field0 = {
  116. .olop = ISIF_GREEN_BLUE,
  117. .olep = ISIF_BLUE,
  118. .elop = ISIF_RED,
  119. .elep = ISIF_GREEN_RED,
  120. },
  121. .col_pat_field1 = {
  122. .olop = ISIF_GREEN_BLUE,
  123. .olep = ISIF_BLUE,
  124. .elop = ISIF_RED,
  125. .elep = ISIF_GREEN_RED,
  126. },
  127. .test_pat_gen = 0,
  128. },
  129. },
  130. .data_pack = ISIF_DATA_PACK8,
  131. };
  132. /* Raw Bayer formats */
  133. static const u32 isif_raw_bayer_pix_formats[] = {
  134. V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
  135. /* Raw YUV formats */
  136. static const u32 isif_raw_yuv_pix_formats[] = {
  137. V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
  138. /* register access routines */
  139. static inline u32 regr(u32 offset)
  140. {
  141. return __raw_readl(isif_cfg.base_addr + offset);
  142. }
  143. static inline void regw(u32 val, u32 offset)
  144. {
  145. __raw_writel(val, isif_cfg.base_addr + offset);
  146. }
  147. /* reg_modify() - read, modify and write register */
  148. static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
  149. {
  150. u32 new_val = (regr(offset) & ~mask) | (val & mask);
  151. regw(new_val, offset);
  152. return new_val;
  153. }
  154. static inline void regw_lin_tbl(u32 val, u32 offset, int i)
  155. {
  156. if (!i)
  157. __raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
  158. else
  159. __raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
  160. }
  161. static void isif_disable_all_modules(void)
  162. {
  163. /* disable BC */
  164. regw(0, CLAMPCFG);
  165. /* disable vdfc */
  166. regw(0, DFCCTL);
  167. /* disable CSC */
  168. regw(0, CSCCTL);
  169. /* disable linearization */
  170. regw(0, LINCFG0);
  171. /* disable other modules here as they are supported */
  172. }
  173. static void isif_enable(int en)
  174. {
  175. if (!en) {
  176. /* Before disable isif, disable all ISIF modules */
  177. isif_disable_all_modules();
  178. /*
  179. * wait for next VD. Assume lowest scan rate is 12 Hz. So
  180. * 100 msec delay is good enough
  181. */
  182. msleep(100);
  183. }
  184. reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
  185. }
  186. static void isif_enable_output_to_sdram(int en)
  187. {
  188. reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
  189. }
  190. static void isif_config_culling(struct isif_cul *cul)
  191. {
  192. u32 val;
  193. /* Horizontal pattern */
  194. val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
  195. regw(val, CULH);
  196. /* vertical pattern */
  197. regw(cul->vcpat, CULV);
  198. /* LPF */
  199. reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
  200. cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
  201. }
  202. static void isif_config_gain_offset(void)
  203. {
  204. struct isif_gain_offsets_adj *gain_off_p =
  205. &isif_cfg.bayer.config_params.gain_offset;
  206. u32 val;
  207. val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
  208. (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
  209. (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
  210. (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
  211. (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
  212. (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
  213. reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
  214. val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
  215. gain_off_p->gain.r_ye.decimal;
  216. regw(val, CRGAIN);
  217. val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
  218. gain_off_p->gain.gr_cy.decimal;
  219. regw(val, CGRGAIN);
  220. val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
  221. gain_off_p->gain.gb_g.decimal;
  222. regw(val, CGBGAIN);
  223. val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
  224. gain_off_p->gain.b_mg.decimal;
  225. regw(val, CBGAIN);
  226. regw(gain_off_p->offset, COFSTA);
  227. }
  228. static void isif_restore_defaults(void)
  229. {
  230. enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
  231. dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
  232. isif_cfg.bayer.config_params = isif_config_defaults;
  233. /* Enable clock to ISIF, IPIPEIF and BL */
  234. vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
  235. vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
  236. vpss_enable_clock(VPSS_BL_CLOCK, 1);
  237. /* Set default offset and gain */
  238. isif_config_gain_offset();
  239. vpss_select_ccdc_source(source);
  240. dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
  241. }
  242. static int isif_open(struct device *device)
  243. {
  244. isif_restore_defaults();
  245. return 0;
  246. }
  247. /* This function will configure the window size to be capture in ISIF reg */
  248. static void isif_setwin(struct v4l2_rect *image_win,
  249. enum ccdc_frmfmt frm_fmt, int ppc)
  250. {
  251. int horz_start, horz_nr_pixels;
  252. int vert_start, vert_nr_lines;
  253. int mid_img = 0;
  254. dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
  255. /*
  256. * ppc - per pixel count. indicates how many pixels per cell
  257. * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
  258. * raw capture this is 1
  259. */
  260. horz_start = image_win->left << (ppc - 1);
  261. horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
  262. /* Writing the horizontal info into the registers */
  263. regw(horz_start & START_PX_HOR_MASK, SPH);
  264. regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
  265. vert_start = image_win->top;
  266. if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
  267. vert_nr_lines = (image_win->height >> 1) - 1;
  268. vert_start >>= 1;
  269. /* To account for VD since line 0 doesn't have any data */
  270. vert_start += 1;
  271. } else {
  272. /* To account for VD since line 0 doesn't have any data */
  273. vert_start += 1;
  274. vert_nr_lines = image_win->height - 1;
  275. /* configure VDINT0 and VDINT1 */
  276. mid_img = vert_start + (image_win->height / 2);
  277. regw(mid_img, VDINT1);
  278. }
  279. regw(0, VDINT0);
  280. regw(vert_start & START_VER_ONE_MASK, SLV0);
  281. regw(vert_start & START_VER_TWO_MASK, SLV1);
  282. regw(vert_nr_lines & NUM_LINES_VER, LNV);
  283. }
  284. static void isif_config_bclamp(struct isif_black_clamp *bc)
  285. {
  286. u32 val;
  287. /*
  288. * DC Offset is always added to image data irrespective of bc enable
  289. * status
  290. */
  291. regw(bc->dc_offset, CLDCOFST);
  292. if (bc->en) {
  293. val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
  294. /* Enable BC and horizontal clamp caculation paramaters */
  295. val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
  296. regw(val, CLAMPCFG);
  297. if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
  298. /*
  299. * Window count for calculation
  300. * Base window selection
  301. * pixel limit
  302. * Horizontal size of window
  303. * vertical size of the window
  304. * Horizontal start position of the window
  305. * Vertical start position of the window
  306. */
  307. val = bc->horz.win_count_calc |
  308. ((!!bc->horz.base_win_sel_calc) <<
  309. ISIF_HORZ_BC_WIN_SEL_SHIFT) |
  310. ((!!bc->horz.clamp_pix_limit) <<
  311. ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
  312. (bc->horz.win_h_sz_calc <<
  313. ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
  314. (bc->horz.win_v_sz_calc <<
  315. ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
  316. regw(val, CLHWIN0);
  317. regw(bc->horz.win_start_h_calc, CLHWIN1);
  318. regw(bc->horz.win_start_v_calc, CLHWIN2);
  319. }
  320. /* vertical clamp caculation paramaters */
  321. /* Reset clamp value sel for previous line */
  322. val |=
  323. (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
  324. (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
  325. regw(val, CLVWIN0);
  326. /* Optical Black horizontal start position */
  327. regw(bc->vert.ob_start_h, CLVWIN1);
  328. /* Optical Black vertical start position */
  329. regw(bc->vert.ob_start_v, CLVWIN2);
  330. /* Optical Black vertical size for calculation */
  331. regw(bc->vert.ob_v_sz_calc, CLVWIN3);
  332. /* Vertical start position for BC subtraction */
  333. regw(bc->vert_start_sub, CLSV);
  334. }
  335. }
  336. static void isif_config_linearization(struct isif_linearize *linearize)
  337. {
  338. u32 val, i;
  339. if (!linearize->en) {
  340. regw(0, LINCFG0);
  341. return;
  342. }
  343. /* shift value for correction & enable linearization (set lsb) */
  344. val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
  345. regw(val, LINCFG0);
  346. /* Scale factor */
  347. val = ((!!linearize->scale_fact.integer) <<
  348. ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
  349. linearize->scale_fact.decimal;
  350. regw(val, LINCFG1);
  351. for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
  352. if (i % 2)
  353. regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
  354. else
  355. regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
  356. }
  357. }
  358. static int isif_config_dfc(struct isif_dfc *vdfc)
  359. {
  360. /* initialize retries to loop for max ~ 250 usec */
  361. u32 val, count, retries = loops_per_jiffy / (4000/HZ);
  362. int i;
  363. if (!vdfc->en)
  364. return 0;
  365. /* Correction mode */
  366. val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
  367. /* Correct whole line or partial */
  368. if (vdfc->corr_whole_line)
  369. val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
  370. /* level shift value */
  371. val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
  372. regw(val, DFCCTL);
  373. /* Defect saturation level */
  374. regw(vdfc->def_sat_level, VDFSATLV);
  375. regw(vdfc->table[0].pos_vert, DFCMEM0);
  376. regw(vdfc->table[0].pos_horz, DFCMEM1);
  377. if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
  378. vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
  379. regw(vdfc->table[0].level_at_pos, DFCMEM2);
  380. regw(vdfc->table[0].level_up_pixels, DFCMEM3);
  381. regw(vdfc->table[0].level_low_pixels, DFCMEM4);
  382. }
  383. /* set DFCMARST and set DFCMWR */
  384. val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
  385. regw(val, DFCMEMCTL);
  386. count = retries;
  387. while (count && (regr(DFCMEMCTL) & 0x1))
  388. count--;
  389. if (!count) {
  390. dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
  391. return -1;
  392. }
  393. for (i = 1; i < vdfc->num_vdefects; i++) {
  394. regw(vdfc->table[i].pos_vert, DFCMEM0);
  395. regw(vdfc->table[i].pos_horz, DFCMEM1);
  396. if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
  397. vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
  398. regw(vdfc->table[i].level_at_pos, DFCMEM2);
  399. regw(vdfc->table[i].level_up_pixels, DFCMEM3);
  400. regw(vdfc->table[i].level_low_pixels, DFCMEM4);
  401. }
  402. val = regr(DFCMEMCTL);
  403. /* clear DFCMARST and set DFCMWR */
  404. val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
  405. val |= 1;
  406. regw(val, DFCMEMCTL);
  407. count = retries;
  408. while (count && (regr(DFCMEMCTL) & 0x1))
  409. count--;
  410. if (!count) {
  411. dev_err(isif_cfg.dev,
  412. "defect table write timeout !!!\n");
  413. return -1;
  414. }
  415. }
  416. if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
  417. /* Extra cycle needed */
  418. regw(0, DFCMEM0);
  419. regw(0x1FFF, DFCMEM1);
  420. regw(1, DFCMEMCTL);
  421. }
  422. /* enable VDFC */
  423. reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
  424. DFCCTL);
  425. return 0;
  426. }
  427. static void isif_config_csc(struct isif_df_csc *df_csc)
  428. {
  429. u32 val1 = 0, val2 = 0, i;
  430. if (!df_csc->csc.en) {
  431. regw(0, CSCCTL);
  432. return;
  433. }
  434. for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
  435. if ((i % 2) == 0) {
  436. /* CSCM - LSB */
  437. val1 = (df_csc->csc.coeff[i].integer <<
  438. ISIF_CSC_COEF_INTEG_SHIFT) |
  439. df_csc->csc.coeff[i].decimal;
  440. } else {
  441. /* CSCM - MSB */
  442. val2 = (df_csc->csc.coeff[i].integer <<
  443. ISIF_CSC_COEF_INTEG_SHIFT) |
  444. df_csc->csc.coeff[i].decimal;
  445. val2 <<= ISIF_CSCM_MSB_SHIFT;
  446. val2 |= val1;
  447. regw(val2, (CSCM0 + ((i - 1) << 1)));
  448. }
  449. }
  450. /* program the active area */
  451. regw(df_csc->start_pix, FMTSPH);
  452. /*
  453. * one extra pixel as required for CSC. Actually number of
  454. * pixel - 1 should be configured in this register. So we
  455. * need to subtract 1 before writing to FMTSPH, but we will
  456. * not do this since csc requires one extra pixel
  457. */
  458. regw(df_csc->num_pixels, FMTLNH);
  459. regw(df_csc->start_line, FMTSLV);
  460. /*
  461. * one extra line as required for CSC. See reason documented for
  462. * num_pixels
  463. */
  464. regw(df_csc->num_lines, FMTLNV);
  465. /* Enable CSC */
  466. regw(1, CSCCTL);
  467. }
  468. static int isif_config_raw(void)
  469. {
  470. struct isif_params_raw *params = &isif_cfg.bayer;
  471. struct isif_config_params_raw *module_params =
  472. &isif_cfg.bayer.config_params;
  473. struct vpss_pg_frame_size frame_size;
  474. struct vpss_sync_pol sync;
  475. u32 val;
  476. dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
  477. /*
  478. * Configure CCDCFG register:-
  479. * Set CCD Not to swap input since input is RAW data
  480. * Set FID detection function to Latch at V-Sync
  481. * Set WENLOG - isif valid area
  482. * Set TRGSEL
  483. * Set EXTRG
  484. * Packed to 8 or 16 bits
  485. */
  486. val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
  487. ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
  488. ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
  489. dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
  490. regw(val, CCDCFG);
  491. /*
  492. * Configure the vertical sync polarity(MODESET.VDPOL)
  493. * Configure the horizontal sync polarity (MODESET.HDPOL)
  494. * Configure frame id polarity (MODESET.FLDPOL)
  495. * Configure data polarity
  496. * Configure External WEN Selection
  497. * Configure frame format(progressive or interlace)
  498. * Configure pixel format (Input mode)
  499. * Configure the data shift
  500. */
  501. val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
  502. (params->hd_pol << ISIF_HD_POL_SHIFT) |
  503. (params->fid_pol << ISIF_FID_POL_SHIFT) |
  504. (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
  505. (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
  506. (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
  507. (params->pix_fmt << ISIF_INPUT_SHIFT) |
  508. (params->config_params.data_shift << ISIF_DATASFT_SHIFT);
  509. regw(val, MODESET);
  510. dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
  511. /*
  512. * Configure GAMMAWD register
  513. * CFA pattern setting
  514. */
  515. val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
  516. /* Gamma msb */
  517. if (module_params->compress.alg == ISIF_ALAW)
  518. val |= ISIF_ALAW_ENABLE;
  519. val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT);
  520. regw(val, CGAMMAWD);
  521. /* Configure DPCM compression settings */
  522. if (module_params->compress.alg == ISIF_DPCM) {
  523. val = BIT(ISIF_DPCM_EN_SHIFT) |
  524. (module_params->compress.pred <<
  525. ISIF_DPCM_PREDICTOR_SHIFT);
  526. }
  527. regw(val, MISC);
  528. /* Configure Gain & Offset */
  529. isif_config_gain_offset();
  530. /* Configure Color pattern */
  531. val = (params->config_params.col_pat_field0.olop) |
  532. (params->config_params.col_pat_field0.olep << 2) |
  533. (params->config_params.col_pat_field0.elop << 4) |
  534. (params->config_params.col_pat_field0.elep << 6) |
  535. (params->config_params.col_pat_field1.olop << 8) |
  536. (params->config_params.col_pat_field1.olep << 10) |
  537. (params->config_params.col_pat_field1.elop << 12) |
  538. (params->config_params.col_pat_field1.elep << 14);
  539. regw(val, CCOLP);
  540. dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
  541. /* Configure HSIZE register */
  542. val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
  543. /* calculate line offset in 32 bytes based on pack value */
  544. if (isif_cfg.data_pack == ISIF_PACK_8BIT)
  545. val |= ((params->win.width + 31) >> 5);
  546. else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
  547. val |= (((params->win.width +
  548. (params->win.width >> 2)) + 31) >> 5);
  549. else
  550. val |= (((params->win.width * 2) + 31) >> 5);
  551. regw(val, HSIZE);
  552. /* Configure SDOFST register */
  553. if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
  554. if (params->image_invert_en) {
  555. /* For interlace inverse mode */
  556. regw(0x4B6D, SDOFST);
  557. dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
  558. } else {
  559. /* For interlace non inverse mode */
  560. regw(0x0B6D, SDOFST);
  561. dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
  562. }
  563. } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
  564. if (params->image_invert_en) {
  565. /* For progressive inverse mode */
  566. regw(0x4000, SDOFST);
  567. dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
  568. } else {
  569. /* For progressive non inverse mode */
  570. regw(0x0000, SDOFST);
  571. dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
  572. }
  573. }
  574. /* Configure video window */
  575. isif_setwin(&params->win, params->frm_fmt, 1);
  576. /* Configure Black Clamp */
  577. isif_config_bclamp(&module_params->bclamp);
  578. /* Configure Vertical Defection Pixel Correction */
  579. if (isif_config_dfc(&module_params->dfc) < 0)
  580. return -EFAULT;
  581. if (!module_params->df_csc.df_or_csc)
  582. /* Configure Color Space Conversion */
  583. isif_config_csc(&module_params->df_csc);
  584. isif_config_linearization(&module_params->linearize);
  585. /* Configure Culling */
  586. isif_config_culling(&module_params->culling);
  587. /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
  588. regw(module_params->horz_offset, DATAHOFST);
  589. regw(module_params->vert_offset, DATAVOFST);
  590. /* Setup test pattern if enabled */
  591. if (params->config_params.test_pat_gen) {
  592. /* Use the HD/VD pol settings from user */
  593. sync.ccdpg_hdpol = params->hd_pol;
  594. sync.ccdpg_vdpol = params->vd_pol;
  595. dm365_vpss_set_sync_pol(sync);
  596. frame_size.hlpfr = isif_cfg.bayer.win.width;
  597. frame_size.pplen = isif_cfg.bayer.win.height;
  598. dm365_vpss_set_pg_frame_size(frame_size);
  599. vpss_select_ccdc_source(VPSS_PGLPBK);
  600. }
  601. dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
  602. return 0;
  603. }
  604. static int isif_set_buftype(enum ccdc_buftype buf_type)
  605. {
  606. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  607. isif_cfg.bayer.buf_type = buf_type;
  608. else
  609. isif_cfg.ycbcr.buf_type = buf_type;
  610. return 0;
  611. }
  612. static enum ccdc_buftype isif_get_buftype(void)
  613. {
  614. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  615. return isif_cfg.bayer.buf_type;
  616. return isif_cfg.ycbcr.buf_type;
  617. }
  618. static int isif_enum_pix(u32 *pix, int i)
  619. {
  620. int ret = -EINVAL;
  621. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  622. if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
  623. *pix = isif_raw_bayer_pix_formats[i];
  624. ret = 0;
  625. }
  626. } else {
  627. if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
  628. *pix = isif_raw_yuv_pix_formats[i];
  629. ret = 0;
  630. }
  631. }
  632. return ret;
  633. }
  634. static int isif_set_pixel_format(unsigned int pixfmt)
  635. {
  636. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  637. if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
  638. if ((isif_cfg.bayer.config_params.compress.alg !=
  639. ISIF_ALAW) &&
  640. (isif_cfg.bayer.config_params.compress.alg !=
  641. ISIF_DPCM)) {
  642. dev_dbg(isif_cfg.dev,
  643. "Either configure A-Law or DPCM\n");
  644. return -EINVAL;
  645. }
  646. isif_cfg.data_pack = ISIF_PACK_8BIT;
  647. } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
  648. isif_cfg.bayer.config_params.compress.alg =
  649. ISIF_NO_COMPRESSION;
  650. isif_cfg.data_pack = ISIF_PACK_16BIT;
  651. } else
  652. return -EINVAL;
  653. isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
  654. } else {
  655. if (pixfmt == V4L2_PIX_FMT_YUYV)
  656. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
  657. else if (pixfmt == V4L2_PIX_FMT_UYVY)
  658. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
  659. else
  660. return -EINVAL;
  661. isif_cfg.data_pack = ISIF_PACK_8BIT;
  662. }
  663. return 0;
  664. }
  665. static u32 isif_get_pixel_format(void)
  666. {
  667. u32 pixfmt;
  668. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  669. if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
  670. isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
  671. pixfmt = V4L2_PIX_FMT_SBGGR8;
  672. else
  673. pixfmt = V4L2_PIX_FMT_SBGGR16;
  674. else {
  675. if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
  676. pixfmt = V4L2_PIX_FMT_YUYV;
  677. else
  678. pixfmt = V4L2_PIX_FMT_UYVY;
  679. }
  680. return pixfmt;
  681. }
  682. static int isif_set_image_window(struct v4l2_rect *win)
  683. {
  684. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  685. isif_cfg.bayer.win.top = win->top;
  686. isif_cfg.bayer.win.left = win->left;
  687. isif_cfg.bayer.win.width = win->width;
  688. isif_cfg.bayer.win.height = win->height;
  689. } else {
  690. isif_cfg.ycbcr.win.top = win->top;
  691. isif_cfg.ycbcr.win.left = win->left;
  692. isif_cfg.ycbcr.win.width = win->width;
  693. isif_cfg.ycbcr.win.height = win->height;
  694. }
  695. return 0;
  696. }
  697. static void isif_get_image_window(struct v4l2_rect *win)
  698. {
  699. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  700. *win = isif_cfg.bayer.win;
  701. else
  702. *win = isif_cfg.ycbcr.win;
  703. }
  704. static unsigned int isif_get_line_length(void)
  705. {
  706. unsigned int len;
  707. if (isif_cfg.if_type == VPFE_RAW_BAYER) {
  708. if (isif_cfg.data_pack == ISIF_PACK_8BIT)
  709. len = ((isif_cfg.bayer.win.width));
  710. else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
  711. len = (((isif_cfg.bayer.win.width * 2) +
  712. (isif_cfg.bayer.win.width >> 2)));
  713. else
  714. len = (((isif_cfg.bayer.win.width * 2)));
  715. } else
  716. len = (((isif_cfg.ycbcr.win.width * 2)));
  717. return ALIGN(len, 32);
  718. }
  719. static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
  720. {
  721. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  722. isif_cfg.bayer.frm_fmt = frm_fmt;
  723. else
  724. isif_cfg.ycbcr.frm_fmt = frm_fmt;
  725. return 0;
  726. }
  727. static enum ccdc_frmfmt isif_get_frame_format(void)
  728. {
  729. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  730. return isif_cfg.bayer.frm_fmt;
  731. return isif_cfg.ycbcr.frm_fmt;
  732. }
  733. static int isif_getfid(void)
  734. {
  735. return (regr(MODESET) >> 15) & 0x1;
  736. }
  737. /* misc operations */
  738. static void isif_setfbaddr(unsigned long addr)
  739. {
  740. regw((addr >> 21) & 0x07ff, CADU);
  741. regw((addr >> 5) & 0x0ffff, CADL);
  742. }
  743. static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
  744. {
  745. isif_cfg.if_type = params->if_type;
  746. switch (params->if_type) {
  747. case VPFE_BT656:
  748. case VPFE_BT656_10BIT:
  749. case VPFE_YCBCR_SYNC_8:
  750. isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
  751. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
  752. break;
  753. case VPFE_BT1120:
  754. case VPFE_YCBCR_SYNC_16:
  755. isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
  756. isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
  757. break;
  758. case VPFE_RAW_BAYER:
  759. isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
  760. break;
  761. default:
  762. dev_dbg(isif_cfg.dev, "Invalid interface type\n");
  763. return -EINVAL;
  764. }
  765. return 0;
  766. }
  767. /* This function will configure ISIF for YCbCr parameters. */
  768. static int isif_config_ycbcr(void)
  769. {
  770. struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
  771. struct vpss_pg_frame_size frame_size;
  772. u32 modeset = 0, ccdcfg = 0;
  773. struct vpss_sync_pol sync;
  774. dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
  775. /* configure pixel format or input mode */
  776. modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
  777. (params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
  778. (params->fid_pol << ISIF_FID_POL_SHIFT) |
  779. (params->hd_pol << ISIF_HD_POL_SHIFT) |
  780. (params->vd_pol << ISIF_VD_POL_SHIFT);
  781. /* pack the data to 8-bit ISIFCFG */
  782. switch (isif_cfg.if_type) {
  783. case VPFE_BT656:
  784. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
  785. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  786. return -EINVAL;
  787. }
  788. modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
  789. regw(3, REC656IF);
  790. ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
  791. break;
  792. case VPFE_BT656_10BIT:
  793. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
  794. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  795. return -EINVAL;
  796. }
  797. /* setup BT.656, embedded sync */
  798. regw(3, REC656IF);
  799. /* enable 10 bit mode in ccdcfg */
  800. ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
  801. ISIF_BW656_ENABLE;
  802. break;
  803. case VPFE_BT1120:
  804. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
  805. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  806. return -EINVAL;
  807. }
  808. regw(3, REC656IF);
  809. break;
  810. case VPFE_YCBCR_SYNC_8:
  811. ccdcfg |= ISIF_DATA_PACK8;
  812. ccdcfg |= ISIF_YCINSWP_YCBCR;
  813. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
  814. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  815. return -EINVAL;
  816. }
  817. break;
  818. case VPFE_YCBCR_SYNC_16:
  819. if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
  820. dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
  821. return -EINVAL;
  822. }
  823. break;
  824. default:
  825. /* should never come here */
  826. dev_dbg(isif_cfg.dev, "Invalid interface type\n");
  827. return -EINVAL;
  828. }
  829. regw(modeset, MODESET);
  830. /* Set up pix order */
  831. ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
  832. regw(ccdcfg, CCDCFG);
  833. /* configure video window */
  834. if ((isif_cfg.if_type == VPFE_BT1120) ||
  835. (isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
  836. isif_setwin(&params->win, params->frm_fmt, 1);
  837. else
  838. isif_setwin(&params->win, params->frm_fmt, 2);
  839. /*
  840. * configure the horizontal line offset
  841. * this is done by rounding up width to a multiple of 16 pixels
  842. * and multiply by two to account for y:cb:cr 4:2:2 data
  843. */
  844. regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
  845. /* configure the memory line offset */
  846. if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
  847. (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
  848. /* two fields are interleaved in memory */
  849. regw(0x00000249, SDOFST);
  850. /* Setup test pattern if enabled */
  851. if (isif_cfg.bayer.config_params.test_pat_gen) {
  852. sync.ccdpg_hdpol = params->hd_pol;
  853. sync.ccdpg_vdpol = params->vd_pol;
  854. dm365_vpss_set_sync_pol(sync);
  855. dm365_vpss_set_pg_frame_size(frame_size);
  856. }
  857. return 0;
  858. }
  859. static int isif_configure(void)
  860. {
  861. if (isif_cfg.if_type == VPFE_RAW_BAYER)
  862. return isif_config_raw();
  863. return isif_config_ycbcr();
  864. }
  865. static int isif_close(struct device *device)
  866. {
  867. /* copy defaults to module params */
  868. isif_cfg.bayer.config_params = isif_config_defaults;
  869. return 0;
  870. }
  871. static struct ccdc_hw_device isif_hw_dev = {
  872. .name = "ISIF",
  873. .owner = THIS_MODULE,
  874. .hw_ops = {
  875. .open = isif_open,
  876. .close = isif_close,
  877. .enable = isif_enable,
  878. .enable_out_to_sdram = isif_enable_output_to_sdram,
  879. .set_hw_if_params = isif_set_hw_if_params,
  880. .configure = isif_configure,
  881. .set_buftype = isif_set_buftype,
  882. .get_buftype = isif_get_buftype,
  883. .enum_pix = isif_enum_pix,
  884. .set_pixel_format = isif_set_pixel_format,
  885. .get_pixel_format = isif_get_pixel_format,
  886. .set_frame_format = isif_set_frame_format,
  887. .get_frame_format = isif_get_frame_format,
  888. .set_image_window = isif_set_image_window,
  889. .get_image_window = isif_get_image_window,
  890. .get_line_length = isif_get_line_length,
  891. .setfbaddr = isif_setfbaddr,
  892. .getfid = isif_getfid,
  893. },
  894. };
  895. static int isif_probe(struct platform_device *pdev)
  896. {
  897. void (*setup_pinmux)(void);
  898. struct resource *res;
  899. void *__iomem addr;
  900. int status = 0, i;
  901. /* Platform data holds setup_pinmux function ptr */
  902. if (!pdev->dev.platform_data)
  903. return -ENODEV;
  904. /*
  905. * first try to register with vpfe. If not correct platform, then we
  906. * don't have to iomap
  907. */
  908. status = vpfe_register_ccdc_device(&isif_hw_dev);
  909. if (status < 0)
  910. return status;
  911. setup_pinmux = pdev->dev.platform_data;
  912. /*
  913. * setup Mux configuration for ccdc which may be different for
  914. * different SoCs using this CCDC
  915. */
  916. setup_pinmux();
  917. i = 0;
  918. /* Get the ISIF base address, linearization table0 and table1 addr. */
  919. while (i < 3) {
  920. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  921. if (!res) {
  922. status = -ENODEV;
  923. goto fail_nobase_res;
  924. }
  925. res = request_mem_region(res->start, resource_size(res),
  926. res->name);
  927. if (!res) {
  928. status = -EBUSY;
  929. goto fail_nobase_res;
  930. }
  931. addr = ioremap_nocache(res->start, resource_size(res));
  932. if (!addr) {
  933. status = -ENOMEM;
  934. goto fail_base_iomap;
  935. }
  936. switch (i) {
  937. case 0:
  938. /* ISIF base address */
  939. isif_cfg.base_addr = addr;
  940. break;
  941. case 1:
  942. /* ISIF linear tbl0 address */
  943. isif_cfg.linear_tbl0_addr = addr;
  944. break;
  945. default:
  946. /* ISIF linear tbl0 address */
  947. isif_cfg.linear_tbl1_addr = addr;
  948. break;
  949. }
  950. i++;
  951. }
  952. isif_cfg.dev = &pdev->dev;
  953. printk(KERN_NOTICE "%s is registered with vpfe.\n",
  954. isif_hw_dev.name);
  955. return 0;
  956. fail_base_iomap:
  957. release_mem_region(res->start, resource_size(res));
  958. i--;
  959. fail_nobase_res:
  960. if (isif_cfg.base_addr)
  961. iounmap(isif_cfg.base_addr);
  962. if (isif_cfg.linear_tbl0_addr)
  963. iounmap(isif_cfg.linear_tbl0_addr);
  964. while (i >= 0) {
  965. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  966. release_mem_region(res->start, resource_size(res));
  967. i--;
  968. }
  969. vpfe_unregister_ccdc_device(&isif_hw_dev);
  970. return status;
  971. }
  972. static int isif_remove(struct platform_device *pdev)
  973. {
  974. struct resource *res;
  975. int i = 0;
  976. iounmap(isif_cfg.base_addr);
  977. iounmap(isif_cfg.linear_tbl0_addr);
  978. iounmap(isif_cfg.linear_tbl1_addr);
  979. while (i < 3) {
  980. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  981. if (res)
  982. release_mem_region(res->start, resource_size(res));
  983. i++;
  984. }
  985. vpfe_unregister_ccdc_device(&isif_hw_dev);
  986. return 0;
  987. }
  988. static struct platform_driver isif_driver = {
  989. .driver = {
  990. .name = "isif",
  991. },
  992. .remove = isif_remove,
  993. .probe = isif_probe,
  994. };
  995. module_platform_driver(isif_driver);
  996. MODULE_LICENSE("GPL");