aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/omap3isp/cfa_coef_table.h61
-rw-r--r--drivers/media/video/omap3isp/gamma_table.h90
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c2268
-rw-r--r--drivers/media/video/omap3isp/ispccdc.h219
-rw-r--r--drivers/media/video/omap3isp/isppreview.c2113
-rw-r--r--drivers/media/video/omap3isp/isppreview.h214
-rw-r--r--drivers/media/video/omap3isp/ispresizer.c1693
-rw-r--r--drivers/media/video/omap3isp/ispresizer.h147
-rw-r--r--drivers/media/video/omap3isp/luma_enhance_table.h42
-rw-r--r--drivers/media/video/omap3isp/noise_filter_table.h30
10 files changed, 6877 insertions, 0 deletions
diff --git a/drivers/media/video/omap3isp/cfa_coef_table.h b/drivers/media/video/omap3isp/cfa_coef_table.h
new file mode 100644
index 000000000000..c60df0ed075a
--- /dev/null
+++ b/drivers/media/video/omap3isp/cfa_coef_table.h
@@ -0,0 +1,61 @@
1/*
2 * cfa_coef_table.h
3 *
4 * TI OMAP3 ISP - CFA coefficients table
5 *
6 * Copyright (C) 2009-2010 Nokia Corporation
7 *
8 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 * Sakari Ailus <sakari.ailus@iki.fi>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
27248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
28247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
29244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
30248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
31247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
32244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
33248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250,
34247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248,
35 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
36 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
37 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
38 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
39 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
40 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
41 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4,
42 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0,
43 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0,
44 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
45 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
46 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
47 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
48 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
49 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
50 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0,
51 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12,
52 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0,
53244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
54248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
55250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248,
56244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
57248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
58250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248,
59244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244,
60248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247,
61250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248
diff --git a/drivers/media/video/omap3isp/gamma_table.h b/drivers/media/video/omap3isp/gamma_table.h
new file mode 100644
index 000000000000..78deebf7d965
--- /dev/null
+++ b/drivers/media/video/omap3isp/gamma_table.h
@@ -0,0 +1,90 @@
1/*
2 * gamma_table.h
3 *
4 * TI OMAP3 ISP - Default gamma table for all components
5 *
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
27 0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20,
28 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42,
29 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 54, 55, 56, 57,
30 58, 59, 60, 61, 62, 63, 63, 64, 65, 66, 66, 67, 68, 69, 69, 70,
31 71, 72, 72, 73, 74, 75, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82,
32 83, 84, 84, 85, 86, 87, 88, 88, 89, 90, 91, 91, 92, 93, 94, 94,
33 95, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 103, 104, 104,
34105, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 117,
35117, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125,
36126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133,
37134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
38142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149,
39150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155,
40156, 156, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 160, 161, 161, 162,
41162, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 167, 167, 168,
42168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 173, 173, 174,
43174, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179,
44179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183,
45183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187,
46187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191,
47191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195,
48195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199,
49199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 203, 203,
50203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207,
51207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210,
52210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
53211, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213,
54213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
55216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219,
56219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221,
57221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 223,
58223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225,
59225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226,
60226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228,
61228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230,
62230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232,
63232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
64233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235,
65235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
66236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238,
67238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,
68238, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240,
69240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
70240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242,
71242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
72242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
73244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
74244, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
75246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
76246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 248,
77248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
78248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250,
79250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
80250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
81250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252,
82252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
83252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
84252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
85252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253,
86253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
87253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
88253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
89253, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
90255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
new file mode 100644
index 000000000000..5ff9d14ce710
--- /dev/null
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -0,0 +1,2268 @@
1/*
2 * ispccdc.c
3 *
4 * TI OMAP3 ISP - CCDC module
5 *
6 * Copyright (C) 2009-2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
27#include <linux/module.h>
28#include <linux/uaccess.h>
29#include <linux/delay.h>
30#include <linux/device.h>
31#include <linux/dma-mapping.h>
32#include <linux/mm.h>
33#include <linux/sched.h>
34#include <media/v4l2-event.h>
35
36#include "isp.h"
37#include "ispreg.h"
38#include "ispccdc.h"
39
40static struct v4l2_mbus_framefmt *
41__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
42 unsigned int pad, enum v4l2_subdev_format_whence which);
43
44static const unsigned int ccdc_fmts[] = {
45 V4L2_MBUS_FMT_Y8_1X8,
46 V4L2_MBUS_FMT_SGRBG10_1X10,
47 V4L2_MBUS_FMT_SRGGB10_1X10,
48 V4L2_MBUS_FMT_SBGGR10_1X10,
49 V4L2_MBUS_FMT_SGBRG10_1X10,
50 V4L2_MBUS_FMT_SGRBG12_1X12,
51 V4L2_MBUS_FMT_SRGGB12_1X12,
52 V4L2_MBUS_FMT_SBGGR12_1X12,
53 V4L2_MBUS_FMT_SGBRG12_1X12,
54};
55
56/*
57 * ccdc_print_status - Print current CCDC Module register values.
58 * @ccdc: Pointer to ISP CCDC device.
59 *
60 * Also prints other debug information stored in the CCDC module.
61 */
62#define CCDC_PRINT_REGISTER(isp, name)\
63 dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \
64 isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name))
65
66static void ccdc_print_status(struct isp_ccdc_device *ccdc)
67{
68 struct isp_device *isp = to_isp_device(ccdc);
69
70 dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n");
71
72 CCDC_PRINT_REGISTER(isp, PCR);
73 CCDC_PRINT_REGISTER(isp, SYN_MODE);
74 CCDC_PRINT_REGISTER(isp, HD_VD_WID);
75 CCDC_PRINT_REGISTER(isp, PIX_LINES);
76 CCDC_PRINT_REGISTER(isp, HORZ_INFO);
77 CCDC_PRINT_REGISTER(isp, VERT_START);
78 CCDC_PRINT_REGISTER(isp, VERT_LINES);
79 CCDC_PRINT_REGISTER(isp, CULLING);
80 CCDC_PRINT_REGISTER(isp, HSIZE_OFF);
81 CCDC_PRINT_REGISTER(isp, SDOFST);
82 CCDC_PRINT_REGISTER(isp, SDR_ADDR);
83 CCDC_PRINT_REGISTER(isp, CLAMP);
84 CCDC_PRINT_REGISTER(isp, DCSUB);
85 CCDC_PRINT_REGISTER(isp, COLPTN);
86 CCDC_PRINT_REGISTER(isp, BLKCMP);
87 CCDC_PRINT_REGISTER(isp, FPC);
88 CCDC_PRINT_REGISTER(isp, FPC_ADDR);
89 CCDC_PRINT_REGISTER(isp, VDINT);
90 CCDC_PRINT_REGISTER(isp, ALAW);
91 CCDC_PRINT_REGISTER(isp, REC656IF);
92 CCDC_PRINT_REGISTER(isp, CFG);
93 CCDC_PRINT_REGISTER(isp, FMTCFG);
94 CCDC_PRINT_REGISTER(isp, FMT_HORZ);
95 CCDC_PRINT_REGISTER(isp, FMT_VERT);
96 CCDC_PRINT_REGISTER(isp, PRGEVEN0);
97 CCDC_PRINT_REGISTER(isp, PRGEVEN1);
98 CCDC_PRINT_REGISTER(isp, PRGODD0);
99 CCDC_PRINT_REGISTER(isp, PRGODD1);
100 CCDC_PRINT_REGISTER(isp, VP_OUT);
101 CCDC_PRINT_REGISTER(isp, LSC_CONFIG);
102 CCDC_PRINT_REGISTER(isp, LSC_INITIAL);
103 CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE);
104 CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET);
105
106 dev_dbg(isp->dev, "--------------------------------------------\n");
107}
108
109/*
110 * omap3isp_ccdc_busy - Get busy state of the CCDC.
111 * @ccdc: Pointer to ISP CCDC device.
112 */
113int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc)
114{
115 struct isp_device *isp = to_isp_device(ccdc);
116
117 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
118 ISPCCDC_PCR_BUSY;
119}
120
121/* -----------------------------------------------------------------------------
122 * Lens Shading Compensation
123 */
124
125/*
126 * ccdc_lsc_validate_config - Check that LSC configuration is valid.
127 * @ccdc: Pointer to ISP CCDC device.
128 * @lsc_cfg: the LSC configuration to check.
129 *
130 * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
131 */
132static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc,
133 struct omap3isp_ccdc_lsc_config *lsc_cfg)
134{
135 struct isp_device *isp = to_isp_device(ccdc);
136 struct v4l2_mbus_framefmt *format;
137 unsigned int paxel_width, paxel_height;
138 unsigned int paxel_shift_x, paxel_shift_y;
139 unsigned int min_width, min_height, min_size;
140 unsigned int input_width, input_height;
141
142 paxel_shift_x = lsc_cfg->gain_mode_m;
143 paxel_shift_y = lsc_cfg->gain_mode_n;
144
145 if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
146 (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
147 dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n");
148 return -EINVAL;
149 }
150
151 if (lsc_cfg->offset & 3) {
152 dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of "
153 "4\n");
154 return -EINVAL;
155 }
156
157 if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
158 dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n");
159 return -EINVAL;
160 }
161
162 format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
163 V4L2_SUBDEV_FORMAT_ACTIVE);
164 input_width = format->width;
165 input_height = format->height;
166
167 /* Calculate minimum bytesize for validation */
168 paxel_width = 1 << paxel_shift_x;
169 min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
170 >> paxel_shift_x) + 1;
171
172 paxel_height = 1 << paxel_shift_y;
173 min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
174 >> paxel_shift_y) + 1;
175
176 min_size = 4 * min_width * min_height;
177 if (min_size > lsc_cfg->size) {
178 dev_dbg(isp->dev, "CCDC: LSC: too small table\n");
179 return -EINVAL;
180 }
181 if (lsc_cfg->offset < (min_width * 4)) {
182 dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n");
183 return -EINVAL;
184 }
185 if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
186 dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n");
187 return -EINVAL;
188 }
189 return 0;
190}
191
192/*
193 * ccdc_lsc_program_table - Program Lens Shading Compensation table address.
194 * @ccdc: Pointer to ISP CCDC device.
195 */
196static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr)
197{
198 isp_reg_writel(to_isp_device(ccdc), addr,
199 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
200}
201
202/*
203 * ccdc_lsc_setup_regs - Configures the lens shading compensation module
204 * @ccdc: Pointer to ISP CCDC device.
205 */
206static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc,
207 struct omap3isp_ccdc_lsc_config *cfg)
208{
209 struct isp_device *isp = to_isp_device(ccdc);
210 int reg;
211
212 isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC,
213 ISPCCDC_LSC_TABLE_OFFSET);
214
215 reg = 0;
216 reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
217 reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
218 reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
219 isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
220
221 reg = 0;
222 reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
223 reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
224 reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
225 reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
226 isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC,
227 ISPCCDC_LSC_INITIAL);
228}
229
230static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc)
231{
232 struct isp_device *isp = to_isp_device(ccdc);
233 unsigned int wait;
234
235 isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
236 OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
237
238 /* timeout 1 ms */
239 for (wait = 0; wait < 1000; wait++) {
240 if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) &
241 IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) {
242 isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
243 OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
244 return 0;
245 }
246
247 rmb();
248 udelay(1);
249 }
250
251 return -ETIMEDOUT;
252}
253
254/*
255 * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module.
256 * @ccdc: Pointer to ISP CCDC device.
257 * @enable: 0 Disables LSC, 1 Enables LSC.
258 */
259static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
260{
261 struct isp_device *isp = to_isp_device(ccdc);
262 const struct v4l2_mbus_framefmt *format =
263 __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
264 V4L2_SUBDEV_FORMAT_ACTIVE);
265
266 if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) &&
267 (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) &&
268 (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) &&
269 (format->code != V4L2_MBUS_FMT_SGBRG10_1X10))
270 return -EINVAL;
271
272 if (enable)
273 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ);
274
275 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
276 ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0);
277
278 if (enable) {
279 if (ccdc_lsc_wait_prefetch(ccdc) < 0) {
280 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,
281 ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);
282 ccdc->lsc.state = LSC_STATE_STOPPED;
283 dev_warn(to_device(ccdc), "LSC prefecth timeout\n");
284 return -ETIMEDOUT;
285 }
286 ccdc->lsc.state = LSC_STATE_RUNNING;
287 } else {
288 ccdc->lsc.state = LSC_STATE_STOPPING;
289 }
290
291 return 0;
292}
293
294static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc)
295{
296 struct isp_device *isp = to_isp_device(ccdc);
297
298 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) &
299 ISPCCDC_LSC_BUSY;
300}
301
302/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine
303 * @ccdc: Pointer to ISP CCDC device
304 * @req: New configuration request
305 *
306 * context: in_interrupt()
307 */
308static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc,
309 struct ispccdc_lsc_config_req *req)
310{
311 if (!req->enable)
312 return -EINVAL;
313
314 if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) {
315 dev_dbg(to_device(ccdc), "Discard LSC configuration\n");
316 return -EINVAL;
317 }
318
319 if (ccdc_lsc_busy(ccdc))
320 return -EBUSY;
321
322 ccdc_lsc_setup_regs(ccdc, &req->config);
323 ccdc_lsc_program_table(ccdc, req->table);
324 return 0;
325}
326
327/*
328 * ccdc_lsc_error_handler - Handle LSC prefetch error scenario.
329 * @ccdc: Pointer to ISP CCDC device.
330 *
331 * Disables LSC, and defers enablement to shadow registers update time.
332 */
333static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc)
334{
335 struct isp_device *isp = to_isp_device(ccdc);
336 /*
337 * From OMAP3 TRM: When this event is pending, the module
338 * goes into transparent mode (output =input). Normal
339 * operation can be resumed at the start of the next frame
340 * after:
341 * 1) Clearing this event
342 * 2) Disabling the LSC module
343 * 3) Enabling it
344 */
345 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
346 ISPCCDC_LSC_ENABLE);
347 ccdc->lsc.state = LSC_STATE_STOPPED;
348}
349
350static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
351 struct ispccdc_lsc_config_req *req)
352{
353 struct isp_device *isp = to_isp_device(ccdc);
354
355 if (req == NULL)
356 return;
357
358 if (req->iovm)
359 dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
360 req->iovm->sgt->nents, DMA_TO_DEVICE);
361 if (req->table)
362 iommu_vfree(isp->iommu, req->table);
363 kfree(req);
364}
365
366static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc,
367 struct list_head *queue)
368{
369 struct ispccdc_lsc_config_req *req, *n;
370 unsigned long flags;
371
372 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
373 list_for_each_entry_safe(req, n, queue, list) {
374 list_del(&req->list);
375 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
376 ccdc_lsc_free_request(ccdc, req);
377 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
378 }
379 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
380}
381
382static void ccdc_lsc_free_table_work(struct work_struct *work)
383{
384 struct isp_ccdc_device *ccdc;
385 struct ispccdc_lsc *lsc;
386
387 lsc = container_of(work, struct ispccdc_lsc, table_work);
388 ccdc = container_of(lsc, struct isp_ccdc_device, lsc);
389
390 ccdc_lsc_free_queue(ccdc, &lsc->free_queue);
391}
392
393/*
394 * ccdc_lsc_config - Configure the LSC module from a userspace request
395 *
396 * Store the request LSC configuration in the LSC engine request pointer. The
397 * configuration will be applied to the hardware when the CCDC will be enabled,
398 * or at the next LSC interrupt if the CCDC is already running.
399 */
400static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
401 struct omap3isp_ccdc_update_config *config)
402{
403 struct isp_device *isp = to_isp_device(ccdc);
404 struct ispccdc_lsc_config_req *req;
405 unsigned long flags;
406 void *table;
407 u16 update;
408 int ret;
409
410 update = config->update &
411 (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC);
412 if (!update)
413 return 0;
414
415 if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) {
416 dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table "
417 "need to be supplied\n", __func__);
418 return -EINVAL;
419 }
420
421 req = kzalloc(sizeof(*req), GFP_KERNEL);
422 if (req == NULL)
423 return -ENOMEM;
424
425 if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) {
426 if (copy_from_user(&req->config, config->lsc_cfg,
427 sizeof(req->config))) {
428 ret = -EFAULT;
429 goto done;
430 }
431
432 req->enable = 1;
433
434 req->table = iommu_vmalloc(isp->iommu, 0, req->config.size,
435 IOMMU_FLAG);
436 if (IS_ERR_VALUE(req->table)) {
437 req->table = 0;
438 ret = -ENOMEM;
439 goto done;
440 }
441
442 req->iovm = find_iovm_area(isp->iommu, req->table);
443 if (req->iovm == NULL) {
444 ret = -ENOMEM;
445 goto done;
446 }
447
448 if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl,
449 req->iovm->sgt->nents, DMA_TO_DEVICE)) {
450 ret = -ENOMEM;
451 req->iovm = NULL;
452 goto done;
453 }
454
455 dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl,
456 req->iovm->sgt->nents, DMA_TO_DEVICE);
457
458 table = da_to_va(isp->iommu, req->table);
459 if (copy_from_user(table, config->lsc, req->config.size)) {
460 ret = -EFAULT;
461 goto done;
462 }
463
464 dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl,
465 req->iovm->sgt->nents, DMA_TO_DEVICE);
466 }
467
468 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
469 if (ccdc->lsc.request) {
470 list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
471 schedule_work(&ccdc->lsc.table_work);
472 }
473 ccdc->lsc.request = req;
474 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
475
476 ret = 0;
477
478done:
479 if (ret < 0)
480 ccdc_lsc_free_request(ccdc, req);
481
482 return ret;
483}
484
485static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
486{
487 unsigned long flags;
488
489 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
490 if (ccdc->lsc.active) {
491 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
492 return 1;
493 }
494 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
495 return 0;
496}
497
498static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
499{
500 struct ispccdc_lsc *lsc = &ccdc->lsc;
501
502 if (lsc->state != LSC_STATE_STOPPED)
503 return -EINVAL;
504
505 if (lsc->active) {
506 list_add_tail(&lsc->active->list, &lsc->free_queue);
507 lsc->active = NULL;
508 }
509
510 if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) {
511 omap3isp_sbl_disable(to_isp_device(ccdc),
512 OMAP3_ISP_SBL_CCDC_LSC_READ);
513 list_add_tail(&lsc->request->list, &lsc->free_queue);
514 lsc->request = NULL;
515 goto done;
516 }
517
518 lsc->active = lsc->request;
519 lsc->request = NULL;
520 __ccdc_lsc_enable(ccdc, 1);
521
522done:
523 if (!list_empty(&lsc->free_queue))
524 schedule_work(&lsc->table_work);
525
526 return 0;
527}
528
529/* -----------------------------------------------------------------------------
530 * Parameters configuration
531 */
532
533/*
534 * ccdc_configure_clamp - Configure optical-black or digital clamping
535 * @ccdc: Pointer to ISP CCDC device.
536 *
537 * The CCDC performs either optical-black or digital clamp. Configure and enable
538 * the selected clamp method.
539 */
540static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc)
541{
542 struct isp_device *isp = to_isp_device(ccdc);
543 u32 clamp;
544
545 if (ccdc->obclamp) {
546 clamp = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
547 clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
548 clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
549 clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
550 isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
551 } else {
552 isp_reg_writel(isp, ccdc->clamp.dcsubval,
553 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
554 }
555
556 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
557 ISPCCDC_CLAMP_CLAMPEN,
558 ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0);
559}
560
561/*
562 * ccdc_configure_fpc - Configure Faulty Pixel Correction
563 * @ccdc: Pointer to ISP CCDC device.
564 */
565static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc)
566{
567 struct isp_device *isp = to_isp_device(ccdc);
568
569 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN);
570
571 if (!ccdc->fpc_en)
572 return;
573
574 isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC,
575 ISPCCDC_FPC_ADDR);
576 /* The FPNUM field must be set before enabling FPC. */
577 isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
578 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
579 isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) |
580 ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
581}
582
583/*
584 * ccdc_configure_black_comp - Configure Black Level Compensation.
585 * @ccdc: Pointer to ISP CCDC device.
586 */
587static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc)
588{
589 struct isp_device *isp = to_isp_device(ccdc);
590 u32 blcomp;
591
592 blcomp = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
593 blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
594 blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
595 blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
596
597 isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
598}
599
600/*
601 * ccdc_configure_lpf - Configure Low-Pass Filter (LPF).
602 * @ccdc: Pointer to ISP CCDC device.
603 */
604static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)
605{
606 struct isp_device *isp = to_isp_device(ccdc);
607
608 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
609 ISPCCDC_SYN_MODE_LPF,
610 ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0);
611}
612
613/*
614 * ccdc_configure_alaw - Configure A-law compression.
615 * @ccdc: Pointer to ISP CCDC device.
616 */
617static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)
618{
619 struct isp_device *isp = to_isp_device(ccdc);
620 u32 alaw = 0;
621
622 switch (ccdc->syncif.datsz) {
623 case 8:
624 return;
625
626 case 10:
627 alaw = ISPCCDC_ALAW_GWDI_9_0;
628 break;
629 case 11:
630 alaw = ISPCCDC_ALAW_GWDI_10_1;
631 break;
632 case 12:
633 alaw = ISPCCDC_ALAW_GWDI_11_2;
634 break;
635 case 13:
636 alaw = ISPCCDC_ALAW_GWDI_12_3;
637 break;
638 }
639
640 if (ccdc->alaw)
641 alaw |= ISPCCDC_ALAW_CCDTBL;
642
643 isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
644}
645
646/*
647 * ccdc_config_imgattr - Configure sensor image specific attributes.
648 * @ccdc: Pointer to ISP CCDC device.
649 * @colptn: Color pattern of the sensor.
650 */
651static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)
652{
653 struct isp_device *isp = to_isp_device(ccdc);
654
655 isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
656}
657
658/*
659 * ccdc_config - Set CCDC configuration from userspace
660 * @ccdc: Pointer to ISP CCDC device.
661 * @userspace_add: Structure containing CCDC configuration sent from userspace.
662 *
663 * Returns 0 if successful, -EINVAL if the pointer to the configuration
664 * structure is null, or the copy_from_user function fails to copy user space
665 * memory to kernel space memory.
666 */
667static int ccdc_config(struct isp_ccdc_device *ccdc,
668 struct omap3isp_ccdc_update_config *ccdc_struct)
669{
670 struct isp_device *isp = to_isp_device(ccdc);
671 unsigned long flags;
672
673 spin_lock_irqsave(&ccdc->lock, flags);
674 ccdc->shadow_update = 1;
675 spin_unlock_irqrestore(&ccdc->lock, flags);
676
677 if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) {
678 ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag);
679 ccdc->update |= OMAP3ISP_CCDC_ALAW;
680 }
681
682 if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) {
683 ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag);
684 ccdc->update |= OMAP3ISP_CCDC_LPF;
685 }
686
687 if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) {
688 if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp,
689 sizeof(ccdc->clamp))) {
690 ccdc->shadow_update = 0;
691 return -EFAULT;
692 }
693
694 ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag);
695 ccdc->update |= OMAP3ISP_CCDC_BLCLAMP;
696 }
697
698 if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) {
699 if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp,
700 sizeof(ccdc->blcomp))) {
701 ccdc->shadow_update = 0;
702 return -EFAULT;
703 }
704
705 ccdc->update |= OMAP3ISP_CCDC_BCOMP;
706 }
707
708 ccdc->shadow_update = 0;
709
710 if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) {
711 u32 table_old = 0;
712 u32 table_new;
713 u32 size;
714
715 if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
716 return -EBUSY;
717
718 ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag);
719
720 if (ccdc->fpc_en) {
721 if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc,
722 sizeof(ccdc->fpc)))
723 return -EFAULT;
724
725 /*
726 * table_new must be 64-bytes aligned, but it's
727 * already done by iommu_vmalloc().
728 */
729 size = ccdc->fpc.fpnum * 4;
730 table_new = iommu_vmalloc(isp->iommu, 0, size,
731 IOMMU_FLAG);
732 if (IS_ERR_VALUE(table_new))
733 return -ENOMEM;
734
735 if (copy_from_user(da_to_va(isp->iommu, table_new),
736 (__force void __user *)
737 ccdc->fpc.fpcaddr, size)) {
738 iommu_vfree(isp->iommu, table_new);
739 return -EFAULT;
740 }
741
742 table_old = ccdc->fpc.fpcaddr;
743 ccdc->fpc.fpcaddr = table_new;
744 }
745
746 ccdc_configure_fpc(ccdc);
747 if (table_old != 0)
748 iommu_vfree(isp->iommu, table_old);
749 }
750
751 return ccdc_lsc_config(ccdc, ccdc_struct);
752}
753
754static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)
755{
756 if (ccdc->update & OMAP3ISP_CCDC_ALAW) {
757 ccdc_configure_alaw(ccdc);
758 ccdc->update &= ~OMAP3ISP_CCDC_ALAW;
759 }
760
761 if (ccdc->update & OMAP3ISP_CCDC_LPF) {
762 ccdc_configure_lpf(ccdc);
763 ccdc->update &= ~OMAP3ISP_CCDC_LPF;
764 }
765
766 if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) {
767 ccdc_configure_clamp(ccdc);
768 ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP;
769 }
770
771 if (ccdc->update & OMAP3ISP_CCDC_BCOMP) {
772 ccdc_configure_black_comp(ccdc);
773 ccdc->update &= ~OMAP3ISP_CCDC_BCOMP;
774 }
775}
776
777/*
778 * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers
779 * @dev: Pointer to ISP device
780 */
781void omap3isp_ccdc_restore_context(struct isp_device *isp)
782{
783 struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
784
785 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
786
787 ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF
788 | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP;
789 ccdc_apply_controls(ccdc);
790 ccdc_configure_fpc(ccdc);
791}
792
793/* -----------------------------------------------------------------------------
794 * Format- and pipeline-related configuration helpers
795 */
796
797/*
798 * ccdc_config_vp - Configure the Video Port.
799 * @ccdc: Pointer to ISP CCDC device.
800 */
801static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
802{
803 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
804 struct isp_device *isp = to_isp_device(ccdc);
805 unsigned long l3_ick = pipe->l3_ick;
806 unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
807 unsigned int div = 0;
808 u32 fmtcfg_vp;
809
810 fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
811 & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
812
813 switch (ccdc->syncif.datsz) {
814 case 8:
815 case 10:
816 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
817 break;
818 case 11:
819 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
820 break;
821 case 12:
822 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
823 break;
824 case 13:
825 fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
826 break;
827 };
828
829 if (pipe->input)
830 div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
831 else if (ccdc->vpcfg.pixelclk)
832 div = l3_ick / ccdc->vpcfg.pixelclk;
833
834 div = clamp(div, 2U, max_div);
835 fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
836
837 isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
838}
839
840/*
841 * ccdc_enable_vp - Enable Video Port.
842 * @ccdc: Pointer to ISP CCDC device.
843 * @enable: 0 Disables VP, 1 Enables VP
844 *
845 * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
846 */
847static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
848{
849 struct isp_device *isp = to_isp_device(ccdc);
850
851 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
852 ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
853}
854
855/*
856 * ccdc_config_outlineoffset - Configure memory saving output line offset
857 * @ccdc: Pointer to ISP CCDC device.
858 * @offset: Address offset to start a new line. Must be twice the
859 * Output width and aligned on 32 byte boundary
860 * @oddeven: Specifies the odd/even line pattern to be chosen to store the
861 * output.
862 * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
863 *
864 * - Configures the output line offset when stored in memory
865 * - Sets the odd/even line pattern to store the output
866 * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
867 * - Configures the number of even and odd line fields in case of rearranging
868 * the lines.
869 */
870static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
871 u32 offset, u8 oddeven, u8 numlines)
872{
873 struct isp_device *isp = to_isp_device(ccdc);
874
875 isp_reg_writel(isp, offset & 0xffff,
876 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
877
878 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
879 ISPCCDC_SDOFST_FINV);
880
881 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
882 ISPCCDC_SDOFST_FOFST_4L);
883
884 switch (oddeven) {
885 case EVENEVEN:
886 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
887 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
888 break;
889 case ODDEVEN:
890 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
891 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
892 break;
893 case EVENODD:
894 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
895 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
896 break;
897 case ODDODD:
898 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
899 (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
900 break;
901 default:
902 break;
903 }
904}
905
906/*
907 * ccdc_set_outaddr - Set memory address to save output image
908 * @ccdc: Pointer to ISP CCDC device.
909 * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
910 *
911 * Sets the memory address where the output will be saved.
912 */
913static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr)
914{
915 struct isp_device *isp = to_isp_device(ccdc);
916
917 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
918}
919
920/*
921 * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input
922 * @ccdc: Pointer to ISP CCDC device.
923 * @max_rate: Maximum calculated data rate.
924 *
925 * Returns in *max_rate less value between calculated and passed
926 */
927void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
928 unsigned int *max_rate)
929{
930 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
931 unsigned int rate;
932
933 if (pipe == NULL)
934 return;
935
936 /*
937 * TRM says that for parallel sensors the maximum data rate
938 * should be 90% form L3/2 clock, otherwise just L3/2.
939 */
940 if (ccdc->input == CCDC_INPUT_PARALLEL)
941 rate = pipe->l3_ick / 2 * 9 / 10;
942 else
943 rate = pipe->l3_ick / 2;
944
945 *max_rate = min(*max_rate, rate);
946}
947
948/*
949 * ccdc_config_sync_if - Set CCDC sync interface configuration
950 * @ccdc: Pointer to ISP CCDC device.
951 * @syncif: Structure containing the sync parameters like field state, CCDC in
952 * master/slave mode, raw/yuv data, polarity of data, field, hs, vs
953 * signals.
954 */
955static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
956 struct ispccdc_syncif *syncif)
957{
958 struct isp_device *isp = to_isp_device(ccdc);
959 u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC,
960 ISPCCDC_SYN_MODE);
961
962 syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
963
964 if (syncif->fldstat)
965 syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT;
966 else
967 syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
968
969 syn_mode &= ~ISPCCDC_SYN_MODE_DATSIZ_MASK;
970 switch (syncif->datsz) {
971 case 8:
972 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
973 break;
974 case 10:
975 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;
976 break;
977 case 11:
978 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;
979 break;
980 case 12:
981 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
982 break;
983 };
984
985 if (syncif->fldmode)
986 syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
987 else
988 syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE;
989
990 if (syncif->datapol)
991 syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
992 else
993 syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL;
994
995 if (syncif->fldpol)
996 syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
997 else
998 syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL;
999
1000 if (syncif->hdpol)
1001 syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
1002 else
1003 syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL;
1004
1005 if (syncif->vdpol)
1006 syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
1007 else
1008 syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL;
1009
1010 if (syncif->ccdc_mastermode) {
1011 syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
1012 isp_reg_writel(isp,
1013 syncif->hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
1014 | syncif->vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
1015 OMAP3_ISP_IOMEM_CCDC,
1016 ISPCCDC_HD_VD_WID);
1017
1018 isp_reg_writel(isp,
1019 syncif->ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
1020 | syncif->hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
1021 OMAP3_ISP_IOMEM_CCDC,
1022 ISPCCDC_PIX_LINES);
1023 } else
1024 syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
1025 ISPCCDC_SYN_MODE_VDHDOUT);
1026
1027 isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
1028
1029 if (!syncif->bt_r656_en)
1030 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
1031 ISPCCDC_REC656IF_R656ON);
1032}
1033
1034/* CCDC formats descriptions */
1035static const u32 ccdc_sgrbg_pattern =
1036 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
1037 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
1038 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
1039 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
1040 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
1041 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
1042 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
1043 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
1044 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
1045 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
1046 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
1047 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
1048 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
1049 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
1050 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
1051 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
1052
1053static const u32 ccdc_srggb_pattern =
1054 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
1055 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
1056 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
1057 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
1058 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
1059 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
1060 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
1061 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
1062 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
1063 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
1064 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
1065 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
1066 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
1067 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
1068 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
1069 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
1070
1071static const u32 ccdc_sbggr_pattern =
1072 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
1073 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
1074 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
1075 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
1076 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
1077 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
1078 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
1079 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
1080 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
1081 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
1082 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
1083 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
1084 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
1085 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
1086 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
1087 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
1088
1089static const u32 ccdc_sgbrg_pattern =
1090 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
1091 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
1092 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
1093 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
1094 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
1095 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
1096 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
1097 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
1098 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
1099 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
1100 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
1101 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
1102 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
1103 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
1104 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
1105 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
1106
1107static void ccdc_configure(struct isp_ccdc_device *ccdc)
1108{
1109 struct isp_device *isp = to_isp_device(ccdc);
1110 struct isp_parallel_platform_data *pdata = NULL;
1111 struct v4l2_subdev *sensor;
1112 struct v4l2_mbus_framefmt *format;
1113 struct media_pad *pad;
1114 unsigned long flags;
1115 u32 syn_mode;
1116 u32 ccdc_pattern;
1117
1118 if (ccdc->input == CCDC_INPUT_PARALLEL) {
1119 pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
1120 sensor = media_entity_to_v4l2_subdev(pad->entity);
1121 pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
1122 ->bus.parallel;
1123 }
1124
1125 omap3isp_configure_bridge(isp, ccdc->input, pdata);
1126
1127 ccdc->syncif.datsz = pdata ? pdata->width : 10;
1128 ccdc_config_sync_if(ccdc, &ccdc->syncif);
1129
1130 /* CCDC_PAD_SINK */
1131 format = &ccdc->formats[CCDC_PAD_SINK];
1132
1133 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
1134
1135 /* Use the raw, unprocessed data when writing to memory. The H3A and
1136 * histogram modules are still fed with lens shading corrected data.
1137 */
1138 syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
1139
1140 if (ccdc->output & CCDC_OUTPUT_MEMORY)
1141 syn_mode |= ISPCCDC_SYN_MODE_WEN;
1142 else
1143 syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
1144
1145 if (ccdc->output & CCDC_OUTPUT_RESIZER)
1146 syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
1147 else
1148 syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
1149
1150 /* Use PACK8 mode for 1byte per pixel formats. */
1151 if (omap3isp_video_format_info(format->code)->bpp <= 8)
1152 syn_mode |= ISPCCDC_SYN_MODE_PACK8;
1153 else
1154 syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
1155
1156 isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
1157
1158 /* Mosaic filter */
1159 switch (format->code) {
1160 case V4L2_MBUS_FMT_SRGGB10_1X10:
1161 case V4L2_MBUS_FMT_SRGGB12_1X12:
1162 ccdc_pattern = ccdc_srggb_pattern;
1163 break;
1164 case V4L2_MBUS_FMT_SBGGR10_1X10:
1165 case V4L2_MBUS_FMT_SBGGR12_1X12:
1166 ccdc_pattern = ccdc_sbggr_pattern;
1167 break;
1168 case V4L2_MBUS_FMT_SGBRG10_1X10:
1169 case V4L2_MBUS_FMT_SGBRG12_1X12:
1170 ccdc_pattern = ccdc_sgbrg_pattern;
1171 break;
1172 default:
1173 /* Use GRBG */
1174 ccdc_pattern = ccdc_sgrbg_pattern;
1175 break;
1176 }
1177 ccdc_config_imgattr(ccdc, ccdc_pattern);
1178
1179 /* Generate VD0 on the last line of the image and VD1 on the
1180 * 2/3 height line.
1181 */
1182 isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
1183 ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
1184 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
1185
1186 /* CCDC_PAD_SOURCE_OF */
1187 format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
1188
1189 isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
1190 ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
1191 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
1192 isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT,
1193 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
1194 isp_reg_writel(isp, (format->height - 1)
1195 << ISPCCDC_VERT_LINES_NLV_SHIFT,
1196 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
1197
1198 ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
1199
1200 /* CCDC_PAD_SOURCE_VP */
1201 format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
1202
1203 isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
1204 (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
1205 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
1206 isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
1207 ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
1208 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
1209
1210 isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
1211 (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
1212 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
1213
1214 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
1215 if (ccdc->lsc.request == NULL)
1216 goto unlock;
1217
1218 WARN_ON(ccdc->lsc.active);
1219
1220 /* Get last good LSC configuration. If it is not supported for
1221 * the current active resolution discard it.
1222 */
1223 if (ccdc->lsc.active == NULL &&
1224 __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) {
1225 ccdc->lsc.active = ccdc->lsc.request;
1226 } else {
1227 list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
1228 schedule_work(&ccdc->lsc.table_work);
1229 }
1230
1231 ccdc->lsc.request = NULL;
1232
1233unlock:
1234 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
1235
1236 ccdc_apply_controls(ccdc);
1237}
1238
1239static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
1240{
1241 struct isp_device *isp = to_isp_device(ccdc);
1242
1243 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
1244 ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
1245}
1246
1247static int ccdc_disable(struct isp_ccdc_device *ccdc)
1248{
1249 unsigned long flags;
1250 int ret = 0;
1251
1252 spin_lock_irqsave(&ccdc->lock, flags);
1253 if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
1254 ccdc->stopping = CCDC_STOP_REQUEST;
1255 spin_unlock_irqrestore(&ccdc->lock, flags);
1256
1257 ret = wait_event_timeout(ccdc->wait,
1258 ccdc->stopping == CCDC_STOP_FINISHED,
1259 msecs_to_jiffies(2000));
1260 if (ret == 0) {
1261 ret = -ETIMEDOUT;
1262 dev_warn(to_device(ccdc), "CCDC stop timeout!\n");
1263 }
1264
1265 omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ);
1266
1267 mutex_lock(&ccdc->ioctl_lock);
1268 ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
1269 ccdc->lsc.request = ccdc->lsc.active;
1270 ccdc->lsc.active = NULL;
1271 cancel_work_sync(&ccdc->lsc.table_work);
1272 ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
1273 mutex_unlock(&ccdc->ioctl_lock);
1274
1275 ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
1276
1277 return ret > 0 ? 0 : ret;
1278}
1279
1280static void ccdc_enable(struct isp_ccdc_device *ccdc)
1281{
1282 if (ccdc_lsc_is_configured(ccdc))
1283 __ccdc_lsc_enable(ccdc, 1);
1284 __ccdc_enable(ccdc, 1);
1285}
1286
1287/* -----------------------------------------------------------------------------
1288 * Interrupt handling
1289 */
1290
1291/*
1292 * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
1293 * @ccdc: Pointer to ISP CCDC device.
1294 *
1295 * Returns zero if the CCDC is idle and the image has been written to
1296 * memory, too.
1297 */
1298static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc)
1299{
1300 struct isp_device *isp = to_isp_device(ccdc);
1301
1302 return omap3isp_ccdc_busy(ccdc)
1303 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
1304 ISPSBL_CCDC_WR_0_DATA_READY)
1305 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
1306 ISPSBL_CCDC_WR_0_DATA_READY)
1307 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
1308 ISPSBL_CCDC_WR_0_DATA_READY)
1309 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
1310 ISPSBL_CCDC_WR_0_DATA_READY);
1311}
1312
1313/*
1314 * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle
1315 * @ccdc: Pointer to ISP CCDC device.
1316 * @max_wait: Max retry count in us for wait for idle/busy transition.
1317 */
1318static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
1319 unsigned int max_wait)
1320{
1321 unsigned int wait = 0;
1322
1323 if (max_wait == 0)
1324 max_wait = 10000; /* 10 ms */
1325
1326 for (wait = 0; wait <= max_wait; wait++) {
1327 if (!ccdc_sbl_busy(ccdc))
1328 return 0;
1329
1330 rmb();
1331 udelay(1);
1332 }
1333
1334 return -EBUSY;
1335}
1336
1337/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
1338 * @ccdc: Pointer to ISP CCDC device.
1339 * @event: Pointing which event trigger handler
1340 *
1341 * Return 1 when the event and stopping request combination is satisfyied,
1342 * zero otherwise.
1343 */
1344static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
1345{
1346 int rval = 0;
1347
1348 switch ((ccdc->stopping & 3) | event) {
1349 case CCDC_STOP_REQUEST | CCDC_EVENT_VD1:
1350 if (ccdc->lsc.state != LSC_STATE_STOPPED)
1351 __ccdc_lsc_enable(ccdc, 0);
1352 __ccdc_enable(ccdc, 0);
1353 ccdc->stopping = CCDC_STOP_EXECUTED;
1354 return 1;
1355
1356 case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0:
1357 ccdc->stopping |= CCDC_STOP_CCDC_FINISHED;
1358 if (ccdc->lsc.state == LSC_STATE_STOPPED)
1359 ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
1360 rval = 1;
1361 break;
1362
1363 case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE:
1364 ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
1365 rval = 1;
1366 break;
1367
1368 case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1:
1369 return 1;
1370 }
1371
1372 if (ccdc->stopping == CCDC_STOP_FINISHED) {
1373 wake_up(&ccdc->wait);
1374 rval = 1;
1375 }
1376
1377 return rval;
1378}
1379
1380static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
1381{
1382 struct video_device *vdev = &ccdc->subdev.devnode;
1383 struct v4l2_event event;
1384
1385 memset(&event, 0, sizeof(event));
1386 event.type = V4L2_EVENT_OMAP3ISP_HS_VS;
1387
1388 v4l2_event_queue(vdev, &event);
1389}
1390
1391/*
1392 * ccdc_lsc_isr - Handle LSC events
1393 * @ccdc: Pointer to ISP CCDC device.
1394 * @events: LSC events
1395 */
1396static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
1397{
1398 unsigned long flags;
1399
1400 if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
1401 ccdc_lsc_error_handler(ccdc);
1402 ccdc->error = 1;
1403 dev_dbg(to_device(ccdc), "lsc prefetch error\n");
1404 }
1405
1406 if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ))
1407 return;
1408
1409 /* LSC_DONE interrupt occur, there are two cases
1410 * 1. stopping for reconfiguration
1411 * 2. stopping because of STREAM OFF command
1412 */
1413 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
1414
1415 if (ccdc->lsc.state == LSC_STATE_STOPPING)
1416 ccdc->lsc.state = LSC_STATE_STOPPED;
1417
1418 if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
1419 goto done;
1420
1421 if (ccdc->lsc.state != LSC_STATE_RECONFIG)
1422 goto done;
1423
1424 /* LSC is in STOPPING state, change to the new state */
1425 ccdc->lsc.state = LSC_STATE_STOPPED;
1426
1427 /* This is an exception. Start of frame and LSC_DONE interrupt
1428 * have been received on the same time. Skip this event and wait
1429 * for better times.
1430 */
1431 if (events & IRQ0STATUS_HS_VS_IRQ)
1432 goto done;
1433
1434 /* The LSC engine is stopped at this point. Enable it if there's a
1435 * pending request.
1436 */
1437 if (ccdc->lsc.request == NULL)
1438 goto done;
1439
1440 ccdc_lsc_enable(ccdc);
1441
1442done:
1443 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
1444}
1445
1446static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
1447{
1448 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
1449 struct isp_device *isp = to_isp_device(ccdc);
1450 struct isp_buffer *buffer;
1451 int restart = 0;
1452
1453 /* The CCDC generates VD0 interrupts even when disabled (the datasheet
1454 * doesn't explicitly state if that's supposed to happen or not, so it
1455 * can be considered as a hardware bug or as a feature, but we have to
1456 * deal with it anyway). Disabling the CCDC when no buffer is available
1457 * would thus not be enough, we need to handle the situation explicitly.
1458 */
1459 if (list_empty(&ccdc->video_out.dmaqueue))
1460 goto done;
1461
1462 /* We're in continuous mode, and memory writes were disabled due to a
1463 * buffer underrun. Reenable them now that we have a buffer. The buffer
1464 * address has been set in ccdc_video_queue.
1465 */
1466 if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
1467 restart = 1;
1468 ccdc->underrun = 0;
1469 goto done;
1470 }
1471
1472 if (ccdc_sbl_wait_idle(ccdc, 1000)) {
1473 dev_info(isp->dev, "CCDC won't become idle!\n");
1474 goto done;
1475 }
1476
1477 buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error);
1478 if (buffer != NULL) {
1479 ccdc_set_outaddr(ccdc, buffer->isp_addr);
1480 restart = 1;
1481 }
1482
1483 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1484
1485 if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT &&
1486 isp_pipeline_ready(pipe))
1487 omap3isp_pipeline_set_stream(pipe,
1488 ISP_PIPELINE_STREAM_SINGLESHOT);
1489
1490done:
1491 ccdc->error = 0;
1492 return restart;
1493}
1494
1495/*
1496 * ccdc_vd0_isr - Handle VD0 event
1497 * @ccdc: Pointer to ISP CCDC device.
1498 *
1499 * Executes LSC deferred enablement before next frame starts.
1500 */
1501static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
1502{
1503 unsigned long flags;
1504 int restart = 0;
1505
1506 if (ccdc->output & CCDC_OUTPUT_MEMORY)
1507 restart = ccdc_isr_buffer(ccdc);
1508
1509 spin_lock_irqsave(&ccdc->lock, flags);
1510 if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
1511 spin_unlock_irqrestore(&ccdc->lock, flags);
1512 return;
1513 }
1514
1515 if (!ccdc->shadow_update)
1516 ccdc_apply_controls(ccdc);
1517 spin_unlock_irqrestore(&ccdc->lock, flags);
1518
1519 if (restart)
1520 ccdc_enable(ccdc);
1521}
1522
1523/*
1524 * ccdc_vd1_isr - Handle VD1 event
1525 * @ccdc: Pointer to ISP CCDC device.
1526 */
1527static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
1528{
1529 unsigned long flags;
1530
1531 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
1532
1533 /*
1534 * Depending on the CCDC pipeline state, CCDC stopping should be
1535 * handled differently. In SINGLESHOT we emulate an internal CCDC
1536 * stopping because the CCDC hw works only in continuous mode.
1537 * When CONTINUOUS pipeline state is used and the CCDC writes it's
1538 * data to memory the CCDC and LSC are stopped immediately but
1539 * without change the CCDC stopping state machine. The CCDC
1540 * stopping state machine should be used only when user request
1541 * for stopping is received (SINGLESHOT is an exeption).
1542 */
1543 switch (ccdc->state) {
1544 case ISP_PIPELINE_STREAM_SINGLESHOT:
1545 ccdc->stopping = CCDC_STOP_REQUEST;
1546 break;
1547
1548 case ISP_PIPELINE_STREAM_CONTINUOUS:
1549 if (ccdc->output & CCDC_OUTPUT_MEMORY) {
1550 if (ccdc->lsc.state != LSC_STATE_STOPPED)
1551 __ccdc_lsc_enable(ccdc, 0);
1552 __ccdc_enable(ccdc, 0);
1553 }
1554 break;
1555
1556 case ISP_PIPELINE_STREAM_STOPPED:
1557 break;
1558 }
1559
1560 if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
1561 goto done;
1562
1563 if (ccdc->lsc.request == NULL)
1564 goto done;
1565
1566 /*
1567 * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ
1568 * do the appropriate changes in registers
1569 */
1570 if (ccdc->lsc.state == LSC_STATE_RUNNING) {
1571 __ccdc_lsc_enable(ccdc, 0);
1572 ccdc->lsc.state = LSC_STATE_RECONFIG;
1573 goto done;
1574 }
1575
1576 /* LSC has been in STOPPED state, enable it */
1577 if (ccdc->lsc.state == LSC_STATE_STOPPED)
1578 ccdc_lsc_enable(ccdc);
1579
1580done:
1581 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
1582}
1583
1584/*
1585 * omap3isp_ccdc_isr - Configure CCDC during interframe time.
1586 * @ccdc: Pointer to ISP CCDC device.
1587 * @events: CCDC events
1588 */
1589int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
1590{
1591 if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED)
1592 return 0;
1593
1594 if (events & IRQ0STATUS_CCDC_VD1_IRQ)
1595 ccdc_vd1_isr(ccdc);
1596
1597 ccdc_lsc_isr(ccdc, events);
1598
1599 if (events & IRQ0STATUS_CCDC_VD0_IRQ)
1600 ccdc_vd0_isr(ccdc);
1601
1602 if (events & IRQ0STATUS_HS_VS_IRQ)
1603 ccdc_hs_vs_isr(ccdc);
1604
1605 return 0;
1606}
1607
1608/* -----------------------------------------------------------------------------
1609 * ISP video operations
1610 */
1611
1612static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
1613{
1614 struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
1615
1616 if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
1617 return -ENODEV;
1618
1619 ccdc_set_outaddr(ccdc, buffer->isp_addr);
1620
1621 /* We now have a buffer queued on the output, restart the pipeline in
1622 * on the next CCDC interrupt if running in continuous mode (or when
1623 * starting the stream).
1624 */
1625 ccdc->underrun = 1;
1626
1627 return 0;
1628}
1629
1630static const struct isp_video_operations ccdc_video_ops = {
1631 .queue = ccdc_video_queue,
1632};
1633
1634/* -----------------------------------------------------------------------------
1635 * V4L2 subdev operations
1636 */
1637
1638/*
1639 * ccdc_ioctl - CCDC module private ioctl's
1640 * @sd: ISP CCDC V4L2 subdevice
1641 * @cmd: ioctl command
1642 * @arg: ioctl argument
1643 *
1644 * Return 0 on success or a negative error code otherwise.
1645 */
1646static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
1647{
1648 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
1649 int ret;
1650
1651 switch (cmd) {
1652 case VIDIOC_OMAP3ISP_CCDC_CFG:
1653 mutex_lock(&ccdc->ioctl_lock);
1654 ret = ccdc_config(ccdc, arg);
1655 mutex_unlock(&ccdc->ioctl_lock);
1656 break;
1657
1658 default:
1659 return -ENOIOCTLCMD;
1660 }
1661
1662 return ret;
1663}
1664
1665static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
1666 struct v4l2_event_subscription *sub)
1667{
1668 if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS)
1669 return -EINVAL;
1670
1671 return v4l2_event_subscribe(fh, sub);
1672}
1673
1674static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
1675 struct v4l2_event_subscription *sub)
1676{
1677 return v4l2_event_unsubscribe(fh, sub);
1678}
1679
1680/*
1681 * ccdc_set_stream - Enable/Disable streaming on the CCDC module
1682 * @sd: ISP CCDC V4L2 subdevice
1683 * @enable: Enable/disable stream
1684 *
1685 * When writing to memory, the CCDC hardware can't be enabled without a memory
1686 * buffer to write to. As the s_stream operation is called in response to a
1687 * STREAMON call without any buffer queued yet, just update the enabled field
1688 * and return immediately. The CCDC will be enabled in ccdc_isr_buffer().
1689 *
1690 * When not writing to memory enable the CCDC immediately.
1691 */
1692static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
1693{
1694 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
1695 struct isp_device *isp = to_isp_device(ccdc);
1696 int ret = 0;
1697
1698 if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) {
1699 if (enable == ISP_PIPELINE_STREAM_STOPPED)
1700 return 0;
1701
1702 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC);
1703 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
1704 ISPCCDC_CFG_VDLC);
1705
1706 ccdc_configure(ccdc);
1707
1708 /* TODO: Don't configure the video port if all of its output
1709 * links are inactive.
1710 */
1711 ccdc_config_vp(ccdc);
1712 ccdc_enable_vp(ccdc, 1);
1713 ccdc->error = 0;
1714 ccdc_print_status(ccdc);
1715 }
1716
1717 switch (enable) {
1718 case ISP_PIPELINE_STREAM_CONTINUOUS:
1719 if (ccdc->output & CCDC_OUTPUT_MEMORY)
1720 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
1721
1722 if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY))
1723 ccdc_enable(ccdc);
1724
1725 ccdc->underrun = 0;
1726 break;
1727
1728 case ISP_PIPELINE_STREAM_SINGLESHOT:
1729 if (ccdc->output & CCDC_OUTPUT_MEMORY &&
1730 ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT)
1731 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
1732
1733 ccdc_enable(ccdc);
1734 break;
1735
1736 case ISP_PIPELINE_STREAM_STOPPED:
1737 ret = ccdc_disable(ccdc);
1738 if (ccdc->output & CCDC_OUTPUT_MEMORY)
1739 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
1740 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC);
1741 ccdc->underrun = 0;
1742 break;
1743 }
1744
1745 ccdc->state = enable;
1746 return ret;
1747}
1748
1749static struct v4l2_mbus_framefmt *
1750__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
1751 unsigned int pad, enum v4l2_subdev_format_whence which)
1752{
1753 if (which == V4L2_SUBDEV_FORMAT_TRY)
1754 return v4l2_subdev_get_try_format(fh, pad);
1755 else
1756 return &ccdc->formats[pad];
1757}
1758
1759/*
1760 * ccdc_try_format - Try video format on a pad
1761 * @ccdc: ISP CCDC device
1762 * @fh : V4L2 subdev file handle
1763 * @pad: Pad number
1764 * @fmt: Format
1765 */
1766static void
1767ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
1768 unsigned int pad, struct v4l2_mbus_framefmt *fmt,
1769 enum v4l2_subdev_format_whence which)
1770{
1771 struct v4l2_mbus_framefmt *format;
1772 const struct isp_format_info *info;
1773 unsigned int width = fmt->width;
1774 unsigned int height = fmt->height;
1775 unsigned int i;
1776
1777 switch (pad) {
1778 case CCDC_PAD_SINK:
1779 /* TODO: If the CCDC output formatter pad is connected directly
1780 * to the resizer, only YUV formats can be used.
1781 */
1782 for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
1783 if (fmt->code == ccdc_fmts[i])
1784 break;
1785 }
1786
1787 /* If not found, use SGRBG10 as default */
1788 if (i >= ARRAY_SIZE(ccdc_fmts))
1789 fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
1790
1791 /* Clamp the input size. */
1792 fmt->width = clamp_t(u32, width, 32, 4096);
1793 fmt->height = clamp_t(u32, height, 32, 4096);
1794 break;
1795
1796 case CCDC_PAD_SOURCE_OF:
1797 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
1798 memcpy(fmt, format, sizeof(*fmt));
1799
1800 /* The data formatter truncates the number of horizontal output
1801 * pixels to a multiple of 16. To avoid clipping data, allow
1802 * callers to request an output size bigger than the input size
1803 * up to the nearest multiple of 16.
1804 */
1805 fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15);
1806 fmt->width &= ~15;
1807 fmt->height = clamp_t(u32, height, 32, fmt->height);
1808 break;
1809
1810 case CCDC_PAD_SOURCE_VP:
1811 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
1812 memcpy(fmt, format, sizeof(*fmt));
1813
1814 /* The video port interface truncates the data to 10 bits. */
1815 info = omap3isp_video_format_info(fmt->code);
1816 fmt->code = info->truncated;
1817
1818 /* The number of lines that can be clocked out from the video
1819 * port output must be at least one line less than the number
1820 * of input lines.
1821 */
1822 fmt->width = clamp_t(u32, width, 32, fmt->width);
1823 fmt->height = clamp_t(u32, height, 32, fmt->height - 1);
1824 break;
1825 }
1826
1827 /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is
1828 * stored on 2 bytes.
1829 */
1830 fmt->colorspace = V4L2_COLORSPACE_SRGB;
1831 fmt->field = V4L2_FIELD_NONE;
1832}
1833
1834/*
1835 * ccdc_enum_mbus_code - Handle pixel format enumeration
1836 * @sd : pointer to v4l2 subdev structure
1837 * @fh : V4L2 subdev file handle
1838 * @code : pointer to v4l2_subdev_mbus_code_enum structure
1839 * return -EINVAL or zero on success
1840 */
1841static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
1842 struct v4l2_subdev_fh *fh,
1843 struct v4l2_subdev_mbus_code_enum *code)
1844{
1845 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
1846 struct v4l2_mbus_framefmt *format;
1847
1848 switch (code->pad) {
1849 case CCDC_PAD_SINK:
1850 if (code->index >= ARRAY_SIZE(ccdc_fmts))
1851 return -EINVAL;
1852
1853 code->code = ccdc_fmts[code->index];
1854 break;
1855
1856 case CCDC_PAD_SOURCE_OF:
1857 case CCDC_PAD_SOURCE_VP:
1858 /* No format conversion inside CCDC */
1859 if (code->index != 0)
1860 return -EINVAL;
1861
1862 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK,
1863 V4L2_SUBDEV_FORMAT_TRY);
1864
1865 code->code = format->code;
1866 break;
1867
1868 default:
1869 return -EINVAL;
1870 }
1871
1872 return 0;
1873}
1874
1875static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
1876 struct v4l2_subdev_fh *fh,
1877 struct v4l2_subdev_frame_size_enum *fse)
1878{
1879 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
1880 struct v4l2_mbus_framefmt format;
1881
1882 if (fse->index != 0)
1883 return -EINVAL;
1884
1885 format.code = fse->code;
1886 format.width = 1;
1887 format.height = 1;
1888 ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1889 fse->min_width = format.width;
1890 fse->min_height = format.height;
1891
1892 if (format.code != fse->code)
1893 return -EINVAL;
1894
1895 format.code = fse->code;
1896 format.width = -1;
1897 format.height = -1;
1898 ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1899 fse->max_width = format.width;
1900 fse->max_height = format.height;
1901
1902 return 0;
1903}
1904
1905/*
1906 * ccdc_get_format - Retrieve the video format on a pad
1907 * @sd : ISP CCDC V4L2 subdevice
1908 * @fh : V4L2 subdev file handle
1909 * @fmt: Format
1910 *
1911 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
1912 * to the format type.
1913 */
1914static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1915 struct v4l2_subdev_format *fmt)
1916{
1917 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
1918 struct v4l2_mbus_framefmt *format;
1919
1920 format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
1921 if (format == NULL)
1922 return -EINVAL;
1923
1924 fmt->format = *format;
1925 return 0;
1926}
1927
1928/*
1929 * ccdc_set_format - Set the video format on a pad
1930 * @sd : ISP CCDC V4L2 subdevice
1931 * @fh : V4L2 subdev file handle
1932 * @fmt: Format
1933 *
1934 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
1935 * to the format type.
1936 */
1937static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1938 struct v4l2_subdev_format *fmt)
1939{
1940 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
1941 struct v4l2_mbus_framefmt *format;
1942
1943 format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
1944 if (format == NULL)
1945 return -EINVAL;
1946
1947 ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which);
1948 *format = fmt->format;
1949
1950 /* Propagate the format from sink to source */
1951 if (fmt->pad == CCDC_PAD_SINK) {
1952 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
1953 fmt->which);
1954 *format = fmt->format;
1955 ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format,
1956 fmt->which);
1957
1958 format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP,
1959 fmt->which);
1960 *format = fmt->format;
1961 ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format,
1962 fmt->which);
1963 }
1964
1965 return 0;
1966}
1967
1968/*
1969 * ccdc_init_formats - Initialize formats on all pads
1970 * @sd: ISP CCDC V4L2 subdevice
1971 * @fh: V4L2 subdev file handle
1972 *
1973 * Initialize all pad formats with default values. If fh is not NULL, try
1974 * formats are initialized on the file handle. Otherwise active formats are
1975 * initialized on the device.
1976 */
1977static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
1978{
1979 struct v4l2_subdev_format format;
1980
1981 memset(&format, 0, sizeof(format));
1982 format.pad = CCDC_PAD_SINK;
1983 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1984 format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
1985 format.format.width = 4096;
1986 format.format.height = 4096;
1987 ccdc_set_format(sd, fh, &format);
1988
1989 return 0;
1990}
1991
1992/* V4L2 subdev core operations */
1993static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {
1994 .ioctl = ccdc_ioctl,
1995 .subscribe_event = ccdc_subscribe_event,
1996 .unsubscribe_event = ccdc_unsubscribe_event,
1997};
1998
1999/* V4L2 subdev video operations */
2000static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {
2001 .s_stream = ccdc_set_stream,
2002};
2003
2004/* V4L2 subdev pad operations */
2005static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
2006 .enum_mbus_code = ccdc_enum_mbus_code,
2007 .enum_frame_size = ccdc_enum_frame_size,
2008 .get_fmt = ccdc_get_format,
2009 .set_fmt = ccdc_set_format,
2010};
2011
2012/* V4L2 subdev operations */
2013static const struct v4l2_subdev_ops ccdc_v4l2_ops = {
2014 .core = &ccdc_v4l2_core_ops,
2015 .video = &ccdc_v4l2_video_ops,
2016 .pad = &ccdc_v4l2_pad_ops,
2017};
2018
2019/* V4L2 subdev internal operations */
2020static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = {
2021 .open = ccdc_init_formats,
2022};
2023
2024/* -----------------------------------------------------------------------------
2025 * Media entity operations
2026 */
2027
2028/*
2029 * ccdc_link_setup - Setup CCDC connections
2030 * @entity: CCDC media entity
2031 * @local: Pad at the local end of the link
2032 * @remote: Pad at the remote end of the link
2033 * @flags: Link flags
2034 *
2035 * return -EINVAL or zero on success
2036 */
2037static int ccdc_link_setup(struct media_entity *entity,
2038 const struct media_pad *local,
2039 const struct media_pad *remote, u32 flags)
2040{
2041 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
2042 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
2043 struct isp_device *isp = to_isp_device(ccdc);
2044
2045 switch (local->index | media_entity_type(remote->entity)) {
2046 case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
2047 /* Read from the sensor (parallel interface), CCP2, CSI2a or
2048 * CSI2c.
2049 */
2050 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
2051 ccdc->input = CCDC_INPUT_NONE;
2052 break;
2053 }
2054
2055 if (ccdc->input != CCDC_INPUT_NONE)
2056 return -EBUSY;
2057
2058 if (remote->entity == &isp->isp_ccp2.subdev.entity)
2059 ccdc->input = CCDC_INPUT_CCP2B;
2060 else if (remote->entity == &isp->isp_csi2a.subdev.entity)
2061 ccdc->input = CCDC_INPUT_CSI2A;
2062 else if (remote->entity == &isp->isp_csi2c.subdev.entity)
2063 ccdc->input = CCDC_INPUT_CSI2C;
2064 else
2065 ccdc->input = CCDC_INPUT_PARALLEL;
2066
2067 break;
2068
2069 /*
2070 * The ISP core doesn't support pipelines with multiple video outputs.
2071 * Revisit this when it will be implemented, and return -EBUSY for now.
2072 */
2073
2074 case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
2075 /* Write to preview engine, histogram and H3A. When none of
2076 * those links are active, the video port can be disabled.
2077 */
2078 if (flags & MEDIA_LNK_FL_ENABLED) {
2079 if (ccdc->output & ~CCDC_OUTPUT_PREVIEW)
2080 return -EBUSY;
2081 ccdc->output |= CCDC_OUTPUT_PREVIEW;
2082 } else {
2083 ccdc->output &= ~CCDC_OUTPUT_PREVIEW;
2084 }
2085 break;
2086
2087 case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE:
2088 /* Write to memory */
2089 if (flags & MEDIA_LNK_FL_ENABLED) {
2090 if (ccdc->output & ~CCDC_OUTPUT_MEMORY)
2091 return -EBUSY;
2092 ccdc->output |= CCDC_OUTPUT_MEMORY;
2093 } else {
2094 ccdc->output &= ~CCDC_OUTPUT_MEMORY;
2095 }
2096 break;
2097
2098 case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV:
2099 /* Write to resizer */
2100 if (flags & MEDIA_LNK_FL_ENABLED) {
2101 if (ccdc->output & ~CCDC_OUTPUT_RESIZER)
2102 return -EBUSY;
2103 ccdc->output |= CCDC_OUTPUT_RESIZER;
2104 } else {
2105 ccdc->output &= ~CCDC_OUTPUT_RESIZER;
2106 }
2107 break;
2108
2109 default:
2110 return -EINVAL;
2111 }
2112
2113 return 0;
2114}
2115
2116/* media operations */
2117static const struct media_entity_operations ccdc_media_ops = {
2118 .link_setup = ccdc_link_setup,
2119};
2120
2121/*
2122 * ccdc_init_entities - Initialize V4L2 subdev and media entity
2123 * @ccdc: ISP CCDC module
2124 *
2125 * Return 0 on success and a negative error code on failure.
2126 */
2127static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
2128{
2129 struct v4l2_subdev *sd = &ccdc->subdev;
2130 struct media_pad *pads = ccdc->pads;
2131 struct media_entity *me = &sd->entity;
2132 int ret;
2133
2134 ccdc->input = CCDC_INPUT_NONE;
2135
2136 v4l2_subdev_init(sd, &ccdc_v4l2_ops);
2137 sd->internal_ops = &ccdc_v4l2_internal_ops;
2138 strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
2139 sd->grp_id = 1 << 16; /* group ID for isp subdevs */
2140 v4l2_set_subdevdata(sd, ccdc);
2141 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
2142 sd->nevents = OMAP3ISP_CCDC_NEVENTS;
2143
2144 pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
2145 pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
2146 pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;
2147
2148 me->ops = &ccdc_media_ops;
2149 ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
2150 if (ret < 0)
2151 return ret;
2152
2153 ccdc_init_formats(sd, NULL);
2154
2155 ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2156 ccdc->video_out.ops = &ccdc_video_ops;
2157 ccdc->video_out.isp = to_isp_device(ccdc);
2158 ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
2159 ccdc->video_out.bpl_alignment = 32;
2160
2161 ret = omap3isp_video_init(&ccdc->video_out, "CCDC");
2162 if (ret < 0)
2163 return ret;
2164
2165 /* Connect the CCDC subdev to the video node. */
2166 ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF,
2167 &ccdc->video_out.video.entity, 0, 0);
2168 if (ret < 0)
2169 return ret;
2170
2171 return 0;
2172}
2173
2174void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
2175{
2176 media_entity_cleanup(&ccdc->subdev.entity);
2177
2178 v4l2_device_unregister_subdev(&ccdc->subdev);
2179 omap3isp_video_unregister(&ccdc->video_out);
2180}
2181
2182int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
2183 struct v4l2_device *vdev)
2184{
2185 int ret;
2186
2187 /* Register the subdev and video node. */
2188 ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
2189 if (ret < 0)
2190 goto error;
2191
2192 ret = omap3isp_video_register(&ccdc->video_out, vdev);
2193 if (ret < 0)
2194 goto error;
2195
2196 return 0;
2197
2198error:
2199 omap3isp_ccdc_unregister_entities(ccdc);
2200 return ret;
2201}
2202
2203/* -----------------------------------------------------------------------------
2204 * ISP CCDC initialisation and cleanup
2205 */
2206
2207/*
2208 * omap3isp_ccdc_init - CCDC module initialization.
2209 * @dev: Device pointer specific to the OMAP3 ISP.
2210 *
2211 * TODO: Get the initialisation values from platform data.
2212 *
2213 * Return 0 on success or a negative error code otherwise.
2214 */
2215int omap3isp_ccdc_init(struct isp_device *isp)
2216{
2217 struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
2218
2219 spin_lock_init(&ccdc->lock);
2220 init_waitqueue_head(&ccdc->wait);
2221 mutex_init(&ccdc->ioctl_lock);
2222
2223 ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
2224
2225 INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work);
2226 ccdc->lsc.state = LSC_STATE_STOPPED;
2227 INIT_LIST_HEAD(&ccdc->lsc.free_queue);
2228 spin_lock_init(&ccdc->lsc.req_lock);
2229
2230 ccdc->syncif.ccdc_mastermode = 0;
2231 ccdc->syncif.datapol = 0;
2232 ccdc->syncif.datsz = 0;
2233 ccdc->syncif.fldmode = 0;
2234 ccdc->syncif.fldout = 0;
2235 ccdc->syncif.fldpol = 0;
2236 ccdc->syncif.fldstat = 0;
2237 ccdc->syncif.hdpol = 0;
2238 ccdc->syncif.vdpol = 0;
2239
2240 ccdc->clamp.oblen = 0;
2241 ccdc->clamp.dcsubval = 0;
2242
2243 ccdc->vpcfg.pixelclk = 0;
2244
2245 ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
2246 ccdc_apply_controls(ccdc);
2247
2248 return ccdc_init_entities(ccdc);
2249}
2250
2251/*
2252 * omap3isp_ccdc_cleanup - CCDC module cleanup.
2253 * @dev: Device pointer specific to the OMAP3 ISP.
2254 */
2255void omap3isp_ccdc_cleanup(struct isp_device *isp)
2256{
2257 struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
2258
2259 /* Free LSC requests. As the CCDC is stopped there's no active request,
2260 * so only the pending request and the free queue need to be handled.
2261 */
2262 ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
2263 cancel_work_sync(&ccdc->lsc.table_work);
2264 ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
2265
2266 if (ccdc->fpc.fpcaddr != 0)
2267 iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr);
2268}
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
new file mode 100644
index 000000000000..d403af5d31d2
--- /dev/null
+++ b/drivers/media/video/omap3isp/ispccdc.h
@@ -0,0 +1,219 @@
1/*
2 * ispccdc.h
3 *
4 * TI OMAP3 ISP - CCDC module
5 *
6 * Copyright (C) 2009-2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
27#ifndef OMAP3_ISP_CCDC_H
28#define OMAP3_ISP_CCDC_H
29
30#include <linux/omap3isp.h>
31#include <linux/workqueue.h>
32
33#include "ispvideo.h"
34
35enum ccdc_input_entity {
36 CCDC_INPUT_NONE,
37 CCDC_INPUT_PARALLEL,
38 CCDC_INPUT_CSI2A,
39 CCDC_INPUT_CCP2B,
40 CCDC_INPUT_CSI2C
41};
42
43#define CCDC_OUTPUT_MEMORY (1 << 0)
44#define CCDC_OUTPUT_PREVIEW (1 << 1)
45#define CCDC_OUTPUT_RESIZER (1 << 2)
46
47#define OMAP3ISP_CCDC_NEVENTS 16
48
49/*
50 * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC
51 * @ccdc_mastermode: Master mode. 1 - Master, 0 - Slave.
52 * @fldstat: Field state. 0 - Odd Field, 1 - Even Field.
53 * @datsz: Data size.
54 * @fldmode: 0 - Progressive, 1 - Interlaced.
55 * @datapol: 0 - Positive, 1 - Negative.
56 * @fldpol: 0 - Positive, 1 - Negative.
57 * @hdpol: 0 - Positive, 1 - Negative.
58 * @vdpol: 0 - Positive, 1 - Negative.
59 * @fldout: 0 - Input, 1 - Output.
60 * @hs_width: Width of the Horizontal Sync pulse, used for HS/VS Output.
61 * @vs_width: Width of the Vertical Sync pulse, used for HS/VS Output.
62 * @ppln: Number of pixels per line, used for HS/VS Output.
63 * @hlprf: Number of half lines per frame, used for HS/VS Output.
64 * @bt_r656_en: 1 - Enable ITU-R BT656 mode, 0 - Sync mode.
65 */
66struct ispccdc_syncif {
67 u8 ccdc_mastermode;
68 u8 fldstat;
69 u8 datsz;
70 u8 fldmode;
71 u8 datapol;
72 u8 fldpol;
73 u8 hdpol;
74 u8 vdpol;
75 u8 fldout;
76 u8 hs_width;
77 u8 vs_width;
78 u8 ppln;
79 u8 hlprf;
80 u8 bt_r656_en;
81};
82
83/*
84 * struct ispccdc_vp - Structure for Video Port parameters
85 * @pixelclk: Input pixel clock in Hz
86 */
87struct ispccdc_vp {
88 unsigned int pixelclk;
89};
90
91enum ispccdc_lsc_state {
92 LSC_STATE_STOPPED = 0,
93 LSC_STATE_STOPPING = 1,
94 LSC_STATE_RUNNING = 2,
95 LSC_STATE_RECONFIG = 3,
96};
97
98struct ispccdc_lsc_config_req {
99 struct list_head list;
100 struct omap3isp_ccdc_lsc_config config;
101 unsigned char enable;
102 u32 table;
103 struct iovm_struct *iovm;
104};
105
106/*
107 * ispccdc_lsc - CCDC LSC parameters
108 * @update_config: Set when user changes config
109 * @request_enable: Whether LSC is requested to be enabled
110 * @config: LSC config set by user
111 * @update_table: Set when user provides a new LSC table to table_new
112 * @table_new: LSC table set by user, ISP address
113 * @table_inuse: LSC table currently in use, ISP address
114 */
115struct ispccdc_lsc {
116 enum ispccdc_lsc_state state;
117 struct work_struct table_work;
118
119 /* LSC queue of configurations */
120 spinlock_t req_lock;
121 struct ispccdc_lsc_config_req *request; /* requested configuration */
122 struct ispccdc_lsc_config_req *active; /* active configuration */
123 struct list_head free_queue; /* configurations for freeing */
124};
125
126#define CCDC_STOP_NOT_REQUESTED 0x00
127#define CCDC_STOP_REQUEST 0x01
128#define CCDC_STOP_EXECUTED (0x02 | CCDC_STOP_REQUEST)
129#define CCDC_STOP_CCDC_FINISHED 0x04
130#define CCDC_STOP_LSC_FINISHED 0x08
131#define CCDC_STOP_FINISHED \
132 (CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED)
133
134#define CCDC_EVENT_VD1 0x10
135#define CCDC_EVENT_VD0 0x20
136#define CCDC_EVENT_LSC_DONE 0x40
137
138/* Sink and source CCDC pads */
139#define CCDC_PAD_SINK 0
140#define CCDC_PAD_SOURCE_OF 1
141#define CCDC_PAD_SOURCE_VP 2
142#define CCDC_PADS_NUM 3
143
144/*
145 * struct isp_ccdc_device - Structure for the CCDC module to store its own
146 * information
147 * @subdev: V4L2 subdevice
148 * @pads: Sink and source media entity pads
149 * @formats: Active video formats
150 * @input: Active input
151 * @output: Active outputs
152 * @video_out: Output video node
153 * @error: A hardware error occured during capture
154 * @alaw: A-law compression enabled (1) or disabled (0)
155 * @lpf: Low pass filter enabled (1) or disabled (0)
156 * @obclamp: Optical-black clamp enabled (1) or disabled (0)
157 * @fpc_en: Faulty pixels correction enabled (1) or disabled (0)
158 * @blcomp: Black level compensation configuration
159 * @clamp: Optical-black or digital clamp configuration
160 * @fpc: Faulty pixels correction configuration
161 * @lsc: Lens shading compensation configuration
162 * @update: Bitmask of controls to update during the next interrupt
163 * @shadow_update: Controls update in progress by userspace
164 * @syncif: Interface synchronization configuration
165 * @vpcfg: Video port configuration
166 * @underrun: A buffer underrun occured and a new buffer has been queued
167 * @state: Streaming state
168 * @lock: Serializes shadow_update with interrupt handler
169 * @wait: Wait queue used to stop the module
170 * @stopping: Stopping state
171 * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
172 */
173struct isp_ccdc_device {
174 struct v4l2_subdev subdev;
175 struct media_pad pads[CCDC_PADS_NUM];
176 struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
177
178 enum ccdc_input_entity input;
179 unsigned int output;
180 struct isp_video video_out;
181 unsigned int error;
182
183 unsigned int alaw:1,
184 lpf:1,
185 obclamp:1,
186 fpc_en:1;
187 struct omap3isp_ccdc_blcomp blcomp;
188 struct omap3isp_ccdc_bclamp clamp;
189 struct omap3isp_ccdc_fpc fpc;
190 struct ispccdc_lsc lsc;
191 unsigned int update;
192 unsigned int shadow_update;
193
194 struct ispccdc_syncif syncif;
195 struct ispccdc_vp vpcfg;
196
197 unsigned int underrun:1;
198 enum isp_pipeline_stream_state state;
199 spinlock_t lock;
200 wait_queue_head_t wait;
201 unsigned int stopping;
202 struct mutex ioctl_lock;
203};
204
205struct isp_device;
206
207int omap3isp_ccdc_init(struct isp_device *isp);
208void omap3isp_ccdc_cleanup(struct isp_device *isp);
209int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
210 struct v4l2_device *vdev);
211void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc);
212
213int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc);
214int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events);
215void omap3isp_ccdc_restore_context(struct isp_device *isp);
216void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
217 unsigned int *max_rate);
218
219#endif /* OMAP3_ISP_CCDC_H */
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c
new file mode 100644
index 000000000000..baf9374201dc
--- /dev/null
+++ b/drivers/media/video/omap3isp/isppreview.c
@@ -0,0 +1,2113 @@
1/*
2 * isppreview.c
3 *
4 * TI OMAP3 ISP driver - Preview module
5 *
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
27#include <linux/device.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30#include <linux/mutex.h>
31#include <linux/uaccess.h>
32
33#include "isp.h"
34#include "ispreg.h"
35#include "isppreview.h"
36
37/* Default values in Office Flourescent Light for RGBtoRGB Blending */
38static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
39 { /* RGB-RGB Matrix */
40 {0x01E2, 0x0F30, 0x0FEE},
41 {0x0F9B, 0x01AC, 0x0FB9},
42 {0x0FE0, 0x0EC0, 0x0260}
43 }, /* RGB Offset */
44 {0x0000, 0x0000, 0x0000}
45};
46
47/* Default values in Office Flourescent Light for RGB to YUV Conversion*/
48static struct omap3isp_prev_csc flr_prev_csc = {
49 { /* CSC Coef Matrix */
50 {66, 129, 25},
51 {-38, -75, 112},
52 {112, -94 , -18}
53 }, /* CSC Offset */
54 {0x0, 0x0, 0x0}
55};
56
57/* Default values in Office Flourescent Light for CFA Gradient*/
58#define FLR_CFA_GRADTHRS_HORZ 0x28
59#define FLR_CFA_GRADTHRS_VERT 0x28
60
61/* Default values in Office Flourescent Light for Chroma Suppression*/
62#define FLR_CSUP_GAIN 0x0D
63#define FLR_CSUP_THRES 0xEB
64
65/* Default values in Office Flourescent Light for Noise Filter*/
66#define FLR_NF_STRGTH 0x03
67
68/* Default values for White Balance */
69#define FLR_WBAL_DGAIN 0x100
70#define FLR_WBAL_COEF 0x20
71
72/* Default values in Office Flourescent Light for Black Adjustment*/
73#define FLR_BLKADJ_BLUE 0x0
74#define FLR_BLKADJ_GREEN 0x0
75#define FLR_BLKADJ_RED 0x0
76
77#define DEF_DETECT_CORRECT_VAL 0xe
78
79#define PREV_MIN_WIDTH 64
80#define PREV_MIN_HEIGHT 8
81#define PREV_MAX_HEIGHT 16384
82
83/*
84 * Coeficient Tables for the submodules in Preview.
85 * Array is initialised with the values from.the tables text file.
86 */
87
88/*
89 * CFA Filter Coefficient Table
90 *
91 */
92static u32 cfa_coef_table[] = {
93#include "cfa_coef_table.h"
94};
95
96/*
97 * Default Gamma Correction Table - All components
98 */
99static u32 gamma_table[] = {
100#include "gamma_table.h"
101};
102
103/*
104 * Noise Filter Threshold table
105 */
106static u32 noise_filter_table[] = {
107#include "noise_filter_table.h"
108};
109
110/*
111 * Luminance Enhancement Table
112 */
113static u32 luma_enhance_table[] = {
114#include "luma_enhance_table.h"
115};
116
117/*
118 * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
119 * @enable: 1 - Reverse the A-Law done in CCDC.
120 */
121static void
122preview_enable_invalaw(struct isp_prev_device *prev, u8 enable)
123{
124 struct isp_device *isp = to_isp_device(prev);
125
126 if (enable)
127 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
128 ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
129 else
130 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
131 ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
132}
133
134/*
135 * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture.
136 * @prev -
137 * @enable: 1 - Enable, 0 - Disable
138 *
139 * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also
140 * The proccess is applied for each captured frame.
141 */
142static void
143preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable)
144{
145 struct isp_device *isp = to_isp_device(prev);
146
147 if (enable)
148 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
149 ISPPRV_PCR_DRKFCAP);
150 else
151 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
152 ISPPRV_PCR_DRKFCAP);
153}
154
155/*
156 * preview_enable_drkframe - Enable/Disable of the darkframe subtract.
157 * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is
158 * subtracted with the pixels in the current frame.
159 *
160 * The proccess is applied for each captured frame.
161 */
162static void
163preview_enable_drkframe(struct isp_prev_device *prev, u8 enable)
164{
165 struct isp_device *isp = to_isp_device(prev);
166
167 if (enable)
168 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
169 ISPPRV_PCR_DRKFEN);
170 else
171 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
172 ISPPRV_PCR_DRKFEN);
173}
174
175/*
176 * preview_config_drkf_shadcomp - Configures shift value in shading comp.
177 * @scomp_shtval: 3bit value of shift used in shading compensation.
178 */
179static void
180preview_config_drkf_shadcomp(struct isp_prev_device *prev,
181 const void *scomp_shtval)
182{
183 struct isp_device *isp = to_isp_device(prev);
184 const u32 *shtval = scomp_shtval;
185
186 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
187 ISPPRV_PCR_SCOMP_SFT_MASK,
188 *shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT);
189}
190
191/*
192 * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
193 * @enable: 1 - Enables Horizontal Median Filter.
194 */
195static void
196preview_enable_hmed(struct isp_prev_device *prev, u8 enable)
197{
198 struct isp_device *isp = to_isp_device(prev);
199
200 if (enable)
201 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
202 ISPPRV_PCR_HMEDEN);
203 else
204 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
205 ISPPRV_PCR_HMEDEN);
206}
207
208/*
209 * preview_config_hmed - Configures the Horizontal Median Filter.
210 * @prev_hmed: Structure containing the odd and even distance between the
211 * pixels in the image along with the filter threshold.
212 */
213static void
214preview_config_hmed(struct isp_prev_device *prev, const void *prev_hmed)
215{
216 struct isp_device *isp = to_isp_device(prev);
217 const struct omap3isp_prev_hmed *hmed = prev_hmed;
218
219 isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
220 (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
221 (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
222 OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
223}
224
225/*
226 * preview_config_noisefilter - Configures the Noise Filter.
227 * @prev_nf: Structure containing the noisefilter table, strength to be used
228 * for the noise filter and the defect correction enable flag.
229 */
230static void
231preview_config_noisefilter(struct isp_prev_device *prev, const void *prev_nf)
232{
233 struct isp_device *isp = to_isp_device(prev);
234 const struct omap3isp_prev_nf *nf = prev_nf;
235 unsigned int i;
236
237 isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
238 isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
239 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
240 for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
241 isp_reg_writel(isp, nf->table[i],
242 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
243 }
244}
245
246/*
247 * preview_config_dcor - Configures the defect correction
248 * @prev_dcor: Structure containing the defect correct thresholds
249 */
250static void
251preview_config_dcor(struct isp_prev_device *prev, const void *prev_dcor)
252{
253 struct isp_device *isp = to_isp_device(prev);
254 const struct omap3isp_prev_dcor *dcor = prev_dcor;
255
256 isp_reg_writel(isp, dcor->detect_correct[0],
257 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
258 isp_reg_writel(isp, dcor->detect_correct[1],
259 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
260 isp_reg_writel(isp, dcor->detect_correct[2],
261 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
262 isp_reg_writel(isp, dcor->detect_correct[3],
263 OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
264 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
265 ISPPRV_PCR_DCCOUP,
266 dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
267}
268
269/*
270 * preview_config_cfa - Configures the CFA Interpolation parameters.
271 * @prev_cfa: Structure containing the CFA interpolation table, CFA format
272 * in the image, vertical and horizontal gradient threshold.
273 */
274static void
275preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa)
276{
277 struct isp_device *isp = to_isp_device(prev);
278 const struct omap3isp_prev_cfa *cfa = prev_cfa;
279 unsigned int i;
280
281 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
282 ISPPRV_PCR_CFAFMT_MASK,
283 cfa->format << ISPPRV_PCR_CFAFMT_SHIFT);
284
285 isp_reg_writel(isp,
286 (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
287 (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
288 OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
289
290 isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
291 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
292
293 for (i = 0; i < OMAP3ISP_PREV_CFA_TBL_SIZE; i++) {
294 isp_reg_writel(isp, cfa->table[i],
295 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
296 }
297}
298
299/*
300 * preview_config_gammacorrn - Configures the Gamma Correction table values
301 * @gtable: Structure containing the table for red, blue, green gamma table.
302 */
303static void
304preview_config_gammacorrn(struct isp_prev_device *prev, const void *gtable)
305{
306 struct isp_device *isp = to_isp_device(prev);
307 const struct omap3isp_prev_gtables *gt = gtable;
308 unsigned int i;
309
310 isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
311 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
312 for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
313 isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
314 ISPPRV_SET_TBL_DATA);
315
316 isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
317 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
318 for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
319 isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
320 ISPPRV_SET_TBL_DATA);
321
322 isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
323 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
324 for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
325 isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
326 ISPPRV_SET_TBL_DATA);
327}
328
329/*
330 * preview_config_luma_enhancement - Sets the Luminance Enhancement table.
331 * @ytable: Structure containing the table for Luminance Enhancement table.
332 */
333static void
334preview_config_luma_enhancement(struct isp_prev_device *prev,
335 const void *ytable)
336{
337 struct isp_device *isp = to_isp_device(prev);
338 const struct omap3isp_prev_luma *yt = ytable;
339 unsigned int i;
340
341 isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
342 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
343 for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
344 isp_reg_writel(isp, yt->table[i],
345 OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
346 }
347}
348
349/*
350 * preview_config_chroma_suppression - Configures the Chroma Suppression.
351 * @csup: Structure containing the threshold value for suppression
352 * and the hypass filter enable flag.
353 */
354static void
355preview_config_chroma_suppression(struct isp_prev_device *prev,
356 const void *csup)
357{
358 struct isp_device *isp = to_isp_device(prev);
359 const struct omap3isp_prev_csup *cs = csup;
360
361 isp_reg_writel(isp,
362 cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
363 (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
364 OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
365}
366
367/*
368 * preview_enable_noisefilter - Enables/Disables the Noise Filter.
369 * @enable: 1 - Enables the Noise Filter.
370 */
371static void
372preview_enable_noisefilter(struct isp_prev_device *prev, u8 enable)
373{
374 struct isp_device *isp = to_isp_device(prev);
375
376 if (enable)
377 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
378 ISPPRV_PCR_NFEN);
379 else
380 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
381 ISPPRV_PCR_NFEN);
382}
383
384/*
385 * preview_enable_dcor - Enables/Disables the defect correction.
386 * @enable: 1 - Enables the defect correction.
387 */
388static void
389preview_enable_dcor(struct isp_prev_device *prev, u8 enable)
390{
391 struct isp_device *isp = to_isp_device(prev);
392
393 if (enable)
394 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
395 ISPPRV_PCR_DCOREN);
396 else
397 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
398 ISPPRV_PCR_DCOREN);
399}
400
401/*
402 * preview_enable_cfa - Enable/Disable the CFA Interpolation.
403 * @enable: 1 - Enables the CFA.
404 */
405static void
406preview_enable_cfa(struct isp_prev_device *prev, u8 enable)
407{
408 struct isp_device *isp = to_isp_device(prev);
409
410 if (enable)
411 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
412 ISPPRV_PCR_CFAEN);
413 else
414 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
415 ISPPRV_PCR_CFAEN);
416}
417
418/*
419 * preview_enable_gammabypass - Enables/Disables the GammaByPass
420 * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
421 * 0 - Goes through Gamma Correction. input and output is 10bit.
422 */
423static void
424preview_enable_gammabypass(struct isp_prev_device *prev, u8 enable)
425{
426 struct isp_device *isp = to_isp_device(prev);
427
428 if (enable)
429 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
430 ISPPRV_PCR_GAMMA_BYPASS);
431 else
432 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
433 ISPPRV_PCR_GAMMA_BYPASS);
434}
435
436/*
437 * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
438 * @enable: 1 - Enable the Luminance Enhancement.
439 */
440static void
441preview_enable_luma_enhancement(struct isp_prev_device *prev, u8 enable)
442{
443 struct isp_device *isp = to_isp_device(prev);
444
445 if (enable)
446 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
447 ISPPRV_PCR_YNENHEN);
448 else
449 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
450 ISPPRV_PCR_YNENHEN);
451}
452
453/*
454 * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
455 * @enable: 1 - Enable the Chrominance Suppression.
456 */
457static void
458preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable)
459{
460 struct isp_device *isp = to_isp_device(prev);
461
462 if (enable)
463 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
464 ISPPRV_PCR_SUPEN);
465 else
466 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
467 ISPPRV_PCR_SUPEN);
468}
469
470/*
471 * preview_config_whitebalance - Configures the White Balance parameters.
472 * @prev_wbal: Structure containing the digital gain and white balance
473 * coefficient.
474 *
475 * Coefficient matrix always with default values.
476 */
477static void
478preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal)
479{
480 struct isp_device *isp = to_isp_device(prev);
481 const struct omap3isp_prev_wbal *wbal = prev_wbal;
482 u32 val;
483
484 isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
485
486 val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
487 val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
488 val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
489 val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
490 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
491
492 isp_reg_writel(isp,
493 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
494 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
495 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
496 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
497 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
498 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
499 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
500 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
501 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
502 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
503 ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
504 ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
505 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
506 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
507 ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
508 ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
509 OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
510}
511
512/*
513 * preview_config_blkadj - Configures the Black Adjustment parameters.
514 * @prev_blkadj: Structure containing the black adjustment towards red, green,
515 * blue.
516 */
517static void
518preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj)
519{
520 struct isp_device *isp = to_isp_device(prev);
521 const struct omap3isp_prev_blkadj *blkadj = prev_blkadj;
522
523 isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
524 (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
525 (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
526 OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
527}
528
529/*
530 * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix.
531 * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
532 * offset.
533 */
534static void
535preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb)
536{
537 struct isp_device *isp = to_isp_device(prev);
538 const struct omap3isp_prev_rgbtorgb *rgbrgb = rgb2rgb;
539 u32 val;
540
541 val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
542 val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
543 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
544
545 val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
546 val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
547 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
548
549 val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
550 val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
551 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
552
553 val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
554 val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
555 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
556
557 val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
558 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
559
560 val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
561 val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
562 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
563
564 val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
565 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
566}
567
568/*
569 * Configures the RGB-YCbYCr conversion matrix
570 * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
571 * YCbCr offset.
572 */
573static void
574preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc)
575{
576 struct isp_device *isp = to_isp_device(prev);
577 const struct omap3isp_prev_csc *csc = prev_csc;
578 u32 val;
579
580 val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
581 val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
582 val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
583 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
584
585 val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
586 val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
587 val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
588 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
589
590 val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
591 val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
592 val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
593 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
594
595 val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
596 val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
597 val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
598 isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
599}
600
601/*
602 * preview_update_contrast - Updates the contrast.
603 * @contrast: Pointer to hold the current programmed contrast value.
604 *
605 * Value should be programmed before enabling the module.
606 */
607static void
608preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
609{
610 struct prev_params *params = &prev->params;
611
612 if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
613 params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
614 prev->update |= PREV_CONTRAST;
615 }
616}
617
618/*
619 * preview_config_contrast - Configures the Contrast.
620 * @params: Contrast value (u8 pointer, U8Q0 format).
621 *
622 * Value should be programmed before enabling the module.
623 */
624static void
625preview_config_contrast(struct isp_prev_device *prev, const void *params)
626{
627 struct isp_device *isp = to_isp_device(prev);
628
629 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
630 0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
631 *(u8 *)params << ISPPRV_CNT_BRT_CNT_SHIFT);
632}
633
634/*
635 * preview_update_brightness - Updates the brightness in preview module.
636 * @brightness: Pointer to hold the current programmed brightness value.
637 *
638 */
639static void
640preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
641{
642 struct prev_params *params = &prev->params;
643
644 if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
645 params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
646 prev->update |= PREV_BRIGHTNESS;
647 }
648}
649
650/*
651 * preview_config_brightness - Configures the brightness.
652 * @params: Brightness value (u8 pointer, U8Q0 format).
653 */
654static void
655preview_config_brightness(struct isp_prev_device *prev, const void *params)
656{
657 struct isp_device *isp = to_isp_device(prev);
658
659 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
660 0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
661 *(u8 *)params << ISPPRV_CNT_BRT_BRT_SHIFT);
662}
663
664/*
665 * preview_config_yc_range - Configures the max and min Y and C values.
666 * @yclimit: Structure containing the range of Y and C values.
667 */
668static void
669preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit)
670{
671 struct isp_device *isp = to_isp_device(prev);
672 const struct omap3isp_prev_yclimit *yc = yclimit;
673
674 isp_reg_writel(isp,
675 yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
676 yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
677 yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
678 yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
679 OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
680}
681
682/* preview parameters update structure */
683struct preview_update {
684 int cfg_bit;
685 int feature_bit;
686 void (*config)(struct isp_prev_device *, const void *);
687 void (*enable)(struct isp_prev_device *, u8);
688};
689
690static struct preview_update update_attrs[] = {
691 {OMAP3ISP_PREV_LUMAENH, PREV_LUMA_ENHANCE,
692 preview_config_luma_enhancement,
693 preview_enable_luma_enhancement},
694 {OMAP3ISP_PREV_INVALAW, PREV_INVERSE_ALAW,
695 NULL,
696 preview_enable_invalaw},
697 {OMAP3ISP_PREV_HRZ_MED, PREV_HORZ_MEDIAN_FILTER,
698 preview_config_hmed,
699 preview_enable_hmed},
700 {OMAP3ISP_PREV_CFA, PREV_CFA,
701 preview_config_cfa,
702 preview_enable_cfa},
703 {OMAP3ISP_PREV_CHROMA_SUPP, PREV_CHROMA_SUPPRESS,
704 preview_config_chroma_suppression,
705 preview_enable_chroma_suppression},
706 {OMAP3ISP_PREV_WB, PREV_WB,
707 preview_config_whitebalance,
708 NULL},
709 {OMAP3ISP_PREV_BLKADJ, PREV_BLKADJ,
710 preview_config_blkadj,
711 NULL},
712 {OMAP3ISP_PREV_RGB2RGB, PREV_RGB2RGB,
713 preview_config_rgb_blending,
714 NULL},
715 {OMAP3ISP_PREV_COLOR_CONV, PREV_COLOR_CONV,
716 preview_config_rgb_to_ycbcr,
717 NULL},
718 {OMAP3ISP_PREV_YC_LIMIT, PREV_YCLIMITS,
719 preview_config_yc_range,
720 NULL},
721 {OMAP3ISP_PREV_DEFECT_COR, PREV_DEFECT_COR,
722 preview_config_dcor,
723 preview_enable_dcor},
724 {OMAP3ISP_PREV_GAMMABYPASS, PREV_GAMMA_BYPASS,
725 NULL,
726 preview_enable_gammabypass},
727 {OMAP3ISP_PREV_DRK_FRM_CAPTURE, PREV_DARK_FRAME_CAPTURE,
728 NULL,
729 preview_enable_drkframe_capture},
730 {OMAP3ISP_PREV_DRK_FRM_SUBTRACT, PREV_DARK_FRAME_SUBTRACT,
731 NULL,
732 preview_enable_drkframe},
733 {OMAP3ISP_PREV_LENS_SHADING, PREV_LENS_SHADING,
734 preview_config_drkf_shadcomp,
735 preview_enable_drkframe},
736 {OMAP3ISP_PREV_NF, PREV_NOISE_FILTER,
737 preview_config_noisefilter,
738 preview_enable_noisefilter},
739 {OMAP3ISP_PREV_GAMMA, PREV_GAMMA,
740 preview_config_gammacorrn,
741 NULL},
742 {-1, PREV_CONTRAST,
743 preview_config_contrast,
744 NULL},
745 {-1, PREV_BRIGHTNESS,
746 preview_config_brightness,
747 NULL},
748};
749
750/*
751 * __preview_get_ptrs - helper function which return pointers to members
752 * of params and config structures.
753 * @params - pointer to preview_params structure.
754 * @param - return pointer to appropriate structure field.
755 * @configs - pointer to update config structure.
756 * @config - return pointer to appropriate structure field.
757 * @bit - for which feature to return pointers.
758 * Return size of coresponding prev_params member
759 */
760static u32
761__preview_get_ptrs(struct prev_params *params, void **param,
762 struct omap3isp_prev_update_config *configs,
763 void __user **config, u32 bit)
764{
765#define CHKARG(cfgs, cfg, field) \
766 if (cfgs && cfg) { \
767 *(cfg) = (cfgs)->field; \
768 }
769
770 switch (bit) {
771 case PREV_HORZ_MEDIAN_FILTER:
772 *param = &params->hmed;
773 CHKARG(configs, config, hmed)
774 return sizeof(params->hmed);
775 case PREV_NOISE_FILTER:
776 *param = &params->nf;
777 CHKARG(configs, config, nf)
778 return sizeof(params->nf);
779 break;
780 case PREV_CFA:
781 *param = &params->cfa;
782 CHKARG(configs, config, cfa)
783 return sizeof(params->cfa);
784 case PREV_LUMA_ENHANCE:
785 *param = &params->luma;
786 CHKARG(configs, config, luma)
787 return sizeof(params->luma);
788 case PREV_CHROMA_SUPPRESS:
789 *param = &params->csup;
790 CHKARG(configs, config, csup)
791 return sizeof(params->csup);
792 case PREV_DEFECT_COR:
793 *param = &params->dcor;
794 CHKARG(configs, config, dcor)
795 return sizeof(params->dcor);
796 case PREV_BLKADJ:
797 *param = &params->blk_adj;
798 CHKARG(configs, config, blkadj)
799 return sizeof(params->blk_adj);
800 case PREV_YCLIMITS:
801 *param = &params->yclimit;
802 CHKARG(configs, config, yclimit)
803 return sizeof(params->yclimit);
804 case PREV_RGB2RGB:
805 *param = &params->rgb2rgb;
806 CHKARG(configs, config, rgb2rgb)
807 return sizeof(params->rgb2rgb);
808 case PREV_COLOR_CONV:
809 *param = &params->rgb2ycbcr;
810 CHKARG(configs, config, csc)
811 return sizeof(params->rgb2ycbcr);
812 case PREV_WB:
813 *param = &params->wbal;
814 CHKARG(configs, config, wbal)
815 return sizeof(params->wbal);
816 case PREV_GAMMA:
817 *param = &params->gamma;
818 CHKARG(configs, config, gamma)
819 return sizeof(params->gamma);
820 case PREV_CONTRAST:
821 *param = &params->contrast;
822 return 0;
823 case PREV_BRIGHTNESS:
824 *param = &params->brightness;
825 return 0;
826 default:
827 *param = NULL;
828 *config = NULL;
829 break;
830 }
831 return 0;
832}
833
834/*
835 * preview_config - Copy and update local structure with userspace preview
836 * configuration.
837 * @prev: ISP preview engine
838 * @cfg: Configuration
839 *
840 * Return zero if success or -EFAULT if the configuration can't be copied from
841 * userspace.
842 */
843static int preview_config(struct isp_prev_device *prev,
844 struct omap3isp_prev_update_config *cfg)
845{
846 struct prev_params *params;
847 struct preview_update *attr;
848 int i, bit, rval = 0;
849
850 params = &prev->params;
851
852 if (prev->state != ISP_PIPELINE_STREAM_STOPPED) {
853 unsigned long flags;
854
855 spin_lock_irqsave(&prev->lock, flags);
856 prev->shadow_update = 1;
857 spin_unlock_irqrestore(&prev->lock, flags);
858 }
859
860 for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
861 attr = &update_attrs[i];
862 bit = 0;
863
864 if (!(cfg->update & attr->cfg_bit))
865 continue;
866
867 bit = cfg->flag & attr->cfg_bit;
868 if (bit) {
869 void *to = NULL, __user *from = NULL;
870 unsigned long sz = 0;
871
872 sz = __preview_get_ptrs(params, &to, cfg, &from,
873 bit);
874 if (to && from && sz) {
875 if (copy_from_user(to, from, sz)) {
876 rval = -EFAULT;
877 break;
878 }
879 }
880 params->features |= attr->feature_bit;
881 } else {
882 params->features &= ~attr->feature_bit;
883 }
884
885 prev->update |= attr->feature_bit;
886 }
887
888 prev->shadow_update = 0;
889 return rval;
890}
891
892/*
893 * preview_setup_hw - Setup preview registers and/or internal memory
894 * @prev: pointer to preview private structure
895 * Note: can be called from interrupt context
896 * Return none
897 */
898static void preview_setup_hw(struct isp_prev_device *prev)
899{
900 struct prev_params *params = &prev->params;
901 struct preview_update *attr;
902 int i, bit;
903 void *param_ptr;
904
905 for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
906 attr = &update_attrs[i];
907
908 if (!(prev->update & attr->feature_bit))
909 continue;
910 bit = params->features & attr->feature_bit;
911 if (bit) {
912 if (attr->config) {
913 __preview_get_ptrs(params, &param_ptr, NULL,
914 NULL, bit);
915 attr->config(prev, param_ptr);
916 }
917 if (attr->enable)
918 attr->enable(prev, 1);
919 } else
920 if (attr->enable)
921 attr->enable(prev, 0);
922
923 prev->update &= ~attr->feature_bit;
924 }
925}
926
927/*
928 * preview_config_ycpos - Configure byte layout of YUV image.
929 * @mode: Indicates the required byte layout.
930 */
931static void
932preview_config_ycpos(struct isp_prev_device *prev,
933 enum v4l2_mbus_pixelcode pixelcode)
934{
935 struct isp_device *isp = to_isp_device(prev);
936 enum preview_ycpos_mode mode;
937
938 switch (pixelcode) {
939 case V4L2_MBUS_FMT_YUYV8_1X16:
940 mode = YCPOS_CrYCbY;
941 break;
942 case V4L2_MBUS_FMT_UYVY8_1X16:
943 mode = YCPOS_YCrYCb;
944 break;
945 default:
946 return;
947 }
948
949 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
950 ISPPRV_PCR_YCPOS_CrYCbY,
951 mode << ISPPRV_PCR_YCPOS_SHIFT);
952}
953
954/*
955 * preview_config_averager - Enable / disable / configure averager
956 * @average: Average value to be configured.
957 */
958static void preview_config_averager(struct isp_prev_device *prev, u8 average)
959{
960 struct isp_device *isp = to_isp_device(prev);
961 int reg = 0;
962
963 if (prev->params.cfa.format == OMAP3ISP_CFAFMT_BAYER)
964 reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
965 ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
966 average;
967 else if (prev->params.cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
968 reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT |
969 ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT |
970 average;
971 isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
972}
973
974/*
975 * preview_config_input_size - Configure the input frame size
976 *
977 * The preview engine crops several rows and columns internally depending on
978 * which processing blocks are enabled. The driver assumes all those blocks are
979 * enabled when reporting source pad formats to userspace. If this assumption is
980 * not true, rows and columns must be manually cropped at the preview engine
981 * input to avoid overflows at the end of lines and frames.
982 */
983static void preview_config_input_size(struct isp_prev_device *prev)
984{
985 struct isp_device *isp = to_isp_device(prev);
986 struct prev_params *params = &prev->params;
987 struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
988 unsigned int sph = 0;
989 unsigned int eph = format->width - 1;
990 unsigned int slv = 0;
991 unsigned int elv = format->height - 1;
992
993 if (prev->input == PREVIEW_INPUT_CCDC) {
994 sph += 2;
995 eph -= 2;
996 }
997
998 /*
999 * Median filter 4 pixels
1000 * Noise filter 4 pixels, 4 lines
1001 * or faulty pixels correction
1002 * CFA filter 4 pixels, 4 lines in Bayer mode
1003 * 2 lines in other modes
1004 * Color suppression 2 pixels
1005 * or luma enhancement
1006 * -------------------------------------------------------------
1007 * Maximum total 14 pixels, 8 lines
1008 */
1009
1010 if (!(params->features & PREV_CFA)) {
1011 sph += 2;
1012 eph -= 2;
1013 slv += 2;
1014 elv -= 2;
1015 }
1016 if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) {
1017 sph += 2;
1018 eph -= 2;
1019 slv += 2;
1020 elv -= 2;
1021 }
1022 if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) {
1023 sph += 2;
1024 eph -= 2;
1025 }
1026 if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)))
1027 sph += 2;
1028
1029 isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
1030 OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
1031 isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
1032 OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
1033}
1034
1035/*
1036 * preview_config_inlineoffset - Configures the Read address line offset.
1037 * @prev: Preview module
1038 * @offset: Line offset
1039 *
1040 * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
1041 * However, a hardware bug requires the memory start address to be aligned on a
1042 * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
1043 * well.
1044 */
1045static void
1046preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
1047{
1048 struct isp_device *isp = to_isp_device(prev);
1049
1050 isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
1051 ISPPRV_RADR_OFFSET);
1052}
1053
1054/*
1055 * preview_set_inaddr - Sets memory address of input frame.
1056 * @addr: 32bit memory address aligned on 32byte boundary.
1057 *
1058 * Configures the memory address from which the input frame is to be read.
1059 */
1060static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
1061{
1062 struct isp_device *isp = to_isp_device(prev);
1063
1064 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
1065}
1066
1067/*
1068 * preview_config_outlineoffset - Configures the Write address line offset.
1069 * @offset: Line Offset for the preview output.
1070 *
1071 * The offset must be a multiple of 32 bytes.
1072 */
1073static void preview_config_outlineoffset(struct isp_prev_device *prev,
1074 u32 offset)
1075{
1076 struct isp_device *isp = to_isp_device(prev);
1077
1078 isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
1079 ISPPRV_WADD_OFFSET);
1080}
1081
1082/*
1083 * preview_set_outaddr - Sets the memory address to store output frame
1084 * @addr: 32bit memory address aligned on 32byte boundary.
1085 *
1086 * Configures the memory address to which the output frame is written.
1087 */
1088static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
1089{
1090 struct isp_device *isp = to_isp_device(prev);
1091
1092 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
1093}
1094
1095static void preview_adjust_bandwidth(struct isp_prev_device *prev)
1096{
1097 struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
1098 struct isp_device *isp = to_isp_device(prev);
1099 const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
1100 unsigned long l3_ick = pipe->l3_ick;
1101 struct v4l2_fract *timeperframe;
1102 unsigned int cycles_per_frame;
1103 unsigned int requests_per_frame;
1104 unsigned int cycles_per_request;
1105 unsigned int minimum;
1106 unsigned int maximum;
1107 unsigned int value;
1108
1109 if (prev->input != PREVIEW_INPUT_MEMORY) {
1110 isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
1111 ISPSBL_SDR_REQ_PRV_EXP_MASK);
1112 return;
1113 }
1114
1115 /* Compute the minimum number of cycles per request, based on the
1116 * pipeline maximum data rate. This is an absolute lower bound if we
1117 * don't want SBL overflows, so round the value up.
1118 */
1119 cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
1120 pipe->max_rate);
1121 minimum = DIV_ROUND_UP(cycles_per_request, 32);
1122
1123 /* Compute the maximum number of cycles per request, based on the
1124 * requested frame rate. This is a soft upper bound to achieve a frame
1125 * rate equal or higher than the requested value, so round the value
1126 * down.
1127 */
1128 timeperframe = &pipe->max_timeperframe;
1129
1130 requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
1131 cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
1132 timeperframe->denominator);
1133 cycles_per_request = cycles_per_frame / requests_per_frame;
1134
1135 maximum = cycles_per_request / 32;
1136
1137 value = max(minimum, maximum);
1138
1139 dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
1140 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
1141 ISPSBL_SDR_REQ_PRV_EXP_MASK,
1142 value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
1143}
1144
1145/*
1146 * omap3isp_preview_busy - Gets busy state of preview module.
1147 */
1148int omap3isp_preview_busy(struct isp_prev_device *prev)
1149{
1150 struct isp_device *isp = to_isp_device(prev);
1151
1152 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
1153 & ISPPRV_PCR_BUSY;
1154}
1155
1156/*
1157 * omap3isp_preview_restore_context - Restores the values of preview registers
1158 */
1159void omap3isp_preview_restore_context(struct isp_device *isp)
1160{
1161 isp->isp_prev.update = PREV_FEATURES_END - 1;
1162 preview_setup_hw(&isp->isp_prev);
1163}
1164
1165/*
1166 * preview_print_status - Dump preview module registers to the kernel log
1167 */
1168#define PREV_PRINT_REGISTER(isp, name)\
1169 dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
1170 isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
1171
1172static void preview_print_status(struct isp_prev_device *prev)
1173{
1174 struct isp_device *isp = to_isp_device(prev);
1175
1176 dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
1177
1178 PREV_PRINT_REGISTER(isp, PCR);
1179 PREV_PRINT_REGISTER(isp, HORZ_INFO);
1180 PREV_PRINT_REGISTER(isp, VERT_INFO);
1181 PREV_PRINT_REGISTER(isp, RSDR_ADDR);
1182 PREV_PRINT_REGISTER(isp, RADR_OFFSET);
1183 PREV_PRINT_REGISTER(isp, DSDR_ADDR);
1184 PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
1185 PREV_PRINT_REGISTER(isp, WSDR_ADDR);
1186 PREV_PRINT_REGISTER(isp, WADD_OFFSET);
1187 PREV_PRINT_REGISTER(isp, AVE);
1188 PREV_PRINT_REGISTER(isp, HMED);
1189 PREV_PRINT_REGISTER(isp, NF);
1190 PREV_PRINT_REGISTER(isp, WB_DGAIN);
1191 PREV_PRINT_REGISTER(isp, WBGAIN);
1192 PREV_PRINT_REGISTER(isp, WBSEL);
1193 PREV_PRINT_REGISTER(isp, CFA);
1194 PREV_PRINT_REGISTER(isp, BLKADJOFF);
1195 PREV_PRINT_REGISTER(isp, RGB_MAT1);
1196 PREV_PRINT_REGISTER(isp, RGB_MAT2);
1197 PREV_PRINT_REGISTER(isp, RGB_MAT3);
1198 PREV_PRINT_REGISTER(isp, RGB_MAT4);
1199 PREV_PRINT_REGISTER(isp, RGB_MAT5);
1200 PREV_PRINT_REGISTER(isp, RGB_OFF1);
1201 PREV_PRINT_REGISTER(isp, RGB_OFF2);
1202 PREV_PRINT_REGISTER(isp, CSC0);
1203 PREV_PRINT_REGISTER(isp, CSC1);
1204 PREV_PRINT_REGISTER(isp, CSC2);
1205 PREV_PRINT_REGISTER(isp, CSC_OFFSET);
1206 PREV_PRINT_REGISTER(isp, CNT_BRT);
1207 PREV_PRINT_REGISTER(isp, CSUP);
1208 PREV_PRINT_REGISTER(isp, SETUP_YC);
1209 PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
1210 PREV_PRINT_REGISTER(isp, CDC_THR0);
1211 PREV_PRINT_REGISTER(isp, CDC_THR1);
1212 PREV_PRINT_REGISTER(isp, CDC_THR2);
1213 PREV_PRINT_REGISTER(isp, CDC_THR3);
1214
1215 dev_dbg(isp->dev, "--------------------------------------------\n");
1216}
1217
1218/*
1219 * preview_init_params - init image processing parameters.
1220 * @prev: pointer to previewer private structure
1221 * return none
1222 */
1223static void preview_init_params(struct isp_prev_device *prev)
1224{
1225 struct prev_params *params = &prev->params;
1226 int i = 0;
1227
1228 /* Init values */
1229 params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
1230 params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
1231 params->average = NO_AVE;
1232 params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
1233 memcpy(params->cfa.table, cfa_coef_table,
1234 sizeof(params->cfa.table));
1235 params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
1236 params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
1237 params->csup.gain = FLR_CSUP_GAIN;
1238 params->csup.thres = FLR_CSUP_THRES;
1239 params->csup.hypf_en = 0;
1240 memcpy(params->luma.table, luma_enhance_table,
1241 sizeof(params->luma.table));
1242 params->nf.spread = FLR_NF_STRGTH;
1243 memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
1244 params->dcor.couplet_mode_en = 1;
1245 for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
1246 params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
1247 memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
1248 memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
1249 memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
1250 params->wbal.dgain = FLR_WBAL_DGAIN;
1251 params->wbal.coef0 = FLR_WBAL_COEF;
1252 params->wbal.coef1 = FLR_WBAL_COEF;
1253 params->wbal.coef2 = FLR_WBAL_COEF;
1254 params->wbal.coef3 = FLR_WBAL_COEF;
1255 params->blk_adj.red = FLR_BLKADJ_RED;
1256 params->blk_adj.green = FLR_BLKADJ_GREEN;
1257 params->blk_adj.blue = FLR_BLKADJ_BLUE;
1258 params->rgb2rgb = flr_rgb2rgb;
1259 params->rgb2ycbcr = flr_prev_csc;
1260 params->yclimit.minC = ISPPRV_YC_MIN;
1261 params->yclimit.maxC = ISPPRV_YC_MAX;
1262 params->yclimit.minY = ISPPRV_YC_MIN;
1263 params->yclimit.maxY = ISPPRV_YC_MAX;
1264
1265 params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER
1266 | PREV_GAMMA | PREV_BLKADJ | PREV_YCLIMITS
1267 | PREV_RGB2RGB | PREV_COLOR_CONV | PREV_WB
1268 | PREV_BRIGHTNESS | PREV_CONTRAST;
1269
1270 prev->update = PREV_FEATURES_END - 1;
1271}
1272
1273/*
1274 * preview_max_out_width - Handle previewer hardware ouput limitations
1275 * @isp_revision : ISP revision
1276 * returns maximum width output for current isp revision
1277 */
1278static unsigned int preview_max_out_width(struct isp_prev_device *prev)
1279{
1280 struct isp_device *isp = to_isp_device(prev);
1281
1282 switch (isp->revision) {
1283 case ISP_REVISION_1_0:
1284 return ISPPRV_MAXOUTPUT_WIDTH;
1285
1286 case ISP_REVISION_2_0:
1287 default:
1288 return ISPPRV_MAXOUTPUT_WIDTH_ES2;
1289
1290 case ISP_REVISION_15_0:
1291 return ISPPRV_MAXOUTPUT_WIDTH_3630;
1292 }
1293}
1294
1295static void preview_configure(struct isp_prev_device *prev)
1296{
1297 struct isp_device *isp = to_isp_device(prev);
1298 struct v4l2_mbus_framefmt *format;
1299 unsigned int max_out_width;
1300 unsigned int format_avg;
1301
1302 preview_setup_hw(prev);
1303
1304 if (prev->output & PREVIEW_OUTPUT_MEMORY)
1305 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1306 ISPPRV_PCR_SDRPORT);
1307 else
1308 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1309 ISPPRV_PCR_SDRPORT);
1310
1311 if (prev->output & PREVIEW_OUTPUT_RESIZER)
1312 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1313 ISPPRV_PCR_RSZPORT);
1314 else
1315 isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1316 ISPPRV_PCR_RSZPORT);
1317
1318 /* PREV_PAD_SINK */
1319 format = &prev->formats[PREV_PAD_SINK];
1320
1321 preview_adjust_bandwidth(prev);
1322
1323 preview_config_input_size(prev);
1324
1325 if (prev->input == PREVIEW_INPUT_CCDC)
1326 preview_config_inlineoffset(prev, 0);
1327 else
1328 preview_config_inlineoffset(prev,
1329 ALIGN(format->width, 0x20) * 2);
1330
1331 /* PREV_PAD_SOURCE */
1332 format = &prev->formats[PREV_PAD_SOURCE];
1333
1334 if (prev->output & PREVIEW_OUTPUT_MEMORY)
1335 preview_config_outlineoffset(prev,
1336 ALIGN(format->width, 0x10) * 2);
1337
1338 max_out_width = preview_max_out_width(prev);
1339
1340 format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1);
1341 preview_config_averager(prev, format_avg);
1342 preview_config_ycpos(prev, format->code);
1343}
1344
1345/* -----------------------------------------------------------------------------
1346 * Interrupt handling
1347 */
1348
1349static void preview_enable_oneshot(struct isp_prev_device *prev)
1350{
1351 struct isp_device *isp = to_isp_device(prev);
1352
1353 /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
1354 * bit is set. As the preview engine is used in single-shot mode, we
1355 * need to set PCR.SOURCE before enabling the preview engine.
1356 */
1357 if (prev->input == PREVIEW_INPUT_MEMORY)
1358 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1359 ISPPRV_PCR_SOURCE);
1360
1361 isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
1362 ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
1363}
1364
1365void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
1366{
1367 /*
1368 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
1369 * condition, the module was paused and now we have a buffer queued
1370 * on the output again. Restart the pipeline if running in continuous
1371 * mode.
1372 */
1373 if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
1374 prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1375 preview_enable_oneshot(prev);
1376 isp_video_dmaqueue_flags_clr(&prev->video_out);
1377 }
1378}
1379
1380static void preview_isr_buffer(struct isp_prev_device *prev)
1381{
1382 struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
1383 struct isp_buffer *buffer;
1384 int restart = 0;
1385
1386 if (prev->input == PREVIEW_INPUT_MEMORY) {
1387 buffer = omap3isp_video_buffer_next(&prev->video_in,
1388 prev->error);
1389 if (buffer != NULL)
1390 preview_set_inaddr(prev, buffer->isp_addr);
1391 pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1392 }
1393
1394 if (prev->output & PREVIEW_OUTPUT_MEMORY) {
1395 buffer = omap3isp_video_buffer_next(&prev->video_out,
1396 prev->error);
1397 if (buffer != NULL) {
1398 preview_set_outaddr(prev, buffer->isp_addr);
1399 restart = 1;
1400 }
1401 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1402 }
1403
1404 switch (prev->state) {
1405 case ISP_PIPELINE_STREAM_SINGLESHOT:
1406 if (isp_pipeline_ready(pipe))
1407 omap3isp_pipeline_set_stream(pipe,
1408 ISP_PIPELINE_STREAM_SINGLESHOT);
1409 break;
1410
1411 case ISP_PIPELINE_STREAM_CONTINUOUS:
1412 /* If an underrun occurs, the video queue operation handler will
1413 * restart the preview engine. Otherwise restart it immediately.
1414 */
1415 if (restart)
1416 preview_enable_oneshot(prev);
1417 break;
1418
1419 case ISP_PIPELINE_STREAM_STOPPED:
1420 default:
1421 return;
1422 }
1423
1424 prev->error = 0;
1425}
1426
1427/*
1428 * omap3isp_preview_isr - ISP preview engine interrupt handler
1429 *
1430 * Manage the preview engine video buffers and configure shadowed registers.
1431 */
1432void omap3isp_preview_isr(struct isp_prev_device *prev)
1433{
1434 unsigned long flags;
1435
1436 if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
1437 return;
1438
1439 spin_lock_irqsave(&prev->lock, flags);
1440 if (prev->shadow_update)
1441 goto done;
1442
1443 preview_setup_hw(prev);
1444 preview_config_input_size(prev);
1445
1446done:
1447 spin_unlock_irqrestore(&prev->lock, flags);
1448
1449 if (prev->input == PREVIEW_INPUT_MEMORY ||
1450 prev->output & PREVIEW_OUTPUT_MEMORY)
1451 preview_isr_buffer(prev);
1452 else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
1453 preview_enable_oneshot(prev);
1454}
1455
1456/* -----------------------------------------------------------------------------
1457 * ISP video operations
1458 */
1459
1460static int preview_video_queue(struct isp_video *video,
1461 struct isp_buffer *buffer)
1462{
1463 struct isp_prev_device *prev = &video->isp->isp_prev;
1464
1465 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1466 preview_set_inaddr(prev, buffer->isp_addr);
1467
1468 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1469 preview_set_outaddr(prev, buffer->isp_addr);
1470
1471 return 0;
1472}
1473
1474static const struct isp_video_operations preview_video_ops = {
1475 .queue = preview_video_queue,
1476};
1477
1478/* -----------------------------------------------------------------------------
1479 * V4L2 subdev operations
1480 */
1481
1482/*
1483 * preview_s_ctrl - Handle set control subdev method
1484 * @ctrl: pointer to v4l2 control structure
1485 */
1486static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
1487{
1488 struct isp_prev_device *prev =
1489 container_of(ctrl->handler, struct isp_prev_device, ctrls);
1490
1491 switch (ctrl->id) {
1492 case V4L2_CID_BRIGHTNESS:
1493 preview_update_brightness(prev, ctrl->val);
1494 break;
1495 case V4L2_CID_CONTRAST:
1496 preview_update_contrast(prev, ctrl->val);
1497 break;
1498 }
1499
1500 return 0;
1501}
1502
1503static const struct v4l2_ctrl_ops preview_ctrl_ops = {
1504 .s_ctrl = preview_s_ctrl,
1505};
1506
1507/*
1508 * preview_ioctl - Handle preview module private ioctl's
1509 * @prev: pointer to preview context structure
1510 * @cmd: configuration command
1511 * @arg: configuration argument
1512 * return -EINVAL or zero on success
1513 */
1514static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
1515{
1516 struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1517
1518 switch (cmd) {
1519 case VIDIOC_OMAP3ISP_PRV_CFG:
1520 return preview_config(prev, arg);
1521
1522 default:
1523 return -ENOIOCTLCMD;
1524 }
1525}
1526
1527/*
1528 * preview_set_stream - Enable/Disable streaming on preview subdev
1529 * @sd : pointer to v4l2 subdev structure
1530 * @enable: 1 == Enable, 0 == Disable
1531 * return -EINVAL or zero on sucess
1532 */
1533static int preview_set_stream(struct v4l2_subdev *sd, int enable)
1534{
1535 struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1536 struct isp_video *video_out = &prev->video_out;
1537 struct isp_device *isp = to_isp_device(prev);
1538 struct device *dev = to_device(prev);
1539 unsigned long flags;
1540
1541 if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
1542 if (enable == ISP_PIPELINE_STREAM_STOPPED)
1543 return 0;
1544
1545 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
1546 preview_configure(prev);
1547 atomic_set(&prev->stopping, 0);
1548 prev->error = 0;
1549 preview_print_status(prev);
1550 }
1551
1552 switch (enable) {
1553 case ISP_PIPELINE_STREAM_CONTINUOUS:
1554 if (prev->output & PREVIEW_OUTPUT_MEMORY)
1555 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
1556
1557 if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
1558 !(prev->output & PREVIEW_OUTPUT_MEMORY))
1559 preview_enable_oneshot(prev);
1560
1561 isp_video_dmaqueue_flags_clr(video_out);
1562 break;
1563
1564 case ISP_PIPELINE_STREAM_SINGLESHOT:
1565 if (prev->input == PREVIEW_INPUT_MEMORY)
1566 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
1567 if (prev->output & PREVIEW_OUTPUT_MEMORY)
1568 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
1569
1570 preview_enable_oneshot(prev);
1571 break;
1572
1573 case ISP_PIPELINE_STREAM_STOPPED:
1574 if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
1575 &prev->stopping))
1576 dev_dbg(dev, "%s: stop timeout.\n", sd->name);
1577 spin_lock_irqsave(&prev->lock, flags);
1578 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
1579 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
1580 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
1581 spin_unlock_irqrestore(&prev->lock, flags);
1582 isp_video_dmaqueue_flags_clr(video_out);
1583 break;
1584 }
1585
1586 prev->state = enable;
1587 return 0;
1588}
1589
1590static struct v4l2_mbus_framefmt *
1591__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
1592 unsigned int pad, enum v4l2_subdev_format_whence which)
1593{
1594 if (which == V4L2_SUBDEV_FORMAT_TRY)
1595 return v4l2_subdev_get_try_format(fh, pad);
1596 else
1597 return &prev->formats[pad];
1598}
1599
1600/* previewer format descriptions */
1601static const unsigned int preview_input_fmts[] = {
1602 V4L2_MBUS_FMT_SGRBG10_1X10,
1603 V4L2_MBUS_FMT_SRGGB10_1X10,
1604 V4L2_MBUS_FMT_SBGGR10_1X10,
1605 V4L2_MBUS_FMT_SGBRG10_1X10,
1606};
1607
1608static const unsigned int preview_output_fmts[] = {
1609 V4L2_MBUS_FMT_UYVY8_1X16,
1610 V4L2_MBUS_FMT_YUYV8_1X16,
1611};
1612
1613/*
1614 * preview_try_format - Handle try format by pad subdev method
1615 * @prev: ISP preview device
1616 * @fh : V4L2 subdev file handle
1617 * @pad: pad num
1618 * @fmt: pointer to v4l2 format structure
1619 */
1620static void preview_try_format(struct isp_prev_device *prev,
1621 struct v4l2_subdev_fh *fh, unsigned int pad,
1622 struct v4l2_mbus_framefmt *fmt,
1623 enum v4l2_subdev_format_whence which)
1624{
1625 struct v4l2_mbus_framefmt *format;
1626 unsigned int max_out_width;
1627 enum v4l2_mbus_pixelcode pixelcode;
1628 unsigned int i;
1629
1630 max_out_width = preview_max_out_width(prev);
1631
1632 switch (pad) {
1633 case PREV_PAD_SINK:
1634 /* When reading data from the CCDC, the input size has already
1635 * been mangled by the CCDC output pad so it can be accepted
1636 * as-is.
1637 *
1638 * When reading data from memory, clamp the requested width and
1639 * height. The TRM doesn't specify a minimum input height, make
1640 * sure we got enough lines to enable the noise filter and color
1641 * filter array interpolation.
1642 */
1643 if (prev->input == PREVIEW_INPUT_MEMORY) {
1644 fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH,
1645 max_out_width * 8);
1646 fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT,
1647 PREV_MAX_HEIGHT);
1648 }
1649
1650 fmt->colorspace = V4L2_COLORSPACE_SRGB;
1651
1652 for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
1653 if (fmt->code == preview_input_fmts[i])
1654 break;
1655 }
1656
1657 /* If not found, use SGRBG10 as default */
1658 if (i >= ARRAY_SIZE(preview_input_fmts))
1659 fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
1660 break;
1661
1662 case PREV_PAD_SOURCE:
1663 pixelcode = fmt->code;
1664 format = __preview_get_format(prev, fh, PREV_PAD_SINK, which);
1665 memcpy(fmt, format, sizeof(*fmt));
1666
1667 /* The preview module output size is configurable through the
1668 * input interface (horizontal and vertical cropping) and the
1669 * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In
1670 * spite of this, hardcode the output size to the biggest
1671 * possible value for simplicity reasons.
1672 */
1673 switch (pixelcode) {
1674 case V4L2_MBUS_FMT_YUYV8_1X16:
1675 case V4L2_MBUS_FMT_UYVY8_1X16:
1676 fmt->code = pixelcode;
1677 break;
1678
1679 default:
1680 fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1681 break;
1682 }
1683
1684 /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped
1685 * from the left and right sides when the input source is the
1686 * CCDC. This seems not to be needed in practice, investigation
1687 * is required.
1688 */
1689 if (prev->input == PREVIEW_INPUT_CCDC)
1690 fmt->width -= 4;
1691
1692 /* The preview module can output a maximum of 3312 pixels
1693 * horizontally due to fixed memory-line sizes. Compute the
1694 * horizontal averaging factor accordingly. Note that the limit
1695 * applies to the noise filter and CFA interpolation blocks, so
1696 * it doesn't take cropping by further blocks into account.
1697 *
1698 * ES 1.0 hardware revision is limited to 1280 pixels
1699 * horizontally.
1700 */
1701 fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1);
1702
1703 /* Assume that all blocks are enabled and crop pixels and lines
1704 * accordingly. See preview_config_input_size() for more
1705 * information.
1706 */
1707 fmt->width -= 14;
1708 fmt->height -= 8;
1709
1710 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1711 break;
1712 }
1713
1714 fmt->field = V4L2_FIELD_NONE;
1715}
1716
1717/*
1718 * preview_enum_mbus_code - Handle pixel format enumeration
1719 * @sd : pointer to v4l2 subdev structure
1720 * @fh : V4L2 subdev file handle
1721 * @code : pointer to v4l2_subdev_mbus_code_enum structure
1722 * return -EINVAL or zero on success
1723 */
1724static int preview_enum_mbus_code(struct v4l2_subdev *sd,
1725 struct v4l2_subdev_fh *fh,
1726 struct v4l2_subdev_mbus_code_enum *code)
1727{
1728 switch (code->pad) {
1729 case PREV_PAD_SINK:
1730 if (code->index >= ARRAY_SIZE(preview_input_fmts))
1731 return -EINVAL;
1732
1733 code->code = preview_input_fmts[code->index];
1734 break;
1735 case PREV_PAD_SOURCE:
1736 if (code->index >= ARRAY_SIZE(preview_output_fmts))
1737 return -EINVAL;
1738
1739 code->code = preview_output_fmts[code->index];
1740 break;
1741 default:
1742 return -EINVAL;
1743 }
1744
1745 return 0;
1746}
1747
1748static int preview_enum_frame_size(struct v4l2_subdev *sd,
1749 struct v4l2_subdev_fh *fh,
1750 struct v4l2_subdev_frame_size_enum *fse)
1751{
1752 struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1753 struct v4l2_mbus_framefmt format;
1754
1755 if (fse->index != 0)
1756 return -EINVAL;
1757
1758 format.code = fse->code;
1759 format.width = 1;
1760 format.height = 1;
1761 preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1762 fse->min_width = format.width;
1763 fse->min_height = format.height;
1764
1765 if (format.code != fse->code)
1766 return -EINVAL;
1767
1768 format.code = fse->code;
1769 format.width = -1;
1770 format.height = -1;
1771 preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1772 fse->max_width = format.width;
1773 fse->max_height = format.height;
1774
1775 return 0;
1776}
1777
1778/*
1779 * preview_get_format - Handle get format by pads subdev method
1780 * @sd : pointer to v4l2 subdev structure
1781 * @fh : V4L2 subdev file handle
1782 * @fmt: pointer to v4l2 subdev format structure
1783 * return -EINVAL or zero on sucess
1784 */
1785static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1786 struct v4l2_subdev_format *fmt)
1787{
1788 struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1789 struct v4l2_mbus_framefmt *format;
1790
1791 format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
1792 if (format == NULL)
1793 return -EINVAL;
1794
1795 fmt->format = *format;
1796 return 0;
1797}
1798
1799/*
1800 * preview_set_format - Handle set format by pads subdev method
1801 * @sd : pointer to v4l2 subdev structure
1802 * @fh : V4L2 subdev file handle
1803 * @fmt: pointer to v4l2 subdev format structure
1804 * return -EINVAL or zero on success
1805 */
1806static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1807 struct v4l2_subdev_format *fmt)
1808{
1809 struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1810 struct v4l2_mbus_framefmt *format;
1811
1812 format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
1813 if (format == NULL)
1814 return -EINVAL;
1815
1816 preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which);
1817 *format = fmt->format;
1818
1819 /* Propagate the format from sink to source */
1820 if (fmt->pad == PREV_PAD_SINK) {
1821 format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
1822 fmt->which);
1823 *format = fmt->format;
1824 preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
1825 fmt->which);
1826 }
1827
1828 return 0;
1829}
1830
1831/*
1832 * preview_init_formats - Initialize formats on all pads
1833 * @sd: ISP preview V4L2 subdevice
1834 * @fh: V4L2 subdev file handle
1835 *
1836 * Initialize all pad formats with default values. If fh is not NULL, try
1837 * formats are initialized on the file handle. Otherwise active formats are
1838 * initialized on the device.
1839 */
1840static int preview_init_formats(struct v4l2_subdev *sd,
1841 struct v4l2_subdev_fh *fh)
1842{
1843 struct v4l2_subdev_format format;
1844
1845 memset(&format, 0, sizeof(format));
1846 format.pad = PREV_PAD_SINK;
1847 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1848 format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
1849 format.format.width = 4096;
1850 format.format.height = 4096;
1851 preview_set_format(sd, fh, &format);
1852
1853 return 0;
1854}
1855
1856/* subdev core operations */
1857static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
1858 .ioctl = preview_ioctl,
1859};
1860
1861/* subdev video operations */
1862static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
1863 .s_stream = preview_set_stream,
1864};
1865
1866/* subdev pad operations */
1867static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
1868 .enum_mbus_code = preview_enum_mbus_code,
1869 .enum_frame_size = preview_enum_frame_size,
1870 .get_fmt = preview_get_format,
1871 .set_fmt = preview_set_format,
1872};
1873
1874/* subdev operations */
1875static const struct v4l2_subdev_ops preview_v4l2_ops = {
1876 .core = &preview_v4l2_core_ops,
1877 .video = &preview_v4l2_video_ops,
1878 .pad = &preview_v4l2_pad_ops,
1879};
1880
1881/* subdev internal operations */
1882static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
1883 .open = preview_init_formats,
1884};
1885
1886/* -----------------------------------------------------------------------------
1887 * Media entity operations
1888 */
1889
1890/*
1891 * preview_link_setup - Setup previewer connections.
1892 * @entity : Pointer to media entity structure
1893 * @local : Pointer to local pad array
1894 * @remote : Pointer to remote pad array
1895 * @flags : Link flags
1896 * return -EINVAL or zero on success
1897 */
1898static int preview_link_setup(struct media_entity *entity,
1899 const struct media_pad *local,
1900 const struct media_pad *remote, u32 flags)
1901{
1902 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1903 struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
1904
1905 switch (local->index | media_entity_type(remote->entity)) {
1906 case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1907 /* read from memory */
1908 if (flags & MEDIA_LNK_FL_ENABLED) {
1909 if (prev->input == PREVIEW_INPUT_CCDC)
1910 return -EBUSY;
1911 prev->input = PREVIEW_INPUT_MEMORY;
1912 } else {
1913 if (prev->input == PREVIEW_INPUT_MEMORY)
1914 prev->input = PREVIEW_INPUT_NONE;
1915 }
1916 break;
1917
1918 case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1919 /* read from ccdc */
1920 if (flags & MEDIA_LNK_FL_ENABLED) {
1921 if (prev->input == PREVIEW_INPUT_MEMORY)
1922 return -EBUSY;
1923 prev->input = PREVIEW_INPUT_CCDC;
1924 } else {
1925 if (prev->input == PREVIEW_INPUT_CCDC)
1926 prev->input = PREVIEW_INPUT_NONE;
1927 }
1928 break;
1929
1930 /*
1931 * The ISP core doesn't support pipelines with multiple video outputs.
1932 * Revisit this when it will be implemented, and return -EBUSY for now.
1933 */
1934
1935 case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1936 /* write to memory */
1937 if (flags & MEDIA_LNK_FL_ENABLED) {
1938 if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
1939 return -EBUSY;
1940 prev->output |= PREVIEW_OUTPUT_MEMORY;
1941 } else {
1942 prev->output &= ~PREVIEW_OUTPUT_MEMORY;
1943 }
1944 break;
1945
1946 case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
1947 /* write to resizer */
1948 if (flags & MEDIA_LNK_FL_ENABLED) {
1949 if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
1950 return -EBUSY;
1951 prev->output |= PREVIEW_OUTPUT_RESIZER;
1952 } else {
1953 prev->output &= ~PREVIEW_OUTPUT_RESIZER;
1954 }
1955 break;
1956
1957 default:
1958 return -EINVAL;
1959 }
1960
1961 return 0;
1962}
1963
1964/* media operations */
1965static const struct media_entity_operations preview_media_ops = {
1966 .link_setup = preview_link_setup,
1967};
1968
1969/*
1970 * review_init_entities - Initialize subdev and media entity.
1971 * @prev : Pointer to preview structure
1972 * return -ENOMEM or zero on success
1973 */
1974static int preview_init_entities(struct isp_prev_device *prev)
1975{
1976 struct v4l2_subdev *sd = &prev->subdev;
1977 struct media_pad *pads = prev->pads;
1978 struct media_entity *me = &sd->entity;
1979 int ret;
1980
1981 prev->input = PREVIEW_INPUT_NONE;
1982
1983 v4l2_subdev_init(sd, &preview_v4l2_ops);
1984 sd->internal_ops = &preview_v4l2_internal_ops;
1985 strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
1986 sd->grp_id = 1 << 16; /* group ID for isp subdevs */
1987 v4l2_set_subdevdata(sd, prev);
1988 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1989
1990 v4l2_ctrl_handler_init(&prev->ctrls, 2);
1991 v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
1992 ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
1993 ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
1994 v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
1995 ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
1996 ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
1997 v4l2_ctrl_handler_setup(&prev->ctrls);
1998 sd->ctrl_handler = &prev->ctrls;
1999
2000 pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
2001 pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
2002
2003 me->ops = &preview_media_ops;
2004 ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
2005 if (ret < 0)
2006 return ret;
2007
2008 preview_init_formats(sd, NULL);
2009
2010 /* According to the OMAP34xx TRM, video buffers need to be aligned on a
2011 * 32 bytes boundary. However, an undocumented hardware bug requires a
2012 * 64 bytes boundary at the preview engine input.
2013 */
2014 prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
2015 prev->video_in.ops = &preview_video_ops;
2016 prev->video_in.isp = to_isp_device(prev);
2017 prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
2018 prev->video_in.bpl_alignment = 64;
2019 prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2020 prev->video_out.ops = &preview_video_ops;
2021 prev->video_out.isp = to_isp_device(prev);
2022 prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
2023 prev->video_out.bpl_alignment = 32;
2024
2025 ret = omap3isp_video_init(&prev->video_in, "preview");
2026 if (ret < 0)
2027 return ret;
2028
2029 ret = omap3isp_video_init(&prev->video_out, "preview");
2030 if (ret < 0)
2031 return ret;
2032
2033 /* Connect the video nodes to the previewer subdev. */
2034 ret = media_entity_create_link(&prev->video_in.video.entity, 0,
2035 &prev->subdev.entity, PREV_PAD_SINK, 0);
2036 if (ret < 0)
2037 return ret;
2038
2039 ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE,
2040 &prev->video_out.video.entity, 0, 0);
2041 if (ret < 0)
2042 return ret;
2043
2044 return 0;
2045}
2046
2047void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
2048{
2049 media_entity_cleanup(&prev->subdev.entity);
2050
2051 v4l2_device_unregister_subdev(&prev->subdev);
2052 v4l2_ctrl_handler_free(&prev->ctrls);
2053 omap3isp_video_unregister(&prev->video_in);
2054 omap3isp_video_unregister(&prev->video_out);
2055}
2056
2057int omap3isp_preview_register_entities(struct isp_prev_device *prev,
2058 struct v4l2_device *vdev)
2059{
2060 int ret;
2061
2062 /* Register the subdev and video nodes. */
2063 ret = v4l2_device_register_subdev(vdev, &prev->subdev);
2064 if (ret < 0)
2065 goto error;
2066
2067 ret = omap3isp_video_register(&prev->video_in, vdev);
2068 if (ret < 0)
2069 goto error;
2070
2071 ret = omap3isp_video_register(&prev->video_out, vdev);
2072 if (ret < 0)
2073 goto error;
2074
2075 return 0;
2076
2077error:
2078 omap3isp_preview_unregister_entities(prev);
2079 return ret;
2080}
2081
2082/* -----------------------------------------------------------------------------
2083 * ISP previewer initialisation and cleanup
2084 */
2085
2086void omap3isp_preview_cleanup(struct isp_device *isp)
2087{
2088}
2089
2090/*
2091 * isp_preview_init - Previewer initialization.
2092 * @dev : Pointer to ISP device
2093 * return -ENOMEM or zero on success
2094 */
2095int omap3isp_preview_init(struct isp_device *isp)
2096{
2097 struct isp_prev_device *prev = &isp->isp_prev;
2098 int ret;
2099
2100 spin_lock_init(&prev->lock);
2101 init_waitqueue_head(&prev->wait);
2102 preview_init_params(prev);
2103
2104 ret = preview_init_entities(prev);
2105 if (ret < 0)
2106 goto out;
2107
2108out:
2109 if (ret)
2110 omap3isp_preview_cleanup(isp);
2111
2112 return ret;
2113}
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h
new file mode 100644
index 000000000000..f2d63ca4bd6f
--- /dev/null
+++ b/drivers/media/video/omap3isp/isppreview.h
@@ -0,0 +1,214 @@
1/*
2 * isppreview.h
3 *
4 * TI OMAP3 ISP - Preview module
5 *
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
27#ifndef OMAP3_ISP_PREVIEW_H
28#define OMAP3_ISP_PREVIEW_H
29
30#include <linux/omap3isp.h>
31#include <linux/types.h>
32#include <media/v4l2-ctrls.h>
33
34#include "ispvideo.h"
35
36#define ISPPRV_BRIGHT_STEP 0x1
37#define ISPPRV_BRIGHT_DEF 0x0
38#define ISPPRV_BRIGHT_LOW 0x0
39#define ISPPRV_BRIGHT_HIGH 0xFF
40#define ISPPRV_BRIGHT_UNITS 0x1
41
42#define ISPPRV_CONTRAST_STEP 0x1
43#define ISPPRV_CONTRAST_DEF 0x10
44#define ISPPRV_CONTRAST_LOW 0x0
45#define ISPPRV_CONTRAST_HIGH 0xFF
46#define ISPPRV_CONTRAST_UNITS 0x1
47
48#define NO_AVE 0x0
49#define AVE_2_PIX 0x1
50#define AVE_4_PIX 0x2
51#define AVE_8_PIX 0x3
52
53/* Features list */
54#define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH
55#define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW
56#define PREV_HORZ_MEDIAN_FILTER OMAP3ISP_PREV_HRZ_MED
57#define PREV_CFA OMAP3ISP_PREV_CFA
58#define PREV_CHROMA_SUPPRESS OMAP3ISP_PREV_CHROMA_SUPP
59#define PREV_WB OMAP3ISP_PREV_WB
60#define PREV_BLKADJ OMAP3ISP_PREV_BLKADJ
61#define PREV_RGB2RGB OMAP3ISP_PREV_RGB2RGB
62#define PREV_COLOR_CONV OMAP3ISP_PREV_COLOR_CONV
63#define PREV_YCLIMITS OMAP3ISP_PREV_YC_LIMIT
64#define PREV_DEFECT_COR OMAP3ISP_PREV_DEFECT_COR
65#define PREV_GAMMA_BYPASS OMAP3ISP_PREV_GAMMABYPASS
66#define PREV_DARK_FRAME_CAPTURE OMAP3ISP_PREV_DRK_FRM_CAPTURE
67#define PREV_DARK_FRAME_SUBTRACT OMAP3ISP_PREV_DRK_FRM_SUBTRACT
68#define PREV_LENS_SHADING OMAP3ISP_PREV_LENS_SHADING
69#define PREV_NOISE_FILTER OMAP3ISP_PREV_NF
70#define PREV_GAMMA OMAP3ISP_PREV_GAMMA
71
72#define PREV_CONTRAST (1 << 17)
73#define PREV_BRIGHTNESS (1 << 18)
74#define PREV_AVERAGER (1 << 19)
75#define PREV_FEATURES_END (1 << 20)
76
77enum preview_input_entity {
78 PREVIEW_INPUT_NONE,
79 PREVIEW_INPUT_CCDC,
80 PREVIEW_INPUT_MEMORY,
81};
82
83#define PREVIEW_OUTPUT_RESIZER (1 << 1)
84#define PREVIEW_OUTPUT_MEMORY (1 << 2)
85
86/* Configure byte layout of YUV image */
87enum preview_ycpos_mode {
88 YCPOS_YCrYCb = 0,
89 YCPOS_YCbYCr = 1,
90 YCPOS_CbYCrY = 2,
91 YCPOS_CrYCbY = 3
92};
93
94/*
95 * struct prev_params - Structure for all configuration
96 * @features: Set of features enabled.
97 * @cfa: CFA coefficients.
98 * @csup: Chroma suppression coefficients.
99 * @luma: Luma enhancement coefficients.
100 * @nf: Noise filter coefficients.
101 * @dcor: Noise filter coefficients.
102 * @gamma: Gamma coefficients.
103 * @wbal: White Balance parameters.
104 * @blk_adj: Black adjustment parameters.
105 * @rgb2rgb: RGB blending parameters.
106 * @rgb2ycbcr: RGB to ycbcr parameters.
107 * @hmed: Horizontal median filter.
108 * @yclimit: YC limits parameters.
109 * @average: Downsampling rate for averager.
110 * @contrast: Contrast.
111 * @brightness: Brightness.
112 */
113struct prev_params {
114 u32 features;
115 struct omap3isp_prev_cfa cfa;
116 struct omap3isp_prev_csup csup;
117 struct omap3isp_prev_luma luma;
118 struct omap3isp_prev_nf nf;
119 struct omap3isp_prev_dcor dcor;
120 struct omap3isp_prev_gtables gamma;
121 struct omap3isp_prev_wbal wbal;
122 struct omap3isp_prev_blkadj blk_adj;
123 struct omap3isp_prev_rgbtorgb rgb2rgb;
124 struct omap3isp_prev_csc rgb2ycbcr;
125 struct omap3isp_prev_hmed hmed;
126 struct omap3isp_prev_yclimit yclimit;
127 u8 average;
128 u8 contrast;
129 u8 brightness;
130};
131
132/*
133 * struct isptables_update - Structure for Table Configuration.
134 * @update: Specifies which tables should be updated.
135 * @flag: Specifies which tables should be enabled.
136 * @nf: Pointer to structure for Noise Filter
137 * @lsc: Pointer to LSC gain table. (currently not used)
138 * @gamma: Pointer to gamma correction tables.
139 * @cfa: Pointer to color filter array configuration.
140 * @wbal: Pointer to colour and digital gain configuration.
141 */
142struct isptables_update {
143 u32 update;
144 u32 flag;
145 struct omap3isp_prev_nf *nf;
146 u32 *lsc;
147 struct omap3isp_prev_gtables *gamma;
148 struct omap3isp_prev_cfa *cfa;
149 struct omap3isp_prev_wbal *wbal;
150};
151
152/* Sink and source previewer pads */
153#define PREV_PAD_SINK 0
154#define PREV_PAD_SOURCE 1
155#define PREV_PADS_NUM 2
156
157/*
158 * struct isp_prev_device - Structure for storing ISP Preview module information
159 * @subdev: V4L2 subdevice
160 * @pads: Media entity pads
161 * @formats: Active formats at the subdev pad
162 * @input: Module currently connected to the input pad
163 * @output: Bitmask of the active output
164 * @video_in: Input video entity
165 * @video_out: Output video entity
166 * @error: A hardware error occured during capture
167 * @params: Module configuration data
168 * @shadow_update: If set, update the hardware configured in the next interrupt
169 * @underrun: Whether the preview entity has queued buffers on the output
170 * @state: Current preview pipeline state
171 * @lock: Shadow update lock
172 * @update: Bitmask of the parameters to be updated
173 *
174 * This structure is used to store the OMAP ISP Preview module Information.
175 */
176struct isp_prev_device {
177 struct v4l2_subdev subdev;
178 struct media_pad pads[PREV_PADS_NUM];
179 struct v4l2_mbus_framefmt formats[PREV_PADS_NUM];
180
181 struct v4l2_ctrl_handler ctrls;
182
183 enum preview_input_entity input;
184 unsigned int output;
185 struct isp_video video_in;
186 struct isp_video video_out;
187 unsigned int error;
188
189 struct prev_params params;
190 unsigned int shadow_update:1;
191 enum isp_pipeline_stream_state state;
192 wait_queue_head_t wait;
193 atomic_t stopping;
194 spinlock_t lock;
195 u32 update;
196};
197
198struct isp_device;
199
200int omap3isp_preview_init(struct isp_device *isp);
201void omap3isp_preview_cleanup(struct isp_device *isp);
202
203int omap3isp_preview_register_entities(struct isp_prev_device *prv,
204 struct v4l2_device *vdev);
205void omap3isp_preview_unregister_entities(struct isp_prev_device *prv);
206
207void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev);
208void omap3isp_preview_isr(struct isp_prev_device *prev);
209
210int omap3isp_preview_busy(struct isp_prev_device *isp_prev);
211
212void omap3isp_preview_restore_context(struct isp_device *isp);
213
214#endif /* OMAP3_ISP_PREVIEW_H */
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c
new file mode 100644
index 000000000000..75d39b115d42
--- /dev/null
+++ b/drivers/media/video/omap3isp/ispresizer.c
@@ -0,0 +1,1693 @@
1/*
2 * ispresizer.c
3 *
4 * TI OMAP3 ISP - Resizer module
5 *
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
27#include <linux/device.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30
31#include "isp.h"
32#include "ispreg.h"
33#include "ispresizer.h"
34
35/*
36 * Resizer Constants
37 */
38#define MIN_RESIZE_VALUE 64
39#define MID_RESIZE_VALUE 512
40#define MAX_RESIZE_VALUE 1024
41
42#define MIN_IN_WIDTH 32
43#define MIN_IN_HEIGHT 32
44#define MAX_IN_WIDTH_MEMORY_MODE 4095
45#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
46#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
47#define MAX_IN_HEIGHT 4095
48
49#define MIN_OUT_WIDTH 16
50#define MIN_OUT_HEIGHT 2
51#define MAX_OUT_HEIGHT 4095
52
53/*
54 * Resizer Use Constraints
55 * "TRM ES3.1, table 12-46"
56 */
57#define MAX_4TAP_OUT_WIDTH_ES1 1280
58#define MAX_7TAP_OUT_WIDTH_ES1 640
59#define MAX_4TAP_OUT_WIDTH_ES2 3312
60#define MAX_7TAP_OUT_WIDTH_ES2 1650
61#define MAX_4TAP_OUT_WIDTH_3630 4096
62#define MAX_7TAP_OUT_WIDTH_3630 2048
63
64/*
65 * Constants for ratio calculation
66 */
67#define RESIZE_DIVISOR 256
68#define DEFAULT_PHASE 1
69
70/*
71 * Default (and only) configuration of filter coefficients.
72 * 7-tap mode is for scale factors 0.25x to 0.5x.
73 * 4-tap mode is for scale factors 0.5x to 4.0x.
74 * There shouldn't be any reason to recalculate these, EVER.
75 */
76static const struct isprsz_coef filter_coefs = {
77 /* For 8-phase 4-tap horizontal filter: */
78 {
79 0x0000, 0x0100, 0x0000, 0x0000,
80 0x03FA, 0x00F6, 0x0010, 0x0000,
81 0x03F9, 0x00DB, 0x002C, 0x0000,
82 0x03FB, 0x00B3, 0x0053, 0x03FF,
83 0x03FD, 0x0082, 0x0084, 0x03FD,
84 0x03FF, 0x0053, 0x00B3, 0x03FB,
85 0x0000, 0x002C, 0x00DB, 0x03F9,
86 0x0000, 0x0010, 0x00F6, 0x03FA
87 },
88 /* For 8-phase 4-tap vertical filter: */
89 {
90 0x0000, 0x0100, 0x0000, 0x0000,
91 0x03FA, 0x00F6, 0x0010, 0x0000,
92 0x03F9, 0x00DB, 0x002C, 0x0000,
93 0x03FB, 0x00B3, 0x0053, 0x03FF,
94 0x03FD, 0x0082, 0x0084, 0x03FD,
95 0x03FF, 0x0053, 0x00B3, 0x03FB,
96 0x0000, 0x002C, 0x00DB, 0x03F9,
97 0x0000, 0x0010, 0x00F6, 0x03FA
98 },
99 /* For 4-phase 7-tap horizontal filter: */
100 #define DUMMY 0
101 {
102 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
103 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
104 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
105 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
106 },
107 /* For 4-phase 7-tap vertical filter: */
108 {
109 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
110 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
111 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
112 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
113 }
114 /*
115 * The dummy padding is required in 7-tap mode because of how the
116 * registers are arranged physically.
117 */
118 #undef DUMMY
119};
120
121/*
122 * __resizer_get_format - helper function for getting resizer format
123 * @res : pointer to resizer private structure
124 * @pad : pad number
125 * @fh : V4L2 subdev file handle
126 * @which : wanted subdev format
127 * return zero
128 */
129static struct v4l2_mbus_framefmt *
130__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
131 unsigned int pad, enum v4l2_subdev_format_whence which)
132{
133 if (which == V4L2_SUBDEV_FORMAT_TRY)
134 return v4l2_subdev_get_try_format(fh, pad);
135 else
136 return &res->formats[pad];
137}
138
139/*
140 * __resizer_get_crop - helper function for getting resizer crop rectangle
141 * @res : pointer to resizer private structure
142 * @fh : V4L2 subdev file handle
143 * @which : wanted subdev crop rectangle
144 */
145static struct v4l2_rect *
146__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
147 enum v4l2_subdev_format_whence which)
148{
149 if (which == V4L2_SUBDEV_FORMAT_TRY)
150 return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
151 else
152 return &res->crop.request;
153}
154
155/*
156 * resizer_set_filters - Set resizer filters
157 * @res: Device context.
158 * @h_coeff: horizontal coefficient
159 * @v_coeff: vertical coefficient
160 * Return none
161 */
162static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
163 const u16 *v_coeff)
164{
165 struct isp_device *isp = to_isp_device(res);
166 u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
167 int i;
168
169 startaddr_h = ISPRSZ_HFILT10;
170 startaddr_v = ISPRSZ_VFILT10;
171
172 for (i = 0; i < COEFF_CNT; i += 2) {
173 tmp_h = h_coeff[i] |
174 (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
175 tmp_v = v_coeff[i] |
176 (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
177 isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
178 isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
179 startaddr_h += 4;
180 startaddr_v += 4;
181 }
182}
183
184/*
185 * resizer_set_bilinear - Chrominance horizontal algorithm select
186 * @res: Device context.
187 * @type: Filtering interpolation type.
188 *
189 * Filtering that is same as luminance processing is
190 * intended only for downsampling, and bilinear interpolation
191 * is intended only for upsampling.
192 */
193static void resizer_set_bilinear(struct isp_res_device *res,
194 enum resizer_chroma_algo type)
195{
196 struct isp_device *isp = to_isp_device(res);
197
198 if (type == RSZ_BILINEAR)
199 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
200 ISPRSZ_CNT_CBILIN);
201 else
202 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
203 ISPRSZ_CNT_CBILIN);
204}
205
206/*
207 * resizer_set_ycpos - Luminance and chrominance order
208 * @res: Device context.
209 * @order: order type.
210 */
211static void resizer_set_ycpos(struct isp_res_device *res,
212 enum v4l2_mbus_pixelcode pixelcode)
213{
214 struct isp_device *isp = to_isp_device(res);
215
216 switch (pixelcode) {
217 case V4L2_MBUS_FMT_YUYV8_1X16:
218 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
219 ISPRSZ_CNT_YCPOS);
220 break;
221 case V4L2_MBUS_FMT_UYVY8_1X16:
222 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
223 ISPRSZ_CNT_YCPOS);
224 break;
225 default:
226 return;
227 }
228}
229
230/*
231 * resizer_set_phase - Setup horizontal and vertical starting phase
232 * @res: Device context.
233 * @h_phase: horizontal phase parameters.
234 * @v_phase: vertical phase parameters.
235 *
236 * Horizontal and vertical phase range is 0 to 7
237 */
238static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
239 u32 v_phase)
240{
241 struct isp_device *isp = to_isp_device(res);
242 u32 rgval = 0;
243
244 rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
245 ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
246 rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
247 rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
248
249 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
250}
251
252/*
253 * resizer_set_luma - Setup luminance enhancer parameters
254 * @res: Device context.
255 * @luma: Structure for luminance enhancer parameters.
256 *
257 * Algorithm select:
258 * 0x0: Disable
259 * 0x1: [-1 2 -1]/2 high-pass filter
260 * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter
261 *
262 * Maximum gain:
263 * The data is coded in U4Q4 representation.
264 *
265 * Slope:
266 * The data is coded in U4Q4 representation.
267 *
268 * Coring offset:
269 * The data is coded in U8Q0 representation.
270 *
271 * The new luminance value is computed as:
272 * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
273 */
274static void resizer_set_luma(struct isp_res_device *res,
275 struct resizer_luma_yenh *luma)
276{
277 struct isp_device *isp = to_isp_device(res);
278 u32 rgval = 0;
279
280 rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
281 & ISPRSZ_YENH_ALGO_MASK;
282 rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
283 & ISPRSZ_YENH_GAIN_MASK;
284 rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
285 & ISPRSZ_YENH_SLOP_MASK;
286 rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
287 & ISPRSZ_YENH_CORE_MASK;
288
289 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
290}
291
292/*
293 * resizer_set_source - Input source select
294 * @res: Device context.
295 * @source: Input source type
296 *
297 * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
298 * Preview/CCDC engine, otherwise from memory.
299 */
300static void resizer_set_source(struct isp_res_device *res,
301 enum resizer_input_entity source)
302{
303 struct isp_device *isp = to_isp_device(res);
304
305 if (source == RESIZER_INPUT_MEMORY)
306 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
307 ISPRSZ_CNT_INPSRC);
308 else
309 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
310 ISPRSZ_CNT_INPSRC);
311}
312
313/*
314 * resizer_set_ratio - Setup horizontal and vertical resizing value
315 * @res: Device context.
316 * @ratio: Structure for ratio parameters.
317 *
318 * Resizing range from 64 to 1024
319 */
320static void resizer_set_ratio(struct isp_res_device *res,
321 const struct resizer_ratio *ratio)
322{
323 struct isp_device *isp = to_isp_device(res);
324 const u16 *h_filter, *v_filter;
325 u32 rgval = 0;
326
327 rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
328 ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
329 rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
330 & ISPRSZ_CNT_HRSZ_MASK;
331 rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
332 & ISPRSZ_CNT_VRSZ_MASK;
333 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
334
335 /* prepare horizontal filter coefficients */
336 if (ratio->horz > MID_RESIZE_VALUE)
337 h_filter = &filter_coefs.h_filter_coef_7tap[0];
338 else
339 h_filter = &filter_coefs.h_filter_coef_4tap[0];
340
341 /* prepare vertical filter coefficients */
342 if (ratio->vert > MID_RESIZE_VALUE)
343 v_filter = &filter_coefs.v_filter_coef_7tap[0];
344 else
345 v_filter = &filter_coefs.v_filter_coef_4tap[0];
346
347 resizer_set_filters(res, h_filter, v_filter);
348}
349
350/*
351 * resizer_set_dst_size - Setup the output height and width
352 * @res: Device context.
353 * @width: Output width.
354 * @height: Output height.
355 *
356 * Width :
357 * The value must be EVEN.
358 *
359 * Height:
360 * The number of bytes written to SDRAM must be
361 * a multiple of 16-bytes if the vertical resizing factor
362 * is greater than 1x (upsizing)
363 */
364static void resizer_set_output_size(struct isp_res_device *res,
365 u32 width, u32 height)
366{
367 struct isp_device *isp = to_isp_device(res);
368 u32 rgval = 0;
369
370 dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
371 rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
372 & ISPRSZ_OUT_SIZE_HORZ_MASK;
373 rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
374 & ISPRSZ_OUT_SIZE_VERT_MASK;
375 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
376}
377
378/*
379 * resizer_set_output_offset - Setup memory offset for the output lines.
380 * @res: Device context.
381 * @offset: Memory offset.
382 *
383 * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
384 * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
385 * the SDRAM line offset must be set on a 256-byte boundary
386 */
387static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
388{
389 struct isp_device *isp = to_isp_device(res);
390
391 isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
392}
393
394/*
395 * resizer_set_start - Setup vertical and horizontal start position
396 * @res: Device context.
397 * @left: Horizontal start position.
398 * @top: Vertical start position.
399 *
400 * Vertical start line:
401 * This field makes sense only when the resizer obtains its input
402 * from the preview engine/CCDC
403 *
404 * Horizontal start pixel:
405 * Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
406 * When the resizer gets its input from SDRAM, this field must be set
407 * to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
408 */
409static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
410{
411 struct isp_device *isp = to_isp_device(res);
412 u32 rgval = 0;
413
414 rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
415 & ISPRSZ_IN_START_HORZ_ST_MASK;
416 rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
417 & ISPRSZ_IN_START_VERT_ST_MASK;
418
419 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
420}
421
422/*
423 * resizer_set_input_size - Setup the input size
424 * @res: Device context.
425 * @width: The range is 0 to 4095 pixels
426 * @height: The range is 0 to 4095 lines
427 */
428static void resizer_set_input_size(struct isp_res_device *res,
429 u32 width, u32 height)
430{
431 struct isp_device *isp = to_isp_device(res);
432 u32 rgval = 0;
433
434 dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
435
436 rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
437 & ISPRSZ_IN_SIZE_HORZ_MASK;
438 rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
439 & ISPRSZ_IN_SIZE_VERT_MASK;
440
441 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
442}
443
444/*
445 * resizer_set_src_offs - Setup the memory offset for the input lines
446 * @res: Device context.
447 * @offset: Memory offset.
448 *
449 * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
450 * boundary; the 5 LSBs are read-only. This field must be programmed to be
451 * 0x0 if the resizer input is from preview engine/CCDC.
452 */
453static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
454{
455 struct isp_device *isp = to_isp_device(res);
456
457 isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
458}
459
460/*
461 * resizer_set_intype - Input type select
462 * @res: Device context.
463 * @type: Pixel format type.
464 */
465static void resizer_set_intype(struct isp_res_device *res,
466 enum resizer_colors_type type)
467{
468 struct isp_device *isp = to_isp_device(res);
469
470 if (type == RSZ_COLOR8)
471 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
472 ISPRSZ_CNT_INPTYP);
473 else
474 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
475 ISPRSZ_CNT_INPTYP);
476}
477
478/*
479 * __resizer_set_inaddr - Helper function for set input address
480 * @res : pointer to resizer private data structure
481 * @addr: input address
482 * return none
483 */
484static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
485{
486 struct isp_device *isp = to_isp_device(res);
487
488 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
489}
490
491/*
492 * The data rate at the horizontal resizer output must not exceed half the
493 * functional clock or 100 MP/s, whichever is lower. According to the TRM
494 * there's no similar requirement for the vertical resizer output. However
495 * experience showed that vertical upscaling by 4 leads to SBL overflows (with
496 * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
497 * output data rate to the functional clock or 200 MP/s, whichever is lower,
498 * seems to get rid of SBL overflows.
499 *
500 * The maximum data rate at the output of the horizontal resizer can thus be
501 * computed with
502 *
503 * max intermediate rate <= L3 clock * input height / output height
504 * max intermediate rate <= L3 clock / 2
505 *
506 * The maximum data rate at the resizer input is then
507 *
508 * max input rate <= max intermediate rate * input width / output width
509 *
510 * where the input width and height are the resizer input crop rectangle size.
511 * The TRM doesn't clearly explain if that's a maximum instant data rate or a
512 * maximum average data rate.
513 */
514void omap3isp_resizer_max_rate(struct isp_res_device *res,
515 unsigned int *max_rate)
516{
517 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
518 const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
519 unsigned long limit = min(pipe->l3_ick, 200000000UL);
520 unsigned long clock;
521
522 clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
523 clock = min(clock, limit / 2);
524 *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
525}
526
527/*
528 * When the resizer processes images from memory, the driver must slow down read
529 * requests on the input to at least comply with the internal data rate
530 * requirements. If the application real-time requirements can cope with slower
531 * processing, the resizer can be slowed down even more to put less pressure on
532 * the overall system.
533 *
534 * When the resizer processes images on the fly (either from the CCDC or the
535 * preview module), the same data rate requirements apply but they can't be
536 * enforced at the resizer level. The image input module (sensor, CCP2 or
537 * preview module) must not provide image data faster than the resizer can
538 * process.
539 *
540 * For live image pipelines, the data rate is set by the frame format, size and
541 * rate. The sensor output frame rate must not exceed the maximum resizer data
542 * rate.
543 *
544 * The resizer slows down read requests by inserting wait cycles in the SBL
545 * requests. The maximum number of 256-byte requests per second can be computed
546 * as (the data rate is multiplied by 2 to convert from pixels per second to
547 * bytes per second)
548 *
549 * request per second = data rate * 2 / 256
550 * cycles per request = cycles per second / requests per second
551 *
552 * The number of cycles per second is controlled by the L3 clock, leading to
553 *
554 * cycles per request = L3 frequency / 2 * 256 / data rate
555 */
556static void resizer_adjust_bandwidth(struct isp_res_device *res)
557{
558 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
559 struct isp_device *isp = to_isp_device(res);
560 unsigned long l3_ick = pipe->l3_ick;
561 struct v4l2_fract *timeperframe;
562 unsigned int cycles_per_frame;
563 unsigned int requests_per_frame;
564 unsigned int cycles_per_request;
565 unsigned int granularity;
566 unsigned int minimum;
567 unsigned int maximum;
568 unsigned int value;
569
570 if (res->input != RESIZER_INPUT_MEMORY) {
571 isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
572 ISPSBL_SDR_REQ_RSZ_EXP_MASK);
573 return;
574 }
575
576 switch (isp->revision) {
577 case ISP_REVISION_1_0:
578 case ISP_REVISION_2_0:
579 default:
580 granularity = 1024;
581 break;
582
583 case ISP_REVISION_15_0:
584 granularity = 32;
585 break;
586 }
587
588 /* Compute the minimum number of cycles per request, based on the
589 * pipeline maximum data rate. This is an absolute lower bound if we
590 * don't want SBL overflows, so round the value up.
591 */
592 cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
593 pipe->max_rate);
594 minimum = DIV_ROUND_UP(cycles_per_request, granularity);
595
596 /* Compute the maximum number of cycles per request, based on the
597 * requested frame rate. This is a soft upper bound to achieve a frame
598 * rate equal or higher than the requested value, so round the value
599 * down.
600 */
601 timeperframe = &pipe->max_timeperframe;
602
603 requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
604 * res->crop.active.height;
605 cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
606 timeperframe->denominator);
607 cycles_per_request = cycles_per_frame / requests_per_frame;
608
609 maximum = cycles_per_request / granularity;
610
611 value = max(minimum, maximum);
612
613 dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
614 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
615 ISPSBL_SDR_REQ_RSZ_EXP_MASK,
616 value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
617}
618
619/*
620 * omap3isp_resizer_busy - Checks if ISP resizer is busy.
621 *
622 * Returns busy field from ISPRSZ_PCR register.
623 */
624int omap3isp_resizer_busy(struct isp_res_device *res)
625{
626 struct isp_device *isp = to_isp_device(res);
627
628 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
629 ISPRSZ_PCR_BUSY;
630}
631
632/*
633 * resizer_set_inaddr - Sets the memory address of the input frame.
634 * @addr: 32bit memory address aligned on 32byte boundary.
635 */
636static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
637{
638 res->addr_base = addr;
639
640 /* This will handle crop settings in stream off state */
641 if (res->crop_offset)
642 addr += res->crop_offset & ~0x1f;
643
644 __resizer_set_inaddr(res, addr);
645}
646
647/*
648 * Configures the memory address to which the output frame is written.
649 * @addr: 32bit memory address aligned on 32byte boundary.
650 * Note: For SBL efficiency reasons the address should be on a 256-byte
651 * boundary.
652 */
653static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
654{
655 struct isp_device *isp = to_isp_device(res);
656
657 /*
658 * Set output address. This needs to be in its own function
659 * because it changes often.
660 */
661 isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
662 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
663}
664
665/*
666 * resizer_print_status - Prints the values of the resizer module registers.
667 */
668#define RSZ_PRINT_REGISTER(isp, name)\
669 dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
670 isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
671
672static void resizer_print_status(struct isp_res_device *res)
673{
674 struct isp_device *isp = to_isp_device(res);
675
676 dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
677
678 RSZ_PRINT_REGISTER(isp, PCR);
679 RSZ_PRINT_REGISTER(isp, CNT);
680 RSZ_PRINT_REGISTER(isp, OUT_SIZE);
681 RSZ_PRINT_REGISTER(isp, IN_START);
682 RSZ_PRINT_REGISTER(isp, IN_SIZE);
683 RSZ_PRINT_REGISTER(isp, SDR_INADD);
684 RSZ_PRINT_REGISTER(isp, SDR_INOFF);
685 RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
686 RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
687 RSZ_PRINT_REGISTER(isp, YENH);
688
689 dev_dbg(isp->dev, "--------------------------------------------\n");
690}
691
692/*
693 * resizer_calc_ratios - Helper function for calculate resizer ratios
694 * @res: pointer to resizer private data structure
695 * @input: input frame size
696 * @output: output frame size
697 * @ratio : return calculated ratios
698 * return none
699 *
700 * The resizer uses a polyphase sample rate converter. The upsampling filter
701 * has a fixed number of phases that depend on the resizing ratio. As the ratio
702 * computation depends on the number of phases, we need to compute a first
703 * approximation and then refine it.
704 *
705 * The input/output/ratio relationship is given by the OMAP34xx TRM:
706 *
707 * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
708 * iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
709 * ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
710 * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
711 * iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
712 * ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
713 *
714 * iw and ih are the input width and height after cropping. Those equations need
715 * to be satisfied exactly for the resizer to work correctly.
716 *
717 * Reverting the equations, we can compute the resizing ratios with
718 *
719 * - 8-phase, 4-tap mode
720 * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1)
721 * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1)
722 * - 4-phase, 7-tap mode
723 * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1)
724 * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1)
725 *
726 * The ratios are integer values, and must be rounded down to ensure that the
727 * cropped input size is not bigger than the uncropped input size. As the ratio
728 * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the
729 * 7-tap mode equations to compute a ratio approximation.
730 *
731 * We first clamp the output size according to the hardware capabilitie to avoid
732 * auto-cropping the input more than required to satisfy the TRM equations. The
733 * minimum output size is achieved with a scaling factor of 1024. It is thus
734 * computed using the 7-tap equations.
735 *
736 * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
737 * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
738 *
739 * Similarly, the maximum output size is achieved with a scaling factor of 64
740 * and computed using the 4-tap equations.
741 *
742 * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
743 * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
744 *
745 * The additional +255 term compensates for the round down operation performed
746 * by the TRM equations when shifting the value right by 8 bits.
747 *
748 * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
749 * the maximum value guarantees that the ratio value will never be smaller than
750 * the minimum, but it could still slightly exceed the maximum. Clamping the
751 * ratio will thus result in a resizing factor slightly larger than the
752 * requested value.
753 *
754 * To accomodate that, and make sure the TRM equations are satisfied exactly, we
755 * compute the input crop rectangle as the last step.
756 *
757 * As if the situation wasn't complex enough, the maximum output width depends
758 * on the vertical resizing ratio. Fortunately, the output height doesn't
759 * depend on the horizontal resizing ratio. We can then start by computing the
760 * output height and the vertical ratio, and then move to computing the output
761 * width and the horizontal ratio.
762 */
763static void resizer_calc_ratios(struct isp_res_device *res,
764 struct v4l2_rect *input,
765 struct v4l2_mbus_framefmt *output,
766 struct resizer_ratio *ratio)
767{
768 struct isp_device *isp = to_isp_device(res);
769 const unsigned int spv = DEFAULT_PHASE;
770 const unsigned int sph = DEFAULT_PHASE;
771 unsigned int upscaled_width;
772 unsigned int upscaled_height;
773 unsigned int min_width;
774 unsigned int min_height;
775 unsigned int max_width;
776 unsigned int max_height;
777 unsigned int width_alignment;
778
779 /*
780 * Clamp the output height based on the hardware capabilities and
781 * compute the vertical resizing ratio.
782 */
783 min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
784 min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
785 max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
786 max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
787 output->height = clamp(output->height, min_height, max_height);
788
789 ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv)
790 / (output->height - 1);
791 ratio->vert = clamp_t(unsigned int, ratio->vert,
792 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
793
794 if (ratio->vert <= MID_RESIZE_VALUE) {
795 upscaled_height = (output->height - 1) * ratio->vert
796 + 32 * spv + 16;
797 input->height = (upscaled_height >> 8) + 4;
798 } else {
799 upscaled_height = (output->height - 1) * ratio->vert
800 + 64 * spv + 32;
801 input->height = (upscaled_height >> 8) + 7;
802 }
803
804 /*
805 * Compute the minimum and maximum output widths based on the hardware
806 * capabilities. The maximum depends on the vertical resizing ratio.
807 */
808 min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
809 min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
810
811 if (ratio->vert <= MID_RESIZE_VALUE) {
812 switch (isp->revision) {
813 case ISP_REVISION_1_0:
814 max_width = MAX_4TAP_OUT_WIDTH_ES1;
815 break;
816
817 case ISP_REVISION_2_0:
818 default:
819 max_width = MAX_4TAP_OUT_WIDTH_ES2;
820 break;
821
822 case ISP_REVISION_15_0:
823 max_width = MAX_4TAP_OUT_WIDTH_3630;
824 break;
825 }
826 } else {
827 switch (isp->revision) {
828 case ISP_REVISION_1_0:
829 max_width = MAX_7TAP_OUT_WIDTH_ES1;
830 break;
831
832 case ISP_REVISION_2_0:
833 default:
834 max_width = MAX_7TAP_OUT_WIDTH_ES2;
835 break;
836
837 case ISP_REVISION_15_0:
838 max_width = MAX_7TAP_OUT_WIDTH_3630;
839 break;
840 }
841 }
842 max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
843 + 1, max_width);
844
845 /*
846 * The output width must be even, and must be a multiple of 16 bytes
847 * when upscaling vertically. Clamp the output width to the valid range.
848 * Take the alignment into account (the maximum width in 7-tap mode on
849 * ES2 isn't a multiple of 8) and align the result up to make sure it
850 * won't be smaller than the minimum.
851 */
852 width_alignment = ratio->vert < 256 ? 8 : 2;
853 output->width = clamp(output->width, min_width,
854 max_width & ~(width_alignment - 1));
855 output->width = ALIGN(output->width, width_alignment);
856
857 ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph)
858 / (output->width - 1);
859 ratio->horz = clamp_t(unsigned int, ratio->horz,
860 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
861
862 if (ratio->horz <= MID_RESIZE_VALUE) {
863 upscaled_width = (output->width - 1) * ratio->horz
864 + 32 * sph + 16;
865 input->width = (upscaled_width >> 8) + 7;
866 } else {
867 upscaled_width = (output->width - 1) * ratio->horz
868 + 64 * sph + 32;
869 input->width = (upscaled_width >> 8) + 7;
870 }
871}
872
873/*
874 * resizer_set_crop_params - Setup hardware with cropping parameters
875 * @res : resizer private structure
876 * @crop_rect : current crop rectangle
877 * @ratio : resizer ratios
878 * return none
879 */
880static void resizer_set_crop_params(struct isp_res_device *res,
881 const struct v4l2_mbus_framefmt *input,
882 const struct v4l2_mbus_framefmt *output)
883{
884 resizer_set_ratio(res, &res->ratio);
885
886 /* Set chrominance horizontal algorithm */
887 if (res->ratio.horz >= RESIZE_DIVISOR)
888 resizer_set_bilinear(res, RSZ_THE_SAME);
889 else
890 resizer_set_bilinear(res, RSZ_BILINEAR);
891
892 resizer_adjust_bandwidth(res);
893
894 if (res->input == RESIZER_INPUT_MEMORY) {
895 /* Calculate additional offset for crop */
896 res->crop_offset = (res->crop.active.top * input->width +
897 res->crop.active.left) * 2;
898 /*
899 * Write lowest 4 bits of horizontal pixel offset (in pixels),
900 * vertical start must be 0.
901 */
902 resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
903
904 /*
905 * Set start (read) address for cropping, in bytes.
906 * Lowest 5 bits must be zero.
907 */
908 __resizer_set_inaddr(res,
909 res->addr_base + (res->crop_offset & ~0x1f));
910 } else {
911 /*
912 * Set vertical start line and horizontal starting pixel.
913 * If the input is from CCDC/PREV, horizontal start field is
914 * in bytes (twice number of pixels).
915 */
916 resizer_set_start(res, res->crop.active.left * 2,
917 res->crop.active.top);
918 /* Input address and offset must be 0 for preview/ccdc input */
919 __resizer_set_inaddr(res, 0);
920 resizer_set_input_offset(res, 0);
921 }
922
923 /* Set the input size */
924 resizer_set_input_size(res, res->crop.active.width,
925 res->crop.active.height);
926}
927
928static void resizer_configure(struct isp_res_device *res)
929{
930 struct v4l2_mbus_framefmt *informat, *outformat;
931 struct resizer_luma_yenh luma = {0, 0, 0, 0};
932
933 resizer_set_source(res, res->input);
934
935 informat = &res->formats[RESZ_PAD_SINK];
936 outformat = &res->formats[RESZ_PAD_SOURCE];
937
938 /* RESZ_PAD_SINK */
939 if (res->input == RESIZER_INPUT_VP)
940 resizer_set_input_offset(res, 0);
941 else
942 resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
943
944 /* YUV422 interleaved, default phase, no luma enhancement */
945 resizer_set_intype(res, RSZ_YUV422);
946 resizer_set_ycpos(res, informat->code);
947 resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
948 resizer_set_luma(res, &luma);
949
950 /* RESZ_PAD_SOURCE */
951 resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
952 resizer_set_output_size(res, outformat->width, outformat->height);
953
954 resizer_set_crop_params(res, informat, outformat);
955}
956
957/* -----------------------------------------------------------------------------
958 * Interrupt handling
959 */
960
961static void resizer_enable_oneshot(struct isp_res_device *res)
962{
963 struct isp_device *isp = to_isp_device(res);
964
965 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
966 ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
967}
968
969void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
970{
971 /*
972 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
973 * condition, the module was paused and now we have a buffer queued
974 * on the output again. Restart the pipeline if running in continuous
975 * mode.
976 */
977 if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
978 res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
979 resizer_enable_oneshot(res);
980 isp_video_dmaqueue_flags_clr(&res->video_out);
981 }
982}
983
984static void resizer_isr_buffer(struct isp_res_device *res)
985{
986 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
987 struct isp_buffer *buffer;
988 int restart = 0;
989
990 if (res->state == ISP_PIPELINE_STREAM_STOPPED)
991 return;
992
993 /* Complete the output buffer and, if reading from memory, the input
994 * buffer.
995 */
996 buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
997 if (buffer != NULL) {
998 resizer_set_outaddr(res, buffer->isp_addr);
999 restart = 1;
1000 }
1001
1002 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1003
1004 if (res->input == RESIZER_INPUT_MEMORY) {
1005 buffer = omap3isp_video_buffer_next(&res->video_in, 0);
1006 if (buffer != NULL)
1007 resizer_set_inaddr(res, buffer->isp_addr);
1008 pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1009 }
1010
1011 if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
1012 if (isp_pipeline_ready(pipe))
1013 omap3isp_pipeline_set_stream(pipe,
1014 ISP_PIPELINE_STREAM_SINGLESHOT);
1015 } else {
1016 /* If an underrun occurs, the video queue operation handler will
1017 * restart the resizer. Otherwise restart it immediately.
1018 */
1019 if (restart)
1020 resizer_enable_oneshot(res);
1021 }
1022
1023 res->error = 0;
1024}
1025
1026/*
1027 * omap3isp_resizer_isr - ISP resizer interrupt handler
1028 *
1029 * Manage the resizer video buffers and configure shadowed and busy-locked
1030 * registers.
1031 */
1032void omap3isp_resizer_isr(struct isp_res_device *res)
1033{
1034 struct v4l2_mbus_framefmt *informat, *outformat;
1035
1036 if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
1037 return;
1038
1039 if (res->applycrop) {
1040 outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1041 V4L2_SUBDEV_FORMAT_ACTIVE);
1042 informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
1043 V4L2_SUBDEV_FORMAT_ACTIVE);
1044 resizer_set_crop_params(res, informat, outformat);
1045 res->applycrop = 0;
1046 }
1047
1048 resizer_isr_buffer(res);
1049}
1050
1051/* -----------------------------------------------------------------------------
1052 * ISP video operations
1053 */
1054
1055static int resizer_video_queue(struct isp_video *video,
1056 struct isp_buffer *buffer)
1057{
1058 struct isp_res_device *res = &video->isp->isp_res;
1059
1060 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1061 resizer_set_inaddr(res, buffer->isp_addr);
1062
1063 /*
1064 * We now have a buffer queued on the output. Despite what the
1065 * TRM says, the resizer can't be restarted immediately.
1066 * Enabling it in one shot mode in the middle of a frame (or at
1067 * least asynchronously to the frame) results in the output
1068 * being shifted randomly left/right and up/down, as if the
1069 * hardware didn't synchronize itself to the beginning of the
1070 * frame correctly.
1071 *
1072 * Restart the resizer on the next sync interrupt if running in
1073 * continuous mode or when starting the stream.
1074 */
1075 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1076 resizer_set_outaddr(res, buffer->isp_addr);
1077
1078 return 0;
1079}
1080
1081static const struct isp_video_operations resizer_video_ops = {
1082 .queue = resizer_video_queue,
1083};
1084
1085/* -----------------------------------------------------------------------------
1086 * V4L2 subdev operations
1087 */
1088
1089/*
1090 * resizer_set_stream - Enable/Disable streaming on resizer subdev
1091 * @sd: ISP resizer V4L2 subdev
1092 * @enable: 1 == Enable, 0 == Disable
1093 *
1094 * The resizer hardware can't be enabled without a memory buffer to write to.
1095 * As the s_stream operation is called in response to a STREAMON call without
1096 * any buffer queued yet, just update the state field and return immediately.
1097 * The resizer will be enabled in resizer_video_queue().
1098 */
1099static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1100{
1101 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1102 struct isp_video *video_out = &res->video_out;
1103 struct isp_device *isp = to_isp_device(res);
1104 struct device *dev = to_device(res);
1105
1106 if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
1107 if (enable == ISP_PIPELINE_STREAM_STOPPED)
1108 return 0;
1109
1110 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1111 resizer_configure(res);
1112 res->error = 0;
1113 resizer_print_status(res);
1114 }
1115
1116 switch (enable) {
1117 case ISP_PIPELINE_STREAM_CONTINUOUS:
1118 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1119 if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1120 resizer_enable_oneshot(res);
1121 isp_video_dmaqueue_flags_clr(video_out);
1122 }
1123 break;
1124
1125 case ISP_PIPELINE_STREAM_SINGLESHOT:
1126 if (res->input == RESIZER_INPUT_MEMORY)
1127 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
1128 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1129
1130 resizer_enable_oneshot(res);
1131 break;
1132
1133 case ISP_PIPELINE_STREAM_STOPPED:
1134 if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1135 &res->stopping))
1136 dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
1137 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
1138 OMAP3_ISP_SBL_RESIZER_WRITE);
1139 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1140 isp_video_dmaqueue_flags_clr(video_out);
1141 break;
1142 }
1143
1144 res->state = enable;
1145 return 0;
1146}
1147
1148/*
1149 * resizer_g_crop - handle get crop subdev operation
1150 * @sd : pointer to v4l2 subdev structure
1151 * @pad : subdev pad
1152 * @crop : pointer to crop structure
1153 * @which : active or try format
1154 * return zero
1155 */
1156static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1157 struct v4l2_subdev_crop *crop)
1158{
1159 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1160 struct v4l2_mbus_framefmt *format;
1161 struct resizer_ratio ratio;
1162
1163 /* Only sink pad has crop capability */
1164 if (crop->pad != RESZ_PAD_SINK)
1165 return -EINVAL;
1166
1167 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
1168 crop->rect = *__resizer_get_crop(res, fh, crop->which);
1169 resizer_calc_ratios(res, &crop->rect, format, &ratio);
1170
1171 return 0;
1172}
1173
1174/*
1175 * resizer_try_crop - mangles crop parameters.
1176 */
1177static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1178 const struct v4l2_mbus_framefmt *source,
1179 struct v4l2_rect *crop)
1180{
1181 const unsigned int spv = DEFAULT_PHASE;
1182 const unsigned int sph = DEFAULT_PHASE;
1183
1184 /* Crop rectangle is constrained to the output size so that zoom ratio
1185 * cannot exceed +/-4.0.
1186 */
1187 unsigned int min_width =
1188 ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1189 unsigned int min_height =
1190 ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1191 unsigned int max_width =
1192 ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1193 unsigned int max_height =
1194 ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1195
1196 crop->width = clamp_t(u32, crop->width, min_width, max_width);
1197 crop->height = clamp_t(u32, crop->height, min_height, max_height);
1198
1199 /* Crop can not go beyond of the input rectangle */
1200 crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1201 crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1202 sink->width - crop->left);
1203 crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1204 crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1205 sink->height - crop->top);
1206}
1207
1208/*
1209 * resizer_s_crop - handle set crop subdev operation
1210 * @sd : pointer to v4l2 subdev structure
1211 * @pad : subdev pad
1212 * @crop : pointer to crop structure
1213 * @which : active or try format
1214 * return -EINVAL or zero when succeed
1215 */
1216static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1217 struct v4l2_subdev_crop *crop)
1218{
1219 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1220 struct isp_device *isp = to_isp_device(res);
1221 struct v4l2_mbus_framefmt *format_sink, *format_source;
1222 struct resizer_ratio ratio;
1223
1224 /* Only sink pad has crop capability */
1225 if (crop->pad != RESZ_PAD_SINK)
1226 return -EINVAL;
1227
1228 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1229 crop->which);
1230 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1231 crop->which);
1232
1233 dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1234 crop->rect.left, crop->rect.top, crop->rect.width,
1235 crop->rect.height, crop->which);
1236
1237 dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1238 format_sink->width, format_sink->height,
1239 format_source->width, format_source->height);
1240
1241 resizer_try_crop(format_sink, format_source, &crop->rect);
1242 *__resizer_get_crop(res, fh, crop->which) = crop->rect;
1243 resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
1244
1245 if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
1246 return 0;
1247
1248 res->ratio = ratio;
1249 res->crop.active = crop->rect;
1250
1251 /*
1252 * s_crop can be called while streaming is on. In this case
1253 * the crop values will be set in the next IRQ.
1254 */
1255 if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1256 res->applycrop = 1;
1257
1258 return 0;
1259}
1260
1261/* resizer pixel formats */
1262static const unsigned int resizer_formats[] = {
1263 V4L2_MBUS_FMT_UYVY8_1X16,
1264 V4L2_MBUS_FMT_YUYV8_1X16,
1265};
1266
1267static unsigned int resizer_max_in_width(struct isp_res_device *res)
1268{
1269 struct isp_device *isp = to_isp_device(res);
1270
1271 if (res->input == RESIZER_INPUT_MEMORY) {
1272 return MAX_IN_WIDTH_MEMORY_MODE;
1273 } else {
1274 if (isp->revision == ISP_REVISION_1_0)
1275 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1276 else
1277 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1278 }
1279}
1280
1281/*
1282 * resizer_try_format - Handle try format by pad subdev method
1283 * @res : ISP resizer device
1284 * @fh : V4L2 subdev file handle
1285 * @pad : pad num
1286 * @fmt : pointer to v4l2 format structure
1287 * @which : wanted subdev format
1288 */
1289static void resizer_try_format(struct isp_res_device *res,
1290 struct v4l2_subdev_fh *fh, unsigned int pad,
1291 struct v4l2_mbus_framefmt *fmt,
1292 enum v4l2_subdev_format_whence which)
1293{
1294 struct v4l2_mbus_framefmt *format;
1295 struct resizer_ratio ratio;
1296 struct v4l2_rect crop;
1297
1298 switch (pad) {
1299 case RESZ_PAD_SINK:
1300 if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1301 fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1302 fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1303
1304 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1305 resizer_max_in_width(res));
1306 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1307 MAX_IN_HEIGHT);
1308 break;
1309
1310 case RESZ_PAD_SOURCE:
1311 format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1312 fmt->code = format->code;
1313
1314 crop = *__resizer_get_crop(res, fh, which);
1315 resizer_calc_ratios(res, &crop, fmt, &ratio);
1316 break;
1317 }
1318
1319 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1320 fmt->field = V4L2_FIELD_NONE;
1321}
1322
1323/*
1324 * resizer_enum_mbus_code - Handle pixel format enumeration
1325 * @sd : pointer to v4l2 subdev structure
1326 * @fh : V4L2 subdev file handle
1327 * @code : pointer to v4l2_subdev_mbus_code_enum structure
1328 * return -EINVAL or zero on success
1329 */
1330static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1331 struct v4l2_subdev_fh *fh,
1332 struct v4l2_subdev_mbus_code_enum *code)
1333{
1334 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1335 struct v4l2_mbus_framefmt *format;
1336
1337 if (code->pad == RESZ_PAD_SINK) {
1338 if (code->index >= ARRAY_SIZE(resizer_formats))
1339 return -EINVAL;
1340
1341 code->code = resizer_formats[code->index];
1342 } else {
1343 if (code->index != 0)
1344 return -EINVAL;
1345
1346 format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1347 V4L2_SUBDEV_FORMAT_TRY);
1348 code->code = format->code;
1349 }
1350
1351 return 0;
1352}
1353
1354static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1355 struct v4l2_subdev_fh *fh,
1356 struct v4l2_subdev_frame_size_enum *fse)
1357{
1358 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1359 struct v4l2_mbus_framefmt format;
1360
1361 if (fse->index != 0)
1362 return -EINVAL;
1363
1364 format.code = fse->code;
1365 format.width = 1;
1366 format.height = 1;
1367 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1368 fse->min_width = format.width;
1369 fse->min_height = format.height;
1370
1371 if (format.code != fse->code)
1372 return -EINVAL;
1373
1374 format.code = fse->code;
1375 format.width = -1;
1376 format.height = -1;
1377 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1378 fse->max_width = format.width;
1379 fse->max_height = format.height;
1380
1381 return 0;
1382}
1383
1384/*
1385 * resizer_get_format - Handle get format by pads subdev method
1386 * @sd : pointer to v4l2 subdev structure
1387 * @fh : V4L2 subdev file handle
1388 * @fmt : pointer to v4l2 subdev format structure
1389 * return -EINVAL or zero on sucess
1390 */
1391static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1392 struct v4l2_subdev_format *fmt)
1393{
1394 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1395 struct v4l2_mbus_framefmt *format;
1396
1397 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1398 if (format == NULL)
1399 return -EINVAL;
1400
1401 fmt->format = *format;
1402 return 0;
1403}
1404
1405/*
1406 * resizer_set_format - Handle set format by pads subdev method
1407 * @sd : pointer to v4l2 subdev structure
1408 * @fh : V4L2 subdev file handle
1409 * @fmt : pointer to v4l2 subdev format structure
1410 * return -EINVAL or zero on success
1411 */
1412static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1413 struct v4l2_subdev_format *fmt)
1414{
1415 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1416 struct v4l2_mbus_framefmt *format;
1417 struct v4l2_rect *crop;
1418
1419 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1420 if (format == NULL)
1421 return -EINVAL;
1422
1423 resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1424 *format = fmt->format;
1425
1426 if (fmt->pad == RESZ_PAD_SINK) {
1427 /* reset crop rectangle */
1428 crop = __resizer_get_crop(res, fh, fmt->which);
1429 crop->left = 0;
1430 crop->top = 0;
1431 crop->width = fmt->format.width;
1432 crop->height = fmt->format.height;
1433
1434 /* Propagate the format from sink to source */
1435 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1436 fmt->which);
1437 *format = fmt->format;
1438 resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1439 fmt->which);
1440 }
1441
1442 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1443 /* Compute and store the active crop rectangle and resizer
1444 * ratios. format already points to the source pad active
1445 * format.
1446 */
1447 res->crop.active = res->crop.request;
1448 resizer_calc_ratios(res, &res->crop.active, format,
1449 &res->ratio);
1450 }
1451
1452 return 0;
1453}
1454
1455/*
1456 * resizer_init_formats - Initialize formats on all pads
1457 * @sd: ISP resizer V4L2 subdevice
1458 * @fh: V4L2 subdev file handle
1459 *
1460 * Initialize all pad formats with default values. If fh is not NULL, try
1461 * formats are initialized on the file handle. Otherwise active formats are
1462 * initialized on the device.
1463 */
1464static int resizer_init_formats(struct v4l2_subdev *sd,
1465 struct v4l2_subdev_fh *fh)
1466{
1467 struct v4l2_subdev_format format;
1468
1469 memset(&format, 0, sizeof(format));
1470 format.pad = RESZ_PAD_SINK;
1471 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1472 format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1473 format.format.width = 4096;
1474 format.format.height = 4096;
1475 resizer_set_format(sd, fh, &format);
1476
1477 return 0;
1478}
1479
1480/* subdev video operations */
1481static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1482 .s_stream = resizer_set_stream,
1483};
1484
1485/* subdev pad operations */
1486static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1487 .enum_mbus_code = resizer_enum_mbus_code,
1488 .enum_frame_size = resizer_enum_frame_size,
1489 .get_fmt = resizer_get_format,
1490 .set_fmt = resizer_set_format,
1491 .get_crop = resizer_g_crop,
1492 .set_crop = resizer_s_crop,
1493};
1494
1495/* subdev operations */
1496static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1497 .video = &resizer_v4l2_video_ops,
1498 .pad = &resizer_v4l2_pad_ops,
1499};
1500
1501/* subdev internal operations */
1502static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1503 .open = resizer_init_formats,
1504};
1505
1506/* -----------------------------------------------------------------------------
1507 * Media entity operations
1508 */
1509
1510/*
1511 * resizer_link_setup - Setup resizer connections.
1512 * @entity : Pointer to media entity structure
1513 * @local : Pointer to local pad array
1514 * @remote : Pointer to remote pad array
1515 * @flags : Link flags
1516 * return -EINVAL or zero on success
1517 */
1518static int resizer_link_setup(struct media_entity *entity,
1519 const struct media_pad *local,
1520 const struct media_pad *remote, u32 flags)
1521{
1522 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1523 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1524
1525 switch (local->index | media_entity_type(remote->entity)) {
1526 case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1527 /* read from memory */
1528 if (flags & MEDIA_LNK_FL_ENABLED) {
1529 if (res->input == RESIZER_INPUT_VP)
1530 return -EBUSY;
1531 res->input = RESIZER_INPUT_MEMORY;
1532 } else {
1533 if (res->input == RESIZER_INPUT_MEMORY)
1534 res->input = RESIZER_INPUT_NONE;
1535 }
1536 break;
1537
1538 case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1539 /* read from ccdc or previewer */
1540 if (flags & MEDIA_LNK_FL_ENABLED) {
1541 if (res->input == RESIZER_INPUT_MEMORY)
1542 return -EBUSY;
1543 res->input = RESIZER_INPUT_VP;
1544 } else {
1545 if (res->input == RESIZER_INPUT_VP)
1546 res->input = RESIZER_INPUT_NONE;
1547 }
1548 break;
1549
1550 case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1551 /* resizer always write to memory */
1552 break;
1553
1554 default:
1555 return -EINVAL;
1556 }
1557
1558 return 0;
1559}
1560
1561/* media operations */
1562static const struct media_entity_operations resizer_media_ops = {
1563 .link_setup = resizer_link_setup,
1564};
1565
1566/*
1567 * resizer_init_entities - Initialize resizer subdev and media entity.
1568 * @res : Pointer to resizer device structure
1569 * return -ENOMEM or zero on success
1570 */
1571static int resizer_init_entities(struct isp_res_device *res)
1572{
1573 struct v4l2_subdev *sd = &res->subdev;
1574 struct media_pad *pads = res->pads;
1575 struct media_entity *me = &sd->entity;
1576 int ret;
1577
1578 res->input = RESIZER_INPUT_NONE;
1579
1580 v4l2_subdev_init(sd, &resizer_v4l2_ops);
1581 sd->internal_ops = &resizer_v4l2_internal_ops;
1582 strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1583 sd->grp_id = 1 << 16; /* group ID for isp subdevs */
1584 v4l2_set_subdevdata(sd, res);
1585 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1586
1587 pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1588 pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1589
1590 me->ops = &resizer_media_ops;
1591 ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1592 if (ret < 0)
1593 return ret;
1594
1595 resizer_init_formats(sd, NULL);
1596
1597 res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1598 res->video_in.ops = &resizer_video_ops;
1599 res->video_in.isp = to_isp_device(res);
1600 res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1601 res->video_in.bpl_alignment = 32;
1602 res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1603 res->video_out.ops = &resizer_video_ops;
1604 res->video_out.isp = to_isp_device(res);
1605 res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1606 res->video_out.bpl_alignment = 32;
1607
1608 ret = omap3isp_video_init(&res->video_in, "resizer");
1609 if (ret < 0)
1610 return ret;
1611
1612 ret = omap3isp_video_init(&res->video_out, "resizer");
1613 if (ret < 0)
1614 return ret;
1615
1616 /* Connect the video nodes to the resizer subdev. */
1617 ret = media_entity_create_link(&res->video_in.video.entity, 0,
1618 &res->subdev.entity, RESZ_PAD_SINK, 0);
1619 if (ret < 0)
1620 return ret;
1621
1622 ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1623 &res->video_out.video.entity, 0, 0);
1624 if (ret < 0)
1625 return ret;
1626
1627 return 0;
1628}
1629
1630void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1631{
1632 media_entity_cleanup(&res->subdev.entity);
1633
1634 v4l2_device_unregister_subdev(&res->subdev);
1635 omap3isp_video_unregister(&res->video_in);
1636 omap3isp_video_unregister(&res->video_out);
1637}
1638
1639int omap3isp_resizer_register_entities(struct isp_res_device *res,
1640 struct v4l2_device *vdev)
1641{
1642 int ret;
1643
1644 /* Register the subdev and video nodes. */
1645 ret = v4l2_device_register_subdev(vdev, &res->subdev);
1646 if (ret < 0)
1647 goto error;
1648
1649 ret = omap3isp_video_register(&res->video_in, vdev);
1650 if (ret < 0)
1651 goto error;
1652
1653 ret = omap3isp_video_register(&res->video_out, vdev);
1654 if (ret < 0)
1655 goto error;
1656
1657 return 0;
1658
1659error:
1660 omap3isp_resizer_unregister_entities(res);
1661 return ret;
1662}
1663
1664/* -----------------------------------------------------------------------------
1665 * ISP resizer initialization and cleanup
1666 */
1667
1668void omap3isp_resizer_cleanup(struct isp_device *isp)
1669{
1670}
1671
1672/*
1673 * isp_resizer_init - Resizer initialization.
1674 * @isp : Pointer to ISP device
1675 * return -ENOMEM or zero on success
1676 */
1677int omap3isp_resizer_init(struct isp_device *isp)
1678{
1679 struct isp_res_device *res = &isp->isp_res;
1680 int ret;
1681
1682 init_waitqueue_head(&res->wait);
1683 atomic_set(&res->stopping, 0);
1684 ret = resizer_init_entities(res);
1685 if (ret < 0)
1686 goto out;
1687
1688out:
1689 if (ret)
1690 omap3isp_resizer_cleanup(isp);
1691
1692 return ret;
1693}
diff --git a/drivers/media/video/omap3isp/ispresizer.h b/drivers/media/video/omap3isp/ispresizer.h
new file mode 100644
index 000000000000..76abc2e42126
--- /dev/null
+++ b/drivers/media/video/omap3isp/ispresizer.h
@@ -0,0 +1,147 @@
1/*
2 * ispresizer.h
3 *
4 * TI OMAP3 ISP - Resizer module
5 *
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
27#ifndef OMAP3_ISP_RESIZER_H
28#define OMAP3_ISP_RESIZER_H
29
30#include <linux/types.h>
31
32/*
33 * Constants for filter coefficents count
34 */
35#define COEFF_CNT 32
36
37/*
38 * struct isprsz_coef - Structure for resizer filter coeffcients.
39 * @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap
40 * mode (.5x-4x)
41 * @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap
42 * mode (.5x-4x)
43 * @h_filter_coef_7tap: Horizontal filter coefficients for 4-phase/7-tap
44 * mode (.25x-.5x)
45 * @v_filter_coef_7tap: Vertical filter coefficients for 4-phase/7-tap
46 * mode (.25x-.5x)
47 */
48struct isprsz_coef {
49 u16 h_filter_coef_4tap[32];
50 u16 v_filter_coef_4tap[32];
51 /* Every 8th value is a dummy value in the following arrays: */
52 u16 h_filter_coef_7tap[32];
53 u16 v_filter_coef_7tap[32];
54};
55
56/* Chrominance horizontal algorithm */
57enum resizer_chroma_algo {
58 RSZ_THE_SAME = 0, /* Chrominance the same as Luminance */
59 RSZ_BILINEAR = 1, /* Chrominance uses bilinear interpolation */
60};
61
62/* Resizer input type select */
63enum resizer_colors_type {
64 RSZ_YUV422 = 0, /* YUV422 color is interleaved */
65 RSZ_COLOR8 = 1, /* Color separate data on 8 bits */
66};
67
68/*
69 * Structure for horizontal and vertical resizing value
70 */
71struct resizer_ratio {
72 u32 horz;
73 u32 vert;
74};
75
76/*
77 * Structure for luminance enhancer parameters.
78 */
79struct resizer_luma_yenh {
80 u8 algo; /* algorithm select. */
81 u8 gain; /* maximum gain. */
82 u8 slope; /* slope. */
83 u8 core; /* core offset. */
84};
85
86enum resizer_input_entity {
87 RESIZER_INPUT_NONE,
88 RESIZER_INPUT_VP, /* input video port - prev or ccdc */
89 RESIZER_INPUT_MEMORY,
90};
91
92/* Sink and source resizer pads */
93#define RESZ_PAD_SINK 0
94#define RESZ_PAD_SOURCE 1
95#define RESZ_PADS_NUM 2
96
97/*
98 * struct isp_res_device - OMAP3 ISP resizer module
99 * @crop.request: Crop rectangle requested by the user
100 * @crop.active: Active crop rectangle (based on hardware requirements)
101 */
102struct isp_res_device {
103 struct v4l2_subdev subdev;
104 struct media_pad pads[RESZ_PADS_NUM];
105 struct v4l2_mbus_framefmt formats[RESZ_PADS_NUM];
106
107 enum resizer_input_entity input;
108 struct isp_video video_in;
109 struct isp_video video_out;
110 unsigned int error;
111
112 u32 addr_base; /* stored source buffer address in memory mode */
113 u32 crop_offset; /* additional offset for crop in memory mode */
114 struct resizer_ratio ratio;
115 int pm_state;
116 unsigned int applycrop:1;
117 enum isp_pipeline_stream_state state;
118 wait_queue_head_t wait;
119 atomic_t stopping;
120
121 struct {
122 struct v4l2_rect request;
123 struct v4l2_rect active;
124 } crop;
125};
126
127struct isp_device;
128
129int omap3isp_resizer_init(struct isp_device *isp);
130void omap3isp_resizer_cleanup(struct isp_device *isp);
131
132int omap3isp_resizer_register_entities(struct isp_res_device *res,
133 struct v4l2_device *vdev);
134void omap3isp_resizer_unregister_entities(struct isp_res_device *res);
135void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res);
136void omap3isp_resizer_isr(struct isp_res_device *isp_res);
137
138void omap3isp_resizer_max_rate(struct isp_res_device *res,
139 unsigned int *max_rate);
140
141void omap3isp_resizer_suspend(struct isp_res_device *isp_res);
142
143void omap3isp_resizer_resume(struct isp_res_device *isp_res);
144
145int omap3isp_resizer_busy(struct isp_res_device *isp_res);
146
147#endif /* OMAP3_ISP_RESIZER_H */
diff --git a/drivers/media/video/omap3isp/luma_enhance_table.h b/drivers/media/video/omap3isp/luma_enhance_table.h
new file mode 100644
index 000000000000..098b45e2280f
--- /dev/null
+++ b/drivers/media/video/omap3isp/luma_enhance_table.h
@@ -0,0 +1,42 @@
1/*
2 * luma_enhance_table.h
3 *
4 * TI OMAP3 ISP - Luminance enhancement table
5 *
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
271047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
281047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
291047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
301047552, 1047552, 1047552, 1047552, 1048575, 1047551, 1046527, 1045503,
311044479, 1043455, 1042431, 1041407, 1040383, 1039359, 1038335, 1037311,
321036287, 1035263, 1034239, 1033215, 1032191, 1031167, 1030143, 1028096,
331028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096,
341028096, 1028100, 1032196, 1036292, 1040388, 1044484, 0, 0,
35 0, 5, 5125, 10245, 15365, 20485, 25605, 30720,
36 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720,
37 30720, 30720, 31743, 30719, 29695, 28671, 27647, 26623,
38 25599, 24575, 23551, 22527, 21503, 20479, 19455, 18431,
39 17407, 16383, 15359, 14335, 13311, 12287, 11263, 10239,
40 9215, 8191, 7167, 6143, 5119, 4095, 3071, 1024,
41 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
42 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024
diff --git a/drivers/media/video/omap3isp/noise_filter_table.h b/drivers/media/video/omap3isp/noise_filter_table.h
new file mode 100644
index 000000000000..d50451a4a242
--- /dev/null
+++ b/drivers/media/video/omap3isp/noise_filter_table.h
@@ -0,0 +1,30 @@
1/*
2 * noise_filter_table.h
3 *
4 * TI OMAP3 ISP - Noise filter table
5 *
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc.
8 *
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301 USA
25 */
26
2716, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2816, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2931, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
3031, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31