Full support for Ginger Console
[linux-ginger.git] / drivers / media / video / isp / ispccdc.c
blobac8478b8859333c4440a3c249256b717ed6f9d54
1 /*
2 * ispccdc.c
4 * Driver Library for CCDC module in TI's OMAP3 Camera ISP
6 * Copyright (C) 2009 Texas Instruments, Inc.
8 * Contributors:
9 * Senthilvadivu Guruswamy <svadivu@ti.com>
10 * Pallavi Kulkarni <p-kulkarni@ti.com>
11 * Sergio Aguirre <saaguirre@ti.com>
13 * This package is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
17 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 #include <linux/mutex.h>
23 #include <linux/module.h>
24 #include <linux/uaccess.h>
25 #include <linux/device.h>
27 #include "isp.h"
28 #include "ispreg.h"
29 #include "ispccdc.h"
31 #define LSC_TABLE_INIT_SIZE 50052
33 /* Structure for saving/restoring CCDC module registers*/
34 static struct isp_reg ispccdc_reg_list[] = {
35 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE, 0},
36 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HD_VD_WID, 0},
37 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PIX_LINES, 0},
38 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO, 0},
39 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START, 0},
40 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES, 0},
41 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CULLING, 0},
42 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF, 0},
43 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, 0},
44 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR, 0},
45 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP, 0},
46 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB, 0},
47 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN, 0},
48 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP, 0},
49 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR, 0},
50 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, 0},
51 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT, 0},
52 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW, 0},
53 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, 0},
54 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, 0},
55 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG, 0},
56 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ, 0},
57 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT, 0},
58 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR0, 0},
59 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR1, 0},
60 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR2, 0},
61 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR3, 0},
62 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR4, 0},
63 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR5, 0},
64 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR6, 0},
65 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR7, 0},
66 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGEVEN0, 0},
67 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGEVEN1, 0},
68 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGODD0, 0},
69 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGODD1, 0},
70 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT, 0},
71 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, 0},
72 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_INITIAL, 0},
73 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE, 0},
74 {OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_OFFSET, 0},
75 {0, ISP_TOK_TERM, 0}
78 /**
79 * omap34xx_isp_ccdc_config - Set CCDC configuration from userspace
80 * @isp_ccdc: Pointer to ISP CCDC device.
81 * @userspace_add: Structure containing CCDC configuration sent from userspace.
83 * Returns 0 if successful, -EINVAL if the pointer to the configuration
84 * structure is null, or the copy_from_user function fails to copy user space
85 * memory to kernel space memory.
86 **/
87 int omap34xx_isp_ccdc_config(struct isp_ccdc_device *isp_ccdc,
88 void *userspace_add)
90 struct isp_device *isp =
91 container_of(isp_ccdc, struct isp_device, isp_ccdc);
92 struct ispccdc_bclamp bclamp_t;
93 struct ispccdc_blcomp blcomp_t;
94 struct ispccdc_fpc fpc_t;
95 struct ispccdc_culling cull_t;
96 struct ispccdc_update_config *ccdc_struct;
98 if (userspace_add == NULL)
99 return -EINVAL;
101 ccdc_struct = userspace_add;
103 if (ISP_ABS_CCDC_ALAW & ccdc_struct->flag) {
104 if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
105 ispccdc_config_alaw(isp_ccdc, ccdc_struct->alawip);
106 ispccdc_enable_alaw(isp_ccdc, 1);
107 } else if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
108 ispccdc_enable_alaw(isp_ccdc, 0);
110 if (ISP_ABS_CCDC_LPF & ccdc_struct->flag)
111 ispccdc_enable_lpf(isp_ccdc, 1);
112 else
113 ispccdc_enable_lpf(isp_ccdc, 0);
115 if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->flag) {
116 if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
117 if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
118 ccdc_struct->bclamp,
119 sizeof(struct ispccdc_bclamp)))
120 goto copy_from_user_err;
122 ispccdc_enable_black_clamp(isp_ccdc, 1);
123 ispccdc_config_black_clamp(isp_ccdc, bclamp_t);
124 } else
125 ispccdc_enable_black_clamp(isp_ccdc, 1);
126 } else {
127 if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
128 if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
129 ccdc_struct->bclamp,
130 sizeof(struct ispccdc_bclamp)))
131 goto copy_from_user_err;
133 ispccdc_enable_black_clamp(isp_ccdc, 0);
134 ispccdc_config_black_clamp(isp_ccdc, bclamp_t);
138 if (ISP_ABS_CCDC_BCOMP & ccdc_struct->update) {
139 if (copy_from_user(&blcomp_t, (struct ispccdc_blcomp *)
140 ccdc_struct->blcomp,
141 sizeof(blcomp_t)))
142 goto copy_from_user_err;
144 ispccdc_config_black_comp(isp_ccdc, blcomp_t);
147 if (ISP_ABS_CCDC_FPC & ccdc_struct->flag) {
148 if (ISP_ABS_CCDC_FPC & ccdc_struct->update) {
149 if (copy_from_user(&fpc_t, (struct ispccdc_fpc *)
150 ccdc_struct->fpc,
151 sizeof(fpc_t)))
152 goto copy_from_user_err;
153 isp_ccdc->fpc_table_add = kmalloc(64 + fpc_t.fpnum * 4,
154 GFP_KERNEL | GFP_DMA);
155 if (!isp_ccdc->fpc_table_add) {
156 dev_err(isp_ccdc->dev,
157 "ccdc: Cannot allocate memory for"
158 " FPC table");
159 return -ENOMEM;
161 while (((unsigned long)isp_ccdc->fpc_table_add
162 & 0xFFFFFFC0)
163 != (unsigned long)isp_ccdc->fpc_table_add)
164 isp_ccdc->fpc_table_add++;
166 isp_ccdc->fpc_table_add_m = iommu_kmap(
167 isp->iommu,
169 virt_to_phys(isp_ccdc->fpc_table_add),
170 fpc_t.fpnum * 4,
171 IOMMU_FLAG);
172 /* FIXME: Correct unwinding */
173 BUG_ON(IS_ERR_VALUE(isp_ccdc->fpc_table_add_m));
175 if (copy_from_user(isp_ccdc->fpc_table_add,
176 (u32 *)fpc_t.fpcaddr,
177 fpc_t.fpnum * 4))
178 goto copy_from_user_err;
180 fpc_t.fpcaddr = isp_ccdc->fpc_table_add_m;
181 ispccdc_config_fpc(isp_ccdc, fpc_t);
183 ispccdc_enable_fpc(isp_ccdc, 1);
184 } else if (ISP_ABS_CCDC_FPC & ccdc_struct->update)
185 ispccdc_enable_fpc(isp_ccdc, 0);
187 if (ISP_ABS_CCDC_CULL & ccdc_struct->update) {
188 if (copy_from_user(&cull_t, (struct ispccdc_culling *)
189 ccdc_struct->cull,
190 sizeof(cull_t)))
191 goto copy_from_user_err;
192 ispccdc_config_culling(isp_ccdc, cull_t);
195 if (is_isplsc_activated()) {
196 if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->flag) {
197 if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
198 if (copy_from_user(
199 &isp_ccdc->lsc_config,
200 (struct ispccdc_lsc_config *)
201 ccdc_struct->lsc_cfg,
202 sizeof(struct ispccdc_lsc_config)))
203 goto copy_from_user_err;
204 ispccdc_config_lsc(isp_ccdc,
205 &isp_ccdc->lsc_config);
207 ispccdc_enable_lsc(isp_ccdc, 1);
208 } else if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
209 ispccdc_enable_lsc(isp_ccdc, 0);
211 if (ISP_ABS_TBL_LSC & ccdc_struct->update) {
212 if (copy_from_user(isp_ccdc->lsc_gain_table,
213 ccdc_struct->lsc,
214 isp_ccdc->lsc_config.size))
215 goto copy_from_user_err;
216 ispccdc_load_lsc(isp_ccdc, isp_ccdc->lsc_gain_table,
217 isp_ccdc->lsc_config.size);
221 if (ISP_ABS_CCDC_COLPTN & ccdc_struct->update)
222 ispccdc_config_imgattr(isp_ccdc, ccdc_struct->colptn);
224 return 0;
226 copy_from_user_err:
227 dev_err(isp_ccdc->dev, "ccdc: Config: copy from user error");
228 return -EINVAL ;
230 EXPORT_SYMBOL(omap34xx_isp_ccdc_config);
233 * ispccdc_set_wenlog - Set the CCDC Write Enable valid region.
234 * @isp_ccdc: Pointer to ISP CCDC device.
235 * @wenlog: Write enable logic to apply against valid area. 0 - AND, 1 - OR.
237 void ispccdc_set_wenlog(struct isp_ccdc_device *isp_ccdc, u32 wenlog)
239 isp_ccdc->wenlog = wenlog;
241 EXPORT_SYMBOL(ispccdc_set_wenlog);
244 * ispccdc_request - Reserve the CCDC module.
245 * @isp_ccdc: Pointer to ISP CCDC device.
247 * Returns 0 if successful, or -EBUSY if CCDC module is busy.
249 int ispccdc_request(struct isp_ccdc_device *isp_ccdc)
251 mutex_lock(&isp_ccdc->mutexlock);
252 if (isp_ccdc->ccdc_inuse) {
253 mutex_unlock(&isp_ccdc->mutexlock);
254 DPRINTK_ISPCCDC("ISP_ERR : CCDC Module Busy\n");
255 return -EBUSY;
258 isp_ccdc->ccdc_inuse = 1;
259 mutex_unlock(&isp_ccdc->mutexlock);
260 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
261 ISPCTRL_CCDC_RAM_EN | ISPCTRL_CCDC_CLK_EN |
262 ISPCTRL_SBL_WR1_RAM_EN);
263 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
264 ISPCCDC_CFG_VDLC);
265 return 0;
267 EXPORT_SYMBOL(ispccdc_request);
270 * ispccdc_free - Free the CCDC module.
271 * @isp_ccdc: Pointer to ISP CCDC device.
273 * Frees the CCDC module so it can be used by another process.
275 * Returns 0 if successful, or -EINVAL if module has been already freed.
277 int ispccdc_free(struct isp_ccdc_device *isp_ccdc)
279 mutex_lock(&isp_ccdc->mutexlock);
280 if (!isp_ccdc->ccdc_inuse) {
281 mutex_unlock(&isp_ccdc->mutexlock);
282 DPRINTK_ISPCCDC("ISP_ERR: CCDC Module already freed\n");
283 return -EINVAL;
286 isp_ccdc->ccdc_inuse = 0;
287 mutex_unlock(&isp_ccdc->mutexlock);
288 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
289 ~(ISPCTRL_CCDC_CLK_EN |
290 ISPCTRL_CCDC_RAM_EN |
291 ISPCTRL_SBL_WR1_RAM_EN));
292 return 0;
294 EXPORT_SYMBOL(ispccdc_free);
297 * ispccdc_free_lsc - Frees Lens Shading Compensation table
298 * @isp_ccdc: Pointer to ISP CCDC device.
300 * Always returns 0.
302 static int ispccdc_free_lsc(struct isp_ccdc_device *isp_ccdc)
304 struct isp_device *isp =
305 container_of(isp_ccdc, struct isp_device, isp_ccdc);
307 if (!isp_ccdc->lsc_ispmmu_addr)
308 return 0;
310 ispccdc_enable_lsc(isp_ccdc, 0);
311 isp_ccdc->lsc_initialized = 0;
312 isp_reg_writel(isp_ccdc->dev, 0, OMAP3_ISP_IOMEM_CCDC,
313 ISPCCDC_LSC_TABLE_BASE);
314 iommu_kunmap(isp->iommu, isp_ccdc->lsc_ispmmu_addr);
315 kfree(isp_ccdc->lsc_gain_table);
316 return 0;
320 * ispccdc_allocate_lsc - Allocate space for Lens Shading Compensation table
321 * @isp_ccdc: Pointer to ISP CCDC device.
322 * @table_size: LSC gain table size.
324 * Returns 0 if successful, -ENOMEM of its no memory available, or -EINVAL if
325 * table_size is zero.
327 static int ispccdc_allocate_lsc(struct isp_ccdc_device *isp_ccdc,
328 u32 table_size)
330 struct isp_device *isp =
331 container_of(isp_ccdc, struct isp_device, isp_ccdc);
333 if (table_size == 0)
334 return -EINVAL;
336 if ((isp_ccdc->lsc_config.size >= table_size)
337 && isp_ccdc->lsc_gain_table)
338 return 0;
340 ispccdc_free_lsc(isp_ccdc);
342 isp_ccdc->lsc_gain_table = kmalloc(table_size, GFP_KERNEL | GFP_DMA);
344 if (!isp_ccdc->lsc_gain_table) {
345 dev_err(isp_ccdc->dev,
346 "ccdc: Cannot allocate memory for gain tables\n");
347 return -ENOMEM;
350 isp_ccdc->lsc_ispmmu_addr =
351 iommu_kmap(isp->iommu,
353 virt_to_phys(isp_ccdc->lsc_gain_table),
354 table_size,
355 IOMMU_FLAG);
356 if (IS_ERR_VALUE(isp_ccdc->lsc_ispmmu_addr)) {
357 dev_err(isp_ccdc->dev,
358 "ccdc: Cannot map memory for gain tables\n");
359 kfree(isp_ccdc->lsc_gain_table);
360 return -ENOMEM;
363 return 0;
367 * ispccdc_program_lsc - Program Lens Shading Compensation table.
368 * @isp_ccdc: Pointer to ISP CCDC device.
370 * Returns 0 if successful, or -EINVAL if there's no mapped address for the
371 * table yet.
373 static int ispccdc_program_lsc(struct isp_ccdc_device *isp_ccdc)
375 if (!isp_ccdc->lsc_ispmmu_addr)
376 return -EINVAL;
378 if (isp_ccdc->lsc_initialized)
379 return 0;
381 isp_reg_writel(isp_ccdc->dev, isp_ccdc->lsc_ispmmu_addr,
382 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
383 isp_ccdc->lsc_initialized = 1;
384 return 0;
388 * ispccdc_load_lsc - Load Lens Shading Compensation table.
389 * @isp_ccdc: Pointer to ISP CCDC device.
390 * @table_addr: MMU Mapped address to LSC gain table.
391 * @table_size: LSC gain table size.
393 * Returns 0 if successful, -ENOMEM of its no memory available, or -EINVAL if
394 * table_size is zero.
396 int ispccdc_load_lsc(struct isp_ccdc_device *isp_ccdc, u8 *table_addr,
397 u32 table_size)
399 int ret;
401 if (!is_isplsc_activated())
402 return 0;
404 if (!table_addr)
405 return -EINVAL;
407 ret = ispccdc_allocate_lsc(isp_ccdc, table_size);
408 if (ret)
409 return ret;
411 if (table_addr != isp_ccdc->lsc_gain_table)
412 memcpy(isp_ccdc->lsc_gain_table, table_addr, table_size);
413 ret = ispccdc_program_lsc(isp_ccdc);
414 if (ret)
415 return ret;
416 return 0;
418 EXPORT_SYMBOL(ispccdc_load_lsc);
421 * ispccdc_config_lsc - Configures the lens shading compensation module
422 * @isp_ccdc: Pointer to ISP CCDC device.
423 * @lsc_cfg: Pointer to LSC configuration structure
425 void ispccdc_config_lsc(struct isp_ccdc_device *isp_ccdc,
426 struct ispccdc_lsc_config *lsc_cfg)
428 int reg;
430 if (!is_isplsc_activated())
431 return;
433 ispccdc_enable_lsc(isp_ccdc, 0);
434 isp_reg_writel(isp_ccdc->dev, lsc_cfg->offset, OMAP3_ISP_IOMEM_CCDC,
435 ISPCCDC_LSC_TABLE_OFFSET);
437 reg = 0;
438 reg |= lsc_cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
439 reg |= lsc_cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
440 reg |= lsc_cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
441 isp_reg_writel(isp_ccdc->dev, reg, OMAP3_ISP_IOMEM_CCDC,
442 ISPCCDC_LSC_CONFIG);
444 reg = 0;
445 reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
446 reg |= lsc_cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
447 reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
448 reg |= lsc_cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
449 isp_reg_writel(isp_ccdc->dev, reg, OMAP3_ISP_IOMEM_CCDC,
450 ISPCCDC_LSC_INITIAL);
452 EXPORT_SYMBOL(ispccdc_config_lsc);
455 * ispccdc_enable_lsc - Enables/Disables the Lens Shading Compensation module.
456 * @isp_ccdc: Pointer to ISP CCDC device.
457 * @enable: 0 Disables LSC, 1 Enables LSC.
459 void ispccdc_enable_lsc(struct isp_ccdc_device *isp_ccdc, u8 enable)
461 if (!is_isplsc_activated())
462 return;
464 if (enable) {
465 if (!ispccdc_busy(isp_ccdc)) {
466 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_MAIN,
467 ISP_CTRL, ISPCTRL_SBL_SHARED_RPORTB
468 | ISPCTRL_SBL_RD_RAM_EN);
470 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
471 ISPCCDC_LSC_CONFIG, 0x1);
473 isp_ccdc->lsc_state = 1;
474 } else {
475 /* Postpone enabling LSC */
476 isp_ccdc->lsc_enable = 1;
478 } else {
479 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
480 ISPCCDC_LSC_CONFIG, 0xFFFE);
481 isp_ccdc->lsc_state = 0;
482 isp_ccdc->lsc_enable = 0;
485 EXPORT_SYMBOL(ispccdc_enable_lsc);
488 * ispccdc_lsc_error_handler - Handle LSC prefetch error scenario.
489 * @isp_ccdc: Pointer to ISP CCDC device.
491 * Disables LSC, and defers enablement to shadow registers update time.
493 void ispccdc_lsc_error_handler(struct isp_ccdc_device *isp_ccdc)
495 int lsc_enable = isp_ccdc->lsc_state;
497 ispccdc_enable_lsc(isp_ccdc, 0);
499 isp_ccdc->lsc_enable = lsc_enable;
503 * ispccdc_config_crop - Configures crop parameters for the ISP CCDC.
504 * @isp_ccdc: Pointer to ISP CCDC device.
505 * @left: Left offset of the crop area.
506 * @top: Top offset of the crop area.
507 * @height: Height of the crop area.
508 * @width: Width of the crop area.
510 * The following restrictions are applied for the crop settings. If incoming
511 * values do not follow these restrictions then we map the settings to the
512 * closest acceptable crop value.
513 * 1) Left offset is always odd. This can be avoided if we enable byte swap
514 * option for incoming data into CCDC.
515 * 2) Top offset is always even.
516 * 3) Crop height is always even.
517 * 4) Crop width is always a multiple of 16 pixels
519 void ispccdc_config_crop(struct isp_ccdc_device *isp_ccdc, u32 left, u32 top,
520 u32 height, u32 width)
522 isp_ccdc->ccdcin_woffset = left + (left % 2);
523 isp_ccdc->ccdcin_hoffset = top + (top % 2);
525 isp_ccdc->crop_w = width - (width % 16);
526 isp_ccdc->crop_h = height + (height % 2);
528 DPRINTK_ISPCCDC("\n\tOffsets L %d T %d W %d H %d\n",
529 isp_ccdc->ccdcin_woffset,
530 isp_ccdc->ccdcin_hoffset,
531 isp_ccdc->crop_w,
532 isp_ccdc->crop_h);
536 * ispccdc_config_datapath - Specify the input and output modules for CCDC.
537 * @isp_ccdc: Pointer to ISP CCDC device.
538 * @pipe: Pointer to ISP pipeline structure to base on for config.
540 * Configures the default configuration for the CCDC to work with.
542 * The valid values for the input are CCDC_RAW (0), CCDC_YUV_SYNC (1),
543 * CCDC_YUV_BT (2), and CCDC_OTHERS (3).
545 * The valid values for the output are CCDC_YUV_RSZ (0), CCDC_YUV_MEM_RSZ (1),
546 * CCDC_OTHERS_VP (2), CCDC_OTHERS_MEM (3), CCDC_OTHERS_VP_MEM (4).
548 * Returns 0 if successful, or -EINVAL if wrong I/O combination or wrong input
549 * or output values.
551 static int ispccdc_config_datapath(struct isp_ccdc_device *isp_ccdc,
552 struct isp_pipeline *pipe)
554 u32 syn_mode = 0;
555 struct ispccdc_vp vpcfg;
556 struct ispccdc_syncif syncif;
557 struct ispccdc_bclamp blkcfg;
559 u32 colptn = ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
560 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
561 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
562 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
563 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
564 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
565 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
566 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
567 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
568 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
569 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
570 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
571 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
572 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
573 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
574 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
576 syn_mode = isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
577 ISPCCDC_SYN_MODE);
579 switch (pipe->ccdc_out) {
580 case CCDC_YUV_RSZ:
581 syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
582 syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
583 break;
585 case CCDC_YUV_MEM_RSZ:
586 syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
587 isp_ccdc->wen = 1;
588 syn_mode |= ISPCCDC_SYN_MODE_WEN;
589 break;
591 case CCDC_OTHERS_VP:
592 syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
593 syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
594 syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
595 vpcfg.bitshift_sel = BIT9_0;
596 vpcfg.freq_sel = PIXCLKBY2;
597 ispccdc_config_vp(isp_ccdc, vpcfg);
598 ispccdc_enable_vp(isp_ccdc, 1);
599 break;
601 case CCDC_OTHERS_MEM:
602 syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
603 syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
604 syn_mode |= ISPCCDC_SYN_MODE_WEN;
605 if (pipe->ccdc_in == CCDC_YUV_BT) {
606 syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
607 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
608 ISPCCDC_CFG, ~ISPCCDC_CFG_WENLOG);
609 } else {
610 syn_mode |= ISPCCDC_SYN_MODE_EXWEN;
611 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
612 ISPCCDC_CFG, ISPCCDC_CFG_WENLOG);
614 vpcfg.bitshift_sel = BIT11_2;
615 vpcfg.freq_sel = PIXCLKBY2;
616 ispccdc_config_vp(isp_ccdc, vpcfg);
617 ispccdc_enable_vp(isp_ccdc, 0);
618 break;
620 case CCDC_OTHERS_VP_MEM:
621 syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
622 syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
623 syn_mode |= ISPCCDC_SYN_MODE_WEN;
624 syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
626 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
627 ISPCCDC_CFG, ~ISPCCDC_CFG_WENLOG,
628 isp_ccdc->wenlog);
629 vpcfg.bitshift_sel = BIT9_0;
630 vpcfg.freq_sel = PIXCLKBY2;
631 ispccdc_config_vp(isp_ccdc, vpcfg);
632 ispccdc_enable_vp(isp_ccdc, 1);
633 break;
634 default:
635 DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Output\n");
636 return -EINVAL;
639 isp_reg_writel(isp_ccdc->dev, syn_mode, OMAP3_ISP_IOMEM_CCDC,
640 ISPCCDC_SYN_MODE);
642 switch (pipe->ccdc_in) {
643 case CCDC_RAW_GRBG:
644 case CCDC_RAW_RGGB:
645 case CCDC_RAW_BGGR:
646 case CCDC_RAW_GBRG:
647 syncif.ccdc_mastermode = 0;
648 syncif.datapol = 0;
649 syncif.datsz = DAT10;
650 syncif.fldmode = 0;
651 syncif.fldout = 0;
652 syncif.fldpol = 0;
653 syncif.fldstat = 0;
654 syncif.hdpol = 0;
655 syncif.ipmod = RAW;
656 syncif.vdpol = 0;
657 syncif.bt_r656_en = 0;
658 ispccdc_config_sync_if(isp_ccdc, syncif);
659 ispccdc_config_imgattr(isp_ccdc, colptn);
660 blkcfg.dcsubval = 64;
661 ispccdc_config_black_clamp(isp_ccdc, blkcfg);
662 if (is_isplsc_activated()) {
663 ispccdc_config_lsc(isp_ccdc, &isp_ccdc->lsc_config);
664 ispccdc_load_lsc(isp_ccdc, isp_ccdc->lsc_gain_table_tmp,
665 LSC_TABLE_INIT_SIZE);
668 break;
669 case CCDC_YUV_SYNC:
670 syncif.ccdc_mastermode = 0;
671 syncif.datapol = 0;
672 syncif.datsz = DAT8;
673 syncif.fldmode = 0;
674 syncif.fldout = 0;
675 syncif.fldpol = 0;
676 syncif.fldstat = 0;
677 syncif.hdpol = 0;
678 syncif.ipmod = YUV16;
679 syncif.vdpol = 1;
680 syncif.bt_r656_en = 0;
681 ispccdc_config_imgattr(isp_ccdc, 0);
682 ispccdc_config_sync_if(isp_ccdc, syncif);
683 blkcfg.dcsubval = 0;
684 ispccdc_config_black_clamp(isp_ccdc, blkcfg);
685 break;
686 case CCDC_YUV_BT:
687 syncif.ccdc_mastermode = 0;
688 syncif.datapol = 0;
689 syncif.datsz = DAT8;
690 syncif.fldmode = 1;
691 syncif.fldout = 0;
692 syncif.fldpol = 0;
693 syncif.fldstat = 0;
694 syncif.hdpol = 0;
695 syncif.ipmod = YUV8;
696 syncif.vdpol = 1;
697 syncif.bt_r656_en = 1;
698 ispccdc_config_imgattr(isp_ccdc, 0);
699 ispccdc_config_sync_if(isp_ccdc, syncif);
700 blkcfg.dcsubval = 0;
701 ispccdc_config_black_clamp(isp_ccdc, blkcfg);
702 break;
703 case CCDC_OTHERS:
704 break;
705 default:
706 DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Input\n");
707 return -EINVAL;
710 ispccdc_print_status(isp_ccdc, pipe);
711 isp_print_status(isp_ccdc->dev);
712 return 0;
714 EXPORT_SYMBOL(ispccdc_config_datapath);
717 * ispccdc_config_sync_if - Set CCDC sync interface params between sensor and CCDC.
718 * @isp_ccdc: Pointer to ISP CCDC device.
719 * @syncif: Structure containing the sync parameters like field state, CCDC in
720 * master/slave mode, raw/yuv data, polarity of data, field, hs, vs
721 * signals.
723 void ispccdc_config_sync_if(struct isp_ccdc_device *isp_ccdc,
724 struct ispccdc_syncif syncif)
726 u32 syn_mode = isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
727 ISPCCDC_SYN_MODE);
729 syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
731 if (syncif.fldstat)
732 syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT;
733 else
734 syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
736 syn_mode &= ISPCCDC_SYN_MODE_INPMOD_MASK;
737 isp_ccdc->syncif_ipmod = syncif.ipmod;
739 switch (syncif.ipmod) {
740 case RAW:
741 break;
742 case YUV16:
743 syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
744 break;
745 case YUV8:
746 syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8;
747 if (syncif.bt_r656_en)
748 syn_mode |= ISPCCDC_SYN_MODE_PACK8;
749 break;
752 syn_mode &= ISPCCDC_SYN_MODE_DATSIZ_MASK;
753 switch (syncif.datsz) {
754 case DAT8:
755 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
756 break;
757 case DAT10:
758 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;
759 break;
760 case DAT11:
761 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;
762 break;
763 case DAT12:
764 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
765 break;
768 if (syncif.fldmode)
769 syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
770 else
771 syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE;
773 if (syncif.datapol)
774 syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
775 else
776 syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL;
778 if (syncif.fldpol)
779 syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
780 else
781 syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL;
783 if (syncif.hdpol)
784 syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
785 else
786 syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL;
788 if (syncif.vdpol)
789 syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
790 else
791 syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL;
793 if (syncif.ccdc_mastermode) {
794 syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
795 isp_reg_writel(isp_ccdc->dev,
796 syncif.hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
797 | syncif.vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
798 OMAP3_ISP_IOMEM_CCDC,
799 ISPCCDC_HD_VD_WID);
801 isp_reg_writel(isp_ccdc->dev,
802 syncif.ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
803 | syncif.hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
804 OMAP3_ISP_IOMEM_CCDC,
805 ISPCCDC_PIX_LINES);
806 } else
807 syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
808 ISPCCDC_SYN_MODE_VDHDOUT);
810 isp_reg_writel(isp_ccdc->dev, syn_mode, OMAP3_ISP_IOMEM_CCDC,
811 ISPCCDC_SYN_MODE);
813 if (!(syncif.bt_r656_en)) {
814 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
815 ISPCCDC_REC656IF, ~ISPCCDC_REC656IF_R656ON);
816 } else {
817 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
818 ISPCCDC_REC656IF, ISPCCDC_REC656IF_R656ON |
819 ISPCCDC_REC656IF_ECCFVH);
822 EXPORT_SYMBOL(ispccdc_config_sync_if);
825 * ispccdc_config_black_clamp - Configures the clamp parameters in CCDC.
826 * @isp_ccdc: Pointer to ISP CCDC device.
827 * @bclamp: Structure containing the optical black average gain, optical black
828 * sample length, sample lines, and the start pixel position of the
829 * samples w.r.t the HS pulse.
831 * Configures the clamp parameters in CCDC. Either if its being used the
832 * optical black clamp, or the digital clamp. If its a digital clamp, then
833 * assures to put a valid DC substraction level.
835 * Returns always 0 when completed.
837 int ispccdc_config_black_clamp(struct isp_ccdc_device *isp_ccdc,
838 struct ispccdc_bclamp bclamp)
840 u32 bclamp_val = 0;
842 if (isp_ccdc->obclamp_en) {
843 bclamp_val |= bclamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
844 bclamp_val |= bclamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
845 bclamp_val |= bclamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
846 bclamp_val |= bclamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
847 isp_reg_writel(isp_ccdc->dev, bclamp_val,
848 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
849 } else {
850 if (omap_rev() < OMAP3430_REV_ES2_0)
851 if (isp_ccdc->syncif_ipmod == YUV16 ||
852 isp_ccdc->syncif_ipmod == YUV8 ||
853 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
854 ISPCCDC_REC656IF) &
855 ISPCCDC_REC656IF_R656ON)
856 bclamp.dcsubval = 0;
857 isp_reg_writel(isp_ccdc->dev, bclamp.dcsubval,
858 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
860 return 0;
862 EXPORT_SYMBOL(ispccdc_config_black_clamp);
865 * ispccdc_enable_black_clamp - Enables/Disables the optical black clamp.
866 * @isp_ccdc: Pointer to ISP CCDC device.
867 * @enable: 0 Disables optical black clamp, 1 Enables optical black clamp.
869 * Enables or disables the optical black clamp. When disabled, the digital
870 * clamp operates.
872 void ispccdc_enable_black_clamp(struct isp_ccdc_device *isp_ccdc, u8 enable)
874 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
875 ~ISPCCDC_CLAMP_CLAMPEN,
876 enable ? ISPCCDC_CLAMP_CLAMPEN : 0);
877 isp_ccdc->obclamp_en = enable;
879 EXPORT_SYMBOL(ispccdc_enable_black_clamp);
882 * ispccdc_config_fpc - Configures the Faulty Pixel Correction parameters.
883 * @isp_ccdc: Pointer to ISP CCDC device.
884 * @fpc: Structure containing the number of faulty pixels corrected in the
885 * frame, address of the FPC table.
887 * Returns 0 if successful, or -EINVAL if FPC Address is not on the 64 byte
888 * boundary.
890 int ispccdc_config_fpc(struct isp_ccdc_device *isp_ccdc, struct ispccdc_fpc fpc)
892 u32 fpc_val = 0;
894 fpc_val = isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
895 ISPCCDC_FPC);
897 if ((fpc.fpcaddr & 0xFFFFFFC0) == fpc.fpcaddr) {
898 isp_reg_writel(isp_ccdc->dev, fpc_val & (~ISPCCDC_FPC_FPCEN),
899 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
900 isp_reg_writel(isp_ccdc->dev, fpc.fpcaddr,
901 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR);
902 } else {
903 DPRINTK_ISPCCDC("FPC Address should be on 64byte boundary\n");
904 return -EINVAL;
906 isp_reg_writel(isp_ccdc->dev, fpc_val |
907 (fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
908 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
909 return 0;
911 EXPORT_SYMBOL(ispccdc_config_fpc);
914 * ispccdc_enable_fpc - Enable Faulty Pixel Correction.
915 * @isp_ccdc: Pointer to ISP CCDC device.
916 * @enable: 0 Disables FPC, 1 Enables FPC.
918 void ispccdc_enable_fpc(struct isp_ccdc_device *isp_ccdc, u8 enable)
920 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC,
921 ~ISPCCDC_FPC_FPCEN,
922 enable ? ISPCCDC_FPC_FPCEN : 0);
924 EXPORT_SYMBOL(ispccdc_enable_fpc);
927 * ispccdc_config_black_comp - Configure Black Level Compensation.
928 * @isp_ccdc: Pointer to ISP CCDC device.
929 * @blcomp: Structure containing the black level compensation value for RGrGbB
930 * pixels. in 2's complement.
932 void ispccdc_config_black_comp(struct isp_ccdc_device *isp_ccdc,
933 struct ispccdc_blcomp blcomp)
935 u32 blcomp_val = 0;
937 blcomp_val |= blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
938 blcomp_val |= blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
939 blcomp_val |= blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
940 blcomp_val |= blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
942 isp_reg_writel(isp_ccdc->dev, blcomp_val, OMAP3_ISP_IOMEM_CCDC,
943 ISPCCDC_BLKCMP);
945 EXPORT_SYMBOL(ispccdc_config_black_comp);
948 * ispccdc_config_vp - Configure the Video Port.
949 * @isp_ccdc: Pointer to ISP CCDC device.
950 * @vpcfg: Structure containing the Video Port input frequency, and the 10 bit
951 * format.
953 void ispccdc_config_vp(struct isp_ccdc_device *isp_ccdc,
954 struct ispccdc_vp vpcfg)
956 u32 fmtcfg_vp = isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
957 ISPCCDC_FMTCFG);
959 fmtcfg_vp &= ISPCCDC_FMTCFG_VPIN_MASK & ISPCCDC_FMTCFG_VPIF_FRQ_MASK;
961 switch (vpcfg.bitshift_sel) {
962 case BIT9_0:
963 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
964 break;
965 case BIT10_1:
966 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
967 break;
968 case BIT11_2:
969 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
970 break;
971 case BIT12_3:
972 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
973 break;
975 switch (vpcfg.freq_sel) {
976 case PIXCLKBY2:
977 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY2;
978 break;
979 case PIXCLKBY3_5:
980 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY3;
981 break;
982 case PIXCLKBY4_5:
983 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY4;
984 break;
985 case PIXCLKBY5_5:
986 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY5;
987 break;
988 case PIXCLKBY6_5:
989 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY6;
990 break;
992 isp_reg_writel(isp_ccdc->dev, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC,
993 ISPCCDC_FMTCFG);
995 EXPORT_SYMBOL(ispccdc_config_vp);
998 * ispccdc_enable_vp - Enable Video Port.
999 * @isp_ccdc: Pointer to ISP CCDC device.
1000 * @enable: 0 Disables VP, 1 Enables VP
1002 * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
1004 void ispccdc_enable_vp(struct isp_ccdc_device *isp_ccdc, u8 enable)
1006 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
1007 ~ISPCCDC_FMTCFG_VPEN,
1008 enable ? ISPCCDC_FMTCFG_VPEN : 0);
1010 EXPORT_SYMBOL(ispccdc_enable_vp);
1013 * ispccdc_config_reformatter - Configure Data Reformatter.
1014 * @isp_ccdc: Pointer to ISP CCDC device.
1015 * @refmt: Structure containing the memory address to format and the bit fields
1016 * for the reformatter registers.
1018 * Configures the Reformatter register values if line alternating is disabled.
1019 * Else, just enabling line alternating is enough.
1021 void ispccdc_config_reformatter(struct isp_ccdc_device *isp_ccdc,
1022 struct ispccdc_refmt refmt)
1024 u32 fmtcfg_val = 0;
1026 fmtcfg_val = isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1027 ISPCCDC_FMTCFG);
1029 if (refmt.lnalt)
1030 fmtcfg_val |= ISPCCDC_FMTCFG_LNALT;
1031 else {
1032 fmtcfg_val &= ~ISPCCDC_FMTCFG_LNALT;
1033 fmtcfg_val &= 0xFFFFF003;
1034 fmtcfg_val |= refmt.lnum << ISPCCDC_FMTCFG_LNUM_SHIFT;
1035 fmtcfg_val |= refmt.plen_even <<
1036 ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT;
1037 fmtcfg_val |= refmt.plen_odd << ISPCCDC_FMTCFG_PLEN_ODD_SHIFT;
1039 isp_reg_writel(isp_ccdc->dev, refmt.prgeven0,
1040 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGEVEN0);
1041 isp_reg_writel(isp_ccdc->dev, refmt.prgeven1,
1042 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGEVEN1);
1043 isp_reg_writel(isp_ccdc->dev, refmt.prgodd0,
1044 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGODD0);
1045 isp_reg_writel(isp_ccdc->dev, refmt.prgodd1,
1046 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PRGODD1);
1047 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr0,
1048 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR0);
1049 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr1,
1050 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR1);
1051 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr2,
1052 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR2);
1053 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr3,
1054 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR3);
1055 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr4,
1056 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR4);
1057 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr5,
1058 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR5);
1059 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr6,
1060 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR6);
1061 isp_reg_writel(isp_ccdc->dev, refmt.fmtaddr7,
1062 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_ADDR7);
1064 isp_reg_writel(isp_ccdc->dev, fmtcfg_val, OMAP3_ISP_IOMEM_CCDC,
1065 ISPCCDC_FMTCFG);
1067 EXPORT_SYMBOL(ispccdc_config_reformatter);
1070 * ispccdc_enable_reformatter - Enable Data Reformatter.
1071 * @isp_ccdc: Pointer to ISP CCDC device.
1072 * @enable: 0 Disables Reformatter, 1- Enables Data Reformatter
1074 void ispccdc_enable_reformatter(struct isp_ccdc_device *isp_ccdc, u8 enable)
1076 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
1077 ~ISPCCDC_FMTCFG_FMTEN,
1078 enable ? ISPCCDC_FMTCFG_FMTEN : 0);
1079 isp_ccdc->refmt_en = enable;
1081 EXPORT_SYMBOL(ispccdc_enable_reformatter);
1084 * ispccdc_config_culling - Configure culling parameters.
1085 * @isp_ccdc: Pointer to ISP CCDC device.
1086 * @cull: Structure containing the vertical culling pattern, and horizontal
1087 * culling pattern for odd and even lines.
1089 void ispccdc_config_culling(struct isp_ccdc_device *isp_ccdc,
1090 struct ispccdc_culling cull)
1092 u32 culling_val = 0;
1094 culling_val |= cull.v_pattern << ISPCCDC_CULLING_CULV_SHIFT;
1095 culling_val |= cull.h_even << ISPCCDC_CULLING_CULHEVN_SHIFT;
1096 culling_val |= cull.h_odd << ISPCCDC_CULLING_CULHODD_SHIFT;
1098 isp_reg_writel(isp_ccdc->dev, culling_val, OMAP3_ISP_IOMEM_CCDC,
1099 ISPCCDC_CULLING);
1101 EXPORT_SYMBOL(ispccdc_config_culling);
1104 * ispccdc_enable_lpf - Enable Low-Pass Filter (LPF).
1105 * @isp_ccdc: Pointer to ISP CCDC device.
1106 * @enable: 0 Disables LPF, 1 Enables LPF
1108 void ispccdc_enable_lpf(struct isp_ccdc_device *isp_ccdc, u8 enable)
1110 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
1111 ~ISPCCDC_SYN_MODE_LPF,
1112 enable ? ISPCCDC_SYN_MODE_LPF : 0);
1114 EXPORT_SYMBOL(ispccdc_enable_lpf);
1117 * ispccdc_config_alaw - Configure the input width for A-law compression.
1118 * @isp_ccdc: Pointer to ISP CCDC device.
1119 * @ipwidth: Input width for A-law
1121 void ispccdc_config_alaw(struct isp_ccdc_device *isp_ccdc,
1122 enum alaw_ipwidth ipwidth)
1124 isp_reg_writel(isp_ccdc->dev, ipwidth << ISPCCDC_ALAW_GWDI_SHIFT,
1125 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
1127 EXPORT_SYMBOL(ispccdc_config_alaw);
1130 * ispccdc_enable_alaw - Enable A-law compression.
1131 * @isp_ccdc: Pointer to ISP CCDC device.
1132 * @enable: 0 - Disables A-law, 1 - Enables A-law
1134 void ispccdc_enable_alaw(struct isp_ccdc_device *isp_ccdc, u8 enable)
1136 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW,
1137 ~ISPCCDC_ALAW_CCDTBL,
1138 enable ? ISPCCDC_ALAW_CCDTBL : 0);
1140 EXPORT_SYMBOL(ispccdc_enable_alaw);
1143 * ispccdc_config_imgattr - Configure sensor image specific attributes.
1144 * @isp_ccdc: Pointer to ISP CCDC device.
1145 * @colptn: Color pattern of the sensor.
1147 void ispccdc_config_imgattr(struct isp_ccdc_device *isp_ccdc, u32 colptn)
1149 isp_reg_writel(isp_ccdc->dev, colptn, OMAP3_ISP_IOMEM_CCDC,
1150 ISPCCDC_COLPTN);
1152 EXPORT_SYMBOL(ispccdc_config_imgattr);
1155 * ispccdc_config_shadow_registers - Configure CCDC during interframe time.
1156 * @isp_ccdc: Pointer to ISP CCDC device.
1158 * Executes LSC deferred enablement before next frame starts.
1160 void ispccdc_config_shadow_registers(struct isp_ccdc_device *isp_ccdc)
1162 if (isp_ccdc->lsc_enable) {
1163 ispccdc_enable_lsc(isp_ccdc, 1);
1164 isp_ccdc->lsc_enable = 0;
1169 * ispccdc_try_pipeline - Checks if requested Input/output dimensions are valid
1170 * @isp_ccdc: Pointer to ISP CCDC device.
1171 * @pipe: Pointer to ISP pipeline structure to fill back.
1173 * Calculates the number of pixels cropped if the reformater is disabled,
1174 * Fills up the output width and height variables in the isp_ccdc structure.
1176 * Returns 0 if successful, or -EINVAL if the input width is less than 2 pixels
1178 int ispccdc_try_pipeline(struct isp_ccdc_device *isp_ccdc,
1179 struct isp_pipeline *pipe)
1181 struct isp_device *isp =
1182 container_of(isp_ccdc, struct isp_device, isp_ccdc);
1184 if (pipe->ccdc_in_w < 32 || pipe->ccdc_in_h < 32) {
1185 DPRINTK_ISPCCDC("ISP_ERR: CCDC cannot handle input width less"
1186 " than 32 pixels or height less than 32\n");
1187 return -EINVAL;
1190 /* CCDC does not convert the image format */
1191 if ((pipe->ccdc_in == CCDC_RAW_GRBG ||
1192 pipe->ccdc_in == CCDC_RAW_RGGB ||
1193 pipe->ccdc_in == CCDC_RAW_BGGR ||
1194 pipe->ccdc_in == CCDC_RAW_GBRG ||
1195 pipe->ccdc_in == CCDC_OTHERS) &&
1196 pipe->ccdc_out == CCDC_YUV_RSZ) {
1197 dev_info(isp->dev, "wrong CCDC I/O Combination\n");
1198 return -EINVAL;
1201 pipe->ccdc_in_h_st = 0;
1202 pipe->ccdc_in_v_st = 0;
1203 pipe->ccdc_out_w = pipe->ccdc_in_w;
1204 pipe->ccdc_out_h = pipe->ccdc_in_h;
1206 if (!isp_ccdc->refmt_en
1207 && pipe->ccdc_out != CCDC_OTHERS_MEM
1208 && pipe->ccdc_out != CCDC_OTHERS_VP_MEM)
1209 pipe->ccdc_out_h -= 1;
1211 if (pipe->ccdc_out == CCDC_OTHERS_VP) {
1212 switch (pipe->ccdc_in) {
1213 case CCDC_RAW_GRBG:
1214 pipe->ccdc_in_h_st = 1;
1215 pipe->ccdc_in_v_st = 0;
1216 break;
1217 case CCDC_RAW_BGGR:
1218 pipe->ccdc_in_h_st = 1;
1219 pipe->ccdc_in_v_st = 1;
1220 break;
1221 case CCDC_RAW_RGGB:
1222 pipe->ccdc_in_h_st = 0;
1223 pipe->ccdc_in_v_st = 0;
1224 break;
1225 case CCDC_RAW_GBRG:
1226 pipe->ccdc_in_h_st = 0;
1227 pipe->ccdc_in_v_st = 1;
1228 break;
1229 default:
1230 break;
1232 pipe->ccdc_out_h -= pipe->ccdc_in_v_st;
1233 pipe->ccdc_out_w -= pipe->ccdc_in_h_st;
1234 pipe->ccdc_out_h -= (pipe->ccdc_out_h % 2);
1235 pipe->ccdc_out_w -= (pipe->ccdc_out_w % 2);
1238 pipe->ccdc_out_w_img = pipe->ccdc_out_w;
1239 /* Round up to nearest 16 pixels. */
1240 pipe->ccdc_out_w = ALIGN(pipe->ccdc_out_w, 0x10);
1242 return 0;
1244 EXPORT_SYMBOL(ispccdc_try_pipeline);
1247 * ispccdc_s_pipeline - Configure the CCDC based on overall ISP pipeline.
1248 * @isp_ccdc: Pointer to ISP CCDC device.
1249 * @pipe: Pointer to ISP pipeline structure to configure.
1251 * Configures the appropriate values stored in the isp_ccdc structure to
1252 * HORZ/VERT_INFO registers and the VP_OUT depending on whether the image
1253 * is stored in memory or given to the another module in the ISP pipeline.
1255 * Returns 0 if successful, or -EINVAL if try_size was not called before to
1256 * validate the requested dimensions.
1258 int ispccdc_s_pipeline(struct isp_ccdc_device *isp_ccdc,
1259 struct isp_pipeline *pipe)
1261 int rval;
1263 rval = ispccdc_config_datapath(isp_ccdc, pipe);
1264 if (rval)
1265 return rval;
1267 if (pipe->ccdc_out == CCDC_OTHERS_VP) {
1268 isp_reg_writel(isp_ccdc->dev, (pipe->ccdc_in_h_st <<
1269 ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
1270 ((pipe->ccdc_in_w - pipe->ccdc_in_h_st) <<
1271 ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
1272 OMAP3_ISP_IOMEM_CCDC,
1273 ISPCCDC_FMT_HORZ);
1274 isp_reg_writel(isp_ccdc->dev, (pipe->ccdc_in_v_st <<
1275 ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
1276 ((pipe->ccdc_in_h - pipe->ccdc_in_v_st) <<
1277 ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
1278 OMAP3_ISP_IOMEM_CCDC,
1279 ISPCCDC_FMT_VERT);
1280 isp_reg_writel(isp_ccdc->dev, (pipe->ccdc_out_w <<
1281 ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
1282 (pipe->ccdc_out_h - 1) <<
1283 ISPCCDC_VP_OUT_VERT_NUM_SHIFT,
1284 OMAP3_ISP_IOMEM_CCDC,
1285 ISPCCDC_VP_OUT);
1286 isp_reg_writel(isp_ccdc->dev, (((pipe->ccdc_out_h - 25) &
1287 ISPCCDC_VDINT_0_MASK) <<
1288 ISPCCDC_VDINT_0_SHIFT) |
1289 ((50 & ISPCCDC_VDINT_1_MASK) <<
1290 ISPCCDC_VDINT_1_SHIFT),
1291 OMAP3_ISP_IOMEM_CCDC,
1292 ISPCCDC_VDINT);
1294 } else if (pipe->ccdc_out == CCDC_OTHERS_MEM) {
1295 isp_reg_writel(isp_ccdc->dev, 0, OMAP3_ISP_IOMEM_CCDC,
1296 ISPCCDC_VP_OUT);
1297 if (pipe->ccdc_in == CCDC_RAW_GRBG ||
1298 pipe->ccdc_in == CCDC_RAW_RGGB ||
1299 pipe->ccdc_in == CCDC_RAW_BGGR ||
1300 pipe->ccdc_in == CCDC_RAW_GBRG) {
1301 isp_reg_writel(isp_ccdc->dev,
1302 pipe->ccdc_in_h_st << ISPCCDC_HORZ_INFO_SPH_SHIFT
1303 | ((pipe->ccdc_out_w - 1)
1304 << ISPCCDC_HORZ_INFO_NPH_SHIFT),
1305 OMAP3_ISP_IOMEM_CCDC,
1306 ISPCCDC_HORZ_INFO);
1307 } else if (pipe->ccdc_in == CCDC_YUV_BT) {
1308 isp_reg_writel(isp_ccdc->dev,
1309 0 << ISPCCDC_HORZ_INFO_SPH_SHIFT |
1310 (((pipe->ccdc_out_w << 1) - 1) <<
1311 ISPCCDC_HORZ_INFO_NPH_SHIFT),
1312 OMAP3_ISP_IOMEM_CCDC,
1313 ISPCCDC_HORZ_INFO);
1314 isp_reg_writel(isp_ccdc->dev,
1315 2 << ISPCCDC_VERT_START_SLV0_SHIFT |
1316 2 << ISPCCDC_VERT_START_SLV1_SHIFT,
1317 OMAP3_ISP_IOMEM_CCDC,
1318 ISPCCDC_VERT_START);
1319 isp_reg_writel(isp_ccdc->dev,
1320 ((pipe->ccdc_out_h >> 1) - 1) <<
1321 ISPCCDC_VERT_LINES_NLV_SHIFT,
1322 OMAP3_ISP_IOMEM_CCDC,
1323 ISPCCDC_VERT_LINES);
1324 } else {
1325 isp_reg_writel(isp_ccdc->dev,
1326 0 << ISPCCDC_HORZ_INFO_SPH_SHIFT
1327 | ((pipe->ccdc_out_w - 1)
1328 << ISPCCDC_HORZ_INFO_NPH_SHIFT),
1329 OMAP3_ISP_IOMEM_CCDC,
1330 ISPCCDC_HORZ_INFO);
1332 ispccdc_config_outlineoffset(isp_ccdc, pipe->ccdc_out_w * 2,
1333 0, 0);
1334 if (pipe->ccdc_in != CCDC_YUV_BT) {
1335 isp_reg_writel(isp_ccdc->dev,
1336 0 << ISPCCDC_VERT_START_SLV0_SHIFT,
1337 OMAP3_ISP_IOMEM_CCDC,
1338 ISPCCDC_VERT_START);
1339 isp_reg_writel(isp_ccdc->dev, (pipe->ccdc_out_h - 1) <<
1340 ISPCCDC_VERT_LINES_NLV_SHIFT,
1341 OMAP3_ISP_IOMEM_CCDC,
1342 ISPCCDC_VERT_LINES);
1343 isp_reg_writel(isp_ccdc->dev, (((pipe->ccdc_out_h - 2) &
1344 ISPCCDC_VDINT_0_MASK) <<
1345 ISPCCDC_VDINT_0_SHIFT) |
1346 ((100 & ISPCCDC_VDINT_1_MASK) <<
1347 ISPCCDC_VDINT_1_SHIFT),
1348 OMAP3_ISP_IOMEM_CCDC,
1349 ISPCCDC_VDINT);
1350 } else {
1351 ispccdc_config_outlineoffset(isp_ccdc,
1352 pipe->ccdc_out_w * 2, EVENEVEN, 1);
1353 ispccdc_config_outlineoffset(isp_ccdc,
1354 pipe->ccdc_out_w * 2, ODDEVEN, 1);
1355 ispccdc_config_outlineoffset(isp_ccdc,
1356 pipe->ccdc_out_w * 2, EVENODD, 1);
1357 ispccdc_config_outlineoffset(isp_ccdc,
1358 pipe->ccdc_out_w * 2, ODDODD, 1);
1359 isp_reg_writel(isp_ccdc->dev,
1360 ((((pipe->ccdc_out_h >> 1) - 1) &
1361 ISPCCDC_VDINT_0_MASK) <<
1362 ISPCCDC_VDINT_0_SHIFT) |
1363 ((50 & ISPCCDC_VDINT_1_MASK) <<
1364 ISPCCDC_VDINT_1_SHIFT),
1365 OMAP3_ISP_IOMEM_CCDC,
1366 ISPCCDC_VDINT);
1369 } else if (pipe->ccdc_out == CCDC_OTHERS_VP_MEM) {
1370 isp_reg_writel(isp_ccdc->dev,
1371 (pipe->ccdc_in_h_st << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
1372 ((pipe->ccdc_in_w - pipe->ccdc_in_h_st) <<
1373 ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
1374 OMAP3_ISP_IOMEM_CCDC,
1375 ISPCCDC_FMT_HORZ);
1376 isp_reg_writel(isp_ccdc->dev,
1377 (pipe->ccdc_in_v_st << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
1378 ((pipe->ccdc_in_h - pipe->ccdc_in_v_st) <<
1379 ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
1380 OMAP3_ISP_IOMEM_CCDC,
1381 ISPCCDC_FMT_VERT);
1382 isp_reg_writel(isp_ccdc->dev, (pipe->ccdc_out_w
1383 << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
1384 ((pipe->ccdc_out_h - 1) <<
1385 ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
1386 OMAP3_ISP_IOMEM_CCDC,
1387 ISPCCDC_VP_OUT);
1388 isp_reg_writel(isp_ccdc->dev,
1389 pipe->ccdc_in_h_st << ISPCCDC_HORZ_INFO_SPH_SHIFT |
1390 ((pipe->ccdc_out_w - 1) <<
1391 ISPCCDC_HORZ_INFO_NPH_SHIFT),
1392 OMAP3_ISP_IOMEM_CCDC,
1393 ISPCCDC_HORZ_INFO);
1394 isp_reg_writel(isp_ccdc->dev,
1395 pipe->ccdc_in_v_st << ISPCCDC_VERT_START_SLV0_SHIFT,
1396 OMAP3_ISP_IOMEM_CCDC,
1397 ISPCCDC_VERT_START);
1398 isp_reg_writel(isp_ccdc->dev, (pipe->ccdc_out_h - 1) <<
1399 ISPCCDC_VERT_LINES_NLV_SHIFT,
1400 OMAP3_ISP_IOMEM_CCDC,
1401 ISPCCDC_VERT_LINES);
1402 ispccdc_config_outlineoffset(isp_ccdc, pipe->ccdc_out_w * 2,
1403 0, 0);
1404 isp_reg_writel(isp_ccdc->dev, (((pipe->ccdc_out_h - 2) &
1405 ISPCCDC_VDINT_0_MASK) <<
1406 ISPCCDC_VDINT_0_SHIFT) |
1407 ((100 & ISPCCDC_VDINT_1_MASK) <<
1408 ISPCCDC_VDINT_1_SHIFT),
1409 OMAP3_ISP_IOMEM_CCDC,
1410 ISPCCDC_VDINT);
1413 if (is_isplsc_activated()) {
1414 if (pipe->ccdc_in == CCDC_RAW_GRBG ||
1415 pipe->ccdc_in == CCDC_RAW_RGGB ||
1416 pipe->ccdc_in == CCDC_RAW_BGGR ||
1417 pipe->ccdc_in == CCDC_RAW_GBRG) {
1418 ispccdc_config_lsc(isp_ccdc, &isp_ccdc->lsc_config);
1419 ispccdc_load_lsc(isp_ccdc, isp_ccdc->lsc_gain_table,
1420 isp_ccdc->lsc_config.size);
1424 return 0;
1426 EXPORT_SYMBOL(ispccdc_s_pipeline);
1429 * ispccdc_config_outlineoffset - Configure memory saving output line offset
1430 * @isp_ccdc: Pointer to ISP CCDC device.
1431 * @offset: Address offset to start a new line. Must be twice the
1432 * Output width and aligned on 32 byte boundary
1433 * @oddeven: Specifies the odd/even line pattern to be chosen to store the
1434 * output.
1435 * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
1437 * - Configures the output line offset when stored in memory
1438 * - Sets the odd/even line pattern to store the output
1439 * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
1440 * - Configures the number of even and odd line fields in case of rearranging
1441 * the lines.
1443 * Returns 0 if successful, or -EINVAL if the offset is not in 32 byte
1444 * boundary.
1446 int ispccdc_config_outlineoffset(struct isp_ccdc_device *isp_ccdc, u32 offset,
1447 u8 oddeven, u8 numlines)
1449 if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) {
1450 isp_reg_writel(isp_ccdc->dev, (offset & 0xFFFF),
1451 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
1452 } else {
1453 DPRINTK_ISPCCDC("ISP_ERR : Offset should be in 32 byte"
1454 " boundary\n");
1455 return -EINVAL;
1458 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
1459 ~ISPCCDC_SDOFST_FINV);
1461 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
1462 ~ISPCCDC_SDOFST_FOFST_4L);
1464 switch (oddeven) {
1465 case EVENEVEN:
1466 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1467 ISPCCDC_SDOFST,
1468 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
1469 break;
1470 case ODDEVEN:
1471 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1472 ISPCCDC_SDOFST,
1473 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
1474 break;
1475 case EVENODD:
1476 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1477 ISPCCDC_SDOFST,
1478 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
1479 break;
1480 case ODDODD:
1481 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1482 ISPCCDC_SDOFST,
1483 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
1484 break;
1485 default:
1486 break;
1488 return 0;
1490 EXPORT_SYMBOL(ispccdc_config_outlineoffset);
1493 * ispccdc_set_outaddr - Set memory address to save output image
1494 * @isp_ccdc: Pointer to ISP CCDC device.
1495 * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
1497 * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
1498 * boundary.
1500 int ispccdc_set_outaddr(struct isp_ccdc_device *isp_ccdc, u32 addr)
1502 if ((addr & ISP_32B_BOUNDARY_BUF) == addr) {
1503 isp_reg_writel(isp_ccdc->dev, addr, OMAP3_ISP_IOMEM_CCDC,
1504 ISPCCDC_SDR_ADDR);
1505 return 0;
1506 } else {
1507 DPRINTK_ISPCCDC("ISP_ERR : Address should be in 32 byte"
1508 " boundary\n");
1509 return -EINVAL;
1513 EXPORT_SYMBOL(ispccdc_set_outaddr);
1516 * ispccdc_enable - Enable the CCDC module.
1517 * @isp_ccdc: Pointer to ISP CCDC device.
1518 * @enable: 0 Disables CCDC, 1 Enables CCDC
1520 * Client should configure all the sub modules in CCDC before this.
1522 void ispccdc_enable(struct isp_ccdc_device *isp_ccdc, u8 enable)
1524 struct isp_device *isp =
1525 container_of(isp_ccdc, struct isp_device, isp_ccdc);
1527 if (enable) {
1528 if (isp_ccdc->lsc_enable &&
1529 ((isp->pipeline.ccdc_in == CCDC_RAW_GRBG) ||
1530 (isp->pipeline.ccdc_in == CCDC_RAW_RGGB) ||
1531 (isp->pipeline.ccdc_in == CCDC_RAW_BGGR) ||
1532 (isp->pipeline.ccdc_in == CCDC_RAW_GBRG)))
1533 ispccdc_enable_lsc(isp_ccdc, 1);
1535 } else {
1536 int lsc_enable = isp_ccdc->lsc_state;
1538 ispccdc_enable_lsc(isp_ccdc, 0);
1539 isp_ccdc->lsc_enable = lsc_enable;
1542 isp_reg_and_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
1543 ~ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
1545 EXPORT_SYMBOL(ispccdc_enable);
1548 * ispccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
1549 * @_isp_ccdc: Pointer to ISP CCDC device.
1551 * Returns zero if the CCDC is idle and the image has been written to
1552 * memory, too.
1554 int ispccdc_sbl_busy(void *_isp_ccdc)
1556 struct isp_ccdc_device *isp_ccdc = _isp_ccdc;
1558 return ispccdc_busy(isp_ccdc)
1559 | (isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_SBL,
1560 ISPSBL_CCDC_WR_0) &
1561 ISPSBL_CCDC_WR_0_DATA_READY)
1562 | (isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_SBL,
1563 ISPSBL_CCDC_WR_1) &
1564 ISPSBL_CCDC_WR_0_DATA_READY)
1565 | (isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_SBL,
1566 ISPSBL_CCDC_WR_2) &
1567 ISPSBL_CCDC_WR_0_DATA_READY)
1568 | (isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_SBL,
1569 ISPSBL_CCDC_WR_3) &
1570 ISPSBL_CCDC_WR_0_DATA_READY);
1572 EXPORT_SYMBOL(ispccdc_sbl_busy);
1575 * ispccdc_config_y8pos - Configures the location of Y color component
1576 * @mode: Y8POS_EVEN Y pixel in even position, otherwise Y pixel in odd
1578 * Configures the location of Y color componenent for YCbCr 8-bit data
1580 void ispccdc_config_y8pos(struct isp_ccdc_device *isp_ccdc,
1581 enum y8pos_mode mode)
1583 if (mode == Y8POS_EVEN) {
1584 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
1585 ~ISPCCDC_CFG_Y8POS);
1586 } else {
1587 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
1588 ISPCCDC_CFG_Y8POS);
1591 EXPORT_SYMBOL(ispccdc_config_y8pos);
1594 * ispccdc_config_byteswap - Configures byte swap data stored in memory
1595 * @swap: 1 - swap bytes, 0 - normal
1597 * Controls the order in which the Y and C pixels are stored in memory
1599 void ispccdc_config_byteswap(struct isp_ccdc_device *isp_ccdc, int swap)
1601 if (swap) {
1602 isp_reg_or(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
1603 ISPCCDC_CFG_BSWD);
1604 } else {
1605 isp_reg_and(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
1606 ~ISPCCDC_CFG_BSWD);
1609 EXPORT_SYMBOL(ispccdc_config_byteswap);
1612 * ispccdc_busy - Get busy state of the CCDC.
1613 * @isp_ccdc: Pointer to ISP CCDC device.
1615 int ispccdc_busy(struct isp_ccdc_device *isp_ccdc)
1617 return isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1618 ISPCCDC_PCR) &
1619 ISPCCDC_PCR_BUSY;
1621 EXPORT_SYMBOL(ispccdc_busy);
1624 * ispccdc_save_context - Save values of the CCDC module registers
1625 * @dev: Device pointer specific to the OMAP3 ISP.
1627 void ispccdc_save_context(struct device *dev)
1629 DPRINTK_ISPCCDC("Saving context\n");
1630 isp_save_context(dev, ispccdc_reg_list);
1632 EXPORT_SYMBOL(ispccdc_save_context);
1635 * ispccdc_restore_context - Restore values of the CCDC module registers
1636 * @dev: Device pointer specific to the OMAP3 ISP.
1638 void ispccdc_restore_context(struct device *dev)
1640 DPRINTK_ISPCCDC("Restoring context\n");
1641 isp_restore_context(dev, ispccdc_reg_list);
1643 EXPORT_SYMBOL(ispccdc_restore_context);
1646 * ispccdc_print_status - Print current CCDC Module register values.
1647 * @isp_ccdc: Pointer to ISP CCDC device.
1648 * @pipe: Pointer to current ISP pipeline structure.
1650 * Also prints other debug information stored in the CCDC module.
1652 void ispccdc_print_status(struct isp_ccdc_device *isp_ccdc,
1653 struct isp_pipeline *pipe)
1655 if (!is_ispccdc_debug_enabled())
1656 return;
1658 DPRINTK_ISPCCDC("Module in use =%d\n", isp_ccdc->ccdc_inuse);
1659 DPRINTK_ISPCCDC("Accepted CCDC Input (width = %d,Height = %d)\n",
1660 isp_ccdc->ccdcin_w,
1661 isp_ccdc->ccdcin_h);
1662 DPRINTK_ISPCCDC("Accepted CCDC Output (width = %d,Height = %d)\n",
1663 isp_ccdc->ccdcout_w,
1664 isp_ccdc->ccdcout_h);
1665 DPRINTK_ISPCCDC("###CCDC PCR=0x%x\n",
1666 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1667 ISPCCDC_PCR));
1668 DPRINTK_ISPCCDC("ISP_CTRL =0x%x\n",
1669 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_MAIN,
1670 ISP_CTRL));
1671 switch ((int)pipe->ccdc_in) {
1672 case CCDC_RAW_GRBG:
1673 case CCDC_RAW_RGGB:
1674 case CCDC_RAW_BGGR:
1675 case CCDC_RAW_GBRG:
1676 DPRINTK_ISPCCDC("ccdc input format is CCDC_RAW\n");
1677 break;
1678 case CCDC_YUV_SYNC:
1679 DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_SYNC\n");
1680 break;
1681 case CCDC_YUV_BT:
1682 DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_BT\n");
1683 break;
1686 switch ((int)pipe->ccdc_out) {
1687 case CCDC_OTHERS_VP:
1688 DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_VP\n");
1689 break;
1690 case CCDC_OTHERS_MEM:
1691 DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_MEM\n");
1692 break;
1693 case CCDC_YUV_RSZ:
1694 DPRINTK_ISPCCDC("ccdc output format is CCDC_YUV_RSZ\n");
1695 break;
1698 DPRINTK_ISPCCDC("###ISP_CTRL in ccdc =0x%x\n",
1699 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_MAIN,
1700 ISP_CTRL));
1701 DPRINTK_ISPCCDC("###ISP_IRQ0ENABLE in ccdc =0x%x\n",
1702 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_MAIN,
1703 ISP_IRQ0ENABLE));
1704 DPRINTK_ISPCCDC("###ISP_IRQ0STATUS in ccdc =0x%x\n",
1705 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_MAIN,
1706 ISP_IRQ0STATUS));
1707 DPRINTK_ISPCCDC("###CCDC SYN_MODE=0x%x\n",
1708 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1709 ISPCCDC_SYN_MODE));
1710 DPRINTK_ISPCCDC("###CCDC HORZ_INFO=0x%x\n",
1711 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1712 ISPCCDC_HORZ_INFO));
1713 DPRINTK_ISPCCDC("###CCDC VERT_START=0x%x\n",
1714 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1715 ISPCCDC_VERT_START));
1716 DPRINTK_ISPCCDC("###CCDC VERT_LINES=0x%x\n",
1717 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1718 ISPCCDC_VERT_LINES));
1719 DPRINTK_ISPCCDC("###CCDC CULLING=0x%x\n",
1720 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1721 ISPCCDC_CULLING));
1722 DPRINTK_ISPCCDC("###CCDC HSIZE_OFF=0x%x\n",
1723 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1724 ISPCCDC_HSIZE_OFF));
1725 DPRINTK_ISPCCDC("###CCDC SDOFST=0x%x\n",
1726 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1727 ISPCCDC_SDOFST));
1728 DPRINTK_ISPCCDC("###CCDC SDR_ADDR=0x%x\n",
1729 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1730 ISPCCDC_SDR_ADDR));
1731 DPRINTK_ISPCCDC("###CCDC CLAMP=0x%x\n",
1732 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1733 ISPCCDC_CLAMP));
1734 DPRINTK_ISPCCDC("###CCDC COLPTN=0x%x\n",
1735 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1736 ISPCCDC_COLPTN));
1737 DPRINTK_ISPCCDC("###CCDC CFG=0x%x\n",
1738 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1739 ISPCCDC_CFG));
1740 DPRINTK_ISPCCDC("###CCDC VP_OUT=0x%x\n",
1741 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1742 ISPCCDC_VP_OUT));
1743 DPRINTK_ISPCCDC("###CCDC_SDR_ADDR= 0x%x\n",
1744 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1745 ISPCCDC_SDR_ADDR));
1746 DPRINTK_ISPCCDC("###CCDC FMTCFG=0x%x\n",
1747 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1748 ISPCCDC_FMTCFG));
1749 DPRINTK_ISPCCDC("###CCDC FMT_HORZ=0x%x\n",
1750 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1751 ISPCCDC_FMT_HORZ));
1752 DPRINTK_ISPCCDC("###CCDC FMT_VERT=0x%x\n",
1753 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1754 ISPCCDC_FMT_VERT));
1755 DPRINTK_ISPCCDC("###CCDC LSC_CONFIG=0x%x\n",
1756 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1757 ISPCCDC_LSC_CONFIG));
1758 DPRINTK_ISPCCDC("###CCDC LSC_INIT=0x%x\n",
1759 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1760 ISPCCDC_LSC_INITIAL));
1761 DPRINTK_ISPCCDC("###CCDC LSC_TABLE BASE=0x%x\n",
1762 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1763 ISPCCDC_LSC_TABLE_BASE));
1764 DPRINTK_ISPCCDC("###CCDC LSC TABLE OFFSET=0x%x\n",
1765 isp_reg_readl(isp_ccdc->dev, OMAP3_ISP_IOMEM_CCDC,
1766 ISPCCDC_LSC_TABLE_OFFSET));
1768 EXPORT_SYMBOL(ispccdc_print_status);
1771 * isp_ccdc_init - CCDC module initialization.
1772 * @dev: Device pointer specific to the OMAP3 ISP.
1774 * Always returns 0
1776 int __init isp_ccdc_init(struct device *dev)
1778 struct isp_device *isp = dev_get_drvdata(dev);
1779 struct isp_ccdc_device *isp_ccdc = &isp->isp_ccdc;
1781 isp_ccdc->ccdc_inuse = 0;
1782 ispccdc_config_crop(isp_ccdc, 0, 0, 0, 0);
1783 mutex_init(&isp_ccdc->mutexlock);
1784 isp_ccdc->dev = dev;
1786 if (is_isplsc_activated()) {
1787 isp_ccdc->lsc_gain_table_tmp = kmalloc(LSC_TABLE_INIT_SIZE,
1788 GFP_KERNEL | GFP_DMA);
1789 memset(isp_ccdc->lsc_gain_table_tmp, 0x40, LSC_TABLE_INIT_SIZE);
1790 isp_ccdc->lsc_config.initial_x = 0;
1791 isp_ccdc->lsc_config.initial_y = 0;
1792 isp_ccdc->lsc_config.gain_mode_n = 0x6;
1793 isp_ccdc->lsc_config.gain_mode_m = 0x6;
1794 isp_ccdc->lsc_config.gain_format = 0x4;
1795 isp_ccdc->lsc_config.offset = 0x60;
1796 isp_ccdc->lsc_config.size = LSC_TABLE_INIT_SIZE;
1797 isp_ccdc->lsc_enable = 1;
1800 return 0;
1804 * isp_ccdc_cleanup - CCDC module cleanup.
1805 * @dev: Device pointer specific to the OMAP3 ISP.
1807 void isp_ccdc_cleanup(struct device *dev)
1809 struct isp_device *isp = dev_get_drvdata(dev);
1810 struct isp_ccdc_device *isp_ccdc = &isp->isp_ccdc;
1812 if (is_isplsc_activated()) {
1813 ispccdc_free_lsc(isp_ccdc);
1814 kfree(isp_ccdc->lsc_gain_table_tmp);
1817 if (isp_ccdc->fpc_table_add_m != 0) {
1818 iommu_kunmap(isp->iommu, isp_ccdc->fpc_table_add_m);
1819 kfree(isp_ccdc->fpc_table_add);