ispresizer.c 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804
  1. /*
  2. * ispresizer.c
  3. *
  4. * TI OMAP3 ISP - Resizer module
  5. *
  6. * Copyright (C) 2010 Nokia Corporation
  7. * Copyright (C) 2009 Texas Instruments, Inc
  8. *
  9. * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  10. * Sakari Ailus <sakari.ailus@iki.fi>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2 as
  14. * published by the Free Software Foundation.
  15. */
  16. #include <linux/device.h>
  17. #include <linux/mm.h>
  18. #include <linux/module.h>
  19. #include "isp.h"
  20. #include "ispreg.h"
  21. #include "ispresizer.h"
  22. /*
  23. * Resizer Constants
  24. */
  25. #define MIN_RESIZE_VALUE 64
  26. #define MID_RESIZE_VALUE 512
  27. #define MAX_RESIZE_VALUE 1024
  28. #define MIN_IN_WIDTH 32
  29. #define MIN_IN_HEIGHT 32
  30. #define MAX_IN_WIDTH_MEMORY_MODE 4095
  31. #define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
  32. #define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
  33. #define MAX_IN_HEIGHT 4095
  34. #define MIN_OUT_WIDTH 16
  35. #define MIN_OUT_HEIGHT 2
  36. #define MAX_OUT_HEIGHT 4095
  37. /*
  38. * Resizer Use Constraints
  39. * "TRM ES3.1, table 12-46"
  40. */
  41. #define MAX_4TAP_OUT_WIDTH_ES1 1280
  42. #define MAX_7TAP_OUT_WIDTH_ES1 640
  43. #define MAX_4TAP_OUT_WIDTH_ES2 3312
  44. #define MAX_7TAP_OUT_WIDTH_ES2 1650
  45. #define MAX_4TAP_OUT_WIDTH_3630 4096
  46. #define MAX_7TAP_OUT_WIDTH_3630 2048
  47. /*
  48. * Constants for ratio calculation
  49. */
  50. #define RESIZE_DIVISOR 256
  51. #define DEFAULT_PHASE 1
  52. /*
  53. * Default (and only) configuration of filter coefficients.
  54. * 7-tap mode is for scale factors 0.25x to 0.5x.
  55. * 4-tap mode is for scale factors 0.5x to 4.0x.
  56. * There shouldn't be any reason to recalculate these, EVER.
  57. */
  58. static const struct isprsz_coef filter_coefs = {
  59. /* For 8-phase 4-tap horizontal filter: */
  60. {
  61. 0x0000, 0x0100, 0x0000, 0x0000,
  62. 0x03FA, 0x00F6, 0x0010, 0x0000,
  63. 0x03F9, 0x00DB, 0x002C, 0x0000,
  64. 0x03FB, 0x00B3, 0x0053, 0x03FF,
  65. 0x03FD, 0x0082, 0x0084, 0x03FD,
  66. 0x03FF, 0x0053, 0x00B3, 0x03FB,
  67. 0x0000, 0x002C, 0x00DB, 0x03F9,
  68. 0x0000, 0x0010, 0x00F6, 0x03FA
  69. },
  70. /* For 8-phase 4-tap vertical filter: */
  71. {
  72. 0x0000, 0x0100, 0x0000, 0x0000,
  73. 0x03FA, 0x00F6, 0x0010, 0x0000,
  74. 0x03F9, 0x00DB, 0x002C, 0x0000,
  75. 0x03FB, 0x00B3, 0x0053, 0x03FF,
  76. 0x03FD, 0x0082, 0x0084, 0x03FD,
  77. 0x03FF, 0x0053, 0x00B3, 0x03FB,
  78. 0x0000, 0x002C, 0x00DB, 0x03F9,
  79. 0x0000, 0x0010, 0x00F6, 0x03FA
  80. },
  81. /* For 4-phase 7-tap horizontal filter: */
  82. #define DUMMY 0
  83. {
  84. 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
  85. 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
  86. 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
  87. 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
  88. },
  89. /* For 4-phase 7-tap vertical filter: */
  90. {
  91. 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
  92. 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
  93. 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
  94. 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
  95. }
  96. /*
  97. * The dummy padding is required in 7-tap mode because of how the
  98. * registers are arranged physically.
  99. */
  100. #undef DUMMY
  101. };
  102. /*
  103. * __resizer_get_format - helper function for getting resizer format
  104. * @res : pointer to resizer private structure
  105. * @pad : pad number
  106. * @fh : V4L2 subdev file handle
  107. * @which : wanted subdev format
  108. * return zero
  109. */
  110. static struct v4l2_mbus_framefmt *
  111. __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
  112. unsigned int pad, enum v4l2_subdev_format_whence which)
  113. {
  114. if (which == V4L2_SUBDEV_FORMAT_TRY)
  115. return v4l2_subdev_get_try_format(fh, pad);
  116. else
  117. return &res->formats[pad];
  118. }
  119. /*
  120. * __resizer_get_crop - helper function for getting resizer crop rectangle
  121. * @res : pointer to resizer private structure
  122. * @fh : V4L2 subdev file handle
  123. * @which : wanted subdev crop rectangle
  124. */
  125. static struct v4l2_rect *
  126. __resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
  127. enum v4l2_subdev_format_whence which)
  128. {
  129. if (which == V4L2_SUBDEV_FORMAT_TRY)
  130. return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
  131. else
  132. return &res->crop.request;
  133. }
  134. /*
  135. * resizer_set_filters - Set resizer filters
  136. * @res: Device context.
  137. * @h_coeff: horizontal coefficient
  138. * @v_coeff: vertical coefficient
  139. * Return none
  140. */
  141. static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
  142. const u16 *v_coeff)
  143. {
  144. struct isp_device *isp = to_isp_device(res);
  145. u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
  146. int i;
  147. startaddr_h = ISPRSZ_HFILT10;
  148. startaddr_v = ISPRSZ_VFILT10;
  149. for (i = 0; i < COEFF_CNT; i += 2) {
  150. tmp_h = h_coeff[i] |
  151. (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
  152. tmp_v = v_coeff[i] |
  153. (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
  154. isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
  155. isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
  156. startaddr_h += 4;
  157. startaddr_v += 4;
  158. }
  159. }
  160. /*
  161. * resizer_set_bilinear - Chrominance horizontal algorithm select
  162. * @res: Device context.
  163. * @type: Filtering interpolation type.
  164. *
  165. * Filtering that is same as luminance processing is
  166. * intended only for downsampling, and bilinear interpolation
  167. * is intended only for upsampling.
  168. */
  169. static void resizer_set_bilinear(struct isp_res_device *res,
  170. enum resizer_chroma_algo type)
  171. {
  172. struct isp_device *isp = to_isp_device(res);
  173. if (type == RSZ_BILINEAR)
  174. isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  175. ISPRSZ_CNT_CBILIN);
  176. else
  177. isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  178. ISPRSZ_CNT_CBILIN);
  179. }
  180. /*
  181. * resizer_set_ycpos - Luminance and chrominance order
  182. * @res: Device context.
  183. * @pixelcode: pixel code.
  184. */
  185. static void resizer_set_ycpos(struct isp_res_device *res,
  186. enum v4l2_mbus_pixelcode pixelcode)
  187. {
  188. struct isp_device *isp = to_isp_device(res);
  189. switch (pixelcode) {
  190. case V4L2_MBUS_FMT_YUYV8_1X16:
  191. isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  192. ISPRSZ_CNT_YCPOS);
  193. break;
  194. case V4L2_MBUS_FMT_UYVY8_1X16:
  195. isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  196. ISPRSZ_CNT_YCPOS);
  197. break;
  198. default:
  199. return;
  200. }
  201. }
  202. /*
  203. * resizer_set_phase - Setup horizontal and vertical starting phase
  204. * @res: Device context.
  205. * @h_phase: horizontal phase parameters.
  206. * @v_phase: vertical phase parameters.
  207. *
  208. * Horizontal and vertical phase range is 0 to 7
  209. */
  210. static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
  211. u32 v_phase)
  212. {
  213. struct isp_device *isp = to_isp_device(res);
  214. u32 rgval;
  215. rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
  216. ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
  217. rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
  218. rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
  219. isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
  220. }
  221. /*
  222. * resizer_set_luma - Setup luminance enhancer parameters
  223. * @res: Device context.
  224. * @luma: Structure for luminance enhancer parameters.
  225. *
  226. * Algorithm select:
  227. * 0x0: Disable
  228. * 0x1: [-1 2 -1]/2 high-pass filter
  229. * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter
  230. *
  231. * Maximum gain:
  232. * The data is coded in U4Q4 representation.
  233. *
  234. * Slope:
  235. * The data is coded in U4Q4 representation.
  236. *
  237. * Coring offset:
  238. * The data is coded in U8Q0 representation.
  239. *
  240. * The new luminance value is computed as:
  241. * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
  242. */
  243. static void resizer_set_luma(struct isp_res_device *res,
  244. struct resizer_luma_yenh *luma)
  245. {
  246. struct isp_device *isp = to_isp_device(res);
  247. u32 rgval;
  248. rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
  249. & ISPRSZ_YENH_ALGO_MASK;
  250. rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
  251. & ISPRSZ_YENH_GAIN_MASK;
  252. rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
  253. & ISPRSZ_YENH_SLOP_MASK;
  254. rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
  255. & ISPRSZ_YENH_CORE_MASK;
  256. isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
  257. }
  258. /*
  259. * resizer_set_source - Input source select
  260. * @res: Device context.
  261. * @source: Input source type
  262. *
  263. * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
  264. * Preview/CCDC engine, otherwise from memory.
  265. */
  266. static void resizer_set_source(struct isp_res_device *res,
  267. enum resizer_input_entity source)
  268. {
  269. struct isp_device *isp = to_isp_device(res);
  270. if (source == RESIZER_INPUT_MEMORY)
  271. isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  272. ISPRSZ_CNT_INPSRC);
  273. else
  274. isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  275. ISPRSZ_CNT_INPSRC);
  276. }
  277. /*
  278. * resizer_set_ratio - Setup horizontal and vertical resizing value
  279. * @res: Device context.
  280. * @ratio: Structure for ratio parameters.
  281. *
  282. * Resizing range from 64 to 1024
  283. */
  284. static void resizer_set_ratio(struct isp_res_device *res,
  285. const struct resizer_ratio *ratio)
  286. {
  287. struct isp_device *isp = to_isp_device(res);
  288. const u16 *h_filter, *v_filter;
  289. u32 rgval;
  290. rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
  291. ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
  292. rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
  293. & ISPRSZ_CNT_HRSZ_MASK;
  294. rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
  295. & ISPRSZ_CNT_VRSZ_MASK;
  296. isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
  297. /* prepare horizontal filter coefficients */
  298. if (ratio->horz > MID_RESIZE_VALUE)
  299. h_filter = &filter_coefs.h_filter_coef_7tap[0];
  300. else
  301. h_filter = &filter_coefs.h_filter_coef_4tap[0];
  302. /* prepare vertical filter coefficients */
  303. if (ratio->vert > MID_RESIZE_VALUE)
  304. v_filter = &filter_coefs.v_filter_coef_7tap[0];
  305. else
  306. v_filter = &filter_coefs.v_filter_coef_4tap[0];
  307. resizer_set_filters(res, h_filter, v_filter);
  308. }
  309. /*
  310. * resizer_set_dst_size - Setup the output height and width
  311. * @res: Device context.
  312. * @width: Output width.
  313. * @height: Output height.
  314. *
  315. * Width :
  316. * The value must be EVEN.
  317. *
  318. * Height:
  319. * The number of bytes written to SDRAM must be
  320. * a multiple of 16-bytes if the vertical resizing factor
  321. * is greater than 1x (upsizing)
  322. */
  323. static void resizer_set_output_size(struct isp_res_device *res,
  324. u32 width, u32 height)
  325. {
  326. struct isp_device *isp = to_isp_device(res);
  327. u32 rgval;
  328. rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
  329. & ISPRSZ_OUT_SIZE_HORZ_MASK;
  330. rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
  331. & ISPRSZ_OUT_SIZE_VERT_MASK;
  332. isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
  333. }
  334. /*
  335. * resizer_set_output_offset - Setup memory offset for the output lines.
  336. * @res: Device context.
  337. * @offset: Memory offset.
  338. *
  339. * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
  340. * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
  341. * the SDRAM line offset must be set on a 256-byte boundary
  342. */
  343. static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
  344. {
  345. struct isp_device *isp = to_isp_device(res);
  346. isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
  347. }
  348. /*
  349. * resizer_set_start - Setup vertical and horizontal start position
  350. * @res: Device context.
  351. * @left: Horizontal start position.
  352. * @top: Vertical start position.
  353. *
  354. * Vertical start line:
  355. * This field makes sense only when the resizer obtains its input
  356. * from the preview engine/CCDC
  357. *
  358. * Horizontal start pixel:
  359. * Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
  360. * When the resizer gets its input from SDRAM, this field must be set
  361. * to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
  362. */
  363. static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
  364. {
  365. struct isp_device *isp = to_isp_device(res);
  366. u32 rgval;
  367. rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
  368. & ISPRSZ_IN_START_HORZ_ST_MASK;
  369. rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
  370. & ISPRSZ_IN_START_VERT_ST_MASK;
  371. isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
  372. }
  373. /*
  374. * resizer_set_input_size - Setup the input size
  375. * @res: Device context.
  376. * @width: The range is 0 to 4095 pixels
  377. * @height: The range is 0 to 4095 lines
  378. */
  379. static void resizer_set_input_size(struct isp_res_device *res,
  380. u32 width, u32 height)
  381. {
  382. struct isp_device *isp = to_isp_device(res);
  383. u32 rgval;
  384. rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
  385. & ISPRSZ_IN_SIZE_HORZ_MASK;
  386. rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
  387. & ISPRSZ_IN_SIZE_VERT_MASK;
  388. isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
  389. }
  390. /*
  391. * resizer_set_src_offs - Setup the memory offset for the input lines
  392. * @res: Device context.
  393. * @offset: Memory offset.
  394. *
  395. * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
  396. * boundary; the 5 LSBs are read-only. This field must be programmed to be
  397. * 0x0 if the resizer input is from preview engine/CCDC.
  398. */
  399. static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
  400. {
  401. struct isp_device *isp = to_isp_device(res);
  402. isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
  403. }
  404. /*
  405. * resizer_set_intype - Input type select
  406. * @res: Device context.
  407. * @type: Pixel format type.
  408. */
  409. static void resizer_set_intype(struct isp_res_device *res,
  410. enum resizer_colors_type type)
  411. {
  412. struct isp_device *isp = to_isp_device(res);
  413. if (type == RSZ_COLOR8)
  414. isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  415. ISPRSZ_CNT_INPTYP);
  416. else
  417. isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
  418. ISPRSZ_CNT_INPTYP);
  419. }
  420. /*
  421. * __resizer_set_inaddr - Helper function for set input address
  422. * @res : pointer to resizer private data structure
  423. * @addr: input address
  424. * return none
  425. */
  426. static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
  427. {
  428. struct isp_device *isp = to_isp_device(res);
  429. isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
  430. }
  431. /*
  432. * The data rate at the horizontal resizer output must not exceed half the
  433. * functional clock or 100 MP/s, whichever is lower. According to the TRM
  434. * there's no similar requirement for the vertical resizer output. However
  435. * experience showed that vertical upscaling by 4 leads to SBL overflows (with
  436. * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
  437. * output data rate to the functional clock or 200 MP/s, whichever is lower,
  438. * seems to get rid of SBL overflows.
  439. *
  440. * The maximum data rate at the output of the horizontal resizer can thus be
  441. * computed with
  442. *
  443. * max intermediate rate <= L3 clock * input height / output height
  444. * max intermediate rate <= L3 clock / 2
  445. *
  446. * The maximum data rate at the resizer input is then
  447. *
  448. * max input rate <= max intermediate rate * input width / output width
  449. *
  450. * where the input width and height are the resizer input crop rectangle size.
  451. * The TRM doesn't clearly explain if that's a maximum instant data rate or a
  452. * maximum average data rate.
  453. */
  454. void omap3isp_resizer_max_rate(struct isp_res_device *res,
  455. unsigned int *max_rate)
  456. {
  457. struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
  458. const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
  459. unsigned long limit = min(pipe->l3_ick, 200000000UL);
  460. unsigned long clock;
  461. clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
  462. clock = min(clock, limit / 2);
  463. *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
  464. }
  465. /*
  466. * When the resizer processes images from memory, the driver must slow down read
  467. * requests on the input to at least comply with the internal data rate
  468. * requirements. If the application real-time requirements can cope with slower
  469. * processing, the resizer can be slowed down even more to put less pressure on
  470. * the overall system.
  471. *
  472. * When the resizer processes images on the fly (either from the CCDC or the
  473. * preview module), the same data rate requirements apply but they can't be
  474. * enforced at the resizer level. The image input module (sensor, CCP2 or
  475. * preview module) must not provide image data faster than the resizer can
  476. * process.
  477. *
  478. * For live image pipelines, the data rate is set by the frame format, size and
  479. * rate. The sensor output frame rate must not exceed the maximum resizer data
  480. * rate.
  481. *
  482. * The resizer slows down read requests by inserting wait cycles in the SBL
  483. * requests. The maximum number of 256-byte requests per second can be computed
  484. * as (the data rate is multiplied by 2 to convert from pixels per second to
  485. * bytes per second)
  486. *
  487. * request per second = data rate * 2 / 256
  488. * cycles per request = cycles per second / requests per second
  489. *
  490. * The number of cycles per second is controlled by the L3 clock, leading to
  491. *
  492. * cycles per request = L3 frequency / 2 * 256 / data rate
  493. */
  494. static void resizer_adjust_bandwidth(struct isp_res_device *res)
  495. {
  496. struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
  497. struct isp_device *isp = to_isp_device(res);
  498. unsigned long l3_ick = pipe->l3_ick;
  499. struct v4l2_fract *timeperframe;
  500. unsigned int cycles_per_frame;
  501. unsigned int requests_per_frame;
  502. unsigned int cycles_per_request;
  503. unsigned int granularity;
  504. unsigned int minimum;
  505. unsigned int maximum;
  506. unsigned int value;
  507. if (res->input != RESIZER_INPUT_MEMORY) {
  508. isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
  509. ISPSBL_SDR_REQ_RSZ_EXP_MASK);
  510. return;
  511. }
  512. switch (isp->revision) {
  513. case ISP_REVISION_1_0:
  514. case ISP_REVISION_2_0:
  515. default:
  516. granularity = 1024;
  517. break;
  518. case ISP_REVISION_15_0:
  519. granularity = 32;
  520. break;
  521. }
  522. /* Compute the minimum number of cycles per request, based on the
  523. * pipeline maximum data rate. This is an absolute lower bound if we
  524. * don't want SBL overflows, so round the value up.
  525. */
  526. cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
  527. pipe->max_rate);
  528. minimum = DIV_ROUND_UP(cycles_per_request, granularity);
  529. /* Compute the maximum number of cycles per request, based on the
  530. * requested frame rate. This is a soft upper bound to achieve a frame
  531. * rate equal or higher than the requested value, so round the value
  532. * down.
  533. */
  534. timeperframe = &pipe->max_timeperframe;
  535. requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
  536. * res->crop.active.height;
  537. cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
  538. timeperframe->denominator);
  539. cycles_per_request = cycles_per_frame / requests_per_frame;
  540. maximum = cycles_per_request / granularity;
  541. value = max(minimum, maximum);
  542. dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
  543. isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
  544. ISPSBL_SDR_REQ_RSZ_EXP_MASK,
  545. value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
  546. }
  547. /*
  548. * omap3isp_resizer_busy - Checks if ISP resizer is busy.
  549. *
  550. * Returns busy field from ISPRSZ_PCR register.
  551. */
  552. int omap3isp_resizer_busy(struct isp_res_device *res)
  553. {
  554. struct isp_device *isp = to_isp_device(res);
  555. return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
  556. ISPRSZ_PCR_BUSY;
  557. }
  558. /*
  559. * resizer_set_inaddr - Sets the memory address of the input frame.
  560. * @addr: 32bit memory address aligned on 32byte boundary.
  561. */
  562. static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
  563. {
  564. res->addr_base = addr;
  565. /* This will handle crop settings in stream off state */
  566. if (res->crop_offset)
  567. addr += res->crop_offset & ~0x1f;
  568. __resizer_set_inaddr(res, addr);
  569. }
  570. /*
  571. * Configures the memory address to which the output frame is written.
  572. * @addr: 32bit memory address aligned on 32byte boundary.
  573. * Note: For SBL efficiency reasons the address should be on a 256-byte
  574. * boundary.
  575. */
  576. static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
  577. {
  578. struct isp_device *isp = to_isp_device(res);
  579. /*
  580. * Set output address. This needs to be in its own function
  581. * because it changes often.
  582. */
  583. isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
  584. OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
  585. }
  586. /*
  587. * resizer_print_status - Prints the values of the resizer module registers.
  588. */
  589. #define RSZ_PRINT_REGISTER(isp, name)\
  590. dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
  591. isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
  592. static void resizer_print_status(struct isp_res_device *res)
  593. {
  594. struct isp_device *isp = to_isp_device(res);
  595. dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
  596. RSZ_PRINT_REGISTER(isp, PCR);
  597. RSZ_PRINT_REGISTER(isp, CNT);
  598. RSZ_PRINT_REGISTER(isp, OUT_SIZE);
  599. RSZ_PRINT_REGISTER(isp, IN_START);
  600. RSZ_PRINT_REGISTER(isp, IN_SIZE);
  601. RSZ_PRINT_REGISTER(isp, SDR_INADD);
  602. RSZ_PRINT_REGISTER(isp, SDR_INOFF);
  603. RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
  604. RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
  605. RSZ_PRINT_REGISTER(isp, YENH);
  606. dev_dbg(isp->dev, "--------------------------------------------\n");
  607. }
  608. /*
  609. * resizer_calc_ratios - Helper function for calculating resizer ratios
  610. * @res: pointer to resizer private data structure
  611. * @input: input frame size
  612. * @output: output frame size
  613. * @ratio : return calculated ratios
  614. * return none
  615. *
  616. * The resizer uses a polyphase sample rate converter. The upsampling filter
  617. * has a fixed number of phases that depend on the resizing ratio. As the ratio
  618. * computation depends on the number of phases, we need to compute a first
  619. * approximation and then refine it.
  620. *
  621. * The input/output/ratio relationship is given by the OMAP34xx TRM:
  622. *
  623. * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
  624. * iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
  625. * ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
  626. * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
  627. * iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
  628. * ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
  629. *
  630. * iw and ih are the input width and height after cropping. Those equations need
  631. * to be satisfied exactly for the resizer to work correctly.
  632. *
  633. * The equations can't be easily reverted, as the >> 8 operation is not linear.
  634. * In addition, not all input sizes can be achieved for a given output size. To
  635. * get the highest input size lower than or equal to the requested input size,
  636. * we need to compute the highest resizing ratio that satisfies the following
  637. * inequality (taking the 4-tap mode width equation as an example)
  638. *
  639. * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
  640. *
  641. * (where iw is the requested input width) which can be rewritten as
  642. *
  643. * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
  644. * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b
  645. * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16
  646. *
  647. * where b is the value of the 8 least significant bits of the right hand side
  648. * expression of the last inequality. The highest resizing ratio value will be
  649. * achieved when b is equal to its maximum value of 255. That resizing ratio
  650. * value will still satisfy the original inequality, as b will disappear when
  651. * the expression will be shifted right by 8.
  652. *
  653. * The reverted equations thus become
  654. *
  655. * - 8-phase, 4-tap mode
  656. * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
  657. * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
  658. * - 4-phase, 7-tap mode
  659. * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
  660. * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
  661. *
  662. * The ratios are integer values, and are rounded down to ensure that the
  663. * cropped input size is not bigger than the uncropped input size.
  664. *
  665. * As the number of phases/taps, used to select the correct equations to compute
  666. * the ratio, depends on the ratio, we start with the 4-tap mode equations to
  667. * compute an approximation of the ratio, and switch to the 7-tap mode equations
  668. * if the approximation is higher than the ratio threshold.
  669. *
  670. * As the 7-tap mode equations will return a ratio smaller than or equal to the
  671. * 4-tap mode equations, the resulting ratio could become lower than or equal to
  672. * the ratio threshold. This 'equations loop' isn't an issue as long as the
  673. * correct equations are used to compute the final input size. Starting with the
  674. * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
  675. * loop', the smallest of the ratio values will be used, never exceeding the
  676. * requested input size.
  677. *
  678. * We first clamp the output size according to the hardware capability to avoid
  679. * auto-cropping the input more than required to satisfy the TRM equations. The
  680. * minimum output size is achieved with a scaling factor of 1024. It is thus
  681. * computed using the 7-tap equations.
  682. *
  683. * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
  684. * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
  685. *
  686. * Similarly, the maximum output size is achieved with a scaling factor of 64
  687. * and computed using the 4-tap equations.
  688. *
  689. * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
  690. * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
  691. *
  692. * The additional +255 term compensates for the round down operation performed
  693. * by the TRM equations when shifting the value right by 8 bits.
  694. *
  695. * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
  696. * the maximum value guarantees that the ratio value will never be smaller than
  697. * the minimum, but it could still slightly exceed the maximum. Clamping the
  698. * ratio will thus result in a resizing factor slightly larger than the
  699. * requested value.
  700. *
  701. * To accommodate that, and make sure the TRM equations are satisfied exactly, we
  702. * compute the input crop rectangle as the last step.
  703. *
  704. * As if the situation wasn't complex enough, the maximum output width depends
  705. * on the vertical resizing ratio. Fortunately, the output height doesn't
  706. * depend on the horizontal resizing ratio. We can then start by computing the
  707. * output height and the vertical ratio, and then move to computing the output
  708. * width and the horizontal ratio.
  709. */
  710. static void resizer_calc_ratios(struct isp_res_device *res,
  711. struct v4l2_rect *input,
  712. struct v4l2_mbus_framefmt *output,
  713. struct resizer_ratio *ratio)
  714. {
  715. struct isp_device *isp = to_isp_device(res);
  716. const unsigned int spv = DEFAULT_PHASE;
  717. const unsigned int sph = DEFAULT_PHASE;
  718. unsigned int upscaled_width;
  719. unsigned int upscaled_height;
  720. unsigned int min_width;
  721. unsigned int min_height;
  722. unsigned int max_width;
  723. unsigned int max_height;
  724. unsigned int width_alignment;
  725. unsigned int width;
  726. unsigned int height;
  727. /*
  728. * Clamp the output height based on the hardware capabilities and
  729. * compute the vertical resizing ratio.
  730. */
  731. min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
  732. min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
  733. max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
  734. max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
  735. output->height = clamp(output->height, min_height, max_height);
  736. ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
  737. / (output->height - 1);
  738. if (ratio->vert > MID_RESIZE_VALUE)
  739. ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
  740. / (output->height - 1);
  741. ratio->vert = clamp_t(unsigned int, ratio->vert,
  742. MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
  743. if (ratio->vert <= MID_RESIZE_VALUE) {
  744. upscaled_height = (output->height - 1) * ratio->vert
  745. + 32 * spv + 16;
  746. height = (upscaled_height >> 8) + 4;
  747. } else {
  748. upscaled_height = (output->height - 1) * ratio->vert
  749. + 64 * spv + 32;
  750. height = (upscaled_height >> 8) + 7;
  751. }
  752. /*
  753. * Compute the minimum and maximum output widths based on the hardware
  754. * capabilities. The maximum depends on the vertical resizing ratio.
  755. */
  756. min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
  757. min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
  758. if (ratio->vert <= MID_RESIZE_VALUE) {
  759. switch (isp->revision) {
  760. case ISP_REVISION_1_0:
  761. max_width = MAX_4TAP_OUT_WIDTH_ES1;
  762. break;
  763. case ISP_REVISION_2_0:
  764. default:
  765. max_width = MAX_4TAP_OUT_WIDTH_ES2;
  766. break;
  767. case ISP_REVISION_15_0:
  768. max_width = MAX_4TAP_OUT_WIDTH_3630;
  769. break;
  770. }
  771. } else {
  772. switch (isp->revision) {
  773. case ISP_REVISION_1_0:
  774. max_width = MAX_7TAP_OUT_WIDTH_ES1;
  775. break;
  776. case ISP_REVISION_2_0:
  777. default:
  778. max_width = MAX_7TAP_OUT_WIDTH_ES2;
  779. break;
  780. case ISP_REVISION_15_0:
  781. max_width = MAX_7TAP_OUT_WIDTH_3630;
  782. break;
  783. }
  784. }
  785. max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
  786. + 1, max_width);
  787. /*
  788. * The output width must be even, and must be a multiple of 16 bytes
  789. * when upscaling vertically. Clamp the output width to the valid range.
  790. * Take the alignment into account (the maximum width in 7-tap mode on
  791. * ES2 isn't a multiple of 8) and align the result up to make sure it
  792. * won't be smaller than the minimum.
  793. */
  794. width_alignment = ratio->vert < 256 ? 8 : 2;
  795. output->width = clamp(output->width, min_width,
  796. max_width & ~(width_alignment - 1));
  797. output->width = ALIGN(output->width, width_alignment);
  798. ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
  799. / (output->width - 1);
  800. if (ratio->horz > MID_RESIZE_VALUE)
  801. ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
  802. / (output->width - 1);
  803. ratio->horz = clamp_t(unsigned int, ratio->horz,
  804. MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
  805. if (ratio->horz <= MID_RESIZE_VALUE) {
  806. upscaled_width = (output->width - 1) * ratio->horz
  807. + 32 * sph + 16;
  808. width = (upscaled_width >> 8) + 7;
  809. } else {
  810. upscaled_width = (output->width - 1) * ratio->horz
  811. + 64 * sph + 32;
  812. width = (upscaled_width >> 8) + 7;
  813. }
  814. /* Center the new crop rectangle. */
  815. input->left += (input->width - width) / 2;
  816. input->top += (input->height - height) / 2;
  817. input->width = width;
  818. input->height = height;
  819. }
  820. /*
  821. * resizer_set_crop_params - Setup hardware with cropping parameters
  822. * @res : resizer private structure
  823. * @input : format on sink pad
  824. * @output : format on source pad
  825. * return none
  826. */
  827. static void resizer_set_crop_params(struct isp_res_device *res,
  828. const struct v4l2_mbus_framefmt *input,
  829. const struct v4l2_mbus_framefmt *output)
  830. {
  831. resizer_set_ratio(res, &res->ratio);
  832. /* Set chrominance horizontal algorithm */
  833. if (res->ratio.horz >= RESIZE_DIVISOR)
  834. resizer_set_bilinear(res, RSZ_THE_SAME);
  835. else
  836. resizer_set_bilinear(res, RSZ_BILINEAR);
  837. resizer_adjust_bandwidth(res);
  838. if (res->input == RESIZER_INPUT_MEMORY) {
  839. /* Calculate additional offset for crop */
  840. res->crop_offset = (res->crop.active.top * input->width +
  841. res->crop.active.left) * 2;
  842. /*
  843. * Write lowest 4 bits of horizontal pixel offset (in pixels),
  844. * vertical start must be 0.
  845. */
  846. resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
  847. /*
  848. * Set start (read) address for cropping, in bytes.
  849. * Lowest 5 bits must be zero.
  850. */
  851. __resizer_set_inaddr(res,
  852. res->addr_base + (res->crop_offset & ~0x1f));
  853. } else {
  854. /*
  855. * Set vertical start line and horizontal starting pixel.
  856. * If the input is from CCDC/PREV, horizontal start field is
  857. * in bytes (twice number of pixels).
  858. */
  859. resizer_set_start(res, res->crop.active.left * 2,
  860. res->crop.active.top);
  861. /* Input address and offset must be 0 for preview/ccdc input */
  862. __resizer_set_inaddr(res, 0);
  863. resizer_set_input_offset(res, 0);
  864. }
  865. /* Set the input size */
  866. resizer_set_input_size(res, res->crop.active.width,
  867. res->crop.active.height);
  868. }
  869. static void resizer_configure(struct isp_res_device *res)
  870. {
  871. struct v4l2_mbus_framefmt *informat, *outformat;
  872. struct resizer_luma_yenh luma = {0, 0, 0, 0};
  873. resizer_set_source(res, res->input);
  874. informat = &res->formats[RESZ_PAD_SINK];
  875. outformat = &res->formats[RESZ_PAD_SOURCE];
  876. /* RESZ_PAD_SINK */
  877. if (res->input == RESIZER_INPUT_VP)
  878. resizer_set_input_offset(res, 0);
  879. else
  880. resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
  881. /* YUV422 interleaved, default phase, no luma enhancement */
  882. resizer_set_intype(res, RSZ_YUV422);
  883. resizer_set_ycpos(res, informat->code);
  884. resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
  885. resizer_set_luma(res, &luma);
  886. /* RESZ_PAD_SOURCE */
  887. resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
  888. resizer_set_output_size(res, outformat->width, outformat->height);
  889. resizer_set_crop_params(res, informat, outformat);
  890. }
  891. /* -----------------------------------------------------------------------------
  892. * Interrupt handling
  893. */
  894. static void resizer_enable_oneshot(struct isp_res_device *res)
  895. {
  896. struct isp_device *isp = to_isp_device(res);
  897. isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
  898. ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
  899. }
  900. void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
  901. {
  902. /*
  903. * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
  904. * condition, the module was paused and now we have a buffer queued
  905. * on the output again. Restart the pipeline if running in continuous
  906. * mode.
  907. */
  908. if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
  909. res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
  910. resizer_enable_oneshot(res);
  911. isp_video_dmaqueue_flags_clr(&res->video_out);
  912. }
  913. }
  914. static void resizer_isr_buffer(struct isp_res_device *res)
  915. {
  916. struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
  917. struct isp_buffer *buffer;
  918. int restart = 0;
  919. if (res->state == ISP_PIPELINE_STREAM_STOPPED)
  920. return;
  921. /* Complete the output buffer and, if reading from memory, the input
  922. * buffer.
  923. */
  924. buffer = omap3isp_video_buffer_next(&res->video_out);
  925. if (buffer != NULL) {
  926. resizer_set_outaddr(res, buffer->dma);
  927. restart = 1;
  928. }
  929. pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
  930. if (res->input == RESIZER_INPUT_MEMORY) {
  931. buffer = omap3isp_video_buffer_next(&res->video_in);
  932. if (buffer != NULL)
  933. resizer_set_inaddr(res, buffer->dma);
  934. pipe->state |= ISP_PIPELINE_IDLE_INPUT;
  935. }
  936. if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
  937. if (isp_pipeline_ready(pipe))
  938. omap3isp_pipeline_set_stream(pipe,
  939. ISP_PIPELINE_STREAM_SINGLESHOT);
  940. } else {
  941. /* If an underrun occurs, the video queue operation handler will
  942. * restart the resizer. Otherwise restart it immediately.
  943. */
  944. if (restart)
  945. resizer_enable_oneshot(res);
  946. }
  947. }
  948. /*
  949. * omap3isp_resizer_isr - ISP resizer interrupt handler
  950. *
  951. * Manage the resizer video buffers and configure shadowed and busy-locked
  952. * registers.
  953. */
  954. void omap3isp_resizer_isr(struct isp_res_device *res)
  955. {
  956. struct v4l2_mbus_framefmt *informat, *outformat;
  957. unsigned long flags;
  958. if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
  959. return;
  960. spin_lock_irqsave(&res->lock, flags);
  961. if (res->applycrop) {
  962. outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
  963. V4L2_SUBDEV_FORMAT_ACTIVE);
  964. informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
  965. V4L2_SUBDEV_FORMAT_ACTIVE);
  966. resizer_set_crop_params(res, informat, outformat);
  967. res->applycrop = 0;
  968. }
  969. spin_unlock_irqrestore(&res->lock, flags);
  970. resizer_isr_buffer(res);
  971. }
  972. /* -----------------------------------------------------------------------------
  973. * ISP video operations
  974. */
  975. static int resizer_video_queue(struct isp_video *video,
  976. struct isp_buffer *buffer)
  977. {
  978. struct isp_res_device *res = &video->isp->isp_res;
  979. if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
  980. resizer_set_inaddr(res, buffer->dma);
  981. /*
  982. * We now have a buffer queued on the output. Despite what the
  983. * TRM says, the resizer can't be restarted immediately.
  984. * Enabling it in one shot mode in the middle of a frame (or at
  985. * least asynchronously to the frame) results in the output
  986. * being shifted randomly left/right and up/down, as if the
  987. * hardware didn't synchronize itself to the beginning of the
  988. * frame correctly.
  989. *
  990. * Restart the resizer on the next sync interrupt if running in
  991. * continuous mode or when starting the stream.
  992. */
  993. if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
  994. resizer_set_outaddr(res, buffer->dma);
  995. return 0;
  996. }
  997. static const struct isp_video_operations resizer_video_ops = {
  998. .queue = resizer_video_queue,
  999. };
  1000. /* -----------------------------------------------------------------------------
  1001. * V4L2 subdev operations
  1002. */
  1003. /*
  1004. * resizer_set_stream - Enable/Disable streaming on resizer subdev
  1005. * @sd: ISP resizer V4L2 subdev
  1006. * @enable: 1 == Enable, 0 == Disable
  1007. *
  1008. * The resizer hardware can't be enabled without a memory buffer to write to.
  1009. * As the s_stream operation is called in response to a STREAMON call without
  1010. * any buffer queued yet, just update the state field and return immediately.
  1011. * The resizer will be enabled in resizer_video_queue().
  1012. */
  1013. static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
  1014. {
  1015. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1016. struct isp_video *video_out = &res->video_out;
  1017. struct isp_device *isp = to_isp_device(res);
  1018. struct device *dev = to_device(res);
  1019. if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
  1020. if (enable == ISP_PIPELINE_STREAM_STOPPED)
  1021. return 0;
  1022. omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
  1023. resizer_configure(res);
  1024. resizer_print_status(res);
  1025. }
  1026. switch (enable) {
  1027. case ISP_PIPELINE_STREAM_CONTINUOUS:
  1028. omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
  1029. if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
  1030. resizer_enable_oneshot(res);
  1031. isp_video_dmaqueue_flags_clr(video_out);
  1032. }
  1033. break;
  1034. case ISP_PIPELINE_STREAM_SINGLESHOT:
  1035. if (res->input == RESIZER_INPUT_MEMORY)
  1036. omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
  1037. omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
  1038. resizer_enable_oneshot(res);
  1039. break;
  1040. case ISP_PIPELINE_STREAM_STOPPED:
  1041. if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
  1042. &res->stopping))
  1043. dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
  1044. omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
  1045. OMAP3_ISP_SBL_RESIZER_WRITE);
  1046. omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
  1047. isp_video_dmaqueue_flags_clr(video_out);
  1048. break;
  1049. }
  1050. res->state = enable;
  1051. return 0;
  1052. }
  1053. /*
  1054. * resizer_try_crop - mangles crop parameters.
  1055. */
  1056. static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
  1057. const struct v4l2_mbus_framefmt *source,
  1058. struct v4l2_rect *crop)
  1059. {
  1060. const unsigned int spv = DEFAULT_PHASE;
  1061. const unsigned int sph = DEFAULT_PHASE;
  1062. /* Crop rectangle is constrained by the output size so that zoom ratio
  1063. * cannot exceed +/-4.0.
  1064. */
  1065. unsigned int min_width =
  1066. ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
  1067. unsigned int min_height =
  1068. ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
  1069. unsigned int max_width =
  1070. ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
  1071. unsigned int max_height =
  1072. ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
  1073. crop->width = clamp_t(u32, crop->width, min_width, max_width);
  1074. crop->height = clamp_t(u32, crop->height, min_height, max_height);
  1075. /* Crop can not go beyond of the input rectangle */
  1076. crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
  1077. crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
  1078. sink->width - crop->left);
  1079. crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
  1080. crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
  1081. sink->height - crop->top);
  1082. }
  1083. /*
  1084. * resizer_get_selection - Retrieve a selection rectangle on a pad
  1085. * @sd: ISP resizer V4L2 subdevice
  1086. * @fh: V4L2 subdev file handle
  1087. * @sel: Selection rectangle
  1088. *
  1089. * The only supported rectangles are the crop rectangles on the sink pad.
  1090. *
  1091. * Return 0 on success or a negative error code otherwise.
  1092. */
  1093. static int resizer_get_selection(struct v4l2_subdev *sd,
  1094. struct v4l2_subdev_fh *fh,
  1095. struct v4l2_subdev_selection *sel)
  1096. {
  1097. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1098. struct v4l2_mbus_framefmt *format_source;
  1099. struct v4l2_mbus_framefmt *format_sink;
  1100. struct resizer_ratio ratio;
  1101. if (sel->pad != RESZ_PAD_SINK)
  1102. return -EINVAL;
  1103. format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
  1104. sel->which);
  1105. format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
  1106. sel->which);
  1107. switch (sel->target) {
  1108. case V4L2_SEL_TGT_CROP_BOUNDS:
  1109. sel->r.left = 0;
  1110. sel->r.top = 0;
  1111. sel->r.width = INT_MAX;
  1112. sel->r.height = INT_MAX;
  1113. resizer_try_crop(format_sink, format_source, &sel->r);
  1114. resizer_calc_ratios(res, &sel->r, format_source, &ratio);
  1115. break;
  1116. case V4L2_SEL_TGT_CROP:
  1117. sel->r = *__resizer_get_crop(res, fh, sel->which);
  1118. resizer_calc_ratios(res, &sel->r, format_source, &ratio);
  1119. break;
  1120. default:
  1121. return -EINVAL;
  1122. }
  1123. return 0;
  1124. }
  1125. /*
  1126. * resizer_set_selection - Set a selection rectangle on a pad
  1127. * @sd: ISP resizer V4L2 subdevice
  1128. * @fh: V4L2 subdev file handle
  1129. * @sel: Selection rectangle
  1130. *
  1131. * The only supported rectangle is the actual crop rectangle on the sink pad.
  1132. *
  1133. * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
  1134. * was always set.
  1135. *
  1136. * Return 0 on success or a negative error code otherwise.
  1137. */
  1138. static int resizer_set_selection(struct v4l2_subdev *sd,
  1139. struct v4l2_subdev_fh *fh,
  1140. struct v4l2_subdev_selection *sel)
  1141. {
  1142. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1143. struct isp_device *isp = to_isp_device(res);
  1144. const struct v4l2_mbus_framefmt *format_sink;
  1145. struct v4l2_mbus_framefmt format_source;
  1146. struct resizer_ratio ratio;
  1147. unsigned long flags;
  1148. if (sel->target != V4L2_SEL_TGT_CROP ||
  1149. sel->pad != RESZ_PAD_SINK)
  1150. return -EINVAL;
  1151. format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
  1152. sel->which);
  1153. format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE,
  1154. sel->which);
  1155. dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
  1156. __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
  1157. format_sink->width, format_sink->height,
  1158. sel->r.left, sel->r.top, sel->r.width, sel->r.height,
  1159. format_source.width, format_source.height);
  1160. /* Clamp the crop rectangle to the bounds, and then mangle it further to
  1161. * fulfill the TRM equations. Store the clamped but otherwise unmangled
  1162. * rectangle to avoid cropping the input multiple times: when an
  1163. * application sets the output format, the current crop rectangle is
  1164. * mangled during crop rectangle computation, which would lead to a new,
  1165. * smaller input crop rectangle every time the output size is set if we
  1166. * stored the mangled rectangle.
  1167. */
  1168. resizer_try_crop(format_sink, &format_source, &sel->r);
  1169. *__resizer_get_crop(res, fh, sel->which) = sel->r;
  1170. resizer_calc_ratios(res, &sel->r, &format_source, &ratio);
  1171. dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
  1172. __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
  1173. format_sink->width, format_sink->height,
  1174. sel->r.left, sel->r.top, sel->r.width, sel->r.height,
  1175. format_source.width, format_source.height);
  1176. if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
  1177. *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
  1178. format_source;
  1179. return 0;
  1180. }
  1181. /* Update the source format, resizing ratios and crop rectangle. If
  1182. * streaming is on the IRQ handler will reprogram the resizer after the
  1183. * current frame. We thus we need to protect against race conditions.
  1184. */
  1185. spin_lock_irqsave(&res->lock, flags);
  1186. *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
  1187. format_source;
  1188. res->ratio = ratio;
  1189. res->crop.active = sel->r;
  1190. if (res->state != ISP_PIPELINE_STREAM_STOPPED)
  1191. res->applycrop = 1;
  1192. spin_unlock_irqrestore(&res->lock, flags);
  1193. return 0;
  1194. }
  1195. /* resizer pixel formats */
  1196. static const unsigned int resizer_formats[] = {
  1197. V4L2_MBUS_FMT_UYVY8_1X16,
  1198. V4L2_MBUS_FMT_YUYV8_1X16,
  1199. };
  1200. static unsigned int resizer_max_in_width(struct isp_res_device *res)
  1201. {
  1202. struct isp_device *isp = to_isp_device(res);
  1203. if (res->input == RESIZER_INPUT_MEMORY) {
  1204. return MAX_IN_WIDTH_MEMORY_MODE;
  1205. } else {
  1206. if (isp->revision == ISP_REVISION_1_0)
  1207. return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
  1208. else
  1209. return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
  1210. }
  1211. }
  1212. /*
  1213. * resizer_try_format - Handle try format by pad subdev method
  1214. * @res : ISP resizer device
  1215. * @fh : V4L2 subdev file handle
  1216. * @pad : pad num
  1217. * @fmt : pointer to v4l2 format structure
  1218. * @which : wanted subdev format
  1219. */
  1220. static void resizer_try_format(struct isp_res_device *res,
  1221. struct v4l2_subdev_fh *fh, unsigned int pad,
  1222. struct v4l2_mbus_framefmt *fmt,
  1223. enum v4l2_subdev_format_whence which)
  1224. {
  1225. struct v4l2_mbus_framefmt *format;
  1226. struct resizer_ratio ratio;
  1227. struct v4l2_rect crop;
  1228. switch (pad) {
  1229. case RESZ_PAD_SINK:
  1230. if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
  1231. fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
  1232. fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
  1233. fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
  1234. resizer_max_in_width(res));
  1235. fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
  1236. MAX_IN_HEIGHT);
  1237. break;
  1238. case RESZ_PAD_SOURCE:
  1239. format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
  1240. fmt->code = format->code;
  1241. crop = *__resizer_get_crop(res, fh, which);
  1242. resizer_calc_ratios(res, &crop, fmt, &ratio);
  1243. break;
  1244. }
  1245. fmt->colorspace = V4L2_COLORSPACE_JPEG;
  1246. fmt->field = V4L2_FIELD_NONE;
  1247. }
  1248. /*
  1249. * resizer_enum_mbus_code - Handle pixel format enumeration
  1250. * @sd : pointer to v4l2 subdev structure
  1251. * @fh : V4L2 subdev file handle
  1252. * @code : pointer to v4l2_subdev_mbus_code_enum structure
  1253. * return -EINVAL or zero on success
  1254. */
  1255. static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
  1256. struct v4l2_subdev_fh *fh,
  1257. struct v4l2_subdev_mbus_code_enum *code)
  1258. {
  1259. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1260. struct v4l2_mbus_framefmt *format;
  1261. if (code->pad == RESZ_PAD_SINK) {
  1262. if (code->index >= ARRAY_SIZE(resizer_formats))
  1263. return -EINVAL;
  1264. code->code = resizer_formats[code->index];
  1265. } else {
  1266. if (code->index != 0)
  1267. return -EINVAL;
  1268. format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
  1269. V4L2_SUBDEV_FORMAT_TRY);
  1270. code->code = format->code;
  1271. }
  1272. return 0;
  1273. }
  1274. static int resizer_enum_frame_size(struct v4l2_subdev *sd,
  1275. struct v4l2_subdev_fh *fh,
  1276. struct v4l2_subdev_frame_size_enum *fse)
  1277. {
  1278. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1279. struct v4l2_mbus_framefmt format;
  1280. if (fse->index != 0)
  1281. return -EINVAL;
  1282. format.code = fse->code;
  1283. format.width = 1;
  1284. format.height = 1;
  1285. resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
  1286. fse->min_width = format.width;
  1287. fse->min_height = format.height;
  1288. if (format.code != fse->code)
  1289. return -EINVAL;
  1290. format.code = fse->code;
  1291. format.width = -1;
  1292. format.height = -1;
  1293. resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
  1294. fse->max_width = format.width;
  1295. fse->max_height = format.height;
  1296. return 0;
  1297. }
  1298. /*
  1299. * resizer_get_format - Handle get format by pads subdev method
  1300. * @sd : pointer to v4l2 subdev structure
  1301. * @fh : V4L2 subdev file handle
  1302. * @fmt : pointer to v4l2 subdev format structure
  1303. * return -EINVAL or zero on success
  1304. */
  1305. static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
  1306. struct v4l2_subdev_format *fmt)
  1307. {
  1308. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1309. struct v4l2_mbus_framefmt *format;
  1310. format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
  1311. if (format == NULL)
  1312. return -EINVAL;
  1313. fmt->format = *format;
  1314. return 0;
  1315. }
  1316. /*
  1317. * resizer_set_format - Handle set format by pads subdev method
  1318. * @sd : pointer to v4l2 subdev structure
  1319. * @fh : V4L2 subdev file handle
  1320. * @fmt : pointer to v4l2 subdev format structure
  1321. * return -EINVAL or zero on success
  1322. */
  1323. static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
  1324. struct v4l2_subdev_format *fmt)
  1325. {
  1326. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1327. struct v4l2_mbus_framefmt *format;
  1328. struct v4l2_rect *crop;
  1329. format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
  1330. if (format == NULL)
  1331. return -EINVAL;
  1332. resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
  1333. *format = fmt->format;
  1334. if (fmt->pad == RESZ_PAD_SINK) {
  1335. /* reset crop rectangle */
  1336. crop = __resizer_get_crop(res, fh, fmt->which);
  1337. crop->left = 0;
  1338. crop->top = 0;
  1339. crop->width = fmt->format.width;
  1340. crop->height = fmt->format.height;
  1341. /* Propagate the format from sink to source */
  1342. format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
  1343. fmt->which);
  1344. *format = fmt->format;
  1345. resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
  1346. fmt->which);
  1347. }
  1348. if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
  1349. /* Compute and store the active crop rectangle and resizer
  1350. * ratios. format already points to the source pad active
  1351. * format.
  1352. */
  1353. res->crop.active = res->crop.request;
  1354. resizer_calc_ratios(res, &res->crop.active, format,
  1355. &res->ratio);
  1356. }
  1357. return 0;
  1358. }
  1359. static int resizer_link_validate(struct v4l2_subdev *sd,
  1360. struct media_link *link,
  1361. struct v4l2_subdev_format *source_fmt,
  1362. struct v4l2_subdev_format *sink_fmt)
  1363. {
  1364. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1365. struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
  1366. omap3isp_resizer_max_rate(res, &pipe->max_rate);
  1367. return v4l2_subdev_link_validate_default(sd, link,
  1368. source_fmt, sink_fmt);
  1369. }
  1370. /*
  1371. * resizer_init_formats - Initialize formats on all pads
  1372. * @sd: ISP resizer V4L2 subdevice
  1373. * @fh: V4L2 subdev file handle
  1374. *
  1375. * Initialize all pad formats with default values. If fh is not NULL, try
  1376. * formats are initialized on the file handle. Otherwise active formats are
  1377. * initialized on the device.
  1378. */
  1379. static int resizer_init_formats(struct v4l2_subdev *sd,
  1380. struct v4l2_subdev_fh *fh)
  1381. {
  1382. struct v4l2_subdev_format format;
  1383. memset(&format, 0, sizeof(format));
  1384. format.pad = RESZ_PAD_SINK;
  1385. format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
  1386. format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
  1387. format.format.width = 4096;
  1388. format.format.height = 4096;
  1389. resizer_set_format(sd, fh, &format);
  1390. return 0;
  1391. }
  1392. /* subdev video operations */
  1393. static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
  1394. .s_stream = resizer_set_stream,
  1395. };
  1396. /* subdev pad operations */
  1397. static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
  1398. .enum_mbus_code = resizer_enum_mbus_code,
  1399. .enum_frame_size = resizer_enum_frame_size,
  1400. .get_fmt = resizer_get_format,
  1401. .set_fmt = resizer_set_format,
  1402. .get_selection = resizer_get_selection,
  1403. .set_selection = resizer_set_selection,
  1404. .link_validate = resizer_link_validate,
  1405. };
  1406. /* subdev operations */
  1407. static const struct v4l2_subdev_ops resizer_v4l2_ops = {
  1408. .video = &resizer_v4l2_video_ops,
  1409. .pad = &resizer_v4l2_pad_ops,
  1410. };
  1411. /* subdev internal operations */
  1412. static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
  1413. .open = resizer_init_formats,
  1414. };
  1415. /* -----------------------------------------------------------------------------
  1416. * Media entity operations
  1417. */
  1418. /*
  1419. * resizer_link_setup - Setup resizer connections.
  1420. * @entity : Pointer to media entity structure
  1421. * @local : Pointer to local pad array
  1422. * @remote : Pointer to remote pad array
  1423. * @flags : Link flags
  1424. * return -EINVAL or zero on success
  1425. */
  1426. static int resizer_link_setup(struct media_entity *entity,
  1427. const struct media_pad *local,
  1428. const struct media_pad *remote, u32 flags)
  1429. {
  1430. struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
  1431. struct isp_res_device *res = v4l2_get_subdevdata(sd);
  1432. switch (local->index | media_entity_type(remote->entity)) {
  1433. case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
  1434. /* read from memory */
  1435. if (flags & MEDIA_LNK_FL_ENABLED) {
  1436. if (res->input == RESIZER_INPUT_VP)
  1437. return -EBUSY;
  1438. res->input = RESIZER_INPUT_MEMORY;
  1439. } else {
  1440. if (res->input == RESIZER_INPUT_MEMORY)
  1441. res->input = RESIZER_INPUT_NONE;
  1442. }
  1443. break;
  1444. case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
  1445. /* read from ccdc or previewer */
  1446. if (flags & MEDIA_LNK_FL_ENABLED) {
  1447. if (res->input == RESIZER_INPUT_MEMORY)
  1448. return -EBUSY;
  1449. res->input = RESIZER_INPUT_VP;
  1450. } else {
  1451. if (res->input == RESIZER_INPUT_VP)
  1452. res->input = RESIZER_INPUT_NONE;
  1453. }
  1454. break;
  1455. case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
  1456. /* resizer always write to memory */
  1457. break;
  1458. default:
  1459. return -EINVAL;
  1460. }
  1461. return 0;
  1462. }
  1463. /* media operations */
  1464. static const struct media_entity_operations resizer_media_ops = {
  1465. .link_setup = resizer_link_setup,
  1466. .link_validate = v4l2_subdev_link_validate,
  1467. };
  1468. void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
  1469. {
  1470. v4l2_device_unregister_subdev(&res->subdev);
  1471. omap3isp_video_unregister(&res->video_in);
  1472. omap3isp_video_unregister(&res->video_out);
  1473. }
  1474. int omap3isp_resizer_register_entities(struct isp_res_device *res,
  1475. struct v4l2_device *vdev)
  1476. {
  1477. int ret;
  1478. /* Register the subdev and video nodes. */
  1479. ret = v4l2_device_register_subdev(vdev, &res->subdev);
  1480. if (ret < 0)
  1481. goto error;
  1482. ret = omap3isp_video_register(&res->video_in, vdev);
  1483. if (ret < 0)
  1484. goto error;
  1485. ret = omap3isp_video_register(&res->video_out, vdev);
  1486. if (ret < 0)
  1487. goto error;
  1488. return 0;
  1489. error:
  1490. omap3isp_resizer_unregister_entities(res);
  1491. return ret;
  1492. }
  1493. /* -----------------------------------------------------------------------------
  1494. * ISP resizer initialization and cleanup
  1495. */
  1496. /*
  1497. * resizer_init_entities - Initialize resizer subdev and media entity.
  1498. * @res : Pointer to resizer device structure
  1499. * return -ENOMEM or zero on success
  1500. */
  1501. static int resizer_init_entities(struct isp_res_device *res)
  1502. {
  1503. struct v4l2_subdev *sd = &res->subdev;
  1504. struct media_pad *pads = res->pads;
  1505. struct media_entity *me = &sd->entity;
  1506. int ret;
  1507. res->input = RESIZER_INPUT_NONE;
  1508. v4l2_subdev_init(sd, &resizer_v4l2_ops);
  1509. sd->internal_ops = &resizer_v4l2_internal_ops;
  1510. strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
  1511. sd->grp_id = 1 << 16; /* group ID for isp subdevs */
  1512. v4l2_set_subdevdata(sd, res);
  1513. sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
  1514. pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK
  1515. | MEDIA_PAD_FL_MUST_CONNECT;
  1516. pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
  1517. me->ops = &resizer_media_ops;
  1518. ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
  1519. if (ret < 0)
  1520. return ret;
  1521. resizer_init_formats(sd, NULL);
  1522. res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
  1523. res->video_in.ops = &resizer_video_ops;
  1524. res->video_in.isp = to_isp_device(res);
  1525. res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
  1526. res->video_in.bpl_alignment = 32;
  1527. res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  1528. res->video_out.ops = &resizer_video_ops;
  1529. res->video_out.isp = to_isp_device(res);
  1530. res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
  1531. res->video_out.bpl_alignment = 32;
  1532. ret = omap3isp_video_init(&res->video_in, "resizer");
  1533. if (ret < 0)
  1534. goto error_video_in;
  1535. ret = omap3isp_video_init(&res->video_out, "resizer");
  1536. if (ret < 0)
  1537. goto error_video_out;
  1538. res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
  1539. /* Connect the video nodes to the resizer subdev. */
  1540. ret = media_entity_create_link(&res->video_in.video.entity, 0,
  1541. &res->subdev.entity, RESZ_PAD_SINK, 0);
  1542. if (ret < 0)
  1543. goto error_link;
  1544. ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
  1545. &res->video_out.video.entity, 0, 0);
  1546. if (ret < 0)
  1547. goto error_link;
  1548. return 0;
  1549. error_link:
  1550. omap3isp_video_cleanup(&res->video_out);
  1551. error_video_out:
  1552. omap3isp_video_cleanup(&res->video_in);
  1553. error_video_in:
  1554. media_entity_cleanup(&res->subdev.entity);
  1555. return ret;
  1556. }
  1557. /*
  1558. * isp_resizer_init - Resizer initialization.
  1559. * @isp : Pointer to ISP device
  1560. * return -ENOMEM or zero on success
  1561. */
  1562. int omap3isp_resizer_init(struct isp_device *isp)
  1563. {
  1564. struct isp_res_device *res = &isp->isp_res;
  1565. init_waitqueue_head(&res->wait);
  1566. atomic_set(&res->stopping, 0);
  1567. spin_lock_init(&res->lock);
  1568. return resizer_init_entities(res);
  1569. }
  1570. void omap3isp_resizer_cleanup(struct isp_device *isp)
  1571. {
  1572. struct isp_res_device *res = &isp->isp_res;
  1573. omap3isp_video_cleanup(&res->video_in);
  1574. omap3isp_video_cleanup(&res->video_out);
  1575. media_entity_cleanup(&res->subdev.entity);
  1576. }