isph3a_aewb.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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. omap3isp_subclk_enable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
  83. } else {
  84. isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
  85. ISPH3A_PCR_AEW_EN);
  86. omap3isp_subclk_disable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
  87. }
  88. }
  89. static int h3a_aewb_busy(struct ispstat *aewb)
  90. {
  91. return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
  92. & ISPH3A_PCR_BUSYAEAWB;
  93. }
  94. static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
  95. {
  96. /* Number of configured windows + extra row for black data */
  97. u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
  98. /*
  99. * Unsaturated block counts for each 8 windows.
  100. * 1 extra for the last (win_count % 8) windows if win_count is not
  101. * divisible by 8.
  102. */
  103. win_count += (win_count + 7) / 8;
  104. return win_count * AEWB_PACKET_SIZE;
  105. }
  106. static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
  107. {
  108. struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
  109. u32 buf_size;
  110. if (unlikely(user_cfg->saturation_limit >
  111. OMAP3ISP_AEWB_MAX_SATURATION_LIM))
  112. return -EINVAL;
  113. if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
  114. user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
  115. user_cfg->win_height & 0x01))
  116. return -EINVAL;
  117. if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
  118. user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
  119. user_cfg->win_width & 0x01))
  120. return -EINVAL;
  121. if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
  122. user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
  123. return -EINVAL;
  124. if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
  125. user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
  126. return -EINVAL;
  127. if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  128. return -EINVAL;
  129. if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  130. return -EINVAL;
  131. if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
  132. return -EINVAL;
  133. if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
  134. user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
  135. user_cfg->blk_win_height & 0x01))
  136. return -EINVAL;
  137. if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
  138. user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
  139. user_cfg->subsample_ver_inc & 0x01))
  140. return -EINVAL;
  141. if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
  142. user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
  143. user_cfg->subsample_hor_inc & 0x01))
  144. return -EINVAL;
  145. buf_size = h3a_aewb_get_buf_size(user_cfg);
  146. if (buf_size > user_cfg->buf_size)
  147. user_cfg->buf_size = buf_size;
  148. else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
  149. user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
  150. return 0;
  151. }
  152. /*
  153. * h3a_aewb_set_params - Helper function to check & store user given params.
  154. * @new_conf: Pointer to AE and AWB parameters struct.
  155. *
  156. * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
  157. * program them during ISR.
  158. */
  159. static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
  160. {
  161. struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
  162. struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
  163. int update = 0;
  164. if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
  165. cur_cfg->saturation_limit = user_cfg->saturation_limit;
  166. update = 1;
  167. }
  168. if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
  169. cur_cfg->alaw_enable = user_cfg->alaw_enable;
  170. update = 1;
  171. }
  172. if (cur_cfg->win_height != user_cfg->win_height) {
  173. cur_cfg->win_height = user_cfg->win_height;
  174. update = 1;
  175. }
  176. if (cur_cfg->win_width != user_cfg->win_width) {
  177. cur_cfg->win_width = user_cfg->win_width;
  178. update = 1;
  179. }
  180. if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
  181. cur_cfg->ver_win_count = user_cfg->ver_win_count;
  182. update = 1;
  183. }
  184. if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
  185. cur_cfg->hor_win_count = user_cfg->hor_win_count;
  186. update = 1;
  187. }
  188. if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
  189. cur_cfg->ver_win_start = user_cfg->ver_win_start;
  190. update = 1;
  191. }
  192. if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
  193. cur_cfg->hor_win_start = user_cfg->hor_win_start;
  194. update = 1;
  195. }
  196. if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
  197. cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
  198. update = 1;
  199. }
  200. if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
  201. cur_cfg->blk_win_height = user_cfg->blk_win_height;
  202. update = 1;
  203. }
  204. if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
  205. cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
  206. update = 1;
  207. }
  208. if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
  209. cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
  210. update = 1;
  211. }
  212. if (update || !aewb->configured) {
  213. aewb->inc_config++;
  214. aewb->update = 1;
  215. cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
  216. }
  217. }
  218. static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
  219. {
  220. struct ispstat *stat = v4l2_get_subdevdata(sd);
  221. switch (cmd) {
  222. case VIDIOC_OMAP3ISP_AEWB_CFG:
  223. return omap3isp_stat_config(stat, arg);
  224. case VIDIOC_OMAP3ISP_STAT_REQ:
  225. return omap3isp_stat_request_statistics(stat, arg);
  226. case VIDIOC_OMAP3ISP_STAT_EN: {
  227. unsigned long *en = arg;
  228. return omap3isp_stat_enable(stat, !!*en);
  229. }
  230. }
  231. return -ENOIOCTLCMD;
  232. }
  233. static const struct ispstat_ops h3a_aewb_ops = {
  234. .validate_params = h3a_aewb_validate_params,
  235. .set_params = h3a_aewb_set_params,
  236. .setup_regs = h3a_aewb_setup_regs,
  237. .enable = h3a_aewb_enable,
  238. .busy = h3a_aewb_busy,
  239. };
  240. static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
  241. .ioctl = h3a_aewb_ioctl,
  242. .subscribe_event = omap3isp_stat_subscribe_event,
  243. .unsubscribe_event = omap3isp_stat_unsubscribe_event,
  244. };
  245. static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
  246. .s_stream = omap3isp_stat_s_stream,
  247. };
  248. static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
  249. .core = &h3a_aewb_subdev_core_ops,
  250. .video = &h3a_aewb_subdev_video_ops,
  251. };
  252. /*
  253. * omap3isp_h3a_aewb_init - Module Initialisation.
  254. */
  255. int omap3isp_h3a_aewb_init(struct isp_device *isp)
  256. {
  257. struct ispstat *aewb = &isp->isp_aewb;
  258. struct omap3isp_h3a_aewb_config *aewb_cfg;
  259. struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
  260. aewb_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_cfg), GFP_KERNEL);
  261. if (!aewb_cfg)
  262. return -ENOMEM;
  263. aewb->ops = &h3a_aewb_ops;
  264. aewb->priv = aewb_cfg;
  265. aewb->dma_ch = -1;
  266. aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
  267. aewb->isp = isp;
  268. /* Set recover state configuration */
  269. aewb_recover_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_recover_cfg),
  270. GFP_KERNEL);
  271. if (!aewb_recover_cfg) {
  272. dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
  273. "recover configuration.\n");
  274. return -ENOMEM;
  275. }
  276. aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
  277. aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
  278. aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
  279. aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
  280. aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
  281. aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
  282. aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
  283. aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
  284. aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
  285. aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
  286. if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
  287. dev_err(aewb->isp->dev, "AEWB: recover configuration is "
  288. "invalid.\n");
  289. return -EINVAL;
  290. }
  291. aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
  292. aewb->recover_priv = aewb_recover_cfg;
  293. return omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
  294. }
  295. /*
  296. * omap3isp_h3a_aewb_cleanup - Module exit.
  297. */
  298. void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
  299. {
  300. omap3isp_stat_cleanup(&isp->isp_aewb);
  301. }