4 * TI OMAP3 ISP - Histogram module
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
9 * Contacts: David Cohen <dacohen@gmail.com>
10 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
11 * Sakari Ailus <sakari.ailus@iki.fi>
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.
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.
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
28 #include <linux/delay.h>
29 #include <linux/slab.h>
30 #include <linux/uaccess.h>
31 #include <linux/device.h>
37 #define HIST_CONFIG_DMA 1
39 #define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
42 * hist_reset_mem - clear Histogram memory before start stats engine.
44 static void hist_reset_mem(struct ispstat
*hist
)
46 struct isp_device
*isp
= hist
->isp
;
47 struct omap3isp_hist_config
*conf
= hist
->priv
;
50 isp_reg_writel(isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
53 * By setting it, the histogram internal buffer is being cleared at the
54 * same time it's being read. This bit must be cleared afterwards.
56 isp_reg_set(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
59 * We'll clear 4 words at each iteration for optimization. It avoids
60 * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
62 for (i
= OMAP3ISP_HIST_MEM_SIZE
/ 4; i
> 0; i
--) {
63 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
64 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
65 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
66 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
68 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
70 hist
->wait_acc_frames
= conf
->num_acc_frames
;
73 static void hist_dma_config(struct ispstat
*hist
)
75 hist
->dma_config
.data_type
= OMAP_DMA_DATA_TYPE_S32
;
76 hist
->dma_config
.sync_mode
= OMAP_DMA_SYNC_ELEMENT
;
77 hist
->dma_config
.frame_count
= 1;
78 hist
->dma_config
.src_amode
= OMAP_DMA_AMODE_CONSTANT
;
79 hist
->dma_config
.src_start
= OMAP3ISP_HIST_REG_BASE
+ ISPHIST_DATA
;
80 hist
->dma_config
.dst_amode
= OMAP_DMA_AMODE_POST_INC
;
81 hist
->dma_config
.src_or_dst_synch
= OMAP_DMA_SRC_SYNC
;
85 * hist_setup_regs - Helper function to update Histogram registers.
87 static void hist_setup_regs(struct ispstat
*hist
, void *priv
)
89 struct isp_device
*isp
= hist
->isp
;
90 struct omap3isp_hist_config
*conf
= priv
;
94 u32 reg_hor
[OMAP3ISP_HIST_MAX_REGIONS
];
95 u32 reg_ver
[OMAP3ISP_HIST_MAX_REGIONS
];
97 if (!hist
->update
|| hist
->state
== ISPSTAT_DISABLED
||
98 hist
->state
== ISPSTAT_DISABLING
)
101 cnt
= conf
->cfa
<< ISPHIST_CNT_CFA_SHIFT
;
103 wb_gain
= conf
->wg
[0] << ISPHIST_WB_GAIN_WG00_SHIFT
;
104 wb_gain
|= conf
->wg
[1] << ISPHIST_WB_GAIN_WG01_SHIFT
;
105 wb_gain
|= conf
->wg
[2] << ISPHIST_WB_GAIN_WG02_SHIFT
;
106 if (conf
->cfa
== OMAP3ISP_HIST_CFA_BAYER
)
107 wb_gain
|= conf
->wg
[3] << ISPHIST_WB_GAIN_WG03_SHIFT
;
109 /* Regions size and position */
110 for (c
= 0; c
< OMAP3ISP_HIST_MAX_REGIONS
; c
++) {
111 if (c
< conf
->num_regions
) {
112 reg_hor
[c
] = conf
->region
[c
].h_start
<<
113 ISPHIST_REG_START_SHIFT
;
114 reg_hor
[c
] = conf
->region
[c
].h_end
<<
115 ISPHIST_REG_END_SHIFT
;
116 reg_ver
[c
] = conf
->region
[c
].v_start
<<
117 ISPHIST_REG_START_SHIFT
;
118 reg_ver
[c
] = conf
->region
[c
].v_end
<<
119 ISPHIST_REG_END_SHIFT
;
126 cnt
|= conf
->hist_bins
<< ISPHIST_CNT_BINS_SHIFT
;
127 switch (conf
->hist_bins
) {
128 case OMAP3ISP_HIST_BINS_256
:
129 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 8) <<
130 ISPHIST_CNT_SHIFT_SHIFT
;
132 case OMAP3ISP_HIST_BINS_128
:
133 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 7) <<
134 ISPHIST_CNT_SHIFT_SHIFT
;
136 case OMAP3ISP_HIST_BINS_64
:
137 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 6) <<
138 ISPHIST_CNT_SHIFT_SHIFT
;
140 default: /* OMAP3ISP_HIST_BINS_32 */
141 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 5) <<
142 ISPHIST_CNT_SHIFT_SHIFT
;
146 hist_reset_mem(hist
);
148 isp_reg_writel(isp
, cnt
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
);
149 isp_reg_writel(isp
, wb_gain
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_WB_GAIN
);
150 isp_reg_writel(isp
, reg_hor
[0], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_HORZ
);
151 isp_reg_writel(isp
, reg_ver
[0], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_VERT
);
152 isp_reg_writel(isp
, reg_hor
[1], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_HORZ
);
153 isp_reg_writel(isp
, reg_ver
[1], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_VERT
);
154 isp_reg_writel(isp
, reg_hor
[2], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_HORZ
);
155 isp_reg_writel(isp
, reg_ver
[2], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_VERT
);
156 isp_reg_writel(isp
, reg_hor
[3], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_HORZ
);
157 isp_reg_writel(isp
, reg_ver
[3], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_VERT
);
160 hist
->config_counter
+= hist
->inc_config
;
161 hist
->inc_config
= 0;
162 hist
->buf_size
= conf
->buf_size
;
165 static void hist_enable(struct ispstat
*hist
, int enable
)
168 isp_reg_set(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
,
170 isp_reg_set(hist
->isp
, OMAP3_ISP_IOMEM_MAIN
, ISP_CTRL
,
171 ISPCTRL_HIST_CLK_EN
);
173 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
,
175 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_MAIN
, ISP_CTRL
,
176 ISPCTRL_HIST_CLK_EN
);
180 static int hist_busy(struct ispstat
*hist
)
182 return isp_reg_readl(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
)
186 static void hist_dma_cb(int lch
, u16 ch_status
, void *data
)
188 struct ispstat
*hist
= data
;
190 if (ch_status
& ~OMAP_DMA_BLOCK_IRQ
) {
191 dev_dbg(hist
->isp
->dev
, "hist: DMA error. status = 0x%04x\n",
194 hist_reset_mem(hist
);
195 atomic_set(&hist
->buf_err
, 1);
197 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
200 omap3isp_stat_dma_isr(hist
);
201 if (hist
->state
!= ISPSTAT_DISABLED
)
202 omap3isp_hist_dma_done(hist
->isp
);
205 static int hist_buf_dma(struct ispstat
*hist
)
207 dma_addr_t dma_addr
= hist
->active_buf
->dma_addr
;
209 if (unlikely(!dma_addr
)) {
210 dev_dbg(hist
->isp
->dev
, "hist: invalid DMA buffer address\n");
211 hist_reset_mem(hist
);
215 isp_reg_writel(hist
->isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
216 isp_reg_set(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
218 omap3isp_flush(hist
->isp
);
219 hist
->dma_config
.dst_start
= dma_addr
;
220 hist
->dma_config
.elem_count
= hist
->buf_size
/ sizeof(u32
);
221 omap_set_dma_params(hist
->dma_ch
, &hist
->dma_config
);
223 omap_start_dma(hist
->dma_ch
);
225 return STAT_BUF_WAITING_DMA
;
228 static int hist_buf_pio(struct ispstat
*hist
)
230 struct isp_device
*isp
= hist
->isp
;
231 u32
*buf
= hist
->active_buf
->virt_addr
;
235 dev_dbg(isp
->dev
, "hist: invalid PIO buffer address\n");
236 hist_reset_mem(hist
);
240 isp_reg_writel(isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
243 * By setting it, the histogram internal buffer is being cleared at the
244 * same time it's being read. This bit must be cleared just after all
247 isp_reg_set(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
250 * We'll read 4 times a 4-bytes-word at each iteration for
251 * optimization. It avoids 3/4 of the jumps. We also know buf_size is
254 for (i
= hist
->buf_size
/ 16; i
> 0; i
--) {
255 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
256 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
257 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
258 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
260 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
263 return STAT_BUF_DONE
;
267 * hist_buf_process - Callback from ISP driver for HIST interrupt.
269 static int hist_buf_process(struct ispstat
*hist
)
271 struct omap3isp_hist_config
*user_cfg
= hist
->priv
;
274 if (atomic_read(&hist
->buf_err
) || hist
->state
!= ISPSTAT_ENABLED
) {
275 hist_reset_mem(hist
);
279 if (--(hist
->wait_acc_frames
))
282 if (HIST_USING_DMA(hist
))
283 ret
= hist_buf_dma(hist
);
285 ret
= hist_buf_pio(hist
);
287 hist
->wait_acc_frames
= user_cfg
->num_acc_frames
;
292 static u32
hist_get_buf_size(struct omap3isp_hist_config
*conf
)
294 return OMAP3ISP_HIST_MEM_SIZE_BINS(conf
->hist_bins
) * conf
->num_regions
;
298 * hist_validate_params - Helper function to check user given params.
299 * @user_cfg: Pointer to user configuration structure.
301 * Returns 0 on success configuration.
303 static int hist_validate_params(struct ispstat
*hist
, void *new_conf
)
305 struct omap3isp_hist_config
*user_cfg
= new_conf
;
309 if (user_cfg
->cfa
> OMAP3ISP_HIST_CFA_FOVEONX3
)
312 /* Regions size and position */
314 if ((user_cfg
->num_regions
< OMAP3ISP_HIST_MIN_REGIONS
) ||
315 (user_cfg
->num_regions
> OMAP3ISP_HIST_MAX_REGIONS
))
319 for (c
= 0; c
< user_cfg
->num_regions
; c
++) {
320 if (user_cfg
->region
[c
].h_start
& ~ISPHIST_REG_START_END_MASK
)
322 if (user_cfg
->region
[c
].h_end
& ~ISPHIST_REG_START_END_MASK
)
324 if (user_cfg
->region
[c
].v_start
& ~ISPHIST_REG_START_END_MASK
)
326 if (user_cfg
->region
[c
].v_end
& ~ISPHIST_REG_START_END_MASK
)
328 if (user_cfg
->region
[c
].h_start
> user_cfg
->region
[c
].h_end
)
330 if (user_cfg
->region
[c
].v_start
> user_cfg
->region
[c
].v_end
)
334 switch (user_cfg
->num_regions
) {
336 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_256
)
340 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_128
)
343 default: /* 3 or 4 */
344 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_64
)
349 buf_size
= hist_get_buf_size(user_cfg
);
350 if (buf_size
> user_cfg
->buf_size
)
351 /* User's buf_size request wasn't enoght */
352 user_cfg
->buf_size
= buf_size
;
353 else if (user_cfg
->buf_size
> OMAP3ISP_HIST_MAX_BUF_SIZE
)
354 user_cfg
->buf_size
= OMAP3ISP_HIST_MAX_BUF_SIZE
;
359 static int hist_comp_params(struct ispstat
*hist
,
360 struct omap3isp_hist_config
*user_cfg
)
362 struct omap3isp_hist_config
*cur_cfg
= hist
->priv
;
365 if (cur_cfg
->cfa
!= user_cfg
->cfa
)
368 if (cur_cfg
->num_acc_frames
!= user_cfg
->num_acc_frames
)
371 if (cur_cfg
->hist_bins
!= user_cfg
->hist_bins
)
374 for (c
= 0; c
< OMAP3ISP_HIST_MAX_WG
; c
++) {
375 if (c
== 3 && user_cfg
->cfa
== OMAP3ISP_HIST_CFA_FOVEONX3
)
377 else if (cur_cfg
->wg
[c
] != user_cfg
->wg
[c
])
381 if (cur_cfg
->num_regions
!= user_cfg
->num_regions
)
385 for (c
= 0; c
< user_cfg
->num_regions
; c
++) {
386 if (cur_cfg
->region
[c
].h_start
!= user_cfg
->region
[c
].h_start
)
388 if (cur_cfg
->region
[c
].h_end
!= user_cfg
->region
[c
].h_end
)
390 if (cur_cfg
->region
[c
].v_start
!= user_cfg
->region
[c
].v_start
)
392 if (cur_cfg
->region
[c
].v_end
!= user_cfg
->region
[c
].v_end
)
400 * hist_update_params - Helper function to check and store user given params.
401 * @new_conf: Pointer to user configuration structure.
403 static void hist_set_params(struct ispstat
*hist
, void *new_conf
)
405 struct omap3isp_hist_config
*user_cfg
= new_conf
;
406 struct omap3isp_hist_config
*cur_cfg
= hist
->priv
;
408 if (!hist
->configured
|| hist_comp_params(hist
, user_cfg
)) {
409 memcpy(cur_cfg
, user_cfg
, sizeof(*user_cfg
));
410 if (user_cfg
->num_acc_frames
== 0)
411 user_cfg
->num_acc_frames
= 1;
415 * User might be asked for a bigger buffer than necessary for
416 * this configuration. In order to return the right amount of
417 * data during buffer request, let's calculate the size here
418 * instead of stick with user_cfg->buf_size.
420 cur_cfg
->buf_size
= hist_get_buf_size(cur_cfg
);
425 static long hist_ioctl(struct v4l2_subdev
*sd
, unsigned int cmd
, void *arg
)
427 struct ispstat
*stat
= v4l2_get_subdevdata(sd
);
430 case VIDIOC_OMAP3ISP_HIST_CFG
:
431 return omap3isp_stat_config(stat
, arg
);
432 case VIDIOC_OMAP3ISP_STAT_REQ
:
433 return omap3isp_stat_request_statistics(stat
, arg
);
434 case VIDIOC_OMAP3ISP_STAT_EN
: {
436 return omap3isp_stat_enable(stat
, !!*en
);
444 static const struct ispstat_ops hist_ops
= {
445 .validate_params
= hist_validate_params
,
446 .set_params
= hist_set_params
,
447 .setup_regs
= hist_setup_regs
,
448 .enable
= hist_enable
,
450 .buf_process
= hist_buf_process
,
453 static const struct v4l2_subdev_core_ops hist_subdev_core_ops
= {
455 .subscribe_event
= omap3isp_stat_subscribe_event
,
456 .unsubscribe_event
= omap3isp_stat_unsubscribe_event
,
459 static const struct v4l2_subdev_video_ops hist_subdev_video_ops
= {
460 .s_stream
= omap3isp_stat_s_stream
,
463 static const struct v4l2_subdev_ops hist_subdev_ops
= {
464 .core
= &hist_subdev_core_ops
,
465 .video
= &hist_subdev_video_ops
,
469 * omap3isp_hist_init - Module Initialization.
471 int omap3isp_hist_init(struct isp_device
*isp
)
473 struct ispstat
*hist
= &isp
->isp_hist
;
474 struct omap3isp_hist_config
*hist_cfg
;
477 hist_cfg
= kzalloc(sizeof(*hist_cfg
), GFP_KERNEL
);
478 if (hist_cfg
== NULL
)
481 memset(hist
, 0, sizeof(*hist
));
483 ret
= omap_request_dma(OMAP24XX_DMA_NO_DEVICE
, "DMA_ISP_HIST",
484 hist_dma_cb
, hist
, &hist
->dma_ch
);
487 dev_warn(isp
->dev
, "hist: DMA request channel failed. "
488 "Using PIO only.\n");
491 dev_dbg(isp
->dev
, "hist: DMA channel = %d\n", hist
->dma_ch
);
492 hist_dma_config(hist
);
493 omap_enable_dma_irq(hist
->dma_ch
, OMAP_DMA_BLOCK_IRQ
);
496 hist
->ops
= &hist_ops
;
497 hist
->priv
= hist_cfg
;
498 hist
->event_type
= V4L2_EVENT_OMAP3ISP_HIST
;
501 ret
= omap3isp_stat_init(hist
, "histogram", &hist_subdev_ops
);
504 if (HIST_USING_DMA(hist
))
505 omap_free_dma(hist
->dma_ch
);
512 * omap3isp_hist_cleanup - Module cleanup.
514 void omap3isp_hist_cleanup(struct isp_device
*isp
)
516 if (HIST_USING_DMA(&isp
->isp_hist
))
517 omap_free_dma(isp
->isp_hist
.dma_ch
);
518 kfree(isp
->isp_hist
.priv
);
519 omap3isp_stat_cleanup(&isp
->isp_hist
);