diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch | 2741 |
1 files changed, 2741 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch new file mode 100644 index 0000000000..876ce780f0 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch | |||
@@ -0,0 +1,2741 @@ | |||
1 | From 9a39eab5ed1b70711c3b10de95cd90749293ef7a Mon Sep 17 00:00:00 2001 | ||
2 | From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
3 | Date: Tue, 10 Mar 2009 10:49:02 +0200 | ||
4 | Subject: [PATCH] omap3isp: Add statistics collection modules (H3A and HIST) | ||
5 | |||
6 | Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
7 | --- | ||
8 | drivers/media/video/isp/isp_af.c | 784 +++++++++++++++++++++++++++++++ | ||
9 | drivers/media/video/isp/isp_af.h | 125 +++++ | ||
10 | drivers/media/video/isp/isph3a.c | 932 +++++++++++++++++++++++++++++++++++++ | ||
11 | drivers/media/video/isp/isph3a.h | 127 +++++ | ||
12 | drivers/media/video/isp/isphist.c | 608 ++++++++++++++++++++++++ | ||
13 | drivers/media/video/isp/isphist.h | 105 +++++ | ||
14 | 6 files changed, 2681 insertions(+), 0 deletions(-) | ||
15 | create mode 100644 drivers/media/video/isp/isp_af.c | ||
16 | create mode 100644 drivers/media/video/isp/isp_af.h | ||
17 | create mode 100644 drivers/media/video/isp/isph3a.c | ||
18 | create mode 100644 drivers/media/video/isp/isph3a.h | ||
19 | create mode 100644 drivers/media/video/isp/isphist.c | ||
20 | create mode 100644 drivers/media/video/isp/isphist.h | ||
21 | |||
22 | diff --git a/drivers/media/video/isp/isp_af.c b/drivers/media/video/isp/isp_af.c | ||
23 | new file mode 100644 | ||
24 | index 0000000..a607b97 | ||
25 | --- /dev/null | ||
26 | +++ b/drivers/media/video/isp/isp_af.c | ||
27 | @@ -0,0 +1,784 @@ | ||
28 | +/* | ||
29 | + * isp_af.c | ||
30 | + * | ||
31 | + * AF module for TI's OMAP3 Camera ISP | ||
32 | + * | ||
33 | + * Copyright (C) 2009 Texas Instruments, Inc. | ||
34 | + * | ||
35 | + * Contributors: | ||
36 | + * Sergio Aguirre <saaguirre@ti.com> | ||
37 | + * Troy Laramy | ||
38 | + * | ||
39 | + * This package is free software; you can redistribute it and/or modify | ||
40 | + * it under the terms of the GNU General Public License version 2 as | ||
41 | + * published by the Free Software Foundation. | ||
42 | + * | ||
43 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
44 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
45 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
46 | + */ | ||
47 | + | ||
48 | +/* Linux specific include files */ | ||
49 | +#include <asm/cacheflush.h> | ||
50 | + | ||
51 | +#include <linux/uaccess.h> | ||
52 | +#include <linux/dma-mapping.h> | ||
53 | +#include <asm/atomic.h> | ||
54 | + | ||
55 | +#include "isp.h" | ||
56 | +#include "ispreg.h" | ||
57 | +#include "isph3a.h" | ||
58 | +#include "isp_af.h" | ||
59 | +#include "ispmmu.h" | ||
60 | + | ||
61 | +/** | ||
62 | + * struct isp_af_buffer - AF frame stats buffer. | ||
63 | + * @virt_addr: Virtual address to mmap the buffer. | ||
64 | + * @phy_addr: Physical address of the buffer. | ||
65 | + * @addr_align: Virtual Address 32 bytes aligned. | ||
66 | + * @ispmmu_addr: Address of the buffer mapped by the ISPMMU. | ||
67 | + * @mmap_addr: Mapped memory area of buffer. For userspace access. | ||
68 | + * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten. | ||
69 | + * @frame_num: Frame number from which the statistics are taken. | ||
70 | + * @lens_position: Lens position currently set in the DW9710 Coil motor driver. | ||
71 | + * @next: Pointer to link next buffer. | ||
72 | + */ | ||
73 | +struct isp_af_buffer { | ||
74 | + unsigned long virt_addr; | ||
75 | + unsigned long phy_addr; | ||
76 | + unsigned long addr_align; | ||
77 | + unsigned long ispmmu_addr; | ||
78 | + unsigned long mmap_addr; | ||
79 | + | ||
80 | + u8 locked; | ||
81 | + u16 frame_num; | ||
82 | + u32 config_counter; | ||
83 | + struct isp_af_xtrastats xtrastats; | ||
84 | + struct isp_af_buffer *next; | ||
85 | +}; | ||
86 | + | ||
87 | +/** | ||
88 | + * struct isp_af_status - AF status. | ||
89 | + * @initialized: 1 - Buffers initialized. | ||
90 | + * @update: 1 - Update registers. | ||
91 | + * @stats_req: 1 - Future stats requested. | ||
92 | + * @stats_done: 1 - Stats ready for user. | ||
93 | + * @frame_req: Number of frame requested for statistics. | ||
94 | + * @af_buff: Array of statistics buffers to access. | ||
95 | + * @stats_buf_size: Statistics buffer size. | ||
96 | + * @curr_cfg_buf_size: Current user configured stats buff size. | ||
97 | + * @min_buf_size: Minimum statisitics buffer size. | ||
98 | + * @frame_count: Frame Count. | ||
99 | + * @stats_wait: Wait primitive for locking/unlocking the stats request. | ||
100 | + * @buffer_lock: Spinlock for statistics buffers access. | ||
101 | + */ | ||
102 | +static struct isp_af_status { | ||
103 | + u8 initialized; | ||
104 | + u8 update; | ||
105 | + u8 stats_req; | ||
106 | + u8 stats_done; | ||
107 | + u16 frame_req; | ||
108 | + | ||
109 | + struct isp_af_buffer af_buff[H3A_MAX_BUFF]; | ||
110 | + unsigned int stats_buf_size; | ||
111 | + unsigned int min_buf_size; | ||
112 | + unsigned int curr_cfg_buf_size; | ||
113 | + | ||
114 | + int pm_state; | ||
115 | + u32 frame_count; | ||
116 | + wait_queue_head_t stats_wait; | ||
117 | + atomic_t config_counter; | ||
118 | + spinlock_t buffer_lock; /* For stats buffers read/write sync */ | ||
119 | +} afstat; | ||
120 | + | ||
121 | +struct af_device *af_dev_configptr; | ||
122 | +static struct isp_af_buffer *active_buff; | ||
123 | +static int af_major = -1; | ||
124 | +static int camnotify; | ||
125 | + | ||
126 | +/** | ||
127 | + * isp_af_setxtrastats - Receives extra statistics from prior frames. | ||
128 | + * @xtrastats: Pointer to structure containing extra statistics fields like | ||
129 | + * field count and timestamp of frame. | ||
130 | + * | ||
131 | + * Called from update_vbq in camera driver | ||
132 | + **/ | ||
133 | +void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag) | ||
134 | +{ | ||
135 | + int i, past_i; | ||
136 | + | ||
137 | + if (active_buff == NULL) | ||
138 | + return; | ||
139 | + | ||
140 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
141 | + if (afstat.af_buff[i].frame_num == active_buff->frame_num) | ||
142 | + break; | ||
143 | + } | ||
144 | + | ||
145 | + if (i == H3A_MAX_BUFF) | ||
146 | + return; | ||
147 | + | ||
148 | + if (i == 0) { | ||
149 | + if (afstat.af_buff[H3A_MAX_BUFF - 1].locked == 0) | ||
150 | + past_i = H3A_MAX_BUFF - 1; | ||
151 | + else | ||
152 | + past_i = H3A_MAX_BUFF - 2; | ||
153 | + } else if (i == 1) { | ||
154 | + if (afstat.af_buff[0].locked == 0) | ||
155 | + past_i = 0; | ||
156 | + else | ||
157 | + past_i = H3A_MAX_BUFF - 1; | ||
158 | + } else { | ||
159 | + if (afstat.af_buff[i - 1].locked == 0) | ||
160 | + past_i = i - 1; | ||
161 | + else | ||
162 | + past_i = i - 2; | ||
163 | + } | ||
164 | + | ||
165 | + if (updateflag & AF_UPDATEXS_TS) | ||
166 | + afstat.af_buff[past_i].xtrastats.ts = xtrastats->ts; | ||
167 | + | ||
168 | + if (updateflag & AF_UPDATEXS_FIELDCOUNT) | ||
169 | + afstat.af_buff[past_i].xtrastats.field_count = | ||
170 | + xtrastats->field_count; | ||
171 | +} | ||
172 | +EXPORT_SYMBOL(isp_af_setxtrastats); | ||
173 | + | ||
174 | +/* | ||
175 | + * Helper function to update buffer cache pages | ||
176 | + */ | ||
177 | +static void isp_af_update_req_buffer(struct isp_af_buffer *buffer) | ||
178 | +{ | ||
179 | + int size = afstat.stats_buf_size; | ||
180 | + | ||
181 | + size = PAGE_ALIGN(size); | ||
182 | + /* Update the kernel pages of the requested buffer */ | ||
183 | + dmac_inv_range((void *)buffer->addr_align, (void *)buffer->addr_align + | ||
184 | + size); | ||
185 | +} | ||
186 | + | ||
187 | +#define IS_OUT_OF_BOUNDS(value, min, max) \ | ||
188 | + (((value) < (min)) || ((value) > (max))) | ||
189 | + | ||
190 | +/* Function to check paxel parameters */ | ||
191 | +int isp_af_check_paxel(void) | ||
192 | +{ | ||
193 | + struct af_paxel *paxel_cfg = &af_dev_configptr->config->paxel_config; | ||
194 | + struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config; | ||
195 | + | ||
196 | + /* Check horizontal Count */ | ||
197 | + if (IS_OUT_OF_BOUNDS(paxel_cfg->hz_cnt, AF_PAXEL_HORIZONTAL_COUNT_MIN, | ||
198 | + AF_PAXEL_HORIZONTAL_COUNT_MAX)) { | ||
199 | + DPRINTK_ISP_AF("Error : Horizontal Count is incorrect"); | ||
200 | + return -AF_ERR_HZ_COUNT; | ||
201 | + } | ||
202 | + | ||
203 | + /*Check Vertical Count */ | ||
204 | + if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_cnt, AF_PAXEL_VERTICAL_COUNT_MIN, | ||
205 | + AF_PAXEL_VERTICAL_COUNT_MAX)) { | ||
206 | + DPRINTK_ISP_AF("Error : Vertical Count is incorrect"); | ||
207 | + return -AF_ERR_VT_COUNT; | ||
208 | + } | ||
209 | + | ||
210 | + /*Check Height */ | ||
211 | + if (IS_OUT_OF_BOUNDS(paxel_cfg->height, AF_PAXEL_HEIGHT_MIN, | ||
212 | + AF_PAXEL_HEIGHT_MAX)) { | ||
213 | + DPRINTK_ISP_AF("Error : Height is incorrect"); | ||
214 | + return -AF_ERR_HEIGHT; | ||
215 | + } | ||
216 | + | ||
217 | + /*Check width */ | ||
218 | + if (IS_OUT_OF_BOUNDS(paxel_cfg->width, AF_PAXEL_WIDTH_MIN, | ||
219 | + AF_PAXEL_WIDTH_MAX)) { | ||
220 | + DPRINTK_ISP_AF("Error : Width is incorrect"); | ||
221 | + return -AF_ERR_WIDTH; | ||
222 | + } | ||
223 | + | ||
224 | + /*Check Line Increment */ | ||
225 | + if (IS_OUT_OF_BOUNDS(paxel_cfg->line_incr, AF_PAXEL_INCREMENT_MIN, | ||
226 | + AF_PAXEL_INCREMENT_MAX)) { | ||
227 | + DPRINTK_ISP_AF("Error : Line Increment is incorrect"); | ||
228 | + return -AF_ERR_INCR; | ||
229 | + } | ||
230 | + | ||
231 | + /*Check Horizontal Start */ | ||
232 | + if ((paxel_cfg->hz_start % 2 != 0) || | ||
233 | + (paxel_cfg->hz_start < (iir_cfg->hz_start_pos + 2)) || | ||
234 | + IS_OUT_OF_BOUNDS(paxel_cfg->hz_start, | ||
235 | + AF_PAXEL_HZSTART_MIN, AF_PAXEL_HZSTART_MAX)) { | ||
236 | + DPRINTK_ISP_AF("Error : Horizontal Start is incorrect"); | ||
237 | + return -AF_ERR_HZ_START; | ||
238 | + } | ||
239 | + | ||
240 | + /*Check Vertical Start */ | ||
241 | + if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_start, AF_PAXEL_VTSTART_MIN, | ||
242 | + AF_PAXEL_VTSTART_MAX)) { | ||
243 | + DPRINTK_ISP_AF("Error : Vertical Start is incorrect"); | ||
244 | + return -AF_ERR_VT_START; | ||
245 | + } | ||
246 | + return 0; | ||
247 | +} | ||
248 | + | ||
249 | +/** | ||
250 | + * isp_af_check_iir - Function to check IIR Coefficient. | ||
251 | + **/ | ||
252 | +int isp_af_check_iir(void) | ||
253 | +{ | ||
254 | + struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config; | ||
255 | + int index; | ||
256 | + | ||
257 | + for (index = 0; index < AF_NUMBER_OF_COEF; index++) { | ||
258 | + if ((iir_cfg->coeff_set0[index]) > AF_COEF_MAX) { | ||
259 | + DPRINTK_ISP_AF("Error : Coefficient for set 0 is " | ||
260 | + "incorrect"); | ||
261 | + return -AF_ERR_IIR_COEF; | ||
262 | + } | ||
263 | + | ||
264 | + if ((iir_cfg->coeff_set1[index]) > AF_COEF_MAX) { | ||
265 | + DPRINTK_ISP_AF("Error : Coefficient for set 1 is " | ||
266 | + "incorrect"); | ||
267 | + return -AF_ERR_IIR_COEF; | ||
268 | + } | ||
269 | + } | ||
270 | + | ||
271 | + if (IS_OUT_OF_BOUNDS(iir_cfg->hz_start_pos, AF_IIRSH_MIN, | ||
272 | + AF_IIRSH_MAX)) { | ||
273 | + DPRINTK_ISP_AF("Error : IIRSH is incorrect"); | ||
274 | + return -AF_ERR_IIRSH; | ||
275 | + } | ||
276 | + | ||
277 | + return 0; | ||
278 | +} | ||
279 | +/** | ||
280 | + * isp_af_unlock_buffers - Helper function to unlock all buffers. | ||
281 | + **/ | ||
282 | +static void isp_af_unlock_buffers(void) | ||
283 | +{ | ||
284 | + int i; | ||
285 | + unsigned long irqflags; | ||
286 | + | ||
287 | + spin_lock_irqsave(&afstat.buffer_lock, irqflags); | ||
288 | + for (i = 0; i < H3A_MAX_BUFF; i++) | ||
289 | + afstat.af_buff[i].locked = 0; | ||
290 | + | ||
291 | + spin_unlock_irqrestore(&afstat.buffer_lock, irqflags); | ||
292 | +} | ||
293 | + | ||
294 | +/* | ||
295 | + * Helper function to link allocated buffers | ||
296 | + */ | ||
297 | +static void isp_af_link_buffers(void) | ||
298 | +{ | ||
299 | + int i; | ||
300 | + | ||
301 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
302 | + if ((i + 1) < H3A_MAX_BUFF) | ||
303 | + afstat.af_buff[i].next = &afstat.af_buff[i + 1]; | ||
304 | + else | ||
305 | + afstat.af_buff[i].next = &afstat.af_buff[0]; | ||
306 | + } | ||
307 | +} | ||
308 | + | ||
309 | +/* Function to perform hardware set up */ | ||
310 | +int isp_af_configure(struct af_configuration *afconfig) | ||
311 | +{ | ||
312 | + int result; | ||
313 | + int buff_size, i; | ||
314 | + unsigned int busyaf; | ||
315 | + struct af_configuration *af_curr_cfg = af_dev_configptr->config; | ||
316 | + | ||
317 | + if (NULL == afconfig) { | ||
318 | + printk(KERN_ERR "Null argument in configuration. \n"); | ||
319 | + return -EINVAL; | ||
320 | + } | ||
321 | + | ||
322 | + memcpy(af_curr_cfg, afconfig, sizeof(struct af_configuration)); | ||
323 | + /* Get the value of PCR register */ | ||
324 | + busyaf = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); | ||
325 | + | ||
326 | + if ((busyaf & AF_BUSYAF) == AF_BUSYAF) { | ||
327 | + DPRINTK_ISP_AF("AF_register_setup_ERROR : Engine Busy"); | ||
328 | + DPRINTK_ISP_AF("\n Configuration cannot be done "); | ||
329 | + return -AF_ERR_ENGINE_BUSY; | ||
330 | + } | ||
331 | + | ||
332 | + /* Check IIR Coefficient and start Values */ | ||
333 | + result = isp_af_check_iir(); | ||
334 | + if (result < 0) | ||
335 | + return result; | ||
336 | + | ||
337 | + /* Check Paxel Values */ | ||
338 | + result = isp_af_check_paxel(); | ||
339 | + if (result < 0) | ||
340 | + return result; | ||
341 | + | ||
342 | + /* Check HMF Threshold Values */ | ||
343 | + if (af_curr_cfg->hmf_config.threshold > AF_THRESHOLD_MAX) { | ||
344 | + DPRINTK_ISP_AF("Error : HMF Threshold is incorrect"); | ||
345 | + return -AF_ERR_THRESHOLD; | ||
346 | + } | ||
347 | + | ||
348 | + /* Compute buffer size */ | ||
349 | + buff_size = (af_curr_cfg->paxel_config.hz_cnt + 1) * | ||
350 | + (af_curr_cfg->paxel_config.vt_cnt + 1) * AF_PAXEL_SIZE; | ||
351 | + | ||
352 | + afstat.curr_cfg_buf_size = buff_size; | ||
353 | + /* Deallocate the previous buffers */ | ||
354 | + if (afstat.stats_buf_size && buff_size > afstat.stats_buf_size) { | ||
355 | + isp_af_enable(0); | ||
356 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
357 | + ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr); | ||
358 | + dma_free_coherent( | ||
359 | + NULL, afstat.min_buf_size, | ||
360 | + (void *)afstat.af_buff[i].virt_addr, | ||
361 | + (dma_addr_t)afstat.af_buff[i].phy_addr); | ||
362 | + afstat.af_buff[i].virt_addr = 0; | ||
363 | + } | ||
364 | + afstat.stats_buf_size = 0; | ||
365 | + } | ||
366 | + | ||
367 | + if (!afstat.af_buff[0].virt_addr) { | ||
368 | + afstat.stats_buf_size = buff_size; | ||
369 | + afstat.min_buf_size = PAGE_ALIGN(afstat.stats_buf_size); | ||
370 | + | ||
371 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
372 | + afstat.af_buff[i].virt_addr = | ||
373 | + (unsigned long)dma_alloc_coherent( | ||
374 | + NULL, | ||
375 | + afstat.min_buf_size, | ||
376 | + (dma_addr_t *) | ||
377 | + &afstat.af_buff[i].phy_addr, | ||
378 | + GFP_KERNEL | GFP_DMA); | ||
379 | + if (afstat.af_buff[i].virt_addr == 0) { | ||
380 | + printk(KERN_ERR "Can't acquire memory for " | ||
381 | + "buffer[%d]\n", i); | ||
382 | + return -ENOMEM; | ||
383 | + } | ||
384 | + afstat.af_buff[i].addr_align = | ||
385 | + afstat.af_buff[i].virt_addr; | ||
386 | + while ((afstat.af_buff[i].addr_align & 0xFFFFFFC0) != | ||
387 | + afstat.af_buff[i].addr_align) | ||
388 | + afstat.af_buff[i].addr_align++; | ||
389 | + afstat.af_buff[i].ispmmu_addr = | ||
390 | + ispmmu_kmap(afstat.af_buff[i].phy_addr, | ||
391 | + afstat.min_buf_size); | ||
392 | + } | ||
393 | + isp_af_unlock_buffers(); | ||
394 | + isp_af_link_buffers(); | ||
395 | + | ||
396 | + /* First active buffer */ | ||
397 | + if (active_buff == NULL) | ||
398 | + active_buff = &afstat.af_buff[0]; | ||
399 | + isp_af_set_address(active_buff->ispmmu_addr); | ||
400 | + } | ||
401 | + | ||
402 | + result = isp_af_register_setup(af_dev_configptr); | ||
403 | + if (result < 0) | ||
404 | + return result; | ||
405 | + af_dev_configptr->size_paxel = buff_size; | ||
406 | + atomic_inc(&afstat.config_counter); | ||
407 | + afstat.initialized = 1; | ||
408 | + afstat.frame_count = 1; | ||
409 | + active_buff->frame_num = 1; | ||
410 | + /* Set configuration flag to indicate HW setup done */ | ||
411 | + if (af_curr_cfg->af_config) | ||
412 | + isp_af_enable(1); | ||
413 | + else | ||
414 | + isp_af_enable(0); | ||
415 | + | ||
416 | + /* Success */ | ||
417 | + return 0; | ||
418 | +} | ||
419 | +EXPORT_SYMBOL(isp_af_configure); | ||
420 | + | ||
421 | +int isp_af_register_setup(struct af_device *af_dev) | ||
422 | +{ | ||
423 | + unsigned int pcr = 0, pax1 = 0, pax2 = 0, paxstart = 0; | ||
424 | + unsigned int coef = 0; | ||
425 | + unsigned int base_coef_set0 = 0; | ||
426 | + unsigned int base_coef_set1 = 0; | ||
427 | + int index; | ||
428 | + | ||
429 | + /* Configure Hardware Registers */ | ||
430 | + /* Read PCR Register */ | ||
431 | + pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); | ||
432 | + | ||
433 | + /* Set Accumulator Mode */ | ||
434 | + if (af_dev->config->mode == ACCUMULATOR_PEAK) | ||
435 | + pcr |= FVMODE; | ||
436 | + else | ||
437 | + pcr &= ~FVMODE; | ||
438 | + | ||
439 | + /* Set A-law */ | ||
440 | + if (af_dev->config->alaw_enable == H3A_AF_ALAW_ENABLE) | ||
441 | + pcr |= AF_ALAW_EN; | ||
442 | + else | ||
443 | + pcr &= ~AF_ALAW_EN; | ||
444 | + | ||
445 | + /* Set RGB Position */ | ||
446 | + pcr &= ~RGBPOS; | ||
447 | + pcr |= af_dev->config->rgb_pos << AF_RGBPOS_SHIFT; | ||
448 | + | ||
449 | + /* HMF Configurations */ | ||
450 | + if (af_dev->config->hmf_config.enable == H3A_AF_HMF_ENABLE) { | ||
451 | + pcr &= ~AF_MED_EN; | ||
452 | + /* Enable HMF */ | ||
453 | + pcr |= AF_MED_EN; | ||
454 | + | ||
455 | + /* Set Median Threshold */ | ||
456 | + pcr &= ~MED_TH; | ||
457 | + pcr |= af_dev->config->hmf_config.threshold << AF_MED_TH_SHIFT; | ||
458 | + } else | ||
459 | + pcr &= ~AF_MED_EN; | ||
460 | + | ||
461 | + /* Set PCR Register */ | ||
462 | + isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); | ||
463 | + | ||
464 | + pax1 &= ~PAXW; | ||
465 | + pax1 |= af_dev->config->paxel_config.width << AF_PAXW_SHIFT; | ||
466 | + | ||
467 | + /* Set height in AFPAX1 */ | ||
468 | + pax1 &= ~PAXH; | ||
469 | + pax1 |= af_dev->config->paxel_config.height; | ||
470 | + | ||
471 | + isp_reg_writel(pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1); | ||
472 | + | ||
473 | + /* Configure AFPAX2 Register */ | ||
474 | + /* Set Line Increment in AFPAX2 Register */ | ||
475 | + pax2 &= ~AFINCV; | ||
476 | + pax2 |= af_dev->config->paxel_config.line_incr << AF_LINE_INCR_SHIFT; | ||
477 | + /* Set Vertical Count */ | ||
478 | + pax2 &= ~PAXVC; | ||
479 | + pax2 |= af_dev->config->paxel_config.vt_cnt << AF_VT_COUNT_SHIFT; | ||
480 | + /* Set Horizontal Count */ | ||
481 | + pax2 &= ~PAXHC; | ||
482 | + pax2 |= af_dev->config->paxel_config.hz_cnt; | ||
483 | + isp_reg_writel(pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2); | ||
484 | + | ||
485 | + /* Configure PAXSTART Register */ | ||
486 | + /*Configure Horizontal Start */ | ||
487 | + paxstart &= ~PAXSH; | ||
488 | + paxstart |= af_dev->config->paxel_config.hz_start << AF_HZ_START_SHIFT; | ||
489 | + /* Configure Vertical Start */ | ||
490 | + paxstart &= ~PAXSV; | ||
491 | + paxstart |= af_dev->config->paxel_config.vt_start; | ||
492 | + isp_reg_writel(paxstart, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART); | ||
493 | + | ||
494 | + /*SetIIRSH Register */ | ||
495 | + isp_reg_writel(af_dev->config->iir_config.hz_start_pos, | ||
496 | + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH); | ||
497 | + | ||
498 | + /*Set IIR Filter0 Coefficients */ | ||
499 | + base_coef_set0 = ISPH3A_AFCOEF010; | ||
500 | + for (index = 0; index <= 8; index += 2) { | ||
501 | + coef &= ~COEF_MASK0; | ||
502 | + coef |= af_dev->config->iir_config.coeff_set0[index]; | ||
503 | + coef &= ~COEF_MASK1; | ||
504 | + coef |= af_dev->config->iir_config.coeff_set0[index + 1] << | ||
505 | + AF_COEF_SHIFT; | ||
506 | + isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set0); | ||
507 | + base_coef_set0 = base_coef_set0 + AFCOEF_OFFSET; | ||
508 | + } | ||
509 | + | ||
510 | + /* set AFCOEF0010 Register */ | ||
511 | + isp_reg_writel(af_dev->config->iir_config.coeff_set0[10], | ||
512 | + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010); | ||
513 | + | ||
514 | + /*Set IIR Filter1 Coefficients */ | ||
515 | + | ||
516 | + base_coef_set1 = ISPH3A_AFCOEF110; | ||
517 | + for (index = 0; index <= 8; index += 2) { | ||
518 | + coef &= ~COEF_MASK0; | ||
519 | + coef |= af_dev->config->iir_config.coeff_set1[index]; | ||
520 | + coef &= ~COEF_MASK1; | ||
521 | + coef |= af_dev->config->iir_config.coeff_set1[index + 1] << | ||
522 | + AF_COEF_SHIFT; | ||
523 | + isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set1); | ||
524 | + | ||
525 | + base_coef_set1 = base_coef_set1 + AFCOEF_OFFSET; | ||
526 | + } | ||
527 | + isp_reg_writel(af_dev->config->iir_config.coeff_set1[10], | ||
528 | + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010); | ||
529 | + | ||
530 | + return 0; | ||
531 | +} | ||
532 | + | ||
533 | +/* Function to set address */ | ||
534 | +void isp_af_set_address(unsigned long address) | ||
535 | +{ | ||
536 | + isp_reg_writel(address, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST); | ||
537 | +} | ||
538 | + | ||
539 | +static int isp_af_stats_available(struct isp_af_data *afdata) | ||
540 | +{ | ||
541 | + int i, ret; | ||
542 | + unsigned long irqflags; | ||
543 | + | ||
544 | + spin_lock_irqsave(&afstat.buffer_lock, irqflags); | ||
545 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
546 | + DPRINTK_ISP_AF("Checking Stats buff[%d] (%d) for %d\n", | ||
547 | + i, afstat.af_buff[i].frame_num, | ||
548 | + afdata->frame_number); | ||
549 | + if (afdata->frame_number == afstat.af_buff[i].frame_num | ||
550 | + && afstat.af_buff[i].frame_num != active_buff->frame_num) { | ||
551 | + afstat.af_buff[i].locked = 1; | ||
552 | + spin_unlock_irqrestore(&afstat.buffer_lock, irqflags); | ||
553 | + isp_af_update_req_buffer(&afstat.af_buff[i]); | ||
554 | + afstat.af_buff[i].frame_num = 0; | ||
555 | + ret = copy_to_user((void *)afdata->af_statistics_buf, | ||
556 | + (void *)afstat.af_buff[i].virt_addr, | ||
557 | + afstat.curr_cfg_buf_size); | ||
558 | + if (ret) { | ||
559 | + printk(KERN_ERR "Failed copy_to_user for " | ||
560 | + "H3A stats buff, %d\n", ret); | ||
561 | + } | ||
562 | + afdata->xtrastats.ts = afstat.af_buff[i].xtrastats.ts; | ||
563 | + afdata->xtrastats.field_count = | ||
564 | + afstat.af_buff[i].xtrastats.field_count; | ||
565 | + return 0; | ||
566 | + } | ||
567 | + } | ||
568 | + spin_unlock_irqrestore(&afstat.buffer_lock, irqflags); | ||
569 | + /* Stats unavailable */ | ||
570 | + | ||
571 | + return -1; | ||
572 | +} | ||
573 | + | ||
574 | +void isp_af_notify(int notify) | ||
575 | +{ | ||
576 | + camnotify = notify; | ||
577 | + if (camnotify && afstat.initialized) { | ||
578 | + printk(KERN_DEBUG "Warning Camera Off \n"); | ||
579 | + afstat.stats_req = 0; | ||
580 | + afstat.stats_done = 1; | ||
581 | + wake_up_interruptible(&afstat.stats_wait); | ||
582 | + } | ||
583 | +} | ||
584 | +EXPORT_SYMBOL(isp_af_notify); | ||
585 | +/* | ||
586 | + * This API allows the user to update White Balance gains, as well as | ||
587 | + * exposure time and analog gain. It is also used to request frame | ||
588 | + * statistics. | ||
589 | + */ | ||
590 | +int isp_af_request_statistics(struct isp_af_data *afdata) | ||
591 | +{ | ||
592 | + int ret = 0; | ||
593 | + u16 frame_diff = 0; | ||
594 | + u16 frame_cnt = afstat.frame_count; | ||
595 | + wait_queue_t wqt; | ||
596 | + | ||
597 | + if (!af_dev_configptr->config->af_config) { | ||
598 | + printk(KERN_ERR "AF engine not enabled\n"); | ||
599 | + return -EINVAL; | ||
600 | + } | ||
601 | + | ||
602 | + if (!(afdata->update & REQUEST_STATISTICS)) { | ||
603 | + afdata->af_statistics_buf = NULL; | ||
604 | + goto out; | ||
605 | + } | ||
606 | + | ||
607 | + isp_af_unlock_buffers(); | ||
608 | + /* Stats available? */ | ||
609 | + DPRINTK_ISP_AF("Stats available?\n"); | ||
610 | + ret = isp_af_stats_available(afdata); | ||
611 | + if (!ret) | ||
612 | + goto out; | ||
613 | + | ||
614 | + /* Stats in near future? */ | ||
615 | + DPRINTK_ISP_AF("Stats in near future?\n"); | ||
616 | + if (afdata->frame_number > frame_cnt) | ||
617 | + frame_diff = afdata->frame_number - frame_cnt; | ||
618 | + else if (afdata->frame_number < frame_cnt) { | ||
619 | + if (frame_cnt > MAX_FRAME_COUNT - MAX_FUTURE_FRAMES | ||
620 | + && afdata->frame_number < MAX_FRAME_COUNT) { | ||
621 | + frame_diff = afdata->frame_number + MAX_FRAME_COUNT - | ||
622 | + frame_cnt; | ||
623 | + } else { | ||
624 | + /* Frame unavailable */ | ||
625 | + frame_diff = MAX_FUTURE_FRAMES + 1; | ||
626 | + } | ||
627 | + } | ||
628 | + | ||
629 | + if (frame_diff > MAX_FUTURE_FRAMES) { | ||
630 | + printk(KERN_ERR "Invalid frame requested, returning current" | ||
631 | + " frame stats\n"); | ||
632 | + afdata->frame_number = frame_cnt; | ||
633 | + } | ||
634 | + if (!camnotify) { | ||
635 | + /* Block until frame in near future completes */ | ||
636 | + afstat.frame_req = afdata->frame_number; | ||
637 | + afstat.stats_req = 1; | ||
638 | + afstat.stats_done = 0; | ||
639 | + init_waitqueue_entry(&wqt, current); | ||
640 | + ret = wait_event_interruptible(afstat.stats_wait, | ||
641 | + afstat.stats_done == 1); | ||
642 | + if (ret < 0) { | ||
643 | + afdata->af_statistics_buf = NULL; | ||
644 | + return ret; | ||
645 | + } | ||
646 | + DPRINTK_ISP_AF("ISP AF request status interrupt raised\n"); | ||
647 | + | ||
648 | + /* Stats now available */ | ||
649 | + ret = isp_af_stats_available(afdata); | ||
650 | + if (ret) { | ||
651 | + printk(KERN_ERR "After waiting for stats, stats not" | ||
652 | + " available!!\n"); | ||
653 | + afdata->af_statistics_buf = NULL; | ||
654 | + } | ||
655 | + } | ||
656 | + | ||
657 | +out: | ||
658 | + afdata->curr_frame = afstat.frame_count; | ||
659 | + | ||
660 | + return 0; | ||
661 | +} | ||
662 | +EXPORT_SYMBOL(isp_af_request_statistics); | ||
663 | + | ||
664 | +/* This function will handle the H3A interrupt. */ | ||
665 | +static void isp_af_isr(unsigned long status, isp_vbq_callback_ptr arg1, | ||
666 | + void *arg2) | ||
667 | +{ | ||
668 | + u16 frame_align; | ||
669 | + | ||
670 | + if ((H3A_AF_DONE & status) != H3A_AF_DONE) | ||
671 | + return; | ||
672 | + | ||
673 | + /* timestamp stats buffer */ | ||
674 | + do_gettimeofday(&active_buff->xtrastats.ts); | ||
675 | + active_buff->config_counter = atomic_read(&afstat.config_counter); | ||
676 | + | ||
677 | + /* Exchange buffers */ | ||
678 | + active_buff = active_buff->next; | ||
679 | + if (active_buff->locked == 1) | ||
680 | + active_buff = active_buff->next; | ||
681 | + isp_af_set_address(active_buff->ispmmu_addr); | ||
682 | + | ||
683 | + /* Update frame counter */ | ||
684 | + afstat.frame_count++; | ||
685 | + frame_align = afstat.frame_count; | ||
686 | + if (afstat.frame_count > MAX_FRAME_COUNT) { | ||
687 | + afstat.frame_count = 1; | ||
688 | + frame_align++; | ||
689 | + } | ||
690 | + active_buff->frame_num = afstat.frame_count; | ||
691 | + | ||
692 | + /* Future Stats requested? */ | ||
693 | + if (afstat.stats_req) { | ||
694 | + /* Is the frame we want already done? */ | ||
695 | + if (frame_align >= afstat.frame_req + 1) { | ||
696 | + afstat.stats_req = 0; | ||
697 | + afstat.stats_done = 1; | ||
698 | + wake_up_interruptible(&afstat.stats_wait); | ||
699 | + } | ||
700 | + } | ||
701 | +} | ||
702 | + | ||
703 | +int __isp_af_enable(int enable) | ||
704 | +{ | ||
705 | + unsigned int pcr; | ||
706 | + | ||
707 | + pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); | ||
708 | + | ||
709 | + /* Set AF_EN bit in PCR Register */ | ||
710 | + if (enable) { | ||
711 | + if (isp_set_callback(CBK_H3A_AF_DONE, isp_af_isr, | ||
712 | + (void *)NULL, (void *)NULL)) { | ||
713 | + printk(KERN_ERR "No callback for AF\n"); | ||
714 | + return -EINVAL; | ||
715 | + } | ||
716 | + | ||
717 | + pcr |= AF_EN; | ||
718 | + } else { | ||
719 | + isp_unset_callback(CBK_H3A_AF_DONE); | ||
720 | + pcr &= ~AF_EN; | ||
721 | + } | ||
722 | + isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); | ||
723 | + return 0; | ||
724 | +} | ||
725 | + | ||
726 | +/* Function to Enable/Disable AF Engine */ | ||
727 | +int isp_af_enable(int enable) | ||
728 | +{ | ||
729 | + int rval; | ||
730 | + | ||
731 | + rval = __isp_af_enable(enable); | ||
732 | + | ||
733 | + if (!rval) | ||
734 | + afstat.pm_state = enable; | ||
735 | + | ||
736 | + return rval; | ||
737 | +} | ||
738 | + | ||
739 | +/* Function to Suspend AF Engine */ | ||
740 | +void isp_af_suspend(void) | ||
741 | +{ | ||
742 | + if (afstat.pm_state) | ||
743 | + __isp_af_enable(0); | ||
744 | +} | ||
745 | + | ||
746 | +/* Function to Resume AF Engine */ | ||
747 | +void isp_af_resume(void) | ||
748 | +{ | ||
749 | + if (afstat.pm_state) | ||
750 | + __isp_af_enable(1); | ||
751 | +} | ||
752 | + | ||
753 | +int isp_af_busy(void) | ||
754 | +{ | ||
755 | + return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) | ||
756 | + & ISPH3A_PCR_BUSYAF; | ||
757 | +} | ||
758 | + | ||
759 | +/* Function to register the AF character device driver. */ | ||
760 | +int __init isp_af_init(void) | ||
761 | +{ | ||
762 | + /*allocate memory for device structure and initialize it with 0 */ | ||
763 | + af_dev_configptr = kzalloc(sizeof(struct af_device), GFP_KERNEL); | ||
764 | + if (!af_dev_configptr) | ||
765 | + goto err_nomem1; | ||
766 | + | ||
767 | + active_buff = NULL; | ||
768 | + | ||
769 | + af_dev_configptr->config = (struct af_configuration *) | ||
770 | + kzalloc(sizeof(struct af_configuration), GFP_KERNEL); | ||
771 | + | ||
772 | + if (af_dev_configptr->config == NULL) | ||
773 | + goto err_nomem2; | ||
774 | + | ||
775 | + memset(&afstat, 0, sizeof(afstat)); | ||
776 | + | ||
777 | + init_waitqueue_head(&afstat.stats_wait); | ||
778 | + spin_lock_init(&afstat.buffer_lock); | ||
779 | + | ||
780 | + return 0; | ||
781 | + | ||
782 | +err_nomem2: | ||
783 | + kfree(af_dev_configptr); | ||
784 | +err_nomem1: | ||
785 | + printk(KERN_ERR "Error: kmalloc fail"); | ||
786 | + return -ENOMEM; | ||
787 | +} | ||
788 | + | ||
789 | +void isp_af_exit(void) | ||
790 | +{ | ||
791 | + int i; | ||
792 | + | ||
793 | + /* Free buffers */ | ||
794 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
795 | + if (!afstat.af_buff[i].phy_addr) | ||
796 | + continue; | ||
797 | + | ||
798 | + ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr); | ||
799 | + | ||
800 | + dma_free_coherent(NULL, | ||
801 | + afstat.min_buf_size, | ||
802 | + (void *)afstat.af_buff[i].virt_addr, | ||
803 | + (dma_addr_t)afstat.af_buff[i].phy_addr); | ||
804 | + } | ||
805 | + kfree(af_dev_configptr->config); | ||
806 | + kfree(af_dev_configptr); | ||
807 | + | ||
808 | + memset(&afstat, 0, sizeof(afstat)); | ||
809 | + | ||
810 | + af_major = -1; | ||
811 | +} | ||
812 | diff --git a/drivers/media/video/isp/isp_af.h b/drivers/media/video/isp/isp_af.h | ||
813 | new file mode 100644 | ||
814 | index 0000000..ee2b89f | ||
815 | --- /dev/null | ||
816 | +++ b/drivers/media/video/isp/isp_af.h | ||
817 | @@ -0,0 +1,125 @@ | ||
818 | +/* | ||
819 | + * isp_af.h | ||
820 | + * | ||
821 | + * Include file for AF module in TI's OMAP3 Camera ISP | ||
822 | + * | ||
823 | + * Copyright (C) 2009 Texas Instruments, Inc. | ||
824 | + * | ||
825 | + * Contributors: | ||
826 | + * Sergio Aguirre <saaguirre@ti.com> | ||
827 | + * Troy Laramy | ||
828 | + * | ||
829 | + * This package is free software; you can redistribute it and/or modify | ||
830 | + * it under the terms of the GNU General Public License version 2 as | ||
831 | + * published by the Free Software Foundation. | ||
832 | + * | ||
833 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
834 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
835 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
836 | + */ | ||
837 | + | ||
838 | +/* Device Constants */ | ||
839 | +#ifndef OMAP_ISP_AF_H | ||
840 | +#define OMAP_ISP_AF_H | ||
841 | + | ||
842 | +#include <mach/isp_user.h> | ||
843 | + | ||
844 | +#define AF_MAJOR_NUMBER 0 | ||
845 | +#define ISPAF_NAME "OMAPISP_AF" | ||
846 | +#define AF_NR_DEVS 1 | ||
847 | +#define AF_TIMEOUT ((300 * HZ) / 1000) | ||
848 | + | ||
849 | + | ||
850 | + | ||
851 | +/* Print Macros */ | ||
852 | +/*list of error code */ | ||
853 | +#define AF_ERR_HZ_COUNT 800 /* Invalid Horizontal Count */ | ||
854 | +#define AF_ERR_VT_COUNT 801 /* Invalid Vertical Count */ | ||
855 | +#define AF_ERR_HEIGHT 802 /* Invalid Height */ | ||
856 | +#define AF_ERR_WIDTH 803 /* Invalid width */ | ||
857 | +#define AF_ERR_INCR 804 /* Invalid Increment */ | ||
858 | +#define AF_ERR_HZ_START 805 /* Invalid horizontal Start */ | ||
859 | +#define AF_ERR_VT_START 806 /* Invalud vertical Start */ | ||
860 | +#define AF_ERR_IIRSH 807 /* Invalid IIRSH value */ | ||
861 | +#define AF_ERR_IIR_COEF 808 /* Invalid Coefficient */ | ||
862 | +#define AF_ERR_SETUP 809 /* Setup not done */ | ||
863 | +#define AF_ERR_THRESHOLD 810 /* Invalid Threshold */ | ||
864 | +#define AF_ERR_ENGINE_BUSY 811 /* Engine is busy */ | ||
865 | + | ||
866 | +#define AFPID 0x0 /* Peripheral Revision | ||
867 | + * and Class Information | ||
868 | + */ | ||
869 | + | ||
870 | +#define AFCOEF_OFFSET 0x00000004 /* COEFFICIENT BASE | ||
871 | + * ADDRESS | ||
872 | + */ | ||
873 | + | ||
874 | +/* | ||
875 | + * PCR fields | ||
876 | + */ | ||
877 | +#define AF_BUSYAF (1 << 15) | ||
878 | +#define FVMODE (1 << 14) | ||
879 | +#define RGBPOS (0x7 << 11) | ||
880 | +#define MED_TH (0xFF << 3) | ||
881 | +#define AF_MED_EN (1 << 2) | ||
882 | +#define AF_ALAW_EN (1 << 1) | ||
883 | +#define AF_EN (1 << 0) | ||
884 | + | ||
885 | +/* | ||
886 | + * AFPAX1 fields | ||
887 | + */ | ||
888 | +#define PAXW (0x7F << 16) | ||
889 | +#define PAXH 0x7F | ||
890 | + | ||
891 | +/* | ||
892 | + * AFPAX2 fields | ||
893 | + */ | ||
894 | +#define AFINCV (0xF << 13) | ||
895 | +#define PAXVC (0x7F << 6) | ||
896 | +#define PAXHC 0x3F | ||
897 | + | ||
898 | +/* | ||
899 | + * AFPAXSTART fields | ||
900 | + */ | ||
901 | +#define PAXSH (0xFFF<<16) | ||
902 | +#define PAXSV 0xFFF | ||
903 | + | ||
904 | +/* | ||
905 | + * COEFFICIENT MASK | ||
906 | + */ | ||
907 | + | ||
908 | +#define COEF_MASK0 0xFFF | ||
909 | +#define COEF_MASK1 (0xFFF<<16) | ||
910 | + | ||
911 | +/* BIT SHIFTS */ | ||
912 | +#define AF_RGBPOS_SHIFT 11 | ||
913 | +#define AF_MED_TH_SHIFT 3 | ||
914 | +#define AF_PAXW_SHIFT 16 | ||
915 | +#define AF_LINE_INCR_SHIFT 13 | ||
916 | +#define AF_VT_COUNT_SHIFT 6 | ||
917 | +#define AF_HZ_START_SHIFT 16 | ||
918 | +#define AF_COEF_SHIFT 16 | ||
919 | + | ||
920 | +#define AF_UPDATEXS_TS (1 << 0) | ||
921 | +#define AF_UPDATEXS_FIELDCOUNT (1 << 1) | ||
922 | +#define AF_UPDATEXS_LENSPOS (1 << 2) | ||
923 | + | ||
924 | +/* Structure for device of AF Engine */ | ||
925 | +struct af_device { | ||
926 | + struct af_configuration *config; /*Device configuration structure */ | ||
927 | + int size_paxel; /*Paxel size in bytes */ | ||
928 | +}; | ||
929 | + | ||
930 | +int isp_af_check_paxel(void); | ||
931 | +int isp_af_check_iir(void); | ||
932 | +int isp_af_register_setup(struct af_device *af_dev); | ||
933 | +int isp_af_enable(int); | ||
934 | +void isp_af_suspend(void); | ||
935 | +void isp_af_resume(void); | ||
936 | +int isp_af_busy(void); | ||
937 | +void isp_af_notify(int notify); | ||
938 | +int isp_af_request_statistics(struct isp_af_data *afdata); | ||
939 | +int isp_af_configure(struct af_configuration *afconfig); | ||
940 | +void isp_af_set_address(unsigned long); | ||
941 | +void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag); | ||
942 | +#endif /* OMAP_ISP_AF_H */ | ||
943 | diff --git a/drivers/media/video/isp/isph3a.c b/drivers/media/video/isp/isph3a.c | ||
944 | new file mode 100644 | ||
945 | index 0000000..7ff1c5b | ||
946 | --- /dev/null | ||
947 | +++ b/drivers/media/video/isp/isph3a.c | ||
948 | @@ -0,0 +1,932 @@ | ||
949 | +/* | ||
950 | + * isph3a.c | ||
951 | + * | ||
952 | + * H3A module for TI's OMAP3 Camera ISP | ||
953 | + * | ||
954 | + * Copyright (C) 2009 Texas Instruments, Inc. | ||
955 | + * | ||
956 | + * Contributors: | ||
957 | + * Sergio Aguirre <saaguirre@ti.com> | ||
958 | + * Troy Laramy | ||
959 | + * | ||
960 | + * This package is free software; you can redistribute it and/or modify | ||
961 | + * it under the terms of the GNU General Public License version 2 as | ||
962 | + * published by the Free Software Foundation. | ||
963 | + * | ||
964 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
965 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
966 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
967 | + */ | ||
968 | + | ||
969 | +#include <asm/cacheflush.h> | ||
970 | + | ||
971 | +#include <linux/dma-mapping.h> | ||
972 | +#include <linux/uaccess.h> | ||
973 | + | ||
974 | +#include "isp.h" | ||
975 | +#include "ispreg.h" | ||
976 | +#include "isph3a.h" | ||
977 | +#include "ispmmu.h" | ||
978 | +#include "isppreview.h" | ||
979 | + | ||
980 | +/** | ||
981 | + * struct isph3a_aewb_buffer - AE, AWB frame stats buffer. | ||
982 | + * @virt_addr: Virtual address to mmap the buffer. | ||
983 | + * @phy_addr: Physical address of the buffer. | ||
984 | + * @addr_align: Virtual Address 32 bytes aligned. | ||
985 | + * @ispmmu_addr: Address of the buffer mapped by the ISPMMU. | ||
986 | + * @mmap_addr: Mapped memory area of buffer. For userspace access. | ||
987 | + * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten. | ||
988 | + * @frame_num: Frame number from which the statistics are taken. | ||
989 | + * @next: Pointer to link next buffer. | ||
990 | + */ | ||
991 | +struct isph3a_aewb_buffer { | ||
992 | + unsigned long virt_addr; | ||
993 | + unsigned long phy_addr; | ||
994 | + unsigned long addr_align; | ||
995 | + unsigned long ispmmu_addr; | ||
996 | + unsigned long mmap_addr; /* For userspace */ | ||
997 | + struct timeval ts; | ||
998 | + u32 config_counter; | ||
999 | + | ||
1000 | + u8 locked; | ||
1001 | + u16 frame_num; | ||
1002 | + struct isph3a_aewb_buffer *next; | ||
1003 | +}; | ||
1004 | + | ||
1005 | +/** | ||
1006 | + * struct isph3a_aewb_status - AE, AWB status. | ||
1007 | + * @initialized: 1 - Buffers initialized. | ||
1008 | + * @update: 1 - Update registers. | ||
1009 | + * @stats_req: 1 - Future stats requested. | ||
1010 | + * @stats_done: 1 - Stats ready for user. | ||
1011 | + * @frame_req: Number of frame requested for statistics. | ||
1012 | + * @h3a_buff: Array of statistics buffers to access. | ||
1013 | + * @stats_buf_size: Statistics buffer size. | ||
1014 | + * @min_buf_size: Minimum statisitics buffer size. | ||
1015 | + * @win_count: Window Count. | ||
1016 | + * @frame_count: Frame Count. | ||
1017 | + * @stats_wait: Wait primitive for locking/unlocking the stats request. | ||
1018 | + * @buffer_lock: Spinlock for statistics buffers access. | ||
1019 | + */ | ||
1020 | +static struct isph3a_aewb_status { | ||
1021 | + u8 initialized; | ||
1022 | + u8 update; | ||
1023 | + u8 stats_req; | ||
1024 | + u8 stats_done; | ||
1025 | + u16 frame_req; | ||
1026 | + int pm_state; | ||
1027 | + | ||
1028 | + struct isph3a_aewb_buffer h3a_buff[H3A_MAX_BUFF]; | ||
1029 | + unsigned int stats_buf_size; | ||
1030 | + unsigned int min_buf_size; | ||
1031 | + unsigned int curr_cfg_buf_size; | ||
1032 | + | ||
1033 | + atomic_t config_counter; | ||
1034 | + | ||
1035 | + u16 win_count; | ||
1036 | + u32 frame_count; | ||
1037 | + wait_queue_head_t stats_wait; | ||
1038 | + spinlock_t buffer_lock; /* For stats buffers read/write sync */ | ||
1039 | +} aewbstat; | ||
1040 | + | ||
1041 | +/** | ||
1042 | + * struct isph3a_aewb_regs - Current value of AE, AWB configuration registers. | ||
1043 | + * reg_pcr: Peripheral control register. | ||
1044 | + * reg_win1: Control register. | ||
1045 | + * reg_start: Start position register. | ||
1046 | + * reg_blk: Black line register. | ||
1047 | + * reg_subwin: Configuration register. | ||
1048 | + */ | ||
1049 | +static struct isph3a_aewb_regs { | ||
1050 | + u32 reg_pcr; | ||
1051 | + u32 reg_win1; | ||
1052 | + u32 reg_start; | ||
1053 | + u32 reg_blk; | ||
1054 | + u32 reg_subwin; | ||
1055 | +} aewb_regs; | ||
1056 | + | ||
1057 | +static struct isph3a_aewb_config aewb_config_local = { | ||
1058 | + .saturation_limit = 0x3FF, | ||
1059 | + .win_height = 0, | ||
1060 | + .win_width = 0, | ||
1061 | + .ver_win_count = 0, | ||
1062 | + .hor_win_count = 0, | ||
1063 | + .ver_win_start = 0, | ||
1064 | + .hor_win_start = 0, | ||
1065 | + .blk_ver_win_start = 0, | ||
1066 | + .blk_win_height = 0, | ||
1067 | + .subsample_ver_inc = 0, | ||
1068 | + .subsample_hor_inc = 0, | ||
1069 | + .alaw_enable = 0, | ||
1070 | + .aewb_enable = 0, | ||
1071 | +}; | ||
1072 | + | ||
1073 | +/* Structure for saving/restoring h3a module registers */ | ||
1074 | +static struct isp_reg isph3a_reg_list[] = { | ||
1075 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, 0}, /* Should be the first one */ | ||
1076 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1, 0}, | ||
1077 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART, 0}, | ||
1078 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK, 0}, | ||
1079 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN, 0}, | ||
1080 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST, 0}, | ||
1081 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1, 0}, | ||
1082 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2, 0}, | ||
1083 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART, 0}, | ||
1084 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH, 0}, | ||
1085 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST, 0}, | ||
1086 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010, 0}, | ||
1087 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF032, 0}, | ||
1088 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF054, 0}, | ||
1089 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF076, 0}, | ||
1090 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF098, 0}, | ||
1091 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010, 0}, | ||
1092 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF110, 0}, | ||
1093 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF132, 0}, | ||
1094 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF154, 0}, | ||
1095 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF176, 0}, | ||
1096 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF198, 0}, | ||
1097 | + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010, 0}, | ||
1098 | + {0, ISP_TOK_TERM, 0} | ||
1099 | +}; | ||
1100 | + | ||
1101 | +static struct ispprev_wbal h3awb_update; | ||
1102 | +static struct isph3a_aewb_buffer *active_buff; | ||
1103 | +static struct isph3a_aewb_xtrastats h3a_xtrastats[H3A_MAX_BUFF]; | ||
1104 | +static int camnotify; | ||
1105 | +static int wb_update; | ||
1106 | +static void isph3a_print_status(void); | ||
1107 | + | ||
1108 | +/** | ||
1109 | + * isph3a_aewb_setxtrastats - Receives extra statistics from prior frames. | ||
1110 | + * @xtrastats: Pointer to structure containing extra statistics fields like | ||
1111 | + * field count and timestamp of frame. | ||
1112 | + * | ||
1113 | + * Called from update_vbq in camera driver | ||
1114 | + **/ | ||
1115 | +void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats) | ||
1116 | +{ | ||
1117 | + int i; | ||
1118 | + | ||
1119 | + if (active_buff == NULL) | ||
1120 | + return; | ||
1121 | + | ||
1122 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
1123 | + if (aewbstat.h3a_buff[i].frame_num != active_buff->frame_num) | ||
1124 | + continue; | ||
1125 | + | ||
1126 | + if (i == 0) { | ||
1127 | + if (aewbstat.h3a_buff[H3A_MAX_BUFF - 1].locked == 0) { | ||
1128 | + h3a_xtrastats[H3A_MAX_BUFF - 1] = | ||
1129 | + *xtrastats; | ||
1130 | + } else { | ||
1131 | + h3a_xtrastats[H3A_MAX_BUFF - 2] = | ||
1132 | + *xtrastats; | ||
1133 | + } | ||
1134 | + } else if (i == 1) { | ||
1135 | + if (aewbstat.h3a_buff[0].locked == 0) | ||
1136 | + h3a_xtrastats[0] = *xtrastats; | ||
1137 | + else { | ||
1138 | + h3a_xtrastats[H3A_MAX_BUFF - 1] = | ||
1139 | + *xtrastats; | ||
1140 | + } | ||
1141 | + } else { | ||
1142 | + if (aewbstat.h3a_buff[i - 1].locked == 0) | ||
1143 | + h3a_xtrastats[i - 1] = *xtrastats; | ||
1144 | + else | ||
1145 | + h3a_xtrastats[i - 2] = *xtrastats; | ||
1146 | + } | ||
1147 | + return; | ||
1148 | + } | ||
1149 | +} | ||
1150 | +EXPORT_SYMBOL(isph3a_aewb_setxtrastats); | ||
1151 | + | ||
1152 | +void __isph3a_aewb_enable(u8 enable) | ||
1153 | +{ | ||
1154 | + isp_reg_writel(IRQ0STATUS_H3A_AWB_DONE_IRQ, OMAP3_ISP_IOMEM_MAIN, | ||
1155 | + ISP_IRQ0STATUS); | ||
1156 | + | ||
1157 | + if (enable) { | ||
1158 | + aewb_regs.reg_pcr |= ISPH3A_PCR_AEW_EN; | ||
1159 | + DPRINTK_ISPH3A(" H3A enabled \n"); | ||
1160 | + } else { | ||
1161 | + aewb_regs.reg_pcr &= ~ISPH3A_PCR_AEW_EN; | ||
1162 | + DPRINTK_ISPH3A(" H3A disabled \n"); | ||
1163 | + } | ||
1164 | + isp_reg_and_or(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, ~ISPH3A_PCR_AEW_EN, | ||
1165 | + (enable ? ISPH3A_PCR_AEW_EN : 0)); | ||
1166 | + aewb_config_local.aewb_enable = enable; | ||
1167 | +} | ||
1168 | + | ||
1169 | +/** | ||
1170 | + * isph3a_aewb_enable - Enables AE, AWB engine in the H3A module. | ||
1171 | + * @enable: 1 - Enables the AE & AWB engine. | ||
1172 | + * | ||
1173 | + * Client should configure all the AE & AWB registers in H3A before this. | ||
1174 | + **/ | ||
1175 | +void isph3a_aewb_enable(u8 enable) | ||
1176 | +{ | ||
1177 | + __isph3a_aewb_enable(enable); | ||
1178 | + aewbstat.pm_state = enable; | ||
1179 | +} | ||
1180 | + | ||
1181 | +/** | ||
1182 | + * isph3a_aewb_suspend - Suspend AE, AWB engine in the H3A module. | ||
1183 | + **/ | ||
1184 | +void isph3a_aewb_suspend(void) | ||
1185 | +{ | ||
1186 | + if (aewbstat.pm_state) | ||
1187 | + __isph3a_aewb_enable(0); | ||
1188 | +} | ||
1189 | + | ||
1190 | +/** | ||
1191 | + * isph3a_aewb_resume - Resume AE, AWB engine in the H3A module. | ||
1192 | + **/ | ||
1193 | +void isph3a_aewb_resume(void) | ||
1194 | +{ | ||
1195 | + if (aewbstat.pm_state) | ||
1196 | + __isph3a_aewb_enable(1); | ||
1197 | +} | ||
1198 | + | ||
1199 | +int isph3a_aewb_busy(void) | ||
1200 | +{ | ||
1201 | + return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) | ||
1202 | + & ISPH3A_PCR_BUSYAEAWB; | ||
1203 | +} | ||
1204 | + | ||
1205 | +/** | ||
1206 | + * isph3a_update_wb - Updates WB parameters. | ||
1207 | + * | ||
1208 | + * Needs to be called when no ISP Preview processing is taking place. | ||
1209 | + **/ | ||
1210 | +void isph3a_update_wb(void) | ||
1211 | +{ | ||
1212 | + if (wb_update) { | ||
1213 | + isppreview_config_whitebalance(h3awb_update); | ||
1214 | + wb_update = 0; | ||
1215 | + } | ||
1216 | + return; | ||
1217 | +} | ||
1218 | +EXPORT_SYMBOL(isph3a_update_wb); | ||
1219 | + | ||
1220 | +/** | ||
1221 | + * isph3a_aewb_update_regs - Helper function to update h3a registers. | ||
1222 | + **/ | ||
1223 | +static void isph3a_aewb_update_regs(void) | ||
1224 | +{ | ||
1225 | + isp_reg_writel(aewb_regs.reg_pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); | ||
1226 | + isp_reg_writel(aewb_regs.reg_win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1); | ||
1227 | + isp_reg_writel(aewb_regs.reg_start, OMAP3_ISP_IOMEM_H3A, | ||
1228 | + ISPH3A_AEWINSTART); | ||
1229 | + isp_reg_writel(aewb_regs.reg_blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK); | ||
1230 | + isp_reg_writel(aewb_regs.reg_subwin, OMAP3_ISP_IOMEM_H3A, | ||
1231 | + ISPH3A_AEWSUBWIN); | ||
1232 | + | ||
1233 | + aewbstat.update = 0; | ||
1234 | + aewbstat.frame_count = 1; | ||
1235 | +} | ||
1236 | + | ||
1237 | +/** | ||
1238 | + * isph3a_aewb_update_req_buffer - Helper function to update buffer cache pages | ||
1239 | + * @buffer: Pointer to structure | ||
1240 | + **/ | ||
1241 | +static void isph3a_aewb_update_req_buffer(struct isph3a_aewb_buffer *buffer) | ||
1242 | +{ | ||
1243 | + int size = aewbstat.stats_buf_size; | ||
1244 | + | ||
1245 | + size = PAGE_ALIGN(size); | ||
1246 | + dmac_inv_range((void *)buffer->addr_align, | ||
1247 | + (void *)buffer->addr_align + size); | ||
1248 | +} | ||
1249 | + | ||
1250 | +/** | ||
1251 | + * isph3a_aewb_stats_available - Check for stats available of specified frame. | ||
1252 | + * @aewbdata: Pointer to return AE AWB statistics data | ||
1253 | + * | ||
1254 | + * Returns 0 if successful, or -1 if statistics are unavailable. | ||
1255 | + **/ | ||
1256 | +static int isph3a_aewb_stats_available(struct isph3a_aewb_data *aewbdata) | ||
1257 | +{ | ||
1258 | + int i, ret; | ||
1259 | + unsigned long irqflags; | ||
1260 | + | ||
1261 | + spin_lock_irqsave(&aewbstat.buffer_lock, irqflags); | ||
1262 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
1263 | + DPRINTK_ISPH3A("Checking Stats buff[%d] (%d) for %d\n", | ||
1264 | + i, aewbstat.h3a_buff[i].frame_num, | ||
1265 | + aewbdata->frame_number); | ||
1266 | + if ((aewbdata->frame_number != | ||
1267 | + aewbstat.h3a_buff[i].frame_num) || | ||
1268 | + (aewbstat.h3a_buff[i].frame_num == | ||
1269 | + active_buff->frame_num)) | ||
1270 | + continue; | ||
1271 | + aewbstat.h3a_buff[i].locked = 1; | ||
1272 | + spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags); | ||
1273 | + isph3a_aewb_update_req_buffer(&aewbstat.h3a_buff[i]); | ||
1274 | + aewbstat.h3a_buff[i].frame_num = 0; | ||
1275 | + ret = copy_to_user((void *)aewbdata->h3a_aewb_statistics_buf, | ||
1276 | + (void *)aewbstat.h3a_buff[i].virt_addr, | ||
1277 | + aewbstat.curr_cfg_buf_size); | ||
1278 | + if (ret) { | ||
1279 | + printk(KERN_ERR "Failed copy_to_user for " | ||
1280 | + "H3A stats buff, %d\n", ret); | ||
1281 | + } | ||
1282 | + aewbdata->ts = aewbstat.h3a_buff[i].ts; | ||
1283 | + aewbdata->config_counter = aewbstat.h3a_buff[i].config_counter; | ||
1284 | + aewbdata->field_count = h3a_xtrastats[i].field_count; | ||
1285 | + return 0; | ||
1286 | + } | ||
1287 | + spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags); | ||
1288 | + | ||
1289 | + return -1; | ||
1290 | +} | ||
1291 | + | ||
1292 | +/** | ||
1293 | + * isph3a_aewb_link_buffers - Helper function to link allocated buffers. | ||
1294 | + **/ | ||
1295 | +static void isph3a_aewb_link_buffers(void) | ||
1296 | +{ | ||
1297 | + int i; | ||
1298 | + | ||
1299 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
1300 | + if ((i + 1) < H3A_MAX_BUFF) { | ||
1301 | + aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[i + 1]; | ||
1302 | + h3a_xtrastats[i].next = &h3a_xtrastats[i + 1]; | ||
1303 | + } else { | ||
1304 | + aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[0]; | ||
1305 | + h3a_xtrastats[i].next = &h3a_xtrastats[0]; | ||
1306 | + } | ||
1307 | + } | ||
1308 | +} | ||
1309 | + | ||
1310 | +/** | ||
1311 | + * isph3a_aewb_unlock_buffers - Helper function to unlock all buffers. | ||
1312 | + **/ | ||
1313 | +static void isph3a_aewb_unlock_buffers(void) | ||
1314 | +{ | ||
1315 | + int i; | ||
1316 | + unsigned long irqflags; | ||
1317 | + | ||
1318 | + spin_lock_irqsave(&aewbstat.buffer_lock, irqflags); | ||
1319 | + for (i = 0; i < H3A_MAX_BUFF; i++) | ||
1320 | + aewbstat.h3a_buff[i].locked = 0; | ||
1321 | + | ||
1322 | + spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags); | ||
1323 | +} | ||
1324 | + | ||
1325 | +/** | ||
1326 | + * isph3a_aewb_isr - Callback from ISP driver for H3A AEWB interrupt. | ||
1327 | + * @status: IRQ0STATUS in case of MMU error, 0 for H3A interrupt. | ||
1328 | + * @arg1: Not used as of now. | ||
1329 | + * @arg2: Not used as of now. | ||
1330 | + */ | ||
1331 | +static void isph3a_aewb_isr(unsigned long status, isp_vbq_callback_ptr arg1, | ||
1332 | + void *arg2) | ||
1333 | +{ | ||
1334 | + u16 frame_align; | ||
1335 | + | ||
1336 | + if ((H3A_AWB_DONE & status) != H3A_AWB_DONE) | ||
1337 | + return; | ||
1338 | + | ||
1339 | + do_gettimeofday(&active_buff->ts); | ||
1340 | + active_buff->config_counter = atomic_read(&aewbstat.config_counter); | ||
1341 | + active_buff = active_buff->next; | ||
1342 | + if (active_buff->locked == 1) | ||
1343 | + active_buff = active_buff->next; | ||
1344 | + isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A, | ||
1345 | + ISPH3A_AEWBUFST); | ||
1346 | + | ||
1347 | + aewbstat.frame_count++; | ||
1348 | + frame_align = aewbstat.frame_count; | ||
1349 | + if (aewbstat.frame_count > MAX_FRAME_COUNT) { | ||
1350 | + aewbstat.frame_count = 1; | ||
1351 | + frame_align++; | ||
1352 | + } | ||
1353 | + active_buff->frame_num = aewbstat.frame_count; | ||
1354 | + | ||
1355 | + if (aewbstat.stats_req) { | ||
1356 | + DPRINTK_ISPH3A("waiting for frame %d\n", aewbstat.frame_req); | ||
1357 | + if (frame_align >= aewbstat.frame_req + 1) { | ||
1358 | + aewbstat.stats_req = 0; | ||
1359 | + aewbstat.stats_done = 1; | ||
1360 | + wake_up_interruptible(&aewbstat.stats_wait); | ||
1361 | + } | ||
1362 | + } | ||
1363 | + | ||
1364 | + if (aewbstat.update) | ||
1365 | + isph3a_aewb_update_regs(); | ||
1366 | +} | ||
1367 | + | ||
1368 | +/** | ||
1369 | + * isph3a_aewb_set_params - Helper function to check & store user given params. | ||
1370 | + * @user_cfg: Pointer to AE and AWB parameters struct. | ||
1371 | + * | ||
1372 | + * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to | ||
1373 | + * program them during ISR. | ||
1374 | + * | ||
1375 | + * Returns 0 if successful, or -EINVAL if any of the parameters are invalid. | ||
1376 | + **/ | ||
1377 | +static int isph3a_aewb_set_params(struct isph3a_aewb_config *user_cfg) | ||
1378 | +{ | ||
1379 | + if (unlikely(user_cfg->saturation_limit > MAX_SATURATION_LIM)) { | ||
1380 | + printk(KERN_ERR "Invalid Saturation_limit: %d\n", | ||
1381 | + user_cfg->saturation_limit); | ||
1382 | + return -EINVAL; | ||
1383 | + } | ||
1384 | + if (aewb_config_local.saturation_limit != user_cfg->saturation_limit) { | ||
1385 | + WRITE_SAT_LIM(aewb_regs.reg_pcr, user_cfg->saturation_limit); | ||
1386 | + aewb_config_local.saturation_limit = | ||
1387 | + user_cfg->saturation_limit; | ||
1388 | + aewbstat.update = 1; | ||
1389 | + } | ||
1390 | + | ||
1391 | + if (aewb_config_local.alaw_enable != user_cfg->alaw_enable) { | ||
1392 | + WRITE_ALAW(aewb_regs.reg_pcr, user_cfg->alaw_enable); | ||
1393 | + aewb_config_local.alaw_enable = user_cfg->alaw_enable; | ||
1394 | + aewbstat.update = 1; | ||
1395 | + } | ||
1396 | + | ||
1397 | + if (unlikely(user_cfg->win_height < MIN_WIN_H || | ||
1398 | + user_cfg->win_height > MAX_WIN_H || | ||
1399 | + user_cfg->win_height & 0x01)) { | ||
1400 | + printk(KERN_ERR "Invalid window height: %d\n", | ||
1401 | + user_cfg->win_height); | ||
1402 | + return -EINVAL; | ||
1403 | + } | ||
1404 | + if (aewb_config_local.win_height != user_cfg->win_height) { | ||
1405 | + WRITE_WIN_H(aewb_regs.reg_win1, user_cfg->win_height); | ||
1406 | + aewb_config_local.win_height = user_cfg->win_height; | ||
1407 | + aewbstat.update = 1; | ||
1408 | + } | ||
1409 | + | ||
1410 | + if (unlikely(user_cfg->win_width < MIN_WIN_W || | ||
1411 | + user_cfg->win_width > MAX_WIN_W || | ||
1412 | + user_cfg->win_width & 0x01)) { | ||
1413 | + printk(KERN_ERR "Invalid window width: %d\n", | ||
1414 | + user_cfg->win_width); | ||
1415 | + return -EINVAL; | ||
1416 | + } | ||
1417 | + if (aewb_config_local.win_width != user_cfg->win_width) { | ||
1418 | + WRITE_WIN_W(aewb_regs.reg_win1, user_cfg->win_width); | ||
1419 | + aewb_config_local.win_width = user_cfg->win_width; | ||
1420 | + aewbstat.update = 1; | ||
1421 | + } | ||
1422 | + | ||
1423 | + if (unlikely(user_cfg->ver_win_count < 1 || | ||
1424 | + user_cfg->ver_win_count > MAX_WINVC)) { | ||
1425 | + printk(KERN_ERR "Invalid vertical window count: %d\n", | ||
1426 | + user_cfg->ver_win_count); | ||
1427 | + return -EINVAL; | ||
1428 | + } | ||
1429 | + if (aewb_config_local.ver_win_count != user_cfg->ver_win_count) { | ||
1430 | + WRITE_VER_C(aewb_regs.reg_win1, user_cfg->ver_win_count); | ||
1431 | + aewb_config_local.ver_win_count = user_cfg->ver_win_count; | ||
1432 | + aewbstat.update = 1; | ||
1433 | + } | ||
1434 | + | ||
1435 | + if (unlikely(user_cfg->hor_win_count < 1 || | ||
1436 | + user_cfg->hor_win_count > MAX_WINHC)) { | ||
1437 | + printk(KERN_ERR "Invalid horizontal window count: %d\n", | ||
1438 | + user_cfg->hor_win_count); | ||
1439 | + return -EINVAL; | ||
1440 | + } | ||
1441 | + if (aewb_config_local.hor_win_count != user_cfg->hor_win_count) { | ||
1442 | + WRITE_HOR_C(aewb_regs.reg_win1, user_cfg->hor_win_count); | ||
1443 | + aewb_config_local.hor_win_count = user_cfg->hor_win_count; | ||
1444 | + aewbstat.update = 1; | ||
1445 | + } | ||
1446 | + | ||
1447 | + if (unlikely(user_cfg->ver_win_start > MAX_WINSTART)) { | ||
1448 | + printk(KERN_ERR "Invalid vertical window start: %d\n", | ||
1449 | + user_cfg->ver_win_start); | ||
1450 | + return -EINVAL; | ||
1451 | + } | ||
1452 | + if (aewb_config_local.ver_win_start != user_cfg->ver_win_start) { | ||
1453 | + WRITE_VER_WIN_ST(aewb_regs.reg_start, user_cfg->ver_win_start); | ||
1454 | + aewb_config_local.ver_win_start = user_cfg->ver_win_start; | ||
1455 | + aewbstat.update = 1; | ||
1456 | + } | ||
1457 | + | ||
1458 | + if (unlikely(user_cfg->hor_win_start > MAX_WINSTART)) { | ||
1459 | + printk(KERN_ERR "Invalid horizontal window start: %d\n", | ||
1460 | + user_cfg->hor_win_start); | ||
1461 | + return -EINVAL; | ||
1462 | + } | ||
1463 | + if (aewb_config_local.hor_win_start != user_cfg->hor_win_start) { | ||
1464 | + WRITE_HOR_WIN_ST(aewb_regs.reg_start, user_cfg->hor_win_start); | ||
1465 | + aewb_config_local.hor_win_start = user_cfg->hor_win_start; | ||
1466 | + aewbstat.update = 1; | ||
1467 | + } | ||
1468 | + | ||
1469 | + if (unlikely(user_cfg->blk_ver_win_start > MAX_WINSTART)) { | ||
1470 | + printk(KERN_ERR "Invalid black vertical window start: %d\n", | ||
1471 | + user_cfg->blk_ver_win_start); | ||
1472 | + return -EINVAL; | ||
1473 | + } | ||
1474 | + if (aewb_config_local.blk_ver_win_start != | ||
1475 | + user_cfg->blk_ver_win_start) { | ||
1476 | + WRITE_BLK_VER_WIN_ST(aewb_regs.reg_blk, | ||
1477 | + user_cfg->blk_ver_win_start); | ||
1478 | + aewb_config_local.blk_ver_win_start = | ||
1479 | + user_cfg->blk_ver_win_start; | ||
1480 | + aewbstat.update = 1; | ||
1481 | + } | ||
1482 | + | ||
1483 | + if (unlikely(user_cfg->blk_win_height < MIN_WIN_H || | ||
1484 | + user_cfg->blk_win_height > MAX_WIN_H || | ||
1485 | + user_cfg->blk_win_height & 0x01)) { | ||
1486 | + printk(KERN_ERR "Invalid black window height: %d\n", | ||
1487 | + user_cfg->blk_win_height); | ||
1488 | + return -EINVAL; | ||
1489 | + } | ||
1490 | + if (aewb_config_local.blk_win_height != user_cfg->blk_win_height) { | ||
1491 | + WRITE_BLK_WIN_H(aewb_regs.reg_blk, user_cfg->blk_win_height); | ||
1492 | + aewb_config_local.blk_win_height = user_cfg->blk_win_height; | ||
1493 | + aewbstat.update = 1; | ||
1494 | + } | ||
1495 | + | ||
1496 | + if (unlikely(user_cfg->subsample_ver_inc < MIN_SUB_INC || | ||
1497 | + user_cfg->subsample_ver_inc > MAX_SUB_INC || | ||
1498 | + user_cfg->subsample_ver_inc & 0x01)) { | ||
1499 | + printk(KERN_ERR "Invalid vertical subsample increment: %d\n", | ||
1500 | + user_cfg->subsample_ver_inc); | ||
1501 | + return -EINVAL; | ||
1502 | + } | ||
1503 | + if (aewb_config_local.subsample_ver_inc != | ||
1504 | + user_cfg->subsample_ver_inc) { | ||
1505 | + WRITE_SUB_VER_INC(aewb_regs.reg_subwin, | ||
1506 | + user_cfg->subsample_ver_inc); | ||
1507 | + aewb_config_local.subsample_ver_inc = | ||
1508 | + user_cfg->subsample_ver_inc; | ||
1509 | + aewbstat.update = 1; | ||
1510 | + } | ||
1511 | + | ||
1512 | + if (unlikely(user_cfg->subsample_hor_inc < MIN_SUB_INC || | ||
1513 | + user_cfg->subsample_hor_inc > MAX_SUB_INC || | ||
1514 | + user_cfg->subsample_hor_inc & 0x01)) { | ||
1515 | + printk(KERN_ERR "Invalid horizontal subsample increment: %d\n", | ||
1516 | + user_cfg->subsample_hor_inc); | ||
1517 | + return -EINVAL; | ||
1518 | + } | ||
1519 | + if (aewb_config_local.subsample_hor_inc != | ||
1520 | + user_cfg->subsample_hor_inc) { | ||
1521 | + WRITE_SUB_HOR_INC(aewb_regs.reg_subwin, | ||
1522 | + user_cfg->subsample_hor_inc); | ||
1523 | + aewb_config_local.subsample_hor_inc = | ||
1524 | + user_cfg->subsample_hor_inc; | ||
1525 | + aewbstat.update = 1; | ||
1526 | + } | ||
1527 | + | ||
1528 | + if (!aewbstat.initialized || !aewb_config_local.aewb_enable) { | ||
1529 | + isph3a_aewb_update_regs(); | ||
1530 | + aewbstat.initialized = 1; | ||
1531 | + } | ||
1532 | + return 0; | ||
1533 | +} | ||
1534 | + | ||
1535 | +/** | ||
1536 | + * isph3a_aewb_configure - Configure AEWB regs, enable/disable H3A engine. | ||
1537 | + * @aewbcfg: Pointer to AEWB config structure. | ||
1538 | + * | ||
1539 | + * Returns 0 if successful, -EINVAL if aewbcfg pointer is NULL, -ENOMEM if | ||
1540 | + * was unable to allocate memory for the buffer, of other errors if H3A | ||
1541 | + * callback is not set or the parameters for AEWB are invalid. | ||
1542 | + **/ | ||
1543 | +int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg) | ||
1544 | +{ | ||
1545 | + int ret = 0; | ||
1546 | + int i; | ||
1547 | + int win_count = 0; | ||
1548 | + | ||
1549 | + if (NULL == aewbcfg) { | ||
1550 | + printk(KERN_ERR "Null argument in configuration. \n"); | ||
1551 | + return -EINVAL; | ||
1552 | + } | ||
1553 | + | ||
1554 | + if (!aewbstat.initialized) { | ||
1555 | + DPRINTK_ISPH3A("Setting callback for H3A\n"); | ||
1556 | + ret = isp_set_callback(CBK_H3A_AWB_DONE, isph3a_aewb_isr, | ||
1557 | + (void *)NULL, (void *)NULL); | ||
1558 | + if (ret) { | ||
1559 | + printk(KERN_ERR "No callback for H3A\n"); | ||
1560 | + return ret; | ||
1561 | + } | ||
1562 | + } | ||
1563 | + | ||
1564 | + ret = isph3a_aewb_set_params(aewbcfg); | ||
1565 | + if (ret) { | ||
1566 | + printk(KERN_ERR "Invalid parameters! \n"); | ||
1567 | + return ret; | ||
1568 | + } | ||
1569 | + | ||
1570 | + win_count = aewbcfg->ver_win_count * aewbcfg->hor_win_count; | ||
1571 | + win_count += aewbcfg->hor_win_count; | ||
1572 | + ret = win_count / 8; | ||
1573 | + win_count += win_count % 8 ? 1 : 0; | ||
1574 | + win_count += ret; | ||
1575 | + | ||
1576 | + aewbstat.win_count = win_count; | ||
1577 | + aewbstat.curr_cfg_buf_size = win_count * AEWB_PACKET_SIZE; | ||
1578 | + | ||
1579 | + if (aewbstat.stats_buf_size | ||
1580 | + && win_count * AEWB_PACKET_SIZE > aewbstat.stats_buf_size) { | ||
1581 | + DPRINTK_ISPH3A("There was a previous buffer... " | ||
1582 | + "Freeing/unmapping current stat busffs\n"); | ||
1583 | + isph3a_aewb_enable(0); | ||
1584 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
1585 | + ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr); | ||
1586 | + dma_free_coherent( | ||
1587 | + NULL, | ||
1588 | + aewbstat.min_buf_size, | ||
1589 | + (void *)aewbstat.h3a_buff[i].virt_addr, | ||
1590 | + (dma_addr_t)aewbstat.h3a_buff[i].phy_addr); | ||
1591 | + aewbstat.h3a_buff[i].virt_addr = 0; | ||
1592 | + } | ||
1593 | + aewbstat.stats_buf_size = 0; | ||
1594 | + } | ||
1595 | + | ||
1596 | + if (!aewbstat.h3a_buff[0].virt_addr) { | ||
1597 | + aewbstat.stats_buf_size = win_count * AEWB_PACKET_SIZE; | ||
1598 | + aewbstat.min_buf_size = PAGE_ALIGN(aewbstat.stats_buf_size); | ||
1599 | + | ||
1600 | + DPRINTK_ISPH3A("Allocating/mapping new stat buffs\n"); | ||
1601 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
1602 | + aewbstat.h3a_buff[i].virt_addr = | ||
1603 | + (unsigned long)dma_alloc_coherent( | ||
1604 | + NULL, | ||
1605 | + aewbstat.min_buf_size, | ||
1606 | + (dma_addr_t *) | ||
1607 | + &aewbstat.h3a_buff[i].phy_addr, | ||
1608 | + GFP_KERNEL | GFP_DMA); | ||
1609 | + if (aewbstat.h3a_buff[i].virt_addr == 0) { | ||
1610 | + printk(KERN_ERR "Can't acquire memory for " | ||
1611 | + "buffer[%d]\n", i); | ||
1612 | + return -ENOMEM; | ||
1613 | + } | ||
1614 | + aewbstat.h3a_buff[i].addr_align = | ||
1615 | + aewbstat.h3a_buff[i].virt_addr; | ||
1616 | + while ((aewbstat.h3a_buff[i].addr_align & 0xFFFFFFC0) != | ||
1617 | + aewbstat.h3a_buff[i].addr_align) | ||
1618 | + aewbstat.h3a_buff[i].addr_align++; | ||
1619 | + aewbstat.h3a_buff[i].ispmmu_addr = | ||
1620 | + ispmmu_kmap(aewbstat.h3a_buff[i].phy_addr, | ||
1621 | + aewbstat.min_buf_size); | ||
1622 | + } | ||
1623 | + isph3a_aewb_unlock_buffers(); | ||
1624 | + isph3a_aewb_link_buffers(); | ||
1625 | + | ||
1626 | + if (active_buff == NULL) | ||
1627 | + active_buff = &aewbstat.h3a_buff[0]; | ||
1628 | + | ||
1629 | + isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A, | ||
1630 | + ISPH3A_AEWBUFST); | ||
1631 | + } | ||
1632 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
1633 | + DPRINTK_ISPH3A("buff[%d] addr is:\n virt 0x%lX\n" | ||
1634 | + " aligned 0x%lX\n" | ||
1635 | + " phys 0x%lX\n" | ||
1636 | + " ispmmu 0x%08lX\n" | ||
1637 | + " mmapped 0x%lX\n" | ||
1638 | + " frame_num %d\n", i, | ||
1639 | + aewbstat.h3a_buff[i].virt_addr, | ||
1640 | + aewbstat.h3a_buff[i].addr_align, | ||
1641 | + aewbstat.h3a_buff[i].phy_addr, | ||
1642 | + aewbstat.h3a_buff[i].ispmmu_addr, | ||
1643 | + aewbstat.h3a_buff[i].mmap_addr, | ||
1644 | + aewbstat.h3a_buff[i].frame_num); | ||
1645 | + } | ||
1646 | + | ||
1647 | + active_buff->frame_num = 1; | ||
1648 | + | ||
1649 | + atomic_inc(&aewbstat.config_counter); | ||
1650 | + isph3a_aewb_enable(aewbcfg->aewb_enable); | ||
1651 | + isph3a_print_status(); | ||
1652 | + | ||
1653 | + return 0; | ||
1654 | +} | ||
1655 | +EXPORT_SYMBOL(isph3a_aewb_configure); | ||
1656 | + | ||
1657 | +/** | ||
1658 | + * isph3a_aewb_request_statistics - REquest statistics and update gains in AEWB | ||
1659 | + * @aewbdata: Pointer to return AE AWB statistics data. | ||
1660 | + * | ||
1661 | + * This API allows the user to update White Balance gains, as well as | ||
1662 | + * exposure time and analog gain. It is also used to request frame | ||
1663 | + * statistics. | ||
1664 | + * | ||
1665 | + * Returns 0 if successful, -EINVAL when H3A engine is not enabled, or other | ||
1666 | + * errors when setting gains. | ||
1667 | + **/ | ||
1668 | +int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata) | ||
1669 | +{ | ||
1670 | + int ret = 0; | ||
1671 | + u16 frame_diff = 0; | ||
1672 | + u16 frame_cnt = aewbstat.frame_count; | ||
1673 | + wait_queue_t wqt; | ||
1674 | + | ||
1675 | + if (!aewb_config_local.aewb_enable) { | ||
1676 | + printk(KERN_ERR "H3A engine not enabled\n"); | ||
1677 | + return -EINVAL; | ||
1678 | + } | ||
1679 | + | ||
1680 | + DPRINTK_ISPH3A("isph3a_aewb_request_statistics: Enter " | ||
1681 | + "(frame req. => %d, current frame => %d," | ||
1682 | + "update => %d)\n", | ||
1683 | + aewbdata->frame_number, frame_cnt, aewbdata->update); | ||
1684 | + DPRINTK_ISPH3A("User data received: \n"); | ||
1685 | + DPRINTK_ISPH3A("Digital gain = 0x%04x\n", aewbdata->dgain); | ||
1686 | + DPRINTK_ISPH3A("WB gain b *= 0x%04x\n", aewbdata->wb_gain_b); | ||
1687 | + DPRINTK_ISPH3A("WB gain r *= 0x%04x\n", aewbdata->wb_gain_r); | ||
1688 | + DPRINTK_ISPH3A("WB gain gb = 0x%04x\n", aewbdata->wb_gain_gb); | ||
1689 | + DPRINTK_ISPH3A("WB gain gr = 0x%04x\n", aewbdata->wb_gain_gr); | ||
1690 | + | ||
1691 | + if (!aewbdata->update) { | ||
1692 | + aewbdata->h3a_aewb_statistics_buf = NULL; | ||
1693 | + goto out; | ||
1694 | + } | ||
1695 | + if (aewbdata->update & SET_DIGITAL_GAIN) | ||
1696 | + h3awb_update.dgain = (u16)aewbdata->dgain; | ||
1697 | + if (aewbdata->update & SET_COLOR_GAINS) { | ||
1698 | + h3awb_update.coef0 = (u8)aewbdata->wb_gain_gr; | ||
1699 | + h3awb_update.coef1 = (u8)aewbdata->wb_gain_r; | ||
1700 | + h3awb_update.coef2 = (u8)aewbdata->wb_gain_b; | ||
1701 | + h3awb_update.coef3 = (u8)aewbdata->wb_gain_gb; | ||
1702 | + } | ||
1703 | + if (aewbdata->update & (SET_COLOR_GAINS | SET_DIGITAL_GAIN)) | ||
1704 | + wb_update = 1; | ||
1705 | + | ||
1706 | + if (!(aewbdata->update & REQUEST_STATISTICS)) { | ||
1707 | + aewbdata->h3a_aewb_statistics_buf = NULL; | ||
1708 | + goto out; | ||
1709 | + } | ||
1710 | + | ||
1711 | + if (aewbdata->frame_number < 1) { | ||
1712 | + printk(KERN_ERR "Illeagal frame number " | ||
1713 | + "requested (%d)\n", | ||
1714 | + aewbdata->frame_number); | ||
1715 | + return -EINVAL; | ||
1716 | + } | ||
1717 | + | ||
1718 | + isph3a_aewb_unlock_buffers(); | ||
1719 | + | ||
1720 | + DPRINTK_ISPH3A("Stats available?\n"); | ||
1721 | + ret = isph3a_aewb_stats_available(aewbdata); | ||
1722 | + if (!ret) | ||
1723 | + goto out; | ||
1724 | + | ||
1725 | + DPRINTK_ISPH3A("Stats in near future?\n"); | ||
1726 | + if (aewbdata->frame_number > frame_cnt) | ||
1727 | + frame_diff = aewbdata->frame_number - frame_cnt; | ||
1728 | + else if (aewbdata->frame_number < frame_cnt) { | ||
1729 | + if ((frame_cnt > (MAX_FRAME_COUNT - MAX_FUTURE_FRAMES)) && | ||
1730 | + (aewbdata->frame_number < MAX_FRAME_COUNT)) { | ||
1731 | + frame_diff = aewbdata->frame_number + MAX_FRAME_COUNT - | ||
1732 | + frame_cnt; | ||
1733 | + } else | ||
1734 | + frame_diff = MAX_FUTURE_FRAMES + 1; | ||
1735 | + } | ||
1736 | + | ||
1737 | + if (frame_diff > MAX_FUTURE_FRAMES) { | ||
1738 | + printk(KERN_ERR "Invalid frame requested, returning current" | ||
1739 | + " frame stats\n"); | ||
1740 | + aewbdata->frame_number = frame_cnt; | ||
1741 | + } | ||
1742 | + if (camnotify) { | ||
1743 | + DPRINTK_ISPH3A("NOT Waiting on stats IRQ for frame %d " | ||
1744 | + "because camnotify set\n", | ||
1745 | + aewbdata->frame_number); | ||
1746 | + aewbdata->h3a_aewb_statistics_buf = NULL; | ||
1747 | + goto out; | ||
1748 | + } | ||
1749 | + DPRINTK_ISPH3A("Waiting on stats IRQ for frame %d\n", | ||
1750 | + aewbdata->frame_number); | ||
1751 | + aewbstat.frame_req = aewbdata->frame_number; | ||
1752 | + aewbstat.stats_req = 1; | ||
1753 | + aewbstat.stats_done = 0; | ||
1754 | + init_waitqueue_entry(&wqt, current); | ||
1755 | + ret = wait_event_interruptible(aewbstat.stats_wait, | ||
1756 | + aewbstat.stats_done == 1); | ||
1757 | + if (ret < 0) { | ||
1758 | + printk(KERN_ERR "isph3a_aewb_request_statistics" | ||
1759 | + " Error on wait event %d\n", ret); | ||
1760 | + aewbdata->h3a_aewb_statistics_buf = NULL; | ||
1761 | + return ret; | ||
1762 | + } | ||
1763 | + | ||
1764 | + DPRINTK_ISPH3A("ISP AEWB request status interrupt raised\n"); | ||
1765 | + ret = isph3a_aewb_stats_available(aewbdata); | ||
1766 | + if (ret) { | ||
1767 | + DPRINTK_ISPH3A("After waiting for stats," | ||
1768 | + " stats not available!!\n"); | ||
1769 | + aewbdata->h3a_aewb_statistics_buf = NULL; | ||
1770 | + } | ||
1771 | +out: | ||
1772 | + DPRINTK_ISPH3A("isph3a_aewb_request_statistics: " | ||
1773 | + "aewbdata->h3a_aewb_statistics_buf => %p\n", | ||
1774 | + aewbdata->h3a_aewb_statistics_buf); | ||
1775 | + aewbdata->curr_frame = aewbstat.frame_count; | ||
1776 | + | ||
1777 | + return 0; | ||
1778 | +} | ||
1779 | +EXPORT_SYMBOL(isph3a_aewb_request_statistics); | ||
1780 | + | ||
1781 | +/** | ||
1782 | + * isph3a_aewb_init - Module Initialisation. | ||
1783 | + * | ||
1784 | + * Always returns 0. | ||
1785 | + **/ | ||
1786 | +int __init isph3a_aewb_init(void) | ||
1787 | +{ | ||
1788 | + memset(&aewbstat, 0, sizeof(aewbstat)); | ||
1789 | + memset(&aewb_regs, 0, sizeof(aewb_regs)); | ||
1790 | + | ||
1791 | + init_waitqueue_head(&aewbstat.stats_wait); | ||
1792 | + spin_lock_init(&aewbstat.buffer_lock); | ||
1793 | + return 0; | ||
1794 | +} | ||
1795 | + | ||
1796 | +/** | ||
1797 | + * isph3a_aewb_cleanup - Module exit. | ||
1798 | + **/ | ||
1799 | +void isph3a_aewb_cleanup(void) | ||
1800 | +{ | ||
1801 | + int i; | ||
1802 | + | ||
1803 | + for (i = 0; i < H3A_MAX_BUFF; i++) { | ||
1804 | + if (!aewbstat.h3a_buff[i].phy_addr) | ||
1805 | + continue; | ||
1806 | + | ||
1807 | + ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr); | ||
1808 | + dma_free_coherent(NULL, | ||
1809 | + aewbstat.min_buf_size, | ||
1810 | + (void *)aewbstat.h3a_buff[i].virt_addr, | ||
1811 | + (dma_addr_t)aewbstat.h3a_buff[i].phy_addr); | ||
1812 | + } | ||
1813 | + memset(&aewbstat, 0, sizeof(aewbstat)); | ||
1814 | + memset(&aewb_regs, 0, sizeof(aewb_regs)); | ||
1815 | +} | ||
1816 | + | ||
1817 | +/** | ||
1818 | + * isph3a_print_status - Debug print. Values of H3A related registers. | ||
1819 | + **/ | ||
1820 | +static void isph3a_print_status(void) | ||
1821 | +{ | ||
1822 | + DPRINTK_ISPH3A("ISPH3A_PCR = 0x%08x\n", | ||
1823 | + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)); | ||
1824 | + DPRINTK_ISPH3A("ISPH3A_AEWWIN1 = 0x%08x\n", | ||
1825 | + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1)); | ||
1826 | + DPRINTK_ISPH3A("ISPH3A_AEWINSTART = 0x%08x\n", | ||
1827 | + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART)); | ||
1828 | + DPRINTK_ISPH3A("ISPH3A_AEWINBLK = 0x%08x\n", | ||
1829 | + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK)); | ||
1830 | + DPRINTK_ISPH3A("ISPH3A_AEWSUBWIN = 0x%08x\n", | ||
1831 | + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN)); | ||
1832 | + DPRINTK_ISPH3A("ISPH3A_AEWBUFST = 0x%08x\n", | ||
1833 | + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST)); | ||
1834 | + DPRINTK_ISPH3A("stats windows = %d\n", aewbstat.win_count); | ||
1835 | + DPRINTK_ISPH3A("stats buff size = %d\n", aewbstat.stats_buf_size); | ||
1836 | + DPRINTK_ISPH3A("currently configured stats buff size = %d\n", | ||
1837 | + aewbstat.curr_cfg_buf_size); | ||
1838 | +} | ||
1839 | + | ||
1840 | +/** | ||
1841 | + * isph3a_notify - Unblocks user request for statistics when camera is off | ||
1842 | + * @notify: 1 - Camera is turned off | ||
1843 | + * | ||
1844 | + * Used when the user has requested statistics about a future frame, but the | ||
1845 | + * camera is turned off before it happens, and this function unblocks the | ||
1846 | + * request so the user can continue in its program. | ||
1847 | + **/ | ||
1848 | +void isph3a_notify(int notify) | ||
1849 | +{ | ||
1850 | + camnotify = notify; | ||
1851 | + if (camnotify && aewbstat.initialized) { | ||
1852 | + printk(KERN_DEBUG "Warning Camera Off \n"); | ||
1853 | + aewbstat.stats_req = 0; | ||
1854 | + aewbstat.stats_done = 1; | ||
1855 | + wake_up_interruptible(&aewbstat.stats_wait); | ||
1856 | + } | ||
1857 | +} | ||
1858 | +EXPORT_SYMBOL(isph3a_notify); | ||
1859 | + | ||
1860 | +/** | ||
1861 | + * isph3a_save_context - Saves the values of the h3a module registers. | ||
1862 | + **/ | ||
1863 | +void isph3a_save_context(void) | ||
1864 | +{ | ||
1865 | + DPRINTK_ISPH3A(" Saving context\n"); | ||
1866 | + isp_save_context(isph3a_reg_list); | ||
1867 | + /* Avoid enable during restore ctx */ | ||
1868 | + isph3a_reg_list[0].val &= ~ISPH3A_PCR_AEW_EN; | ||
1869 | +} | ||
1870 | +EXPORT_SYMBOL(isph3a_save_context); | ||
1871 | + | ||
1872 | +/** | ||
1873 | + * isph3a_restore_context - Restores the values of the h3a module registers. | ||
1874 | + **/ | ||
1875 | +void isph3a_restore_context(void) | ||
1876 | +{ | ||
1877 | + DPRINTK_ISPH3A(" Restoring context\n"); | ||
1878 | + isp_restore_context(isph3a_reg_list); | ||
1879 | +} | ||
1880 | +EXPORT_SYMBOL(isph3a_restore_context); | ||
1881 | diff --git a/drivers/media/video/isp/isph3a.h b/drivers/media/video/isp/isph3a.h | ||
1882 | new file mode 100644 | ||
1883 | index 0000000..7d4c765 | ||
1884 | --- /dev/null | ||
1885 | +++ b/drivers/media/video/isp/isph3a.h | ||
1886 | @@ -0,0 +1,127 @@ | ||
1887 | +/* | ||
1888 | + * isph3a.h | ||
1889 | + * | ||
1890 | + * Include file for H3A module in TI's OMAP3 Camera ISP | ||
1891 | + * | ||
1892 | + * Copyright (C) 2009 Texas Instruments, Inc. | ||
1893 | + * | ||
1894 | + * Contributors: | ||
1895 | + * Sergio Aguirre <saaguirre@ti.com> | ||
1896 | + * Troy Laramy | ||
1897 | + * | ||
1898 | + * This package is free software; you can redistribute it and/or modify | ||
1899 | + * it under the terms of the GNU General Public License version 2 as | ||
1900 | + * published by the Free Software Foundation. | ||
1901 | + * | ||
1902 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
1903 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
1904 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
1905 | + */ | ||
1906 | + | ||
1907 | +#ifndef OMAP_ISP_H3A_H | ||
1908 | +#define OMAP_ISP_H3A_H | ||
1909 | + | ||
1910 | +#include <mach/isp_user.h> | ||
1911 | + | ||
1912 | +#define AEWB_PACKET_SIZE 16 | ||
1913 | +#define H3A_MAX_BUFF 5 | ||
1914 | + | ||
1915 | +/* Flags for changed registers */ | ||
1916 | +#define PCR_CHNG (1 << 0) | ||
1917 | +#define AEWWIN1_CHNG (1 << 1) | ||
1918 | +#define AEWINSTART_CHNG (1 << 2) | ||
1919 | +#define AEWINBLK_CHNG (1 << 3) | ||
1920 | +#define AEWSUBWIN_CHNG (1 << 4) | ||
1921 | +#define PRV_WBDGAIN_CHNG (1 << 5) | ||
1922 | +#define PRV_WBGAIN_CHNG (1 << 6) | ||
1923 | + | ||
1924 | +/* ISPH3A REGISTERS bits */ | ||
1925 | +#define ISPH3A_PCR_AF_EN (1 << 0) | ||
1926 | +#define ISPH3A_PCR_AF_ALAW_EN (1 << 1) | ||
1927 | +#define ISPH3A_PCR_AF_MED_EN (1 << 2) | ||
1928 | +#define ISPH3A_PCR_AF_BUSY (1 << 15) | ||
1929 | +#define ISPH3A_PCR_AEW_EN (1 << 16) | ||
1930 | +#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17) | ||
1931 | +#define ISPH3A_PCR_AEW_BUSY (1 << 18) | ||
1932 | + | ||
1933 | +#define WRITE_SAT_LIM(reg, sat_limit) \ | ||
1934 | + (reg = (reg & (~(ISPH3A_PCR_AEW_AVE2LMT_MASK))) \ | ||
1935 | + | (sat_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT)) | ||
1936 | + | ||
1937 | +#define WRITE_ALAW(reg, alaw_en) \ | ||
1938 | + (reg = (reg & (~(ISPH3A_PCR_AEW_ALAW_EN))) \ | ||
1939 | + | ((alaw_en & ISPH3A_PCR_AF_ALAW_EN) \ | ||
1940 | + << ISPH3A_PCR_AEW_ALAW_EN_SHIFT)) | ||
1941 | + | ||
1942 | +#define WRITE_WIN_H(reg, height) \ | ||
1943 | + (reg = (reg & (~(ISPH3A_AEWWIN1_WINH_MASK))) \ | ||
1944 | + | (((height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT)) | ||
1945 | + | ||
1946 | +#define WRITE_WIN_W(reg, width) \ | ||
1947 | + (reg = (reg & (~(ISPH3A_AEWWIN1_WINW_MASK))) \ | ||
1948 | + | (((width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT)) | ||
1949 | + | ||
1950 | +#define WRITE_VER_C(reg, ver_count) \ | ||
1951 | + (reg = (reg & ~(ISPH3A_AEWWIN1_WINVC_MASK)) \ | ||
1952 | + | ((ver_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT)) | ||
1953 | + | ||
1954 | +#define WRITE_HOR_C(reg, hor_count) \ | ||
1955 | + (reg = (reg & ~(ISPH3A_AEWWIN1_WINHC_MASK)) \ | ||
1956 | + | ((hor_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT)) | ||
1957 | + | ||
1958 | +#define WRITE_VER_WIN_ST(reg, ver_win_st) \ | ||
1959 | + (reg = (reg & ~(ISPH3A_AEWINSTART_WINSV_MASK)) \ | ||
1960 | + | (ver_win_st << ISPH3A_AEWINSTART_WINSV_SHIFT)) | ||
1961 | + | ||
1962 | +#define WRITE_HOR_WIN_ST(reg, hor_win_st) \ | ||
1963 | + (reg = (reg & ~(ISPH3A_AEWINSTART_WINSH_MASK)) \ | ||
1964 | + | (hor_win_st << ISPH3A_AEWINSTART_WINSH_SHIFT)) | ||
1965 | + | ||
1966 | +#define WRITE_BLK_VER_WIN_ST(reg, blk_win_st) \ | ||
1967 | + (reg = (reg & ~(ISPH3A_AEWINBLK_WINSV_MASK)) \ | ||
1968 | + | (blk_win_st << ISPH3A_AEWINBLK_WINSV_SHIFT)) | ||
1969 | + | ||
1970 | +#define WRITE_BLK_WIN_H(reg, height) \ | ||
1971 | + (reg = (reg & ~(ISPH3A_AEWINBLK_WINH_MASK)) \ | ||
1972 | + | (((height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT)) | ||
1973 | + | ||
1974 | +#define WRITE_SUB_VER_INC(reg, sub_ver_inc) \ | ||
1975 | + (reg = (reg & ~(ISPH3A_AEWSUBWIN_AEWINCV_MASK)) \ | ||
1976 | + | (((sub_ver_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCV_SHIFT)) | ||
1977 | + | ||
1978 | +#define WRITE_SUB_HOR_INC(reg, sub_hor_inc) \ | ||
1979 | + (reg = (reg & ~(ISPH3A_AEWSUBWIN_AEWINCH_MASK)) \ | ||
1980 | + | (((sub_hor_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCH_SHIFT)) | ||
1981 | + | ||
1982 | +/** | ||
1983 | + * struct isph3a_aewb_xtrastats - Structure with extra statistics sent by cam. | ||
1984 | + * @field_count: Sequence number of returned framestats. | ||
1985 | + * @isph3a_aewb_xtrastats: Pointer to next buffer with extra stats. | ||
1986 | + */ | ||
1987 | +struct isph3a_aewb_xtrastats { | ||
1988 | + unsigned long field_count; | ||
1989 | + struct isph3a_aewb_xtrastats *next; | ||
1990 | +}; | ||
1991 | + | ||
1992 | +void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats); | ||
1993 | + | ||
1994 | +int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg); | ||
1995 | + | ||
1996 | +int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata); | ||
1997 | + | ||
1998 | +void isph3a_save_context(void); | ||
1999 | + | ||
2000 | +void isph3a_restore_context(void); | ||
2001 | + | ||
2002 | +void isph3a_aewb_enable(u8 enable); | ||
2003 | + | ||
2004 | +int isph3a_aewb_busy(void); | ||
2005 | + | ||
2006 | +void isph3a_aewb_suspend(void); | ||
2007 | + | ||
2008 | +void isph3a_aewb_resume(void); | ||
2009 | + | ||
2010 | +void isph3a_update_wb(void); | ||
2011 | + | ||
2012 | +void isph3a_notify(int notify); | ||
2013 | +#endif /* OMAP_ISP_H3A_H */ | ||
2014 | diff --git a/drivers/media/video/isp/isphist.c b/drivers/media/video/isp/isphist.c | ||
2015 | new file mode 100644 | ||
2016 | index 0000000..c6f6a77 | ||
2017 | --- /dev/null | ||
2018 | +++ b/drivers/media/video/isp/isphist.c | ||
2019 | @@ -0,0 +1,608 @@ | ||
2020 | +/* | ||
2021 | + * isphist.c | ||
2022 | + * | ||
2023 | + * HISTOGRAM module for TI's OMAP3 Camera ISP | ||
2024 | + * | ||
2025 | + * Copyright (C) 2009 Texas Instruments, Inc. | ||
2026 | + * | ||
2027 | + * Contributors: | ||
2028 | + * Sergio Aguirre <saaguirre@ti.com> | ||
2029 | + * Troy Laramy | ||
2030 | + * | ||
2031 | + * This package is free software; you can redistribute it and/or modify | ||
2032 | + * it under the terms of the GNU General Public License version 2 as | ||
2033 | + * published by the Free Software Foundation. | ||
2034 | + * | ||
2035 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
2036 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
2037 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
2038 | + */ | ||
2039 | + | ||
2040 | +#include <asm/cacheflush.h> | ||
2041 | + | ||
2042 | +#include <linux/delay.h> | ||
2043 | +#include <linux/dma-mapping.h> | ||
2044 | +#include <linux/uaccess.h> | ||
2045 | + | ||
2046 | +#include "isp.h" | ||
2047 | +#include "ispreg.h" | ||
2048 | +#include "isphist.h" | ||
2049 | +#include "ispmmu.h" | ||
2050 | + | ||
2051 | +/** | ||
2052 | + * struct isp_hist_status - Histogram status. | ||
2053 | + * @hist_enable: Enables the histogram module. | ||
2054 | + * @initialized: Flag to indicate that the module is correctly initializated. | ||
2055 | + * @frame_cnt: Actual frame count. | ||
2056 | + * @frame_req: Frame requested by user. | ||
2057 | + * @completed: Flag to indicate if a frame request is completed. | ||
2058 | + */ | ||
2059 | +struct isp_hist_status { | ||
2060 | + u8 hist_enable; | ||
2061 | + u8 pm_state; | ||
2062 | + u8 initialized; | ||
2063 | + u8 frame_cnt; | ||
2064 | + u8 frame_req; | ||
2065 | + u8 completed; | ||
2066 | +} histstat; | ||
2067 | + | ||
2068 | +/** | ||
2069 | + * struct isp_hist_buffer - Frame histogram buffer. | ||
2070 | + * @virt_addr: Virtual address to mmap the buffer. | ||
2071 | + * @phy_addr: Physical address of the buffer. | ||
2072 | + * @addr_align: Virtual Address 32 bytes aligned. | ||
2073 | + * @ispmmu_addr: Address of the buffer mapped by the ISPMMU. | ||
2074 | + * @mmap_addr: Mapped memory area of buffer. For userspace access. | ||
2075 | + */ | ||
2076 | +struct isp_hist_buffer { | ||
2077 | + unsigned long virt_addr; | ||
2078 | + unsigned long phy_addr; | ||
2079 | + unsigned long addr_align; | ||
2080 | + unsigned long ispmmu_addr; | ||
2081 | + unsigned long mmap_addr; | ||
2082 | +} hist_buff; | ||
2083 | + | ||
2084 | +/** | ||
2085 | + * struct isp_hist_regs - Current value of Histogram configuration registers. | ||
2086 | + * @reg_pcr: Peripheral control register. | ||
2087 | + * @reg_cnt: Histogram control register. | ||
2088 | + * @reg_wb_gain: Histogram white balance gain register. | ||
2089 | + * @reg_r0_h: Region 0 horizontal register. | ||
2090 | + * @reg_r0_v: Region 0 vertical register. | ||
2091 | + * @reg_r1_h: Region 1 horizontal register. | ||
2092 | + * @reg_r1_v: Region 1 vertical register. | ||
2093 | + * @reg_r2_h: Region 2 horizontal register. | ||
2094 | + * @reg_r2_v: Region 2 vertical register. | ||
2095 | + * @reg_r3_h: Region 3 horizontal register. | ||
2096 | + * @reg_r3_v: Region 3 vertical register. | ||
2097 | + * @reg_hist_addr: Histogram address register. | ||
2098 | + * @reg_hist_data: Histogram data. | ||
2099 | + * @reg_hist_radd: Address register. When input data comes from mem. | ||
2100 | + * @reg_hist_radd_off: Address offset register. When input data comes from mem. | ||
2101 | + * @reg_h_v_info: Image size register. When input data comes from mem. | ||
2102 | + */ | ||
2103 | +static struct isp_hist_regs { | ||
2104 | + u32 reg_pcr; | ||
2105 | + u32 reg_cnt; | ||
2106 | + u32 reg_wb_gain; | ||
2107 | + u32 reg_r0_h; | ||
2108 | + u32 reg_r0_v; | ||
2109 | + u32 reg_r1_h; | ||
2110 | + u32 reg_r1_v; | ||
2111 | + u32 reg_r2_h; | ||
2112 | + u32 reg_r2_v; | ||
2113 | + u32 reg_r3_h; | ||
2114 | + u32 reg_r3_v; | ||
2115 | + u32 reg_hist_addr; | ||
2116 | + u32 reg_hist_data; | ||
2117 | + u32 reg_hist_radd; | ||
2118 | + u32 reg_hist_radd_off; | ||
2119 | + u32 reg_h_v_info; | ||
2120 | +} hist_regs; | ||
2121 | + | ||
2122 | +/* Structure for saving/restoring histogram module registers */ | ||
2123 | +struct isp_reg isphist_reg_list[] = { | ||
2124 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, 0}, | ||
2125 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN, 0}, | ||
2126 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ, 0}, | ||
2127 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT, 0}, | ||
2128 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ, 0}, | ||
2129 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT, 0}, | ||
2130 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ, 0}, | ||
2131 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT, 0}, | ||
2132 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ, 0}, | ||
2133 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT, 0}, | ||
2134 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR, 0}, | ||
2135 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD, 0}, | ||
2136 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF, 0}, | ||
2137 | + {OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO, 0}, | ||
2138 | + {0, ISP_TOK_TERM, 0} | ||
2139 | +}; | ||
2140 | + | ||
2141 | +static void isp_hist_print_status(void); | ||
2142 | + | ||
2143 | +void __isp_hist_enable(u8 enable) | ||
2144 | +{ | ||
2145 | + if (enable) | ||
2146 | + DPRINTK_ISPHIST(" histogram enabled \n"); | ||
2147 | + else | ||
2148 | + DPRINTK_ISPHIST(" histogram disabled \n"); | ||
2149 | + | ||
2150 | + isp_reg_and_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ~ISPHIST_PCR_EN, | ||
2151 | + (enable ? ISPHIST_PCR_EN : 0)); | ||
2152 | + histstat.hist_enable = enable; | ||
2153 | +} | ||
2154 | + | ||
2155 | +/** | ||
2156 | + * isp_hist_enable - Enables ISP Histogram submodule operation. | ||
2157 | + * @enable: 1 - Enables the histogram submodule. | ||
2158 | + * | ||
2159 | + * Client should configure all the Histogram registers before calling this | ||
2160 | + * function. | ||
2161 | + **/ | ||
2162 | +void isp_hist_enable(u8 enable) | ||
2163 | +{ | ||
2164 | + __isp_hist_enable(enable); | ||
2165 | + histstat.pm_state = enable; | ||
2166 | +} | ||
2167 | + | ||
2168 | +/** | ||
2169 | + * isp_hist_suspend - Suspend ISP Histogram submodule. | ||
2170 | + **/ | ||
2171 | +void isp_hist_suspend(void) | ||
2172 | +{ | ||
2173 | + if (histstat.pm_state) | ||
2174 | + __isp_hist_enable(0); | ||
2175 | +} | ||
2176 | + | ||
2177 | +/** | ||
2178 | + * isp_hist_resume - Resume ISP Histogram submodule. | ||
2179 | + **/ | ||
2180 | +void isp_hist_resume(void) | ||
2181 | +{ | ||
2182 | + if (histstat.pm_state) | ||
2183 | + __isp_hist_enable(1); | ||
2184 | +} | ||
2185 | + | ||
2186 | +int isp_hist_busy(void) | ||
2187 | +{ | ||
2188 | + return isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR) & | ||
2189 | + ISPHIST_PCR_BUSY; | ||
2190 | +} | ||
2191 | + | ||
2192 | + | ||
2193 | +/** | ||
2194 | + * isp_hist_update_regs - Helper function to update Histogram registers. | ||
2195 | + **/ | ||
2196 | +static void isp_hist_update_regs(void) | ||
2197 | +{ | ||
2198 | + isp_reg_writel(hist_regs.reg_pcr, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR); | ||
2199 | + isp_reg_writel(hist_regs.reg_cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT); | ||
2200 | + isp_reg_writel(hist_regs.reg_wb_gain, OMAP3_ISP_IOMEM_HIST, | ||
2201 | + ISPHIST_WB_GAIN); | ||
2202 | + isp_reg_writel(hist_regs.reg_r0_h, OMAP3_ISP_IOMEM_HIST, | ||
2203 | + ISPHIST_R0_HORZ); | ||
2204 | + isp_reg_writel(hist_regs.reg_r0_v, OMAP3_ISP_IOMEM_HIST, | ||
2205 | + ISPHIST_R0_VERT); | ||
2206 | + isp_reg_writel(hist_regs.reg_r1_h, OMAP3_ISP_IOMEM_HIST, | ||
2207 | + ISPHIST_R1_HORZ); | ||
2208 | + isp_reg_writel(hist_regs.reg_r1_v, OMAP3_ISP_IOMEM_HIST, | ||
2209 | + ISPHIST_R1_VERT); | ||
2210 | + isp_reg_writel(hist_regs.reg_r2_h, OMAP3_ISP_IOMEM_HIST, | ||
2211 | + ISPHIST_R2_HORZ); | ||
2212 | + isp_reg_writel(hist_regs.reg_r2_v, OMAP3_ISP_IOMEM_HIST, | ||
2213 | + ISPHIST_R2_VERT); | ||
2214 | + isp_reg_writel(hist_regs.reg_r3_h, OMAP3_ISP_IOMEM_HIST, | ||
2215 | + ISPHIST_R3_HORZ); | ||
2216 | + isp_reg_writel(hist_regs.reg_r3_v, OMAP3_ISP_IOMEM_HIST, | ||
2217 | + ISPHIST_R3_VERT); | ||
2218 | + isp_reg_writel(hist_regs.reg_hist_addr, OMAP3_ISP_IOMEM_HIST, | ||
2219 | + ISPHIST_ADDR); | ||
2220 | + isp_reg_writel(hist_regs.reg_hist_data, OMAP3_ISP_IOMEM_HIST, | ||
2221 | + ISPHIST_DATA); | ||
2222 | + isp_reg_writel(hist_regs.reg_hist_radd, OMAP3_ISP_IOMEM_HIST, | ||
2223 | + ISPHIST_RADD); | ||
2224 | + isp_reg_writel(hist_regs.reg_hist_radd_off, OMAP3_ISP_IOMEM_HIST, | ||
2225 | + ISPHIST_RADD_OFF); | ||
2226 | + isp_reg_writel(hist_regs.reg_h_v_info, OMAP3_ISP_IOMEM_HIST, | ||
2227 | + ISPHIST_H_V_INFO); | ||
2228 | +} | ||
2229 | + | ||
2230 | +/** | ||
2231 | + * isp_hist_isr - Callback from ISP driver for HIST interrupt. | ||
2232 | + * @status: IRQ0STATUS in case of MMU error, 0 for hist interrupt. | ||
2233 | + * arg1 and arg2 Not used as of now. | ||
2234 | + **/ | ||
2235 | +static void isp_hist_isr(unsigned long status, isp_vbq_callback_ptr arg1, | ||
2236 | + void *arg2) | ||
2237 | +{ | ||
2238 | + isp_hist_enable(0); | ||
2239 | + | ||
2240 | + if (!(status & HIST_DONE)) | ||
2241 | + return; | ||
2242 | + | ||
2243 | + if (!histstat.completed) { | ||
2244 | + if (histstat.frame_req == histstat.frame_cnt) { | ||
2245 | + histstat.frame_cnt = 0; | ||
2246 | + histstat.frame_req = 0; | ||
2247 | + histstat.completed = 1; | ||
2248 | + } else { | ||
2249 | + isp_hist_enable(1); | ||
2250 | + histstat.frame_cnt++; | ||
2251 | + } | ||
2252 | + } | ||
2253 | +} | ||
2254 | + | ||
2255 | +/** | ||
2256 | + * isp_hist_reset_mem - clear Histogram memory before start stats engine. | ||
2257 | + * | ||
2258 | + * Returns 0 after histogram memory was cleared. | ||
2259 | + **/ | ||
2260 | +static int isp_hist_reset_mem(void) | ||
2261 | +{ | ||
2262 | + int i; | ||
2263 | + | ||
2264 | + isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN); | ||
2265 | + | ||
2266 | + for (i = 0; i < HIST_MEM_SIZE; i++) | ||
2267 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); | ||
2268 | + | ||
2269 | + isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ~ISPHIST_CNT_CLR_EN); | ||
2270 | + | ||
2271 | + return 0; | ||
2272 | +} | ||
2273 | + | ||
2274 | +/** | ||
2275 | + * isp_hist_set_params - Helper function to check and store user given params. | ||
2276 | + * @user_cfg: Pointer to user configuration structure. | ||
2277 | + * | ||
2278 | + * Returns 0 on success configuration. | ||
2279 | + **/ | ||
2280 | +static int isp_hist_set_params(struct isp_hist_config *user_cfg) | ||
2281 | +{ | ||
2282 | + | ||
2283 | + int reg_num = 0; | ||
2284 | + int bit_shift = 0; | ||
2285 | + | ||
2286 | + | ||
2287 | + if (isp_hist_busy()) | ||
2288 | + return -EINVAL; | ||
2289 | + | ||
2290 | + if (user_cfg->input_bit_width > MIN_BIT_WIDTH) | ||
2291 | + WRITE_DATA_SIZE(hist_regs.reg_cnt, 0); | ||
2292 | + else | ||
2293 | + WRITE_DATA_SIZE(hist_regs.reg_cnt, 1); | ||
2294 | + | ||
2295 | + WRITE_SOURCE(hist_regs.reg_cnt, user_cfg->hist_source); | ||
2296 | + | ||
2297 | + if (user_cfg->hist_source) { | ||
2298 | + WRITE_HV_INFO(hist_regs.reg_h_v_info, user_cfg->hist_h_v_info); | ||
2299 | + | ||
2300 | + if ((user_cfg->hist_radd & ISP_32B_BOUNDARY_BUF) == | ||
2301 | + user_cfg->hist_radd) { | ||
2302 | + WRITE_RADD(hist_regs.reg_hist_radd, | ||
2303 | + user_cfg->hist_radd); | ||
2304 | + } else { | ||
2305 | + printk(KERN_ERR "Address should be in 32 byte boundary" | ||
2306 | + "\n"); | ||
2307 | + return -EINVAL; | ||
2308 | + } | ||
2309 | + | ||
2310 | + if ((user_cfg->hist_radd_off & ISP_32B_BOUNDARY_OFFSET) == | ||
2311 | + user_cfg->hist_radd_off) { | ||
2312 | + WRITE_RADD_OFF(hist_regs.reg_hist_radd_off, | ||
2313 | + user_cfg->hist_radd_off); | ||
2314 | + } else { | ||
2315 | + printk(KERN_ERR "Offset should be in 32 byte boundary" | ||
2316 | + "\n"); | ||
2317 | + return -EINVAL; | ||
2318 | + } | ||
2319 | + | ||
2320 | + } | ||
2321 | + | ||
2322 | + isp_hist_reset_mem(); | ||
2323 | + DPRINTK_ISPHIST("ISPHIST: Memory Cleared\n"); | ||
2324 | + histstat.frame_req = user_cfg->hist_frames; | ||
2325 | + | ||
2326 | + if (unlikely(user_cfg->wb_gain_R > MAX_WB_GAIN || | ||
2327 | + user_cfg->wb_gain_RG > MAX_WB_GAIN || | ||
2328 | + user_cfg->wb_gain_B > MAX_WB_GAIN || | ||
2329 | + user_cfg->wb_gain_BG > MAX_WB_GAIN)) { | ||
2330 | + printk(KERN_ERR "Invalid WB gain\n"); | ||
2331 | + return -EINVAL; | ||
2332 | + } else { | ||
2333 | + WRITE_WB_R(hist_regs.reg_wb_gain, user_cfg->wb_gain_R); | ||
2334 | + WRITE_WB_RG(hist_regs.reg_wb_gain, user_cfg->wb_gain_RG); | ||
2335 | + WRITE_WB_B(hist_regs.reg_wb_gain, user_cfg->wb_gain_B); | ||
2336 | + WRITE_WB_BG(hist_regs.reg_wb_gain, user_cfg->wb_gain_BG); | ||
2337 | + } | ||
2338 | + | ||
2339 | + /* Regions size and position */ | ||
2340 | + | ||
2341 | + if (user_cfg->num_regions > MAX_REGIONS) | ||
2342 | + return -EINVAL; | ||
2343 | + | ||
2344 | + if (likely((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HEND_MASK) - | ||
2345 | + ((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HSTART_MASK) >> | ||
2346 | + ISPHIST_REGHORIZ_HSTART_SHIFT))) { | ||
2347 | + WRITE_REG_HORIZ(hist_regs.reg_r0_h, user_cfg->reg0_hor); | ||
2348 | + reg_num++; | ||
2349 | + } else { | ||
2350 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2351 | + return -EINVAL; | ||
2352 | + } | ||
2353 | + | ||
2354 | + if (likely((user_cfg->reg0_ver & ISPHIST_REGVERT_VEND_MASK) - | ||
2355 | + ((user_cfg->reg0_ver & ISPHIST_REGVERT_VSTART_MASK) >> | ||
2356 | + ISPHIST_REGVERT_VSTART_SHIFT))) { | ||
2357 | + WRITE_REG_VERT(hist_regs.reg_r0_v, user_cfg->reg0_ver); | ||
2358 | + } else { | ||
2359 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2360 | + return -EINVAL; | ||
2361 | + } | ||
2362 | + | ||
2363 | + if (user_cfg->num_regions >= 1) { | ||
2364 | + if (likely((user_cfg->reg1_hor & ISPHIST_REGHORIZ_HEND_MASK) - | ||
2365 | + ((user_cfg->reg1_hor & | ||
2366 | + ISPHIST_REGHORIZ_HSTART_MASK) >> | ||
2367 | + ISPHIST_REGHORIZ_HSTART_SHIFT))) { | ||
2368 | + WRITE_REG_HORIZ(hist_regs.reg_r1_h, user_cfg->reg1_hor); | ||
2369 | + } else { | ||
2370 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2371 | + return -EINVAL; | ||
2372 | + } | ||
2373 | + | ||
2374 | + if (likely((user_cfg->reg1_ver & ISPHIST_REGVERT_VEND_MASK) - | ||
2375 | + ((user_cfg->reg1_ver & | ||
2376 | + ISPHIST_REGVERT_VSTART_MASK) >> | ||
2377 | + ISPHIST_REGVERT_VSTART_SHIFT))) { | ||
2378 | + WRITE_REG_VERT(hist_regs.reg_r1_v, user_cfg->reg1_ver); | ||
2379 | + } else { | ||
2380 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2381 | + return -EINVAL; | ||
2382 | + } | ||
2383 | + } | ||
2384 | + | ||
2385 | + if (user_cfg->num_regions >= 2) { | ||
2386 | + if (likely((user_cfg->reg2_hor & ISPHIST_REGHORIZ_HEND_MASK) - | ||
2387 | + ((user_cfg->reg2_hor & | ||
2388 | + ISPHIST_REGHORIZ_HSTART_MASK) >> | ||
2389 | + ISPHIST_REGHORIZ_HSTART_SHIFT))) { | ||
2390 | + WRITE_REG_HORIZ(hist_regs.reg_r2_h, user_cfg->reg2_hor); | ||
2391 | + } else { | ||
2392 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2393 | + return -EINVAL; | ||
2394 | + } | ||
2395 | + | ||
2396 | + if (likely((user_cfg->reg2_ver & ISPHIST_REGVERT_VEND_MASK) - | ||
2397 | + ((user_cfg->reg2_ver & | ||
2398 | + ISPHIST_REGVERT_VSTART_MASK) >> | ||
2399 | + ISPHIST_REGVERT_VSTART_SHIFT))) { | ||
2400 | + WRITE_REG_VERT(hist_regs.reg_r2_v, user_cfg->reg2_ver); | ||
2401 | + } else { | ||
2402 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2403 | + return -EINVAL; | ||
2404 | + } | ||
2405 | + } | ||
2406 | + | ||
2407 | + if (user_cfg->num_regions >= 3) { | ||
2408 | + if (likely((user_cfg->reg3_hor & ISPHIST_REGHORIZ_HEND_MASK) - | ||
2409 | + ((user_cfg->reg3_hor & | ||
2410 | + ISPHIST_REGHORIZ_HSTART_MASK) >> | ||
2411 | + ISPHIST_REGHORIZ_HSTART_SHIFT))) { | ||
2412 | + WRITE_REG_HORIZ(hist_regs.reg_r3_h, user_cfg->reg3_hor); | ||
2413 | + } else { | ||
2414 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2415 | + return -EINVAL; | ||
2416 | + } | ||
2417 | + | ||
2418 | + if (likely((user_cfg->reg3_ver & ISPHIST_REGVERT_VEND_MASK) - | ||
2419 | + ((user_cfg->reg3_ver & | ||
2420 | + ISPHIST_REGVERT_VSTART_MASK) >> | ||
2421 | + ISPHIST_REGVERT_VSTART_SHIFT))) { | ||
2422 | + WRITE_REG_VERT(hist_regs.reg_r3_v, user_cfg->reg3_ver); | ||
2423 | + } else { | ||
2424 | + printk(KERN_ERR "Invalid Region parameters\n"); | ||
2425 | + return -EINVAL; | ||
2426 | + } | ||
2427 | + } | ||
2428 | + reg_num = user_cfg->num_regions; | ||
2429 | + if (unlikely(((user_cfg->hist_bins > BINS_256) && | ||
2430 | + (user_cfg->hist_bins != BINS_32)) || | ||
2431 | + ((user_cfg->hist_bins == BINS_256) && | ||
2432 | + reg_num != 0) || ((user_cfg->hist_bins == | ||
2433 | + BINS_128) && reg_num >= 2))) { | ||
2434 | + printk(KERN_ERR "Invalid Bins Number: %d\n", | ||
2435 | + user_cfg->hist_bins); | ||
2436 | + return -EINVAL; | ||
2437 | + } else { | ||
2438 | + WRITE_NUM_BINS(hist_regs.reg_cnt, user_cfg->hist_bins); | ||
2439 | + } | ||
2440 | + | ||
2441 | + if (user_cfg->input_bit_width > MAX_BIT_WIDTH || | ||
2442 | + user_cfg->input_bit_width < MIN_BIT_WIDTH) { | ||
2443 | + printk(KERN_ERR "Invalid Bit Width: %d\n", | ||
2444 | + user_cfg->input_bit_width); | ||
2445 | + return -EINVAL; | ||
2446 | + } else { | ||
2447 | + switch (user_cfg->hist_bins) { | ||
2448 | + case BINS_256: | ||
2449 | + bit_shift = user_cfg->input_bit_width - 8; | ||
2450 | + break; | ||
2451 | + case BINS_128: | ||
2452 | + bit_shift = user_cfg->input_bit_width - 7; | ||
2453 | + break; | ||
2454 | + case BINS_64: | ||
2455 | + bit_shift = user_cfg->input_bit_width - 6; | ||
2456 | + break; | ||
2457 | + case BINS_32: | ||
2458 | + bit_shift = user_cfg->input_bit_width - 5; | ||
2459 | + break; | ||
2460 | + default: | ||
2461 | + return -EINVAL; | ||
2462 | + } | ||
2463 | + WRITE_BIT_SHIFT(hist_regs.reg_cnt, bit_shift); | ||
2464 | + } | ||
2465 | + | ||
2466 | + isp_hist_update_regs(); | ||
2467 | + histstat.initialized = 1; | ||
2468 | + | ||
2469 | + return 0; | ||
2470 | +} | ||
2471 | + | ||
2472 | +/** | ||
2473 | + * isp_hist_configure - API to configure HIST registers. | ||
2474 | + * @histcfg: Pointer to user configuration structure. | ||
2475 | + * | ||
2476 | + * Returns 0 on success configuration. | ||
2477 | + **/ | ||
2478 | +int isp_hist_configure(struct isp_hist_config *histcfg) | ||
2479 | +{ | ||
2480 | + | ||
2481 | + int ret = 0; | ||
2482 | + | ||
2483 | + if (NULL == histcfg) { | ||
2484 | + printk(KERN_ERR "Null argument in configuration. \n"); | ||
2485 | + return -EINVAL; | ||
2486 | + } | ||
2487 | + | ||
2488 | + if (!histstat.initialized) { | ||
2489 | + DPRINTK_ISPHIST("Setting callback for HISTOGRAM\n"); | ||
2490 | + ret = isp_set_callback(CBK_HIST_DONE, isp_hist_isr, | ||
2491 | + (void *)NULL, (void *)NULL); | ||
2492 | + if (ret) { | ||
2493 | + printk(KERN_ERR "No callback for HIST\n"); | ||
2494 | + return ret; | ||
2495 | + } | ||
2496 | + } | ||
2497 | + | ||
2498 | + ret = isp_hist_set_params(histcfg); | ||
2499 | + if (ret) { | ||
2500 | + printk(KERN_ERR "Invalid parameters! \n"); | ||
2501 | + return ret; | ||
2502 | + } | ||
2503 | + | ||
2504 | + histstat.frame_cnt = 0; | ||
2505 | + histstat.completed = 0; | ||
2506 | + isp_hist_enable(1); | ||
2507 | + isp_hist_print_status(); | ||
2508 | + | ||
2509 | + return 0; | ||
2510 | +} | ||
2511 | +EXPORT_SYMBOL(isp_hist_configure); | ||
2512 | + | ||
2513 | +/** | ||
2514 | + * isp_hist_request_statistics - Request statistics in Histogram. | ||
2515 | + * @histdata: Pointer to data structure. | ||
2516 | + * | ||
2517 | + * This API allows the user to request for histogram statistics. | ||
2518 | + * | ||
2519 | + * Returns 0 on successful request. | ||
2520 | + **/ | ||
2521 | +int isp_hist_request_statistics(struct isp_hist_data *histdata) | ||
2522 | +{ | ||
2523 | + int i, ret; | ||
2524 | + u32 curr; | ||
2525 | + | ||
2526 | + if (isp_hist_busy()) | ||
2527 | + return -EBUSY; | ||
2528 | + | ||
2529 | + if (!histstat.completed && histstat.initialized) | ||
2530 | + return -EINVAL; | ||
2531 | + | ||
2532 | + isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN); | ||
2533 | + | ||
2534 | + for (i = 0; i < HIST_MEM_SIZE; i++) { | ||
2535 | + curr = isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); | ||
2536 | + ret = put_user(curr, histdata->hist_statistics_buf + i); | ||
2537 | + if (ret) { | ||
2538 | + printk(KERN_ERR "Failed copy_to_user for " | ||
2539 | + "HIST stats buff, %d\n", ret); | ||
2540 | + } | ||
2541 | + } | ||
2542 | + | ||
2543 | + isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, | ||
2544 | + ~ISPHIST_CNT_CLR_EN); | ||
2545 | + histstat.completed = 0; | ||
2546 | + return 0; | ||
2547 | +} | ||
2548 | +EXPORT_SYMBOL(isp_hist_request_statistics); | ||
2549 | + | ||
2550 | +/** | ||
2551 | + * isp_hist_init - Module Initialization. | ||
2552 | + * | ||
2553 | + * Returns 0 if successful. | ||
2554 | + **/ | ||
2555 | +int __init isp_hist_init(void) | ||
2556 | +{ | ||
2557 | + memset(&histstat, 0, sizeof(histstat)); | ||
2558 | + memset(&hist_regs, 0, sizeof(hist_regs)); | ||
2559 | + | ||
2560 | + return 0; | ||
2561 | +} | ||
2562 | + | ||
2563 | +/** | ||
2564 | + * isp_hist_cleanup - Module cleanup. | ||
2565 | + **/ | ||
2566 | +void isp_hist_cleanup(void) | ||
2567 | +{ | ||
2568 | + memset(&histstat, 0, sizeof(histstat)); | ||
2569 | + memset(&hist_regs, 0, sizeof(hist_regs)); | ||
2570 | +} | ||
2571 | + | ||
2572 | +/** | ||
2573 | + * isphist_save_context - Saves the values of the histogram module registers. | ||
2574 | + **/ | ||
2575 | +void isphist_save_context(void) | ||
2576 | +{ | ||
2577 | + DPRINTK_ISPHIST(" Saving context\n"); | ||
2578 | + isp_save_context(isphist_reg_list); | ||
2579 | +} | ||
2580 | +EXPORT_SYMBOL(isphist_save_context); | ||
2581 | + | ||
2582 | +/** | ||
2583 | + * isphist_restore_context - Restores the values of the histogram module regs. | ||
2584 | + **/ | ||
2585 | +void isphist_restore_context(void) | ||
2586 | +{ | ||
2587 | + DPRINTK_ISPHIST(" Restoring context\n"); | ||
2588 | + isp_restore_context(isphist_reg_list); | ||
2589 | +} | ||
2590 | +EXPORT_SYMBOL(isphist_restore_context); | ||
2591 | + | ||
2592 | +/** | ||
2593 | + * isp_hist_print_status - Debug print | ||
2594 | + **/ | ||
2595 | +static void isp_hist_print_status(void) | ||
2596 | +{ | ||
2597 | + DPRINTK_ISPHIST("ISPHIST_PCR = 0x%08x\n", | ||
2598 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)); | ||
2599 | + DPRINTK_ISPHIST("ISPHIST_CNT = 0x%08x\n", | ||
2600 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT)); | ||
2601 | + DPRINTK_ISPHIST("ISPHIST_WB_GAIN = 0x%08x\n", | ||
2602 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN)); | ||
2603 | + DPRINTK_ISPHIST("ISPHIST_R0_HORZ = 0x%08x\n", | ||
2604 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ)); | ||
2605 | + DPRINTK_ISPHIST("ISPHIST_R0_VERT = 0x%08x\n", | ||
2606 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT)); | ||
2607 | + DPRINTK_ISPHIST("ISPHIST_R1_HORZ = 0x%08x\n", | ||
2608 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ)); | ||
2609 | + DPRINTK_ISPHIST("ISPHIST_R1_VERT = 0x%08x\n", | ||
2610 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT)); | ||
2611 | + DPRINTK_ISPHIST("ISPHIST_R2_HORZ = 0x%08x\n", | ||
2612 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ)); | ||
2613 | + DPRINTK_ISPHIST("ISPHIST_R2_VERT = 0x%08x\n", | ||
2614 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT)); | ||
2615 | + DPRINTK_ISPHIST("ISPHIST_R3_HORZ = 0x%08x\n", | ||
2616 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ)); | ||
2617 | + DPRINTK_ISPHIST("ISPHIST_R3_VERT = 0x%08x\n", | ||
2618 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT)); | ||
2619 | + DPRINTK_ISPHIST("ISPHIST_ADDR = 0x%08x\n", | ||
2620 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR)); | ||
2621 | + DPRINTK_ISPHIST("ISPHIST_RADD = 0x%08x\n", | ||
2622 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD)); | ||
2623 | + DPRINTK_ISPHIST("ISPHIST_RADD_OFF = 0x%08x\n", | ||
2624 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF)); | ||
2625 | + DPRINTK_ISPHIST("ISPHIST_H_V_INFO = 0x%08x\n", | ||
2626 | + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO)); | ||
2627 | +} | ||
2628 | diff --git a/drivers/media/video/isp/isphist.h b/drivers/media/video/isp/isphist.h | ||
2629 | new file mode 100644 | ||
2630 | index 0000000..6b17c4e | ||
2631 | --- /dev/null | ||
2632 | +++ b/drivers/media/video/isp/isphist.h | ||
2633 | @@ -0,0 +1,105 @@ | ||
2634 | +/* | ||
2635 | + * isphist.h | ||
2636 | + * | ||
2637 | + * Header file for HISTOGRAM module in TI's OMAP3 Camera ISP | ||
2638 | + * | ||
2639 | + * Copyright (C) 2009 Texas Instruments, Inc. | ||
2640 | + * | ||
2641 | + * Contributors: | ||
2642 | + * Sergio Aguirre <saaguirre@ti.com> | ||
2643 | + * Troy Laramy | ||
2644 | + * | ||
2645 | + * This package is free software; you can redistribute it and/or modify | ||
2646 | + * it under the terms of the GNU General Public License version 2 as | ||
2647 | + * published by the Free Software Foundation. | ||
2648 | + * | ||
2649 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
2650 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
2651 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
2652 | + */ | ||
2653 | + | ||
2654 | +#ifndef OMAP_ISP_HIST_H | ||
2655 | +#define OMAP_ISP_HIST_H | ||
2656 | + | ||
2657 | +#include <mach/isp_user.h> | ||
2658 | + | ||
2659 | +#define MAX_REGIONS 0x4 | ||
2660 | +#define MAX_WB_GAIN 255 | ||
2661 | +#define MIN_WB_GAIN 0x0 | ||
2662 | +#define MAX_BIT_WIDTH 14 | ||
2663 | +#define MIN_BIT_WIDTH 8 | ||
2664 | + | ||
2665 | +#define ISPHIST_PCR_EN (1 << 0) | ||
2666 | +#define HIST_MEM_SIZE 1024 | ||
2667 | +#define ISPHIST_CNT_CLR_EN (1 << 7) | ||
2668 | + | ||
2669 | +#define WRITE_SOURCE(reg, source) \ | ||
2670 | + (reg = (reg & ~(ISPHIST_CNT_SOURCE_MASK)) \ | ||
2671 | + | (source << ISPHIST_CNT_SOURCE_SHIFT)) | ||
2672 | + | ||
2673 | +#define WRITE_HV_INFO(reg, hv_info) \ | ||
2674 | + (reg = ((reg & ~(ISPHIST_HV_INFO_MASK)) \ | ||
2675 | + | (hv_info & ISPHIST_HV_INFO_MASK))) | ||
2676 | + | ||
2677 | +#define WRITE_RADD(reg, radd) \ | ||
2678 | + (reg = (reg & ~(ISPHIST_RADD_MASK)) \ | ||
2679 | + | (radd << ISPHIST_RADD_SHIFT)) | ||
2680 | + | ||
2681 | +#define WRITE_RADD_OFF(reg, radd_off) \ | ||
2682 | + (reg = (reg & ~(ISPHIST_RADD_OFF_MASK)) \ | ||
2683 | + | (radd_off << ISPHIST_RADD_OFF_SHIFT)) | ||
2684 | + | ||
2685 | +#define WRITE_BIT_SHIFT(reg, bit_shift) \ | ||
2686 | + (reg = (reg & ~(ISPHIST_CNT_SHIFT_MASK)) \ | ||
2687 | + | (bit_shift << ISPHIST_CNT_SHIFT_SHIFT)) | ||
2688 | + | ||
2689 | +#define WRITE_DATA_SIZE(reg, data_size) \ | ||
2690 | + (reg = (reg & ~(ISPHIST_CNT_DATASIZE_MASK)) \ | ||
2691 | + | (data_size << ISPHIST_CNT_DATASIZE_SHIFT)) | ||
2692 | + | ||
2693 | +#define WRITE_NUM_BINS(reg, num_bins) \ | ||
2694 | + (reg = (reg & ~(ISPHIST_CNT_BINS_MASK)) \ | ||
2695 | + | (num_bins << ISPHIST_CNT_BINS_SHIFT)) | ||
2696 | + | ||
2697 | +#define WRITE_WB_R(reg, reg_wb_gain) \ | ||
2698 | + reg = ((reg & ~(ISPHIST_WB_GAIN_WG00_MASK)) \ | ||
2699 | + | (reg_wb_gain << ISPHIST_WB_GAIN_WG00_SHIFT)) | ||
2700 | + | ||
2701 | +#define WRITE_WB_RG(reg, reg_wb_gain) \ | ||
2702 | + (reg = (reg & ~(ISPHIST_WB_GAIN_WG01_MASK)) \ | ||
2703 | + | (reg_wb_gain << ISPHIST_WB_GAIN_WG01_SHIFT)) | ||
2704 | + | ||
2705 | +#define WRITE_WB_B(reg, reg_wb_gain) \ | ||
2706 | + (reg = (reg & ~(ISPHIST_WB_GAIN_WG02_MASK)) \ | ||
2707 | + | (reg_wb_gain << ISPHIST_WB_GAIN_WG02_SHIFT)) | ||
2708 | + | ||
2709 | +#define WRITE_WB_BG(reg, reg_wb_gain) \ | ||
2710 | + (reg = (reg & ~(ISPHIST_WB_GAIN_WG03_MASK)) \ | ||
2711 | + | (reg_wb_gain << ISPHIST_WB_GAIN_WG03_SHIFT)) | ||
2712 | + | ||
2713 | +#define WRITE_REG_HORIZ(reg, reg_n_hor) \ | ||
2714 | + (reg = ((reg & ~ISPHIST_REGHORIZ_MASK) \ | ||
2715 | + | (reg_n_hor & ISPHIST_REGHORIZ_MASK))) | ||
2716 | + | ||
2717 | +#define WRITE_REG_VERT(reg, reg_n_vert) \ | ||
2718 | + (reg = ((reg & ~ISPHIST_REGVERT_MASK) \ | ||
2719 | + | (reg_n_vert & ISPHIST_REGVERT_MASK))) | ||
2720 | + | ||
2721 | + | ||
2722 | +void isp_hist_enable(u8 enable); | ||
2723 | + | ||
2724 | +int isp_hist_busy(void); | ||
2725 | + | ||
2726 | +int isp_hist_configure(struct isp_hist_config *histcfg); | ||
2727 | + | ||
2728 | +int isp_hist_request_statistics(struct isp_hist_data *histdata); | ||
2729 | + | ||
2730 | +void isphist_save_context(void); | ||
2731 | + | ||
2732 | +void isp_hist_suspend(void); | ||
2733 | + | ||
2734 | +void isp_hist_resume(void); | ||
2735 | + | ||
2736 | +void isphist_restore_context(void); | ||
2737 | + | ||
2738 | +#endif /* OMAP_ISP_HIST */ | ||
2739 | -- | ||
2740 | 1.5.6.5 | ||
2741 | |||