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.
18 #include <linux/delay.h>
19 #include <linux/device.h>
20 #include <linux/dmaengine.h>
21 #include <linux/omap-dmaengine.h>
22 #include <linux/slab.h>
23 #include <linux/uaccess.h>
29 #define HIST_CONFIG_DMA 1
32 * hist_reset_mem - clear Histogram memory before start stats engine.
34 static void hist_reset_mem(struct ispstat
*hist
)
36 struct isp_device
*isp
= hist
->isp
;
37 struct omap3isp_hist_config
*conf
= hist
->priv
;
40 isp_reg_writel(isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
43 * By setting it, the histogram internal buffer is being cleared at the
44 * same time it's being read. This bit must be cleared afterwards.
46 isp_reg_set(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
49 * We'll clear 4 words at each iteration for optimization. It avoids
50 * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
52 for (i
= OMAP3ISP_HIST_MEM_SIZE
/ 4; i
> 0; i
--) {
53 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
54 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
55 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
56 isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
58 isp_reg_clr(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
60 hist
->wait_acc_frames
= conf
->num_acc_frames
;
64 * hist_setup_regs - Helper function to update Histogram registers.
66 static void hist_setup_regs(struct ispstat
*hist
, void *priv
)
68 struct isp_device
*isp
= hist
->isp
;
69 struct omap3isp_hist_config
*conf
= priv
;
73 u32 reg_hor
[OMAP3ISP_HIST_MAX_REGIONS
];
74 u32 reg_ver
[OMAP3ISP_HIST_MAX_REGIONS
];
76 if (!hist
->update
|| hist
->state
== ISPSTAT_DISABLED
||
77 hist
->state
== ISPSTAT_DISABLING
)
80 cnt
= conf
->cfa
<< ISPHIST_CNT_CFA_SHIFT
;
82 wb_gain
= conf
->wg
[0] << ISPHIST_WB_GAIN_WG00_SHIFT
;
83 wb_gain
|= conf
->wg
[1] << ISPHIST_WB_GAIN_WG01_SHIFT
;
84 wb_gain
|= conf
->wg
[2] << ISPHIST_WB_GAIN_WG02_SHIFT
;
85 if (conf
->cfa
== OMAP3ISP_HIST_CFA_BAYER
)
86 wb_gain
|= conf
->wg
[3] << ISPHIST_WB_GAIN_WG03_SHIFT
;
88 /* Regions size and position */
89 for (c
= 0; c
< OMAP3ISP_HIST_MAX_REGIONS
; c
++) {
90 if (c
< conf
->num_regions
) {
91 reg_hor
[c
] = (conf
->region
[c
].h_start
<<
92 ISPHIST_REG_START_SHIFT
)
93 | (conf
->region
[c
].h_end
<<
94 ISPHIST_REG_END_SHIFT
);
95 reg_ver
[c
] = (conf
->region
[c
].v_start
<<
96 ISPHIST_REG_START_SHIFT
)
97 | (conf
->region
[c
].v_end
<<
98 ISPHIST_REG_END_SHIFT
);
105 cnt
|= conf
->hist_bins
<< ISPHIST_CNT_BINS_SHIFT
;
106 switch (conf
->hist_bins
) {
107 case OMAP3ISP_HIST_BINS_256
:
108 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 8) <<
109 ISPHIST_CNT_SHIFT_SHIFT
;
111 case OMAP3ISP_HIST_BINS_128
:
112 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 7) <<
113 ISPHIST_CNT_SHIFT_SHIFT
;
115 case OMAP3ISP_HIST_BINS_64
:
116 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 6) <<
117 ISPHIST_CNT_SHIFT_SHIFT
;
119 default: /* OMAP3ISP_HIST_BINS_32 */
120 cnt
|= (ISPHIST_IN_BIT_WIDTH_CCDC
- 5) <<
121 ISPHIST_CNT_SHIFT_SHIFT
;
125 hist_reset_mem(hist
);
127 isp_reg_writel(isp
, cnt
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
);
128 isp_reg_writel(isp
, wb_gain
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_WB_GAIN
);
129 isp_reg_writel(isp
, reg_hor
[0], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_HORZ
);
130 isp_reg_writel(isp
, reg_ver
[0], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_VERT
);
131 isp_reg_writel(isp
, reg_hor
[1], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_HORZ
);
132 isp_reg_writel(isp
, reg_ver
[1], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_VERT
);
133 isp_reg_writel(isp
, reg_hor
[2], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_HORZ
);
134 isp_reg_writel(isp
, reg_ver
[2], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_VERT
);
135 isp_reg_writel(isp
, reg_hor
[3], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_HORZ
);
136 isp_reg_writel(isp
, reg_ver
[3], OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_VERT
);
139 hist
->config_counter
+= hist
->inc_config
;
140 hist
->inc_config
= 0;
141 hist
->buf_size
= conf
->buf_size
;
144 static void hist_enable(struct ispstat
*hist
, int enable
)
147 isp_reg_set(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
,
149 omap3isp_subclk_enable(hist
->isp
, OMAP3_ISP_SUBCLK_HIST
);
151 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
,
153 omap3isp_subclk_disable(hist
->isp
, OMAP3_ISP_SUBCLK_HIST
);
157 static int hist_busy(struct ispstat
*hist
)
159 return isp_reg_readl(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
)
163 static void hist_dma_cb(void *data
)
165 struct ispstat
*hist
= data
;
167 /* FIXME: The DMA engine API can't report transfer errors :-/ */
169 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
172 omap3isp_stat_dma_isr(hist
);
173 if (hist
->state
!= ISPSTAT_DISABLED
)
174 omap3isp_hist_dma_done(hist
->isp
);
177 static int hist_buf_dma(struct ispstat
*hist
)
179 dma_addr_t dma_addr
= hist
->active_buf
->dma_addr
;
180 struct dma_async_tx_descriptor
*tx
;
181 struct dma_slave_config cfg
;
185 if (unlikely(!dma_addr
)) {
186 dev_dbg(hist
->isp
->dev
, "hist: invalid DMA buffer address\n");
190 isp_reg_writel(hist
->isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
191 isp_reg_set(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
193 omap3isp_flush(hist
->isp
);
195 memset(&cfg
, 0, sizeof(cfg
));
196 cfg
.src_addr
= hist
->isp
->mmio_hist_base_phys
+ ISPHIST_DATA
;
197 cfg
.src_addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
198 cfg
.src_maxburst
= hist
->buf_size
/ 4;
200 ret
= dmaengine_slave_config(hist
->dma_ch
, &cfg
);
202 dev_dbg(hist
->isp
->dev
,
203 "hist: DMA slave configuration failed\n");
207 tx
= dmaengine_prep_slave_single(hist
->dma_ch
, dma_addr
,
208 hist
->buf_size
, DMA_DEV_TO_MEM
,
211 dev_dbg(hist
->isp
->dev
,
212 "hist: DMA slave preparation failed\n");
216 tx
->callback
= hist_dma_cb
;
217 tx
->callback_param
= hist
;
218 cookie
= tx
->tx_submit(tx
);
219 if (dma_submit_error(cookie
)) {
220 dev_dbg(hist
->isp
->dev
, "hist: DMA submission failed\n");
224 dma_async_issue_pending(hist
->dma_ch
);
226 return STAT_BUF_WAITING_DMA
;
229 hist_reset_mem(hist
);
233 static int hist_buf_pio(struct ispstat
*hist
)
235 struct isp_device
*isp
= hist
->isp
;
236 u32
*buf
= hist
->active_buf
->virt_addr
;
240 dev_dbg(isp
->dev
, "hist: invalid PIO buffer address\n");
241 hist_reset_mem(hist
);
245 isp_reg_writel(isp
, 0, OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
248 * By setting it, the histogram internal buffer is being cleared at the
249 * same time it's being read. This bit must be cleared just after all
252 isp_reg_set(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, ISPHIST_CNT_CLEAR
);
255 * We'll read 4 times a 4-bytes-word at each iteration for
256 * optimization. It avoids 3/4 of the jumps. We also know buf_size is
259 for (i
= hist
->buf_size
/ 16; i
> 0; i
--) {
260 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
261 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
262 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
263 *buf
++ = isp_reg_readl(isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
265 isp_reg_clr(hist
->isp
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
268 return STAT_BUF_DONE
;
272 * hist_buf_process - Callback from ISP driver for HIST interrupt.
274 static int hist_buf_process(struct ispstat
*hist
)
276 struct omap3isp_hist_config
*user_cfg
= hist
->priv
;
279 if (atomic_read(&hist
->buf_err
) || hist
->state
!= ISPSTAT_ENABLED
) {
280 hist_reset_mem(hist
);
284 if (--(hist
->wait_acc_frames
))
288 ret
= hist_buf_dma(hist
);
290 ret
= hist_buf_pio(hist
);
292 hist
->wait_acc_frames
= user_cfg
->num_acc_frames
;
297 static u32
hist_get_buf_size(struct omap3isp_hist_config
*conf
)
299 return OMAP3ISP_HIST_MEM_SIZE_BINS(conf
->hist_bins
) * conf
->num_regions
;
303 * hist_validate_params - Helper function to check user given params.
304 * @new_conf: Pointer to user configuration structure.
306 * Returns 0 on success configuration.
308 static int hist_validate_params(struct ispstat
*hist
, void *new_conf
)
310 struct omap3isp_hist_config
*user_cfg
= new_conf
;
314 if (user_cfg
->cfa
> OMAP3ISP_HIST_CFA_FOVEONX3
)
317 /* Regions size and position */
319 if ((user_cfg
->num_regions
< OMAP3ISP_HIST_MIN_REGIONS
) ||
320 (user_cfg
->num_regions
> OMAP3ISP_HIST_MAX_REGIONS
))
324 for (c
= 0; c
< user_cfg
->num_regions
; c
++) {
325 if (user_cfg
->region
[c
].h_start
& ~ISPHIST_REG_START_END_MASK
)
327 if (user_cfg
->region
[c
].h_end
& ~ISPHIST_REG_START_END_MASK
)
329 if (user_cfg
->region
[c
].v_start
& ~ISPHIST_REG_START_END_MASK
)
331 if (user_cfg
->region
[c
].v_end
& ~ISPHIST_REG_START_END_MASK
)
333 if (user_cfg
->region
[c
].h_start
> user_cfg
->region
[c
].h_end
)
335 if (user_cfg
->region
[c
].v_start
> user_cfg
->region
[c
].v_end
)
339 switch (user_cfg
->num_regions
) {
341 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_256
)
345 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_128
)
348 default: /* 3 or 4 */
349 if (user_cfg
->hist_bins
> OMAP3ISP_HIST_BINS_64
)
354 buf_size
= hist_get_buf_size(user_cfg
);
355 if (buf_size
> user_cfg
->buf_size
)
356 /* User's buf_size request wasn't enough */
357 user_cfg
->buf_size
= buf_size
;
358 else if (user_cfg
->buf_size
> OMAP3ISP_HIST_MAX_BUF_SIZE
)
359 user_cfg
->buf_size
= OMAP3ISP_HIST_MAX_BUF_SIZE
;
364 static int hist_comp_params(struct ispstat
*hist
,
365 struct omap3isp_hist_config
*user_cfg
)
367 struct omap3isp_hist_config
*cur_cfg
= hist
->priv
;
370 if (cur_cfg
->cfa
!= user_cfg
->cfa
)
373 if (cur_cfg
->num_acc_frames
!= user_cfg
->num_acc_frames
)
376 if (cur_cfg
->hist_bins
!= user_cfg
->hist_bins
)
379 for (c
= 0; c
< OMAP3ISP_HIST_MAX_WG
; c
++) {
380 if (c
== 3 && user_cfg
->cfa
== OMAP3ISP_HIST_CFA_FOVEONX3
)
382 else if (cur_cfg
->wg
[c
] != user_cfg
->wg
[c
])
386 if (cur_cfg
->num_regions
!= user_cfg
->num_regions
)
390 for (c
= 0; c
< user_cfg
->num_regions
; c
++) {
391 if (cur_cfg
->region
[c
].h_start
!= user_cfg
->region
[c
].h_start
)
393 if (cur_cfg
->region
[c
].h_end
!= user_cfg
->region
[c
].h_end
)
395 if (cur_cfg
->region
[c
].v_start
!= user_cfg
->region
[c
].v_start
)
397 if (cur_cfg
->region
[c
].v_end
!= user_cfg
->region
[c
].v_end
)
405 * hist_update_params - Helper function to check and store user given params.
406 * @new_conf: Pointer to user configuration structure.
408 static void hist_set_params(struct ispstat
*hist
, void *new_conf
)
410 struct omap3isp_hist_config
*user_cfg
= new_conf
;
411 struct omap3isp_hist_config
*cur_cfg
= hist
->priv
;
413 if (!hist
->configured
|| hist_comp_params(hist
, user_cfg
)) {
414 memcpy(cur_cfg
, user_cfg
, sizeof(*user_cfg
));
415 if (user_cfg
->num_acc_frames
== 0)
416 user_cfg
->num_acc_frames
= 1;
420 * User might be asked for a bigger buffer than necessary for
421 * this configuration. In order to return the right amount of
422 * data during buffer request, let's calculate the size here
423 * instead of stick with user_cfg->buf_size.
425 cur_cfg
->buf_size
= hist_get_buf_size(cur_cfg
);
430 static long hist_ioctl(struct v4l2_subdev
*sd
, unsigned int cmd
, void *arg
)
432 struct ispstat
*stat
= v4l2_get_subdevdata(sd
);
435 case VIDIOC_OMAP3ISP_HIST_CFG
:
436 return omap3isp_stat_config(stat
, arg
);
437 case VIDIOC_OMAP3ISP_STAT_REQ
:
438 return omap3isp_stat_request_statistics(stat
, arg
);
439 case VIDIOC_OMAP3ISP_STAT_EN
: {
441 return omap3isp_stat_enable(stat
, !!*en
);
449 static const struct ispstat_ops hist_ops
= {
450 .validate_params
= hist_validate_params
,
451 .set_params
= hist_set_params
,
452 .setup_regs
= hist_setup_regs
,
453 .enable
= hist_enable
,
455 .buf_process
= hist_buf_process
,
458 static const struct v4l2_subdev_core_ops hist_subdev_core_ops
= {
460 .subscribe_event
= omap3isp_stat_subscribe_event
,
461 .unsubscribe_event
= omap3isp_stat_unsubscribe_event
,
464 static const struct v4l2_subdev_video_ops hist_subdev_video_ops
= {
465 .s_stream
= omap3isp_stat_s_stream
,
468 static const struct v4l2_subdev_ops hist_subdev_ops
= {
469 .core
= &hist_subdev_core_ops
,
470 .video
= &hist_subdev_video_ops
,
474 * omap3isp_hist_init - Module Initialization.
476 int omap3isp_hist_init(struct isp_device
*isp
)
478 struct ispstat
*hist
= &isp
->isp_hist
;
479 struct omap3isp_hist_config
*hist_cfg
;
482 hist_cfg
= devm_kzalloc(isp
->dev
, sizeof(*hist_cfg
), GFP_KERNEL
);
483 if (hist_cfg
== NULL
)
488 if (HIST_CONFIG_DMA
) {
489 struct platform_device
*pdev
= to_platform_device(isp
->dev
);
490 struct resource
*res
;
491 unsigned int sig
= 0;
495 dma_cap_set(DMA_SLAVE
, mask
);
497 res
= platform_get_resource_byname(pdev
, IORESOURCE_DMA
,
502 hist
->dma_ch
= dma_request_slave_channel_compat(mask
,
503 omap_dma_filter_fn
, &sig
, isp
->dev
, "hist");
506 "hist: DMA channel request failed, using PIO\n");
508 dev_dbg(isp
->dev
, "hist: using DMA channel %s\n",
509 dma_chan_name(hist
->dma_ch
));
512 hist
->ops
= &hist_ops
;
513 hist
->priv
= hist_cfg
;
514 hist
->event_type
= V4L2_EVENT_OMAP3ISP_HIST
;
516 ret
= omap3isp_stat_init(hist
, "histogram", &hist_subdev_ops
);
519 dma_release_channel(hist
->dma_ch
);
526 * omap3isp_hist_cleanup - Module cleanup.
528 void omap3isp_hist_cleanup(struct isp_device
*isp
)
530 struct ispstat
*hist
= &isp
->isp_hist
;
533 dma_release_channel(hist
->dma_ch
);
535 omap3isp_stat_cleanup(hist
);