Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] omap3isp: CCDC, preview engine and resizer

The OMAP3 ISP CCDC, preview engine and resizer entities perform image
processing and scaling.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: David Cohen <dacohen@gmail.com>
Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@gmail.com>
Signed-off-by: Tuukka Toivonen <tuukkat76@gmail.com>
Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
Signed-off-by: Antti Koskipaa <akoskipa@gmail.com>
Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com>
Signed-off-by: RaniSuneela <r-m@ti.com>
Signed-off-by: Atanas Filipov <afilipov@mm-sol.com>
Signed-off-by: Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
Signed-off-by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Signed-off-by: Nayden Kanchev <nkanchev@mm-sol.com>
Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: Dominic Curran <dcurran@ti.com>
Signed-off-by: Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
Signed-off-by: Pallavi Kulkarni <p-kulkarni@ti.com>
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Laurent Pinchart and committed by
Mauro Carvalho Chehab
de1135d4 121e9f1c

+6877
+61
drivers/media/video/omap3isp/cfa_coef_table.h
··· 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 + 26 + 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, 27 + 248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, 28 + 247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, 29 + 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, 30 + 248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, 31 + 247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, 32 + 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, 33 + 248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, 34 + 247, 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, 53 + 244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, 54 + 248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, 55 + 250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248, 56 + 244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, 57 + 248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, 58 + 250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248, 59 + 244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, 60 + 248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, 61 + 250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248
+90
drivers/media/video/omap3isp/gamma_table.h
··· 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, 34 + 105, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 117, 35 + 117, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 36 + 126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 37 + 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 38 + 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, 39 + 150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 40 + 156, 156, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 160, 161, 161, 162, 41 + 162, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 167, 167, 168, 42 + 168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 173, 173, 174, 43 + 174, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, 44 + 179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, 45 + 183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, 46 + 187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 47 + 191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, 48 + 195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, 49 + 199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 203, 203, 50 + 203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, 51 + 207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210, 52 + 210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 53 + 211, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 54 + 213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 55 + 216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, 56 + 219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, 57 + 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 223, 58 + 223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225, 59 + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 60 + 226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228, 61 + 228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, 62 + 230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232, 63 + 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 64 + 233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235, 65 + 235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 66 + 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 67 + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 68 + 238, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, 69 + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 70 + 240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242, 71 + 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 72 + 242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 73 + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 74 + 244, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 75 + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 76 + 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 248, 77 + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 78 + 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250, 79 + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 80 + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 81 + 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 82 + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 83 + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 84 + 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 85 + 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 86 + 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 87 + 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 88 + 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 89 + 253, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90 + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+2268
drivers/media/video/omap3isp/ispccdc.c
··· 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 + 40 + static 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 + 44 + static 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 + 66 + static 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 + */ 113 + int 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 + */ 132 + static 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 + */ 196 + static 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 + */ 206 + static 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 + 230 + static 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 + */ 259 + static 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 + 294 + static 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 + */ 308 + static 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 + */ 333 + static 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 + 350 + static 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 + 366 + static 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 + 382 + static 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 + */ 400 + static 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 + 478 + done: 479 + if (ret < 0) 480 + ccdc_lsc_free_request(ccdc, req); 481 + 482 + return ret; 483 + } 484 + 485 + static 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 + 498 + static 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 + 522 + done: 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 + */ 540 + static 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 + */ 565 + static 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 + */ 587 + static 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 + */ 604 + static 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 + */ 617 + static 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 + */ 651 + static 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 + */ 667 + static 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 + 754 + static 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 + */ 781 + void 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 + */ 801 + static 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 + */ 847 + static 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 + */ 870 + static 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 + */ 913 + static 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 + */ 927 + void 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 + */ 955 + static 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 */ 1035 + static 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 + 1053 + static 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 + 1071 + static 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 + 1089 + static 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 + 1107 + static 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 + 1233 + unlock: 1234 + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); 1235 + 1236 + ccdc_apply_controls(ccdc); 1237 + } 1238 + 1239 + static 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 + 1247 + static 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 + 1280 + static 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 + */ 1298 + static 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 + */ 1318 + static 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 + */ 1344 + static 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 + 1380 + static 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 + */ 1396 + static 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 + 1442 + done: 1443 + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); 1444 + } 1445 + 1446 + static 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 + 1490 + done: 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 + */ 1501 + static 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 + */ 1527 + static 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 + 1580 + done: 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 + */ 1589 + int 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 + 1612 + static 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 + 1630 + static 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 + */ 1646 + static 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 + 1665 + static 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 + 1674 + static 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 + */ 1692 + static 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 + 1749 + static 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 + */ 1766 + static void 1767 + ccdc_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 + */ 1841 + static 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 + 1875 + static 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 + */ 1914 + static 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 + */ 1937 + static 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 + */ 1977 + static 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 */ 1993 + static 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 */ 2000 + static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = { 2001 + .s_stream = ccdc_set_stream, 2002 + }; 2003 + 2004 + /* V4L2 subdev pad operations */ 2005 + static 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 */ 2013 + static 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 */ 2020 + static 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 + */ 2037 + static 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 */ 2117 + static 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 + */ 2127 + static 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 + 2174 + void 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 + 2182 + int 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 + 2198 + error: 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 + */ 2215 + int 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 + */ 2255 + void 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 + }
+219
drivers/media/video/omap3isp/ispccdc.h
··· 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 + 35 + enum 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 + */ 66 + struct 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 + */ 87 + struct ispccdc_vp { 88 + unsigned int pixelclk; 89 + }; 90 + 91 + enum 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 + 98 + struct 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 + */ 115 + struct 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 + */ 173 + struct 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 + 205 + struct isp_device; 206 + 207 + int omap3isp_ccdc_init(struct isp_device *isp); 208 + void omap3isp_ccdc_cleanup(struct isp_device *isp); 209 + int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, 210 + struct v4l2_device *vdev); 211 + void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc); 212 + 213 + int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc); 214 + int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events); 215 + void omap3isp_ccdc_restore_context(struct isp_device *isp); 216 + void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, 217 + unsigned int *max_rate); 218 + 219 + #endif /* OMAP3_ISP_CCDC_H */
+2113
drivers/media/video/omap3isp/isppreview.c
··· 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 */ 38 + static 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*/ 48 + static 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 + */ 92 + static u32 cfa_coef_table[] = { 93 + #include "cfa_coef_table.h" 94 + }; 95 + 96 + /* 97 + * Default Gamma Correction Table - All components 98 + */ 99 + static u32 gamma_table[] = { 100 + #include "gamma_table.h" 101 + }; 102 + 103 + /* 104 + * Noise Filter Threshold table 105 + */ 106 + static u32 noise_filter_table[] = { 107 + #include "noise_filter_table.h" 108 + }; 109 + 110 + /* 111 + * Luminance Enhancement Table 112 + */ 113 + static 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 + */ 121 + static void 122 + preview_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 + */ 142 + static void 143 + preview_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 + */ 162 + static void 163 + preview_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 + */ 179 + static void 180 + preview_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 + */ 195 + static void 196 + preview_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 + */ 213 + static void 214 + preview_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 + */ 230 + static void 231 + preview_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 + */ 250 + static void 251 + preview_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 + */ 274 + static void 275 + preview_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 + */ 303 + static void 304 + preview_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 + */ 333 + static void 334 + preview_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 + */ 354 + static void 355 + preview_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 + */ 371 + static void 372 + preview_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 + */ 388 + static void 389 + preview_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 + */ 405 + static void 406 + preview_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 + */ 423 + static void 424 + preview_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 + */ 440 + static void 441 + preview_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 + */ 457 + static void 458 + preview_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 + */ 477 + static void 478 + preview_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 + */ 517 + static void 518 + preview_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 + */ 534 + static void 535 + preview_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 + */ 573 + static void 574 + preview_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 + */ 607 + static void 608 + preview_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 + */ 624 + static void 625 + preview_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 + */ 639 + static void 640 + preview_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 + */ 654 + static void 655 + preview_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 + */ 668 + static void 669 + preview_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 */ 683 + struct 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 + 690 + static 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 + */ 760 + static 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 + */ 843 + static 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 + */ 898 + static 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 + */ 931 + static void 932 + preview_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 + */ 958 + static 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 + */ 983 + static 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 + */ 1045 + static void 1046 + preview_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 + */ 1060 + static 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 + */ 1073 + static 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 + */ 1088 + static 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 + 1095 + static 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 + */ 1148 + int 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 + */ 1159 + void 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 + 1172 + static 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 + */ 1223 + static 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 + */ 1278 + static 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 + 1295 + static 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 + 1349 + static 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 + 1365 + void 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 + 1380 + static 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 + */ 1432 + void 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 + 1446 + done: 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 + 1460 + static 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 + 1474 + static 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 + */ 1486 + static 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 + 1503 + static 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 + */ 1514 + static 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 + */ 1533 + static 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 + 1590 + static 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 */ 1601 + static 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 + 1608 + static 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 + */ 1620 + static 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 + */ 1724 + static 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 + 1748 + static 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 + */ 1785 + static 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 + */ 1806 + static 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 + */ 1840 + static 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 */ 1857 + static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = { 1858 + .ioctl = preview_ioctl, 1859 + }; 1860 + 1861 + /* subdev video operations */ 1862 + static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = { 1863 + .s_stream = preview_set_stream, 1864 + }; 1865 + 1866 + /* subdev pad operations */ 1867 + static 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 */ 1875 + static 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 */ 1882 + static 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 + */ 1898 + static 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 */ 1965 + static 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 + */ 1974 + static 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 + 2047 + void 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 + 2057 + int 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 + 2077 + error: 2078 + omap3isp_preview_unregister_entities(prev); 2079 + return ret; 2080 + } 2081 + 2082 + /* ----------------------------------------------------------------------------- 2083 + * ISP previewer initialisation and cleanup 2084 + */ 2085 + 2086 + void 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 + */ 2095 + int 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 + 2108 + out: 2109 + if (ret) 2110 + omap3isp_preview_cleanup(isp); 2111 + 2112 + return ret; 2113 + }
+214
drivers/media/video/omap3isp/isppreview.h
··· 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 + 77 + enum 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 */ 87 + enum 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 + */ 113 + struct 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 + */ 142 + struct 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 + */ 176 + struct 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 + 198 + struct isp_device; 199 + 200 + int omap3isp_preview_init(struct isp_device *isp); 201 + void omap3isp_preview_cleanup(struct isp_device *isp); 202 + 203 + int omap3isp_preview_register_entities(struct isp_prev_device *prv, 204 + struct v4l2_device *vdev); 205 + void omap3isp_preview_unregister_entities(struct isp_prev_device *prv); 206 + 207 + void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev); 208 + void omap3isp_preview_isr(struct isp_prev_device *prev); 209 + 210 + int omap3isp_preview_busy(struct isp_prev_device *isp_prev); 211 + 212 + void omap3isp_preview_restore_context(struct isp_device *isp); 213 + 214 + #endif /* OMAP3_ISP_PREVIEW_H */
+1693
drivers/media/video/omap3isp/ispresizer.c
··· 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 + */ 76 + static 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 + */ 129 + static 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 + */ 145 + static 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 + */ 162 + static 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 + */ 193 + static 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 + */ 211 + static 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 + */ 238 + static 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 + */ 274 + static 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 + */ 300 + static 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 + */ 320 + static 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 + */ 364 + static 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 + */ 387 + static 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 + */ 409 + static 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 + */ 428 + static 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 + */ 453 + static 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 + */ 465 + static 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 + */ 484 + static 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 + */ 514 + void 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 + */ 556 + static 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 + */ 624 + int 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 + */ 636 + static 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 + */ 653 + static 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 + 672 + static 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 + */ 763 + static 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 + */ 880 + static 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 + 928 + static 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 + 961 + static 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 + 969 + void 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 + 984 + static 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 + */ 1032 + void 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 + 1055 + static 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 + 1081 + static 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 + */ 1099 + static 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 + */ 1156 + static 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 + */ 1177 + static 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 + */ 1216 + static 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 */ 1262 + static const unsigned int resizer_formats[] = { 1263 + V4L2_MBUS_FMT_UYVY8_1X16, 1264 + V4L2_MBUS_FMT_YUYV8_1X16, 1265 + }; 1266 + 1267 + static 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 + */ 1289 + static 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 + */ 1330 + static 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 + 1354 + static 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 + */ 1391 + static 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 + */ 1412 + static 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 + */ 1464 + static 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 */ 1481 + static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = { 1482 + .s_stream = resizer_set_stream, 1483 + }; 1484 + 1485 + /* subdev pad operations */ 1486 + static 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 */ 1496 + static 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 */ 1502 + static 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 + */ 1518 + static 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 */ 1562 + static 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 + */ 1571 + static 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 + 1630 + void 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 + 1639 + int 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 + 1659 + error: 1660 + omap3isp_resizer_unregister_entities(res); 1661 + return ret; 1662 + } 1663 + 1664 + /* ----------------------------------------------------------------------------- 1665 + * ISP resizer initialization and cleanup 1666 + */ 1667 + 1668 + void 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 + */ 1677 + int 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 + 1688 + out: 1689 + if (ret) 1690 + omap3isp_resizer_cleanup(isp); 1691 + 1692 + return ret; 1693 + }
+147
drivers/media/video/omap3isp/ispresizer.h
··· 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 + */ 48 + struct 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 */ 57 + enum 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 */ 63 + enum 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 + */ 71 + struct resizer_ratio { 72 + u32 horz; 73 + u32 vert; 74 + }; 75 + 76 + /* 77 + * Structure for luminance enhancer parameters. 78 + */ 79 + struct resizer_luma_yenh { 80 + u8 algo; /* algorithm select. */ 81 + u8 gain; /* maximum gain. */ 82 + u8 slope; /* slope. */ 83 + u8 core; /* core offset. */ 84 + }; 85 + 86 + enum 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 + */ 102 + struct 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 + 127 + struct isp_device; 128 + 129 + int omap3isp_resizer_init(struct isp_device *isp); 130 + void omap3isp_resizer_cleanup(struct isp_device *isp); 131 + 132 + int omap3isp_resizer_register_entities(struct isp_res_device *res, 133 + struct v4l2_device *vdev); 134 + void omap3isp_resizer_unregister_entities(struct isp_res_device *res); 135 + void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res); 136 + void omap3isp_resizer_isr(struct isp_res_device *isp_res); 137 + 138 + void omap3isp_resizer_max_rate(struct isp_res_device *res, 139 + unsigned int *max_rate); 140 + 141 + void omap3isp_resizer_suspend(struct isp_res_device *isp_res); 142 + 143 + void omap3isp_resizer_resume(struct isp_res_device *isp_res); 144 + 145 + int omap3isp_resizer_busy(struct isp_res_device *isp_res); 146 + 147 + #endif /* OMAP3_ISP_RESIZER_H */
+42
drivers/media/video/omap3isp/luma_enhance_table.h
··· 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 + 27 + 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 28 + 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 29 + 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 30 + 1047552, 1047552, 1047552, 1047552, 1048575, 1047551, 1046527, 1045503, 31 + 1044479, 1043455, 1042431, 1041407, 1040383, 1039359, 1038335, 1037311, 32 + 1036287, 1035263, 1034239, 1033215, 1032191, 1031167, 1030143, 1028096, 33 + 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 34 + 1028096, 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
+30
drivers/media/video/omap3isp/noise_filter_table.h
··· 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 + 27 + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 28 + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 29 + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 30 + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31