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 OMAP24XX_DMA_NO_DEVICE 0
39 #define HIST_CONFIG_DMA 1
41 #define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
44 * hist_reset_mem - clear Histogram memory before start stats engine.
46 static void hist_reset_mem(struct ispstat
*hist
)
48 struct isp_device
*isp
= hist
->isp
;
49 struct omap3isp_hist_config
*conf
= hist
->priv
;
52 isp_reg_writel(isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
55 * By setting it, the histogram internal buffer is being cleared at the
56 * same time it's being read. This bit must be cleared afterwards.
58 isp_reg_set(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
61 * We'll clear 4 words at each iteration for optimization. It avoids
62 * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
64 for (i
= OMAP3ISP_HIST_MEM_SIZE
/ 4; i
> 0; i
--) {
65 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
66 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
67 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
68 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
70 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
72 hist
->wait_acc_frames
= conf
->num_acc_frames
;
75 static void hist_dma_config(struct ispstat
*hist
)
77 struct isp_device
*isp
= hist
->isp
;
79 hist
->dma_config
.data_type
= OMAP_DMA_DATA_TYPE_S32
;
80 hist
->dma_config
.sync_mode
= OMAP_DMA_SYNC_ELEMENT
;
81 hist
->dma_config
.frame_count
= 1;
82 hist
->dma_config
.src_amode
= OMAP_DMA_AMODE_CONSTANT
;
83 hist
->dma_config
.src_start
= isp
->mmio_base_phys
[OMAP3_ISP_IOMEM_HIST
]
85 hist
->dma_config
.dst_amode
= OMAP_DMA_AMODE_POST_INC
;
86 hist
->dma_config
.src_or_dst_synch
= OMAP_DMA_SRC_SYNC
;
90 * hist_setup_regs - Helper function to update Histogram registers.
92 static void hist_setup_regs(struct ispstat
*hist
, void *priv
)
94 struct isp_device
*isp
= hist
->isp
;
95 struct omap3isp_hist_config
*conf
= priv
;
99 u32 reg_hor
[OMAP3ISP_HIST_MAX_REGIONS
];
100 u32 reg_ver
[OMAP3ISP_HIST_MAX_REGIONS
];
102 if (!hist
->update
|| hist
->state
== ISPSTAT_DISABLED
||
103 hist
->state
== ISPSTAT_DISABLING
)
106 cnt
= conf
->cfa
<< ISPHIST_CNT_CFA_SHIFT
;
108 wb_gain
= conf
->wg
[0] << ISPHIST_WB_GAIN_WG00_SHIFT
;
109 wb_gain
|= conf
->wg
[1] << ISPHIST_WB_GAIN_WG01_SHIFT
;
110 wb_gain
|= conf
->wg
[2] << ISPHIST_WB_GAIN_WG02_SHIFT
;
111 if (conf
->cfa
== OMAP3ISP_HIST_CFA_BAYER
)
112 wb_gain
|= conf
->wg
[3] << ISPHIST_WB_GAIN_WG03_SHIFT
;
114 /* Regions size and position */
115 for (c
= 0; c
< OMAP3ISP_HIST_MAX_REGIONS
; c
++) {
116 if (c
< conf
->num_regions
) {
117 reg_hor
[c
] = (conf
->region
[c
].h_start
<<
118 ISPHIST_REG_START_SHIFT
)
119 | (conf
->region
[c
].h_end
<<
120 ISPHIST_REG_END_SHIFT
);
121 reg_ver
[c
] = (conf
->region
[c
].v_start
<<
122 ISPHIST_REG_START_SHIFT
)
123 | (conf
->region
[c
].v_end
<<
124 ISPHIST_REG_END_SHIFT
);
131 cnt
|= conf
->hist_bins
<< ISPHIST_CNT_BINS_SHIFT
;
132 switch (conf
->hist_bins
) {
133 case OMAP3ISP_HIST_BINS_256
:
134 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 8) <<
135 ISPHIST_CNT_SHIFT_SHIFT
;
137 case OMAP3ISP_HIST_BINS_128
:
138 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 7) <<
139 ISPHIST_CNT_SHIFT_SHIFT
;
141 case OMAP3ISP_HIST_BINS_64
:
142 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 6) <<
143 ISPHIST_CNT_SHIFT_SHIFT
;
145 default: /* OMAP3ISP_HIST_BINS_32 */
146 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 5) <<
147 ISPHIST_CNT_SHIFT_SHIFT
;
151 hist_reset_mem(hist
);
153 isp_reg_writel(isp
, cnt
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
);
154 isp_reg_writel(isp
, wb_gain
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_WB_GAIN
);
155 isp_reg_writel(isp
, reg_hor
[0], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_HORZ
);
156 isp_reg_writel(isp
, reg_ver
[0], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_VERT
);
157 isp_reg_writel(isp
, reg_hor
[1], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_HORZ
);
158 isp_reg_writel(isp
, reg_ver
[1], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_VERT
);
159 isp_reg_writel(isp
, reg_hor
[2], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_HORZ
);
160 isp_reg_writel(isp
, reg_ver
[2], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_VERT
);
161 isp_reg_writel(isp
, reg_hor
[3], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_HORZ
);
162 isp_reg_writel(isp
, reg_ver
[3], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_VERT
);
165 hist
->config_counter
+= hist
->inc_config
;
166 hist
->inc_config
= 0;
167 hist
->buf_size
= conf
->buf_size
;
170 static void hist_enable(struct ispstat
*hist
, int enable
)
173 isp_reg_set(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
,
175 omap3isp_subclk_enable(hist
->isp
, OMAP3_ISP_SUBCLK_HIST
);
177 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
,
179 omap3isp_subclk_disable(hist
->isp
, OMAP3_ISP_SUBCLK_HIST
);
183 static int hist_busy(struct ispstat
*hist
)
185 return isp_reg_readl(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
)
189 static void hist_dma_cb(int lch
, u16 ch_status
, void *data
)
191 struct ispstat
*hist
= data
;
193 if (ch_status
& ~OMAP_DMA_BLOCK_IRQ
) {
194 dev_dbg(hist
->isp
->dev
, "hist: DMA error. status = 0x%04x\n",
197 hist_reset_mem(hist
);
198 atomic_set(&hist
->buf_err
, 1);
200 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
203 omap3isp_stat_dma_isr(hist
);
204 if (hist
->state
!= ISPSTAT_DISABLED
)
205 omap3isp_hist_dma_done(hist
->isp
);
208 static int hist_buf_dma(struct ispstat
*hist
)
210 dma_addr_t dma_addr
= hist
->active_buf
->dma_addr
;
212 if (unlikely(!dma_addr
)) {
213 dev_dbg(hist
->isp
->dev
, "hist: invalid DMA buffer address\n");
214 hist_reset_mem(hist
);
218 isp_reg_writel(hist
->isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
219 isp_reg_set(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
221 omap3isp_flush(hist
->isp
);
222 hist
->dma_config
.dst_start
= dma_addr
;
223 hist
->dma_config
.elem_count
= hist
->buf_size
/ sizeof(u32
);
224 omap_set_dma_params(hist
->dma_ch
, &hist
->dma_config
);
226 omap_start_dma(hist
->dma_ch
);
228 return STAT_BUF_WAITING_DMA
;
231 static int hist_buf_pio(struct ispstat
*hist
)
233 struct isp_device
*isp
= hist
->isp
;
234 u32
*buf
= hist
->active_buf
->virt_addr
;
238 dev_dbg(isp
->dev
, "hist: invalid PIO buffer address\n");
239 hist_reset_mem(hist
);
243 isp_reg_writel(isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
246 * By setting it, the histogram internal buffer is being cleared at the
247 * same time it's being read. This bit must be cleared just after all
250 isp_reg_set(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
253 * We'll read 4 times a 4-bytes-word at each iteration for
254 * optimization. It avoids 3/4 of the jumps. We also know buf_size is
257 for (i
= hist
->buf_size
/ 16; i
> 0; i
--) {
258 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
259 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
260 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
261 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
263 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
266 return STAT_BUF_DONE
;
270 * hist_buf_process - Callback from ISP driver for HIST interrupt.
272 static int hist_buf_process(struct ispstat
*hist
)
274 struct omap3isp_hist_config
*user_cfg
= hist
->priv
;
277 if (atomic_read(&hist
->buf_err
) || hist
->state
!= ISPSTAT_ENABLED
) {
278 hist_reset_mem(hist
);
282 if (--(hist
->wait_acc_frames
))
285 if (HIST_USING_DMA(hist
))
286 ret
= hist_buf_dma(hist
);
288 ret
= hist_buf_pio(hist
);
290 hist
->wait_acc_frames
= user_cfg
->num_acc_frames
;
295 static u32
hist_get_buf_size(struct omap3isp_hist_config
*conf
)
297 return OMAP3ISP_HIST_MEM_SIZE_BINS(conf
->hist_bins
) * conf
->num_regions
;
301 * hist_validate_params - Helper function to check user given params.
302 * @user_cfg: Pointer to user configuration structure.
304 * Returns 0 on success configuration.
306 static int hist_validate_params(struct ispstat
*hist
, void *new_conf
)
308 struct omap3isp_hist_config
*user_cfg
= new_conf
;
312 if (user_cfg
->cfa
> OMAP3ISP_HIST_CFA_FOVEONX3
)
315 /* Regions size and position */
317 if ((user_cfg
->num_regions
< OMAP3ISP_HIST_MIN_REGIONS
) ||
318 (user_cfg
->num_regions
> OMAP3ISP_HIST_MAX_REGIONS
))
322 for (c
= 0; c
< user_cfg
->num_regions
; c
++) {
323 if (user_cfg
->region
[c
].h_start
& ~ISPHIST_REG_START_END_MASK
)
325 if (user_cfg
->region
[c
].h_end
& ~ISPHIST_REG_START_END_MASK
)
327 if (user_cfg
->region
[c
].v_start
& ~ISPHIST_REG_START_END_MASK
)
329 if (user_cfg
->region
[c
].v_end
& ~ISPHIST_REG_START_END_MASK
)
331 if (user_cfg
->region
[c
].h_start
> user_cfg
->region
[c
].h_end
)
333 if (user_cfg
->region
[c
].v_start
> user_cfg
->region
[c
].v_end
)
337 switch (user_cfg
->num_regions
) {
339 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_256
)
343 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_128
)
346 default: /* 3 or 4 */
347 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_64
)
352 buf_size
= hist_get_buf_size(user_cfg
);
353 if (buf_size
> user_cfg
->buf_size
)
354 /* User's buf_size request wasn't enoght */
355 user_cfg
->buf_size
= buf_size
;
356 else if (user_cfg
->buf_size
> OMAP3ISP_HIST_MAX_BUF_SIZE
)
357 user_cfg
->buf_size
= OMAP3ISP_HIST_MAX_BUF_SIZE
;
362 static int hist_comp_params(struct ispstat
*hist
,
363 struct omap3isp_hist_config
*user_cfg
)
365 struct omap3isp_hist_config
*cur_cfg
= hist
->priv
;
368 if (cur_cfg
->cfa
!= user_cfg
->cfa
)
371 if (cur_cfg
->num_acc_frames
!= user_cfg
->num_acc_frames
)
374 if (cur_cfg
->hist_bins
!= user_cfg
->hist_bins
)
377 for (c
= 0; c
< OMAP3ISP_HIST_MAX_WG
; c
++) {
378 if (c
== 3 && user_cfg
->cfa
== OMAP3ISP_HIST_CFA_FOVEONX3
)
380 else if (cur_cfg
->wg
[c
] != user_cfg
->wg
[c
])
384 if (cur_cfg
->num_regions
!= user_cfg
->num_regions
)
388 for (c
= 0; c
< user_cfg
->num_regions
; c
++) {
389 if (cur_cfg
->region
[c
].h_start
!= user_cfg
->region
[c
].h_start
)
391 if (cur_cfg
->region
[c
].h_end
!= user_cfg
->region
[c
].h_end
)
393 if (cur_cfg
->region
[c
].v_start
!= user_cfg
->region
[c
].v_start
)
395 if (cur_cfg
->region
[c
].v_end
!= user_cfg
->region
[c
].v_end
)
403 * hist_update_params - Helper function to check and store user given params.
404 * @new_conf: Pointer to user configuration structure.
406 static void hist_set_params(struct ispstat
*hist
, void *new_conf
)
408 struct omap3isp_hist_config
*user_cfg
= new_conf
;
409 struct omap3isp_hist_config
*cur_cfg
= hist
->priv
;
411 if (!hist
->configured
|| hist_comp_params(hist
, user_cfg
)) {
412 memcpy(cur_cfg
, user_cfg
, sizeof(*user_cfg
));
413 if (user_cfg
->num_acc_frames
== 0)
414 user_cfg
->num_acc_frames
= 1;
418 * User might be asked for a bigger buffer than necessary for
419 * this configuration. In order to return the right amount of
420 * data during buffer request, let's calculate the size here
421 * instead of stick with user_cfg->buf_size.
423 cur_cfg
->buf_size
= hist_get_buf_size(cur_cfg
);
428 static long hist_ioctl(struct v4l2_subdev
*sd
, unsigned int cmd
, void *arg
)
430 struct ispstat
*stat
= v4l2_get_subdevdata(sd
);
433 case VIDIOC_OMAP3ISP_HIST_CFG
:
434 return omap3isp_stat_config(stat
, arg
);
435 case VIDIOC_OMAP3ISP_STAT_REQ
:
436 return omap3isp_stat_request_statistics(stat
, arg
);
437 case VIDIOC_OMAP3ISP_STAT_EN
: {
439 return omap3isp_stat_enable(stat
, !!*en
);
447 static const struct ispstat_ops hist_ops
= {
448 .validate_params
= hist_validate_params
,
449 .set_params
= hist_set_params
,
450 .setup_regs
= hist_setup_regs
,
451 .enable
= hist_enable
,
453 .buf_process
= hist_buf_process
,
456 static const struct v4l2_subdev_core_ops hist_subdev_core_ops
= {
458 .subscribe_event
= omap3isp_stat_subscribe_event
,
459 .unsubscribe_event
= omap3isp_stat_unsubscribe_event
,
462 static const struct v4l2_subdev_video_ops hist_subdev_video_ops
= {
463 .s_stream
= omap3isp_stat_s_stream
,
466 static const struct v4l2_subdev_ops hist_subdev_ops
= {
467 .core
= &hist_subdev_core_ops
,
468 .video
= &hist_subdev_video_ops
,
472 * omap3isp_hist_init - Module Initialization.
474 int omap3isp_hist_init(struct isp_device
*isp
)
476 struct ispstat
*hist
= &isp
->isp_hist
;
477 struct omap3isp_hist_config
*hist_cfg
;
480 hist_cfg
= devm_kzalloc(isp
->dev
, sizeof(*hist_cfg
), GFP_KERNEL
);
481 if (hist_cfg
== NULL
)
487 ret
= omap_request_dma(OMAP24XX_DMA_NO_DEVICE
, "DMA_ISP_HIST",
488 hist_dma_cb
, hist
, &hist
->dma_ch
);
491 dev_warn(isp
->dev
, "hist: DMA request channel failed. "
492 "Using PIO only.\n");
495 dev_dbg(isp
->dev
, "hist: DMA channel = %d\n", hist
->dma_ch
);
496 hist_dma_config(hist
);
497 omap_enable_dma_irq(hist
->dma_ch
, OMAP_DMA_BLOCK_IRQ
);
500 hist
->ops
= &hist_ops
;
501 hist
->priv
= hist_cfg
;
502 hist
->event_type
= V4L2_EVENT_OMAP3ISP_HIST
;
504 ret
= omap3isp_stat_init(hist
, "histogram", &hist_subdev_ops
);
506 if (HIST_USING_DMA(hist
))
507 omap_free_dma(hist
->dma_ch
);
514 * omap3isp_hist_cleanup - Module cleanup.
516 void omap3isp_hist_cleanup(struct isp_device
*isp
)
518 if (HIST_USING_DMA(&isp
->isp_hist
))
519 omap_free_dma(isp
->isp_hist
.dma_ch
);
520 omap3isp_stat_cleanup(&isp
->isp_hist
);