isph3a_aewb.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. #include <linux/slab.h>
  18. #include <linux/uaccess.h>
  19. #include "isp.h"
  20. #include "isph3a.h"
  21. #include "ispstat.h"
  22. /*
  23. * h3a_aewb_update_regs - Helper function to update h3a registers.
  24. */
  25. static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv)
  26. {
  27. struct omap3isp_h3a_aewb_config *conf = priv;
  28. u32 pcr;
  29. u32 win1;
  30. u32 start;
  31. u32 blk;
  32. u32 subwin;
  33. if (aewb->state == ISPSTAT_DISABLED)
  34. return;
  35. isp_reg_writel(aewb->isp, aewb->active_buf->dma_addr,
  36. OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
  37. if (!aewb->update)
  38. return;
  39. /* Converting config metadata into reg values */
  40. pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT;
  41. pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT;
  42. win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT;
  43. win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT;
  44. win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT;
  45. win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT;
  46. start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT;
  47. start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT;
  48. blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT;
  49. blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT;
  50. subwin = ((conf->subsample_ver_inc >> 1) - 1) <<
  51. ISPH3A_AEWSUBWIN_AEWINCV_SHIFT;
  52. subwin |= ((conf->subsample_hor_inc >> 1) - 1) <<
  53. ISPH3A_AEWSUBWIN_AEWINCH_SHIFT;
  54. isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
  55. isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A,
  56. ISPH3A_AEWINSTART);
  57. isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
  58. isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A,
  59. ISPH3A_AEWSUBWIN);
  60. isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
  61. ISPH3A_PCR_AEW_MASK, pcr);
  62. aewb->update = 0;
  63. aewb->config_counter += aewb->inc_config;
  64. aewb->inc_config = 0;
  65. aewb->buf_size = conf->buf_size;
  66. }
  67. static void h3a_aewb_enable(struct ispstat *aewb, int enable)
  68. {
  69. if (enable) {
  70. isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
  71. ISPH3A_PCR_AEW_EN);
  72. omap3isp_subclk_enable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
  73. } else {
  74. isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
  75. ISPH3A_PCR_AEW_EN);
  76. omap3isp_subclk_disable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
  77. }
  78. }
  79. static int h3a_aewb_busy(struct ispstat *aewb)
  80. {
  81. return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
  82. & ISPH3A_PCR_BUSYAEAWB;
  83. }
  84. static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
  85. {
  86. /* Number of configured windows + extra row for black data */
  87. u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
  88. /*
  89. * Unsaturated block counts for each 8 windows.
  90. * 1 extra for the last (win_count % 8) windows if win_count is not
  91. * divisible by 8.
  92. */
  93. win_count += (win_count + 7) / 8;
  94. return win_count * AEWB_PACKET_SIZE;
  95. }
  96. static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
  97. {
  98. struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
  99. u32 buf_size;
  100. if (unlikely(user_cfg->saturation_limit >
  101. OMAP3ISP_AEWB_MAX_SATURATION_LIM))
  102. return -EINVAL;
  103. if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
  104. user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
  105. user_cfg->win_height & 0x01))
  106. return -EINVAL;
  107. if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
  108. user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
  109. user_cfg->win_width & 0x01))
  110. return -EINVAL;
  111. if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
  112. user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
  113. return -EINVAL;
  114. if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
  115. user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
  116. return -EINVAL;
  117. if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  118. return -EINVAL;
  119. if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  120. return -EINVAL;
  121. if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  122. return -EINVAL;
  123. if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
  124. user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
  125. user_cfg->blk_win_height & 0x01))
  126. return -EINVAL;
  127. if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
  128. user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
  129. user_cfg->subsample_ver_inc & 0x01))
  130. return -EINVAL;
  131. if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
  132. user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
  133. user_cfg->subsample_hor_inc & 0x01))
  134. return -EINVAL;
  135. buf_size = h3a_aewb_get_buf_size(user_cfg);
  136. if (buf_size > user_cfg->buf_size)
  137. user_cfg->buf_size = buf_size;
  138. else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
  139. user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
  140. return 0;
  141. }
  142. /*
  143. * h3a_aewb_set_params - Helper function to check & store user given params.
  144. * @new_conf: Pointer to AE and AWB parameters struct.
  145. *
  146. * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
  147. * program them during ISR.
  148. */
  149. static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
  150. {
  151. struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
  152. struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
  153. int update = 0;
  154. if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
  155. cur_cfg->saturation_limit = user_cfg->saturation_limit;
  156. update = 1;
  157. }
  158. if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
  159. cur_cfg->alaw_enable = user_cfg->alaw_enable;
  160. update = 1;
  161. }
  162. if (cur_cfg->win_height != user_cfg->win_height) {
  163. cur_cfg->win_height = user_cfg->win_height;
  164. update = 1;
  165. }
  166. if (cur_cfg->win_width != user_cfg->win_width) {
  167. cur_cfg->win_width = user_cfg->win_width;
  168. update = 1;
  169. }
  170. if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
  171. cur_cfg->ver_win_count = user_cfg->ver_win_count;
  172. update = 1;
  173. }
  174. if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
  175. cur_cfg->hor_win_count = user_cfg->hor_win_count;
  176. update = 1;
  177. }
  178. if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
  179. cur_cfg->ver_win_start = user_cfg->ver_win_start;
  180. update = 1;
  181. }
  182. if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
  183. cur_cfg->hor_win_start = user_cfg->hor_win_start;
  184. update = 1;
  185. }
  186. if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
  187. cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
  188. update = 1;
  189. }
  190. if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
  191. cur_cfg->blk_win_height = user_cfg->blk_win_height;
  192. update = 1;
  193. }
  194. if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
  195. cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
  196. update = 1;
  197. }
  198. if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
  199. cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
  200. update = 1;
  201. }
  202. if (update || !aewb->configured) {
  203. aewb->inc_config++;
  204. aewb->update = 1;
  205. cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
  206. }
  207. }
  208. static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
  209. {
  210. struct ispstat *stat = v4l2_get_subdevdata(sd);
  211. switch (cmd) {
  212. case VIDIOC_OMAP3ISP_AEWB_CFG:
  213. return omap3isp_stat_config(stat, arg);
  214. case VIDIOC_OMAP3ISP_STAT_REQ:
  215. return omap3isp_stat_request_statistics(stat, arg);
  216. case VIDIOC_OMAP3ISP_STAT_EN: {
  217. unsigned long *en = arg;
  218. return omap3isp_stat_enable(stat, !!*en);
  219. }
  220. }
  221. return -ENOIOCTLCMD;
  222. }
  223. static const struct ispstat_ops h3a_aewb_ops = {
  224. .validate_params = h3a_aewb_validate_params,
  225. .set_params = h3a_aewb_set_params,
  226. .setup_regs = h3a_aewb_setup_regs,
  227. .enable = h3a_aewb_enable,
  228. .busy = h3a_aewb_busy,
  229. };
  230. static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
  231. .ioctl = h3a_aewb_ioctl,
  232. .subscribe_event = omap3isp_stat_subscribe_event,
  233. .unsubscribe_event = omap3isp_stat_unsubscribe_event,
  234. };
  235. static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
  236. .s_stream = omap3isp_stat_s_stream,
  237. };
  238. static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
  239. .core = &h3a_aewb_subdev_core_ops,
  240. .video = &h3a_aewb_subdev_video_ops,
  241. };
  242. /*
  243. * omap3isp_h3a_aewb_init - Module Initialisation.
  244. */
  245. int omap3isp_h3a_aewb_init(struct isp_device *isp)
  246. {
  247. struct ispstat *aewb = &isp->isp_aewb;
  248. struct omap3isp_h3a_aewb_config *aewb_cfg;
  249. struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
  250. aewb_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_cfg), GFP_KERNEL);
  251. if (!aewb_cfg)
  252. return -ENOMEM;
  253. aewb->ops = &h3a_aewb_ops;
  254. aewb->priv = aewb_cfg;
  255. aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
  256. aewb->isp = isp;
  257. /* Set recover state configuration */
  258. aewb_recover_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_recover_cfg),
  259. GFP_KERNEL);
  260. if (!aewb_recover_cfg) {
  261. dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
  262. "recover configuration.\n");
  263. return -ENOMEM;
  264. }
  265. aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
  266. aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
  267. aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
  268. aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
  269. aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
  270. aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
  271. aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
  272. aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
  273. aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
  274. aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
  275. if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
  276. dev_err(aewb->isp->dev, "AEWB: recover configuration is "
  277. "invalid.\n");
  278. return -EINVAL;
  279. }
  280. aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
  281. aewb->recover_priv = aewb_recover_cfg;
  282. return omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
  283. }
  284. /*
  285. * omap3isp_h3a_aewb_cleanup - Module exit.
  286. */
  287. void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
  288. {
  289. omap3isp_stat_cleanup(&isp->isp_aewb);
  290. }