isph3a_aewb.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * isph3a.c
  3. *
  4. * TI OMAP3 ISP - H3A module
  5. *
  6. * Copyright (C) 2010 Nokia Corporation
  7. * Copyright (C) 2009 Texas Instruments, Inc.
  8. *
  9. * Contacts: David Cohen <dacohen@gmail.com>
  10. * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  11. * Sakari Ailus <sakari.ailus@iki.fi>
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License version 2 as
  15. * published by the Free Software Foundation.
  16. *
  17. * This program is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  25. * 02110-1301 USA
  26. */
  27. #include <linux/slab.h>
  28. #include <linux/uaccess.h>
  29. #include "isp.h"
  30. #include "isph3a.h"
  31. #include "ispstat.h"
  32. /*
  33. * h3a_aewb_update_regs - Helper function to update h3a registers.
  34. */
  35. static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv)
  36. {
  37. struct omap3isp_h3a_aewb_config *conf = priv;
  38. u32 pcr;
  39. u32 win1;
  40. u32 start;
  41. u32 blk;
  42. u32 subwin;
  43. if (aewb->state == ISPSTAT_DISABLED)
  44. return;
  45. isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr,
  46. OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
  47. if (!aewb->update)
  48. return;
  49. /* Converting config metadata into reg values */
  50. pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT;
  51. pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT;
  52. win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT;
  53. win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT;
  54. win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT;
  55. win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT;
  56. start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT;
  57. start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT;
  58. blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT;
  59. blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT;
  60. subwin = ((conf->subsample_ver_inc >> 1) - 1) <<
  61. ISPH3A_AEWSUBWIN_AEWINCV_SHIFT;
  62. subwin |= ((conf->subsample_hor_inc >> 1) - 1) <<
  63. ISPH3A_AEWSUBWIN_AEWINCH_SHIFT;
  64. isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
  65. isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A,
  66. ISPH3A_AEWINSTART);
  67. isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
  68. isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A,
  69. ISPH3A_AEWSUBWIN);
  70. isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
  71. ISPH3A_PCR_AEW_MASK, pcr);
  72. aewb->update = 0;
  73. aewb->config_counter += aewb->inc_config;
  74. aewb->inc_config = 0;
  75. aewb->buf_size = conf->buf_size;
  76. }
  77. static void h3a_aewb_enable(struct ispstat *aewb, int enable)
  78. {
  79. if (enable) {
  80. isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
  81. ISPH3A_PCR_AEW_EN);
  82. /* This bit is already set if AF is enabled */
  83. if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
  84. isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
  85. ISPCTRL_H3A_CLK_EN);
  86. } else {
  87. isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
  88. ISPH3A_PCR_AEW_EN);
  89. /* This bit can't be cleared if AF is enabled */
  90. if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
  91. isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
  92. ISPCTRL_H3A_CLK_EN);
  93. }
  94. }
  95. static int h3a_aewb_busy(struct ispstat *aewb)
  96. {
  97. return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
  98. & ISPH3A_PCR_BUSYAEAWB;
  99. }
  100. static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
  101. {
  102. /* Number of configured windows + extra row for black data */
  103. u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
  104. /*
  105. * Unsaturated block counts for each 8 windows.
  106. * 1 extra for the last (win_count % 8) windows if win_count is not
  107. * divisible by 8.
  108. */
  109. win_count += (win_count + 7) / 8;
  110. return win_count * AEWB_PACKET_SIZE;
  111. }
  112. static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
  113. {
  114. struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
  115. u32 buf_size;
  116. if (unlikely(user_cfg->saturation_limit >
  117. OMAP3ISP_AEWB_MAX_SATURATION_LIM))
  118. return -EINVAL;
  119. if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
  120. user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
  121. user_cfg->win_height & 0x01))
  122. return -EINVAL;
  123. if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
  124. user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
  125. user_cfg->win_width & 0x01))
  126. return -EINVAL;
  127. if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
  128. user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
  129. return -EINVAL;
  130. if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
  131. user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
  132. return -EINVAL;
  133. if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  134. return -EINVAL;
  135. if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  136. return -EINVAL;
  137. if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  138. return -EINVAL;
  139. if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
  140. user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
  141. user_cfg->blk_win_height & 0x01))
  142. return -EINVAL;
  143. if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
  144. user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
  145. user_cfg->subsample_ver_inc & 0x01))
  146. return -EINVAL;
  147. if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
  148. user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
  149. user_cfg->subsample_hor_inc & 0x01))
  150. return -EINVAL;
  151. buf_size = h3a_aewb_get_buf_size(user_cfg);
  152. if (buf_size > user_cfg->buf_size)
  153. user_cfg->buf_size = buf_size;
  154. else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
  155. user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
  156. return 0;
  157. }
  158. /*
  159. * h3a_aewb_set_params - Helper function to check & store user given params.
  160. * @new_conf: Pointer to AE and AWB parameters struct.
  161. *
  162. * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
  163. * program them during ISR.
  164. */
  165. static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
  166. {
  167. struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
  168. struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
  169. int update = 0;
  170. if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
  171. cur_cfg->saturation_limit = user_cfg->saturation_limit;
  172. update = 1;
  173. }
  174. if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
  175. cur_cfg->alaw_enable = user_cfg->alaw_enable;
  176. update = 1;
  177. }
  178. if (cur_cfg->win_height != user_cfg->win_height) {
  179. cur_cfg->win_height = user_cfg->win_height;
  180. update = 1;
  181. }
  182. if (cur_cfg->win_width != user_cfg->win_width) {
  183. cur_cfg->win_width = user_cfg->win_width;
  184. update = 1;
  185. }
  186. if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
  187. cur_cfg->ver_win_count = user_cfg->ver_win_count;
  188. update = 1;
  189. }
  190. if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
  191. cur_cfg->hor_win_count = user_cfg->hor_win_count;
  192. update = 1;
  193. }
  194. if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
  195. cur_cfg->ver_win_start = user_cfg->ver_win_start;
  196. update = 1;
  197. }
  198. if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
  199. cur_cfg->hor_win_start = user_cfg->hor_win_start;
  200. update = 1;
  201. }
  202. if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
  203. cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
  204. update = 1;
  205. }
  206. if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
  207. cur_cfg->blk_win_height = user_cfg->blk_win_height;
  208. update = 1;
  209. }
  210. if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
  211. cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
  212. update = 1;
  213. }
  214. if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
  215. cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
  216. update = 1;
  217. }
  218. if (update || !aewb->configured) {
  219. aewb->inc_config++;
  220. aewb->update = 1;
  221. cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
  222. }
  223. }
  224. static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
  225. {
  226. struct ispstat *stat = v4l2_get_subdevdata(sd);
  227. switch (cmd) {
  228. case VIDIOC_OMAP3ISP_AEWB_CFG:
  229. return omap3isp_stat_config(stat, arg);
  230. case VIDIOC_OMAP3ISP_STAT_REQ:
  231. return omap3isp_stat_request_statistics(stat, arg);
  232. case VIDIOC_OMAP3ISP_STAT_EN: {
  233. unsigned long *en = arg;
  234. return omap3isp_stat_enable(stat, !!*en);
  235. }
  236. }
  237. return -ENOIOCTLCMD;
  238. }
  239. static const struct ispstat_ops h3a_aewb_ops = {
  240. .validate_params = h3a_aewb_validate_params,
  241. .set_params = h3a_aewb_set_params,
  242. .setup_regs = h3a_aewb_setup_regs,
  243. .enable = h3a_aewb_enable,
  244. .busy = h3a_aewb_busy,
  245. };
  246. static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
  247. .ioctl = h3a_aewb_ioctl,
  248. .subscribe_event = omap3isp_stat_subscribe_event,
  249. .unsubscribe_event = omap3isp_stat_unsubscribe_event,
  250. };
  251. static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
  252. .s_stream = omap3isp_stat_s_stream,
  253. };
  254. static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
  255. .core = &h3a_aewb_subdev_core_ops,
  256. .video = &h3a_aewb_subdev_video_ops,
  257. };
  258. /*
  259. * omap3isp_h3a_aewb_init - Module Initialisation.
  260. */
  261. int omap3isp_h3a_aewb_init(struct isp_device *isp)
  262. {
  263. struct ispstat *aewb = &isp->isp_aewb;
  264. struct omap3isp_h3a_aewb_config *aewb_cfg;
  265. struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
  266. int ret;
  267. aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
  268. if (!aewb_cfg)
  269. return -ENOMEM;
  270. memset(aewb, 0, sizeof(*aewb));
  271. aewb->ops = &h3a_aewb_ops;
  272. aewb->priv = aewb_cfg;
  273. aewb->dma_ch = -1;
  274. aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
  275. aewb->isp = isp;
  276. /* Set recover state configuration */
  277. aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
  278. if (!aewb_recover_cfg) {
  279. dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
  280. "recover configuration.\n");
  281. ret = -ENOMEM;
  282. goto err_recover_alloc;
  283. }
  284. aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
  285. aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
  286. aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
  287. aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
  288. aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
  289. aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
  290. aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
  291. aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
  292. aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
  293. aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
  294. if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
  295. dev_err(aewb->isp->dev, "AEWB: recover configuration is "
  296. "invalid.\n");
  297. ret = -EINVAL;
  298. goto err_conf;
  299. }
  300. aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
  301. aewb->recover_priv = aewb_recover_cfg;
  302. ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
  303. if (ret)
  304. goto err_conf;
  305. return 0;
  306. err_conf:
  307. kfree(aewb_recover_cfg);
  308. err_recover_alloc:
  309. kfree(aewb_cfg);
  310. return ret;
  311. }
  312. /*
  313. * omap3isp_h3a_aewb_cleanup - Module exit.
  314. */
  315. void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
  316. {
  317. kfree(isp->isp_aewb.priv);
  318. kfree(isp->isp_aewb.recover_priv);
  319. omap3isp_stat_cleanup(&isp->isp_aewb);
  320. }