From 8bffe04905eeb80bf93bbc57c2cf2e3c0c281306 Mon Sep 17 00:00:00 2001 From: "dalong.zhang" Date: Sun, 9 Oct 2016 16:32:39 +0800 Subject: [PATCH] isp10: rockchip: v0.1.6 Change-Id: I1b702fb51d1baabd47f190fdafd79ecd22e18be0 Signed-off-by: dalong.zhang --- drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 2 + drivers/media/platform/rk-isp10/Kconfig | 11 + drivers/media/platform/rk-isp10/Makefile | 3 + drivers/media/platform/rk-isp10/cif_isp10.c | 6427 +++++++++++++++++ drivers/media/platform/rk-isp10/cif_isp10.h | 713 ++ .../platform/rk-isp10/cif_isp10_img_src.c | 175 + .../platform/rk-isp10/cif_isp10_img_src.h | 83 + .../platform/rk-isp10/cif_isp10_img_src_ops.h | 89 + .../rk-isp10/cif_isp10_img_src_v4l2-subdev.c | 470 ++ .../rk-isp10/cif_isp10_img_src_v4l2-subdev.h | 65 + .../media/platform/rk-isp10/cif_isp10_isp.c | 5190 +++++++++++++ .../media/platform/rk-isp10/cif_isp10_isp.h | 133 + .../platform/rk-isp10/cif_isp10_pltfrm.c | 1443 ++++ .../platform/rk-isp10/cif_isp10_pltfrm.h | 204 + .../media/platform/rk-isp10/cif_isp10_regs.h | 1203 +++ .../platform/rk-isp10/cif_isp10_rk3288.c | 616 ++ .../platform/rk-isp10/cif_isp10_rk3399.c | 630 ++ .../media/platform/rk-isp10/cif_isp10_v4l2.c | 1854 +++++ .../platform/rk-isp10/cif_isp10_version.h | 64 + .../linux/platform_data/rk_isp10_platform.h | 180 + .../rk_isp10_platform_camera_module.h | 126 + include/media/rk-isp10-config.h | 550 ++ include/media/rk-isp10-ioctl.h | 133 + include/media/v4l2-config_rockchip.h | 95 + include/media/v4l2-controls_rockchip.h | 32 + 26 files changed, 20492 insertions(+) create mode 100644 drivers/media/platform/rk-isp10/Kconfig create mode 100644 drivers/media/platform/rk-isp10/Makefile create mode 100644 drivers/media/platform/rk-isp10/cif_isp10.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10.h create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_img_src.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_img_src.h create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_img_src_ops.h create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.h create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_isp.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_isp.h create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_pltfrm.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_pltfrm.h create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_regs.h create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_rk3288.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_rk3399.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_v4l2.c create mode 100644 drivers/media/platform/rk-isp10/cif_isp10_version.h create mode 100644 include/linux/platform_data/rk_isp10_platform.h create mode 100644 include/linux/platform_data/rk_isp10_platform_camera_module.h create mode 100644 include/media/rk-isp10-config.h create mode 100644 include/media/rk-isp10-ioctl.h create mode 100644 include/media/v4l2-config_rockchip.h create mode 100644 include/media/v4l2-controls_rockchip.h diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 9f3f03bdc1bd..d648cd80e282 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -120,6 +120,7 @@ source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" +source "drivers/media/platform/rk-isp10/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index c52535ead136..5c90cf280486 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -57,3 +57,5 @@ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu/ ccflags-y += -I$(srctree)/drivers/media/i2c + +obj-$(CONFIG_VIDEO_RK_CIF_ISP10) += rk-isp10/ diff --git a/drivers/media/platform/rk-isp10/Kconfig b/drivers/media/platform/rk-isp10/Kconfig new file mode 100644 index 000000000000..bb2679b79677 --- /dev/null +++ b/drivers/media/platform/rk-isp10/Kconfig @@ -0,0 +1,11 @@ +config VIDEO_RK_CIF_ISP10 + tristate "Rockchip cif isp10 camera sensors" + depends on VIDEO_V4L2 && I2C + select VIDEOBUF_GEN + select VIDEOBUF_DMA_CONTIG + select VIDEOBUF_VMALLOC + default n + + ---help--- + Say Y here to enable selecting the + rockchip cif isp10 camera sensors diff --git a/drivers/media/platform/rk-isp10/Makefile b/drivers/media/platform/rk-isp10/Makefile new file mode 100644 index 000000000000..9caf7f94e771 --- /dev/null +++ b/drivers/media/platform/rk-isp10/Makefile @@ -0,0 +1,3 @@ + +obj-$(CONFIG_VIDEO_RK_CIF_ISP10) += video_cif_isp10.o +video_cif_isp10-objs += cif_isp10.o cif_isp10_img_src.o cif_isp10_img_src_v4l2-subdev.o cif_isp10_isp.o cif_isp10_pltfrm.o cif_isp10_rk3288.o cif_isp10_rk3399.o cif_isp10_v4l2.o \ No newline at end of file diff --git a/drivers/media/platform/rk-isp10/cif_isp10.c b/drivers/media/platform/rk-isp10/cif_isp10.c new file mode 100644 index 000000000000..3f1dd33a225d --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10.c @@ -0,0 +1,6427 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#include +#include +#include "cif_isp10_regs.h" +#include "cif_isp10.h" +#include +#include + +static int cif_isp10_mipi_isr( + unsigned int mis, + void *cntxt); +static int cif_isp10_isp_isr( + unsigned int mis, + void *cntxt); +static void init_output_formats(void); + +struct v4l2_fmtdesc output_formats[MAX_NB_FORMATS]; + +/* JPEG quantization tables for JPEG encoding */ +/* DC luma table according to ISO/IEC 10918-1 annex K */ +static const unsigned char dc_luma_table_annex_k[] = { + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b +}; + +/* DC chroma table according to ISO/IEC 10918-1 annex K */ +static const unsigned char dc_chroma_table_annex_k[] = { + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b +}; + +/* AC luma table according to ISO/IEC 10918-1 annex K */ +static const unsigned char ac_luma_table_annex_k[] = { + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +/* AC Chroma table according to ISO/IEC 10918-1 annex K */ +static const unsigned char ac_chroma_table_annex_k[] = { + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +/* Standard JPEG quantization tables */ +/* luma */ +/* According to JPEG spec: + * [ + * 16, 11, 10, 16, 24, 40, 51, 61, + * 12, 12, 14, 19, 26, 58, 60, 55, + * 14, 13, 16, 24, 40, 57, 69, 56, + * 14, 17, 22, 29, 51, 87, 80, 62, + * 18, 22, 37, 56, 68, 109, 103, 77, + * 24, 35, 55, 64, 81, 104, 113, 92, + * 49, 64, 78, 87, 103, 121, 120, 101, + * 72, 92, 95, 98, 112, 100, 103, 99 + * ] + */ + +/* CIF needs it in zigzag order */ +static const unsigned char yq_table_base_zigzag[] = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 +}; + +/* chroma */ +/* According to JPEG spec: + * [ + * 17, 18, 24, 47, 99, 99, 99, 99, + * 18, 21, 26, 66, 99, 99, 99, 99, + * 24, 26, 56, 99, 99, 99, 99, 99, + * 47, 66, 99, 99, 99, 99, 99, 99, + * 99, 99, 99, 99, 99, 99, 99, 99, + * 99, 99, 99, 99, 99, 99, 99, 99, + * 99, 99, 99, 99, 99, 99, 99, 99, + * 99, 99, 99, 99, 99, 99, 99, 99 + * ] + */ + +/* CIF needs it in zigzag order */ +static const unsigned char uvq_table_base_zigzag[] = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + +static struct cif_isp10_fmt cif_isp10_output_format[] = { +/* ************* YUV422 ************* */ +{ + .name = "YUV422-Interleaved", + .fourcc = V4L2_PIX_FMT_YUYV, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +{ + .name = "YUV422-Interleaved", + .fourcc = V4L2_PIX_FMT_YUYV, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +{ + .name = "YVU422-Interleaved", + .fourcc = V4L2_PIX_FMT_UYVY, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +{ + .name = "YUV422-Planar", + .fourcc = V4L2_PIX_FMT_YUV422P, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +{ + .name = "YUV422-Semi-Planar", + .fourcc = V4L2_PIX_FMT_NV16, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +/* ************* YUV420 ************* */ +{ + .name = "YUV420-Planar", + .fourcc = V4L2_PIX_FMT_YUV420, + .flags = 0, + .depth = 12, + .rotation = false, + .overlay = false, +}, +{ + .name = "YUV420-Planar", + .fourcc = V4L2_PIX_FMT_YUV420, + .flags = 0, + .depth = 12, + .rotation = false, + .overlay = false, +}, +{ + .name = "YVU420-Planar", + .fourcc = V4L2_PIX_FMT_YVU420, + .flags = 0, + .depth = 12, + .rotation = false, + .overlay = false, +}, +{ + .name = "YUV420-Semi-Planar", + .fourcc = V4L2_PIX_FMT_NV12, + .flags = 0, + .depth = 12, + .rotation = false, + .overlay = false, +}, +{ + .name = "YVU420-Semi-Planar", + .fourcc = V4L2_PIX_FMT_NV21, + .flags = 0, + .depth = 12, + .rotation = false, + .overlay = false, +}, +/* ************* YUV400 ************* */ +{ + .name = "YVU400-Grey-Planar", + .fourcc = V4L2_PIX_FMT_GREY, + .flags = 0, + .depth = 8, + .rotation = false, + .overlay = false, +}, +/* ************* YUV444 ************* */ +{ + .name = "YVU444-Planar", + .fourcc = V4L2_PIX_FMT_YUV444, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +{ + .name = "YVU444-Semi-Planar", + .fourcc = V4L2_PIX_FMT_NV24, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +/* ************* JPEG ************* */ +{ + .name = "JPEG", + .fourcc = V4L2_PIX_FMT_JPEG, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +/* ************ RGB565 *********** */ +{ + .name = "RGB565", + .fourcc = V4L2_PIX_FMT_RGB565, + .flags = 0, + .depth = 16, + .rotation = false, + .overlay = false, +}, +/* ************ SGRBG8 *********** */ +{ + .name = "SGRBG8", + .fourcc = V4L2_PIX_FMT_SGRBG8, + .flags = 0, + .depth = 8, + .rotation = false, + .overlay = false, +}, +}; + +struct cif_isp10_hw_error { + char *name; + unsigned int count; + unsigned int mask; + unsigned int type; /* isp:0 ;mipi:1 */ +}; + +static struct cif_isp10_hw_error cif_isp10_hw_errors[] = { + { + .name = "isp_data_loss", + .count = 0, + .mask = CIF_ISP_DATA_LOSS, + .type = 0, + }, + { + .name = "isp_pic_size_err", + .count = 0, + .mask = CIF_ISP_PIC_SIZE_ERROR, + .type = 0, + }, + { + .name = "mipi_fifo_err", + .count = 0, + .mask = CIF_MIPI_SYNC_FIFO_OVFLW(1), + .type = 1, + }, + { + .name = "dphy_err_sot", + .count = 0, + .mask = CIF_MIPI_ERR_SOT(3), + .type = 1, + }, + { + .name = "dphy_err_sot_sync", + .count = 0, + .mask = CIF_MIPI_ERR_SOT_SYNC(3), + .type = 1, + }, + { + .name = "dphy_err_eot_sync", + .count = 0, + .mask = CIF_MIPI_ERR_EOT_SYNC(3), + .type = 1, + }, + { + .name = "dphy_err_ctrl", + .count = 0, + .mask = CIF_MIPI_ERR_CTRL(3), + .type = 1, + }, + { + .name = "csi_err_protocol", + .count = 0, + .mask = CIF_MIPI_ERR_PROTOCOL, + .type = 2, + }, + { + .name = "csi_err_ecc1", + .count = 0, + .mask = CIF_MIPI_ERR_ECC1, + .type = 2, + }, + { + .name = "csi_err_ecc2", + .count = 0, + .mask = CIF_MIPI_ERR_ECC2, + .type = 2, + }, + { + .name = "csi_err_cs", + .count = 0, + .mask = CIF_MIPI_ERR_CS, + .type = 2, + }, + { + .name = "fifo_ovf", + .count = 0, + .mask = (3 << 0), + .type = 2, + }, + { + .name = "isp_outform", + .count = 0, + .mask = CIF_ISP_ERR_OUTFORM_SIZE, + .type = 0, + }, + { + .name = "isp_stab", + .count = 0, + .mask = CIF_ISP_ERR_IS_SIZE, + .type = 0, + }, + { + .name = "isp_inform", + .count = 0, + .mask = CIF_ISP_ERR_INFORM_SIZE, + .type = 0, + } +}; + +/* Defines */ + +#define CIF_ISP10_INVALID_BUFF_ADDR ((u32)~0) +#define CIF_ISP10_MI_IS_BUSY(dev)\ + (dev->config.mi_config.mp.busy ||\ + dev->config.mi_config.sp.busy ||\ + dev->config.mi_config.dma.busy) +enum { + CIF_ISP10_ASYNC_JPEG = 0x1, + CIF_ISP10_ASYNC_YCFLT = 0x2, + CIF_ISP10_ASYNC_ISM = 0x4, + CIF_ISP10_ASYNC_DMA = 0x8 +}; + +#define CIF_ISP10_ALWAYS_ASYNC 0x00 +#define CIF_ISP10_ALWAYS_STALL_ON_NO_BUFS (false) + +#ifndef DIV_ROUND_UP +#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) +#endif + +#ifndef DIV_TRUNCATE +#define DIV_TRUNCATE(x, y) ((x) / (y)) +#endif + +/* Structures and Types */ + +/* Static Functions */ +static const char *cif_isp10_interface_string( + enum pltfrm_cam_itf_type itf) +{ + switch (itf) { + case PLTFRM_CAM_ITF_MIPI: + return "MIPI"; + case PLTFRM_CAM_ITF_BT601_8: + return "DVP_BT601_8Bit"; + case PLTFRM_CAM_ITF_BT656_8: + return "DVP_BT656_8Bit"; + case PLTFRM_CAM_ITF_BT601_10: + return "DVP_BT601_10Bit"; + case PLTFRM_CAM_ITF_BT656_10: + return "DVP_BT656_10Bit"; + case PLTFRM_CAM_ITF_BT601_12: + return "DVP_BT601_12Bit"; + case PLTFRM_CAM_ITF_BT656_12: + return "DVP_BT656_12Bit"; + case PLTFRM_CAM_ITF_BT601_16: + return "DVP_BT601_16Bit"; + case PLTFRM_CAM_ITF_BT656_16: + return "DVP_BT656_16Bit"; + default: + return "UNKNOWN/UNSUPPORTED"; + } +} + +static const char *cif_isp10_img_src_state_string( + enum cif_isp10_img_src_state state) +{ + switch (state) { + case CIF_ISP10_IMG_SRC_STATE_OFF: + return "OFF"; + case CIF_ISP10_IMG_SRC_STATE_SW_STNDBY: + return "SW_STNDBY"; + case CIF_ISP10_IMG_SRC_STATE_STREAMING: + return "STREAMING"; + default: + return "UNKNOWN/UNSUPPORTED"; + } +} + +static const char *cif_isp10_state_string( + enum cif_isp10_state state) +{ + switch (state) { + case CIF_ISP10_STATE_DISABLED: + return "DISABLED"; + case CIF_ISP10_STATE_INACTIVE: + return "INACTIVE"; + case CIF_ISP10_STATE_READY: + return "READY"; + case CIF_ISP10_STATE_STREAMING: + return "STREAMING"; + default: + return "UNKNOWN/UNSUPPORTED"; + } +} + +static const char *cif_isp10_pm_state_string( + enum cif_isp10_pm_state pm_state) +{ + switch (pm_state) { + case CIF_ISP10_PM_STATE_OFF: + return "OFF"; + case CIF_ISP10_PM_STATE_SW_STNDBY: + return "STANDBY"; + case CIF_ISP10_PM_STATE_SUSPENDED: + return "SUSPENDED"; + case CIF_ISP10_PM_STATE_STREAMING: + return "STREAMING"; + default: + return "UNKNOWN/UNSUPPORTED"; + } +} + +static const char *cif_isp10_stream_id_string( + enum cif_isp10_stream_id stream_id) +{ + switch (stream_id) { + case CIF_ISP10_STREAM_SP: + return "SP"; + case CIF_ISP10_STREAM_MP: + return "MP"; + case CIF_ISP10_STREAM_DMA: + return "DMA"; + case CIF_ISP10_STREAM_ISP: + return "ISP"; + default: + return "UNKNOWN/UNSUPPORTED"; + } +} + +static const char *cif_isp10_inp_string( + enum cif_isp10_inp inp) +{ + switch (inp) { + case CIF_ISP10_INP_CSI: + return "CSI"; + case CIF_ISP10_INP_CPI: + return "CPI"; + case CIF_ISP10_INP_DMA: + return "DMA(ISP)"; + case CIF_ISP10_INP_DMA_IE: + return "DMA(Image Effects)"; + case CIF_ISP10_INP_DMA_SP: + return "DMA(SP)"; + default: + return "UNKNOWN/UNSUPPORTED"; + } +} + +enum cif_isp10_inp cif_isp10_input_index2inp( + struct cif_isp10_device *dev, + unsigned int input) +{ + struct pltfrm_cam_itf itf; + + if (input >= dev->img_src_cnt) + return input - dev->img_src_cnt + CIF_ISP10_INP_DMA; + + cif_isp10_pltfrm_g_interface_config( + dev->img_src_array[input], + &itf); + if (PLTFRM_CAM_ITF_IS_MIPI(itf.type)) + return CIF_ISP10_INP_CSI; + if (PLTFRM_CAM_ITF_IS_DVP(itf.type)) + return CIF_ISP10_INP_CPI; + + return -EINVAL; +} + +static const char *cif_isp10_pix_fmt_string(int pixfmt) +{ + switch (pixfmt) { + case CIF_YUV400: + return "YUV400"; + case CIF_YUV420I: + return "YUV420I"; + case CIF_YUV420SP: + return "YUV420SP"; + case CIF_YUV420P: + return "YUV420P"; + case CIF_YVU420I: + return "YVU420I"; + case CIF_YVU420SP: + return "YVU420SP"; + case CIF_YVU420P: + return "YVU420P"; + case CIF_YUV422I: + return "YUV422I"; + case CIF_YUV422SP: + return "YUV422SP"; + case CIF_YUV422P: + return "YUV422P"; + case CIF_YVU422I: + return "YVU422I"; + case CIF_YVU422SP: + return "YVU422SP"; + case CIF_YVU422P: + return "YVU422P"; + case CIF_YUV444I: + return "YUV444I"; + case CIF_YUV444SP: + return "YUV444SP"; + case CIF_YUV444P: + return "YUV444P"; + case CIF_YVU444I: + return "YVU444I"; + case CIF_YVU444SP: + return "YVU444SP"; + case CIF_YVU444P: + return "YVU444SP"; + case CIF_UYV400: + return "UYV400"; + case CIF_UYV420I: + return "UYV420I"; + case CIF_UYV420SP: + return "UYV420SP"; + case CIF_UYV420P: + return "UYV420P"; + case CIF_VYU420I: + return "VYU420I"; + case CIF_VYU420SP: + return "VYU420SP"; + case CIF_VYU420P: + return "VYU420P"; + case CIF_UYV422I: + return "UYV422I"; + case CIF_UYV422SP: + return "UYV422I"; + case CIF_UYV422P: + return "UYV422P"; + case CIF_VYU422I: + return "VYU422I"; + case CIF_VYU422SP: + return "VYU422SP"; + case CIF_VYU422P: + return "VYU422P"; + case CIF_UYV444I: + return "UYV444I"; + case CIF_UYV444SP: + return "UYV444SP"; + case CIF_UYV444P: + return "UYV444P"; + case CIF_VYU444I: + return "VYU444I"; + case CIF_VYU444SP: + return "VYU444SP"; + case CIF_VYU444P: + return "VYU444P"; + case CIF_RGB565: + return "RGB565"; + case CIF_RGB666: + return "RGB666"; + case CIF_RGB888: + return "RGB888"; + case CIF_BAYER_SBGGR8: + return "BAYER BGGR8"; + case CIF_BAYER_SGBRG8: + return "BAYER GBRG8"; + case CIF_BAYER_SGRBG8: + return "BAYER GRBG8"; + case CIF_BAYER_SRGGB8: + return "BAYER RGGB8"; + case CIF_BAYER_SBGGR10: + return "BAYER BGGR10"; + case CIF_BAYER_SGBRG10: + return "BAYER GBRG10"; + case CIF_BAYER_SGRBG10: + return "BAYER GRBG10"; + case CIF_BAYER_SRGGB10: + return "BAYER RGGB10"; + case CIF_BAYER_SBGGR12: + return "BAYER BGGR12"; + case CIF_BAYER_SGBRG12: + return "BAYER GBRG12"; + case CIF_BAYER_SGRBG12: + return "BAYER GRBG12"; + case CIF_BAYER_SRGGB12: + return "BAYER RGGB12"; + case CIF_DATA: + return "DATA"; + case CIF_JPEG: + return "JPEG"; + default: + return "unknown/unsupported"; + } +} + +static void cif_isp10_debug_print_mi_sp(struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_info(dev->dev, + "\n MI_CTRL 0x%08x/0x%08x\n" + " MI_STATUS 0x%08x\n" + " MI_RIS 0x%08x/0x%08x\n" + " MI_IMSC 0x%08x\n" + " MI_SP_Y_SIZE %d/%d\n" + " MI_SP_CB_SIZE %d/%d\n" + " MI_SP_CR_SIZE %d/%d\n" + " MI_SP_PIC_WIDTH %d\n" + " MI_SP_PIC_HEIGHT %d\n" + " MI_SP_PIC_LLENGTH %d\n" + " MI_SP_PIC_SIZE %d\n" + " MI_SP_Y_BASE_AD 0x%08x/0x%08x\n" + " MI_SP_Y_OFFS_CNT %d/%d\n" + " MI_SP_Y_OFFS_CNT_START %d\n" + " MI_SP_CB_OFFS_CNT %d/%d\n" + " MI_SP_CB_OFFS_CNT_START %d\n" + " MI_SP_CR_OFFS_CNT %d/%d\n" + " MI_SP_CR_OFFS_CNT_START %d\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_MI_CTRL_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_STATUS), + cif_ioread32(dev->config.base_addr + + CIF_MI_RIS), + cif_ioread32(dev->config.base_addr + + CIF_MI_MIS), + cif_ioread32(dev->config.base_addr + + CIF_MI_IMSC), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CB_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CB_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CR_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CR_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_PIC_WIDTH), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_PIC_HEIGHT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_LLENGTH), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_PIC_SIZE), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_BASE_AD_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_OFFS_CNT_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_OFFS_CNT_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_OFFS_CNT_START), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CB_OFFS_CNT_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CB_OFFS_CNT_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CB_OFFS_CNT_START), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CR_OFFS_CNT_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CR_OFFS_CNT_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CR_OFFS_CNT_START)); +} + +static void cif_isp10_debug_print_mi_mp(struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_info(dev->dev, + "\n MI_CTRL 0x%08x/0x%08x\n" + " MI_STATUS 0x%08x\n" + " MI_BYTE_CNT %d\n" + " MI_RIS 0x%08x/0x%08x\n" + " MI_IMSC 0x%08x\n" + " MI_MP_Y_SIZE %d/%d\n" + " MI_MP_CB_SIZE %d/%d\n" + " MI_MP_CR_SIZE %d/%d\n" + " MI_MP_Y_BASE_AD 0x%08x/0x%08x\n" + " MI_MP_Y_OFFS_CNT %d/%d\n" + " MI_MP_Y_OFFS_CNT_START %d\n" + " MI_MP_CB_OFFS_CNT %d/%d\n" + " MI_MP_CB_OFFS_CNT_START %d\n" + " MI_MP_CR_OFFS_CNT %d/%d\n" + " MI_MP_CR_OFFS_CNT_START %d\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_MI_CTRL_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_STATUS), + cif_ioread32(dev->config.base_addr + + CIF_MI_BYTE_CNT), + cif_ioread32(dev->config.base_addr + + CIF_MI_RIS), + cif_ioread32(dev->config.base_addr + + CIF_MI_MIS), + cif_ioread32(dev->config.base_addr + + CIF_MI_IMSC), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_OFFS_CNT_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_OFFS_CNT_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_OFFS_CNT_START), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_OFFS_CNT_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_OFFS_CNT_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_OFFS_CNT_START), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_OFFS_CNT_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_OFFS_CNT_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_OFFS_CNT_START)); +} + +static void cif_isp10_debug_print_srsz(struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_info(dev->dev, + "\n SRSZ_CTRL 0x%08x/0x%08x\n" + " SRSZ_SCALE_HY %d/%d\n" + " SRSZ_SCALE_HCB %d/%d\n" + " SRSZ_SCALE_HCR %d/%d\n" + " SRSZ_SCALE_VY %d/%d\n" + " SRSZ_SCALE_VC %d/%d\n" + " SRSZ_PHASE_HY %d/%d\n" + " SRSZ_PHASE_HC %d/%d\n" + " SRSZ_PHASE_VY %d/%d\n" + " SRSZ_PHASE_VC %d/%d\n", + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_CTRL_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCB), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCB_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCR), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCR_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VC), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HC), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VC), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VC_SHD)); +} + +static void cif_isp10_debug_print_mrsz(struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_info(dev->dev, + "\n MRSZ_CTRL 0x%08x/0x%08x\n" + " MRSZ_SCALE_HY %d/%d\n" + " MRSZ_SCALE_HCB %d/%d\n" + " MRSZ_SCALE_HCR %d/%d\n" + " MRSZ_SCALE_VY %d/%d\n" + " MRSZ_SCALE_VC %d/%d\n" + " MRSZ_PHASE_HY %d/%d\n" + " MRSZ_PHASE_HC %d/%d\n" + " MRSZ_PHASE_VY %d/%d\n" + " MRSZ_PHASE_VC %d/%d\n", + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_CTRL_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCB), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCB_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCR), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCR_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VC), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HC), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VC), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VC_SHD)); +} + +static void cif_isp10_debug_print_block( + struct cif_isp10_device *dev, + const char *block_name) +{ + if (!strncmp(block_name, "all", 3)) { + cif_isp10_debug_print_srsz(dev); + cif_isp10_debug_print_mrsz(dev); + cif_isp10_debug_print_mi_sp(dev); + cif_isp10_debug_print_mi_mp(dev); + } else if (!strncmp(block_name, "srsz", 4)) { + cif_isp10_debug_print_srsz(dev); + } else if (!strncmp(block_name, "mrsz", 4)) { + cif_isp10_debug_print_mrsz(dev); + } else if (!strncmp(block_name, "mi_sp", 5)) { + cif_isp10_debug_print_mi_sp(dev); + } else if (!strncmp(block_name, "mi_mp", 5)) { + cif_isp10_debug_print_mi_mp(dev); + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unknown block %s\n", block_name); + } +} + +static u32 cif_isp10_calc_llength( + u32 width, + u32 stride, + enum cif_isp10_pix_fmt pix_fmt) +{ + if (stride == 0) + return width; + + if (CIF_ISP10_PIX_FMT_IS_YUV(pix_fmt)) { + u32 num_cplanes = + CIF_ISP10_PIX_FMT_YUV_GET_NUM_CPLANES(pix_fmt); + if (num_cplanes == 0) + return 8 * stride / CIF_ISP10_PIX_FMT_GET_BPP(pix_fmt); + else + return stride; + } else if (CIF_ISP10_PIX_FMT_IS_RGB(pix_fmt)) { + return 8 * stride / CIF_ISP10_PIX_FMT_GET_BPP(pix_fmt); + } else { + return width; + } +} + +static int cif_isp10_set_pm_state( + struct cif_isp10_device *dev, + enum cif_isp10_pm_state pm_state) +{ + cif_isp10_pltfrm_pr_dbg(dev->dev, "%s -> %s\n", + cif_isp10_pm_state_string(dev->pm_state), + cif_isp10_pm_state_string(pm_state)); + + if (dev->pm_state == pm_state) + return 0; + + switch (pm_state) { + case CIF_ISP10_PM_STATE_OFF: + case CIF_ISP10_PM_STATE_SUSPENDED: + if ((dev->pm_state == CIF_ISP10_PM_STATE_SW_STNDBY) || + (dev->pm_state == CIF_ISP10_PM_STATE_STREAMING)) { + pm_runtime_put_sync(dev->dev); + } + break; + case CIF_ISP10_PM_STATE_SW_STNDBY: + case CIF_ISP10_PM_STATE_STREAMING: + if ((dev->pm_state == CIF_ISP10_PM_STATE_OFF) || + (dev->pm_state == CIF_ISP10_PM_STATE_SUSPENDED)) { + pm_runtime_get_sync(dev->dev); + } + break; + default: + cif_isp10_pltfrm_pr_err(dev->dev, + "unknown or unsupported PM state %d\n", pm_state); + return -EINVAL; + } + + dev->pm_state = pm_state; + + return 0; +} + +static int cif_isp10_img_src_set_state( + struct cif_isp10_device *dev, + enum cif_isp10_img_src_state state) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, "%s -> %s\n", + cif_isp10_img_src_state_string(dev->img_src_state), + cif_isp10_img_src_state_string(state)); + + if (dev->img_src_state == state) + return 0; + + switch (state) { + case CIF_ISP10_IMG_SRC_STATE_OFF: + ret = cif_isp10_img_src_s_power(dev->img_src, false); + break; + case CIF_ISP10_IMG_SRC_STATE_SW_STNDBY: + if (dev->img_src_state == CIF_ISP10_IMG_SRC_STATE_STREAMING) { + ret = cif_isp10_img_src_s_streaming( + dev->img_src, false); + } else { + ret = cif_isp10_img_src_s_power(dev->img_src, true); + } + break; + case CIF_ISP10_IMG_SRC_STATE_STREAMING: + if (dev->config.flash_mode != + CIF_ISP10_FLASH_MODE_OFF) + cif_isp10_img_src_s_ctrl(dev->img_src, + CIF_ISP10_CID_FLASH_MODE, + dev->config.flash_mode); + ret = cif_isp10_img_src_s_streaming(dev->img_src, true); + break; + default: + break; + } + + if ((dev->config.flash_mode != CIF_ISP10_FLASH_MODE_OFF) && + (IS_ERR_VALUE(ret) || + (state == CIF_ISP10_IMG_SRC_STATE_OFF))) + cif_isp10_img_src_s_ctrl(dev->img_src, + CIF_ISP10_CID_FLASH_MODE, + CIF_ISP10_FLASH_MODE_OFF); + + if (!IS_ERR_VALUE(ret)) + dev->img_src_state = state; + else + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + + return ret; +} + +static int cif_isp10_img_srcs_init( + struct cif_isp10_device *dev) +{ + int ret = 0; + + memset(dev->img_src_array, 0x00, sizeof(dev->img_src_array)); + dev->img_src_cnt = cif_isp10_pltfrm_get_img_src_device(dev->dev, + dev->img_src_array, CIF_ISP10_NUM_INPUTS); + + if (dev->img_src_cnt > 0) + return 0; + + dev->img_src_cnt = 0; + ret = -EFAULT; + + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_img_src_select_strm_fmt( + struct cif_isp10_device *dev) +{ + int ret = 0; + u32 index; + struct cif_isp10_strm_fmt_desc strm_fmt_desc; + struct cif_isp10_strm_fmt request_strm_fmt; + bool matching_format_found = false; + bool better_match = false; + u32 target_width, target_height; + u32 img_src_width, img_src_height; + u32 best_diff = ~0; + int vblanking; + + if (IS_ERR_OR_NULL(dev->img_src)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "no image source selected as input (call s_input first)\n"); + ret = -EFAULT; + goto err; + } + + ret = cif_isp10_get_target_frm_size(dev, + &target_width, &target_height); + if (IS_ERR_VALUE(ret)) + goto err; + + /* find the best matching format from the image source */ + /* TODO: frame interval and pixel format handling */ + for (index = 0;; index++) { + if (IS_ERR_VALUE(cif_isp10_img_src_enum_strm_fmts(dev->img_src, + index, &strm_fmt_desc))) + break; + if (!strm_fmt_desc.discrete_frmsize) { + if (strm_fmt_desc.min_frmsize.width >= target_width) + img_src_width = strm_fmt_desc.min_frmsize.width; + else if (strm_fmt_desc.max_frmsize.width >= + target_width) + img_src_width = target_width; + else + img_src_width = strm_fmt_desc.max_frmsize.width; + if (strm_fmt_desc.min_frmsize.height >= target_height) + img_src_height = + strm_fmt_desc.min_frmsize.height; + else if (strm_fmt_desc.max_frmsize.height >= + target_height) + img_src_height = target_height; + else + img_src_height = + strm_fmt_desc.max_frmsize.height; + } else { + img_src_width = strm_fmt_desc.min_frmsize.width; + img_src_height = strm_fmt_desc.min_frmsize.height; + } + if ((img_src_width >= target_width) && + (img_src_height >= target_height)) { + u32 diff = abs( + target_height - + (target_width * img_src_height / + img_src_width)); + if (matching_format_found) { + if (dev->config.jpeg_config.enable && + ((img_src_width >= + request_strm_fmt.frm_fmt.width) && + (img_src_height > + request_strm_fmt.frm_fmt.height))) + /* + * for image capturing we try to + * maximize the size + */ + better_match = true; + else if (!dev->config.jpeg_config.enable && + ((strm_fmt_desc.min_intrvl.denominator / + strm_fmt_desc.min_intrvl.numerator) > + (request_strm_fmt.frm_intrvl.denominator / + request_strm_fmt.frm_intrvl.numerator))) + /* maximize fps */ + better_match = true; + else if (!dev->config.jpeg_config.enable && + ((strm_fmt_desc.min_intrvl.denominator / + strm_fmt_desc.min_intrvl.numerator) == + (request_strm_fmt.frm_intrvl.denominator / + request_strm_fmt.frm_intrvl.numerator)) && + (diff < best_diff)) + /* + * chose better aspect ratio + * match if fps equal + */ + better_match = true; + else + better_match = false; + } + + if (!matching_format_found || + better_match) { + request_strm_fmt.frm_fmt.width = + strm_fmt_desc.min_frmsize.width; + request_strm_fmt.frm_fmt.height = + strm_fmt_desc.min_frmsize.height; + request_strm_fmt.frm_fmt.std_id = + strm_fmt_desc.std_id; + request_strm_fmt.frm_fmt.pix_fmt = + strm_fmt_desc.pix_fmt; + request_strm_fmt.frm_intrvl.numerator = + strm_fmt_desc.min_intrvl.numerator; + request_strm_fmt.frm_intrvl.denominator = + strm_fmt_desc.min_intrvl.denominator; + request_strm_fmt.frm_fmt.defrect = + strm_fmt_desc.defrect; + best_diff = diff; + matching_format_found = true; + } + } + } + + if (!matching_format_found) { + cif_isp10_pltfrm_pr_err(dev->dev, + "no matching image source format (%dx%d) found\n", + target_width, target_height); + ret = -EINVAL; + goto err; + } + + cif_isp10_pltfrm_pr_dbg( + dev->dev, + "requesting format %s %dx%d(%d,%d,%d,%d)@%d/%dfps from %s\n", + cif_isp10_pix_fmt_string(request_strm_fmt.frm_fmt.pix_fmt), + request_strm_fmt.frm_fmt.width, + request_strm_fmt.frm_fmt.height, + request_strm_fmt.frm_fmt.defrect.left, + request_strm_fmt.frm_fmt.defrect.top, + request_strm_fmt.frm_fmt.defrect.width, + request_strm_fmt.frm_fmt.defrect.height, + request_strm_fmt.frm_intrvl.denominator, + request_strm_fmt.frm_intrvl.numerator, + cif_isp10_img_src_g_name(dev->img_src)); + + ret = cif_isp10_img_src_s_strm_fmt(dev->img_src, &request_strm_fmt); + if (IS_ERR_VALUE(ret)) + goto err; + + dev->config.img_src_output = request_strm_fmt; + + ret = cif_isp10_img_src_g_ctrl(dev->img_src, + CIF_ISP10_CID_VBLANKING, &vblanking); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_dbg( + dev->dev, + "get vblanking failed: %d\n", ret); + vblanking = 0; + } + + if (vblanking >= 0) + dev->isp_dev.v_blanking_us = vblanking; + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +/* + * This should only be called when configuring CIF + * or at the frame end interrupt + */ +static void cif_isp10_config_ism(struct cif_isp10_device *dev, bool async) +{ + const struct cif_isp10_ism_config *pconfig = + &dev->config.isp_config.ism_config; + + if (pconfig->ism_en) { + cif_isp10_pltfrm_pr_dbg(dev->dev, "%dx%d -> %dx%d@(%d,%d)\n", + dev->isp_dev.input_width, + dev->isp_dev.input_height, + pconfig->ism_params.h_size, + pconfig->ism_params.v_size, + pconfig->ism_params.h_offs, + pconfig->ism_params.v_offs); + cif_iowrite32(pconfig->ism_params.recenter, + dev->config.base_addr + CIF_ISP_IS_RECENTER); + cif_iowrite32(pconfig->ism_params.max_dx, + dev->config.base_addr + CIF_ISP_IS_MAX_DX); + cif_iowrite32(pconfig->ism_params.max_dy, + dev->config.base_addr + CIF_ISP_IS_MAX_DY); + cif_iowrite32(pconfig->ism_params.displace, + dev->config.base_addr + CIF_ISP_IS_DISPLACE); + cif_iowrite32(pconfig->ism_params.h_offs, + dev->config.base_addr + CIF_ISP_IS_H_OFFS); + cif_iowrite32(pconfig->ism_params.v_offs, + dev->config.base_addr + CIF_ISP_IS_V_OFFS); + cif_iowrite32(pconfig->ism_params.h_size, + dev->config.base_addr + CIF_ISP_IS_H_SIZE); + cif_iowrite32(pconfig->ism_params.v_size, + dev->config.base_addr + CIF_ISP_IS_V_SIZE); + cif_iowrite32OR(1, + dev->config.base_addr + CIF_ISP_IS_CTRL); + dev->config.isp_config.output.width = + dev->config.isp_config.ism_config.ism_params.h_size; + dev->config.isp_config.output.height = + dev->config.isp_config.ism_config.ism_params.v_size; + } else { + cif_iowrite32(pconfig->ism_params.recenter, + dev->config.base_addr + CIF_ISP_IS_RECENTER); + cif_iowrite32(pconfig->ism_params.max_dx, + dev->config.base_addr + CIF_ISP_IS_MAX_DX); + cif_iowrite32(pconfig->ism_params.max_dy, + dev->config.base_addr + CIF_ISP_IS_MAX_DY); + cif_iowrite32(pconfig->ism_params.displace, + dev->config.base_addr + CIF_ISP_IS_DISPLACE); + cif_iowrite32(0, + dev->config.base_addr + CIF_ISP_IS_H_OFFS); + cif_iowrite32(0, + dev->config.base_addr + CIF_ISP_IS_V_OFFS); + cif_iowrite32(dev->config.isp_config.output.width, + dev->config.base_addr + CIF_ISP_IS_H_SIZE); + cif_iowrite32(dev->config.isp_config.output.height, + dev->config.base_addr + CIF_ISP_IS_V_SIZE); + cif_iowrite32(0, + dev->config.base_addr + CIF_ISP_IS_CTRL); + } + + if (async) + cif_iowrite32OR(CIF_ISP_CTRL_ISP_CFG_UPD, + dev->config.base_addr + CIF_ISP_CTRL); + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n ISP_IS_H_OFFS %d/%d\n" + " ISP_IS_V_OFFS %d/%d\n" + " ISP_IS_H_SIZE %d/%d\n" + " ISP_IS_V_SIZE %d/%d\n" + " ISP_IS_RECENTER 0x%08x\n" + " ISP_IS_MAX_DX %d\n" + " ISP_IS_MAX_DY %d\n" + " ISP_IS_DISPLACE 0x%08x\n" + " ISP_IS_CTRL 0x%08x\n", + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_H_OFFS), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_H_OFFS_SHD), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_V_OFFS), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_V_OFFS_SHD), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_H_SIZE), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_H_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_V_SIZE), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_V_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_RECENTER), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_MAX_DX), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_MAX_DY), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_DISPLACE), + cif_ioread32(dev->config.base_addr + + CIF_ISP_IS_CTRL)); +} + +static void cif_isp10_program_jpeg_tables( + struct cif_isp10_device *dev) +{ + unsigned int ratio = dev->config.jpeg_config.ratio; + unsigned int i = 0; + unsigned int q, q_next, scale; + + cif_isp10_pltfrm_pr_dbg(NULL, "ratio %d\n", ratio); + + /* Y q-table 0 programming */ + cif_iowrite32(CIF_JPE_TAB_ID_QUANT0, + dev->config.base_addr + CIF_JPE_TABLE_ID); + if (ratio != 50) { + scale = (ratio < 50) ? 5000 / ratio : 200 - (ratio << 1); + for (i = 0; i < 32; i++) { + q = yq_table_base_zigzag[i * 2]; + q_next = yq_table_base_zigzag[i * 2 + 1]; + q = (scale * q + 50) / 100; + q = (q > 1) ? ((q < 255) ? q : 255) : 1; + q_next = (scale * q_next + 50) / 100; + q_next = (q_next > 1) ? + ((q_next < 255) ? q_next : 255) : 1; + cif_iowrite32(q_next + (q << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } + } else { + for (i = 0; i < 32; i++) { + q = yq_table_base_zigzag[i * 2]; + q_next = yq_table_base_zigzag[i * 2 + 1]; + cif_iowrite32(q_next + (q << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } + } + + /* U/V q-table 0 programming */ + cif_iowrite32(CIF_JPE_TAB_ID_QUANT1, + dev->config.base_addr + CIF_JPE_TABLE_ID); + if (ratio != 50) { + for (i = 0; i < 32; i++) { + q = uvq_table_base_zigzag[i * 2]; + q_next = uvq_table_base_zigzag[i * 2 + 1]; + q = (scale * q + 50) / 100; + q = (q > 1) ? ((q < 255) ? q : 255) : 1; + q_next = (scale * q_next + 50) / 100; + q_next = (q_next > 1) ? + ((q_next < 255) ? q_next : 255) : 1; + cif_iowrite32(q_next + (q << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } + } else { + for (i = 0; i < 32; i++) { + q = uvq_table_base_zigzag[i * 2]; + q_next = uvq_table_base_zigzag[i * 2 + 1]; + cif_iowrite32(q_next + (q << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } + } + + /* Y AC-table 0 programming */ + cif_iowrite32(CIF_JPE_TAB_ID_HUFFAC0, + dev->config.base_addr + CIF_JPE_TABLE_ID); + cif_iowrite32(178, dev->config.base_addr + CIF_JPE_TAC0_LEN); + for (i = 0; i < (178 / 2); i++) { + cif_iowrite32(ac_luma_table_annex_k[i * 2 + 1] + + (ac_luma_table_annex_k[i * 2] << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } + + /* U/V AC-table 1 programming */ + cif_iowrite32(CIF_JPE_TAB_ID_HUFFAC1, + dev->config.base_addr + CIF_JPE_TABLE_ID); + cif_iowrite32(178, dev->config.base_addr + CIF_JPE_TAC1_LEN); + for (i = 0; i < (178 / 2); i++) { + cif_iowrite32(ac_chroma_table_annex_k[i * 2 + 1] + + (ac_chroma_table_annex_k[i * 2] << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } + + /* Y DC-table 0 programming */ + cif_iowrite32(CIF_JPE_TAB_ID_HUFFDC0, + dev->config.base_addr + CIF_JPE_TABLE_ID); + cif_iowrite32(28, dev->config.base_addr + CIF_JPE_TDC0_LEN); + for (i = 0; i < (28 / 2); i++) { + cif_iowrite32(dc_luma_table_annex_k[i * 2 + 1] + + (dc_luma_table_annex_k[i * 2] << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } + + /* U/V DC-table 1 programming */ + cif_iowrite32(CIF_JPE_TAB_ID_HUFFDC1, + dev->config.base_addr + CIF_JPE_TABLE_ID); + cif_iowrite32(28, dev->config.base_addr + CIF_JPE_TDC1_LEN); + for (i = 0; i < (28 / 2); i++) { + cif_iowrite32(dc_chroma_table_annex_k[i * 2 + 1] + + (dc_chroma_table_annex_k[i * 2] << 8), + dev->config.base_addr + + CIF_JPE_TABLE_DATA); + } +} + +static void cif_isp10_select_jpeg_tables( + struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + /* Selects quantization table for Y */ + cif_iowrite32(CIF_JPE_TQ_TAB0, + dev->config.base_addr + CIF_JPE_TQ_Y_SELECT); + /* Selects quantization table for U */ + cif_iowrite32(CIF_JPE_TQ_TAB1, + dev->config.base_addr + CIF_JPE_TQ_U_SELECT); + /* Selects quantization table for V */ + cif_iowrite32(CIF_JPE_TQ_TAB1, + dev->config.base_addr + CIF_JPE_TQ_V_SELECT); + /* Selects Huffman DC table */ + cif_iowrite32(CIF_DC_V_TABLE | CIF_DC_U_TABLE, + dev->config.base_addr + CIF_JPE_DC_TABLE_SELECT); + /* Selects Huffman AC table */ + cif_iowrite32(CIF_AC_V_TABLE | CIF_AC_U_TABLE, + dev->config.base_addr + CIF_JPE_AC_TABLE_SELECT); + + cif_isp10_pltfrm_pr_dbg(NULL, + "\n JPE_TQ_Y_SELECT 0x%08x\n" + " JPE_TQ_U_SELECT 0x%08x\n" + " JPE_TQ_V_SELECT 0x%08x\n" + " JPE_DC_TABLE_SELECT 0x%08x\n" + " JPE_AC_TABLE_SELECT 0x%08x\n", + cif_ioread32(dev->config.base_addr + CIF_JPE_TQ_Y_SELECT), + cif_ioread32(dev->config.base_addr + CIF_JPE_TQ_U_SELECT), + cif_ioread32(dev->config.base_addr + CIF_JPE_TQ_V_SELECT), + cif_ioread32(dev->config.base_addr + CIF_JPE_DC_TABLE_SELECT), + cif_ioread32(dev->config.base_addr + CIF_JPE_AC_TABLE_SELECT)); +} + +static int cif_isp10_config_img_src( + struct cif_isp10_device *dev) +{ + int ret = 0; + struct isp_supplemental_sensor_mode_data sensor_mode; + + cif_isp10_pltfrm_pr_dbg(dev->dev, "\n"); + + ret = cif_isp10_img_src_set_state(dev, + CIF_ISP10_IMG_SRC_STATE_SW_STNDBY); + if (IS_ERR_VALUE(ret)) + goto err; + + if (!dev->sp_stream.updt_cfg && + !dev->mp_stream.updt_cfg) + return 0; + + ret = cif_isp10_pltfrm_g_interface_config(dev->img_src, + &dev->config.cam_itf); + if (IS_ERR_VALUE(ret)) + goto err; + + ret = (int)cif_isp10_img_src_ioctl(dev->img_src, + RK_VIDIOC_SENSOR_MODE_DATA, &sensor_mode); + if (IS_ERR_VALUE(ret)) { + dev->img_src_exps.exp_valid_frms = 2; + } else { + if ((sensor_mode.exposure_valid_frame < 2) || + (sensor_mode.exposure_valid_frame > 6)) + dev->img_src_exps.exp_valid_frms = 2; + else + dev->img_src_exps.exp_valid_frms = + sensor_mode.exposure_valid_frame; + } + cif_isp10_pltfrm_pr_dbg(dev->dev, + "cam_itf: (type: 0x%x, dphy: %d, vc: %d, nb_lanes: %d, bitrate: %d)", + dev->config.cam_itf.type, + dev->config.cam_itf.cfg.mipi.dphy_index, + dev->config.cam_itf.cfg.mipi.vc, + dev->config.cam_itf.cfg.mipi.nb_lanes, + dev->config.cam_itf.cfg.mipi.bit_rate); + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_config_isp( + struct cif_isp10_device *dev) +{ + int ret = 0; + u32 h_offs; + u32 v_offs; + u32 yuv_seq = 0; + u32 bpp; + u32 isp_input_sel = 0; + u32 isp_bayer_pat = 0; + u32 acq_mult = 1; + u32 irq_mask = 0; + u32 signal = 0; + enum cif_isp10_pix_fmt in_pix_fmt; + struct cif_isp10_frm_fmt *output; + struct pltfrm_cam_itf *cam_itf; + + if (dev->config.input_sel == CIF_ISP10_INP_DMA_IE) { + dev->config.isp_config.output = + dev->config.mi_config.dma.output; + cifisp_disable_isp(&dev->isp_dev); + return 0; + } else if (dev->config.input_sel == CIF_ISP10_INP_DMA_SP) { + cif_iowrite32AND(~CIF_ICCL_ISP_CLK, + dev->config.base_addr + CIF_ICCL); + cif_isp10_pltfrm_pr_dbg(NULL, + "ISP disabled\n"); + return 0; + } + cif_iowrite32OR(CIF_ICCL_ISP_CLK, + dev->config.base_addr + CIF_ICCL); + + in_pix_fmt = dev->config.isp_config.input->pix_fmt; + + output = &dev->config.isp_config.output; + cam_itf = &dev->config.cam_itf; + + if (CIF_ISP10_PIX_FMT_IS_RAW_BAYER(in_pix_fmt)) { + if (!dev->config.mi_config.raw_enable) { + output->pix_fmt = CIF_YUV422I; + + if ((dev->mp_stream.state == CIF_ISP10_STATE_READY) && + (dev->sp_stream.state == + CIF_ISP10_STATE_READY)) { + if (dev->config.mi_config.mp.output. + quantization != + dev->config.mi_config.sp.output. + quantization) { + cif_isp10_pltfrm_pr_err(dev->dev, + "colorspace quantization (mp: %d, sp: %d) is not support!\n", + dev-> + config.mi_config.mp.output. + quantization, + dev-> + config.mi_config.sp.output. + quantization); + } + } + + if (dev->sp_stream.state == CIF_ISP10_STATE_READY) { + output->quantization = + dev->config.mi_config.sp.output.quantization; + } + + if (dev->mp_stream.state == CIF_ISP10_STATE_READY) { + output->quantization = + dev->config.mi_config.sp.output.quantization; + } + + cif_iowrite32(0xc, + dev->config.base_addr + CIF_ISP_DEMOSAIC); + + if (PLTFRM_CAM_ITF_IS_BT656(dev->config.cam_itf.type)) { + cif_iowrite32( + CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656, + dev->config.base_addr + CIF_ISP_CTRL); + } else { + cif_iowrite32( + CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601, + dev->config.base_addr + CIF_ISP_CTRL); + } + } else { + output->pix_fmt = in_pix_fmt; + if (PLTFRM_CAM_ITF_IS_BT656(dev->config.cam_itf.type)) { + cif_iowrite32( + CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656, + dev->config.base_addr + CIF_ISP_CTRL); + } else { + cif_iowrite32(CIF_ISP_CTRL_ISP_MODE_RAW_PICT, + dev->config.base_addr + CIF_ISP_CTRL); + } + } + + bpp = CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt); + if (bpp == 8) { + isp_input_sel = CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB; + } else if (bpp == 10) { + isp_input_sel = CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB; + } else if (bpp == 12) { + isp_input_sel = CIF_ISP_ACQ_PROP_IN_SEL_12B; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "%d bits per pixel not supported\n", bpp); + ret = -EINVAL; + goto err; + } + if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_BGGR(in_pix_fmt)) { + isp_bayer_pat = CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR; + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GBRG(in_pix_fmt)) { + isp_bayer_pat = CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG; + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GRBG(in_pix_fmt)) { + isp_bayer_pat = CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG; + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_RGGB(in_pix_fmt)) { + isp_bayer_pat = CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "BAYER pattern not supported\n"); + ret = -EINVAL; + goto err; + } + } else if (CIF_ISP10_PIX_FMT_IS_YUV(in_pix_fmt)) { + output->pix_fmt = in_pix_fmt; + acq_mult = 2; + if (dev->config.input_sel == CIF_ISP10_INP_DMA) { + bpp = CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt); + bpp = + bpp * 4 / + (4 + (CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS( + in_pix_fmt) * + CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS( + in_pix_fmt) / 2)); + if (bpp == 8) { + isp_input_sel = CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB; + } else if (bpp == 10) { + isp_input_sel = CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB; + } else if (bpp == 12) { + isp_input_sel = CIF_ISP_ACQ_PROP_IN_SEL_12B; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "format %s not supported, invalid bpp %d\n", + cif_isp10_pix_fmt_string(in_pix_fmt), + bpp); + ret = -EINVAL; + goto err; + } + cif_iowrite32(CIF_ISP_CTRL_ISP_MODE_ITU601, + dev->config.base_addr + CIF_ISP_CTRL); + } else{ + if (PLTFRM_CAM_ITF_IS_MIPI( + dev->config.cam_itf.type)) { + isp_input_sel = CIF_ISP_ACQ_PROP_IN_SEL_12B; + cif_iowrite32(CIF_ISP_CTRL_ISP_MODE_ITU601, + dev->config.base_addr + CIF_ISP_CTRL); + } else if (PLTFRM_CAM_ITF_IS_DVP( + dev->config.cam_itf.type)) { + if (PLTFRM_CAM_ITF_IS_BT656( + dev->config.cam_itf.type)) { + cif_iowrite32( + CIF_ISP_CTRL_ISP_MODE_ITU656, + dev->config.base_addr + + CIF_ISP_CTRL); + } else { + cif_iowrite32( + CIF_ISP_CTRL_ISP_MODE_ITU601, + dev->config.base_addr + + CIF_ISP_CTRL); + } + + switch (PLTFRM_CAM_ITF_DVP_BW( + dev->config.cam_itf.type)) { + case 8: + isp_input_sel = + CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; + break; + case 10: + isp_input_sel = + CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; + break; + case 12: + isp_input_sel = + CIF_ISP_ACQ_PROP_IN_SEL_12B; + break; + default: + cif_isp10_pltfrm_pr_err(dev->dev, + "%s isn't support for cif isp10\n", + cif_isp10_interface_string( + dev->config.cam_itf.type)); + break; + } + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "%s isn't support for cif isp10\n", + cif_isp10_interface_string( + dev->config.cam_itf.type)); + } + /* + * ISP DATA LOSS is only meaningful + * when input is not DMA + */ + irq_mask |= CIF_ISP_DATA_LOSS; + } + if (CIF_ISP10_PIX_FMT_YUV_IS_YC_SWAPPED(in_pix_fmt)) { + yuv_seq = CIF_ISP_ACQ_PROP_CBYCRY; + cif_isp10_pix_fmt_set_yc_swapped(output->pix_fmt, 0); + } else if (CIF_ISP10_PIX_FMT_YUV_IS_UV_SWAPPED(in_pix_fmt)) { + yuv_seq = CIF_ISP_ACQ_PROP_YCRYCB; + } else { + yuv_seq = CIF_ISP_ACQ_PROP_YCBYCR; + } + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "format %s not supported\n", + cif_isp10_pix_fmt_string(in_pix_fmt)); + ret = -EINVAL; + goto err; + } + + /* Set up input acquisition properties*/ + if (PLTFRM_CAM_ITF_IS_DVP(cam_itf->type)) { + signal = + ((cam_itf->cfg.dvp.pclk == PLTFRM_CAM_SDR_POS_EDG) ? + CIF_ISP_ACQ_PROP_POS_EDGE : CIF_ISP_ACQ_PROP_NEG_EDGE); + + if (PLTFRM_CAM_ITF_IS_BT601(cam_itf->type)) { + signal |= + (cam_itf->cfg.dvp.vsync == + PLTFRM_CAM_SIGNAL_HIGH_LEVEL) ? + CIF_ISP_ACQ_PROP_VSYNC_HIGH : + CIF_ISP_ACQ_PROP_VSYNC_LOW; + + signal |= + (cam_itf->cfg.dvp.hsync == + PLTFRM_CAM_SIGNAL_HIGH_LEVEL) ? + CIF_ISP_ACQ_PROP_HSYNC_HIGH : + CIF_ISP_ACQ_PROP_HSYNC_LOW; + + } else { + signal |= CIF_ISP_ACQ_PROP_HSYNC_HIGH | + CIF_ISP_ACQ_PROP_VSYNC_HIGH; + } + } else { + signal = CIF_ISP_ACQ_PROP_NEG_EDGE | + CIF_ISP_ACQ_PROP_HSYNC_HIGH | + CIF_ISP_ACQ_PROP_VSYNC_HIGH; + } + + cif_iowrite32(signal | + yuv_seq | + CIF_ISP_ACQ_PROP_FIELD_SEL_ALL | + isp_input_sel | + isp_bayer_pat | + (0 << 20), /* input_selection_no_app */ + dev->config.base_addr + CIF_ISP_ACQ_PROP); + cif_iowrite32(0, + dev->config.base_addr + CIF_ISP_ACQ_NR_FRAMES); + + /* Acquisition Size */ + cif_iowrite32(dev->config.isp_config.input->defrect.left, + dev->config.base_addr + CIF_ISP_ACQ_H_OFFS); + cif_iowrite32(dev->config.isp_config.input->defrect.top, + dev->config.base_addr + CIF_ISP_ACQ_V_OFFS); + cif_iowrite32( + acq_mult * dev->config.isp_config.input->defrect.width, + dev->config.base_addr + CIF_ISP_ACQ_H_SIZE); + cif_iowrite32( + dev->config.isp_config.input->defrect.height, + dev->config.base_addr + CIF_ISP_ACQ_V_SIZE); + + /* do cropping to match output aspect ratio */ + ret = cif_isp10_calc_isp_cropping(dev, + &output->width, &output->height, + &h_offs, &v_offs); + if (IS_ERR_VALUE(ret)) + goto err; + + cif_iowrite32(v_offs, + dev->config.base_addr + CIF_ISP_OUT_V_OFFS); + cif_iowrite32(h_offs, + dev->config.base_addr + CIF_ISP_OUT_H_OFFS); + cif_iowrite32(output->width, + dev->config.base_addr + CIF_ISP_OUT_H_SIZE); + cif_iowrite32(output->height, + dev->config.base_addr + CIF_ISP_OUT_V_SIZE); + + dev->isp_dev.input_width = + dev->config.isp_config.input->defrect.width; + dev->isp_dev.input_height = + dev->config.isp_config.input->defrect.height; + + /* interrupt mask */ + irq_mask |= + CIF_ISP_FRAME | + CIF_ISP_PIC_SIZE_ERROR | + CIF_ISP_FRAME_IN | + CIF_ISP_V_START; + cif_iowrite32(irq_mask, + dev->config.base_addr + CIF_ISP_IMSC); + + if (!dev->config.mi_config.raw_enable) + cifisp_configure_isp(&dev->isp_dev, + in_pix_fmt, + output->quantization); + else + cifisp_disable_isp(&dev->isp_dev); + + cif_isp10_pltfrm_pr_dbg( + dev->dev, + "\n ISP_CTRL 0x%08x\n" + " ISP_IMSC 0x%08x\n" + " ISP_ACQ_PROP 0x%08x\n" + " ISP_ACQ %dx%d@(%d,%d)\n" + " ISP_OUT %dx%d@(%d,%d)\n" + " ISP_IS %dx%d@(%d,%d)\n", + cif_ioread32(dev->config.base_addr + CIF_ISP_CTRL), + cif_ioread32(dev->config.base_addr + CIF_ISP_IMSC), + cif_ioread32(dev->config.base_addr + CIF_ISP_ACQ_PROP), + cif_ioread32(dev->config.base_addr + CIF_ISP_ACQ_H_SIZE), + cif_ioread32(dev->config.base_addr + CIF_ISP_ACQ_V_SIZE), + cif_ioread32(dev->config.base_addr + CIF_ISP_ACQ_H_OFFS), + cif_ioread32(dev->config.base_addr + CIF_ISP_ACQ_V_OFFS), + cif_ioread32(dev->config.base_addr + CIF_ISP_OUT_H_SIZE), + cif_ioread32(dev->config.base_addr + CIF_ISP_OUT_V_SIZE), + cif_ioread32(dev->config.base_addr + CIF_ISP_OUT_H_OFFS), + cif_ioread32(dev->config.base_addr + CIF_ISP_OUT_V_OFFS), + cif_ioread32(dev->config.base_addr + CIF_ISP_IS_H_SIZE), + cif_ioread32(dev->config.base_addr + CIF_ISP_IS_V_SIZE), + cif_ioread32(dev->config.base_addr + CIF_ISP_IS_H_OFFS), + cif_ioread32(dev->config.base_addr + CIF_ISP_IS_V_OFFS)); + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_config_mipi( + struct cif_isp10_device *dev) +{ + int ret = 0; + u32 data_type; + u32 mipi_ctrl; + u32 shutdown_lanes; + u32 i; + enum cif_isp10_pix_fmt in_pix_fmt; + + if (!CIF_ISP10_INP_IS_MIPI(dev->config.input_sel)) { + cif_iowrite32AND(~CIF_ICCL_MIPI_CLK, + dev->config.base_addr + CIF_ICCL); + cif_isp10_pltfrm_pr_dbg(NULL, + "MIPI disabled\n"); + return 0; + } + cif_iowrite32OR(CIF_ICCL_MIPI_CLK, + dev->config.base_addr + CIF_ICCL); + + in_pix_fmt = dev->config.img_src_output.frm_fmt.pix_fmt; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "input %s, vc = %d, nb_lanes = %d\n", + cif_isp10_inp_string(dev->config.input_sel), + dev->config.cam_itf.cfg.mipi.vc, + dev->config.cam_itf.cfg.mipi.nb_lanes); + + if ((dev->config.cam_itf.cfg.mipi.nb_lanes == 0) || + (dev->config.cam_itf.cfg.mipi.nb_lanes > 4)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "invalid number (%d) of MIPI lanes, valid range is [1..4]\n", + dev->config.cam_itf.cfg.mipi.nb_lanes); + ret = -EINVAL; + goto err; + } + + shutdown_lanes = 0x00; + for (i = 0; i < dev->config.cam_itf.cfg.mipi.nb_lanes; i++) + shutdown_lanes |= (1 << i); + + mipi_ctrl = + CIF_MIPI_CTRL_NUM_LANES( + dev->config.cam_itf.cfg.mipi.nb_lanes - 1) | + CIF_MIPI_CTRL_ERR_SOT_HS_ENA | + CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | + CIF_MIPI_CTRL_SHUTDOWNLANES(shutdown_lanes) | + CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_ENA | + CIF_MIPI_CTRL_ERR_SOT_HS_ENA | + CIF_MIPI_CTRL_CLOCKLANE_ENA; + + cif_iowrite32(mipi_ctrl, + dev->config.base_addr + CIF_MIPI_CTRL); + + /* mipi_dphy */ + cif_isp10_pltfrm_mipi_dphy_config(dev); + + /* Configure Data Type and Virtual Channel */ + if (CIF_ISP10_PIX_FMT_IS_YUV(in_pix_fmt)) { + if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt) == 12)) + data_type = CSI2_DT_YUV420_8b; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt) == 15)) + data_type = CSI2_DT_YUV420_10b; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 4) && + (CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt) == 16)) + data_type = CSI2_DT_YUV422_8b; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 4) && + (CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt) == 20)) + data_type = CSI2_DT_YUV422_10b; + else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported format %s\n", + cif_isp10_pix_fmt_string(in_pix_fmt)); + ret = -EINVAL; + goto err; + } + } else if (CIF_ISP10_PIX_FMT_IS_RAW_BAYER(in_pix_fmt)) { + if (CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt) == 8) { + data_type = CSI2_DT_RAW8; + } else if (CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt) == 10) { + data_type = CSI2_DT_RAW10; + } else if (CIF_ISP10_PIX_FMT_GET_BPP(in_pix_fmt) == 12) { + data_type = CSI2_DT_RAW12; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported format %s\n", + cif_isp10_pix_fmt_string(in_pix_fmt)); + ret = -EINVAL; + goto err; + } + } else if (in_pix_fmt == CIF_RGB565) { + data_type = CSI2_DT_RGB565; + } else if (in_pix_fmt == CIF_RGB666) { + data_type = CSI2_DT_RGB666; + } else if (in_pix_fmt == CIF_RGB888) { + data_type = CSI2_DT_RGB888; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported format %s\n", + cif_isp10_pix_fmt_string(in_pix_fmt)); + ret = -EINVAL; + goto err; + } + + cif_iowrite32( + CIF_MIPI_DATA_SEL_DT(data_type) | + CIF_MIPI_DATA_SEL_VC( + dev->config.cam_itf.cfg.mipi.vc), + dev->config.base_addr + CIF_MIPI_IMG_DATA_SEL); + + /* Enable MIPI interrupts */ + cif_iowrite32(~0, + dev->config.base_addr + CIF_MIPI_ICR); + /* + * Disable CIF_MIPI_ERR_DPHY interrupt here temporary for + * isp bus may be dead when switch isp. + */ + cif_iowrite32( + CIF_MIPI_FRAME_END | + CIF_MIPI_ERR_CSI | + CIF_MIPI_ERR_DPHY | + CIF_MIPI_SYNC_FIFO_OVFLW(3) | + CIF_MIPI_ADD_DATA_OVFLW, + dev->config.base_addr + CIF_MIPI_IMSC); + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MIPI_CTRL 0x%08x\n" + " MIPI_IMG_DATA_SEL 0x%08x\n" + " MIPI_STATUS 0x%08x\n" + " MIPI_IMSC 0x%08x\n", + cif_ioread32(dev->config.base_addr + CIF_MIPI_CTRL), + cif_ioread32(dev->config.base_addr + CIF_MIPI_IMG_DATA_SEL), + cif_ioread32(dev->config.base_addr + CIF_MIPI_STATUS), + cif_ioread32(dev->config.base_addr + CIF_MIPI_IMSC)); + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_config_mi_mp( + struct cif_isp10_device *dev) +{ + enum cif_isp10_pix_fmt out_pix_fmt = + dev->config.mi_config.mp.output.pix_fmt; + u32 llength = + dev->config.mi_config.mp.llength; + u32 width = + dev->config.mi_config.mp.output.width; + u32 height = + dev->config.mi_config.mp.output.height; + u32 writeformat = CIF_ISP10_BUFF_FMT_PLANAR; + u32 swap_cb_cr = 0; + u32 bpp = CIF_ISP10_PIX_FMT_GET_BPP(out_pix_fmt); + u32 size = llength * height * bpp / 8; + u32 mi_ctrl; + + dev->config.mi_config.mp.input = + &dev->config.mp_config.rsz_config.output; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s %dx%d, llength = %d\n", + cif_isp10_pix_fmt_string(out_pix_fmt), + width, + height, + llength); + + dev->config.mi_config.mp.y_size = size; + dev->config.mi_config.mp.cb_size = 0; + dev->config.mi_config.mp.cr_size = 0; + if (CIF_ISP10_PIX_FMT_IS_YUV(out_pix_fmt)) { + u32 num_cplanes = + CIF_ISP10_PIX_FMT_YUV_GET_NUM_CPLANES(out_pix_fmt); + if (num_cplanes == 0) { + writeformat = CIF_ISP10_BUFF_FMT_INTERLEAVED; + } else { + dev->config.mi_config.mp.y_size = + (dev->config.mi_config.mp.y_size * 4) / + (4 + (CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS( + out_pix_fmt) * + CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS( + out_pix_fmt) / 2)); + dev->config.mi_config.mp.cb_size = + size - + dev->config.mi_config.mp.y_size; + if (num_cplanes == 1) { + writeformat = CIF_ISP10_BUFF_FMT_SEMIPLANAR; + } else if (num_cplanes == 2) { + writeformat = CIF_ISP10_BUFF_FMT_PLANAR; + dev->config.mi_config.mp.cb_size /= 2; + } + /* for U<->V swapping: */ + dev->config.mi_config.mp.cr_size = + dev->config.mi_config.mp.cb_size; + } + if (CIF_ISP10_PIX_FMT_YUV_IS_UV_SWAPPED(out_pix_fmt)) + swap_cb_cr = CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; + + if (writeformat == CIF_ISP10_BUFF_FMT_SEMIPLANAR) { + dev->config.mi_config.mp.cb_offs = + dev->config.mi_config.mp.y_size; + dev->config.mi_config.mp.cr_offs = + dev->config.mi_config.mp.cb_offs; + } else if (writeformat == CIF_ISP10_BUFF_FMT_PLANAR) { + if (swap_cb_cr) { + swap_cb_cr = 0; + dev->config.mi_config.mp.cr_offs = + dev->config.mi_config.mp.y_size; + dev->config.mi_config.mp.cb_offs = + dev->config.mi_config.mp.cr_offs + + dev->config.mi_config.mp.cr_size; + } else { + dev->config.mi_config.mp.cb_offs = + dev->config.mi_config.mp.y_size; + dev->config.mi_config.mp.cr_offs = + dev->config.mi_config.mp.cb_offs + + dev->config.mi_config.mp.cb_size; + } + } + } else if (CIF_ISP10_PIX_FMT_IS_RAW_BAYER(out_pix_fmt)) { + if (CIF_ISP10_PIX_FMT_GET_BPP(out_pix_fmt) > 8) { + writeformat = CIF_ISP10_BUFF_FMT_RAW12; + dev->config.mi_config.mp.y_size = width * height * 2; + } else { + writeformat = CIF_ISP10_BUFF_FMT_RAW8; + dev->config.mi_config.mp.y_size = width * height; + } + dev->config.mi_config.mp.cb_offs = 0x00; + dev->config.mi_config.mp.cr_offs = 0x00; + dev->config.mi_config.mp.cb_size = 0x00; + dev->config.mi_config.mp.cr_size = 0x00; + } + + cif_iowrite32_verify(dev->config.mi_config.mp.y_size, + dev->config.base_addr + CIF_MI_MP_Y_SIZE_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.mp.cb_size, + dev->config.base_addr + CIF_MI_MP_CB_SIZE_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.mp.cr_size, + dev->config.base_addr + CIF_MI_MP_CR_SIZE_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32OR_verify(CIF_MI_MP_FRAME, + dev->config.base_addr + + CIF_MI_IMSC, ~0); + + if (swap_cb_cr) { + cif_iowrite32OR(swap_cb_cr, + dev->config.base_addr + CIF_MI_XTD_FORMAT_CTRL); + } + + mi_ctrl = cif_ioread32(dev->config.base_addr + CIF_MI_CTRL) | + CIF_MI_CTRL_MP_WRITE_FMT(writeformat) | + CIF_MI_CTRL_BURST_LEN_LUM_64 | + CIF_MI_CTRL_BURST_LEN_CHROM_64 | + CIF_MI_CTRL_INIT_BASE_EN | + CIF_MI_CTRL_INIT_OFFSET_EN | + CIF_MI_MP_AUTOUPDATE_ENABLE; + + cif_iowrite32_verify(mi_ctrl, + dev->config.base_addr + CIF_MI_CTRL, ~0); + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_CTRL 0x%08x\n" + " MI_STATUS 0x%08x\n" + " MI_MP_Y_SIZE %d\n" + " MI_MP_CB_SIZE %d\n" + " MI_MP_CR_SIZE %d\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_MI_STATUS), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_SIZE_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_SIZE_INIT)); + + return 0; +} + +static int cif_isp10_config_mi_sp( + struct cif_isp10_device *dev) +{ + int ret = 0; + enum cif_isp10_pix_fmt out_pix_fmt = + dev->config.mi_config.sp.output.pix_fmt; + enum cif_isp10_pix_fmt in_pix_fmt = + dev->config.sp_config.rsz_config.output.pix_fmt; + u32 llength = + dev->config.mi_config.sp.llength; + u32 width = + dev->config.mi_config.sp.output.width; + u32 height = + dev->config.mi_config.sp.output.height; + u32 writeformat = CIF_ISP10_BUFF_FMT_PLANAR; + u32 swap_cb_cr = 0; + u32 bpp = CIF_ISP10_PIX_FMT_GET_BPP(out_pix_fmt); + u32 size = llength * height * bpp / 8; + u32 input_format = 0; + u32 output_format; + u32 mi_ctrl; + + dev->config.mi_config.sp.input = + &dev->config.sp_config.rsz_config.output; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s %dx%d, llength = %d\n", + cif_isp10_pix_fmt_string(out_pix_fmt), + width, + height, + llength); + + if (!CIF_ISP10_PIX_FMT_IS_YUV(in_pix_fmt)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported format %s (must be YUV)\n", + cif_isp10_pix_fmt_string(in_pix_fmt)); + ret = -EINVAL; + goto err; + } + + dev->config.mi_config.sp.y_size = size; + dev->config.mi_config.sp.cb_size = 0; + dev->config.mi_config.sp.cr_size = 0; + if (CIF_ISP10_PIX_FMT_IS_YUV(out_pix_fmt)) { + u32 num_cplanes = + CIF_ISP10_PIX_FMT_YUV_GET_NUM_CPLANES(out_pix_fmt); + if (num_cplanes == 0) { + writeformat = CIF_ISP10_BUFF_FMT_INTERLEAVED; + } else { + dev->config.mi_config.sp.y_size = + (dev->config.mi_config.sp.y_size * 4) / + (4 + (CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS( + out_pix_fmt) * + CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS( + out_pix_fmt) / 2)); + dev->config.mi_config.sp.cb_size = + size - + dev->config.mi_config.sp.y_size; + if (num_cplanes == 1) { + writeformat = CIF_ISP10_BUFF_FMT_SEMIPLANAR; + } else if (num_cplanes == 2) { + writeformat = CIF_ISP10_BUFF_FMT_PLANAR; + dev->config.mi_config.sp.cb_size /= 2; + } + /* for U<->V swapping: */ + dev->config.mi_config.sp.cr_size = + dev->config.mi_config.sp.cb_size; + } + if (CIF_ISP10_PIX_FMT_YUV_IS_UV_SWAPPED(out_pix_fmt)) + swap_cb_cr = CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; + + if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 0) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 0)) + output_format = CIF_MI_CTRL_SP_OUTPUT_FMT_YUV400; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 2)) + output_format = CIF_MI_CTRL_SP_OUTPUT_FMT_YUV420; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 4)) + output_format = CIF_MI_CTRL_SP_OUTPUT_FMT_YUV422; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 4) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 4)) + output_format = CIF_MI_CTRL_SP_OUTPUT_FMT_YUV444; + else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported YUV output format %s\n", + cif_isp10_pix_fmt_string(out_pix_fmt)); + ret = -EINVAL; + goto err; + } + } else if (CIF_ISP10_PIX_FMT_IS_RGB(out_pix_fmt)) { + if (out_pix_fmt == CIF_RGB565) { + output_format = CIF_MI_CTRL_SP_OUTPUT_FMT_RGB565; + } else if (out_pix_fmt == CIF_RGB666) { + output_format = CIF_MI_CTRL_SP_OUTPUT_FMT_RGB666; + } else if (out_pix_fmt == CIF_RGB888) { + output_format = CIF_MI_CTRL_SP_OUTPUT_FMT_RGB888; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported RGB output format %s\n", + cif_isp10_pix_fmt_string(out_pix_fmt)); + ret = -EINVAL; + goto err; + } + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported output format %s\n", + cif_isp10_pix_fmt_string(out_pix_fmt)); + ret = -EINVAL; + goto err; + } + + if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 0) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 0)) + input_format = CIF_MI_CTRL_SP_INPUT_FMT_YUV400; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 2)) + input_format = CIF_MI_CTRL_SP_INPUT_FMT_YUV420; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 4)) + input_format = CIF_MI_CTRL_SP_INPUT_FMT_YUV422; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(in_pix_fmt) == 4) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(in_pix_fmt) == 4)) + input_format = CIF_MI_CTRL_SP_INPUT_FMT_YUV444; + else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported YUV input format %s\n", + cif_isp10_pix_fmt_string(in_pix_fmt)); + ret = -EINVAL; + goto err; + } + + if (writeformat == CIF_ISP10_BUFF_FMT_SEMIPLANAR) { + dev->config.mi_config.sp.cb_offs = + dev->config.mi_config.sp.y_size; + dev->config.mi_config.sp.cr_offs = + dev->config.mi_config.sp.cb_offs; + } else if (writeformat == CIF_ISP10_BUFF_FMT_PLANAR) { + if (swap_cb_cr) { + swap_cb_cr = 0; + dev->config.mi_config.sp.cr_offs = + dev->config.mi_config.sp.y_size; + dev->config.mi_config.sp.cb_offs = + dev->config.mi_config.sp.cr_offs + + dev->config.mi_config.sp.cr_size; + } else { + dev->config.mi_config.sp.cb_offs = + dev->config.mi_config.sp.y_size; + dev->config.mi_config.sp.cr_offs = + dev->config.mi_config.sp.cb_offs + + dev->config.mi_config.sp.cb_size; + } + } + + cif_iowrite32_verify(dev->config.mi_config.sp.y_size, + dev->config.base_addr + CIF_MI_SP_Y_SIZE_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.sp.y_size, + dev->config.base_addr + CIF_MI_SP_Y_PIC_SIZE, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.sp.cb_size, + dev->config.base_addr + CIF_MI_SP_CB_SIZE_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.sp.cr_size, + dev->config.base_addr + CIF_MI_SP_CR_SIZE_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(width, + dev->config.base_addr + CIF_MI_SP_Y_PIC_WIDTH, ~0x3); + cif_iowrite32_verify(height, + dev->config.base_addr + CIF_MI_SP_Y_PIC_HEIGHT, ~0x3); + cif_iowrite32_verify(llength, + dev->config.base_addr + CIF_MI_SP_Y_LLENGTH, ~0x3); + cif_iowrite32OR_verify(CIF_MI_SP_FRAME, + dev->config.base_addr + + CIF_MI_IMSC, ~0); + + if (swap_cb_cr) { + cif_iowrite32OR(swap_cb_cr, + dev->config.base_addr + CIF_MI_XTD_FORMAT_CTRL); + } + + mi_ctrl = cif_ioread32(dev->config.base_addr + CIF_MI_CTRL) | + CIF_MI_CTRL_SP_WRITE_FMT(writeformat) | + input_format | + output_format | + CIF_MI_CTRL_BURST_LEN_LUM_64 | + CIF_MI_CTRL_BURST_LEN_CHROM_64 | + CIF_MI_CTRL_INIT_BASE_EN | + CIF_MI_CTRL_INIT_OFFSET_EN | + CIF_MI_SP_AUTOUPDATE_ENABLE; + cif_iowrite32_verify(mi_ctrl, + dev->config.base_addr + CIF_MI_CTRL, ~0); + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_CTRL 0x%08x\n" + " MI_STATUS 0x%08x\n" + " MI_SP_Y_SIZE %d\n" + " MI_SP_CB_SIZE %d\n" + " MI_SP_CR_SIZE %d\n" + " MI_SP_PIC_WIDTH %d\n" + " MI_SP_PIC_HEIGHT %d\n" + " MI_SP_PIC_LLENGTH %d\n" + " MI_SP_PIC_SIZE %d\n", + cif_ioread32(dev->config.base_addr + CIF_MI_CTRL), + cif_ioread32(dev->config.base_addr + CIF_MI_STATUS), + cif_ioread32(dev->config.base_addr + CIF_MI_SP_Y_SIZE_INIT), + cif_ioread32(dev->config.base_addr + CIF_MI_SP_CB_SIZE_INIT), + cif_ioread32(dev->config.base_addr + CIF_MI_SP_CR_SIZE_INIT), + cif_ioread32(dev->config.base_addr + CIF_MI_SP_Y_PIC_WIDTH), + cif_ioread32(dev->config.base_addr + CIF_MI_SP_Y_PIC_HEIGHT), + cif_ioread32(dev->config.base_addr + CIF_MI_SP_Y_LLENGTH), + cif_ioread32(dev->config.base_addr + CIF_MI_SP_Y_PIC_SIZE)); + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_config_mi_dma( + struct cif_isp10_device *dev) +{ + int ret = 0; + enum cif_isp10_pix_fmt out_pix_fmt = + dev->config.mi_config.dma.output.pix_fmt; + u32 llength = + dev->config.mi_config.dma.llength; + u32 width = + dev->config.mi_config.dma.output.width; + u32 height = + dev->config.mi_config.dma.output.height; + u32 readformat = CIF_ISP10_BUFF_FMT_PLANAR; + u32 bpp = CIF_ISP10_PIX_FMT_GET_BPP(out_pix_fmt); + u32 size = llength * height * bpp / 8; + u32 output_format; + u32 mi_ctrl; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s %dx%d, llength = %d\n", + cif_isp10_pix_fmt_string(out_pix_fmt), + width, + height, + llength); + + dev->config.mi_config.dma.y_size = size; + dev->config.mi_config.dma.cb_size = 0; + dev->config.mi_config.dma.cr_size = 0; + if (CIF_ISP10_PIX_FMT_IS_YUV(out_pix_fmt)) { + u32 num_cplanes = + CIF_ISP10_PIX_FMT_YUV_GET_NUM_CPLANES(out_pix_fmt); + if (num_cplanes == 0) { + readformat = CIF_ISP10_BUFF_FMT_INTERLEAVED; + } else { + dev->config.mi_config.dma.y_size = + (dev->config.mi_config.dma.y_size * 4) / + (4 + (CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS( + out_pix_fmt) * + CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS( + out_pix_fmt) / 2)); + dev->config.mi_config.dma.cb_size = + size - + dev->config.mi_config.dma.y_size; + if (num_cplanes == 1) { + readformat = CIF_ISP10_BUFF_FMT_SEMIPLANAR; + } else if (num_cplanes == 2) { + readformat = CIF_ISP10_BUFF_FMT_PLANAR; + dev->config.mi_config.dma.cb_size /= 2; + } + /* for U<->V swapping: */ + dev->config.mi_config.dma.cr_size = + dev->config.mi_config.dma.cb_size; + } + + if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 0) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 0)) + output_format = CIF_MI_DMA_CTRL_FMT_YUV400; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 2)) + output_format = CIF_MI_DMA_CTRL_FMT_YUV420; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 2) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 4)) + output_format = CIF_MI_DMA_CTRL_FMT_YUV422; + else if ((CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(out_pix_fmt) == 4) && + (CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(out_pix_fmt) == 4)) + output_format = CIF_MI_DMA_CTRL_FMT_YUV444; + else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported YUV output format %s\n", + cif_isp10_pix_fmt_string(out_pix_fmt)); + ret = -EINVAL; + goto err; + } + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "unsupported output format %s\n", + cif_isp10_pix_fmt_string(out_pix_fmt)); + ret = -EINVAL; + goto err; + } + + if (readformat == CIF_ISP10_BUFF_FMT_SEMIPLANAR) { + dev->config.mi_config.dma.cb_offs = + dev->config.mi_config.dma.y_size; + dev->config.mi_config.dma.cr_offs = + dev->config.mi_config.dma.cb_offs; + } else if (readformat == CIF_ISP10_BUFF_FMT_PLANAR) { + dev->config.mi_config.dma.cb_offs = + dev->config.mi_config.dma.y_size; + dev->config.mi_config.dma.cr_offs = + dev->config.mi_config.dma.cb_offs + + dev->config.mi_config.dma.cb_size; + } + + cif_iowrite32_verify(dev->config.mi_config.dma.y_size, + dev->config.base_addr + CIF_MI_DMA_Y_PIC_SIZE, ~0x3); + cif_iowrite32_verify(width, + dev->config.base_addr + CIF_MI_DMA_Y_PIC_WIDTH, ~0x3); + cif_iowrite32_verify(llength, + dev->config.base_addr + CIF_MI_DMA_Y_LLENGTH, ~0x3); + + mi_ctrl = cif_ioread32(dev->config.base_addr + CIF_MI_DMA_CTRL) | + CIF_MI_DMA_CTRL_READ_FMT(readformat) | + output_format | + CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 | + CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64; + cif_iowrite32_verify(mi_ctrl, + dev->config.base_addr + CIF_MI_DMA_CTRL, ~0); + + cif_iowrite32OR_verify(CIF_MI_DMA_READY, + dev->config.base_addr + CIF_MI_IMSC, ~0); + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_DMA_CTRL 0x%08x\n" + " MI_DMA_STATUS 0x%08x\n" + " MI_DMA_Y_PIC_WIDTH %d\n" + " MI_DMA_Y_LLENGTH %d\n" + " MI_DMA_Y_PIC_SIZE %d\n" + " MI_DMA_Y_PIC_START_AD %d\n" + " MI_DMA_CB_PIC_START_AD %d\n" + " MI_DMA_CR_PIC_START_AD %d\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_STATUS), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_Y_PIC_WIDTH), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_Y_LLENGTH), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_Y_PIC_SIZE), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_Y_PIC_START_AD), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_CB_PIC_START_AD), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_CR_PIC_START_AD)); + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_config_jpeg_enc( + struct cif_isp10_device *dev) +{ + struct cif_isp10_frm_fmt *inp_fmt = + &dev->config.mp_config.rsz_config.output; + dev->config.jpeg_config.input = inp_fmt; + + cif_isp10_pltfrm_pr_dbg(NULL, + "%s %dx%d\n", + cif_isp10_pix_fmt_string(inp_fmt->pix_fmt), + inp_fmt->width, inp_fmt->height); + + /* + * Reset JPEG-Encoder. In contrast to other software + * resets this triggers the modules asynchronous reset + * resulting in loss of all data + */ + cif_iowrite32OR(CIF_IRCL_JPEG_SW_RST, + dev->config.base_addr + CIF_IRCL); + cif_iowrite32AND(~CIF_IRCL_JPEG_SW_RST, + dev->config.base_addr + CIF_IRCL); + + cif_iowrite32(CIF_JPE_ERROR_MASK, + dev->config.base_addr + CIF_JPE_ERROR_IMSC); + + /* Set configuration for the Jpeg capturing */ + cif_iowrite32(inp_fmt->width, + dev->config.base_addr + CIF_JPE_ENC_HSIZE); + cif_iowrite32(inp_fmt->height, + dev->config.base_addr + CIF_JPE_ENC_VSIZE); + + if (CIF_ISP10_INP_IS_DMA(dev->config.input_sel) || + !CIF_ISP10_PIX_FMT_IS_RAW_BAYER( + dev->config.isp_config.input->pix_fmt)) { + /* + * upscaling of BT601 color space to full range 0..255 + * TODO: DMA or YUV sensor input in full range. + */ + cif_iowrite32(CIF_JPE_LUM_SCALE_ENABLE, + dev->config.base_addr + CIF_JPE_Y_SCALE_EN); + cif_iowrite32(CIF_JPE_CHROM_SCALE_ENABLE, + dev->config.base_addr + CIF_JPE_CBCR_SCALE_EN); + } + + switch (inp_fmt->pix_fmt) { + case CIF_YUV422I: + case CIF_YVU422I: + case CIF_YUV422SP: + case CIF_YVU422SP: + case CIF_YUV422P: + case CIF_YVU422P: + cif_iowrite32(CIF_JPE_PIC_FORMAT_YUV422, + dev->config.base_addr + CIF_JPE_PIC_FORMAT); + break; + case CIF_YUV400: + case CIF_YVU400: + cif_iowrite32(CIF_JPE_PIC_FORMAT_YUV400, + dev->config.base_addr + CIF_JPE_PIC_FORMAT); + break; + default: + cif_isp10_pltfrm_pr_err(NULL, + "format %s not supported as input for JPEG encoder\n", + cif_isp10_pix_fmt_string(inp_fmt->pix_fmt)); + WARN_ON(1); + break; + } + + /* + * Set to normal operation (wait for encoded image data + * to fill output buffer) + */ + cif_iowrite32(0, dev->config.base_addr + CIF_JPE_TABLE_FLUSH); + + /* + * CIF Spec 4.7 + * 3.14 JPEG Encoder Programming + * Do not forget to re-program all AC and DC tables + * after system reset as well as after + * module software reset because after any reset + * the internal RAM is filled with FFH which + * is an illegal symbol. This filling takes + * approximately 400 clock cycles. So do not start + * any table programming during the first 400 clock + * cycles after reset is de-asserted. + * Note: depends on CIF clock setting + * 400 clock cycles at 312 Mhz CIF clock-> 1.3 us + * 400 clock cycles at 208 Mhz CIF clock-> 1.93 us + * -> 2us ok for both + */ + udelay(2); + + /* Program JPEG tables */ + cif_isp10_program_jpeg_tables(dev); + /* Select JPEG tables */ + cif_isp10_select_jpeg_tables(dev); + + switch (dev->config.jpeg_config.header) { + case CIF_ISP10_JPEG_HEADER_JFIF: + cif_isp10_pltfrm_pr_dbg(NULL, + "generate JFIF header\n"); + cif_iowrite32(CIF_JPE_HEADER_MODE_JFIF, + dev->config.base_addr + + CIF_JPE_HEADER_MODE); + break; + case CIF_ISP10_JPEG_HEADER_NONE: + cif_isp10_pltfrm_pr_dbg(NULL, + "generate no JPEG header\n"); + cif_iowrite32(CIF_JPE_HEADER_MODE_NOAPPN, + dev->config.base_addr + + CIF_JPE_HEADER_MODE); + break; + default: + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupport JPEG header type %d\n", + dev->config.jpeg_config.header); + WARN_ON(1); + break; + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n JPE_PIC_FORMAT 0x%08x\n" + " JPE_ENC_HSIZE %d\n" + " JPE_ENC_VSIZE %d\n" + " JPE_Y_SCALE_EN 0x%08x\n" + " JPE_CBCR_SCALE_EN 0x%08x\n" + " JPE_ERROR_RIS 0x%08x\n" + " JPE_ERROR_IMSC 0x%08x\n" + " JPE_STATUS_RIS 0x%08x\n" + " JPE_STATUS_IMSC 0x%08x\n" + " JPE_DEBUG 0x%08x\n", + cif_ioread32(dev->config.base_addr + CIF_JPE_PIC_FORMAT), + cif_ioread32(dev->config.base_addr + CIF_JPE_ENC_HSIZE), + cif_ioread32(dev->config.base_addr + CIF_JPE_ENC_VSIZE), + cif_ioread32(dev->config.base_addr + CIF_JPE_Y_SCALE_EN), + cif_ioread32(dev->config.base_addr + CIF_JPE_CBCR_SCALE_EN), + cif_ioread32(dev->config.base_addr + CIF_JPE_ERROR_RIS), + cif_ioread32(dev->config.base_addr + CIF_JPE_ERROR_IMSC), + cif_ioread32(dev->config.base_addr + CIF_JPE_STATUS_RIS), + cif_ioread32(dev->config.base_addr + CIF_JPE_STATUS_IMSC), + cif_ioread32(dev->config.base_addr + CIF_JPE_DEBUG)); + + return 0; +} + +static int cif_isp10_config_path( + struct cif_isp10_device *dev, + u32 stream_ids) +{ + u32 dpcl = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, "\n"); + + /* if_sel */ + if (dev->config.input_sel == CIF_ISP10_INP_DMA) { + dpcl |= CIF_VI_DPCL_DMA_SW_ISP; + } else if (dev->config.input_sel == CIF_ISP10_INP_DMA_IE) { + dpcl |= CIF_VI_DPCL_DMA_IE_MUX_DMA | + CIF_VI_DPCL_DMA_SW_IE; + } else if (dev->config.input_sel == CIF_ISP10_INP_DMA_SP) { + dpcl |= CIF_VI_DPCL_DMA_SP_MUX_DMA; + } else { + if (PLTFRM_CAM_ITF_IS_DVP(dev->config.cam_itf.type)) { + dpcl |= CIF_VI_DPCL_IF_SEL_PARALLEL; + } else if (PLTFRM_CAM_ITF_IS_MIPI(dev->config.cam_itf.type)) { + dpcl |= CIF_VI_DPCL_IF_SEL_MIPI; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "Sensor Interface: 0x%x isn't support\n", + dev->config.cam_itf.type); + return -EINVAL; + } + } + + /* chan_mode */ + if (stream_ids & CIF_ISP10_STREAM_SP) + dpcl |= CIF_VI_DPCL_CHAN_MODE_SP; + + if ((stream_ids & CIF_ISP10_STREAM_MP) && + !(dev->config.input_sel == CIF_ISP10_INP_DMA_SP)) { + dpcl |= CIF_VI_DPCL_CHAN_MODE_MP; + /* mp_dmux */ + if (dev->config.jpeg_config.enable) + dpcl |= CIF_VI_DPCL_MP_MUX_MRSZ_JPEG; + else + dpcl |= CIF_VI_DPCL_MP_MUX_MRSZ_MI; + } + + cif_iowrite32(dpcl, + dev->config.base_addr + CIF_VI_DPCL); + + cif_isp10_pltfrm_pr_dbg(dev->dev, "CIF_DPCL 0x%08x\n", dpcl); + + return 0; +} + +int cif_isp10_config_dcrop( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + bool async) +{ + unsigned int dc_ctrl = cif_ioread32( + dev->config.base_addr + + CIF_DUAL_CROP_CTRL); + + if (stream_id == CIF_ISP10_STREAM_MP) { + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_M_H_OFFS); + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_M_V_OFFS); + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_M_H_SIZE); + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_M_V_SIZE); + + dc_ctrl |= CIF_DUAL_CROP_MP_MODE_BYPASS; + if (async) + dc_ctrl |= CIF_DUAL_CROP_GEN_CFG_UPD; + else + dc_ctrl |= CIF_DUAL_CROP_CFG_UPD; + + cif_iowrite32(dc_ctrl, + dev->config.base_addr + CIF_DUAL_CROP_CTRL); + } else if (stream_id == CIF_ISP10_STREAM_SP) { + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_S_H_OFFS); + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_S_V_OFFS); + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_S_H_SIZE); + cif_iowrite32(0, dev->config.base_addr + + CIF_DUAL_CROP_S_V_SIZE); + + dc_ctrl |= CIF_DUAL_CROP_MP_MODE_BYPASS; + if (async) + dc_ctrl |= CIF_DUAL_CROP_GEN_CFG_UPD; + else + dc_ctrl |= CIF_DUAL_CROP_CFG_UPD; + + cif_iowrite32(dc_ctrl, + dev->config.base_addr + CIF_DUAL_CROP_CTRL); + } + + return 0; +} + +int cif_isp10_config_rsz( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + bool async) +{ + int ret; + u32 i; + CIF_ISP10_PLTFRM_MEM_IO_ADDR scale_h_y_addr = + dev->config.base_addr; + CIF_ISP10_PLTFRM_MEM_IO_ADDR scale_h_cr_addr = + dev->config.base_addr; + CIF_ISP10_PLTFRM_MEM_IO_ADDR scale_h_cb_addr = + dev->config.base_addr; + CIF_ISP10_PLTFRM_MEM_IO_ADDR scale_v_y_addr = + dev->config.base_addr; + CIF_ISP10_PLTFRM_MEM_IO_ADDR scale_v_c_addr = + dev->config.base_addr; + CIF_ISP10_PLTFRM_MEM_IO_ADDR rsz_ctrl_addr = + dev->config.base_addr; + struct cif_isp10_frm_fmt *rsz_input; + struct cif_isp10_frm_fmt *rsz_output; + struct cif_isp10_frm_fmt *mi_output; + u32 rsz_ctrl; + u32 input_width_y; + u32 output_width_y; + u32 input_height_y; + u32 output_height_y; + u32 input_width_c; + u32 output_width_c; + u32 input_height_c; + u32 output_height_c; + u32 scale_h_c; + + if (stream_id == CIF_ISP10_STREAM_MP) { + rsz_ctrl_addr += CIF_MRSZ_CTRL; + scale_h_y_addr += CIF_MRSZ_SCALE_HY; + scale_v_y_addr += CIF_MRSZ_SCALE_VY; + scale_h_cb_addr += CIF_MRSZ_SCALE_HCB; + scale_h_cr_addr += CIF_MRSZ_SCALE_HCR; + scale_v_c_addr += CIF_MRSZ_SCALE_VC; + dev->config.mp_config.rsz_config.input = + &dev->config.isp_config.output; + rsz_input = dev->config.mp_config.rsz_config.input; + rsz_output = &dev->config.mp_config.rsz_config.output; + mi_output = &dev->config.mi_config.mp.output; + /* No phase offset */ + cif_iowrite32(0, dev->config.base_addr + CIF_MRSZ_PHASE_HY); + cif_iowrite32(0, dev->config.base_addr + CIF_MRSZ_PHASE_HC); + cif_iowrite32(0, dev->config.base_addr + CIF_MRSZ_PHASE_VY); + cif_iowrite32(0, dev->config.base_addr + CIF_MRSZ_PHASE_VC); + /* Linear interpolation */ + for (i = 0; i < 64; i++) { + cif_iowrite32(i, + dev->config.base_addr + + CIF_MRSZ_SCALE_LUT_ADDR); + cif_iowrite32(i, + dev->config.base_addr + + CIF_MRSZ_SCALE_LUT); + } + } else { + rsz_ctrl_addr += CIF_SRSZ_CTRL; + scale_h_y_addr += CIF_SRSZ_SCALE_HY; + scale_v_y_addr += CIF_SRSZ_SCALE_VY; + scale_h_cb_addr += CIF_SRSZ_SCALE_HCB; + scale_h_cr_addr += CIF_SRSZ_SCALE_HCR; + scale_v_c_addr += CIF_SRSZ_SCALE_VC; + if (dev->config.input_sel == CIF_ISP10_INP_DMA_SP) + dev->config.sp_config.rsz_config.input = + &dev->config.mi_config.dma.output; + else + dev->config.sp_config.rsz_config.input = + &dev->config.isp_config.output; + + rsz_input = dev->config.sp_config.rsz_config.input; + rsz_output = &dev->config.sp_config.rsz_config.output; + mi_output = &dev->config.mi_config.sp.output; + /* No phase offset */ + cif_iowrite32(0, dev->config.base_addr + CIF_SRSZ_PHASE_HY); + cif_iowrite32(0, dev->config.base_addr + CIF_SRSZ_PHASE_HC); + cif_iowrite32(0, dev->config.base_addr + CIF_SRSZ_PHASE_VY); + cif_iowrite32(0, dev->config.base_addr + CIF_SRSZ_PHASE_VC); + /* Linear interpolation */ + for (i = 0; i < 64; i++) { + cif_iowrite32(i, + dev->config.base_addr + + CIF_SRSZ_SCALE_LUT_ADDR); + cif_iowrite32(i, + dev->config.base_addr + + CIF_SRSZ_SCALE_LUT); + } + } + + /* set RSZ input and output */ + rsz_output->width = mi_output->width; + rsz_output->height = mi_output->height; + rsz_output->pix_fmt = rsz_input->pix_fmt; + if (CIF_ISP10_PIX_FMT_IS_YUV(mi_output->pix_fmt)) { + cif_isp10_pix_fmt_set_y_subs( + rsz_output->pix_fmt, + CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(mi_output->pix_fmt)); + cif_isp10_pix_fmt_set_x_subs( + rsz_output->pix_fmt, + CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(mi_output->pix_fmt)); + cif_isp10_pix_fmt_set_bpp( + rsz_output->pix_fmt, + CIF_ISP10_PIX_FMT_GET_BPP(mi_output->pix_fmt)); + } else if (CIF_ISP10_PIX_FMT_IS_JPEG(mi_output->pix_fmt)) { + cif_isp10_pix_fmt_set_y_subs( + rsz_output->pix_fmt, 4); + cif_isp10_pix_fmt_set_x_subs( + rsz_output->pix_fmt, 2); + cif_isp10_pix_fmt_set_bpp( + rsz_output->pix_fmt, 16); + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s %s %dx%d -> %s %dx%d\n", + cif_isp10_stream_id_string(stream_id), + cif_isp10_pix_fmt_string(rsz_input->pix_fmt), + rsz_input->width, + rsz_input->height, + cif_isp10_pix_fmt_string(rsz_output->pix_fmt), + rsz_output->width, + rsz_output->height); + + /* set input and output sizes for scale calculation */ + input_width_y = rsz_input->width; + output_width_y = rsz_output->width; + input_height_y = rsz_input->height; + output_height_y = rsz_output->height; + input_width_c = input_width_y; + output_width_c = output_width_y; + input_height_c = input_height_y; + output_height_c = output_height_y; + + if (CIF_ISP10_PIX_FMT_IS_YUV(rsz_output->pix_fmt)) { + input_width_c = (input_width_c * + CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS( + rsz_input->pix_fmt)) / 4; + input_height_c = (input_height_c * + CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS( + rsz_input->pix_fmt)) / 4; + output_width_c = (output_width_c * + CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS( + rsz_output->pix_fmt)) / 4; + output_height_c = (output_height_c * + CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS( + rsz_output->pix_fmt)) / 4; + + cif_isp10_pltfrm_pr_dbg(NULL, + "chroma scaling %dx%d -> %dx%d\n", + input_width_c, input_height_c, + output_width_c, output_height_c); + + if (((input_width_c == 0) && (output_width_c > 0)) || + ((input_height_c == 0) && (output_height_c > 0))) { + cif_isp10_pltfrm_pr_err(NULL, + "input is black and white, cannot output colour\n"); + ret = -EINVAL; + goto err; + } + } else { + if ((input_width_y != output_width_y) || + (input_height_y != output_height_y)) { + cif_isp10_pltfrm_pr_err(NULL, + "%dx%d -> %dx%d isn't support, can only scale YUV input\n", + input_width_y, input_height_y, + output_width_y, output_height_y); + ret = -EINVAL; + goto err; + } + } + + /* calculate and set scale */ + rsz_ctrl = 0; + if (input_width_y < output_width_y) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HY_ENABLE | + CIF_RSZ_CTRL_SCALE_HY_UP; + cif_iowrite32( + DIV_TRUNCATE((input_width_y - 1) + * CIF_RSZ_SCALER_BYPASS, + output_width_y - 1), + scale_h_y_addr); + } else if (input_width_y > output_width_y) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HY_ENABLE; + cif_iowrite32( + DIV_TRUNCATE((output_width_y - 1) + * CIF_RSZ_SCALER_BYPASS, + input_width_y - 1) + 1, + scale_h_y_addr); + } + if (input_width_c < output_width_c) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HC_ENABLE | + CIF_RSZ_CTRL_SCALE_HC_UP; + scale_h_c = DIV_TRUNCATE((input_width_c - 1) + * CIF_RSZ_SCALER_BYPASS, + output_width_c - 1); + cif_iowrite32(scale_h_c, scale_h_cb_addr); + cif_iowrite32(scale_h_c, scale_h_cr_addr); + } else if (input_width_c > output_width_c) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HC_ENABLE; + scale_h_c = DIV_TRUNCATE((output_width_c - 1) + * CIF_RSZ_SCALER_BYPASS, + input_width_c - 1) + 1; + cif_iowrite32(scale_h_c, scale_h_cb_addr); + cif_iowrite32(scale_h_c, scale_h_cr_addr); + } + + if (input_height_y < output_height_y) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VY_ENABLE | + CIF_RSZ_CTRL_SCALE_VY_UP; + cif_iowrite32( + DIV_TRUNCATE((input_height_y - 1) + * CIF_RSZ_SCALER_BYPASS, + output_height_y - 1), + scale_v_y_addr); + } else if (input_height_y > output_height_y) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VY_ENABLE; + cif_iowrite32( + DIV_TRUNCATE((output_height_y - 1) + * CIF_RSZ_SCALER_BYPASS, + input_height_y - 1) + 1, + scale_v_y_addr); + } + + if (input_height_c < output_height_c) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VC_ENABLE | + CIF_RSZ_CTRL_SCALE_VC_UP; + cif_iowrite32( + DIV_TRUNCATE((input_height_c - 1) + * CIF_RSZ_SCALER_BYPASS, + output_height_c - 1), + scale_v_c_addr); + } else if (input_height_c > output_height_c) { + rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VC_ENABLE; + cif_iowrite32( + DIV_TRUNCATE((output_height_c - 1) + * CIF_RSZ_SCALER_BYPASS, + input_height_c - 1) + 1, + scale_v_c_addr); + } + + cif_iowrite32(rsz_ctrl, rsz_ctrl_addr); + + if (stream_id == CIF_ISP10_STREAM_MP) { + if (async) + cif_iowrite32OR(CIF_RSZ_CTRL_CFG_UPD, + dev->config.base_addr + CIF_MRSZ_CTRL); + dev->config.mp_config.rsz_config.ycflt_adjust = false; + dev->config.mp_config.rsz_config.ism_adjust = false; + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MRSZ_CTRL 0x%08x/0x%08x\n" + " MRSZ_SCALE_HY %d/%d\n" + " MRSZ_SCALE_HCB %d/%d\n" + " MRSZ_SCALE_HCR %d/%d\n" + " MRSZ_SCALE_VY %d/%d\n" + " MRSZ_SCALE_VC %d/%d\n" + " MRSZ_PHASE_HY %d/%d\n" + " MRSZ_PHASE_HC %d/%d\n" + " MRSZ_PHASE_VY %d/%d\n" + " MRSZ_PHASE_VC %d/%d\n", + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_CTRL_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCB), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCB_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCR), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_HCR_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VC), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_SCALE_VC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HC), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_HC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VY), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VC), + cif_ioread32(dev->config.base_addr + + CIF_MRSZ_PHASE_VC_SHD)); + } else { + if (async) + cif_iowrite32OR(CIF_RSZ_CTRL_CFG_UPD, + dev->config.base_addr + CIF_SRSZ_CTRL); + dev->config.sp_config.rsz_config.ycflt_adjust = false; + dev->config.sp_config.rsz_config.ism_adjust = false; + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n SRSZ_CTRL 0x%08x/0x%08x\n" + " SRSZ_SCALE_HY %d/%d\n" + " SRSZ_SCALE_HCB %d/%d\n" + " SRSZ_SCALE_HCR %d/%d\n" + " SRSZ_SCALE_VY %d/%d\n" + " SRSZ_SCALE_VC %d/%d\n" + " SRSZ_PHASE_HY %d/%d\n" + " SRSZ_PHASE_HC %d/%d\n" + " SRSZ_PHASE_VY %d/%d\n" + " SRSZ_PHASE_VC %d/%d\n", + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_CTRL_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCB), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCB_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCR), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_HCR_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VC), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_SCALE_VC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HC), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_HC_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VY), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VY_SHD), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VC), + cif_ioread32(dev->config.base_addr + + CIF_SRSZ_PHASE_VC_SHD)); + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +static int cif_isp10_config_sp( + struct cif_isp10_device *dev) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + ret = cif_isp10_config_rsz(dev, CIF_ISP10_STREAM_SP, true); + if (IS_ERR_VALUE(ret)) + goto err; + + ret = cif_isp10_config_dcrop(dev, CIF_ISP10_STREAM_SP, true); + if (IS_ERR_VALUE(ret)) + goto err; + + ret = cif_isp10_config_mi_sp(dev); + if (IS_ERR_VALUE(ret)) + goto err; + + dev->sp_stream.updt_cfg = false; + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_config_mp( + struct cif_isp10_device *dev) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + ret = cif_isp10_config_rsz(dev, CIF_ISP10_STREAM_MP, true); + if (IS_ERR_VALUE(ret)) + goto err; + + ret = cif_isp10_config_dcrop(dev, CIF_ISP10_STREAM_MP, true); + if (IS_ERR_VALUE(ret)) + goto err; + + ret = cif_isp10_config_mi_mp(dev); + if (IS_ERR_VALUE(ret)) + goto err; + if (dev->config.jpeg_config.enable) { + ret = cif_isp10_config_jpeg_enc(dev); + if (IS_ERR_VALUE(ret)) + goto err; + dev->config.jpeg_config.busy = false; + } + + dev->mp_stream.updt_cfg = false; + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static void cif_isp10_config_clk( + struct cif_isp10_device *dev) +{ + cif_iowrite32(CIF_CCL_CIF_CLK_ENA, + dev->config.base_addr + CIF_CCL); + cif_iowrite32(0x0000187B, dev->config.base_addr + CIF_ICCL); + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n CIF_CCL 0x%08x\n" + " CIF_ICCL 0x%08x\n", + cif_ioread32(dev->config.base_addr + CIF_CCL), + cif_ioread32(dev->config.base_addr + CIF_ICCL)); +} + +static int cif_isp10_config_cif( + struct cif_isp10_device *dev, + u32 stream_ids) +{ + int ret = 0; + u32 cif_id; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "config MP = %d, config SP = %d, img_src state = %s, PM state = %s, SP state = %s, MP state = %s\n", + (stream_ids & CIF_ISP10_STREAM_MP) == CIF_ISP10_STREAM_MP, + (stream_ids & CIF_ISP10_STREAM_SP) == CIF_ISP10_STREAM_SP, + cif_isp10_img_src_state_string(dev->img_src_state), + cif_isp10_pm_state_string(dev->pm_state), + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state)); + + cif_isp10_pltfrm_rtrace_printf(NULL, + "start configuring CIF...\n"); + + if ((stream_ids & CIF_ISP10_STREAM_MP) || + (stream_ids & CIF_ISP10_STREAM_SP)) { + ret = cif_isp10_set_pm_state(dev, + CIF_ISP10_PM_STATE_SW_STNDBY); + if (IS_ERR_VALUE(ret)) + goto err; + + if (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel)) { + /* configure sensor */ + ret = cif_isp10_config_img_src(dev); + if (IS_ERR_VALUE(ret)) + goto err; + } + + cif_id = cif_ioread32(dev->config.base_addr + CIF_VI_ID); + dev->config.out_of_buffer_stall = + CIF_ISP10_ALWAYS_STALL_ON_NO_BUFS; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "CIF_ID 0x%08x\n", cif_id); + + /* + * Cancel isp reset internal here temporary for + * isp bus may be dead when switch isp. + */ + /* + * cif_iowrite32(CIF_IRCL_CIF_SW_RST, + * dev->config.base_addr + CIF_IRCL); + */ + + cif_isp10_config_clk(dev); + + /* Decide when to switch to asynchronous mode */ + /* + * TODO: remove dev->isp_dev.ycflt_en check for + * HW with the scaler fix. + */ + dev->config.mi_config.async_updt = CIF_ISP10_ALWAYS_ASYNC; + if (CIF_ISP10_INP_IS_DMA(dev->config.input_sel)) { + dev->config.mi_config.async_updt |= CIF_ISP10_ASYNC_DMA; + ret = cif_isp10_config_mi_dma(dev); + if (IS_ERR_VALUE(ret)) + goto err; + } + if ((stream_ids & CIF_ISP10_STREAM_MP) && + (dev->config.jpeg_config.enable)) + dev->config.mi_config.async_updt |= + CIF_ISP10_ASYNC_JPEG; + if (dev->config.isp_config.ism_config.ism_en) + dev->config.mi_config.async_updt |= + CIF_ISP10_ASYNC_ISM; + + if (PLTFRM_CAM_ITF_IS_MIPI(dev->config.cam_itf.type)) { + ret = cif_isp10_config_mipi(dev); + if (IS_ERR_VALUE(ret)) + goto err; + } + + ret = cif_isp10_config_isp(dev); + if (IS_ERR_VALUE(ret)) + goto err; + + cif_isp10_config_ism(dev, true); + dev->config.isp_config.ism_config.ism_update_needed = false; + + if (stream_ids & CIF_ISP10_STREAM_SP) + dev->config.sp_config.rsz_config.ism_adjust = true; + if (stream_ids & CIF_ISP10_STREAM_MP) + dev->config.mp_config.rsz_config.ism_adjust = true; + + if (stream_ids & CIF_ISP10_STREAM_SP) { + ret = cif_isp10_config_sp(dev); + if (IS_ERR_VALUE(ret)) + goto err; + } + + if (stream_ids & CIF_ISP10_STREAM_MP) { + ret = cif_isp10_config_mp(dev); + if (IS_ERR_VALUE(ret)) + goto err; + } + ret = cif_isp10_config_path(dev, stream_ids); + if (IS_ERR_VALUE(ret)) + goto err; + } + + /* Turn off XNR vertical subsampling when ism cropping is enabled */ + if (dev->config.isp_config.ism_config.ism_en) { + if (!dev->isp_dev.cif_ism_cropping) + dev->isp_dev.cif_ism_cropping = true; + } else { + if (dev->isp_dev.cif_ism_cropping) + dev->isp_dev.cif_ism_cropping = false; + } + + if (dev->config.sp_config.rsz_config.ycflt_adjust || + dev->config.sp_config.rsz_config.ism_adjust) { + if (dev->sp_stream.state == CIF_ISP10_STATE_READY) { + ret = cif_isp10_config_rsz(dev, + CIF_ISP10_STREAM_SP, true); + if (IS_ERR_VALUE(ret)) + goto err; + } else { + /* Disable SRSZ if SP is not used */ + cif_iowrite32(0, dev->config.base_addr + CIF_SRSZ_CTRL); + cif_iowrite32OR(CIF_RSZ_CTRL_CFG_UPD, + dev->config.base_addr + CIF_SRSZ_CTRL); + dev->config.sp_config.rsz_config.ycflt_adjust = false; + dev->config.sp_config.rsz_config.ism_adjust = false; + } + } + + if (dev->config.mp_config.rsz_config.ycflt_adjust || + dev->config.mp_config.rsz_config.ism_adjust) { + if (dev->mp_stream.state == CIF_ISP10_STATE_READY) { + ret = cif_isp10_config_rsz(dev, + CIF_ISP10_STREAM_MP, true); + if (IS_ERR_VALUE(ret)) + goto err; + } else { + /* Disable MRSZ if MP is not used */ + cif_iowrite32(0, dev->config.base_addr + CIF_MRSZ_CTRL); + cif_iowrite32OR(CIF_RSZ_CTRL_CFG_UPD, + dev->config.base_addr + CIF_MRSZ_CTRL); + dev->config.mp_config.rsz_config.ycflt_adjust = false; + dev->config.mp_config.rsz_config.ism_adjust = false; + } + } + + if (dev->config.mi_config.async_updt) + cif_isp10_pltfrm_pr_dbg(dev->dev, + "CIF in asynchronous mode (0x%08x)\n", + dev->config.mi_config.async_updt); + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static void cif_isp10_init_stream( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id) +{ + struct cif_isp10_stream *stream = NULL; + + switch (stream_id) { + case CIF_ISP10_STREAM_SP: + stream = &dev->sp_stream; + dev->config.sp_config.rsz_config.ycflt_adjust = false; + dev->config.sp_config.rsz_config.ism_adjust = false; + dev->config.mi_config.sp.busy = false; + break; + case CIF_ISP10_STREAM_MP: + stream = &dev->mp_stream; + dev->config.jpeg_config.ratio = 50; + dev->config.jpeg_config.header = + CIF_ISP10_JPEG_HEADER_JFIF; + dev->config.jpeg_config.enable = false; + dev->config.mi_config.raw_enable = false; + dev->config.mp_config.rsz_config.ycflt_adjust = false; + dev->config.mp_config.rsz_config.ism_adjust = false; + dev->config.mi_config.mp.busy = false; + break; + case CIF_ISP10_STREAM_DMA: + stream = &dev->dma_stream; + dev->config.mi_config.dma.busy = false; + break; + default: + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported stream ID %d\n", stream_id); + WARN_ON(1); + break; + } + + INIT_LIST_HEAD(&stream->buf_queue); + stream->next_buf = NULL; + stream->curr_buf = NULL; + stream->updt_cfg = false; + stream->stop = false; + stream->stall = false; + + cif_isp10_pltfrm_event_clear(dev->dev, &stream->done); + stream->state = CIF_ISP10_STATE_INACTIVE; +} + +static int cif_isp10_jpeg_gen_header( + struct cif_isp10_device *dev) +{ + unsigned int timeout = 10000; + + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + cif_iowrite32(CIF_JPE_GEN_HEADER_ENABLE, + dev->config.base_addr + CIF_JPE_GEN_HEADER); + + while (timeout--) { + if (cif_ioread32(dev->config.base_addr + + CIF_JPE_STATUS_RIS) & + CIF_JPE_STATUS_GENHEADER_DONE) { + cif_isp10_pltfrm_pr_dbg(NULL, + "JPEG header generated\n"); + cif_iowrite32(CIF_JPE_STATUS_GENHEADER_DONE, + dev->config.base_addr + CIF_JPE_STATUS_ICR); + break; + } + } + + if (!timeout) { + cif_isp10_pltfrm_pr_err(NULL, + "JPEG header generation timeout\n"); + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", -ETIMEDOUT); + return -ETIMEDOUT; + } + +#ifdef CIF_ISP10_VERIFY_JPEG_HEADER + { + u32 *buff = (u32 *)phys_to_virt( + dev->config.mi_config.mp.curr_buff_addr); + if (buff[0] != 0xe0ffd8ff) + cif_isp10_pltfrm_pr_err(NULL, + "JPEG HEADER WRONG: 0x%08x\n" + "curr_buff_addr 0x%08x\n" + "MI_MP_Y_SIZE_SHD 0x%08x\n" + "MI_MP_Y_BASE_AD_SHD 0x%08x\n", + buff[0], + dev->config.mi_config.mp.curr_buff_addr, + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_SIZE_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_SHD)); + } +#endif + + return 0; +} + +static void cif_isp10_mi_update_buff_addr( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id strm_id) +{ + if (strm_id == CIF_ISP10_STREAM_SP) { + cif_iowrite32_verify(dev->config.mi_config.sp.next_buff_addr, + dev->config.base_addr + + CIF_MI_SP_Y_BASE_AD_INIT, CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.sp.next_buff_addr + + dev->config.mi_config.sp.cb_offs, + dev->config.base_addr + + CIF_MI_SP_CB_BASE_AD_INIT, CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.sp.next_buff_addr + + dev->config.mi_config.sp.cr_offs, + dev->config.base_addr + + CIF_MI_SP_CR_BASE_AD_INIT, CIF_MI_ADDR_SIZE_ALIGN_MASK); + /* + * There have bee repeatedly issues with + * the offset registers, it is safer to write + * them each time, even though it is always + * 0 and even though that is the + * register's default value + */ + cif_iowrite32_verify(0, + dev->config.base_addr + + CIF_MI_SP_Y_OFFS_CNT_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(0, + dev->config.base_addr + + CIF_MI_SP_CB_OFFS_CNT_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(0, + dev->config.base_addr + + CIF_MI_SP_CR_OFFS_CNT_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_SP_Y_BASE_AD 0x%08x/0x%08x\n" + " MI_SP_CB_BASE_AD 0x%08x/0x%08x\n" + " MI_SP_CR_BASE_AD 0x%08x/0x%08x\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_BASE_AD_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CB_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CB_BASE_AD_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CR_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_CR_BASE_AD_SHD)); + } else if (strm_id == CIF_ISP10_STREAM_MP) { + cif_iowrite32_verify(dev->config.mi_config.mp.next_buff_addr, + dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_INIT, CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.mp.next_buff_addr + + dev->config.mi_config.mp.cb_offs, + dev->config.base_addr + + CIF_MI_MP_CB_BASE_AD_INIT, CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.mp.next_buff_addr + + dev->config.mi_config.mp.cr_offs, + dev->config.base_addr + + CIF_MI_MP_CR_BASE_AD_INIT, CIF_MI_ADDR_SIZE_ALIGN_MASK); + /* + * There have bee repeatedly issues with + * the offset registers, it is safer to write + * them each time, even though it is always + * 0 and even though that is the + * register's default value + */ + cif_iowrite32_verify(0, + dev->config.base_addr + + CIF_MI_MP_Y_OFFS_CNT_INIT, CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(0, + dev->config.base_addr + + CIF_MI_MP_CB_OFFS_CNT_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(0, + dev->config.base_addr + + CIF_MI_MP_CR_OFFS_CNT_INIT, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_MP_Y_BASE_AD 0x%08x/0x%08x\n" + " MI_MP_CB_BASE_AD 0x%08x/0x%08x\n" + " MI_MP_CR_BASE_AD 0x%08x/0x%08x\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CB_BASE_AD_SHD), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_BASE_AD_INIT), + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_CR_BASE_AD_SHD)); + } else { /* DMA */ + cif_iowrite32_verify(dev->config.mi_config.dma.next_buff_addr, + dev->config.base_addr + + CIF_MI_DMA_Y_PIC_START_AD, CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.dma.next_buff_addr + + dev->config.mi_config.dma.cb_offs, + dev->config.base_addr + + CIF_MI_DMA_CB_PIC_START_AD, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_iowrite32_verify(dev->config.mi_config.dma.next_buff_addr + + dev->config.mi_config.dma.cr_offs, + dev->config.base_addr + + CIF_MI_DMA_CR_PIC_START_AD, + CIF_MI_ADDR_SIZE_ALIGN_MASK); + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_DMA_Y_PIC_START_AD 0x%08x\n" + " MI_DMA_CB_PIC_START_AD 0x%08x\n" + " MI_DMA_CR_PIC_START_AD 0x%08x\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_Y_PIC_START_AD), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_CB_PIC_START_AD), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_CR_PIC_START_AD)); + } +} + +static int cif_isp10_update_mi_mp( + struct cif_isp10_device *dev) +{ + int ret = 0; + enum cif_isp10_pix_fmt out_pix_fmt = + dev->config.mi_config.mp.output.pix_fmt; + + cif_isp10_pltfrm_pr_dbg(NULL, + "curr 0x%08x next 0x%08x\n", + dev->config.mi_config.mp.curr_buff_addr, + dev->config.mi_config.mp.next_buff_addr); + + if (dev->config.jpeg_config.enable) { + /* + * in case of jpeg encoding, we don't have to disable the + * MI, because the encoding + * anyway has to be started explicitly + */ + if (!dev->config.jpeg_config.busy) { + if ((dev->config.mi_config.mp.curr_buff_addr != + dev->config.mi_config.mp.next_buff_addr) && + (dev->config.mi_config.mp.curr_buff_addr != + CIF_ISP10_INVALID_BUFF_ADDR)) { + ret = cif_isp10_jpeg_gen_header(dev); + if (IS_ERR_VALUE(ret)) + goto err; + cif_isp10_pltfrm_pr_dbg(NULL, + "Starting JPEG encoding\n"); + cif_isp10_pltfrm_rtrace_printf(dev->dev, + "Starting JPEG encoding\n"); + cif_iowrite32(CIF_JPE_ENCODE_ENABLE, + dev->config.base_addr + CIF_JPE_ENCODE); + cif_iowrite32(CIF_JPE_INIT_ENABLE, + dev->config.base_addr + + CIF_JPE_INIT); + dev->config.jpeg_config.busy = true; + } + if (dev->config.mi_config.mp.next_buff_addr != + CIF_ISP10_INVALID_BUFF_ADDR) + cif_isp10_mi_update_buff_addr(dev, + CIF_ISP10_STREAM_MP); + dev->config.mi_config.mp.curr_buff_addr = + dev->config.mi_config.mp.next_buff_addr; + } + } else { + if (dev->config.mi_config.mp.next_buff_addr != + dev->config.mi_config.mp.curr_buff_addr) { + if (dev->config.mi_config.mp.next_buff_addr == + CIF_ISP10_INVALID_BUFF_ADDR) { + /* disable MI MP */ + cif_isp10_pltfrm_pr_dbg(NULL, + "disabling MP MI\n"); + cif_iowrite32AND_verify( + ~(CIF_MI_CTRL_MP_ENABLE_IN | + CIF_MI_CTRL_JPEG_ENABLE | + CIF_MI_CTRL_RAW_ENABLE), + dev->config.base_addr + CIF_MI_CTRL, + ~0); + } else if (dev->config.mi_config.mp.curr_buff_addr == + CIF_ISP10_INVALID_BUFF_ADDR) { + /* re-enable MI MP */ + cif_isp10_pltfrm_pr_dbg(NULL, + "enabling MP MI\n"); + cif_iowrite32(CIF_MI_MP_FRAME, + dev->config.base_addr + CIF_MI_ICR); + cif_iowrite32AND_verify( + ~(CIF_MI_CTRL_MP_ENABLE_IN | + CIF_MI_CTRL_JPEG_ENABLE | + CIF_MI_CTRL_RAW_ENABLE), + dev->config.base_addr + + CIF_MI_CTRL, ~0); + if (CIF_ISP10_PIX_FMT_IS_RAW_BAYER + (out_pix_fmt)) { + cif_iowrite32OR_verify( + CIF_MI_CTRL_RAW_ENABLE, + dev->config.base_addr + + CIF_MI_CTRL, + ~0); + } else if (CIF_ISP10_PIX_FMT_IS_YUV + (out_pix_fmt)) { + cif_iowrite32OR_verify( + CIF_MI_CTRL_MP_ENABLE_IN, + dev->config.base_addr + + CIF_MI_CTRL, ~0); + } + } + cif_isp10_mi_update_buff_addr(dev, CIF_ISP10_STREAM_MP); + dev->config.mi_config.mp.curr_buff_addr = + dev->config.mi_config.mp.next_buff_addr; + } + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +static int cif_isp10_update_mi_sp( + struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_dbg(NULL, + "curr 0x%08x next 0x%08x\n", + dev->config.mi_config.sp.curr_buff_addr, + dev->config.mi_config.sp.next_buff_addr); + + if (dev->config.mi_config.sp.next_buff_addr != + dev->config.mi_config.sp.curr_buff_addr) { + if (dev->config.mi_config.sp.next_buff_addr == + CIF_ISP10_INVALID_BUFF_ADDR) { + /* disable MI SP */ + cif_isp10_pltfrm_pr_dbg(NULL, "disabling SP MI\n"); + /* 'switch off' MI interface */ + cif_iowrite32AND_verify(~CIF_MI_CTRL_SP_ENABLE, + dev->config.base_addr + CIF_MI_CTRL, ~0); + } else if (dev->config.mi_config.sp.curr_buff_addr == + CIF_ISP10_INVALID_BUFF_ADDR) { + /* re-enable MI SP */ + cif_isp10_pltfrm_pr_dbg(NULL, "enabling SP MI\n"); + cif_iowrite32(CIF_MI_SP_FRAME, + dev->config.base_addr + CIF_MI_ICR); + cif_iowrite32OR_verify(CIF_MI_CTRL_SP_ENABLE, + dev->config.base_addr + CIF_MI_CTRL, ~0); + } + cif_isp10_mi_update_buff_addr(dev, CIF_ISP10_STREAM_SP); + dev->config.mi_config.sp.curr_buff_addr = + dev->config.mi_config.sp.next_buff_addr; + } + + return 0; +} + +static int cif_isp10_s_fmt_mp( + struct cif_isp10_device *dev, + struct cif_isp10_strm_fmt *strm_fmt, + u32 stride) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s %dx%d@%d/%dfps, stride = %d, quantization: %d\n", + cif_isp10_pix_fmt_string(strm_fmt->frm_fmt.pix_fmt), + strm_fmt->frm_fmt.width, + strm_fmt->frm_fmt.height, + strm_fmt->frm_intrvl.numerator, + strm_fmt->frm_intrvl.denominator, + stride, + strm_fmt->frm_fmt.quantization); + + /* TBD: check whether format is a valid format for MP */ + + if (CIF_ISP10_PIX_FMT_IS_JPEG(strm_fmt->frm_fmt.pix_fmt)) { + dev->config.jpeg_config.enable = true; + } else if (CIF_ISP10_PIX_FMT_IS_RAW_BAYER + (strm_fmt->frm_fmt.pix_fmt)) { + if ((dev->sp_stream.state == CIF_ISP10_STATE_READY) || + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING)) + cif_isp10_pltfrm_pr_warn(dev->dev, + "cannot output RAW data when SP is active, you will not be able to (re-)start streaming\n"); + dev->config.mi_config.raw_enable = true; + } + + dev->config.mi_config.mp.output = strm_fmt->frm_fmt; + dev->config.mi_config.mp.output.stride = stride; + + dev->config.mi_config.mp.llength = + cif_isp10_calc_llength( + strm_fmt->frm_fmt.width, + stride, + strm_fmt->frm_fmt.pix_fmt); + cif_isp10_pltfrm_pr_dbg(dev->dev, + "mp llength=0x%x\n", dev->config.mi_config.mp.llength); + + dev->mp_stream.updt_cfg = true; + dev->mp_stream.state = CIF_ISP10_STATE_READY; + + if (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel)) { + ret = cif_isp10_img_src_select_strm_fmt(dev); + if (IS_ERR_VALUE(ret)) { + dev->mp_stream.updt_cfg = false; + dev->mp_stream.state = CIF_ISP10_STATE_INACTIVE; + goto err; + } + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_s_fmt_sp( + struct cif_isp10_device *dev, + struct cif_isp10_strm_fmt *strm_fmt, + u32 stride) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s %dx%d@%d/%dfps, stride = %d, quantization: %d\n", + cif_isp10_pix_fmt_string(strm_fmt->frm_fmt.pix_fmt), + strm_fmt->frm_fmt.width, + strm_fmt->frm_fmt.height, + strm_fmt->frm_intrvl.numerator, + strm_fmt->frm_intrvl.denominator, + stride, + strm_fmt->frm_fmt.quantization); + + if (dev->config.mi_config.raw_enable) + cif_isp10_pltfrm_pr_warn(dev->dev, + "cannot activate SP when MP is set to RAW data output, you will not be able to (re-)start streaming\n"); + + /* TBD: more detailed check whether format is a valid format for SP */ + /* TBD: remove the mode stuff */ + if (!CIF_ISP10_PIX_FMT_IS_YUV(strm_fmt->frm_fmt.pix_fmt) && + !CIF_ISP10_PIX_FMT_IS_RGB(strm_fmt->frm_fmt.pix_fmt)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "format %s %dx%d@%d/%dfps, stride = %d not supported on SP\n", + cif_isp10_pix_fmt_string(strm_fmt->frm_fmt.pix_fmt), + strm_fmt->frm_fmt.width, + strm_fmt->frm_fmt.height, + strm_fmt->frm_intrvl.numerator, + strm_fmt->frm_intrvl.denominator, + stride); + ret = -EINVAL; + goto err; + } + + dev->config.mi_config.sp.output = strm_fmt->frm_fmt; + dev->config.mi_config.sp.llength = + cif_isp10_calc_llength( + strm_fmt->frm_fmt.width, + stride, + strm_fmt->frm_fmt.pix_fmt); + + dev->sp_stream.updt_cfg = true; + dev->sp_stream.state = CIF_ISP10_STATE_READY; + + if (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel)) { + ret = cif_isp10_img_src_select_strm_fmt(dev); + if (IS_ERR_VALUE(ret)) { + dev->sp_stream.updt_cfg = false; + dev->sp_stream.state = CIF_ISP10_STATE_INACTIVE; + goto err; + } + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_s_fmt_dma( + struct cif_isp10_device *dev, + struct cif_isp10_strm_fmt *strm_fmt, + u32 stride) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s %dx%d@%d/%dfps, stride = %d\n", + cif_isp10_pix_fmt_string(strm_fmt->frm_fmt.pix_fmt), + strm_fmt->frm_fmt.width, + strm_fmt->frm_fmt.height, + strm_fmt->frm_intrvl.numerator, + strm_fmt->frm_intrvl.denominator, + stride); + + if (!CIF_ISP10_PIX_FMT_IS_YUV(strm_fmt->frm_fmt.pix_fmt) && + !CIF_ISP10_PIX_FMT_IS_RAW_BAYER(strm_fmt->frm_fmt.pix_fmt)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "format %s %dx%d@%d/%dfps, stride = %d not supported for DMA\n", + cif_isp10_pix_fmt_string(strm_fmt->frm_fmt.pix_fmt), + strm_fmt->frm_fmt.width, + strm_fmt->frm_fmt.height, + strm_fmt->frm_intrvl.numerator, + strm_fmt->frm_intrvl.denominator, + stride); + ret = -EINVAL; + goto err; + } + + dev->config.mi_config.dma.output = strm_fmt->frm_fmt; + dev->config.mi_config.dma.llength = + cif_isp10_calc_llength( + strm_fmt->frm_fmt.width, + stride, + strm_fmt->frm_fmt.pix_fmt); + + dev->dma_stream.updt_cfg = true; + dev->dma_stream.state = CIF_ISP10_STATE_READY; + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static void cif_isp10_dma_next_buff( + struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + if (!list_empty(&dev->dma_stream.buf_queue) && + !dev->dma_stream.stop) { + if (dev->dma_stream.curr_buf) + WARN_ON(1); + dev->dma_stream.curr_buf = + list_first_entry(&dev->dma_stream.buf_queue, + struct videobuf_buffer, queue); + list_del(&dev->dma_stream.curr_buf->queue); + dev->dma_stream.curr_buf->state = VIDEOBUF_ACTIVE; + dev->config.mi_config.dma.next_buff_addr = + videobuf_to_dma_contig( + dev->dma_stream.curr_buf); + cif_isp10_mi_update_buff_addr(dev, + CIF_ISP10_STREAM_DMA); + dev->config.mi_config.dma.busy = true; + if ((dev->sp_stream.state == CIF_ISP10_STATE_STREAMING) && + dev->sp_stream.curr_buf) + dev->config.mi_config.sp.busy = true; + if ((dev->mp_stream.state == CIF_ISP10_STATE_STREAMING) && + dev->mp_stream.curr_buf) + dev->config.mi_config.mp.busy = true; + /* workaround for write register failure bug */ + do { + cif_iowrite32(CIF_MI_DMA_START_ENABLE, + dev->config.base_addr + CIF_MI_DMA_START); + udelay(1); + } while (!cif_ioread32( + dev->config.base_addr + CIF_MI_DMA_STATUS)); + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_DMA_CTRL 0x%08x\n" + " MI_DMA_STATUS 0x%08x\n", + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_CTRL), + cif_ioread32(dev->config.base_addr + + CIF_MI_DMA_STATUS)); +} + +static void cif_isp10_dma_ready( + struct cif_isp10_device *dev) +{ + unsigned int mi_mis_tmp; + + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + cif_iowrite32(CIF_MI_DMA_READY, + dev->config.base_addr + CIF_MI_ICR); + mi_mis_tmp = cif_ioread32(dev->config.base_addr + CIF_MI_MIS); + if (mi_mis_tmp & CIF_MI_DMA_READY) + cif_isp10_pltfrm_pr_err(dev->dev, + "dma icr err: 0x%x\n", + mi_mis_tmp); + dev->dma_stream.curr_buf->state = VIDEOBUF_DONE; + wake_up(&dev->dma_stream.curr_buf->done); + dev->dma_stream.curr_buf = NULL; + dev->config.mi_config.dma.busy = false; + cif_isp10_pltfrm_event_signal(dev->dev, &dev->dma_stream.done); +} + +static int cif_isp10_mi_frame_end( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id) +{ + struct cif_isp10_stream *stream = NULL; + u32 *next_buff_addr = NULL; + CIF_ISP10_PLTFRM_MEM_IO_ADDR y_base_addr; + int (*update_mi)( + struct cif_isp10_device *dev); + struct cif_isp10_isp_readout_work *work; + + cif_isp10_pltfrm_pr_dbg(NULL, "%s\n", + cif_isp10_stream_id_string(stream_id)); + + if (stream_id == CIF_ISP10_STREAM_MP) { + stream = &dev->mp_stream; + y_base_addr = + dev->config.base_addr + CIF_MI_MP_Y_BASE_AD_SHD; + next_buff_addr = &dev->config.mi_config.mp.next_buff_addr; + update_mi = cif_isp10_update_mi_mp; + if (dev->config.jpeg_config.enable) { + unsigned int jpe_status = + cif_ioread32(dev->config.base_addr + + CIF_JPE_STATUS_RIS); + if (jpe_status & CIF_JPE_STATUS_ENCODE_DONE) { + cif_iowrite32(CIF_JPE_STATUS_ENCODE_DONE, + dev->config.base_addr + + CIF_JPE_STATUS_ICR); + if (stream->curr_buf) { + stream->curr_buf->size = + cif_ioread32(dev->config.base_addr + + CIF_MI_BYTE_CNT); + cif_isp10_pltfrm_pr_dbg(NULL, + "JPEG encoding done, size %lu\n", + stream->curr_buf->size); + if (cif_ioread32(dev->config.base_addr + + CIF_MI_RIS) & CIF_MI_WRAP_MP_Y) + cif_isp10_pltfrm_pr_err(NULL, + "buffer wrap around detected, JPEG presumably corrupted (%d/%d/%lu)\n", + dev->config.mi_config. + mp.y_size, + cif_ioread32( + dev->config.base_addr + + CIF_MI_MP_Y_SIZE_SHD), + stream->curr_buf->size); + } + } + } + } else if (stream_id == CIF_ISP10_STREAM_SP) { + stream = &dev->sp_stream; + y_base_addr = + dev->config.base_addr + CIF_MI_SP_Y_BASE_AD_SHD; + next_buff_addr = &dev->config.mi_config.sp.next_buff_addr; + update_mi = cif_isp10_update_mi_sp; + } else { + WARN_ON(1); + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s Y_BASE_AD_INIT/Y_BASE_AD_SHD (0x%08x/0x%08x)\n", + cif_isp10_stream_id_string(stream_id), + (stream_id & CIF_ISP10_STREAM_MP) ? + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_INIT) : + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_BASE_AD_INIT), + cif_ioread32(y_base_addr)); + + if ((!stream->next_buf) && + !(dev->config.jpeg_config.enable && + (stream_id == CIF_ISP10_STREAM_MP))) { + stream->stall = dev->config.out_of_buffer_stall; + } else if ((stream->next_buf) && + (videobuf_to_dma_contig(stream->next_buf) != + cif_ioread32(y_base_addr))) { + cif_isp10_pltfrm_pr_warn(dev->dev, + "%s buffer queue is not advancing (0x%08x/0x%08x)\n", + cif_isp10_stream_id_string(stream_id), + (stream_id & CIF_ISP10_STREAM_MP) ? + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_BASE_AD_INIT) : + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_BASE_AD_INIT), + cif_ioread32(y_base_addr)); + stream->stall = true; + } + + if (!stream->stall) { + /* + * If mi restart after switch off for buffer is empty, + * mi may be restart failed. So mi write data to last + * buffer, the last buffer isn't been release to user + * until new buffer queue; + */ + if ((stream->curr_buf) && + (stream->next_buf)) { + bool wake_now; + + stream->curr_buf->field_count = dev->isp_dev.frame_id; + stream->curr_buf->state = VIDEOBUF_DONE; + wake_now = false; + + if (stream->metadata.d && dev->isp_dev.streamon) { + struct v4l2_buffer_metadata_s *metadata; + + metadata = (struct v4l2_buffer_metadata_s *) + (stream->metadata.d + + stream->curr_buf->i * + CAMERA_METADATA_LEN); + metadata->frame_id = dev->isp_dev.frame_id; + metadata->frame_t.vs_t = dev->isp_dev.vs_t; + metadata->frame_t.fi_t = dev->isp_dev.fi_t; + + work = (struct cif_isp10_isp_readout_work *) + kmalloc( + sizeof( + struct cif_isp10_isp_readout_work), + GFP_ATOMIC); + if (work) { + INIT_WORK((struct work_struct *)work, + cifisp_isp_readout_work); + work->readout = + CIF_ISP10_ISP_READOUT_META; + work->isp_dev = + &dev->isp_dev; + work->frame_id = + dev->isp_dev.frame_id; + work->vb = stream->curr_buf; + work->stream_id = stream->id; + if (!queue_work(dev->isp_dev.readout_wq, + (struct work_struct *)work)) { + cif_isp10_pltfrm_pr_err( + dev->dev, + "Could not schedule work\n"); + wake_now = true; + kfree((void *)work); + } + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "Could not allocate work\n"); + wake_now = true; + } + } else { + wake_now = true; + } + + if (wake_now) { + cif_isp10_pltfrm_pr_dbg(NULL, + "frame done\n"); + wake_up(&stream->curr_buf->done); + } + stream->curr_buf = NULL; + } + + if (!stream->curr_buf) { + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; + } + } + + if (!stream->next_buf) { + /* + * in case of jpeg encoding, we are only programming + * a new buffer, if the jpeg header was generated, because + * we need the curent buffer for the jpeg encoding + * in the current frame period + */ + if (!list_empty(&stream->buf_queue)) { + stream->next_buf = + list_first_entry(&stream->buf_queue, + struct videobuf_buffer, queue); + list_del(&stream->next_buf->queue); + stream->next_buf->state = VIDEOBUF_ACTIVE; + *next_buff_addr = videobuf_to_dma_contig( + stream->next_buf); + } else if ( + !dev->config.out_of_buffer_stall || + (dev->config.jpeg_config.enable && + (stream_id == CIF_ISP10_STREAM_MP))) { +/* + * If mi restart after switch off for buffer is empty, + * mi may be restart failed. So mi write data to last + * buffer, the last buffer isn't been release to user + * until new buffer queue; + * + * if + * *next_buff_addr = CIF_ISP10_INVALID_BUFF_ADDR; + * mi will stop; + */ + *next_buff_addr = + videobuf_to_dma_contig( + stream->curr_buf); + } + } + (void)update_mi(dev); + + stream->stall = false; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s curr_buff: %d, 0x%08x next_buf: %d, 0x%x\n", + cif_isp10_stream_id_string(stream_id), + (stream->curr_buf) ? stream->curr_buf->i : -1, + (stream->curr_buf) ? (int)videobuf_to_dma_contig + (stream->curr_buf) : -1, + (stream->next_buf) ? stream->next_buf->i : -1, + *next_buff_addr); + + return 0; +} + +static void cif_isp10_stream_metadata_reset( + struct cif_isp10_stream *stream_dev +) +{ + unsigned int i; + struct v4l2_buffer_metadata_s *metadata; + struct cifisp_isp_metadata *isp_metadata; + + if (stream_dev->metadata.d) { + for (i = 0; i < stream_dev->metadata.cnt; i++) { + metadata = (struct v4l2_buffer_metadata_s *) + (stream_dev->metadata.d + + i * CAMERA_METADATA_LEN); + isp_metadata = (struct cifisp_isp_metadata *) + metadata->isp; + isp_metadata->other_cfg.s_frame_id = 0xffffffff; + isp_metadata->meas_cfg.s_frame_id = 0xffffffff; + } + } +} + +static void cif_isp10_start_mi( + struct cif_isp10_device *dev, + bool start_mi_sp, + bool start_mi_mp) +{ + cif_isp10_pltfrm_pr_dbg(dev->dev, "\n"); + + if (start_mi_sp && + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING)) + start_mi_sp = false; + if (start_mi_mp && + (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING)) + start_mi_mp = false; + if (!start_mi_sp && !start_mi_mp) + return; + + if ((start_mi_sp && + (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING)) || + (start_mi_mp && + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING))) + WARN_ON(1); + + if (start_mi_sp) { + cif_isp10_stream_metadata_reset(&dev->sp_stream); + dev->config.mi_config.sp.next_buff_addr = + CIF_ISP10_INVALID_BUFF_ADDR; + dev->config.mi_config.sp.curr_buff_addr = + CIF_ISP10_INVALID_BUFF_ADDR; + spin_lock(&dev->vbq_lock); + cif_isp10_mi_frame_end(dev, CIF_ISP10_STREAM_SP); + spin_unlock(&dev->vbq_lock); + dev->sp_stream.stall = false; + } + + if (start_mi_mp) { + cif_isp10_stream_metadata_reset(&dev->mp_stream); + dev->config.mi_config.mp.next_buff_addr = + CIF_ISP10_INVALID_BUFF_ADDR; + dev->config.mi_config.mp.curr_buff_addr = + CIF_ISP10_INVALID_BUFF_ADDR; + spin_lock(&dev->vbq_lock); + cif_isp10_mi_frame_end(dev, CIF_ISP10_STREAM_MP); + spin_unlock(&dev->vbq_lock); + dev->mp_stream.stall = false; + } + + cif_iowrite32OR(CIF_MI_INIT_SOFT_UPD, + dev->config.base_addr + CIF_MI_INIT); + cif_isp10_pltfrm_pr_dbg(NULL, + "CIF_MI_INIT_SOFT_UPD\n"); + + if (start_mi_sp) { + spin_lock(&dev->vbq_lock); + cif_isp10_mi_frame_end(dev, CIF_ISP10_STREAM_SP); + spin_unlock(&dev->vbq_lock); + if (dev->sp_stream.curr_buf && + (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel))) + dev->config.mi_config.sp.busy = true; + } + + if (start_mi_mp) { + spin_lock(&dev->vbq_lock); + cif_isp10_mi_frame_end(dev, CIF_ISP10_STREAM_MP); + spin_unlock(&dev->vbq_lock); + if (dev->mp_stream.curr_buf && + (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel))) + dev->config.mi_config.mp.busy = true; + } + + if (!dev->config.mi_config.async_updt) + cif_iowrite32OR(CIF_ISP_CTRL_ISP_GEN_CFG_UPD, + dev->config.base_addr + CIF_ISP_CTRL); +} + +static void cif_isp10_stop_mi( + struct cif_isp10_device *dev, + bool stop_mi_sp, + bool stop_mi_mp) +{ + cif_isp10_pltfrm_pr_dbg(dev->dev, "\n"); + + if (stop_mi_sp && + (dev->sp_stream.state != CIF_ISP10_STATE_STREAMING)) + stop_mi_sp = false; + if (stop_mi_mp && + (dev->mp_stream.state != CIF_ISP10_STATE_STREAMING)) + stop_mi_mp = false; + + if (!stop_mi_sp && !stop_mi_mp) + return; + + if (stop_mi_sp && stop_mi_mp) { + cif_iowrite32AND_verify(~(CIF_MI_SP_FRAME | + CIF_MI_MP_FRAME | + CIF_JPE_STATUS_ENCODE_DONE), + dev->config.base_addr + CIF_MI_IMSC, ~0); + cif_iowrite32(CIF_MI_SP_FRAME | + CIF_MI_MP_FRAME | + CIF_JPE_STATUS_ENCODE_DONE, + dev->config.base_addr + CIF_MI_ICR); + cif_iowrite32AND_verify(~CIF_MI_CTRL_SP_ENABLE, + dev->config.base_addr + CIF_MI_CTRL, ~0); + cif_iowrite32AND_verify(~(CIF_MI_CTRL_MP_ENABLE_IN | + CIF_MI_CTRL_SP_ENABLE | + CIF_MI_CTRL_JPEG_ENABLE | + CIF_MI_CTRL_RAW_ENABLE), + dev->config.base_addr + CIF_MI_CTRL, ~0); + cif_iowrite32(CIF_MI_INIT_SOFT_UPD, + dev->config.base_addr + CIF_MI_INIT); + } else if (stop_mi_sp) { + cif_iowrite32(CIF_MI_SP_FRAME, + dev->config.base_addr + CIF_MI_ICR); + cif_iowrite32AND_verify(~CIF_MI_CTRL_SP_ENABLE, + dev->config.base_addr + CIF_MI_CTRL, ~0); + } else if (stop_mi_mp) { + cif_iowrite32(CIF_MI_MP_FRAME | + CIF_JPE_STATUS_ENCODE_DONE, + dev->config.base_addr + CIF_MI_ICR); + cif_iowrite32AND_verify(~(CIF_MI_CTRL_MP_ENABLE_IN | + CIF_MI_CTRL_JPEG_ENABLE | + CIF_MI_CTRL_RAW_ENABLE), + dev->config.base_addr + CIF_MI_CTRL, ~0); + } +} + +static void cif_isp10_requeue_bufs( + struct cif_isp10_device *dev, + struct cif_isp10_stream *stream) +{ + INIT_LIST_HEAD(&stream->buf_queue); + stream->next_buf = NULL; + stream->curr_buf = NULL; + dev->requeue_bufs(dev, stream->id); +} + +static void cif_isp10_stop_sp( + struct cif_isp10_device *dev) +{ + int ret; + + if (dev->sp_stream.state == + CIF_ISP10_STATE_STREAMING) { + dev->sp_stream.stop = true; + ret = cif_isp10_pltfrm_event_wait_timeout(dev->dev, + &dev->sp_stream.done, + dev->sp_stream.state != + CIF_ISP10_STATE_STREAMING, + 1000000); + dev->sp_stream.stop = false; + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_warn(NULL, + "waiting on event returned with error %d\n", + ret); + } + if (dev->config.mi_config.sp.busy) + cif_isp10_pltfrm_pr_warn(NULL, + "SP path still active while stopping it\n"); + } +} + +static void cif_isp10_stop_mp( + struct cif_isp10_device *dev) +{ + int ret; + + if (dev->mp_stream.state == + CIF_ISP10_STATE_STREAMING) { + dev->mp_stream.stop = true; + ret = cif_isp10_pltfrm_event_wait_timeout(dev->dev, + &dev->mp_stream.done, + dev->mp_stream.state != + CIF_ISP10_STATE_STREAMING, + 1000000); + dev->mp_stream.stop = false; + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_warn(NULL, + "waiting on event returned with error %d\n", + ret); + } + if (dev->config.mi_config.mp.busy || + dev->config.jpeg_config.busy) + cif_isp10_pltfrm_pr_warn(NULL, + "MP path still active while stopping it\n"); + } +} + +static void cif_isp10_stop_dma( + struct cif_isp10_device *dev) +{ + unsigned long flags = 0; + + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + if (dev->dma_stream.state == + CIF_ISP10_STATE_STREAMING) { + /* we should not stop during an active DMA transfer */ + dev->dma_stream.stop = true; + (void)cif_isp10_pltfrm_event_wait_timeout(dev->dev, + &dev->dma_stream.done, + dev->dma_stream.state != + CIF_ISP10_STATE_STREAMING, + 50000); + /* intentionally NOT checking dma.busy again */ + if (dev->config.mi_config.dma.busy) + cif_isp10_pltfrm_pr_warn(NULL, + "DMA transfer still active while stopping it\n"); + dev->dma_stream.state = CIF_ISP10_STATE_READY; + spin_lock_irqsave(&dev->vbq_lock, flags); + cif_isp10_requeue_bufs(dev, &dev->dma_stream); + spin_unlock_irqrestore(&dev->vbq_lock, flags); + } +} + +static int cif_isp10_stop( + struct cif_isp10_device *dev, + bool stop_sp, + bool stop_mp) +{ + unsigned long flags = 0; + bool stop_all; + int timeout; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, img_src state = %s, stop_sp = %d, stop_mp = %d\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_img_src_state_string(dev->img_src_state), + stop_sp, + stop_mp); + + if (!((stop_mp && + (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING)) || + (stop_sp && + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING)))) { + return 0; + } + + stop_all = ((stop_mp && stop_sp) || + (stop_sp && + (dev->mp_stream.state != CIF_ISP10_STATE_STREAMING)) || + (stop_mp && + (dev->sp_stream.state != CIF_ISP10_STATE_STREAMING))); + + if (stop_all) { + /* + * Modify ISP stop sequence for isp bus dead: + * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> + * Stop ISP(isp) ->wait for ISP isp off + */ + + cif_isp10_stop_mp(dev); + cif_isp10_stop_sp(dev); + cif_isp10_stop_dma(dev); + + local_irq_save(flags); + /* stop and clear MI, MIPI, and ISP interrupts */ + cif_iowrite32(0, dev->config.base_addr + CIF_MIPI_IMSC); + cif_iowrite32(~0, dev->config.base_addr + CIF_MIPI_ICR); + + cif_iowrite32(0, dev->config.base_addr + CIF_ISP_IMSC); + cif_iowrite32(~0, dev->config.base_addr + CIF_ISP_ICR); + + cif_iowrite32_verify(0, + dev->config.base_addr + CIF_MI_IMSC, ~0); + cif_iowrite32(~0, dev->config.base_addr + CIF_MI_ICR); + + cif_iowrite32AND(~CIF_MIPI_CTRL_OUTPUT_ENA, + dev->config.base_addr + CIF_MIPI_CTRL); + /* stop ISP */ + cif_iowrite32AND(~(CIF_ISP_CTRL_ISP_INFORM_ENABLE | + CIF_ISP_CTRL_ISP_ENABLE), + dev->config.base_addr + CIF_ISP_CTRL); + cif_iowrite32OR(CIF_ISP_CTRL_ISP_CFG_UPD, + dev->config.base_addr + CIF_ISP_CTRL); + + timeout = 100; + while ((timeout-- > 0) && + ((cif_ioread32(dev->config.base_addr + CIF_ISP_RIS) + & CIF_ISP_OFF) != CIF_ISP_OFF)) { + msleep(20); + }; + local_irq_restore(flags); + + if (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel)) { + if (IS_ERR_VALUE(cif_isp10_img_src_set_state(dev, + CIF_ISP10_IMG_SRC_STATE_SW_STNDBY))) + cif_isp10_pltfrm_pr_dbg(dev->dev, + "unable to put image source into standby\n"); + } + if (IS_ERR_VALUE(cif_isp10_set_pm_state(dev, + CIF_ISP10_PM_STATE_SW_STNDBY))) + cif_isp10_pltfrm_pr_dbg(dev->dev, + "unable to put CIF into standby\n"); + } else if (stop_sp) { + if (!dev->config.mi_config.async_updt) { + local_irq_save(flags); + cif_isp10_stop_mi(dev, true, false); + local_irq_restore(flags); + } + cif_isp10_stop_sp(dev); + cif_iowrite32AND_verify(~CIF_MI_SP_FRAME, + dev->config.base_addr + CIF_MI_IMSC, ~0); + + } else /* stop_mp */ { + if (!dev->config.mi_config.async_updt) { + local_irq_save(flags); + cif_isp10_stop_mi(dev, false, true); + local_irq_restore(flags); + } + cif_isp10_stop_mp(dev); + cif_iowrite32AND_verify(~(CIF_MI_MP_FRAME | + CIF_JPE_STATUS_ENCODE_DONE), + dev->config.base_addr + CIF_MI_IMSC, ~0); + } + + if (stop_mp && (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING)) + dev->mp_stream.state = CIF_ISP10_STATE_READY; + + if (stop_sp && (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING)) + dev->sp_stream.state = CIF_ISP10_STATE_READY; + + spin_lock(&dev->vbq_lock); + if (stop_sp) { + dev->config.mi_config.sp.busy = false; + cif_isp10_requeue_bufs(dev, &dev->sp_stream); + } + if (stop_mp) { + dev->config.mi_config.mp.busy = false; + cif_isp10_requeue_bufs(dev, &dev->mp_stream); + } + spin_unlock(&dev->vbq_lock); + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s, img_src state = %s\n" + " MI_CTRL 0x%08x\n" + " ISP_CTRL 0x%08x\n" + " MIPI_CTRL 0x%08x\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state), + cif_isp10_img_src_state_string(dev->img_src_state), + cif_ioread32(dev->config.base_addr + CIF_MI_CTRL), + cif_ioread32(dev->config.base_addr + CIF_ISP_CTRL), + cif_ioread32(dev->config.base_addr + CIF_MIPI_CTRL)); + + return 0; +} + +static int cif_isp10_start( + struct cif_isp10_device *dev, + bool start_sp, + bool start_mp) +{ + unsigned int ret; + struct videobuf_buffer *vb, *n; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s, img_src state = %s, start_sp = %d, start_mp = %d\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state), + cif_isp10_img_src_state_string(dev->img_src_state), + start_sp, + start_mp); + + if (!((start_mp && + (dev->mp_stream.state != CIF_ISP10_STATE_STREAMING)) || + (start_sp && + (dev->sp_stream.state != CIF_ISP10_STATE_STREAMING)))) + return 0; + + if (CIF_ISP10_INP_IS_DMA(dev->config.input_sel) && + (dev->dma_stream.state < CIF_ISP10_STATE_READY)) { + cif_isp10_pltfrm_pr_err(NULL, + "cannot start streaming, input source (DMA) not ready\n"); + ret = -EFAULT; + goto err; + } + + /* Activate MI */ + cif_isp10_start_mi(dev, start_sp, start_mp); + + if ((dev->sp_stream.state != CIF_ISP10_STATE_STREAMING) && + (dev->mp_stream.state != CIF_ISP10_STATE_STREAMING)) { + /* Activate MIPI */ + if (CIF_ISP10_INP_IS_MIPI(dev->config.input_sel)) + cif_iowrite32OR(CIF_MIPI_CTRL_OUTPUT_ENA, + dev->config.base_addr + CIF_MIPI_CTRL); + + /* Activate ISP ! */ + if (CIF_ISP10_INP_NEED_ISP(dev->config.input_sel)) + cif_iowrite32OR(CIF_ISP_CTRL_ISP_CFG_UPD | + CIF_ISP_CTRL_ISP_INFORM_ENABLE | + CIF_ISP_CTRL_ISP_ENABLE, + dev->config.base_addr + CIF_ISP_CTRL); + } + + if (start_sp && + (dev->sp_stream.state != CIF_ISP10_STATE_STREAMING)) { + dev->sp_stream.state = CIF_ISP10_STATE_STREAMING; + } + if (start_mp && + (dev->mp_stream.state != CIF_ISP10_STATE_STREAMING)) { + dev->mp_stream.state = CIF_ISP10_STATE_STREAMING; + } + ret = cif_isp10_set_pm_state(dev, + CIF_ISP10_PM_STATE_STREAMING); + if (IS_ERR_VALUE(ret)) + goto err; + + if (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel)) { + /* + * CIF spec says to wait for sufficient time after enabling + * the MIPI interface and before starting the sensor output. + */ + mdelay(1); + /* start sensor output! */ + dev->isp_dev.frame_id = 0; + dev->isp_dev.frame_id_setexp = 0; + videobuf_queue_lock(&dev->isp_dev.vbq_stat); + list_for_each_entry_safe( + vb, n, &dev->isp_dev.vbq_stat.stream, queue) { + if (vb->state == VIDEOBUF_DONE) { + vb->field_count = -1; + cif_isp10_pltfrm_pr_info( + dev->dev, + "discard vb: %d\n", vb->i); + } + } + videobuf_queue_unlock(&dev->isp_dev.vbq_stat); + + mutex_lock(&dev->img_src_exps.mutex); + cif_isp10_img_src_ioctl(dev->img_src, + RK_VIDIOC_SENSOR_MODE_DATA, + &dev->img_src_exps.data[0].data); + cif_isp10_img_src_ioctl(dev->img_src, + RK_VIDIOC_SENSOR_MODE_DATA, + &dev->img_src_exps.data[1].data); + dev->img_src_exps.data[0].v_frame_id = 0; + dev->img_src_exps.data[1].v_frame_id = 0; + mutex_unlock(&dev->img_src_exps.mutex); + + cif_isp10_pltfrm_rtrace_printf(dev->dev, + "starting image source...\n"); + ret = cif_isp10_img_src_set_state(dev, + CIF_ISP10_IMG_SRC_STATE_STREAMING); + if (IS_ERR_VALUE(ret)) + goto err; + } else { + cif_isp10_pltfrm_rtrace_printf(dev->dev, + "starting DMA...\n"); + dev->dma_stream.state = CIF_ISP10_STATE_STREAMING; + dev->dma_stream.stop = false; + cif_isp10_dma_next_buff(dev); + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s, img_src state = %s\n" + " MI_CTRL 0x%08x\n" + " ISP_CTRL 0x%08x\n" + " MIPI_CTRL 0x%08x\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state), + cif_isp10_img_src_state_string(dev->img_src_state), + cif_ioread32(dev->config.base_addr + CIF_MI_CTRL), + cif_ioread32(dev->config.base_addr + CIF_ISP_CTRL), + cif_ioread32(dev->config.base_addr + CIF_MIPI_CTRL)); + + return 0; +err: + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s, img_src state = %s\n" + " MI_CTRL 0x%08x\n" + " ISP_CTRL 0x%08x\n" + " MIPI_CTRL 0x%08x\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state), + cif_isp10_img_src_state_string(dev->img_src_state), + cif_ioread32(dev->config.base_addr + CIF_MI_CTRL), + cif_ioread32(dev->config.base_addr + CIF_ISP_CTRL), + cif_ioread32(dev->config.base_addr + CIF_MIPI_CTRL)); + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +/* Function to be called inside ISR to update CIF ISM/DCROP/RSZ */ +static int cif_isp10_update_ism_dcr_rsz( + struct cif_isp10_device *dev) +{ + int ret = 0; + + if (dev->config.isp_config.ism_config.ism_update_needed) { + if (dev->config.isp_config.ism_config.ism_en) { + if (!dev->isp_dev.cif_ism_cropping) + dev->isp_dev.cif_ism_cropping = true; + } else { + if (dev->isp_dev.cif_ism_cropping) + dev->isp_dev.cif_ism_cropping = false; + } + } + + /* + * Update ISM, cif_isp10_config_ism() changes the output size of isp, + * so it must be called before cif_isp10_config_rsz() + */ + if (dev->config.isp_config.ism_config.ism_update_needed) { + cif_isp10_config_ism(dev, false); + if (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING) + dev->config.mp_config.rsz_config.ism_adjust = true; + if (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING) + dev->config.sp_config.rsz_config.ism_adjust = true; + + dev->config.isp_config.ism_config.ism_update_needed = false; + cif_iowrite32OR(CIF_ISP_CTRL_ISP_CFG_UPD, + dev->config.base_addr + CIF_ISP_CTRL); + + if (dev->config.isp_config.ism_config.ism_en) + dev->config.mi_config.async_updt |= CIF_ISP10_ASYNC_ISM; + } + + /* Update RSZ */ + if ((dev->config.mp_config.rsz_config.ycflt_adjust || + dev->config.mp_config.rsz_config.ism_adjust)) { + ret = cif_isp10_config_rsz(dev, CIF_ISP10_STREAM_MP, true); + if (IS_ERR_VALUE(ret)) + goto err; + } + if ((dev->config.sp_config.rsz_config.ycflt_adjust || + dev->config.sp_config.rsz_config.ism_adjust)) { + ret = cif_isp10_config_rsz(dev, CIF_ISP10_STREAM_SP, true); + if (IS_ERR_VALUE(ret)) + goto err; + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +static int cif_isp10_mi_isr(unsigned int mi_mis, void *cntxt) +{ + struct cif_isp10_device *dev = cntxt; + unsigned int mi_mis_tmp; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "\n MI_RIS 0x%08x\n" + " MI_IMSC 0x%08x\n" + " MI_MIS 0x%08x\n", + cif_ioread32(dev->config.base_addr + CIF_MI_RIS), + cif_ioread32(dev->config.base_addr + CIF_MI_IMSC), + mi_mis); + + cif_isp10_pltfrm_rtrace_printf(dev->dev, + "MI_MIS %08x, MI_RIS %08x, MI_IMSC %08x\n", + mi_mis, + cif_ioread32(dev->config.base_addr + CIF_MI_RIS), + cif_ioread32(dev->config.base_addr + CIF_MI_IMSC)); + + if (mi_mis & CIF_MI_SP_FRAME) { + dev->config.mi_config.sp.busy = false; + cif_iowrite32(CIF_MI_SP_FRAME, + dev->config.base_addr + CIF_MI_ICR); + mi_mis_tmp = cif_ioread32(dev->config.base_addr + CIF_MI_MIS); + if (mi_mis_tmp & CIF_MI_SP_FRAME) + cif_isp10_pltfrm_pr_err(dev->dev, + "sp icr err: 0x%x\n", + mi_mis_tmp); + } + + if (mi_mis & CIF_MI_MP_FRAME) { + dev->config.mi_config.mp.busy = false; + cif_iowrite32(CIF_MI_MP_FRAME, + dev->config.base_addr + CIF_MI_ICR); + mi_mis_tmp = cif_ioread32(dev->config.base_addr + CIF_MI_MIS); + if (mi_mis_tmp & CIF_MI_MP_FRAME) + cif_isp10_pltfrm_pr_err(dev->dev, + "mp icr err: 0x%x\n", + mi_mis_tmp); + } + if (mi_mis & CIF_MI_DMA_READY) + (void)cif_isp10_dma_ready(dev); + if (dev->config.jpeg_config.enable && + (cif_ioread32(dev->config.base_addr + + CIF_JPE_STATUS_RIS) & CIF_JPE_STATUS_ENCODE_DONE)) + dev->config.jpeg_config.busy = false; + + if (!CIF_ISP10_MI_IS_BUSY(dev) && + !dev->config.jpeg_config.busy) { + if (dev->config.mi_config.async_updt) { + u32 mp_y_off_cnt_shd = + cif_ioread32(dev->config.base_addr + + CIF_MI_MP_Y_OFFS_CNT_SHD); + u32 sp_y_off_cnt_shd = + cif_ioread32(dev->config.base_addr + + CIF_MI_SP_Y_OFFS_CNT_SHD); + + cif_iowrite32(CIF_MI_INIT_SOFT_UPD, + dev->config.base_addr + CIF_MI_INIT); + cif_isp10_pltfrm_pr_dbg(NULL, + "CIF_MI_INIT_SOFT_UPD\n"); + if (!dev->config.isp_config.ism_config.ism_en && + (dev->config.mi_config.async_updt & + CIF_ISP10_ASYNC_ISM)) + dev->config.mi_config.async_updt &= + ~CIF_ISP10_ASYNC_ISM; + if (sp_y_off_cnt_shd != 0) { + spin_lock(&dev->vbq_lock); + cif_isp10_requeue_bufs(dev, &dev->sp_stream); + spin_unlock(&dev->vbq_lock); + } + if ((mp_y_off_cnt_shd != 0) && + (!dev->config.jpeg_config.enable)) { + spin_lock(&dev->vbq_lock); + cif_isp10_requeue_bufs(dev, &dev->mp_stream); + spin_unlock(&dev->vbq_lock); + } + if (((mp_y_off_cnt_shd != 0) && + !dev->config.jpeg_config.enable) || + (sp_y_off_cnt_shd != 0)) { + cif_isp10_pltfrm_pr_dbg(dev->dev, + "soft update too late (SP offset %d, MP offset %d)\n", + sp_y_off_cnt_shd, mp_y_off_cnt_shd); + } + } + + if (dev->mp_stream.stop && + (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING)) { + cif_isp10_stop_mi(dev, false, true); + dev->mp_stream.state = CIF_ISP10_STATE_READY; + dev->mp_stream.stop = false; + + /* Turn off MRSZ since it is not needed */ + cif_iowrite32(0, dev->config.base_addr + CIF_MRSZ_CTRL); + cif_iowrite32OR(CIF_RSZ_CTRL_CFG_UPD, + dev->config.base_addr + CIF_MRSZ_CTRL); + + cif_isp10_pltfrm_pr_dbg(NULL, + "MP has stopped\n"); + cif_isp10_pltfrm_event_signal(dev->dev, + &dev->mp_stream.done); + } + if (dev->sp_stream.stop && + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING)) { + cif_isp10_stop_mi(dev, true, false); + dev->sp_stream.state = CIF_ISP10_STATE_READY; + dev->sp_stream.stop = false; + + /* Turn off SRSZ since it is not needed */ + cif_iowrite32(0, dev->config.base_addr + CIF_SRSZ_CTRL); + cif_iowrite32OR(CIF_RSZ_CTRL_CFG_UPD, + dev->config.base_addr + CIF_SRSZ_CTRL); + + cif_isp10_pltfrm_pr_dbg(NULL, + "SP has stopped\n"); + cif_isp10_pltfrm_event_signal(dev->dev, + &dev->sp_stream.done); + } + + if (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING) { + spin_lock(&dev->vbq_lock); + (void)cif_isp10_mi_frame_end(dev, + CIF_ISP10_STREAM_SP); + spin_unlock(&dev->vbq_lock); + } + if (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING) { + spin_lock(&dev->vbq_lock); + (void)cif_isp10_mi_frame_end(dev, + CIF_ISP10_STREAM_MP); + spin_unlock(&dev->vbq_lock); + } + + dev->b_mi_frame_end = true; + + if (dev->dma_stream.state == CIF_ISP10_STATE_STREAMING) { + cif_isp10_dma_next_buff(dev); + } else { + if ((dev->sp_stream.state == + CIF_ISP10_STATE_STREAMING) && + dev->sp_stream.curr_buf) + dev->config.mi_config.sp.busy = true; + if ((dev->mp_stream.state == + CIF_ISP10_STATE_STREAMING) && + dev->mp_stream.curr_buf) + dev->config.mi_config.mp.busy = true; + } + + if (dev->b_isp_frame_in && + ((dev->mp_stream.state == CIF_ISP10_STATE_STREAMING) || + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING))) + cif_isp10_update_ism_dcr_rsz(dev); + } + + cif_iowrite32(~(CIF_MI_MP_FRAME | + CIF_MI_SP_FRAME | CIF_MI_DMA_READY), + dev->config.base_addr + CIF_MI_ICR); + + return 0; +} + +static int cif_isp10_register_isrs(struct cif_isp10_device *dev) +{ + int ret = 0; + + cif_isp10_pltfrm_irq_register_isr( + dev->dev, + CIF_ISP_MIS, + cif_isp10_isp_isr, + dev); + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_warn(dev->dev, + "unable to register ISP ISR, some processing errors may go unnoticed\n"); + + cif_isp10_pltfrm_irq_register_isr( + dev->dev, + CIF_MIPI_MIS, + cif_isp10_mipi_isr, + dev); + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_warn(dev->dev, + "unable to register MIPI ISR, MIPI errors may go unnoticed\n"); + + ret = cif_isp10_pltfrm_irq_register_isr( + dev->dev, + CIF_MI_MIS, + cif_isp10_mi_isr, + dev); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "unable to register MI ISR, aborting\n"); + goto err; + } + + return 0; + +err: + cif_isp10_pltfrm_pr_err(dev->dev, "failed with error %d", ret); + return ret; +} + +static void cif_isp10_vs_work(struct work_struct *work) +{ + struct cif_isp10_isp_vs_work *vs_wk = + container_of(work, struct cif_isp10_isp_vs_work, work); + struct cif_isp10_device *dev = vs_wk->dev; + + switch (vs_wk->cmd) { + case CIF_ISP10_VS_EXP: { + struct cif_isp10_img_src_exp *exp = + (struct cif_isp10_img_src_exp *)vs_wk->param; + struct cif_isp10_img_src_ext_ctrl *exp_ctrl = exp->exp; + struct cif_isp10_img_src_data *new_data; + + if (dev->img_src) + cif_isp10_img_src_s_ext_ctrls(dev->img_src, exp_ctrl); + else + cif_isp10_pltfrm_pr_err(dev->dev, + "dev->img_src is NULL\n"); + + if (dev->img_src_exps.data[0].v_frame_id < + dev->img_src_exps.data[1].v_frame_id) + new_data = &dev->img_src_exps.data[0]; + else + new_data = &dev->img_src_exps.data[1]; + + mutex_lock(&dev->img_src_exps.mutex); + new_data->v_frame_id = dev->isp_dev.frame_id + + dev->img_src_exps.exp_valid_frms; + cif_isp10_img_src_ioctl(dev->img_src, + RK_VIDIOC_SENSOR_MODE_DATA, + &new_data->data); + mutex_unlock(&dev->img_src_exps.mutex); + + /* + * pr_info("%s: exp_time: %d gain: %d, frame_id: s %d, v %d\n", + * __func__, + * new_data->data.exp_time, + * new_data->data.gain, + * dev->isp_dev.frame_id, + * new_data->v_frame_id); + */ + + kfree(exp->exp->ctrls); + exp->exp->ctrls = NULL; + kfree(exp->exp); + exp->exp = NULL; + kfree(exp); + exp = NULL; + break; + } + default: + break; + } + + kfree(vs_wk); + vs_wk = NULL; +} + +/* Public Functions */ +void cif_isp10_sensor_mode_data_sync( + struct cif_isp10_device *dev, + unsigned int frame_id, + struct isp_supplemental_sensor_mode_data *data) +{ + struct cif_isp10_img_src_data *last_data; + struct cif_isp10_img_src_data *new_data; + + mutex_lock(&dev->img_src_exps.mutex); + if (dev->img_src_exps.data[0].v_frame_id < + dev->img_src_exps.data[1].v_frame_id) { + last_data = &dev->img_src_exps.data[0]; + new_data = &dev->img_src_exps.data[1]; + } else { + last_data = &dev->img_src_exps.data[1]; + new_data = &dev->img_src_exps.data[0]; + } + + if (frame_id >= new_data->v_frame_id) { + memcpy(data, + &new_data->data, + sizeof(struct isp_supplemental_sensor_mode_data)); + } else { + memcpy(data, + &last_data->data, + sizeof(struct isp_supplemental_sensor_mode_data)); + } + mutex_unlock(&dev->img_src_exps.mutex); +} + +int cif_isp10_streamon( + struct cif_isp10_device *dev, + u32 stream_ids) +{ + int ret = 0; + bool streamon_sp = stream_ids & CIF_ISP10_STREAM_SP; + bool streamon_mp = stream_ids & CIF_ISP10_STREAM_MP; + bool streamon_dma = stream_ids & CIF_ISP10_STREAM_DMA; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s, streamon SP = %d, streamon MP = %d, streamon DMA = %d\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state), + streamon_sp, streamon_mp, streamon_dma); + + if (!((streamon_sp && + (dev->sp_stream.state != CIF_ISP10_STATE_STREAMING)) || + (streamon_mp && + (dev->mp_stream.state != CIF_ISP10_STATE_STREAMING)))) + return 0; + + if (streamon_sp && + (dev->sp_stream.state != CIF_ISP10_STATE_READY)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "cannot start streaming on SP path, path not yet enabled\n"); + ret = -EFAULT; + goto err; + } + + if (streamon_mp && (dev->mp_stream.state != CIF_ISP10_STATE_READY)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "cannot start streaming on MP path, path not yet enabled\n"); + ret = -EFAULT; + goto err; + } + + if (streamon_sp && dev->config.mi_config.raw_enable && + (streamon_mp || + (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING))) { + cif_isp10_pltfrm_pr_err(dev->dev, + "cannot start streaming on SP path when MP is active and set to RAW output\n"); + ret = -EBUSY; + goto err; + } + + if (streamon_mp && + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING)) + dev->mp_stream.updt_cfg = true; + if (streamon_sp && + (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING)) + dev->sp_stream.updt_cfg = true; + + if (streamon_sp && dev->sp_stream.updt_cfg && + (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING)) { + ret = cif_isp10_stop(dev, false, true); + if (IS_ERR_VALUE(ret)) + goto err; + streamon_mp = true; + dev->mp_stream.updt_cfg = true; + } + if (streamon_mp && dev->mp_stream.updt_cfg && + (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING)) { + ret = cif_isp10_stop(dev, true, false); + if (IS_ERR_VALUE(ret)) + goto err; + + streamon_sp = true; + dev->sp_stream.updt_cfg = true; + } + + stream_ids = 0; + if (streamon_mp && dev->mp_stream.updt_cfg) + stream_ids |= CIF_ISP10_STREAM_MP; + if (streamon_sp && dev->sp_stream.updt_cfg) + stream_ids |= CIF_ISP10_STREAM_SP; + + ret = cif_isp10_config_cif(dev, stream_ids); + if (IS_ERR_VALUE(ret)) + goto err; + + ret = cif_isp10_start(dev, streamon_sp, streamon_mp); + if (IS_ERR_VALUE(ret)) + goto err; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state)); + + return 0; +err: + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state)); + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +int cif_isp10_streamoff( + struct cif_isp10_device *dev, + u32 stream_ids) +{ + int ret = 0; + bool streamoff_sp = stream_ids & CIF_ISP10_STREAM_SP; + bool streamoff_mp = stream_ids & CIF_ISP10_STREAM_MP; + bool streamoff_dma = stream_ids & CIF_ISP10_STREAM_DMA; + unsigned int streamoff_all = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s, streamoff SP = %d, streamoff MP = %d, streamoff DMA = %d\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state), + streamoff_sp, + streamoff_mp, + streamoff_dma); + + if (dev->config.flash_mode != CIF_ISP10_FLASH_MODE_OFF && + ((streamoff_sp && + (dev->mp_stream.state == CIF_ISP10_STATE_INACTIVE)) || + (streamoff_mp && + (dev->sp_stream.state == CIF_ISP10_STATE_INACTIVE)))) + cif_isp10_img_src_s_ctrl(dev->img_src, + CIF_ISP10_CID_FLASH_MODE, + CIF_ISP10_FLASH_MODE_OFF); + + streamoff_all = 0; + if (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING) { + if (streamoff_sp) + streamoff_all |= CIF_ISP10_STREAM_SP; + } else { + streamoff_all |= CIF_ISP10_STREAM_SP; + } + if (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING) { + if (streamoff_mp) + streamoff_all |= CIF_ISP10_STREAM_MP; + } else { + streamoff_all |= CIF_ISP10_STREAM_MP; + } + if (streamoff_all == (CIF_ISP10_STREAM_MP | CIF_ISP10_STREAM_SP)) + drain_workqueue(dev->vs_wq); + + ret = cif_isp10_stop(dev, streamoff_sp, streamoff_mp); + if (IS_ERR_VALUE(ret)) + goto err; + if ((streamoff_sp) && + (dev->sp_stream.state == CIF_ISP10_STATE_READY)) + dev->sp_stream.state = CIF_ISP10_STATE_INACTIVE; + if (streamoff_mp) { + dev->config.jpeg_config.enable = false; + dev->config.mi_config.raw_enable = false; + dev->config.mi_config.mp.output.width = 0; + dev->config.mi_config.mp.output.height = 0; + dev->config.mi_config.mp.output.pix_fmt = + CIF_UNKNOWN_FORMAT; + if (dev->mp_stream.state == CIF_ISP10_STATE_READY) + dev->mp_stream.state = CIF_ISP10_STATE_INACTIVE; + } + if (streamoff_dma) { + cif_isp10_stop_dma(dev); + if (dev->dma_stream.state == CIF_ISP10_STATE_READY) + dev->dma_stream.state = CIF_ISP10_STATE_INACTIVE; + } + if ((dev->dma_stream.state <= CIF_ISP10_STATE_INACTIVE) && + (dev->mp_stream.state <= CIF_ISP10_STATE_INACTIVE) && + (dev->sp_stream.state <= CIF_ISP10_STATE_INACTIVE)) { + dev->isp_dev.input_width = 0; + dev->isp_dev.input_height = 0; + dev->config.isp_config.ism_config.ism_en = 0; + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s, # frames received = %d\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state), + dev->isp_dev.frame_id >> 1); + + return 0; +err: + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s, DMA state = %s\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state), + cif_isp10_state_string(dev->dma_stream.state)); + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +int cif_isp10_suspend( + struct cif_isp10_device *dev) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state)); + + if ((dev->pm_state == CIF_ISP10_PM_STATE_SUSPENDED) || + (dev->pm_state == CIF_ISP10_PM_STATE_OFF)) + return 0; + + dev->sp_stream.saved_state = dev->sp_stream.state; + dev->mp_stream.saved_state = dev->mp_stream.state; + ret = cif_isp10_stop(dev, true, true); + if (IS_ERR_VALUE(ret)) + goto err; + ret = cif_isp10_set_pm_state(dev, CIF_ISP10_PM_STATE_SUSPENDED); + if (IS_ERR_VALUE(ret)) + goto err; + ret = cif_isp10_img_src_set_state(dev, CIF_ISP10_IMG_SRC_STATE_OFF); + if (IS_ERR_VALUE(ret)) + goto err; + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +int cif_isp10_resume( + struct cif_isp10_device *dev) +{ + u32 stream_ids = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "SP state = %s, MP state = %s\n", + cif_isp10_state_string(dev->sp_stream.state), + cif_isp10_state_string(dev->mp_stream.state)); + + if ((dev->sp_stream.saved_state == CIF_ISP10_STATE_READY) || + (dev->sp_stream.saved_state == CIF_ISP10_STATE_STREAMING)) { + dev->sp_stream.updt_cfg = true; + dev->sp_stream.state = CIF_ISP10_STATE_READY; + if (dev->sp_stream.saved_state == CIF_ISP10_STATE_STREAMING) + stream_ids |= CIF_ISP10_STREAM_SP; + } + if ((dev->mp_stream.saved_state == CIF_ISP10_STATE_READY) || + (dev->mp_stream.saved_state == CIF_ISP10_STATE_STREAMING)) { + dev->mp_stream.updt_cfg = true; + dev->mp_stream.state = CIF_ISP10_STATE_READY; + if (dev->mp_stream.saved_state == CIF_ISP10_STATE_STREAMING) + stream_ids |= CIF_ISP10_STREAM_MP; + } + + if ((dev->dma_stream.saved_state == CIF_ISP10_STATE_READY) || + (dev->dma_stream.saved_state == CIF_ISP10_STATE_STREAMING)) { + dev->dma_stream.state = CIF_ISP10_STATE_READY; + if (dev->dma_stream.saved_state == CIF_ISP10_STATE_STREAMING) + stream_ids |= CIF_ISP10_STREAM_DMA; + } + + return cif_isp10_streamon(dev, stream_ids); +} + +int cif_isp10_s_fmt( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + struct cif_isp10_strm_fmt *strm_fmt, + u32 stride) +{ + int ret; + + cif_isp10_pltfrm_pr_dbg(NULL, "%s\n", + cif_isp10_stream_id_string(stream_id)); + + switch (stream_id) { + case CIF_ISP10_STREAM_SP: + return cif_isp10_s_fmt_sp(dev, strm_fmt, stride); + case CIF_ISP10_STREAM_MP: + return cif_isp10_s_fmt_mp(dev, strm_fmt, stride); + case CIF_ISP10_STREAM_DMA: + return cif_isp10_s_fmt_dma(dev, strm_fmt, stride); + default: + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported stream ID %d\n", stream_id); + ret = -EINVAL; + goto err; + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + return ret; +} + +int cif_isp10_init( + struct cif_isp10_device *dev, + u32 stream_ids) +{ + int ret; + + cif_isp10_pltfrm_pr_dbg(NULL, "0x%08x\n", stream_ids); + + if (stream_ids & ~(CIF_ISP10_ALL_STREAMS)) { + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported stream IDs 0x%08x\n", + stream_ids); + ret = -EINVAL; + goto err; + } + + /* set default input, failure is not fatal here */ + if ((dev->sp_stream.state == CIF_ISP10_STATE_DISABLED) && + (dev->mp_stream.state == CIF_ISP10_STATE_DISABLED)) { + (void)cif_isp10_s_input(dev, 0); + dev->config.isp_config.si_enable = false; + dev->config.isp_config.ie_config.effect = + CIF_ISP10_IE_NONE; + } + + if (stream_ids & CIF_ISP10_STREAM_SP) + cif_isp10_init_stream(dev, CIF_ISP10_STREAM_SP); + if (stream_ids & CIF_ISP10_STREAM_MP) + cif_isp10_init_stream(dev, CIF_ISP10_STREAM_MP); + if (stream_ids & CIF_ISP10_STREAM_DMA) + cif_isp10_init_stream(dev, CIF_ISP10_STREAM_DMA); + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + return ret; +} + +int cif_isp10_release( + struct cif_isp10_device *dev, + int stream_ids) +{ + int ret; + struct cif_isp10_stream *strm_dev; + + cif_isp10_pltfrm_pr_dbg(NULL, "0x%08x\n", stream_ids); + + if ((dev->sp_stream.state == CIF_ISP10_STATE_DISABLED) && + (dev->mp_stream.state == CIF_ISP10_STATE_DISABLED) && + (dev->dma_stream.state == CIF_ISP10_STATE_DISABLED)) + return 0; + + if (stream_ids & ~(CIF_ISP10_ALL_STREAMS)) { + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported stream IDs 0x%08x\n", + stream_ids); + ret = -EINVAL; + goto err; + } + + if (stream_ids == CIF_ISP10_STREAM_MP) + strm_dev = &dev->mp_stream; + else if (stream_ids == CIF_ISP10_STREAM_SP) + strm_dev = &dev->sp_stream; + else + strm_dev = NULL; + + if (strm_dev) { + if (strm_dev->metadata.d) { + vfree(strm_dev->metadata.d); + strm_dev->metadata.d = NULL; + strm_dev->metadata.cnt = 0; + } + } + + if (stream_ids & CIF_ISP10_STREAM_SP) { + if (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING) { + cif_isp10_pltfrm_pr_warn(dev->dev, + "CIF SP in streaming state, should be stopped before release, trying to stop it\n"); + ret = cif_isp10_stop(dev, true, false); + if (IS_ERR_VALUE(ret)) + goto err; + } + dev->sp_stream.state = CIF_ISP10_STATE_DISABLED; + } + if (stream_ids & CIF_ISP10_STREAM_MP) { + if (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING) { + cif_isp10_pltfrm_pr_warn(dev->dev, + "CIF MP in streaming state, should be stopped before release, trying to stop it\n"); + ret = cif_isp10_stop(dev, false, true); + if (IS_ERR_VALUE(ret)) + goto err; + } + dev->mp_stream.state = CIF_ISP10_STATE_DISABLED; + } + + if ((dev->sp_stream.state == CIF_ISP10_STATE_DISABLED) && + (dev->mp_stream.state == CIF_ISP10_STATE_DISABLED)) { + if (IS_ERR_VALUE(cif_isp10_set_pm_state(dev, + CIF_ISP10_PM_STATE_OFF))) + cif_isp10_pltfrm_pr_warn(dev->dev, + "CIF power off failed\n"); + if (dev->img_src) { + if (IS_ERR_VALUE(cif_isp10_img_src_set_state(dev, + CIF_ISP10_IMG_SRC_STATE_OFF))) + cif_isp10_pltfrm_pr_warn(dev->dev, + "image source power off failed\n"); + dev->img_src = NULL; + } + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +struct cif_isp10_device *cif_isp10_create( + CIF_ISP10_PLTFRM_DEVICE pdev, + void (*sof_event)(struct cif_isp10_device *dev, __u32 frame_sequence), + void (*requeue_bufs)(struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id), + struct pltfrm_soc_cfg *soc_cfg) +{ + int ret; + struct cif_isp10_device *dev; + + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + /* Allocate needed structures */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + cif_isp10_pltfrm_pr_err(dev->dev, + "memory allocation failed\n"); + ret = -ENOMEM; + goto err; + } + dev->sof_event = sof_event; + dev->requeue_bufs = requeue_bufs; + + ret = cif_isp10_pltfrm_dev_init(dev, + &pdev, &dev->config.base_addr); + if (IS_ERR_VALUE(ret)) + goto err; + cif_isp10_pltfrm_debug_register_print_cb( + dev->dev, + (void (*)(void *, const char *))cif_isp10_debug_print_block, + dev); + + cif_isp10_pltfrm_soc_init(dev, soc_cfg); + + ret = cif_isp10_img_srcs_init(dev); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "cif_isp10_img_srcs_init failed\n"); + goto err; + } + + ret = cif_isp10_register_isrs(dev); + if (IS_ERR_VALUE(ret)) + goto err; + + (void)cif_isp10_init(dev, CIF_ISP10_ALL_STREAMS); + dev->pm_state = CIF_ISP10_PM_STATE_OFF; + dev->sp_stream.state = CIF_ISP10_STATE_DISABLED; + dev->sp_stream.id = CIF_ISP10_STREAM_SP; + dev->mp_stream.state = CIF_ISP10_STATE_DISABLED; + dev->mp_stream.id = CIF_ISP10_STREAM_MP; + dev->dma_stream.state = CIF_ISP10_STATE_DISABLED; + dev->dma_stream.id = CIF_ISP10_STREAM_DMA; + dev->config.mi_config.async_updt = 0; + cif_isp10_pltfrm_event_init(dev->dev, &dev->dma_stream.done); + cif_isp10_pltfrm_event_init(dev->dev, &dev->sp_stream.done); + cif_isp10_pltfrm_event_init(dev->dev, &dev->mp_stream.done); + + dev->img_src_exps.exp_valid_frms = 2; + mutex_init(&dev->img_src_exps.mutex); + memset(&dev->img_src_exps.data, 0x00, sizeof(dev->img_src_exps.data)); + spin_lock_init(&dev->img_src_exps.lock); + INIT_LIST_HEAD(&dev->img_src_exps.list); + dev->vs_wq = alloc_workqueue("cif isp10 vs workqueue", + WQ_UNBOUND | WQ_MEM_RECLAIM, 1); + + /* TBD: clean this up */ + init_output_formats(); + + return dev; +err: + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + if (!IS_ERR_OR_NULL(dev)) + kfree(dev); + return ERR_PTR(ret); +} + +void cif_isp10_destroy( + struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + if (!IS_ERR_OR_NULL(dev)) + kfree(dev); +} + +int cif_isp10_s_input( + struct cif_isp10_device *dev, + unsigned int input) +{ + int ret; + enum cif_isp10_inp inp; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "setting input to %s\n", + cif_isp10_inp_string( + cif_isp10_input_index2inp(dev, input))); + + if (input >= dev->img_src_cnt + CIF_ISP10_INP_DMA_CNT()) { + cif_isp10_pltfrm_pr_err(NULL, + "invalid input %d\n", input); + ret = -EINVAL; + goto err; + } + + dev->img_src = NULL; + + inp = cif_isp10_input_index2inp(dev, input); + + /* DMA -> ISP or DMA -> IE */ + if ((inp == CIF_ISP10_INP_DMA) || (inp == CIF_ISP10_INP_DMA_IE)) + dev->config.isp_config.input = + &dev->config.mi_config.dma.output; + else { + dev->img_src = dev->img_src_array[input]; + dev->config.isp_config.input = + &dev->config.img_src_output.frm_fmt; + } + dev->config.input_sel = inp; + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + return ret; +} + +const char *cif_isp10_g_input_name( + struct cif_isp10_device *dev, + unsigned int input_index) +{ + if (input_index >= + dev->img_src_cnt + CIF_ISP10_INP_DMA_CNT()) { + cif_isp10_pltfrm_pr_dbg(NULL, + "index %d out of bounds\n", + input_index); + return NULL; + } + + if (input_index < dev->img_src_cnt) + return cif_isp10_img_src_g_name( + dev->img_src_array[input_index]); + else + return cif_isp10_inp_string(CIF_ISP10_INP_DMA + + ((input_index - dev->img_src_cnt) << 24)); +} + +int cif_isp10_qbuf( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream, + struct cif_isp10_buffer *buf) +{ + int ret = 0; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "%s\n", + cif_isp10_stream_id_string(stream)); + + switch (stream) { + case CIF_ISP10_STREAM_SP: + list_add_tail(&buf->queue, &dev->sp_stream.buf_queue); + break; + case CIF_ISP10_STREAM_MP: + list_add_tail(&buf->queue, &dev->mp_stream.buf_queue); + break; + case CIF_ISP10_STREAM_DMA: + list_add_tail(&buf->queue, &dev->dma_stream.buf_queue); + if ((dev->dma_stream.state == CIF_ISP10_STATE_STREAMING) && + !CIF_ISP10_MI_IS_BUSY(dev)) + cif_isp10_dma_next_buff(dev); + break; + case CIF_ISP10_STREAM_ISP: + WARN_ON(1); + break; + default: + cif_isp10_pltfrm_pr_err(dev->dev, + "unknown stream %d\n", stream); + ret = -EINVAL; + goto err; + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +int cif_isp10_reqbufs( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id strm, + struct v4l2_requestbuffers *req) +{ + struct cif_isp10_stream *strm_dev = NULL; + + switch (strm) { + case CIF_ISP10_STREAM_MP: + strm_dev = &dev->mp_stream; + break; + case CIF_ISP10_STREAM_SP: + strm_dev = &dev->sp_stream; + break; + default: + cif_isp10_pltfrm_pr_err(dev->dev, + "unknown stream id%d\n", strm); + break; + } + + strm_dev->metadata.cnt = req->count; + + return 0; +} + +int cif_isp10_s_exp( + struct cif_isp10_device *dev, + struct cif_isp10_img_src_ext_ctrl *exp_ctrl) +{ + struct cif_isp10_img_src_exp *exp = NULL; + unsigned long lock_flags; + int retval; + + if (!dev->vs_wq) + return -ENODEV; + + exp = kmalloc(sizeof(*exp), GFP_KERNEL); + if (!exp) { + retval = -ENOMEM; + goto failed; + } + + exp->exp = exp_ctrl; + + spin_lock_irqsave(&dev->img_src_exps.lock, lock_flags); + list_add_tail(&exp->list, &dev->img_src_exps.list); + spin_unlock_irqrestore(&dev->img_src_exps.lock, lock_flags); + + return 0; + +failed: + return retval; +} + +int cif_isp10_s_isp_metadata( + struct cif_isp10_device *dev, + struct cif_isp10_isp_readout_work *readout_work, + struct cifisp_isp_other_cfg *new_other, + struct cifisp_isp_meas_cfg *new_meas, + struct cifisp_stat_buffer *new_stats) +{ + unsigned int stream_id = + readout_work->stream_id; + struct videobuf_buffer *vb = + readout_work->vb; + struct cif_isp10_stream *strm_dev = NULL; + struct v4l2_buffer_metadata_s *metadata; + struct cifisp_isp_metadata *isp_last; + + switch (stream_id) { + case CIF_ISP10_STREAM_MP: + strm_dev = &dev->mp_stream; + break; + case CIF_ISP10_STREAM_SP: + strm_dev = &dev->sp_stream; + break; + default: + cif_isp10_pltfrm_pr_err(dev->dev, + "unknown stream id%d\n", stream_id); + break; + } + + if (vb && strm_dev->metadata.d) { + metadata = (struct v4l2_buffer_metadata_s *) + (strm_dev->metadata.d + + vb->i * CAMERA_METADATA_LEN); + + metadata->frame_id = readout_work->frame_id; + isp_last = + (struct cifisp_isp_metadata *)metadata->isp; + + if (new_meas) { + if ((isp_last->meas_cfg.s_frame_id == 0xffffffff) || + (isp_last->meas_cfg.s_frame_id < + new_meas->s_frame_id)) { + memcpy(&isp_last->meas_cfg, + new_meas, + sizeof(struct cifisp_isp_meas_cfg)); + } + } + + if (new_other) { + if ((isp_last->other_cfg.s_frame_id == 0xffffffff) || + (isp_last->other_cfg.s_frame_id < + new_other->s_frame_id)) { + memcpy(&isp_last->other_cfg, + new_other, + sizeof(struct cifisp_isp_other_cfg)); + } + } + + if (new_stats) { + memcpy(&isp_last->meas_stat, + new_stats, + sizeof(struct cifisp_stat_buffer)); + metadata->sensor.exp_time = + new_stats->sensor_mode.exp_time; + metadata->sensor.gain = + new_stats->sensor_mode.gain; + } else { + isp_last->meas_stat.meas_type = 0x00; + } + } + + if (vb) { + cif_isp10_pltfrm_pr_dbg(NULL, + "frame done\n"); + wake_up(&vb->done); + } + + return 0; +} + +int cif_isp10_mmap( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + struct vm_area_struct *vma) +{ + struct cif_isp10_stream *strm_dev; + void *mem_vaddr; + int retval = 0, pages; + unsigned long mem_size; + + switch (stream_id) { + case CIF_ISP10_STREAM_MP: + strm_dev = &dev->mp_stream; + break; + case CIF_ISP10_STREAM_SP: + strm_dev = &dev->sp_stream; + break; + default: + cif_isp10_pltfrm_pr_err(dev->dev, + "unknown stream id%d\n", stream_id); + return -ENODEV; + } + + mem_size = vma->vm_end - vma->vm_start; + if (mem_size > strm_dev->metadata.cnt * CAMERA_METADATA_LEN) { + retval = -ENOMEM; + cif_isp10_pltfrm_pr_err(dev->dev, + "mmap size(0x%lx) > metadata memory size(0x%lx), so failed!", + mem_size, + (unsigned long)(strm_dev->metadata.cnt + * CAMERA_METADATA_LEN)); + goto done; + } + + pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); + mem_vaddr = (struct v4l2_buffer_metadata_s *)vmalloc_user(pages); + if (!mem_vaddr) { + cif_isp10_pltfrm_pr_err(dev->dev, + "vmalloc (%d bytes) failed for %s metadata\n", + pages, + (stream_id == CIF_ISP10_STREAM_MP) ? "mp" : "sp"); + retval = -ENOMEM; + goto done; + } + + /* Try to remap memory */ + retval = remap_vmalloc_range(vma, mem_vaddr, 0); + if (retval < 0) { + cif_isp10_pltfrm_pr_err(dev->dev, + "mmap: remap failed with error %d. ", retval); + vfree(mem_vaddr); + goto done; + } + + strm_dev->metadata.d = (unsigned char *)mem_vaddr; + + vma->vm_private_data = (void *)&strm_dev->metadata; + +done: + return retval; +} + +int cif_isp10_get_target_frm_size( + struct cif_isp10_device *dev, + u32 *target_width, + u32 *target_height) +{ + if (dev->sp_stream.state >= CIF_ISP10_STATE_READY) { + if ((dev->mp_stream.state >= CIF_ISP10_STATE_READY) && + (dev->config.mi_config.mp.output.width > + dev->config.mi_config.sp.output.width)) + *target_width = + dev->config.mi_config.mp.output.width; + else + *target_width = + dev->config.mi_config.sp.output.width; + if ((dev->mp_stream.state >= CIF_ISP10_STATE_READY) && + (dev->config.mi_config.mp.output.height > + dev->config.mi_config.sp.output.height)) + *target_height = + dev->config.mi_config.mp.output.height; + else + *target_height = + dev->config.mi_config.sp.output.height; + } else if (dev->mp_stream.state >= CIF_ISP10_STATE_READY) { + *target_width = dev->config.mi_config.mp.output.width; + *target_height = dev->config.mi_config.mp.output.height; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "cannot get target frame size, no path ready\n"); + return -EFAULT; + } + return 0; +} + +int cif_isp10_calc_isp_cropping( + struct cif_isp10_device *dev, + u32 *width, + u32 *height, + u32 *h_offs, + u32 *v_offs) +{ + int ret = 0; + u32 input_width; + u32 input_height; + u32 target_width; + u32 target_height; + + if (IS_ERR_OR_NULL(dev->config.isp_config.input)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "no input selected for ISP\n"); + ret = -EFAULT; + goto err; + } + + input_width = dev->config.isp_config.input->defrect.width; + input_height = dev->config.isp_config.input->defrect.height; + + ret = cif_isp10_get_target_frm_size(dev, + &target_width, &target_height); + if (IS_ERR_VALUE(ret)) + goto err; + + *width = input_width; + *height = input_width * target_height / target_width; + *v_offs = 0; + *h_offs = 0; + *height &= ~1; + if (*height < input_height) + /* vertical cropping */ + *v_offs = (input_height - *height) >> 1; + else if (*height > input_height) { + /* horizontal cropping */ + *height = input_height; + *width = input_height * target_width / target_height; + *width &= ~1; + *h_offs = (input_width - *width) >> 1; + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +int cif_isp10_calc_min_out_buff_size( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + u32 *size) +{ + int ret = 0; + enum cif_isp10_pix_fmt pix_fmt; + u32 llength; + u32 height; + u32 bpp; + struct cif_isp10_mi_path_config *mi_path; + struct cif_isp10_stream *stream; + + cif_isp10_pltfrm_pr_dbg(NULL, + "%s\n", + cif_isp10_stream_id_string(stream_id)); + + if (stream_id == CIF_ISP10_STREAM_SP) { + mi_path = &dev->config.mi_config.sp; + stream = &dev->sp_stream; + } else if (stream_id == CIF_ISP10_STREAM_MP) { + mi_path = &dev->config.mi_config.mp; + stream = &dev->mp_stream; + } else if (stream_id == CIF_ISP10_STREAM_DMA) { + mi_path = &dev->config.mi_config.dma; + stream = &dev->dma_stream; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "cannot calculate buffer size for this stream (%s)\n", + cif_isp10_stream_id_string(stream_id)); + ret = -EINVAL; + goto err; + } + + if (stream->state < CIF_ISP10_STATE_READY) { + cif_isp10_pltfrm_pr_err(NULL, + "cannot calculate buffer size, %s stream not ready\n", + cif_isp10_stream_id_string(stream_id)); + ret = -EINVAL; + goto err; + } + pix_fmt = mi_path->output.pix_fmt; + llength = mi_path->llength; + height = mi_path->output.height; + cif_isp10_pltfrm_pr_dbg(NULL, + "mi_path->llength: 0x%x\n", + mi_path->llength); + + if (CIF_ISP10_PIX_FMT_IS_RAW_BAYER(pix_fmt) && + CIF_ISP10_PIX_FMT_GET_BPP(pix_fmt) > 8) + /* RAW input > 8BPP is stored with 16BPP by MI */ + bpp = 16; + else + bpp = CIF_ISP10_PIX_FMT_GET_BPP(pix_fmt); + *size = llength * height * bpp / 8; + + cif_isp10_pltfrm_pr_dbg(NULL, + "calculated buffer size: %d\n", + *size); + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with err %d\n", ret); + return ret; +} + +int cif_isp10_s_ctrl( + struct cif_isp10_device *dev, + const enum cif_isp10_cid id, + int val) +{ + cif_isp10_pltfrm_pr_dbg(NULL, + "id %d, val %d\n", + id, val); + + switch (id) { + case CIF_ISP10_CID_SUPER_IMPOSE: + dev->config.isp_config.si_enable = val; + break; + case CIF_ISP10_CID_IMAGE_EFFECT: + if ((u32)val > CIF_ISP10_IE_NONE) { + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported image effect %d\n", val); + return -EINVAL; + } + dev->config.isp_config.ie_config.effect = val; + break; + case CIF_ISP10_CID_JPEG_QUALITY: + if ((u32)val > 100) { + cif_isp10_pltfrm_pr_err(NULL, + "JPEG quality (%d) must be in [1..100]\n", val); + return -EINVAL; + } + dev->config.jpeg_config.ratio = val; + break; + case CIF_ISP10_CID_FLASH_MODE: + if ((u32)val > CIF_ISP10_FLASH_MODE_TORCH) { + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported flash mode (%d)\n", val); + return -EINVAL; + } + dev->config.flash_mode = val; + cif_isp10_img_src_s_ctrl( + dev->img_src, + CIF_ISP10_CID_FLASH_MODE, + dev->config.flash_mode); + if (dev->config.flash_mode == CIF_ISP10_FLASH_MODE_FLASH) { + do_gettimeofday(&dev->flash_t.mainflash_start_t); + dev->flash_t.mainflash_start_t.tv_usec += + dev->flash_t.flash_turn_on_time; + dev->flash_t.mainflash_end_t = + dev->flash_t.mainflash_start_t; + dev->flash_t.mainflash_end_t.tv_sec += + dev->flash_t.flash_on_timeout; + } else if (dev->config.flash_mode == + CIF_ISP10_FLASH_MODE_TORCH) { + do_gettimeofday(&dev->flash_t.preflash_start_t); + dev->flash_t.preflash_end_t = + dev->flash_t.preflash_start_t; + dev->flash_t.preflash_end_t.tv_sec = 0x00; + dev->flash_t.preflash_end_t.tv_usec = 0x00; + } else if (dev->config.flash_mode == CIF_ISP10_FLASH_MODE_OFF) { + do_gettimeofday(&dev->flash_t.preflash_end_t); + if (dev->flash_t.preflash_end_t.tv_sec * 1000000 + + dev->flash_t.preflash_end_t.tv_usec < + dev->flash_t.mainflash_end_t.tv_sec * 1000000 + + dev->flash_t.mainflash_end_t.tv_usec) { + dev->flash_t.mainflash_end_t = + dev->flash_t.preflash_end_t; + } + } + break; + case CIF_ISP10_CID_WB_TEMPERATURE: + case CIF_ISP10_CID_ANALOG_GAIN: + case CIF_ISP10_CID_EXPOSURE_TIME: + case CIF_ISP10_CID_BLACK_LEVEL: + case CIF_ISP10_CID_FOCUS_ABSOLUTE: + case CIF_ISP10_CID_AUTO_N_PRESET_WHITE_BALANCE: + case CIF_ISP10_CID_SCENE_MODE: + case CIF_ISP10_CID_AUTO_FPS: + case CIF_ISP10_CID_HFLIP: + case CIF_ISP10_CID_VFLIP: + return cif_isp10_img_src_s_ctrl(dev->img_src, + id, val); + default: + cif_isp10_pltfrm_pr_err(dev->dev, + "unknown/unsupported control %d\n", id); + return -EINVAL; + } + + return 0; +} + +/* end */ + +enum { + isp_data_loss = 0, + isp_pic_size_err, + mipi_fifo_err, + dphy_err_sot, + dphy_err_sot_sync, + dphy_err_eot_sync, + dphy_err_ctrl, + csi_err_protocol, + csi_ecc1_err, + csi_ecc2_err, + csi_cs_err, +}; + +static void cif_isp10_hw_restart(struct cif_isp10_device *dev) +{ + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + cif_isp10_hw_errors[isp_pic_size_err].count = 0; + cif_isp10_hw_errors[isp_data_loss].count = 0; + cif_isp10_hw_errors[csi_err_protocol].count = 0; + cif_isp10_hw_errors[csi_ecc1_err].count = 0; + cif_isp10_hw_errors[csi_ecc2_err].count = 0; + cif_isp10_hw_errors[csi_cs_err].count = 0; + cif_iowrite32(0x00000841, dev->config.base_addr + CIF_IRCL); + cif_iowrite32(0x0, dev->config.base_addr + CIF_IRCL); + + /* enable mipi frame end interrupt */ + cif_iowrite32(CIF_MIPI_FRAME_END, + dev->config.base_addr + CIF_MIPI_IMSC); + /* enable csi protocol errors interrupts */ + cif_iowrite32OR(CIF_MIPI_ERR_CSI, + dev->config.base_addr + CIF_MIPI_IMSC); + /* enable dphy errors interrupts */ + cif_iowrite32OR(CIF_MIPI_ERR_DPHY, + dev->config.base_addr + CIF_MIPI_IMSC); + /* add fifo error */ + cif_iowrite32OR(CIF_MIPI_SYNC_FIFO_OVFLW(3), + dev->config.base_addr + CIF_MIPI_IMSC); + /* add data overflow_error */ + cif_iowrite32OR(CIF_MIPI_ADD_DATA_OVFLW, + dev->config.base_addr + CIF_MIPI_IMSC); + + cif_iowrite32(0x0, + dev->config.base_addr + CIF_MI_MP_Y_OFFS_CNT_INIT); + cif_iowrite32(0x0, + dev->config.base_addr + + CIF_MI_MP_CR_OFFS_CNT_INIT); + cif_iowrite32(0x0, + dev->config.base_addr + + CIF_MI_MP_CB_OFFS_CNT_INIT); + cif_iowrite32(0x0, + dev->config.base_addr + CIF_MI_SP_Y_OFFS_CNT_INIT); + cif_iowrite32(0x0, + dev->config.base_addr + + CIF_MI_SP_CR_OFFS_CNT_INIT); + cif_iowrite32(0x0, + dev->config.base_addr + + CIF_MI_SP_CB_OFFS_CNT_INIT); + cif_iowrite32OR(CIF_MI_CTRL_INIT_OFFSET_EN, + dev->config.base_addr + CIF_MI_CTRL); + + /* Enable ISP ! */ + cif_iowrite32OR(CIF_ISP_CTRL_ISP_CFG_UPD | + CIF_ISP_CTRL_ISP_INFORM_ENABLE | + CIF_ISP_CTRL_ISP_ENABLE, + dev->config.base_addr + CIF_ISP_CTRL); + /* enable MIPI */ + cif_iowrite32OR(CIF_MIPI_CTRL_OUTPUT_ENA, + dev->config.base_addr + CIF_MIPI_CTRL); +} + +int cif_isp10_mipi_isr(unsigned int mipi_mis, void *cntxt) +{ + struct cif_isp10_device *dev = + (struct cif_isp10_device *)cntxt; + unsigned int mipi_ris = 0; + + mipi_ris = cif_ioread32(dev->config.base_addr + CIF_MIPI_RIS); + mipi_mis = cif_ioread32(dev->config.base_addr + CIF_MIPI_MIS); + + cif_isp10_pltfrm_rtrace_printf(dev->dev, + "MIPI_MIS %08x, MIPI_RIS %08x, MIPI_IMSC %08x\n", + mipi_mis, + mipi_ris, + cif_ioread32(dev->config.base_addr + CIF_MIPI_IMSC)); + + cif_iowrite32(~0, + dev->config.base_addr + CIF_MIPI_ICR); + + if (mipi_mis & CIF_MIPI_ERR_DPHY) { + cif_isp10_pltfrm_pr_warn(dev->dev, + "CIF_MIPI_ERR_DPHY: 0x%x\n", mipi_mis); + + /* + * Disable DPHY errctrl interrupt, because this dphy + * erctrl signal is assert and until the next changes + * in line state. This time is may be too long and cpu + * is hold in this interrupt. + */ + if (mipi_mis & CIF_MIPI_ERR_CTRL(3)) + cif_iowrite32AND(~(CIF_MIPI_ERR_CTRL(3)), + dev->config.base_addr + CIF_MIPI_IMSC); + } + + if (mipi_mis & CIF_MIPI_ERR_CSI) { + cif_isp10_pltfrm_pr_warn(dev->dev, + "CIF_MIPI_ERR_CSI: 0x%x\n", mipi_mis); + } + + if (mipi_mis & CIF_MIPI_SYNC_FIFO_OVFLW(3)) { + cif_isp10_pltfrm_pr_warn(dev->dev, + "CIF_MIPI_SYNC_FIFO_OVFLW: 0x%x\n", mipi_mis); + } + + if (mipi_mis == CIF_MIPI_FRAME_END) { + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + cif_iowrite32OR(CIF_MIPI_ERR_CTRL(3), + dev->config.base_addr + CIF_MIPI_IMSC); + } + + mipi_mis = cif_ioread32(dev->config.base_addr + CIF_MIPI_MIS); + + if (mipi_mis) { + cif_isp10_pltfrm_pr_err(dev->dev, + "mipi_mis icr err: 0x%x\n", mipi_mis); + } + + return 0; +} + +/* ======================================================================== */ +int cif_isp10_isp_isr(unsigned int isp_mis, void *cntxt) +{ + struct cif_isp10_device *dev = + (struct cif_isp10_device *)cntxt; + unsigned int isp_mis_tmp = 0; + unsigned int isp_err = 0; + struct timeval tv; + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "ISP_MIS %08x, ISP_RIS %08x, ISP_IMSC %08x\n", + isp_mis, + cif_ioread32(dev->config.base_addr + CIF_ISP_RIS), + cif_ioread32(dev->config.base_addr + CIF_ISP_IMSC)); + + if (isp_mis & CIF_ISP_V_START) { + struct cif_isp10_isp_vs_work *vs_wk; + struct cif_isp10_img_src_exp *exp; + + do_gettimeofday(&tv); + dev->b_isp_frame_in = false; + dev->b_mi_frame_end = false; + cifisp_v_start(&dev->isp_dev, &tv); + + cif_iowrite32(CIF_ISP_V_START, + dev->config.base_addr + CIF_ISP_ICR); + isp_mis_tmp = cif_ioread32(dev->config.base_addr + CIF_ISP_MIS); + if (isp_mis_tmp & CIF_ISP_V_START) + cif_isp10_pltfrm_pr_err(dev->dev, + "isp icr v_statr err: 0x%x\n", + isp_mis_tmp); + + if (!dev->config.mi_config.async_updt) { + cif_iowrite32OR(CIF_ISP_CTRL_ISP_GEN_CFG_UPD, + dev->config.base_addr + CIF_ISP_CTRL); + cif_isp10_pltfrm_pr_dbg(NULL, + "CIF_ISP_CTRL_ISP_GEN_CFG_UPD\n"); + } + if (dev->sof_event) + dev->sof_event(dev, dev->isp_dev.frame_id >> 1); + spin_lock(&dev->img_src_exps.lock); + if (!list_empty(&dev->img_src_exps.list)) { + exp = list_first_entry(&dev->img_src_exps.list, + struct cif_isp10_img_src_exp, + list); + list_del(&exp->list); + } else { + exp = NULL; + } + spin_unlock(&dev->img_src_exps.lock); + + if (exp) { + vs_wk = kmalloc(sizeof(*vs_wk), + GFP_KERNEL); + if (vs_wk) { + vs_wk->cmd = CIF_ISP10_VS_EXP; + vs_wk->dev = dev; + vs_wk->param = (void *)exp; + INIT_WORK((struct work_struct *)&vs_wk->work, + cif_isp10_vs_work); + if (!queue_work(dev->vs_wq, + (struct work_struct *)&vs_wk->work)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "%s: queue work failed\n", __func__); + kfree(vs_wk); + } + } + } + } + + if (isp_mis & CIF_ISP_FRAME_IN) { + do_gettimeofday(&tv); + cif_iowrite32(CIF_ISP_FRAME_IN, + dev->config.base_addr + CIF_ISP_ICR); + cifisp_frame_in(&dev->isp_dev, &tv); + } + + if ((isp_mis & (CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR))) { + dev->sp_stream.stall = true; + dev->mp_stream.stall = true; + + if ((isp_mis & CIF_ISP_PIC_SIZE_ERROR)) { + /* Clear pic_size_error */ + cif_iowrite32(CIF_ISP_PIC_SIZE_ERROR, + dev->config.base_addr + + CIF_ISP_ICR); + cif_isp10_hw_errors[isp_pic_size_err].count++; + isp_err = + cif_ioread32(dev->config.base_addr + + CIF_ISP_ERR); + dev_err(dev->dev, + "CIF_ISP_PIC_SIZE_ERROR (0x%08x)", + isp_err); + cif_iowrite32(isp_err, + dev->config.base_addr + + CIF_ISP_ERR_CLR); + } else if ((isp_mis & CIF_ISP_DATA_LOSS)) { + /* Clear data_loss */ + cif_iowrite32(CIF_ISP_DATA_LOSS, + dev->config.base_addr + + CIF_ISP_ICR); + cif_isp10_hw_errors[isp_data_loss].count++; + dev_err(dev->dev, + "CIF_ISP_DATA_LOSS\n"); + cif_iowrite32(CIF_ISP_DATA_LOSS, + dev->config.base_addr + + CIF_ISP_ICR); + } + + /* Stop ISP */ + cif_iowrite32AND(~CIF_ISP_CTRL_ISP_INFORM_ENABLE & + ~CIF_ISP_CTRL_ISP_ENABLE, + dev->config.base_addr + CIF_ISP_CTRL); + /* isp_update */ + cif_iowrite32OR(CIF_ISP_CTRL_ISP_CFG_UPD, + dev->config.base_addr + CIF_ISP_CTRL); + cif_isp10_hw_restart(dev); + } + + if (isp_mis & CIF_ISP_FRAME_IN) { + cif_iowrite32(CIF_ISP_FRAME_IN, + dev->config.base_addr + CIF_ISP_ICR); + isp_mis_tmp = cif_ioread32(dev->config.base_addr + CIF_ISP_MIS); + if (isp_mis_tmp & CIF_ISP_FRAME_IN) + cif_isp10_pltfrm_pr_err(dev->dev, + "isp icr frame_in err: 0x%x\n", + isp_mis_tmp); + + /* restart MI if CIF has run out of buffers */ + if (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel) && + !CIF_ISP10_MI_IS_BUSY(dev) && + !dev->config.jpeg_config.busy && + (dev->config.mi_config.async_updt || + (!dev->sp_stream.next_buf && + !dev->mp_stream.next_buf))){ + u32 mi_isr = 0; + + if (dev->sp_stream.state == CIF_ISP10_STATE_STREAMING) + mi_isr |= CIF_MI_SP_FRAME; + if (dev->mp_stream.state == CIF_ISP10_STATE_STREAMING) + mi_isr |= CIF_MI_MP_FRAME; + cif_iowrite32(mi_isr, + dev->config.base_addr + CIF_MI_ISR); + } + } + + if (isp_mis & CIF_ISP_FRAME) { + /* Clear Frame In (ISP) */ + cif_iowrite32(CIF_ISP_FRAME, + dev->config.base_addr + CIF_ISP_ICR); + isp_mis_tmp = cif_ioread32(dev->config.base_addr + CIF_ISP_MIS); + if (isp_mis_tmp & CIF_ISP_FRAME) + cif_isp10_pltfrm_pr_err(dev->dev, + "isp icr frame end err: 0x%x\n", + isp_mis_tmp); + + if (dev->b_mi_frame_end) + cif_isp10_update_ism_dcr_rsz(dev); + dev->b_isp_frame_in = true; + } + + cifisp_isp_isr(&dev->isp_dev, isp_mis); + + return 0; +} + +/* ======================================================================== */ + +void init_output_formats(void) +{ + unsigned int i = 0; + int ret = 0; /* RF*/ + int xgold_num_format = 0; /*RF*/ + + xgold_num_format = + (sizeof(cif_isp10_output_format) / sizeof(struct cif_isp10_fmt)); + + for (i = 0; i < xgold_num_format; i++) { + struct v4l2_fmtdesc fmtdesc; + + memset(&fmtdesc, 0, sizeof(fmtdesc)); + fmtdesc.index = i; + fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + strlcpy((&fmtdesc)->description, + cif_isp10_output_format[(&fmtdesc)->index].name, + sizeof((&fmtdesc)->description)); + (&fmtdesc)->pixelformat = + cif_isp10_output_format[(&fmtdesc)->index].fourcc; + (&fmtdesc)->flags = + cif_isp10_output_format[(&fmtdesc)->index].flags; + + if (ret < 0) + break; + + output_formats[i] = fmtdesc; + } +} + +int get_cif_isp10_output_format_size(void) +{ + return sizeof(cif_isp10_output_format) / sizeof(struct cif_isp10_fmt); +} + +struct cif_isp10_fmt *get_cif_isp10_output_format(int index) +{ + struct cif_isp10_fmt *fmt = NULL; + + if ((index >= 0) && (index < get_cif_isp10_output_format_size())) + fmt = &cif_isp10_output_format[index]; + + return fmt; +} + +struct v4l2_fmtdesc *get_cif_isp10_output_format_desc(int index) +{ + struct v4l2_fmtdesc *desc = NULL; + + if ((index >= 0) && (index < get_cif_isp10_output_format_desc_size())) + desc = &output_formats[index]; + + return desc; +} + +int get_cif_isp10_output_format_desc_size(void) +{ + return ARRAY_SIZE(cif_isp10_output_format); +} diff --git a/drivers/media/platform/rk-isp10/cif_isp10.h b/drivers/media/platform/rk-isp10/cif_isp10.h new file mode 100644 index 000000000000..c8eb6c5377ee --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10.h @@ -0,0 +1,713 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _CIF_ISP10_H +#define _CIF_ISP10_H + +#include +#include "cif_isp10_pltfrm.h" +#include "cif_isp10_img_src.h" +#include "cif_isp10_isp.h" +#include +#include +#include +/*****************************************************************************/ +/* Definitions */ + +#define CONFIG_CIF_ISP_AUTO_UPD_CFG_BUG + +#define CIF_ISP10_NUM_INPUTS 10 + +/* FORMAT */ +#define MAX_NB_FORMATS 30 + +#define CONTRAST_DEF 0x80 +#define BRIGHTNESS_DEF 0x0 +#define HUE_DEF 0x0 + +/* + * MIPI CSI2.0 + */ +#define CSI2_DT_YUV420_8b (0x18) +#define CSI2_DT_YUV420_10b (0x19) +#define CSI2_DT_YUV422_8b (0x1E) +#define CSI2_DT_YUV422_10b (0x1F) +#define CSI2_DT_RGB565 (0x22) +#define CSI2_DT_RGB666 (0x23) +#define CSI2_DT_RGB888 (0x24) +#define CSI2_DT_RAW8 (0x2A) +#define CSI2_DT_RAW10 (0x2B) +#define CSI2_DT_RAW12 (0x2C) + +enum cif_isp10_img_src_state { + CIF_ISP10_IMG_SRC_STATE_OFF = 0, + CIF_ISP10_IMG_SRC_STATE_SW_STNDBY = 1, + CIF_ISP10_IMG_SRC_STATE_STREAMING = 2 +}; + +enum cif_isp10_state { + /* path not yet opened: */ + CIF_ISP10_STATE_DISABLED = 0, + /* path opened but not yet configured: */ + CIF_ISP10_STATE_INACTIVE = 1, + /* path opened and configured, ready for streaming: */ + CIF_ISP10_STATE_READY = 2, + /* path is streaming: */ + CIF_ISP10_STATE_STREAMING = 3 +}; + +enum cif_isp10_pm_state { + CIF_ISP10_PM_STATE_OFF, + CIF_ISP10_PM_STATE_SUSPENDED, + CIF_ISP10_PM_STATE_SW_STNDBY, + CIF_ISP10_PM_STATE_STREAMING +}; + +enum cif_isp10_inp { + CIF_ISP10_INP_CSI = 0x10000000, + CIF_ISP10_INP_CPI = 0x20000000, + + CIF_ISP10_INP_DMA = 0x30000000, /* DMA -> ISP */ + CIF_ISP10_INP_DMA_IE = 0x31000000, /* DMA -> IE */ + CIF_ISP10_INP_DMA_SP = 0x32000000, /* DMA -> SP */ + CIF_ISP10_INP_DMA_MAX = 0x33000000, + + CIF_ISP10_INP_MAX = 0x7fffffff +}; + +#define CIF_ISP10_INP_IS_DMA(inp) \ + (((inp) & 0xf0000000) == CIF_ISP10_INP_DMA) +#define CIF_ISP10_INP_IS_MIPI(inp) \ + (((inp) & 0xf0000000) == CIF_ISP10_INP_CSI) +#define CIF_ISP10_INP_IS_DVP(inp) \ + (((inp) & 0xf0000000) == CIF_ISP10_INP_CPI) +#define CIF_ISP10_INP_NEED_ISP(inp) \ + ((inp) < CIF_ISP10_INP_DMA_IE) +#define CIF_ISP10_INP_DMA_CNT() \ + ((CIF_ISP10_INP_DMA_MAX -\ + CIF_ISP10_INP_DMA) >> 24) + +enum cif_isp10_pinctrl_state { + CIF_ISP10_PINCTRL_STATE_SLEEP, + CIF_ISP10_PINCTRL_STATE_INACTIVE, + CIF_ISP10_PINCTRL_STATE_DEFAULT, + CIF_ISP10_PINCTRL_STATE_ACTIVE +}; + +enum cif_isp10_flash_mode { + CIF_ISP10_FLASH_MODE_OFF, + CIF_ISP10_FLASH_MODE_FLASH, + CIF_ISP10_FLASH_MODE_TORCH, +}; + +enum cif_isp10_cid { + CIF_ISP10_CID_FLASH_MODE = 0, + CIF_ISP10_CID_EXPOSURE_TIME = 1, + CIF_ISP10_CID_ANALOG_GAIN = 2, + CIF_ISP10_CID_WB_TEMPERATURE = 3, + CIF_ISP10_CID_BLACK_LEVEL = 4, + CIF_ISP10_CID_AUTO_GAIN = 5, + CIF_ISP10_CID_AUTO_EXPOSURE = 6, + CIF_ISP10_CID_AUTO_WHITE_BALANCE = 7, + CIF_ISP10_CID_FOCUS_ABSOLUTE = 8, + CIF_ISP10_CID_AUTO_N_PRESET_WHITE_BALANCE = 9, + CIF_ISP10_CID_SCENE_MODE = 10, + CIF_ISP10_CID_SUPER_IMPOSE = 11, + CIF_ISP10_CID_JPEG_QUALITY = 12, + CIF_ISP10_CID_IMAGE_EFFECT = 13, + CIF_ISP10_CID_HFLIP = 14, + CIF_ISP10_CID_VFLIP = 15, + CIF_ISP10_CID_AUTO_FPS = 16, + CIF_ISP10_CID_VBLANKING = 17, + CIF_ISP10_CID_ISO_SENSITIVITY = 18, + +}; + +/* correspond to bit field values */ +enum cif_isp10_image_effect { + CIF_ISP10_IE_BW = 0, + CIF_ISP10_IE_NEGATIVE = 1, + CIF_ISP10_IE_SEPIA = 2, + CIF_ISP10_IE_C_SEL = 3, + CIF_ISP10_IE_EMBOSS = 4, + CIF_ISP10_IE_SKETCH = 5, + CIF_ISP10_IE_NONE /* not a bit field value */ +}; + +#define CIF_ISP10_PIX_FMT_MASK 0xf0000000 +#define CIF_ISP10_PIX_FMT_MASK_BPP 0x0003f000 +#define CIF_ISP10_PIX_FMT_YUV_MASK_CPLANES 0x00000003 +#define CIF_ISP10_PIX_FMT_YUV_MASK_UVSWAP 0x00000004 +#define CIF_ISP10_PIX_FMT_YUV_MASK_YCSWAP 0x00000008 +#define CIF_ISP10_PIX_FMT_YUV_MASK_X 0x00000f00 +#define CIF_ISP10_PIX_FMT_YUV_MASK_Y 0x000000f0 +#define CIF_ISP10_PIX_FMT_RGB_MASK_PAT 0x000000f0 +#define CIF_ISP10_PIX_FMT_BAYER_MASK_PAT 0x000000f0 +#define CIF_ISP10_PIX_FMT_GET_BPP(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_MASK_BPP) >> 12) +#define cif_isp10_pix_fmt_set_bpp(pix_fmt, bpp) \ + { \ + pix_fmt = (((pix_fmt) & ~CIF_ISP10_PIX_FMT_MASK_BPP) | \ + (((bpp) << 12) & CIF_ISP10_PIX_FMT_MASK_BPP)); \ + } + +#define CIF_ISP10_PIX_FMT_YUV_GET_NUM_CPLANES(pix_fmt) \ + ((pix_fmt) & CIF_ISP10_PIX_FMT_YUV_MASK_CPLANES) +#define CIF_ISP10_PIX_FMT_YUV_IS_YC_SWAPPED(pix_fmt) \ + ((pix_fmt) & CIF_ISP10_PIX_FMT_YUV_MASK_YCSWAP) +#define CIF_ISP10_PIX_FMT_YUV_IS_UV_SWAPPED(pix_fmt) \ + ((pix_fmt) & CIF_ISP10_PIX_FMT_YUV_MASK_UVSWAP) +#define CIF_ISP10_PIX_FMT_YUV_GET_X_SUBS(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_YUV_MASK_X) >> 8) +#define CIF_ISP10_PIX_FMT_YUV_GET_Y_SUBS(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_YUV_MASK_Y) >> 4) +#define cif_isp10_pix_fmt_set_y_subs(pix_fmt, y_subs) \ + { \ + pix_fmt = (((pix_fmt) & ~CIF_ISP10_PIX_FMT_YUV_MASK_Y) | \ + ((y_subs << 4) & CIF_ISP10_PIX_FMT_YUV_MASK_Y)); \ + } +#define cif_isp10_pix_fmt_set_x_subs(pix_fmt, x_subs) \ + { \ + pix_fmt = (((pix_fmt) & ~CIF_ISP10_PIX_FMT_YUV_MASK_X) | \ + (((x_subs) << 8) & CIF_ISP10_PIX_FMT_YUV_MASK_X)); \ + } +#define cif_isp10_pix_fmt_set_yc_swapped(pix_fmt, yc_swapped) \ + { \ + pix_fmt = (((pix_fmt) & ~CIF_ISP10_PIX_FMT_YUV_MASK_YCSWAP) | \ + (((yc_swapped) << 3) & \ + CIF_ISP10_PIX_FMT_YUV_MASK_YCSWAP)); \ + } + +#define CIF_ISP10_PIX_FMT_BAYER_PAT_IS_BGGR(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_BAYER_MASK_PAT) == 0x0) +#define CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GBRG(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_BAYER_MASK_PAT) == 0x10) +#define CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GRBG(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_BAYER_MASK_PAT) == 0x20) +#define CIF_ISP10_PIX_FMT_BAYER_PAT_IS_RGGB(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_BAYER_MASK_PAT) == 0x30) + +#define CIF_ISP10_PIX_FMT_IS_YUV(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_MASK) == 0x10000000) +#define CIF_ISP10_PIX_FMT_IS_RGB(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_MASK) == 0x20000000) +#define CIF_ISP10_PIX_FMT_IS_RAW_BAYER(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_MASK) == 0x30000000) +#define CIF_ISP10_PIX_FMT_IS_JPEG(pix_fmt) \ + (((pix_fmt) & CIF_ISP10_PIX_FMT_MASK) == 0x40000000) + +#define CIF_ISP10_PIX_FMT_IS_INTERLEAVED(pix_fmt) \ + (!CIF_ISP10_PIX_FMT_IS_YUV(pix_fmt) ||\ + !CIF_ISP10_PIX_FMT_YUV_GET_NUM_CPLANES(pix_fmt)) + +enum cif_isp10_pix_fmt { + /* YUV */ + CIF_YUV400 = 0x10008000, + CIF_YVU400 = 0x10008004, + + CIF_YUV420I = 0x1000c220, + CIF_YUV420SP = 0x1000c221, /* NV12 */ + CIF_YUV420P = 0x1000c222, + CIF_YVU420I = 0x1000c224, + CIF_YVU420SP = 0x1000c225, /* NV21 */ + CIF_YVU420P = 0x1000c226, /* YV12 */ + + CIF_YUV422I = 0x10010240, + CIF_YUV422SP = 0x10010241, + CIF_YUV422P = 0x10010242, + CIF_YVU422I = 0x10010244, + CIF_YVU422SP = 0x10010245, + CIF_YVU422P = 0x10010246, + + CIF_YUV444I = 0x10018440, + CIF_YUV444SP = 0x10018441, + CIF_YUV444P = 0x10018442, + CIF_YVU444I = 0x10018444, + CIF_YVU444SP = 0x10018445, + CIF_YVU444P = 0x10018446, + + CIF_UYV400 = 0x10008008, + + CIF_UYV420I = 0x1000c228, + CIF_UYV420SP = 0x1000c229, + CIF_UYV420P = 0x1000c22a, + CIF_VYU420I = 0x1000c22c, + CIF_VYU420SP = 0x1000c22d, + CIF_VYU420P = 0x1000c22e, + + CIF_UYV422I = 0x10010248, + CIF_UYV422SP = 0x10010249, + CIF_UYV422P = 0x1001024a, + CIF_VYU422I = 0x1001024c, + CIF_VYU422SP = 0x1001024d, + CIF_VYU422P = 0x1001024e, + + CIF_UYV444I = 0x10018448, + CIF_UYV444SP = 0x10018449, + CIF_UYV444P = 0x1001844a, + CIF_VYU444I = 0x1001844c, + CIF_VYU444SP = 0x1001844d, + CIF_VYU444P = 0x1001844e, + + /* RGB */ + CIF_RGB565 = 0x20010000, + CIF_RGB666 = 0x20012000, + CIF_RGB888 = 0x20018000, + + /* RAW Bayer */ + CIF_BAYER_SBGGR8 = 0x30008000, + CIF_BAYER_SGBRG8 = 0x30008010, + CIF_BAYER_SGRBG8 = 0x30008020, + CIF_BAYER_SRGGB8 = 0x30008030, + + CIF_BAYER_SBGGR10 = 0x3000a000, + CIF_BAYER_SGBRG10 = 0x3000a010, + CIF_BAYER_SGRBG10 = 0x3000a020, + CIF_BAYER_SRGGB10 = 0x3000a030, + + CIF_BAYER_SBGGR12 = 0x3000c000, + CIF_BAYER_SGBRG12 = 0x3000c010, + CIF_BAYER_SGRBG12 = 0x3000c020, + CIF_BAYER_SRGGB12 = 0x3000c030, + + /* JPEG */ + CIF_JPEG = 0x40008000, + + /* Data */ + CIF_DATA = 0x70000000, + + CIF_UNKNOWN_FORMAT = 0x80000000 +}; + +enum cif_isp10_stream_id { + CIF_ISP10_STREAM_SP = 0x1, + CIF_ISP10_STREAM_MP = 0x2, + CIF_ISP10_STREAM_DMA = 0x4, + CIF_ISP10_STREAM_ISP = 0x8 +}; + +#define CIF_ISP10_ALL_STREAMS \ + (CIF_ISP10_STREAM_SP | \ + CIF_ISP10_STREAM_MP | \ + CIF_ISP10_STREAM_DMA) + +enum cif_isp10_buff_fmt { + /* values correspond to bitfield values */ + CIF_ISP10_BUFF_FMT_PLANAR = 0, + CIF_ISP10_BUFF_FMT_SEMIPLANAR = 1, + CIF_ISP10_BUFF_FMT_INTERLEAVED = 2, + + CIF_ISP10_BUFF_FMT_RAW8 = 0, + CIF_ISP10_BUFF_FMT_RAW12 = 2 +}; + +enum cif_isp10_jpeg_header { + CIF_ISP10_JPEG_HEADER_JFIF, + CIF_ISP10_JPEG_HEADER_NONE +}; + +struct cif_isp10_csi_config { + u32 vc; + u32 nb_lanes; + u32 bit_rate; + /* really used csi */ + u32 used_csi; /* xuhf@rock-chips.com: v1.0.4 */ +}; + +struct cif_isp10_paraport_config { + u32 cif_vsync; + u32 cif_hsync; + u32 cif_pclk; + /* really used csi */ + u32 used_csi; /* xuhf@rock-chips.com: v1.0.4 */ +}; + +struct cif_isp10_frm_intrvl { + u32 numerator; + u32 denominator; +}; + +struct cif_isp10_frm_fmt { + u32 width; + u32 height; + u32 stride; + u32 std_id; + enum cif_isp10_pix_fmt pix_fmt; + enum cif_isp10_pix_fmt_quantization quantization; + struct v4l2_rect defrect; +}; + +struct cif_isp10_strm_fmt { + struct cif_isp10_frm_fmt frm_fmt; + struct cif_isp10_frm_intrvl frm_intrvl; +}; + +struct cif_isp10_strm_fmt_desc { + bool discrete_frmsize; + struct { + u32 width; + u32 height; + } min_frmsize; + struct { + u32 width; + u32 height; + } max_frmsize; + enum cif_isp10_pix_fmt pix_fmt; + bool discrete_intrvl; + struct cif_isp10_frm_intrvl min_intrvl; + struct cif_isp10_frm_intrvl max_intrvl; + struct v4l2_rect defrect; + u32 std_id; +}; + +struct cif_isp10_rsz_config { + struct cif_isp10_frm_fmt *input; + struct cif_isp10_frm_fmt output; + bool ycflt_adjust; + bool ism_adjust; +}; + +struct cif_isp10_dcrop_config { + unsigned int h_offs; + unsigned int v_offs; + unsigned int h_size; + unsigned int v_size; +}; + +struct cif_isp10_sp_config { + struct cif_isp10_rsz_config rsz_config; + struct cif_isp10_dcrop_config dcrop; +}; + +struct cif_isp10_mp_config { + struct cif_isp10_rsz_config rsz_config; + struct cif_isp10_dcrop_config dcrop; +}; + +struct cif_isp10_mi_path_config { + struct cif_isp10_frm_fmt *input; + struct cif_isp10_frm_fmt output; + u32 llength; + u32 curr_buff_addr; + u32 next_buff_addr; + u32 cb_offs; + u32 cr_offs; + u32 y_size; + u32 cb_size; + u32 cr_size; + bool busy; +}; + +struct cif_isp10_zoom_buffer_info { + u32 width; + u32 height; + unsigned long buff_addr; + u32 flags; +}; + +struct cif_isp10_mi_config { + bool raw_enable; + u32 async_updt; + struct cif_isp10_mi_path_config mp; + struct cif_isp10_mi_path_config sp; + struct cif_isp10_mi_path_config dma; +}; + +#ifdef NO_YET +struct cif_isp10_buffer { + struct list_head list; + u32 dma_addr; + u32 size; +}; +#else +#define cif_isp10_buffer videobuf_buffer +#endif + +struct cif_isp10_metadata_s { + unsigned int cnt; + unsigned int vmas; + unsigned char *d; +}; + +struct cif_isp10_stream { + enum cif_isp10_stream_id id; + enum cif_isp10_state state; + enum cif_isp10_state saved_state; + struct list_head buf_queue; + struct videobuf_buffer *curr_buf; + struct videobuf_buffer *next_buf; + bool updt_cfg; + bool stall; + bool stop; + CIF_ISP10_PLTFRM_EVENT done; + struct cif_isp10_metadata_s metadata; +}; + +struct cif_isp10_jpeg_config { + bool enable; + bool busy; + u32 ratio; + struct cif_isp10_frm_fmt *input; + enum cif_isp10_jpeg_header header; +}; + +struct cif_isp10_ie_config { + enum cif_isp10_image_effect effect; +}; + +/* IS */ +struct cif_isp10_ism_params { + unsigned int ctrl; + unsigned int recenter; + unsigned int h_offs; + unsigned int v_offs; + unsigned int h_size; + unsigned int v_size; + unsigned int max_dx; + unsigned int max_dy; + unsigned int displace; +}; + +struct cif_isp10_ism_config { + bool ism_en; + struct cif_isp10_ism_params ism_params; + bool ism_update_needed; +}; + +struct cif_isp10_isp_config { + bool si_enable; + struct cif_isp10_ie_config ie_config; + struct cif_isp10_ism_config ism_config; + struct cif_isp10_frm_fmt *input; + struct cif_isp10_frm_fmt output; +}; + +struct cif_isp10_config { + CIF_ISP10_PLTFRM_MEM_IO_ADDR base_addr; + enum cif_isp10_flash_mode flash_mode; + enum cif_isp10_inp input_sel; + struct cif_isp10_jpeg_config jpeg_config; + struct cif_isp10_mi_config mi_config; + struct cif_isp10_sp_config sp_config; + struct cif_isp10_mp_config mp_config; + struct cif_isp10_strm_fmt img_src_output; + struct cif_isp10_isp_config isp_config; + struct pltfrm_cam_itf cam_itf; + bool out_of_buffer_stall; +}; + +struct cif_isp10_mi_state { + unsigned long flags; + unsigned int isp_ctrl; + unsigned int y_base_ad; + unsigned int y_size; + unsigned int cb_base_ad; + unsigned int cb_size; + unsigned int cr_base_ad; + unsigned int cr_size; +}; + +struct cif_isp10_img_src_exp { + struct list_head list; + struct cif_isp10_img_src_ext_ctrl *exp; +}; + +struct cif_isp10_img_src_data { + unsigned int v_frame_id; + struct isp_supplemental_sensor_mode_data data; +}; + +struct cif_isp10_img_src_exps { + spinlock_t lock; /* protect list */ + struct list_head list; + + struct mutex mutex; /* protect frm_exp */ + struct cif_isp10_img_src_data data[2]; + unsigned char exp_valid_frms; +}; + +enum cif_isp10_isp_vs_cmd { + CIF_ISP10_VS_EXP = 0, +}; + +struct cif_isp10_isp_vs_work { + struct work_struct work; + struct cif_isp10_device *dev; + enum cif_isp10_isp_vs_cmd cmd; + void *param; +}; + +struct cif_isp10_fmt { + char *name; + u32 fourcc; + int flags; + int depth; + unsigned char rotation; + unsigned char overlay; +}; + +struct cif_isp10_device { + unsigned int dev_id; + CIF_ISP10_PLTFRM_DEVICE dev; + struct v4l2_device v4l2_dev; + enum cif_isp10_pm_state pm_state; + enum cif_isp10_img_src_state img_src_state; + + spinlock_t vbq_lock; /* spinlock for videobuf queues */ + spinlock_t vbreq_lock; /* spinlock for videobuf requeues */ + + struct cif_isp10_img_src *img_src; + struct cif_isp10_img_src *img_src_array[CIF_ISP10_NUM_INPUTS]; + unsigned int img_src_cnt; + struct cif_isp10_img_src_exps img_src_exps; + + struct cif_isp10_config config; + struct cif_isp10_isp_dev isp_dev; + struct cif_isp10_stream sp_stream; + struct cif_isp10_stream mp_stream; + struct cif_isp10_stream dma_stream; + + struct workqueue_struct *vs_wq; + void (*sof_event)(struct cif_isp10_device *dev, __u32 frame_sequence); + /* + * requeue_bufs() is used to clean and rebuild the local buffer + * lists xx_stream.buf_queue. This is used e.g. in the CAPTURE use + * case where we start MP and SP separately and needs to shortly + * stop and start SP when start MP + */ + void (*requeue_bufs)(struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id); + bool b_isp_frame_in; + bool b_mi_frame_end; + int otf_zsl_mode; + struct flash_timeinfo_s flash_t; + + struct pltfrm_soc_cfg *soc_cfg; + void *nodes; + +}; + +struct cif_isp10_fmt *get_cif_isp10_output_format(int index); +int get_cif_isp10_output_format_size(void); + +struct v4l2_fmtdesc *get_cif_isp10_output_format_desc(int index); +int get_cif_isp10_output_format_desc_size(void); + +/* Clean code starts from here */ + +struct cif_isp10_device *cif_isp10_create( + CIF_ISP10_PLTFRM_DEVICE pdev, + void (*sof_event)(struct cif_isp10_device *dev, __u32 frame_sequence), + void (*requeue_bufs)(struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id), + struct pltfrm_soc_cfg *soc_cfg); + +void cif_isp10_destroy( + struct cif_isp10_device *dev); + +int cif_isp10_init( + struct cif_isp10_device *dev, + u32 stream_ids); + +int cif_isp10_release( + struct cif_isp10_device *dev, + int stream_ids); + +int cif_isp10_streamon( + struct cif_isp10_device *dev, + u32 stream_ids); + +int cif_isp10_streamoff( + struct cif_isp10_device *dev, + u32 stream_ids); + +int cif_isp10_s_input( + struct cif_isp10_device *dev, + enum cif_isp10_inp inp); + +int cif_isp10_s_fmt( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + struct cif_isp10_strm_fmt *strm_fmt, + u32 stride); + +int cif_isp10_resume( + struct cif_isp10_device *dev); + +int cif_isp10_suspend( + struct cif_isp10_device *dev); + +int cif_isp10_qbuf( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream, + struct cif_isp10_buffer *buf); + +int cif_isp10_reqbufs( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id strm, + struct v4l2_requestbuffers *req); +int cif_isp10_mmap( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + struct vm_area_struct *vma); + +int cif_isp10_get_target_frm_size( + struct cif_isp10_device *dev, + u32 *target_width, + u32 *target_height); + +int cif_isp10_calc_isp_cropping( + struct cif_isp10_device *dev, + u32 *width, + u32 *height, + u32 *h_offs, + u32 *v_offs); + +const char *cif_isp10_g_input_name( + struct cif_isp10_device *dev, + enum cif_isp10_inp inp); + +int cif_isp10_calc_min_out_buff_size( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id, + u32 *size); + +int cif_isp10_s_ctrl( + struct cif_isp10_device *dev, + const enum cif_isp10_cid id, + int val); + +void cif_isp10_dbgfs_fill_sensor_aec_para( + struct cif_isp10_device *cif_isp10_dev, + s32 exp_time, + u16 gain); + +int cif_isp10_s_isp_metadata( + struct cif_isp10_device *dev, + struct cif_isp10_isp_readout_work *readout_work, + struct cifisp_isp_other_cfg *new_other, + struct cifisp_isp_meas_cfg *new_meas, + struct cifisp_stat_buffer *new_stats); + +int cif_isp10_s_exp( + struct cif_isp10_device *dev, + struct cif_isp10_img_src_ext_ctrl *exp_ctrl); + +void cif_isp10_sensor_mode_data_sync( + struct cif_isp10_device *dev, + unsigned int frame_id, + struct isp_supplemental_sensor_mode_data *data); +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_img_src.c b/drivers/media/platform/rk-isp10/cif_isp10_img_src.c new file mode 100644 index 000000000000..7d8a18c30578 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_img_src.c @@ -0,0 +1,175 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#include +#include +#include "cif_isp10.h" +#include "cif_isp10_img_src_ops.h" + +struct cif_isp10_img_src { + void *img_src; + const struct cif_isp10_img_src_ops *ops; +}; + +struct cif_isp10_img_src *cif_isp10_img_src_to_img_src( + CIF_ISP10_PLTFRM_DEVICE dev, + struct pltfrm_soc_cfg *soc_cfg) +{ + int ret = 0; + int i; + const char *device_type; + struct cif_isp10_img_src *img_src; + + img_src = devm_kzalloc(dev, sizeof(*img_src), GFP_KERNEL); + if (!img_src) { + ret = -ENOMEM; + goto err; + } + + device_type = cif_isp10_pltfrm_get_device_type(dev); + + img_src->ops = NULL; + for (i = 0; i < ARRAY_SIZE(cif_isp10_img_src_ops); i++) { + if (!strcmp(device_type, cif_isp10_img_src_ops->device_type)) { + img_src->ops = &cif_isp10_img_src_ops[i].ops; + break; + } + } + if (!img_src->ops) { + cif_isp10_pltfrm_pr_err(NULL, + "unsupported device type %s\n", + device_type); + ret = -EINVAL; + goto err; + } + + WARN_ON(!img_src->ops->to_img_src); + WARN_ON(!img_src->ops->s_streaming); + WARN_ON(!img_src->ops->s_power); + WARN_ON(!img_src->ops->enum_strm_fmts); + WARN_ON(!img_src->ops->s_strm_fmt); + WARN_ON(!img_src->ops->g_ctrl); + WARN_ON(!img_src->ops->s_ctrl); + + img_src->img_src = img_src->ops->to_img_src(dev, soc_cfg); + if (IS_ERR_OR_NULL(img_src->img_src)) { + cif_isp10_pltfrm_pr_err(NULL, + "to_img_src failed!\n"); + ret = -EFAULT; + goto err; + } + + return img_src; +err: + cif_isp10_pltfrm_pr_err(NULL, "failed with error %d\n", + ret); + if (!IS_ERR_OR_NULL(img_src)) + devm_kfree(dev, img_src); + + return ERR_PTR(ret); +} + +int cif_isp10_img_src_s_streaming( + struct cif_isp10_img_src *img_src, + bool enable) +{ + return img_src->ops->s_streaming(img_src->img_src, enable); +} + +int cif_isp10_img_src_s_power( + struct cif_isp10_img_src *img_src, + bool on) +{ + return img_src->ops->s_power(img_src->img_src, on); +} + +int cif_isp10_img_src_enum_strm_fmts( + struct cif_isp10_img_src *img_src, + u32 index, + struct cif_isp10_strm_fmt_desc *strm_fmt_desc) +{ + return img_src->ops->enum_strm_fmts(img_src->img_src, + index, strm_fmt_desc); +} + +int cif_isp10_img_src_s_strm_fmt( + struct cif_isp10_img_src *img_src, + struct cif_isp10_strm_fmt *strm_fmt) +{ + if (!img_src) { + cif_isp10_pltfrm_pr_err(NULL, "img_src is NULL\n"); + return -EINVAL; + } + return img_src->ops->s_strm_fmt(img_src->img_src, strm_fmt); +} + +int cif_isp10_img_src_g_ctrl( + struct cif_isp10_img_src *img_src, + int id, + int *val) +{ + if (!img_src) { + cif_isp10_pltfrm_pr_err(NULL, "img_src is NULL\n"); + return -EINVAL; + } + return img_src->ops->g_ctrl(img_src->img_src, id, val); +} + +int cif_isp10_img_src_s_ctrl( + struct cif_isp10_img_src *img_src, + int id, + int val) +{ + if (!img_src) { + cif_isp10_pltfrm_pr_err(NULL, "img_src is NULL\n"); + return -EINVAL; + } + return img_src->ops->s_ctrl(img_src->img_src, id, val); +} + +int cif_isp10_img_src_s_ext_ctrls( + struct cif_isp10_img_src *img_src, + struct cif_isp10_img_src_ext_ctrl *ctrl) +{ + if (!img_src) { + cif_isp10_pltfrm_pr_err(NULL, "img_src is NULL\n"); + return -EINVAL; + } + return img_src->ops->s_ext_ctrls(img_src->img_src, ctrl); +} + +long cif_isp10_img_src_ioctl( + struct cif_isp10_img_src *img_src, + unsigned int cmd, + void *arg) +{ + if (!img_src) { + cif_isp10_pltfrm_pr_err(NULL, "img_src is NULL\n"); + return -EINVAL; + } + return img_src->ops->ioctl(img_src->img_src, cmd, arg); +} + +const char *cif_isp10_img_src_g_name( + struct cif_isp10_img_src *img_src) +{ + if (!img_src) { + cif_isp10_pltfrm_pr_err(NULL, "img_src is NULL\n"); + return ERR_PTR(-EINVAL); + } + return img_src->ops->g_name(img_src->img_src); +} + diff --git a/drivers/media/platform/rk-isp10/cif_isp10_img_src.h b/drivers/media/platform/rk-isp10/cif_isp10_img_src.h new file mode 100644 index 000000000000..0ef90b036954 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_img_src.h @@ -0,0 +1,83 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _CIF_ISP10_IMG_SRC_H +#define _CIF_ISP10_IMG_SRC_H + +struct cif_isp10_img_src; +struct cif_isp10_strm_fmt_desc; +struct cif_isp10_strm_fmt; +struct cif_isp10_csi_config; +enum cif_isp10_pix_fmt; + +struct cif_isp10_img_src; +struct pltfrm_soc_cfg; + +struct cif_isp10_img_src_ctrl { + unsigned int id; + int val; +}; + +struct cif_isp10_img_src_ext_ctrl { + int cnt; + unsigned int class; + struct cif_isp10_img_src_ctrl *ctrls; +}; + +struct cif_isp10_img_src *cif_isp10_img_src_to_img_src( + CIF_ISP10_PLTFRM_DEVICE dev, + struct pltfrm_soc_cfg *soc_cfg); + +int cif_isp10_img_src_s_streaming( + struct cif_isp10_img_src *img_src, + bool enable); + +int cif_isp10_img_src_s_power( + struct cif_isp10_img_src *img_src, + bool on); + +int cif_isp10_img_src_enum_strm_fmts( + struct cif_isp10_img_src *img_src, + u32 index, + struct cif_isp10_strm_fmt_desc *strm_fmt_desc); + +int cif_isp10_img_src_s_strm_fmt( + struct cif_isp10_img_src *img_src, + struct cif_isp10_strm_fmt *strm_fmt); + +int cif_isp10_img_src_g_ctrl( + struct cif_isp10_img_src *img_src, + int id, + int *val); + +int cif_isp10_img_src_s_ctrl( + struct cif_isp10_img_src *img_src, + int id, + int val); + +const char *cif_isp10_img_src_g_name( + struct cif_isp10_img_src *img_src); + +int cif_isp10_img_src_s_ext_ctrls( + struct cif_isp10_img_src *img_src, + struct cif_isp10_img_src_ext_ctrl *ctrls); + +long cif_isp10_img_src_ioctl( + struct cif_isp10_img_src *img_src, + unsigned int cmd, + void *arg); + +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_img_src_ops.h b/drivers/media/platform/rk-isp10/cif_isp10_img_src_ops.h new file mode 100644 index 000000000000..130af3b6eb1c --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_img_src_ops.h @@ -0,0 +1,89 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _CIF_ISP10_IMG_SRC_OPS_H +#define _CIF_ISP10_IMG_SRC_OPS_H +#include +#include "cif_isp10_img_src_v4l2-subdev.h" + +struct cif_isp10_img_src_ops { + void * (*to_img_src)( + CIF_ISP10_PLTFRM_DEVICE dev, + struct pltfrm_soc_cfg *soc_cfg); + int (*s_streaming)( + void *img_src, + bool enable); + int (*s_power)( + void *img_src, + bool on); + int (*enum_strm_fmts)( + void *img_src, + u32 index, + struct cif_isp10_strm_fmt_desc *strm_fmt_desc); + int (*s_strm_fmt)( + void *img_src, + struct cif_isp10_strm_fmt *strm_fmt); + int (*g_ctrl)( + void *img_src, + int id, + int *val); + const char * (*g_name)( + void *img_src); + int (*s_ctrl)( + void *img_src, + int id, + int val); + int (*s_ext_ctrls)( + void *img_src, + struct cif_isp10_img_src_ext_ctrl *ctrl); + long (*ioctl)( + void *img_src, + unsigned int cmd, + void *arg); +}; + +const struct { + const char *device_type; + struct cif_isp10_img_src_ops ops; +} cif_isp10_img_src_ops[] = { + { + .device_type = CIF_ISP10_IMG_SRC_V4L2_I2C_SUBDEV, + .ops = { + .to_img_src = + cif_isp10_img_src_v4l2_i2c_subdev_to_img_src, + .s_streaming = + cif_isp10_img_src_v4l2_subdev_s_streaming, + .s_power = + cif_isp10_img_src_v4l2_subdev_s_power, + .enum_strm_fmts = + cif_isp10_img_src_v4l2_subdev_enum_strm_fmts, + .s_strm_fmt = + cif_isp10_img_src_v4l2_subdev_s_strm_fmt, + .g_ctrl = + cif_isp10_img_src_v4l2_subdev_g_ctrl, + .g_name = + cif_isp10_img_src_v4l2_subdev_g_name, + .s_ctrl = + cif_isp10_img_src_v4l2_subdev_s_ctrl, + .s_ext_ctrls = + cif_isp10_img_src_v4l2_subdev_s_ext_ctrls, + .ioctl = + cif_isp10_img_src_v4l2_subdev_ioctl + } + }, +}; + +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.c b/drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.c new file mode 100644 index 000000000000..7b9b45e4b359 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.c @@ -0,0 +1,470 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#include +#include +#include +#include +#include +#include "cif_isp10.h" +#include +#include +#include +/* ===================== */ +/* Image Source */ +/* ===================== */ +void *cif_isp10_img_src_v4l2_i2c_subdev_to_img_src( + struct device *dev, + struct pltfrm_soc_cfg *soc_cfg) +{ + int ret = 0; + struct i2c_client *client; + struct v4l2_subdev *subdev; + + client = i2c_verify_client(dev); + if (IS_ERR_OR_NULL(client)) { + cif_isp10_pltfrm_pr_err(dev, + "not an I2C device\n"); + ret = -EINVAL; + goto err; + } + + subdev = i2c_get_clientdata(client); + if (IS_ERR_OR_NULL(subdev)) + return subdev; + + ret = v4l2_subdev_call(subdev, + core, + ioctl, + PLTFRM_CIFCAM_ATTACH, + (void *)soc_cfg); + if (ret != 0) + goto err; + + return (void *)subdev; +err: + cif_isp10_pltfrm_pr_err(NULL, "failed with error %d\n", ret); + return ERR_PTR(ret); +} + +static enum cif_isp10_pix_fmt img_src_v4l2_subdev_pix_fmt2cif_isp10_pix_fmt( + int img_src_pix_fmt) +{ + switch (img_src_pix_fmt) { + case MEDIA_BUS_FMT_YUYV8_1_5X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV10_2X10: + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YUYV10_1X20: + return CIF_YUV422I; + case MEDIA_BUS_FMT_UYVY8_1_5X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: + return CIF_UYV422I; + case MEDIA_BUS_FMT_RGB565_2X8_BE: + case MEDIA_BUS_FMT_RGB565_2X8_LE: + return CIF_RGB565; + case MEDIA_BUS_FMT_RGB666_1X18: + return CIF_RGB666; + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB888_2X12_BE: + case MEDIA_BUS_FMT_RGB888_2X12_LE: + return CIF_RGB888; + case MEDIA_BUS_FMT_SBGGR8_1X8: + return CIF_BAYER_SBGGR8; + case MEDIA_BUS_FMT_SGBRG8_1X8: + return CIF_BAYER_SGBRG8; + case MEDIA_BUS_FMT_SGRBG8_1X8: + return CIF_BAYER_SGRBG8; + case MEDIA_BUS_FMT_SRGGB8_1X8: + return CIF_BAYER_SRGGB8; + case MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8: + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE: + case MEDIA_BUS_FMT_SBGGR10_1X10: + return CIF_BAYER_SBGGR10; + case MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8: + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGBRG10_1X10: + return CIF_BAYER_SGBRG10; + case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: + case MEDIA_BUS_FMT_SGRBG10_1X10: + return CIF_BAYER_SGRBG10; + case MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8: + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return CIF_BAYER_SRGGB10; + case MEDIA_BUS_FMT_SBGGR12_1X12: + return CIF_BAYER_SBGGR12; + case MEDIA_BUS_FMT_SGBRG12_1X12: + return CIF_BAYER_SGBRG12; + case MEDIA_BUS_FMT_SGRBG12_1X12: + return CIF_BAYER_SGRBG12; + case MEDIA_BUS_FMT_SRGGB12_1X12: + return CIF_BAYER_SRGGB12; + case MEDIA_BUS_FMT_JPEG_1X8: + return CIF_JPEG; + default: + return CIF_UNKNOWN_FORMAT; + } +} + +static int cif_isp10_pix_fmt2img_src_v4l2_subdev_pix_fmt( + enum cif_isp10_pix_fmt cif_isp10_pix_fmt) +{ + switch (cif_isp10_pix_fmt) { + case CIF_YUV422I: + return MEDIA_BUS_FMT_YUYV8_2X8; + case CIF_UYV422I: + return MEDIA_BUS_FMT_UYVY8_2X8; + case CIF_RGB565: + return MEDIA_BUS_FMT_RGB565_2X8_LE; + case CIF_RGB666: + return MEDIA_BUS_FMT_RGB666_1X18; + case CIF_RGB888: + return MEDIA_BUS_FMT_RGB888_1X24; + case CIF_BAYER_SBGGR8: + return MEDIA_BUS_FMT_SBGGR8_1X8; + case CIF_BAYER_SGBRG8: + return MEDIA_BUS_FMT_SGBRG8_1X8; + case CIF_BAYER_SGRBG8: + return MEDIA_BUS_FMT_SGRBG8_1X8; + case CIF_BAYER_SRGGB8: + return MEDIA_BUS_FMT_SRGGB8_1X8; + case CIF_BAYER_SBGGR10: + return MEDIA_BUS_FMT_SBGGR10_1X10; + case CIF_BAYER_SGBRG10: + return MEDIA_BUS_FMT_SGBRG10_1X10; + case CIF_BAYER_SGRBG10: + return MEDIA_BUS_FMT_SGRBG10_1X10; + case CIF_BAYER_SRGGB10: + return MEDIA_BUS_FMT_SRGGB10_1X10; + case CIF_BAYER_SBGGR12: + return MEDIA_BUS_FMT_SBGGR12_1X12; + case CIF_BAYER_SGBRG12: + return MEDIA_BUS_FMT_SGBRG12_1X12; + case CIF_BAYER_SGRBG12: + return MEDIA_BUS_FMT_SGRBG12_1X12; + case CIF_BAYER_SRGGB12: + return MEDIA_BUS_FMT_SRGGB12_1X12; + case CIF_JPEG: + return MEDIA_BUS_FMT_JPEG_1X8; + default: + return -EINVAL; + } +} + +static int cif_isp10_v4l2_cid2v4l2_cid(u32 cif_isp10_cid) +{ + switch (cif_isp10_cid) { + case CIF_ISP10_CID_FLASH_MODE: + return V4L2_CID_FLASH_LED_MODE; + case CIF_ISP10_CID_AUTO_GAIN: + return V4L2_CID_AUTOGAIN; + case CIF_ISP10_CID_AUTO_EXPOSURE: + return V4L2_EXPOSURE_AUTO; + case CIF_ISP10_CID_AUTO_WHITE_BALANCE: + return V4L2_CID_AUTO_WHITE_BALANCE; + case CIF_ISP10_CID_BLACK_LEVEL: + return V4L2_CID_BLACK_LEVEL; + case CIF_ISP10_CID_WB_TEMPERATURE: + return V4L2_CID_WHITE_BALANCE_TEMPERATURE; + case CIF_ISP10_CID_EXPOSURE_TIME: + return V4L2_CID_EXPOSURE; + case CIF_ISP10_CID_ANALOG_GAIN: + return V4L2_CID_GAIN; + case CIF_ISP10_CID_FOCUS_ABSOLUTE: + return V4L2_CID_FOCUS_ABSOLUTE; + case CIF_ISP10_CID_AUTO_N_PRESET_WHITE_BALANCE: + return V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE; + case CIF_ISP10_CID_SCENE_MODE: + return V4L2_CID_SCENE_MODE; + case CIF_ISP10_CID_ISO_SENSITIVITY: + return V4L2_CID_ISO_SENSITIVITY; + case CIF_ISP10_CID_AUTO_FPS: + return RK_V4L2_CID_AUTO_FPS; + case CIF_ISP10_CID_VBLANKING: + return RK_V4L2_CID_VBLANKING; + case CIF_ISP10_CID_HFLIP: + return V4L2_CID_HFLIP; + case CIF_ISP10_CID_VFLIP: + return V4L2_CID_VFLIP; + default: + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported CIF ISP20 ID %d\n", + cif_isp10_cid); + break; + } + return -EINVAL; +} + +int cif_isp10_img_src_v4l2_subdev_s_streaming( + void *img_src, + bool enable) +{ + struct v4l2_subdev *subdev = img_src; + + if (enable) + return v4l2_subdev_call(subdev, video, s_stream, 1); + else + return v4l2_subdev_call(subdev, video, s_stream, 0); +} + +int cif_isp10_img_src_v4l2_subdev_s_power( + void *img_src, + bool on) +{ + struct v4l2_subdev *subdev = img_src; + + if (on) + return v4l2_subdev_call(subdev, core, s_power, 1); + else + return v4l2_subdev_call(subdev, core, s_power, 0); +} + +int cif_isp10_img_src_v4l2_subdev_enum_strm_fmts( + void *img_src, + u32 index, + struct cif_isp10_strm_fmt_desc *strm_fmt_desc) +{ + int ret; + struct v4l2_subdev *subdev = img_src; + struct v4l2_subdev_frame_interval_enum fie = {.index = index}; + struct pltfrm_cam_defrect defrect; + v4l2_std_id std; + + ret = v4l2_subdev_call(subdev, video, querystd, &std); + if (!IS_ERR_VALUE(ret)) + strm_fmt_desc->std_id = std; + else + strm_fmt_desc->std_id = 0; + + ret = v4l2_subdev_call(subdev, pad, + enum_frame_interval, NULL, &fie); + if (!IS_ERR_VALUE(ret)) { + strm_fmt_desc->discrete_intrvl = true; + strm_fmt_desc->min_intrvl.numerator = + fie.interval.numerator; + strm_fmt_desc->min_intrvl.denominator = + fie.interval.denominator; + strm_fmt_desc->discrete_frmsize = true; + strm_fmt_desc->min_frmsize.width = fie.width; + strm_fmt_desc->min_frmsize.height = fie.height; + strm_fmt_desc->pix_fmt = + img_src_v4l2_subdev_pix_fmt2cif_isp10_pix_fmt( + fie.code); + + defrect.width = fie.width; + defrect.height = fie.height; + memset(&defrect, 0x00, sizeof(struct v4l2_rect)); + v4l2_subdev_call(subdev, + core, + ioctl, + PLTFRM_CIFCAM_G_DEFRECT, + (void *)&defrect); + if ((defrect.defrect.width == 0) || + (defrect.defrect.height == 0)) { + strm_fmt_desc->defrect.left = 0; + strm_fmt_desc->defrect.top = 0; + strm_fmt_desc->defrect.width = fie.width; + strm_fmt_desc->defrect.height = fie.height; + } else { + strm_fmt_desc->defrect = defrect.defrect; + } + } + + return ret; +} + +int cif_isp10_img_src_v4l2_subdev_s_strm_fmt( + void *img_src, + struct cif_isp10_strm_fmt *strm_fmt) +{ + int ret = 0; + struct v4l2_subdev *subdev = img_src; + struct v4l2_subdev_format format; + struct v4l2_subdev_frame_interval intrvl; + + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; + format.format.code = cif_isp10_pix_fmt2img_src_v4l2_subdev_pix_fmt( + strm_fmt->frm_fmt.pix_fmt); + format.format.width = strm_fmt->frm_fmt.width; + format.format.height = strm_fmt->frm_fmt.height; + ret = v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format); + if (IS_ERR_VALUE(ret)) + goto err; + intrvl.interval.numerator = strm_fmt->frm_intrvl.numerator; + intrvl.interval.denominator = strm_fmt->frm_intrvl.denominator; + ret = v4l2_subdev_call(subdev, video, s_frame_interval, &intrvl); + if (IS_ERR_VALUE(ret)) + goto err; + return 0; +err: + pr_err("img_src.%s ERR: failed with error %d\n", __func__, ret); + return ret; +} + +int cif_isp10_img_src_v4l2_subdev_g_ctrl( + void *img_src, + int id, + int *val) +{ + struct v4l2_control ctrl; + int ret; + struct v4l2_subdev *subdev = img_src; + + ctrl.id = cif_isp10_v4l2_cid2v4l2_cid(id); + + if (IS_ERR_VALUE(ctrl.id)) + return (int)ctrl.id; + + ret = v4l2_subdev_call(subdev, core, g_ctrl, &ctrl); + if (!IS_ERR_VALUE(ret)) { + if (id == CIF_ISP10_CID_FLASH_MODE) { + if (ctrl.value == V4L2_FLASH_LED_MODE_NONE) { + ctrl.value = CIF_ISP10_FLASH_MODE_OFF; + } else if (ctrl.value == V4L2_FLASH_LED_MODE_FLASH) { + ctrl.value = CIF_ISP10_FLASH_MODE_FLASH; + } else if (ctrl.value == V4L2_FLASH_LED_MODE_TORCH) { + ctrl.value = CIF_ISP10_FLASH_MODE_TORCH; + } else { + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported value %d for control ID 0x%x\n", + ctrl.value, id); + return -EINVAL; + } + } + *val = ctrl.value; + } + return ret; +} + +int cif_isp10_img_src_v4l2_subdev_s_ctrl( + void *img_src, + int id, + int val) +{ + struct v4l2_control ctrl; + struct v4l2_subdev *subdev = img_src; + + ctrl.value = val; + ctrl.id = cif_isp10_v4l2_cid2v4l2_cid(id); + + if (IS_ERR_VALUE(ctrl.id)) { + return (int)ctrl.id; + } else if (id == CIF_ISP10_CID_FLASH_MODE) { + if (val == CIF_ISP10_FLASH_MODE_OFF) { + ctrl.value = V4L2_FLASH_LED_MODE_NONE; + } else if (val == CIF_ISP10_FLASH_MODE_FLASH) { + ctrl.value = V4L2_FLASH_LED_MODE_FLASH; + } else if (val == CIF_ISP10_FLASH_MODE_TORCH) { + ctrl.value = V4L2_FLASH_LED_MODE_TORCH; + } else { + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported value %d for control ID %d\n", + val, id); + return -EINVAL; + } + } + return v4l2_subdev_call(subdev, core, s_ctrl, &ctrl); +} + +const char *cif_isp10_img_src_v4l2_subdev_g_name( + void *img_src) +{ + struct v4l2_subdev *subdev = img_src; + + return dev_driver_string(subdev->dev); +} + +int cif_isp10_img_src_v4l2_subdev_s_ext_ctrls( + void *img_src, + struct cif_isp10_img_src_ext_ctrl *ctrl) +{ + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control *controls; + int i; + int ret; + struct v4l2_subdev *subdev = img_src; + + if (ctrl->cnt == 0) + return -EINVAL; + + controls = kmalloc_array(ctrl->cnt, sizeof(struct v4l2_ext_control), + GFP_KERNEL); + + if (!controls) + return -ENOMEM; + + for (i = 0; i < ctrl->cnt; i++) { + controls[i].id = ctrl->ctrls[i].id; + controls[i].value = ctrl->ctrls[i].val; + } + + ctrls.count = ctrl->cnt; + ctrls.controls = controls; + /* + * current kernel version don't define + * this member for struct v4l2_ext_control. + */ + /* ctrls.ctrl_class = ctrl->class; */ + ctrls.reserved[0] = 0; + ctrls.reserved[1] = 0; + + ret = v4l2_subdev_call(subdev, + core, s_ext_ctrls, &ctrls); + + kfree(controls); + + return ret; +} + +long cif_isp10_img_src_v4l2_subdev_ioctl( + void *img_src, + unsigned int cmd, + void *arg) +{ + struct v4l2_subdev *subdev = img_src; + long ret = -EINVAL; + + switch (cmd) { + case RK_VIDIOC_SENSOR_MODE_DATA: + case RK_VIDIOC_CAMERA_MODULEINFO: + + case PLTFRM_CIFCAM_G_ITF_CFG: + case PLTFRM_CIFCAM_G_DEFRECT: + case PLTFRM_CIFCAM_ATTACH: + ret = v4l2_subdev_call(subdev, + core, + ioctl, + cmd, + arg); + + break; + default: + break; + } + + if (IS_ERR_VALUE(ret)) + pr_err("img_src.%s subdev call(cmd: 0x%x) failed with error %ld\n", + __func__, cmd, ret); + + return ret; +} diff --git a/drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.h b/drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.h new file mode 100644 index 000000000000..a5ba17e4b7c8 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_img_src_v4l2-subdev.h @@ -0,0 +1,65 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _CIF_ISP10_IMG_SRC_V4L2_SUBDEV_H +#define _CIF_ISP10_IMG_SRC_V4L2_SUBDEV_H + +#define CIF_ISP10_IMG_SRC_V4L2_I2C_SUBDEV "v4l2-i2c-subdev" + +void *cif_isp10_img_src_v4l2_i2c_subdev_to_img_src( + struct device *dev, + struct pltfrm_soc_cfg *soc_cfg); + +int cif_isp10_img_src_v4l2_subdev_s_streaming( + void *img_src, + bool enable); + +int cif_isp10_img_src_v4l2_subdev_s_power( + void *img_src, + bool on); + +int cif_isp10_img_src_v4l2_subdev_enum_strm_fmts( + void *img_src, + u32 index, + struct cif_isp10_strm_fmt_desc *strm_fmt_desc); + +int cif_isp10_img_src_v4l2_subdev_s_strm_fmt( + void *img_src, + struct cif_isp10_strm_fmt *strm_fmt); + +int cif_isp10_img_src_v4l2_subdev_g_ctrl( + void *img_src, + int id, + int *val); + +int cif_isp10_img_src_v4l2_subdev_s_ctrl( + void *img_src, + int id, + int val); + +const char *cif_isp10_img_src_v4l2_subdev_g_name( + void *img_src); + +int cif_isp10_img_src_v4l2_subdev_s_ext_ctrls( + void *img_src, + struct cif_isp10_img_src_ext_ctrl *ctrl); + +long cif_isp10_img_src_v4l2_subdev_ioctl( + void *img_src, + unsigned int cmd, + void *arg); + +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_isp.c b/drivers/media/platform/rk-isp10/cif_isp10_isp.c new file mode 100644 index 000000000000..a01f591ae5b0 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_isp.c @@ -0,0 +1,5190 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* for ISP statistics */ +#include +#include +#include +#include +#include "cif_isp10_regs.h" +#include "cif_isp10_isp.h" +#include "cif_isp10_pltfrm.h" +#include "cif_isp10.h" + +#define _GET_ 0 +#define _SET_ 1 +#define CIFISP_MODULE_EN(v, m) ((v) |= (m)) +#define CIFISP_MODULE_DIS(v, m) ((v) &= ~(m)) +#define CIFISP_MODULE_IS_EN(v, m) (((v) & (m)) == (m)) +#define CIFISP_MODULE_UPDATE(v, m) ((v) |= (m)) +#define CIFISP_MODULE_CLR_UPDATE(v, m) ((v) &= ~(m)) +#define CIFISP_MODULE_IS_UPDATE(v, m) (((v) & (m)) == (m)) + +/* Demosaic */ +#define CIFISP_BDM_BYPASS_EN(val) ((val) << 10) +/* HIST */ +#define CIFISP_HIST_PREDIV_SET(val) ((val) << 3) +#define CIFISP_HIST_WEIGHT_SET(v0, v1, v2, v3) ((v0) | ((v1) << 8) |\ + ((v2) << 16) | ((v3) << 24)) +#define CIFISP_HIST_WINDOW_OFFSET_RESERVED (0xFFFFF000) +#define CIFISP_HIST_WINDOW_SIZE_RESERVED (0xFFFFF800) +#define CIFISP_HIST_WEIGHT_RESERVED (0xE0E0E0E0) +#define CIFISP_MAX_HIST_PREDIVIDER (0x0000007F) +#define CIFISP_HIST_ROW_NUM (5) +#define CIFISP_HIST_COLUMN_NUM (5) +/* ISP Ctrl */ +#define CIF_ISP_CTRL_ISP_GAMMA_IN_ENA BIT(6) +#define CIF_ISP_CTRL_ISP_AWB_ENA BIT(7) +#define CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA BIT(11) +/* AWB */ +#define CIFISP_AWB_GAIN_R_SET(val) ((val) << 16) +#define CIFISP_AWB_GAIN_R_READ(val) ((val) >> 16) +#define CIFISP_AWB_GAIN_B_READ(val) ((val) & 0xFFFF) + +#define CIFISP_AWB_YMAX_CMP_EN BIT(2) +#define CIFISP_AWB_REF_CR_SET(val) ((val) << 8) +#define CIFISP_AWB_REF_CR_READ(val) ((val) >> 8) +#define CIFISP_AWB_REF_CB_READ(val) ((val) & 0xFF) +#define CIFISP_AWB_MAX_CS_SET(val) ((val) << 8) +#define CIFISP_AWB_MAX_CS_READ(val) (((val) >> 8) & 0xFF) +#define CIFISP_AWB_MIN_C_READ(val) ((val) & 0xFF) +#define CIFISP_AWB_MIN_Y_SET(val) ((val) << 16) +#define CIFISP_AWB_MIN_Y_READ(val) (((val) >> 16) & 0xFF) +#define CIFISP_AWB_MAX_Y_SET(val) ((val) << 24) +#define CIFISP_AWB_MAX_Y_READ(val) ((val) >> 24) +#define CIFISP_AWB_MODE_RGB_EN ((1 << 31) | (0x02 << 0)) +#define CIFISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x02 << 0)) +#define CIFISP_AWB_MODE_READ(val) ((val) & 3) +#define CIFISP_AWB_YMAX_READ(val) (((val) >> 2) & 1) + +#define CIFISP_AWB_GET_MEAN_CR(val) ((val) & 0xFF) +#define CIFISP_AWB_GET_MEAN_CB(val) (((val) >> 8) & 0xFF) +#define CIFISP_AWB_GET_MEAN_Y(val) (((val) >> 16) & 0xFF) +#define CIFISP_AWB_GET_MEAN_R(val) ((val) & 0xFF) +#define CIFISP_AWB_GET_MEAN_B(val) (((val) >> 8) & 0xFF) +#define CIFISP_AWB_GET_MEAN_G(val) (((val) >> 16) & 0xFF) +#define CIFISP_AWB_GET_PIXEL_CNT(val) ((val) & 0x3FFFFFF) + +#define CIFISP_AWB_GAINS_MAX_VAL (0x000003FF) +#define CIFISP_AWB_WINDOW_OFFSET_MAX (0x00000FFF) +#define CIFISP_AWB_WINDOW_MAX_SIZE (0x00001FFF) +#define CIFISP_AWB_CBCR_MAX_REF (0x000000FF) +#define CIFISP_AWB_THRES_MAX_YC (0x000000FF) +/* AE */ +#define CIFISP_EXP_ENA (1) +#define CIFISP_EXP_DIS (0) +#define CIFISP_EXP_ROW_NUM (5) +#define CIFISP_EXP_COLUMN_NUM (5) +#define CIFISP_EXP_NUM_LUMA_REGS (CIFISP_EXP_ROW_NUM *\ + CIFISP_EXP_COLUMN_NUM) +#define CIFISP_EXP_MAX_HOFFS (2424) +#define CIFISP_EXP_MAX_VOFFS (1806) +#define CIFISP_EXP_BLOCK_MAX_HSIZE (516) +#define CIFISP_EXP_BLOCK_MIN_HSIZE (35) +#define CIFISP_EXP_BLOCK_MAX_VSIZE (390) +#define CIFISP_EXP_BLOCK_MIN_VSIZE (28) +#define CIFISP_EXP_MAX_HSIZE \ + (CIFISP_EXP_BLOCK_MAX_HSIZE * CIFISP_EXP_COLUMN_NUM + 1) +#define CIFISP_EXP_MIN_HSIZE \ + (CIFISP_EXP_BLOCK_MIN_HSIZE * CIFISP_EXP_COLUMN_NUM + 1) +#define CIFISP_EXP_MAX_VSIZE \ + (CIFISP_EXP_BLOCK_MAX_VSIZE * CIFISP_EXP_ROW_NUM + 1) +#define CIFISP_EXP_MIN_VSIZE \ + (CIFISP_EXP_BLOCK_MIN_VSIZE * CIFISP_EXP_ROW_NUM + 1) +#define CIFISP_EXP_HEIGHT_MASK (0x000007FF) +#define CIFISP_EXP_MAX_HOFFSET (0x00000FFF) +#define CIFISP_EXP_MAX_VOFFSET (0x00000FFF) + +#define CIFISP_EXP_CTRL_AUTOSTOP(val) ((val) << 1) +#define CIFISP_EXP_CTRL_MEASMODE(val) ((val) << 31) +#define CIFISP_EXP_HSIZE(val) ((val) & 0x7FF) +#define CIFISP_EXP_VSIZE(val) ((val) & 0x7FE) +/* LSC */ +#define CIFISP_LSC_GRADH_SET(val) ((val) << 11) +#define CIFISP_LSC_SECTH_SET(val) ((val) << 10) + +/* FLT */ +#define CIFISP_FLT_MODE_MAX (1) +#define CIFISP_FLT_CHROMA_MODE_MAX (3) +#define CIFISP_FLT_GREEN_STAGE1_MAX (8) +#define CIFISP_FLT_MODE(v) ((v) << 1) +#define CIFISP_FLT_CHROMA_V_MODE(v) ((v) << 4) +#define CIFISP_FLT_CHROMA_H_MODE(v) ((v) << 6) +#define CIFISP_FLT_GREEN_STAGE1(v) ((v) << 8) +#define CIFISP_FLT_THREAD_RESERVED (0xfffffc00) +#define CIFISP_FLT_FAC_RESERVED (0xffffffc0) +#define CIFISP_FLT_LUM_WEIGHT_RESERVED (0xfff80000) +#define CIFISP_FLT_ENA (1) +#define CIFISP_FLT_DIS (0) + +#define CIFISP_CTK_COEFF_RESERVED 0xFFFFF800 +#define CIFISP_XTALK_OFFSET_RESERVED 0xFFFFF000 + +/* GOC */ +#define CIFISP_GOC_MODE_MAX (1) +#define CIFISP_GOC_RESERVED 0xFFFFF800 +#define CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(value) (((value) >> 11) & 1) +/* DPCC */ +#define CIFISP_DPCC_ENA BIT(0) +#define CIFISP_DPCC_DIS (0 << 0) +#define CIFISP_DPCC_MODE_MAX (0x07) +#define CIFISP_DPCC_OUTPUTMODE_MAX (0x0f) +#define CIFISP_DPCC_SETUSE_MAX (0x0f) +#define CIFISP_DPCC_METHODS_SET_RESERVED (0xFFFFE000) +#define CIFISP_DPCC_LINE_THRESH_RESERVED (0xFFFF0000) +#define CIFISP_DPCC_LINE_MAD_FAC_RESERVED (0xFFFFC0C0) +#define CIFISP_DPCC_PG_FAC_RESERVED (0xFFFFC0C0) +#define CIFISP_DPCC_RND_THRESH_RESERVED (0xFFFF0000) +#define CIFISP_DPCC_RG_FAC_RESERVED (0xFFFFC0C0) +#define CIFISP_DPCC_RO_LIMIT_RESERVED (0xFFFFF000) +#define CIFISP_DPCC_RND_OFFS_RESERVED (0xFFFFF000) +/* BLS */ +#define CIFISP_BLS_ENA BIT(0) +#define CIFISP_BLS_DIS (0 << 0) +#define CIFISP_BLS_MODE_MEASURED BIT(1) +#define CIFISP_BLS_MODE_FIXED (0 << 1) +#define CIFISP_BLS_WINDOW_1 BIT(2) +#define CIFISP_BLS_WINDOW_2 BIT(3) +/* GAMMA-IN */ +#define CIFISP_DEGAMMA_X_RESERVED \ + ((1 << 31) | (1 << 27) | (1 << 23) | (1 << 19) |\ + (1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)) +#define CIFISP_DEGAMMA_Y_RESERVED 0xFFFFF000 +/*CPROC*/ +#define CIFISP_CPROC_CTRL_RESERVED 0xFFFFFFFE +#define CIFISP_CPROC_CONTRAST_RESERVED 0xFFFFFF00 +#define CIFISP_CPROC_BRIGHTNESS_RESERVED 0xFFFFFF00 +#define CIFISP_CPROC_HUE_RESERVED 0xFFFFFF00 +#define CIFISP_CPROC_SATURATION_RESERVED 0xFFFFFF00 +#define CIFISP_CPROC_MACC_RESERVED 0xE000E000 +#define CIFISP_CPROC_TONE_RESERVED 0xF000 +#define CIFISP_CPROC_TONE_Y(value) ((value) << 16) +#define CIFISP_CPROC_TONE_C(value) ((value)) +#define CIFISP_CPROC_TONE_Y_READ(value) ((value) >> 16) +#define CIFISP_CPROC_TONE_C_READ(value) ((value) & 0xFFFF) +#define CIFISP_CPROC_EN 1 +#define CIFISP_CPROC_MACC_EN BIT(4) +#define CIFISP_CPROC_TMAP_EN BIT(5) +/* LSC */ +#define CIFISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 +#define CIFISP_LSC_GRAD_RESERVED 0xF000F000 +#define CIFISP_LSC_SAMPLE_RESERVED 0xF000F000 +#define CIFISP_LSC_SECTORS_MAX 16 +#define CIFISP_LSC_TABLE_DATA(v0, v1) (v0 | ((v1) << 12)) +#define CIFISP_LSC_SECT_SIZE(v0, v1) (v0 | ((v1) << 16)) +#define CIFISP_LSC_GRAD_SIZE(v0, v1) (v0 | ((v1) << 16)) +/* AFC */ +#define CIFISP_AFC_THRES_RESERVED 0xFFFF0000 +#define CIFISP_AFC_VAR_SHIFT_RESERVED 0xFFF8FFF8 +#define CIFISP_AFC_WINDOW_X_RESERVED 0xE000 +#define CIFISP_AFC_WINDOW_Y_RESERVED 0xF000 +#define CIFISP_AFC_WINDOW_X_MIN 0x5 +#define CIFISP_AFC_WINDOW_Y_MIN 0x2 +#define CIFISP_AFC_WINDOW_X(value) ((value) << 16) +#define CIFISP_AFC_WINDOW_Y(value) (value) +#define CIFISP_AFC_ENA (1) +#define CIFISP_AFC_DIS (0) + +/* DPF */ +#define CIFISP_DPF_NF_GAIN_RESERVED 0xFFFFF000 +#define CIFISP_DPF_SPATIAL_COEFF_MAX 0x1f +#define CIFISP_DPF_NLL_COEFF_N_MAX 0x3ff + +#define CIFISP_DPF_MODE_USE_NF_GAIN BIT(9) +#define CIFISP_DPF_MODE_LSC_GAIN_COMP BIT(8) +#define CIFISP_DPF_MODE_AWB_GAIN_COMP BIT(7) +#define CIFISP_DPF_MODE_NLL_SEGMENTATION(a) ((a) << 6) +#define CIFISP_DPF_MODE_RB_FLTSIZE(a) ((a) << 5) +#define CIFISP_DPF_MODE_R_FLT_DIS BIT(4) +#define CIFISP_DPF_MODE_R_FLT_EN (0 << 4) +#define CIFISP_DPF_MODE_GR_FLT_DIS BIT(3) +#define CIFISP_DPF_MODE_GR_FLT_EN (0 << 3) +#define CIFISP_DPF_MODE_GB_FLT_DIS BIT(2) +#define CIFISP_DPF_MODE_GB_FLT_EN (0 << 2) +#define CIFISP_DPF_MODE_B_FLT_DIS BIT(1) +#define CIFISP_DPF_MODE_B_FLT_EN (0 << 1) +#define CIFISP_DPF_MODE_EN BIT(0) + +#define CIFISP_DEBUG BIT(0) +#define CIFISP_ERROR BIT(1) + +/* + * Empirical rough (relative) times it takes to perform + * given function. + */ +#define CIFISP_MODULE_DPCC_PROC_TIME 3 +#define CIFISP_MODULE_BLS_PROC_TIME 10 +#define CIFISP_MODULE_LSC_PROC_TIME 1747 +#define CIFISP_MODULE_FLT_PROC_TIME 15 +#define CIFISP_MODULE_BDM_PROC_TIME 1 +#define CIFISP_MODULE_SDG_PROC_TIME 53 +#define CIFISP_MODULE_GOC_PROC_TIME 1000 +#define CIFISP_MODULE_CTK_PROC_TIME 772 +#define CIFISP_MODULE_AWB_PROC_TIME 8 +#define CIFISP_MODULE_HST_PROC_TIME 5 +#define CIFISP_MODULE_AEC_PROC_TIME 5 +#define CIFISP_MODULE_AWB_GAIN_PROC_TIME 2 +#define CIFISP_MODULE_CPROC_PROC_TIME 5 +#define CIFISP_MODULE_AFC_PROC_TIME 8 +#define CIFISP_MODULE_IE_PROC_TIME 5 +#define CIFISP_MODULE_DPF_TIME 5 +#define CIFISP_MODULE_DPF_STRENGTH_TIME 2 +#define CIFISP_MODULE_CSM_PROC_TIME 8 + +/* For Debugging only!!! */ + +#define CIFISP_MODULE_DEFAULT_VBLANKING_TIME 2000 + +#define V4L2_DEV_DEBUG_LEVEL 0 + +#define CIFISP_DPRINT(level, fmt, arg...) \ + do { \ + if (level == CIFISP_ERROR) \ + pr_err(fmt, ##arg); \ + else \ + pr_debug(fmt, ##arg); \ + } while (0) + +#define cifisp_iowrite32(d, a) \ + cif_isp10_pltfrm_write_reg(NULL, (u32)(d), isp_dev->base_addr + (a)) +#define cifisp_ioread32(a) \ + cif_isp10_pltfrm_read_reg(NULL, isp_dev->base_addr + (a)) +#define cifisp_iowrite32OR(d, a) \ + cif_isp10_pltfrm_write_reg_OR(NULL, (u32)(d), isp_dev->base_addr + (a)) +#define cifisp_iowrite32AND(d, a) \ + cif_isp10_pltfrm_write_reg_AND(NULL, (u32)(d), isp_dev->base_addr + (a)) + +/* + * Set this flag to enable CIF ISP Register debug + * #define CIFISP_DEBUG_REG + */ +/* + * Set this flag to dump the parameters + * #define CIFISP_DEBUG_PARAM + */ +/* + * Set this flag to trace the capture params + * #define LOG_CAPTURE_PARAMS + */ +/* + * Set this flag to trace the isr execution time + * #define LOG_ISR_EXE_TIME + */ +/* + * Set this flag to exclude everything except + * measurements + * #define CIFISP_DEBUG_DISABLE_BLOCKS + */ + +#ifdef LOG_CAPTURE_PARAMS +static struct cifisp_last_capture_config g_last_capture_config; +#endif + +#ifdef LOG_ISR_EXE_TIME +static unsigned int g_longest_isr_time; +#endif + +/* Functions for Debugging */ +static void cifisp_param_dump(const void *config, unsigned int module); +#ifdef CIFISP_DEBUG_REG +static void cifisp_reg_dump(const struct cif_isp10_isp_dev *isp_dev, + unsigned int module, int level); +#endif +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_reg_dump_capture(const struct cif_isp10_isp_dev *isp_dev); +#endif + +static int cifisp_module_enable(struct cif_isp10_isp_dev *isp_dev, + bool flag, __s32 *value, unsigned int module) +{ + unsigned int *curr_ens, *updates, *new_ens; + unsigned long lock_flags = 0; + int retval = 0; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (module & (CIFISP_MODULE_AWB | + CIFISP_MODULE_AEC | + CIFISP_MODULE_AFC | + CIFISP_MODULE_HST)) { + curr_ens = &isp_dev->meas_cfgs.curr->module_ens; + new_ens = &isp_dev->meas_cfgs.last_or_new->module_ens; + updates = &isp_dev->meas_cfgs.module_updates; + } else { + curr_ens = &isp_dev->other_cfgs.curr->module_ens; + new_ens = &isp_dev->other_cfgs.last_or_new->module_ens; + updates = &isp_dev->other_cfgs.module_updates; + } + + if (flag == _GET_) { + *value = CIFISP_MODULE_IS_EN(*curr_ens, module); + goto end; + } + + if (CIFISP_MODULE_IS_EN(*curr_ens, module) != *value) { + if (*value) + CIFISP_MODULE_EN(*new_ens, module); + else + CIFISP_MODULE_DIS(*new_ens, module); + + CIFISP_MODULE_UPDATE(*updates, module); + } + +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP BP interface function */ +static int cifisp_dpcc_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_dpcc_config *arg) +{ + unsigned long lock_flags = 0; + unsigned int i; + struct cifisp_dpcc_methods_config *method; + int retval = 0; + + if (!arg) { + CIFISP_DPRINT(CIFISP_ERROR, + "arg is NULL: %s\n", __func__); + + return -EINVAL; + } + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->dpcc_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_DPCC); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->dpcc_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->mode > CIFISP_DPCC_MODE_MAX || + arg->output_mode > CIFISP_DPCC_OUTPUTMODE_MAX || + arg->set_use > CIFISP_DPCC_SETUSE_MAX || + arg->ro_limits & CIFISP_DPCC_RO_LIMIT_RESERVED || + arg->rnd_offs & CIFISP_DPCC_RND_OFFS_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + method = &arg->methods[i]; + for (i = 0; i < CIFISP_DPCC_METHODS_MAX; i++) { + if ((method->method & + CIFISP_DPCC_METHODS_SET_RESERVED) || + (method->line_thresh & + CIFISP_DPCC_LINE_THRESH_RESERVED) || + (method->line_mad_fac & + CIFISP_DPCC_LINE_MAD_FAC_RESERVED) || + (method->pg_fac & + CIFISP_DPCC_PG_FAC_RESERVED) || + (method->rnd_thresh & + CIFISP_DPCC_RND_THRESH_RESERVED) || + (method->rg_fac & CIFISP_DPCC_RG_FAC_RESERVED)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + method++; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->dpcc_config, + arg, + sizeof(struct cifisp_dpcc_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPCC); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP black level subtraction interface function */ +static int cifisp_bls_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_bls_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->bls_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_BLS); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->bls_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->bls_window1.h_offs > CIFISP_BLS_START_H_MAX || + arg->bls_window1.h_size > CIFISP_BLS_STOP_H_MAX || + arg->bls_window1.v_offs > CIFISP_BLS_START_V_MAX || + arg->bls_window1.v_size > CIFISP_BLS_STOP_V_MAX || + arg->bls_window2.h_offs > CIFISP_BLS_START_H_MAX || + arg->bls_window2.h_size > CIFISP_BLS_STOP_H_MAX || + arg->bls_window2.v_offs > CIFISP_BLS_START_V_MAX || + arg->bls_window2.v_size > CIFISP_BLS_STOP_V_MAX || + arg->bls_samples > CIFISP_BLS_SAMPLES_MAX || + arg->fixed_val.r > CIFISP_BLS_FIX_SUB_MAX || + arg->fixed_val.gr > CIFISP_BLS_FIX_SUB_MAX || + arg->fixed_val.gb > CIFISP_BLS_FIX_SUB_MAX || + arg->fixed_val.b > CIFISP_BLS_FIX_SUB_MAX || + arg->fixed_val.r < (s16)CIFISP_BLS_FIX_SUB_MIN || + arg->fixed_val.gr < (s16)CIFISP_BLS_FIX_SUB_MIN || + arg->fixed_val.gb < (s16)CIFISP_BLS_FIX_SUB_MIN || + arg->fixed_val.b < (s16)CIFISP_BLS_FIX_SUB_MIN) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->bls_config, + arg, + sizeof(struct cifisp_bls_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_BLS); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP LS correction interface function */ +static int cifisp_lsc_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_lsc_config *arg) +{ + int i; + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->lsc_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_LSC); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->lsc_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + for (i = 0; i < CIFISP_LSC_SIZE_TBL_SIZE; i++) { + if ((*(arg->x_size_tbl + i) & CIFISP_LSC_SECT_SIZE_RESERVED) || + (*(arg->y_size_tbl + i) & CIFISP_LSC_SECT_SIZE_RESERVED)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible sect size x 0x%x y 0x%x in function: %s\n", + *(arg->x_size_tbl + i), + *(arg->y_size_tbl + i), __func__); + retval = -EINVAL; + goto end; + } + } + + for (i = 0; i < CIFISP_LSC_GRAD_TBL_SIZE; i++) { + if ((*(arg->x_grad_tbl + i) & CIFISP_LSC_GRAD_RESERVED) || + (*(arg->y_grad_tbl + i) & CIFISP_LSC_GRAD_RESERVED)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible grad x 0x%x y 0x%xin function: %s\n", + *(arg->x_grad_tbl + i), + *(arg->y_grad_tbl + i), __func__); + retval = -EINVAL; + goto end; + } + } + + for (i = 0; i < CIFISP_LSC_DATA_TBL_SIZE; i++) { + if ((*(arg->r_data_tbl + i) & + CIFISP_LSC_SAMPLE_RESERVED) || + (*(arg->gr_data_tbl + i) & + CIFISP_LSC_SAMPLE_RESERVED) || + (*(arg->gb_data_tbl + i) & + CIFISP_LSC_SAMPLE_RESERVED) || + (*(arg->b_data_tbl + i) & + CIFISP_LSC_SAMPLE_RESERVED)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible sample r 0x%x gr 0x%x gb 0x%x b 0x%x in function: %s\n", + *(arg->r_data_tbl + i), + *(arg->gr_data_tbl + i), + *(arg->gb_data_tbl + i), + *(arg->b_data_tbl + i), __func__); + retval = -EINVAL; + goto end; + } + } + + memcpy(&isp_dev->other_cfgs.last_or_new->lsc_config, + arg, + sizeof(struct cifisp_lsc_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_LSC); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP Filtering function */ +static int cifisp_flt_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_flt_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->flt_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_FLT); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->flt_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + /* Parameter check */ + if (arg->mode > CIFISP_FLT_MODE_MAX || + arg->grn_stage1 > CIFISP_FLT_GREEN_STAGE1_MAX || + arg->chr_v_mode > CIFISP_FLT_CHROMA_MODE_MAX || + arg->chr_h_mode > CIFISP_FLT_CHROMA_MODE_MAX || + arg->thresh_sh0 & CIFISP_FLT_THREAD_RESERVED || + arg->thresh_sh1 & CIFISP_FLT_THREAD_RESERVED || + arg->thresh_bl0 & CIFISP_FLT_THREAD_RESERVED || + arg->thresh_bl1 & CIFISP_FLT_THREAD_RESERVED || + arg->fac_bl0 & CIFISP_FLT_FAC_RESERVED || + arg->fac_bl1 & CIFISP_FLT_FAC_RESERVED || + arg->fac_sh0 & CIFISP_FLT_FAC_RESERVED || + arg->fac_sh1 & CIFISP_FLT_FAC_RESERVED || + arg->fac_mid & CIFISP_FLT_FAC_RESERVED || + arg->lum_weight & CIFISP_FLT_LUM_WEIGHT_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->flt_config, + arg, + sizeof(struct cifisp_flt_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_FLT); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP demosaic interface function */ +static int cifisp_bdm_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_bdm_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->bdm_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_BDM); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->bdm_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->bdm_config, + arg, + sizeof(struct cifisp_bdm_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_BDM); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP GAMMA correction interface function */ +static int cifisp_sdg_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_sdg_config *arg) +{ + unsigned long lock_flags = 0; + unsigned int i; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->sdg_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_SDG); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->sdg_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->xa_pnts.gamma_dx0 & CIFISP_DEGAMMA_X_RESERVED || + arg->xa_pnts.gamma_dx1 & CIFISP_DEGAMMA_X_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + for (i = 0; i < CIFISP_DEGAMMA_CURVE_SIZE; i++) { + if ((arg->curve_b.gamma_y[i] & CIFISP_DEGAMMA_Y_RESERVED) || + (arg->curve_r.gamma_y[i] & CIFISP_DEGAMMA_Y_RESERVED) || + (arg->curve_g.gamma_y[i] & CIFISP_DEGAMMA_Y_RESERVED)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + } + + memcpy(&isp_dev->other_cfgs.last_or_new->sdg_config, + arg, + sizeof(struct cifisp_sdg_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_SDG); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP GAMMA correction interface function */ +static int cifisp_goc_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_goc_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->goc_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_GOC); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->goc_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->mode > CIFISP_GOC_MODE_MAX) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param 0x%x in function: %s\n", + arg->mode, __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->goc_config, + arg, + sizeof(struct cifisp_goc_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_GOC); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP Cross Talk */ +static int cifisp_ctk_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_ctk_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->ctk_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_CTK); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->ctk_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + /* Perform parameter check */ + if (arg->coeff0 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff1 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff2 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff3 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff4 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff5 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff6 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff7 & CIFISP_CTK_COEFF_RESERVED || + arg->coeff8 & CIFISP_CTK_COEFF_RESERVED || + arg->ct_offset_r & CIFISP_XTALK_OFFSET_RESERVED || + arg->ct_offset_g & CIFISP_XTALK_OFFSET_RESERVED || + arg->ct_offset_b & CIFISP_XTALK_OFFSET_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->ctk_config, + arg, + sizeof(struct cifisp_ctk_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_CTK); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP White Balance Mode */ +static int cifisp_awb_meas_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_awb_meas_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->meas_cfgs.curr->awb_meas_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_AWB); + + if (memcmp(arg, + &isp_dev->meas_cfgs.curr->awb_meas_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->awb_mode > CIFISP_AWB_MODE_YCBCR || + arg->awb_wnd.h_offs > CIFISP_AWB_WINDOW_OFFSET_MAX || + arg->awb_wnd.v_offs > CIFISP_AWB_WINDOW_OFFSET_MAX || + arg->awb_wnd.h_size > CIFISP_AWB_WINDOW_MAX_SIZE || + arg->awb_wnd.v_size > CIFISP_AWB_WINDOW_MAX_SIZE || + arg->frames > CIFISP_AWB_MAX_FRAMES) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->meas_cfgs.last_or_new->awb_meas_config, + arg, + sizeof(struct cifisp_awb_meas_config)); + CIFISP_MODULE_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AWB); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_awb_gain_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_awb_gain_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->awb_gain_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_AWB_GAIN); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->awb_gain_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->gain_red > CIFISP_AWB_GAINS_MAX_VAL || + arg->gain_green_r > CIFISP_AWB_GAINS_MAX_VAL || + arg->gain_green_b > CIFISP_AWB_GAINS_MAX_VAL || + arg->gain_blue > CIFISP_AWB_GAINS_MAX_VAL) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->awb_gain_config, + arg, + sizeof(struct cifisp_awb_gain_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_AWB_GAIN); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_aec_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_aec_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->meas_cfgs.curr->aec_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_AEC); + + if (memcmp(arg, + &isp_dev->meas_cfgs.curr->aec_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->meas_window.h_offs > CIFISP_EXP_MAX_HOFFS || + arg->meas_window.h_size > CIFISP_EXP_MAX_HSIZE || + arg->meas_window.h_size < CIFISP_EXP_MIN_HSIZE || + arg->meas_window.v_offs > CIFISP_EXP_MAX_VOFFS || + arg->meas_window.v_size > CIFISP_EXP_MAX_VSIZE || + arg->meas_window.v_size < CIFISP_EXP_MIN_VSIZE || + arg->mode > CIFISP_EXP_MEASURING_MODE_1) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->meas_cfgs.last_or_new->aec_config, + arg, + sizeof(struct cifisp_aec_config)); + CIFISP_MODULE_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AEC); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_cproc_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_cproc_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->cproc_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_CPROC); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->cproc_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->c_out_range & CIFISP_CPROC_CTRL_RESERVED || + arg->y_out_range & CIFISP_CPROC_CTRL_RESERVED || + arg->y_in_range & CIFISP_CPROC_CTRL_RESERVED || + arg->contrast & CIFISP_CPROC_CONTRAST_RESERVED || + arg->brightness & CIFISP_CPROC_BRIGHTNESS_RESERVED || + arg->sat & CIFISP_CPROC_SATURATION_RESERVED || + arg->hue & CIFISP_CPROC_HUE_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->cproc_config, + arg, + sizeof(struct cifisp_cproc_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_CPROC); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_hst_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_hst_config *arg) +{ + unsigned long lock_flags = 0; + unsigned int i; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->meas_cfgs.curr->hst_config, + sizeof(*arg)); + goto end; + } + + if (memcmp(arg, + &isp_dev->meas_cfgs.curr->hst_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->mode > CIFISP_HISTOGRAM_MODE_Y_HISTOGRAM || + arg->histogram_predivider > CIFISP_MAX_HIST_PREDIVIDER || + arg->meas_window.v_offs & CIFISP_HIST_WINDOW_OFFSET_RESERVED || + arg->meas_window.h_offs & CIFISP_HIST_WINDOW_OFFSET_RESERVED || + (arg->meas_window.v_size / (CIFISP_HIST_ROW_NUM - 1)) & + CIFISP_HIST_WINDOW_SIZE_RESERVED || + (arg->meas_window.h_size / (CIFISP_HIST_COLUMN_NUM - 1)) & + CIFISP_HIST_WINDOW_SIZE_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s line: %d\n", + __func__, __LINE__); + retval = -EINVAL; + goto end; + } + + for (i = 0; i < CIFISP_HISTOGRAM_WEIGHT_GRIDS_SIZE; i++) { + if (arg->hist_weight[i] & CIFISP_HIST_WEIGHT_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s line: %d\n", + __func__, __LINE__); + retval = -EINVAL; + goto end; + } + } + + memcpy(&isp_dev->meas_cfgs.last_or_new->hst_config, + arg, + sizeof(struct cifisp_hst_config)); + CIFISP_MODULE_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_HST); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_afc_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_afc_config *arg) +{ + unsigned long lock_flags = 0; + int i; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->meas_cfgs.curr->afc_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_AFC); + + if (memcmp(arg, + &isp_dev->meas_cfgs.curr->afc_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->num_afm_win > CIFISP_AFM_MAX_WINDOWS || + arg->thres & CIFISP_AFC_THRES_RESERVED || + arg->var_shift & CIFISP_AFC_VAR_SHIFT_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + for (i = 0; i < arg->num_afm_win; i++) { + if (arg->afm_win[i].h_offs & CIFISP_AFC_WINDOW_X_RESERVED || + arg->afm_win[i].h_offs < CIFISP_AFC_WINDOW_X_MIN || + arg->afm_win[i].v_offs & CIFISP_AFC_WINDOW_Y_RESERVED || + arg->afm_win[i].v_offs < CIFISP_AFC_WINDOW_Y_MIN || + arg->afm_win[i].h_size & CIFISP_AFC_WINDOW_X_RESERVED || + arg->afm_win[i].v_size & CIFISP_AFC_WINDOW_Y_RESERVED) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", + __func__); + retval = -EINVAL; + goto end; + } + } + + memcpy(&isp_dev->meas_cfgs.last_or_new->afc_config, + arg, + sizeof(struct cifisp_afc_config)); + CIFISP_MODULE_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AFC); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_ie_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_ie_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->ie_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_IE); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->ie_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + if (arg->effect != V4L2_COLORFX_NONE && + arg->effect != V4L2_COLORFX_BW && + arg->effect != V4L2_COLORFX_SEPIA && + arg->effect != V4L2_COLORFX_NEGATIVE && + arg->effect != V4L2_COLORFX_EMBOSS && + arg->effect != V4L2_COLORFX_SKETCH && + arg->effect != V4L2_COLORFX_AQUA && + arg->effect != V4L2_COLORFX_SET_CBCR) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible param in function: %s\n", __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->ie_config, + arg, + sizeof(struct cifisp_ie_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_IE); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +/* ISP De-noise Pre-Filter(DPF) function */ +static int cifisp_dpf_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_dpf_config *arg) +{ + unsigned long lock_flags = 0; + unsigned int i; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->dpf_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_DPF); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->dpf_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + /* Parameter check */ + if ((arg->gain.mode >= CIFISP_DPF_GAIN_USAGE_MAX) || + (arg->gain.mode < CIFISP_DPF_GAIN_USAGE_DISABLED) || + (arg->gain.nf_b_gain & CIFISP_DPF_NF_GAIN_RESERVED) || + (arg->gain.nf_r_gain & CIFISP_DPF_NF_GAIN_RESERVED) || + (arg->gain.nf_gr_gain & CIFISP_DPF_NF_GAIN_RESERVED) || + (arg->gain.nf_gb_gain & CIFISP_DPF_NF_GAIN_RESERVED)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible DPF GAIN param in function: %s\n", + __func__); + retval = -EINVAL; + goto end; + } + + for (i = 0; i < CIFISP_DPF_MAX_SPATIAL_COEFFS; i++) { + if ((arg->g_flt.spatial_coeff[i] > + CIFISP_DPF_SPATIAL_COEFF_MAX)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible DPF G Spatial param in function: %s\n", + __func__); + retval = -EINVAL; + goto end; + } + + if (arg->rb_flt.spatial_coeff[i] > + CIFISP_DPF_SPATIAL_COEFF_MAX) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible DPF RB Spatial param in function: %s\n", + __func__); + retval = -EINVAL; + goto end; + } + } + + if ((arg->rb_flt.fltsize != CIFISP_DPF_RB_FILTERSIZE_9x9) && + (arg->rb_flt.fltsize != CIFISP_DPF_RB_FILTERSIZE_13x9)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible DPF RB filter size param in function: %s\n", + __func__); + retval = -EINVAL; + goto end; + } + + for (i = 0; i < CIFISP_DPF_MAX_NLF_COEFFS; i++) { + if (arg->nll.coeff[i] > CIFISP_DPF_NLL_COEFF_N_MAX) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible DPF NLL coeff param in function: %s\n", + __func__); + retval = -EINVAL; + goto end; + } + } + + if ((arg->nll.scale_mode != CIFISP_NLL_SCALE_LINEAR) && + (arg->nll.scale_mode != CIFISP_NLL_SCALE_LOGARITHMIC)) { + CIFISP_DPRINT(CIFISP_ERROR, + "incompatible DPF NLL scale mode param in function: %s\n", + __func__); + retval = -EINVAL; + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->dpf_config, + arg, + sizeof(struct cifisp_dpf_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPF); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_dpf_strength_param(struct cif_isp10_isp_dev *isp_dev, + bool flag, struct cifisp_dpf_strength_config *arg) +{ + unsigned long lock_flags = 0; + int retval = 0; + + if (!arg) + return -EINVAL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (flag == _GET_) { + memcpy(arg, + &isp_dev->other_cfgs.curr->dpf_strength_config, + sizeof(*arg)); + goto end; + } + + cifisp_param_dump(arg, CIFISP_MODULE_DPF_STRENGTH); + + if (memcmp(arg, + &isp_dev->other_cfgs.curr->dpf_strength_config, + sizeof(*arg)) == 0) { + CIFISP_DPRINT(CIFISP_DEBUG, + "same param in function: %s\n", __func__); + goto end; + } + + memcpy(&isp_dev->other_cfgs.last_or_new->dpf_strength_config, + arg, + sizeof(struct cifisp_dpf_strength_config)); + CIFISP_MODULE_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPF_STRENGTH); +end: + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + return retval; +} + +static int cifisp_last_capture_config(struct cifisp_last_capture_config *arg) +{ +#ifdef LOG_CAPTURE_PARAMS + if (!arg) + return -EINVAL; + + memcpy(arg, &g_last_capture_config, sizeof(*arg)); + + return 0; +#else + return -EPERM; +#endif +} + +/* DPCC */ +static void cifisp_dpcc_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_dpcc_config *pconfig = + &isp_dev->other_cfgs.last_or_new->dpcc_config; + unsigned int i; + + cifisp_iowrite32(pconfig->mode, CIF_ISP_DPCC_MODE); + cifisp_iowrite32(pconfig->output_mode, CIF_ISP_DPCC_OUTPUT_MODE); + cifisp_iowrite32(pconfig->set_use, CIF_ISP_DPCC_SET_USE); + + cifisp_iowrite32(pconfig->methods[0].method, + CIF_ISP_DPCC_METHODS_SET_1); + cifisp_iowrite32(pconfig->methods[1].method, + CIF_ISP_DPCC_METHODS_SET_2); + cifisp_iowrite32(pconfig->methods[2].method, + CIF_ISP_DPCC_METHODS_SET_3); + for (i = 0; i < CIFISP_DPCC_METHODS_MAX; i++) { + cifisp_iowrite32(pconfig->methods[i].line_thresh, + CIF_ISP_DPCC_LINE_THRESH_1 + 0x14 * i); + cifisp_iowrite32(pconfig->methods[i].line_mad_fac, + CIF_ISP_DPCC_LINE_MAD_FAC_1 + 0x14 * i); + cifisp_iowrite32(pconfig->methods[i].pg_fac, + CIF_ISP_DPCC_PG_FAC_1 + 0x14 * i); + cifisp_iowrite32(pconfig->methods[i].rnd_thresh, + CIF_ISP_DPCC_RND_THRESH_1 + 0x14 * i); + cifisp_iowrite32(pconfig->methods[i].rg_fac, + CIF_ISP_DPCC_RG_FAC_1 + 0x14 * i); + } + + cifisp_iowrite32(pconfig->rnd_offs, CIF_ISP_DPCC_RND_OFFS); + cifisp_iowrite32(pconfig->ro_limits, CIF_ISP_DPCC_RO_LIMITS); +} + +static void cifisp_dpcc_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIFISP_DPCC_ENA, CIF_ISP_DPCC_MODE); +} + +static void cifisp_dpcc_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32(CIFISP_DPCC_DIS, CIF_ISP_DPCC_MODE); +} + +/* Lens Shade Correction */ + +/*****************************************************************************/ +static void cifisp_lsc_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32(0, CIF_ISP_LSC_CTRL); +} + +static bool cifisp_lsc_correct_matrix_config(struct cif_isp10_isp_dev *isp_dev) +{ + int i, n; + unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel; + unsigned int data; + struct cifisp_lsc_config *pconfig = + &isp_dev->other_cfgs.last_or_new->lsc_config; + + isp_lsc_status = cifisp_ioread32(CIF_ISP_LSC_STATUS); + sram_addr = (isp_lsc_status & 0x2U) ? 0U : 153U; /* ( 17 * 18 ) >> 1 */ + + cifisp_iowrite32(sram_addr, CIF_ISP_LSC_R_TABLE_ADDR); + cifisp_iowrite32(sram_addr, CIF_ISP_LSC_GR_TABLE_ADDR); + cifisp_iowrite32(sram_addr, CIF_ISP_LSC_GB_TABLE_ADDR); + cifisp_iowrite32(sram_addr, CIF_ISP_LSC_B_TABLE_ADDR); + + /* program data tables (table size is 9 * 17 = 153) */ + for (n = 0; n < ((CIFISP_LSC_SECTORS_MAX + 1) * + (CIFISP_LSC_SECTORS_MAX + 1)); + n += CIFISP_LSC_SECTORS_MAX + 1) { + /* + * 17 sectors with 2 values in one DWORD = 9 + * DWORDs (8 steps + 1 outside loop) + */ + for (i = 0; i < (CIFISP_LSC_SECTORS_MAX); i += 2) { + data = CIFISP_LSC_TABLE_DATA(pconfig->r_data_tbl[n + i], + pconfig->r_data_tbl[n + i + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_R_TABLE_DATA); + + data = CIFISP_LSC_TABLE_DATA( + pconfig->gr_data_tbl[n + i], + pconfig->gr_data_tbl[n + i + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_GR_TABLE_DATA); + + data = CIFISP_LSC_TABLE_DATA( + pconfig->gb_data_tbl[n + i], + pconfig->gb_data_tbl[n + i + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_GB_TABLE_DATA); + + data = CIFISP_LSC_TABLE_DATA(pconfig->b_data_tbl[n + i], + pconfig->b_data_tbl[n + i + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_B_TABLE_DATA); + } + + data = CIFISP_LSC_TABLE_DATA( + pconfig->r_data_tbl[n + CIFISP_LSC_SECTORS_MAX], + /* isp_dev->lsc_config.r_data_tbl[n + i] */0); + cifisp_iowrite32(data, CIF_ISP_LSC_R_TABLE_DATA); + + data = CIFISP_LSC_TABLE_DATA( + pconfig->gr_data_tbl[n + CIFISP_LSC_SECTORS_MAX], + /* isp_dev->lsc_config.gr_data_tbl[n + i] */0); + cifisp_iowrite32(data, CIF_ISP_LSC_GR_TABLE_DATA); + + data = CIFISP_LSC_TABLE_DATA( + pconfig->gb_data_tbl[n + CIFISP_LSC_SECTORS_MAX], + /* isp_dev->lsc_config.gr_data_tbl[n + i] */0); + cifisp_iowrite32(data, CIF_ISP_LSC_GB_TABLE_DATA); + + data = CIFISP_LSC_TABLE_DATA( + pconfig->b_data_tbl[n + CIFISP_LSC_SECTORS_MAX], + /* isp_dev->lsc_config.b_data_tbl[n + i] */0); + cifisp_iowrite32(data, CIF_ISP_LSC_B_TABLE_DATA); + } + + isp_lsc_table_sel = (isp_lsc_status & 0x2U) ? 0U : 1U; + cifisp_iowrite32(isp_lsc_table_sel, CIF_ISP_LSC_TABLE_SEL); + return true; +} + +/*****************************************************************************/ +static bool cifisp_lsc_config(struct cif_isp10_isp_dev *isp_dev) +{ + int i; + unsigned int data; + struct cifisp_lsc_config *pconfig = + &isp_dev->other_cfgs.last_or_new->lsc_config; + + if (pconfig->config_width != isp_dev->input_width || + pconfig->config_height != isp_dev->input_height) { + CIFISP_DPRINT(CIFISP_DEBUG, + "LSC config: lsc_w %d lsc_h %d act_w %d act_h %d\n", + pconfig->config_width, + pconfig->config_height, + isp_dev->input_width, + isp_dev->input_height); + return false; + } + + CIFISP_DPRINT(CIFISP_DEBUG, + "LSC config: lsc_w %d lsc_h %d\n", + pconfig->config_width, + pconfig->config_height); + + /* To config must be off */ + cifisp_iowrite32(0, CIF_ISP_LSC_CTRL); + + cifisp_lsc_correct_matrix_config(isp_dev); + + if (isp_dev->active_lsc_width != + pconfig->config_width || + isp_dev->active_lsc_height != + pconfig->config_height) { + for (i = 0; i < 4; i++) { + /* program x size tables */ + data = CIFISP_LSC_SECT_SIZE( + pconfig->x_size_tbl[i * 2], + pconfig->x_size_tbl[i * 2 + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_XSIZE_01 + i * 4); + + /* program x grad tables */ + data = CIFISP_LSC_SECT_SIZE( + pconfig->x_grad_tbl[i * 2], + pconfig->x_grad_tbl[i * 2 + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_XGRAD_01 + i * 4); + + /* program y size tables */ + data = CIFISP_LSC_SECT_SIZE( + pconfig->y_size_tbl[i * 2], + pconfig->y_size_tbl[i * 2 + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_YSIZE_01 + i * 4); + + /* program y grad tables */ + data = CIFISP_LSC_SECT_SIZE( + pconfig->y_grad_tbl[i * 2], + pconfig->y_grad_tbl[i * 2 + 1]); + cifisp_iowrite32(data, CIF_ISP_LSC_YGRAD_01 + i * 4); + } + + isp_dev->active_lsc_width = pconfig->config_width; + isp_dev->active_lsc_height = pconfig->config_height; + } + + cifisp_iowrite32(1, CIF_ISP_LSC_CTRL); + + return true; +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_lsc_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_lsc_config *pconfig) +{ +); +} +#endif + +/*****************************************************************************/ +static void cifisp_bls_get_meas(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_stat_buffer *pbuf) +{ + const struct cif_isp10_device *cif_dev = + container_of(isp_dev, struct cif_isp10_device, isp_dev); + enum cif_isp10_pix_fmt in_pix_fmt; + + in_pix_fmt = cif_dev->config.isp_config.input->pix_fmt; + if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_BGGR(in_pix_fmt)) { + pbuf->params.ae.bls_val.meas_b = + cifisp_ioread32(CIF_ISP_BLS_A_MEASURED); + pbuf->params.ae.bls_val.meas_gb = + cifisp_ioread32(CIF_ISP_BLS_B_MEASURED); + pbuf->params.ae.bls_val.meas_gr = + cifisp_ioread32(CIF_ISP_BLS_C_MEASURED); + pbuf->params.ae.bls_val.meas_r = + cifisp_ioread32(CIF_ISP_BLS_D_MEASURED); + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GBRG(in_pix_fmt)) { + pbuf->params.ae.bls_val.meas_gb = + cifisp_ioread32(CIF_ISP_BLS_A_MEASURED); + pbuf->params.ae.bls_val.meas_b = + cifisp_ioread32(CIF_ISP_BLS_B_MEASURED); + pbuf->params.ae.bls_val.meas_r = + cifisp_ioread32(CIF_ISP_BLS_C_MEASURED); + pbuf->params.ae.bls_val.meas_gr = + cifisp_ioread32(CIF_ISP_BLS_D_MEASURED); + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GRBG(in_pix_fmt)) { + pbuf->params.ae.bls_val.meas_gr = + cifisp_ioread32(CIF_ISP_BLS_A_MEASURED); + pbuf->params.ae.bls_val.meas_r = + cifisp_ioread32(CIF_ISP_BLS_B_MEASURED); + pbuf->params.ae.bls_val.meas_b = + cifisp_ioread32(CIF_ISP_BLS_C_MEASURED); + pbuf->params.ae.bls_val.meas_gb = + cifisp_ioread32(CIF_ISP_BLS_D_MEASURED); + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_RGGB(in_pix_fmt)) { + pbuf->params.ae.bls_val.meas_r = + cifisp_ioread32(CIF_ISP_BLS_A_MEASURED); + pbuf->params.ae.bls_val.meas_gr = + cifisp_ioread32(CIF_ISP_BLS_B_MEASURED); + pbuf->params.ae.bls_val.meas_gb = + cifisp_ioread32(CIF_ISP_BLS_C_MEASURED); + pbuf->params.ae.bls_val.meas_b = + cifisp_ioread32(CIF_ISP_BLS_D_MEASURED); + } +} + +/*****************************************************************************/ +static void cifisp_bls_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_bls_config *pconfig = + &isp_dev->other_cfgs.last_or_new->bls_config; + u32 new_control = 0; + const struct cif_isp10_device *cif_dev = + container_of(isp_dev, struct cif_isp10_device, isp_dev); + enum cif_isp10_pix_fmt in_pix_fmt; + + in_pix_fmt = cif_dev->config.isp_config.input->pix_fmt; + + /* fixed subtraction values */ + if (!pconfig->enable_auto) { + const struct cifisp_bls_fixed_val *pval = + &isp_dev->other_cfgs.last_or_new->bls_config.fixed_val; + + if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_BGGR(in_pix_fmt)) { + cifisp_iowrite32(pval->r, CIF_ISP_BLS_D_FIXED); + cifisp_iowrite32(pval->gr, CIF_ISP_BLS_C_FIXED); + cifisp_iowrite32(pval->gb, CIF_ISP_BLS_B_FIXED); + cifisp_iowrite32(pval->b, CIF_ISP_BLS_A_FIXED); + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GBRG(in_pix_fmt)) { + cifisp_iowrite32(pval->r, CIF_ISP_BLS_C_FIXED); + cifisp_iowrite32(pval->gr, CIF_ISP_BLS_D_FIXED); + cifisp_iowrite32(pval->gb, CIF_ISP_BLS_A_FIXED); + cifisp_iowrite32(pval->b, CIF_ISP_BLS_B_FIXED); + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_GRBG(in_pix_fmt)) { + cifisp_iowrite32(pval->r, CIF_ISP_BLS_B_FIXED); + cifisp_iowrite32(pval->gr, CIF_ISP_BLS_A_FIXED); + cifisp_iowrite32(pval->gb, CIF_ISP_BLS_D_FIXED); + cifisp_iowrite32(pval->b, CIF_ISP_BLS_C_FIXED); + } else if (CIF_ISP10_PIX_FMT_BAYER_PAT_IS_RGGB(in_pix_fmt)) { + cifisp_iowrite32(pval->r, CIF_ISP_BLS_A_FIXED); + cifisp_iowrite32(pval->gr, CIF_ISP_BLS_B_FIXED); + cifisp_iowrite32(pval->gb, CIF_ISP_BLS_C_FIXED); + cifisp_iowrite32(pval->b, CIF_ISP_BLS_D_FIXED); + } + + new_control = CIFISP_BLS_MODE_FIXED; + cifisp_iowrite32(new_control, CIF_ISP_BLS_CTRL); + } else { + if (pconfig->en_windows & 2) { + cifisp_iowrite32(pconfig->bls_window2.h_offs, + CIF_ISP_BLS_H2_START); + cifisp_iowrite32(pconfig->bls_window2.h_size, + CIF_ISP_BLS_H2_STOP); + cifisp_iowrite32(pconfig->bls_window2.v_offs, + CIF_ISP_BLS_V2_START); + cifisp_iowrite32(pconfig->bls_window2.v_size, + CIF_ISP_BLS_V2_STOP); + new_control |= CIFISP_BLS_WINDOW_2; + } + + if (pconfig->en_windows & 1) { + cifisp_iowrite32(pconfig->bls_window1.h_offs, + CIF_ISP_BLS_H1_START); + cifisp_iowrite32(pconfig->bls_window1.h_size, + CIF_ISP_BLS_H1_STOP); + cifisp_iowrite32(pconfig->bls_window1.v_offs, + CIF_ISP_BLS_V1_START); + cifisp_iowrite32(pconfig->bls_window1.v_size, + CIF_ISP_BLS_V1_STOP); + new_control |= CIFISP_BLS_WINDOW_1; + } + + cifisp_iowrite32(pconfig->bls_samples, CIF_ISP_BLS_SAMPLES); + + new_control |= CIFISP_BLS_MODE_MEASURED; + + cifisp_iowrite32(new_control, CIF_ISP_BLS_CTRL); + } +} + +/*****************************************************************************/ +static void cifisp_bls_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIFISP_BLS_ENA, CIF_ISP_BLS_CTRL); +} + +/*****************************************************************************/ +static void cifisp_bls_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32(CIFISP_BLS_DIS, CIF_ISP_BLS_CTRL); +} + +/* Gamma correction */ +/*****************************************************************************/ +static void cifisp_sdg_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_sdg_config *pconfig = + &isp_dev->other_cfgs.last_or_new->sdg_config; + unsigned int i; + + cifisp_iowrite32(pconfig->xa_pnts.gamma_dx0, CIF_ISP_GAMMA_DX_LO); + cifisp_iowrite32(pconfig->xa_pnts.gamma_dx1, CIF_ISP_GAMMA_DX_HI); + + for (i = 0; i < CIFISP_DEGAMMA_CURVE_SIZE; i++) { + cifisp_iowrite32(pconfig->curve_r.gamma_y[i], + CIF_ISP_GAMMA_R_Y0 + i * 4); + cifisp_iowrite32(pconfig->curve_g.gamma_y[i], + CIF_ISP_GAMMA_G_Y0 + i * 4); + cifisp_iowrite32(pconfig->curve_b.gamma_y[i], + CIF_ISP_GAMMA_B_Y0 + i * 4); + } +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_sdg_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_sdg_config *pconfig) +{ +} +#endif + +/*****************************************************************************/ +static void cifisp_sdg_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIF_ISP_CTRL_ISP_GAMMA_IN_ENA, CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_sdg_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32AND(~CIF_ISP_CTRL_ISP_GAMMA_IN_ENA, CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_goc_config(const struct cif_isp10_isp_dev *isp_dev) +{ + int i; + const struct cifisp_goc_config *pconfig = + &isp_dev->other_cfgs.last_or_new->goc_config; + + cifisp_iowrite32AND(~CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA, CIF_ISP_CTRL); + + cifisp_iowrite32(pconfig->mode, CIF_ISP_GAMMA_OUT_MODE); + for (i = 0; i < CIFISP_GAMMA_OUT_MAX_SAMPLES; i++) + cifisp_iowrite32(pconfig->gamma_y[i], + CIF_ISP_GAMMA_OUT_Y_0 + i * 4); +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_goc_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_goc_config *pconfig) +{ +} +#endif + +/*****************************************************************************/ +static void cifisp_goc_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA, CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_goc_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32AND(~CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA, CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_bdm_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_bdm_config *pconfig = + &isp_dev->other_cfgs.last_or_new->bdm_config; + + /*set demosaic threshold */ + cifisp_iowrite32(pconfig->demosaic_th, CIF_ISP_DEMOSAIC); +} + +/*****************************************************************************/ +static void cifisp_bdm_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32AND(~(CIFISP_BDM_BYPASS_EN(1)), CIF_ISP_DEMOSAIC); +} + +/*****************************************************************************/ +static void cifisp_bdm_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32(0, CIF_ISP_DEMOSAIC); +} + +/*****************************************************************************/ +static void cifisp_flt_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_flt_config *pconfig = + &isp_dev->other_cfgs.last_or_new->flt_config; + + cifisp_iowrite32(pconfig->thresh_bl0, + CIF_ISP_FILT_THRESH_BL0); + cifisp_iowrite32(pconfig->thresh_bl1, + CIF_ISP_FILT_THRESH_BL1); + cifisp_iowrite32(pconfig->thresh_sh0, + CIF_ISP_FILT_THRESH_SH0); + cifisp_iowrite32(pconfig->thresh_sh1, + CIF_ISP_FILT_THRESH_SH1); + cifisp_iowrite32(pconfig->fac_bl0, + CIF_ISP_FILT_FAC_BL0); + cifisp_iowrite32(pconfig->fac_bl1, + CIF_ISP_FILT_FAC_BL1); + cifisp_iowrite32(pconfig->fac_mid, + CIF_ISP_FILT_FAC_MID); + cifisp_iowrite32(pconfig->fac_sh0, + CIF_ISP_FILT_FAC_SH0); + cifisp_iowrite32(pconfig->fac_sh1, + CIF_ISP_FILT_FAC_SH1); + cifisp_iowrite32(pconfig->lum_weight, + CIF_ISP_FILT_LUM_WEIGHT); + + cifisp_iowrite32(CIFISP_FLT_MODE(pconfig->mode) | + CIFISP_FLT_CHROMA_V_MODE(pconfig->chr_v_mode) | + CIFISP_FLT_CHROMA_H_MODE(pconfig->chr_h_mode) | + CIFISP_FLT_GREEN_STAGE1(pconfig->grn_stage1), + CIF_ISP_FILT_MODE); +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_flt_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_flt_config *pconfig) +{ +} +#endif + +/*****************************************************************************/ +static void cifisp_flt_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIFISP_FLT_ENA, CIF_ISP_FILT_MODE); +} + +/*****************************************************************************/ +static void cifisp_flt_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32(CIFISP_FLT_DIS, CIF_ISP_FILT_MODE); +} + +/* Auto White Balance */ +/*****************************************************************************/ +static void cifisp_awb_gain_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_awb_gain_config *pconfig = + &isp_dev->other_cfgs.last_or_new->awb_gain_config; + + cifisp_iowrite32(CIFISP_AWB_GAIN_R_SET(pconfig->gain_green_r) | + pconfig->gain_green_b, CIF_ISP_AWB_GAIN_G); + + cifisp_iowrite32(CIFISP_AWB_GAIN_R_SET(pconfig->gain_red) | + pconfig->gain_blue, CIF_ISP_AWB_GAIN_RB); +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_awb_gain_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_awb_gain_config *pconfig) +{ + unsigned int reg = cifisp_ioread32(CIF_ISP_AWB_GAIN_G); + + pconfig->gain_green_r = CIFISP_AWB_GAIN_R_READ(reg); + pconfig->gain_green_b = CIFISP_AWB_GAIN_B_READ(reg); + reg = cifisp_ioread32(CIF_ISP_AWB_GAIN_RB); + pconfig->gain_red = CIFISP_AWB_GAIN_R_READ(reg); + pconfig->gain_blue = CIFISP_AWB_GAIN_B_READ(reg); +} +#endif + +/*****************************************************************************/ +static void cifisp_awb_meas_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_awb_meas_config *pconfig = + &isp_dev->meas_cfgs.last_or_new->awb_meas_config; + unsigned int awb_prob = 0; + + /* based on the mode,configure the awb module */ + if (pconfig->awb_mode == CIFISP_AWB_MODE_RGB) { + awb_prob = CIFISP_AWB_MODE_RGB_EN; + } else { + if (pconfig->enable_ymax_cmp) + awb_prob = CIFISP_AWB_YMAX_CMP_EN; + + /* Reference Cb and Cr */ + cifisp_iowrite32(CIFISP_AWB_REF_CR_SET(pconfig->awb_ref_cr) | + pconfig->awb_ref_cb, CIF_ISP_AWB_REF); + /* Yc Threshold */ + cifisp_iowrite32(CIFISP_AWB_MAX_Y_SET(pconfig->max_y) | + CIFISP_AWB_MIN_Y_SET(pconfig->min_y) | + CIFISP_AWB_MAX_CS_SET(pconfig->max_csum) | + pconfig->min_c, CIF_ISP_AWB_THRESH); + } + + /* Common Configuration */ + cifisp_iowrite32(awb_prob, CIF_ISP_AWB_PROP); + /* window offset */ + cifisp_iowrite32(pconfig->awb_wnd.v_offs, + CIF_ISP_AWB_WND_V_OFFS); + cifisp_iowrite32(pconfig->awb_wnd.h_offs, + CIF_ISP_AWB_WND_H_OFFS); + /* AWB window size */ + cifisp_iowrite32(pconfig->awb_wnd.v_size, CIF_ISP_AWB_WND_V_SIZE); + cifisp_iowrite32(pconfig->awb_wnd.h_size, CIF_ISP_AWB_WND_H_SIZE); + /* Number of frames */ + cifisp_iowrite32(pconfig->frames, CIF_ISP_AWB_FRAMES); +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_awb_meas_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_awb_meas_config *pconfig) +{ +} +#endif + +/*****************************************************************************/ +static void cifisp_awb_meas_en(struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_awb_meas_config *pconfig = + &isp_dev->meas_cfgs.last_or_new->awb_meas_config; + u32 reg_val = cifisp_ioread32(CIF_ISP_AWB_PROP); + + /* switch off */ + reg_val &= 0xFFFFFFFC; + + if (pconfig->awb_mode == CIFISP_AWB_MODE_RGB) + reg_val |= CIFISP_AWB_MODE_RGB_EN; + else + reg_val |= CIFISP_AWB_MODE_YCBCR_EN; + + cifisp_iowrite32(reg_val, CIF_ISP_AWB_PROP); + + isp_dev->active_meas |= CIF_ISP_AWB_DONE; + + /* Measurements require AWB block be active. */ + cifisp_iowrite32OR(CIF_ISP_CTRL_ISP_AWB_ENA, CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_awb_meas_end(struct cif_isp10_isp_dev *isp_dev) +{ + u32 reg_val = cifisp_ioread32(CIF_ISP_AWB_PROP); + + /* switch off */ + reg_val &= 0xFFFFFFFC; + + cifisp_iowrite32(reg_val, CIF_ISP_AWB_PROP); + + isp_dev->active_meas &= ~CIF_ISP_AWB_DONE; + + if (!CIFISP_MODULE_IS_EN( + isp_dev->meas_cfgs.last_or_new->module_ens, + CIFISP_MODULE_AWB)) + cifisp_iowrite32AND(~CIF_ISP_CTRL_ISP_AWB_ENA, + CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_awb_gain_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIF_ISP_CTRL_ISP_AWB_ENA, CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_awb_gain_end(const struct cif_isp10_isp_dev *isp_dev) +{ + if (!CIFISP_MODULE_IS_EN( + isp_dev->meas_cfgs.last_or_new->module_ens, + CIFISP_MODULE_AWB)) + cifisp_iowrite32AND(~CIF_ISP_CTRL_ISP_AWB_ENA, + CIF_ISP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_get_awb_meas(struct cif_isp10_isp_dev *isp_dev, + struct cifisp_stat_buffer *pbuf) +{ + /* Protect against concurrent access from ISR? */ + u32 reg_val; + const struct cifisp_awb_meas_config *pconfig = + &isp_dev->meas_cfgs.curr->awb_meas_config; + + pbuf->meas_type |= CIFISP_STAT_AWB; + reg_val = cifisp_ioread32(CIF_ISP_AWB_WHITE_CNT); + pbuf->params.awb.awb_mean[0].cnt = + CIFISP_AWB_GET_PIXEL_CNT(reg_val); + reg_val = cifisp_ioread32(CIF_ISP_AWB_MEAN); + + if (pconfig->awb_mode == CIFISP_AWB_MODE_RGB) { + pbuf->params.awb.awb_mean[0].mean_r = + CIFISP_AWB_GET_MEAN_R(reg_val); + pbuf->params.awb.awb_mean[0].mean_b = + CIFISP_AWB_GET_MEAN_B(reg_val); + pbuf->params.awb.awb_mean[0].mean_g = + CIFISP_AWB_GET_MEAN_G(reg_val); + } else { + pbuf->params.awb.awb_mean[0].mean_cr = + (u8)CIFISP_AWB_GET_MEAN_CR(reg_val); + pbuf->params.awb.awb_mean[0].mean_cb = + (u8)CIFISP_AWB_GET_MEAN_CB(reg_val); + pbuf->params.awb.awb_mean[0].mean_y = + (u8)CIFISP_AWB_GET_MEAN_Y(reg_val); + } +} + +/* Auto Exposure */ +/*****************************************************************************/ +static void cifisp_aec_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_aec_config *pconfig = + &isp_dev->meas_cfgs.last_or_new->aec_config; + unsigned int block_hsize, block_vsize; + + cifisp_iowrite32(CIFISP_EXP_CTRL_AUTOSTOP(pconfig->autostop) | + CIFISP_EXP_CTRL_MEASMODE(pconfig->mode), + CIF_ISP_EXP_CTRL); + + cifisp_iowrite32(pconfig->meas_window.h_offs, CIF_ISP_EXP_H_OFFSET); + cifisp_iowrite32(pconfig->meas_window.v_offs, CIF_ISP_EXP_V_OFFSET); + + block_hsize = pconfig->meas_window.h_size / + CIFISP_EXP_COLUMN_NUM - 1; + block_vsize = pconfig->meas_window.v_size / + CIFISP_EXP_ROW_NUM - 1; + + cifisp_iowrite32(CIFISP_EXP_HSIZE(block_hsize), CIF_ISP_EXP_H_SIZE); + cifisp_iowrite32(CIFISP_EXP_VSIZE(block_vsize), CIF_ISP_EXP_V_SIZE); +} + +/*****************************************************************************/ +static void cifisp_aec_en(struct cif_isp10_isp_dev *isp_dev) +{ + isp_dev->active_meas |= CIF_ISP_EXP_END; + + cifisp_iowrite32OR(CIFISP_EXP_ENA, CIF_ISP_EXP_CTRL); +} + +/*****************************************************************************/ +static void cifisp_aec_end(struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32(CIFISP_EXP_DIS, CIF_ISP_EXP_CTRL); + + isp_dev->active_meas &= ~CIF_ISP_EXP_END; +} + +/*****************************************************************************/ +static void cifisp_get_aec_meas(struct cif_isp10_isp_dev *isp_dev, + struct cifisp_stat_buffer *pbuf) +{ + unsigned int i; + + pbuf->meas_type |= CIFISP_STAT_AUTOEXP; /*Set the measurement type */ + for (i = 0; i < CIFISP_AE_MEAN_MAX; i++) { + pbuf->params.ae.exp_mean[i] = + (u8)cifisp_ioread32(CIF_ISP_EXP_MEAN_00 + i * 4); + } +} + +/* X-Talk Matrix */ +/*****************************************************************************/ +static void cifisp_ctk_config(const struct cif_isp10_isp_dev *isp_dev) +{ + /* Nothing to do */ +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_ctk_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_ctk_config *pconfig) +{ + pconfig->coeff0 = cifisp_ioread32(CIF_ISP_CT_COEFF_0); + pconfig->coeff1 = cifisp_ioread32(CIF_ISP_CT_COEFF_1); + pconfig->coeff2 = cifisp_ioread32(CIF_ISP_CT_COEFF_2); + pconfig->coeff3 = cifisp_ioread32(CIF_ISP_CT_COEFF_3); + pconfig->coeff4 = cifisp_ioread32(CIF_ISP_CT_COEFF_4); + pconfig->coeff5 = cifisp_ioread32(CIF_ISP_CT_COEFF_5); + pconfig->coeff6 = cifisp_ioread32(CIF_ISP_CT_COEFF_6); + pconfig->coeff7 = cifisp_ioread32(CIF_ISP_CT_COEFF_7); + pconfig->coeff8 = cifisp_ioread32(CIF_ISP_CT_COEFF_8); + pconfig->ct_offset_r = cifisp_ioread32(CIF_ISP_CT_OFFSET_R); + pconfig->ct_offset_g = cifisp_ioread32(CIF_ISP_CT_OFFSET_G); + pconfig->ct_offset_b = cifisp_ioread32(CIF_ISP_CT_OFFSET_B); +} +#endif + +/*****************************************************************************/ +static void cifisp_ctk_en(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_ctk_config *pconfig = + &isp_dev->other_cfgs.last_or_new->ctk_config; + + cifisp_iowrite32(pconfig->coeff0, CIF_ISP_CT_COEFF_0); + cifisp_iowrite32(pconfig->coeff1, CIF_ISP_CT_COEFF_1); + cifisp_iowrite32(pconfig->coeff2, CIF_ISP_CT_COEFF_2); + cifisp_iowrite32(pconfig->coeff3, CIF_ISP_CT_COEFF_3); + cifisp_iowrite32(pconfig->coeff4, CIF_ISP_CT_COEFF_4); + cifisp_iowrite32(pconfig->coeff5, CIF_ISP_CT_COEFF_5); + cifisp_iowrite32(pconfig->coeff6, CIF_ISP_CT_COEFF_6); + cifisp_iowrite32(pconfig->coeff7, CIF_ISP_CT_COEFF_7); + cifisp_iowrite32(pconfig->coeff8, CIF_ISP_CT_COEFF_8); + cifisp_iowrite32(pconfig->ct_offset_r, CIF_ISP_CT_OFFSET_R); + cifisp_iowrite32(pconfig->ct_offset_g, CIF_ISP_CT_OFFSET_G); + cifisp_iowrite32(pconfig->ct_offset_b, CIF_ISP_CT_OFFSET_B); +} + +/*****************************************************************************/ +static void cifisp_ctk_end(const struct cif_isp10_isp_dev *isp_dev) +{ + /* Write back the default values. */ + cifisp_iowrite32(0x80, CIF_ISP_CT_COEFF_0); + cifisp_iowrite32(0, CIF_ISP_CT_COEFF_1); + cifisp_iowrite32(0, CIF_ISP_CT_COEFF_2); + cifisp_iowrite32(0, CIF_ISP_CT_COEFF_3); + cifisp_iowrite32(0x80, CIF_ISP_CT_COEFF_4); + cifisp_iowrite32(0, CIF_ISP_CT_COEFF_5); + cifisp_iowrite32(0, CIF_ISP_CT_COEFF_6); + cifisp_iowrite32(0, CIF_ISP_CT_COEFF_7); + cifisp_iowrite32(0x80, CIF_ISP_CT_COEFF_8); + + cifisp_iowrite32(0, CIF_ISP_CT_OFFSET_R); + cifisp_iowrite32(0, CIF_ISP_CT_OFFSET_G); + cifisp_iowrite32(0, CIF_ISP_CT_OFFSET_B); +} + +/* CPROC */ +/*****************************************************************************/ +static void cifisp_cproc_config(const struct cif_isp10_isp_dev *isp_dev, + enum cif_isp10_pix_fmt_quantization quantization) +{ + const struct cifisp_cproc_config *pconfig = + &isp_dev->other_cfgs.last_or_new->cproc_config; + const struct cifisp_ie_config *ie_pconfig = + &isp_dev->other_cfgs.last_or_new->ie_config; + + cifisp_iowrite32(pconfig->contrast, CIF_C_PROC_CONTRAST); + cifisp_iowrite32(pconfig->hue, CIF_C_PROC_HUE); + cifisp_iowrite32(pconfig->sat, CIF_C_PROC_SATURATION); + cifisp_iowrite32(pconfig->brightness, CIF_C_PROC_BRIGHTNESS); + + if ((quantization != CIF_ISP10_QUANTIZATION_FULL_RANGE) || + (ie_pconfig->effect != V4L2_COLORFX_NONE)) { + cifisp_iowrite32( + ~(CIF_C_PROC_YOUT_FULL | + CIF_C_PROC_YIN_FULL | + CIF_C_PROC_COUT_FULL), + CIF_C_PROC_CTRL); + } else { + cifisp_iowrite32OR( + (CIF_C_PROC_YOUT_FULL | + CIF_C_PROC_YIN_FULL | + CIF_C_PROC_COUT_FULL), + CIF_C_PROC_CTRL); + } +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_cproc_config_read(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_cproc_config *pconfig) +{ + unsigned int reg; + + pconfig->contrast = cifisp_ioread32(CIF_C_PROC_CONTRAST); + pconfig->hue = cifisp_ioread32(CIF_C_PROC_HUE); + pconfig->sat = cifisp_ioread32(CIF_C_PROC_SATURATION); + pconfig->brightness = cifisp_ioread32(CIF_C_PROC_BRIGHTNESS); + reg = cifisp_ioread32(CIF_C_PROC_CTRL); + pconfig->y_out_range = (reg >> 1) & 1; + pconfig->y_in_range = (reg >> 2) & 1; + pconfig->c_out_range = (reg >> 3) & 1; +} +#endif + +/*****************************************************************************/ +static void cifisp_cproc_en(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIFISP_CPROC_EN, CIF_C_PROC_CTRL); +} + +/*****************************************************************************/ +static void cifisp_cproc_end(const struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32AND(~CIFISP_CPROC_EN, CIF_C_PROC_CTRL); +} + +static void cifisp_afc_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_afc_config *pconfig = + &isp_dev->meas_cfgs.last_or_new->afc_config; + int num_of_win = pconfig->num_afm_win, i; + + /* Switch off to configure. Enabled during normal flow in frame isr. */ + cifisp_iowrite32(0, CIF_ISP_AFM_CTRL); + + for (i = 0; i < num_of_win; i++) { + cifisp_iowrite32( + CIFISP_AFC_WINDOW_X(pconfig->afm_win[0].h_offs) | + CIFISP_AFC_WINDOW_Y(pconfig->afm_win[0].v_offs), + CIF_ISP_AFM_LT_A + i * 8); + cifisp_iowrite32( + CIFISP_AFC_WINDOW_X(pconfig->afm_win[0].h_size + + pconfig->afm_win[0].h_offs) | + CIFISP_AFC_WINDOW_Y(pconfig->afm_win[0].v_size + + pconfig->afm_win[0].v_offs), + CIF_ISP_AFM_RB_A + i * 8); + } + + cifisp_iowrite32(pconfig->thres, CIF_ISP_AFM_THRES); + cifisp_iowrite32(pconfig->var_shift, CIF_ISP_AFM_VAR_SHIFT); +} + +/*****************************************************************************/ +static void cifisp_afc_en(struct cif_isp10_isp_dev *isp_dev) +{ + isp_dev->active_meas |= CIF_ISP_AFM_FIN; + + cifisp_iowrite32(CIFISP_AFC_ENA, CIF_ISP_AFM_CTRL); +} + +/*****************************************************************************/ +static void cifisp_afc_end(struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32(CIFISP_AFC_DIS, CIF_ISP_AFM_CTRL); + isp_dev->active_meas &= ~CIF_ISP_AFM_FIN; +} + +/*****************************************************************************/ +static void cifisp_get_afc_meas(struct cif_isp10_isp_dev *isp_dev, + struct cifisp_stat_buffer *pbuf) +{ + pbuf->meas_type = CIFISP_STAT_AFM_FIN; + + pbuf->params.af.window[0].sum = + cifisp_ioread32(CIF_ISP_AFM_SUM_A); + pbuf->params.af.window[0].lum = + cifisp_ioread32(CIF_ISP_AFM_LUM_A); + pbuf->params.af.window[1].sum = + cifisp_ioread32(CIF_ISP_AFM_SUM_B); + pbuf->params.af.window[1].lum = + cifisp_ioread32(CIF_ISP_AFM_LUM_B); + pbuf->params.af.window[2].sum = + cifisp_ioread32(CIF_ISP_AFM_SUM_C); + pbuf->params.af.window[2].lum = + cifisp_ioread32(CIF_ISP_AFM_LUM_C); +} + +/* HISTOGRAM CALCULATION */ +/*****************************************************************************/ +static void cifisp_hst_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_hst_config *pconfig = + &isp_dev->meas_cfgs.last_or_new->hst_config; + unsigned int block_hsize, block_vsize; + + cifisp_iowrite32(CIFISP_HIST_PREDIV_SET(pconfig->histogram_predivider), + CIF_ISP_HIST_PROP); + cifisp_iowrite32(pconfig->meas_window.h_offs, CIF_ISP_HIST_H_OFFS); + cifisp_iowrite32(pconfig->meas_window.v_offs, CIF_ISP_HIST_V_OFFS); + + block_hsize = pconfig->meas_window.h_size / + CIFISP_HIST_COLUMN_NUM - 1; + block_vsize = pconfig->meas_window.v_size / + CIFISP_HIST_ROW_NUM - 1; + + cifisp_iowrite32(block_hsize, CIF_ISP_HIST_H_SIZE); + cifisp_iowrite32(block_vsize, CIF_ISP_HIST_V_SIZE); + + cifisp_iowrite32(CIFISP_HIST_WEIGHT_SET(pconfig->hist_weight[0], + pconfig->hist_weight[1], pconfig->hist_weight[2], + pconfig->hist_weight[3]), CIF_ISP_HIST_WEIGHT_00TO30); + cifisp_iowrite32(CIFISP_HIST_WEIGHT_SET(pconfig->hist_weight[4], + pconfig->hist_weight[5], pconfig->hist_weight[6], + pconfig->hist_weight[7]), CIF_ISP_HIST_WEIGHT_40TO21); + cifisp_iowrite32(CIFISP_HIST_WEIGHT_SET(pconfig->hist_weight[8], + pconfig->hist_weight[9], pconfig->hist_weight[10], + pconfig->hist_weight[11]), CIF_ISP_HIST_WEIGHT_31TO12); + cifisp_iowrite32(CIFISP_HIST_WEIGHT_SET(pconfig->hist_weight[12], + pconfig->hist_weight[13], pconfig->hist_weight[14], + pconfig->hist_weight[15]), CIF_ISP_HIST_WEIGHT_22TO03); + cifisp_iowrite32(CIFISP_HIST_WEIGHT_SET(pconfig->hist_weight[16], + pconfig->hist_weight[17], pconfig->hist_weight[18], + pconfig->hist_weight[19]), CIF_ISP_HIST_WEIGHT_13TO43); + cifisp_iowrite32(CIFISP_HIST_WEIGHT_SET(pconfig->hist_weight[20], + pconfig->hist_weight[21], pconfig->hist_weight[22], + pconfig->hist_weight[23]), CIF_ISP_HIST_WEIGHT_04TO34); + cifisp_iowrite32(CIFISP_HIST_WEIGHT_SET(pconfig->hist_weight[24], + 0, 0, 0), CIF_ISP_HIST_WEIGHT_44); +} + +static void cifisp_hst_en(struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_hst_config *pconfig = + &isp_dev->meas_cfgs.last_or_new->hst_config; + + isp_dev->active_meas |= CIF_ISP_HIST_MEASURE_RDY; + + cifisp_iowrite32OR(pconfig->mode, + CIF_ISP_HIST_PROP); +} + +/*****************************************************************************/ +static void cifisp_hst_end(struct cif_isp10_isp_dev *isp_dev) +{ + /* Disable measurement */ + cifisp_iowrite32(CIFISP_HISTOGRAM_MODE_DISABLE, + CIF_ISP_HIST_PROP); + + isp_dev->active_meas &= ~CIF_ISP_HIST_MEASURE_RDY; +} + +/*****************************************************************************/ +static void cifisp_get_hst_meas(const struct cif_isp10_isp_dev *isp_dev, + struct cifisp_stat_buffer *pbuf) +{ + int i; + + pbuf->meas_type |= CIFISP_STAT_HIST; + for (i = 0; i < CIFISP_HIST_BIN_N_MAX; i++) { + pbuf->params.hist.hist_bins[i] = + cifisp_ioread32(CIF_ISP_HIST_BIN_0 + (i * 4)); + } +} + +/* IMAGE EFFECT */ +/*****************************************************************************/ +static void cifisp_ie_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_ie_config *pconfig = + &isp_dev->other_cfgs.last_or_new->ie_config; + + switch (pconfig->effect) { + case V4L2_COLORFX_SET_CBCR: + cifisp_iowrite32(pconfig->eff_tint, CIF_IMG_EFF_TINT); + break; + /* + * Color selection is similar to water color(AQUA): + * grayscale + selected color w threshold + */ + case V4L2_COLORFX_AQUA: + cifisp_iowrite32(pconfig->color_sel, CIF_IMG_EFF_COLOR_SEL); + break; + case V4L2_COLORFX_EMBOSS: + cifisp_iowrite32(pconfig->eff_mat_1, CIF_IMG_EFF_MAT_1); + cifisp_iowrite32(pconfig->eff_mat_2, CIF_IMG_EFF_MAT_2); + cifisp_iowrite32(pconfig->eff_mat_3, CIF_IMG_EFF_MAT_3); + break; + case V4L2_COLORFX_SKETCH: + cifisp_iowrite32(pconfig->eff_mat_3, CIF_IMG_EFF_MAT_3); + cifisp_iowrite32(pconfig->eff_mat_4, CIF_IMG_EFF_MAT_4); + cifisp_iowrite32(pconfig->eff_mat_5, CIF_IMG_EFF_MAT_5); + break; + default: + break; + } +} + +static void cifisp_ie_en(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_ie_config *pconfig = + &isp_dev->other_cfgs.last_or_new->ie_config; + enum cif_isp10_image_effect effect; + + switch (pconfig->effect) { + case V4L2_COLORFX_SEPIA: + case V4L2_COLORFX_SET_CBCR: + effect = CIF_ISP10_IE_SEPIA; + break; + case V4L2_COLORFX_BW: + effect = CIF_ISP10_IE_BW; + break; + case V4L2_COLORFX_NEGATIVE: + effect = CIF_ISP10_IE_NEGATIVE; + break; + case V4L2_COLORFX_EMBOSS: + effect = CIF_ISP10_IE_EMBOSS; + break; + case V4L2_COLORFX_SKETCH: + effect = CIF_ISP10_IE_SKETCH; + break; + case V4L2_COLORFX_AQUA: + effect = CIF_ISP10_IE_C_SEL; + break; + case V4L2_COLORFX_NONE: + default: + effect = CIF_ISP10_IE_NONE; + break; + } + + if (effect < CIF_ISP10_IE_NONE) { + cifisp_iowrite32OR(CIF_ICCL_IE_CLK, CIF_ICCL); + cifisp_iowrite32(CIF_IMG_EFF_CTRL_ENABLE | + effect << 1, CIF_IMG_EFF_CTRL); + cifisp_iowrite32OR(CIF_IMG_EFF_CTRL_CFG_UPD, CIF_IMG_EFF_CTRL); + } else if (effect == CIF_ISP10_IE_NONE) { + cifisp_iowrite32AND(~CIF_IMG_EFF_CTRL_ENABLE, CIF_IMG_EFF_CTRL); + cifisp_iowrite32AND(~CIF_ICCL_IE_CLK, CIF_ICCL); + } +} + +static void cifisp_ie_end(const struct cif_isp10_isp_dev *isp_dev) +{ + /* Disable measurement */ + cifisp_iowrite32AND(~CIF_IMG_EFF_CTRL_ENABLE, CIF_IMG_EFF_CTRL); + cifisp_iowrite32AND(~CIF_ICCL_IE_CLK, CIF_ICCL); +} + +static void cifisp_csm_config(const struct cif_isp10_isp_dev *isp_dev, + enum cif_isp10_pix_fmt_quantization quantization) +{ + const struct cifisp_ie_config *pconfig = + &isp_dev->other_cfgs.last_or_new->ie_config; + + if ((quantization != CIF_ISP10_QUANTIZATION_FULL_RANGE) || + ((pconfig->effect != V4L2_COLORFX_NONE) && + CIFISP_MODULE_IS_EN( + isp_dev->other_cfgs.last_or_new->module_ens, + CIFISP_MODULE_CPROC))) { + /* Limit range conversion */ + cifisp_iowrite32(0x21, CIF_ISP_CC_COEFF_0); + cifisp_iowrite32(0x40, CIF_ISP_CC_COEFF_1); + cifisp_iowrite32(0xd, CIF_ISP_CC_COEFF_2); + cifisp_iowrite32(0x1ed, CIF_ISP_CC_COEFF_3); + cifisp_iowrite32(0x1db, CIF_ISP_CC_COEFF_4); + cifisp_iowrite32(0x38, CIF_ISP_CC_COEFF_5); + cifisp_iowrite32(0x38, CIF_ISP_CC_COEFF_6); + cifisp_iowrite32(0x1d1, CIF_ISP_CC_COEFF_7); + cifisp_iowrite32(0x1f7, CIF_ISP_CC_COEFF_8); + cifisp_iowrite32AND(~CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA, + CIF_ISP_CTRL); + cifisp_iowrite32AND(~CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA, + CIF_ISP_CTRL); + } else { + cifisp_iowrite32(0x26, CIF_ISP_CC_COEFF_0); + cifisp_iowrite32(0x4b, CIF_ISP_CC_COEFF_1); + cifisp_iowrite32(0xf, CIF_ISP_CC_COEFF_2); + cifisp_iowrite32(0x1ea, CIF_ISP_CC_COEFF_3); + cifisp_iowrite32(0x1d6, CIF_ISP_CC_COEFF_4); + cifisp_iowrite32(0x40, CIF_ISP_CC_COEFF_5); + cifisp_iowrite32(0x40, CIF_ISP_CC_COEFF_6); + cifisp_iowrite32(0x1ca, CIF_ISP_CC_COEFF_7); + cifisp_iowrite32(0x1f6, CIF_ISP_CC_COEFF_8); + cifisp_iowrite32OR(CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA, + CIF_ISP_CTRL); + cifisp_iowrite32OR(CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA, + CIF_ISP_CTRL); + } +} + +/* DPF */ +/*****************************************************************************/ +static void cifisp_dpf_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_dpf_config *pconfig = + &isp_dev->other_cfgs.last_or_new->dpf_config; + unsigned int isp_dpf_mode; + unsigned int i; + unsigned int spatial_coeff; + + isp_dpf_mode = 0x00; + + switch (pconfig->gain.mode) { + case CIFISP_DPF_GAIN_USAGE_DISABLED: + break; + case CIFISP_DPF_GAIN_USAGE_NF_GAINS: + isp_dpf_mode |= CIFISP_DPF_MODE_USE_NF_GAIN | + CIFISP_DPF_MODE_AWB_GAIN_COMP; + break; + case CIFISP_DPF_GAIN_USAGE_LSC_GAINS: + isp_dpf_mode |= CIFISP_DPF_MODE_LSC_GAIN_COMP; + break; + case CIFISP_DPF_GAIN_USAGE_NF_LSC_GAINS: + isp_dpf_mode |= CIFISP_DPF_MODE_USE_NF_GAIN | + CIFISP_DPF_MODE_AWB_GAIN_COMP | + CIFISP_DPF_MODE_LSC_GAIN_COMP; + break; + case CIFISP_DPF_GAIN_USAGE_AWB_GAINS: + isp_dpf_mode |= CIFISP_DPF_MODE_AWB_GAIN_COMP; + break; + case CIFISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: + isp_dpf_mode |= CIFISP_DPF_MODE_LSC_GAIN_COMP | + CIFISP_DPF_MODE_AWB_GAIN_COMP; + break; + default: + break; + } + + isp_dpf_mode |= + CIFISP_DPF_MODE_NLL_SEGMENTATION(pconfig->nll.scale_mode); + isp_dpf_mode |= + CIFISP_DPF_MODE_RB_FLTSIZE(pconfig->rb_flt.fltsize); + + isp_dpf_mode |= (pconfig->rb_flt.r_enable) ? + CIFISP_DPF_MODE_R_FLT_EN : CIFISP_DPF_MODE_R_FLT_DIS; + isp_dpf_mode |= (pconfig->rb_flt.b_enable) ? + CIFISP_DPF_MODE_B_FLT_EN : CIFISP_DPF_MODE_B_FLT_DIS; + isp_dpf_mode |= (pconfig->g_flt.gb_enable) ? + CIFISP_DPF_MODE_GB_FLT_EN : CIFISP_DPF_MODE_GB_FLT_DIS; + isp_dpf_mode |= (pconfig->g_flt.gr_enable) ? + CIFISP_DPF_MODE_GR_FLT_EN : CIFISP_DPF_MODE_GR_FLT_DIS; + + cifisp_iowrite32(isp_dpf_mode, CIF_ISP_DPF_MODE); + cifisp_iowrite32(pconfig->gain.nf_b_gain, CIF_ISP_DPF_NF_GAIN_B); + cifisp_iowrite32(pconfig->gain.nf_r_gain, CIF_ISP_DPF_NF_GAIN_R); + cifisp_iowrite32(pconfig->gain.nf_gb_gain, CIF_ISP_DPF_NF_GAIN_GB); + cifisp_iowrite32(pconfig->gain.nf_gr_gain, CIF_ISP_DPF_NF_GAIN_GR); + + for (i = 0; i < CIFISP_DPF_MAX_NLF_COEFFS; i++) { + cifisp_iowrite32(pconfig->nll.coeff[i], + CIF_ISP_DPF_NULL_COEFF_0 + i * 4); + } + + spatial_coeff = pconfig->g_flt.spatial_coeff[0] | + ((unsigned int)pconfig->g_flt.spatial_coeff[1] << 8) | + ((unsigned int)pconfig->g_flt.spatial_coeff[2] << 16) | + ((unsigned int)pconfig->g_flt.spatial_coeff[3] << 24); + cifisp_iowrite32(spatial_coeff, CIF_ISP_DPF_S_WEIGHT_G_1_4); + spatial_coeff = pconfig->g_flt.spatial_coeff[4] | + ((unsigned int)pconfig->g_flt.spatial_coeff[5] << 8); + cifisp_iowrite32(spatial_coeff, CIF_ISP_DPF_S_WEIGHT_G_5_6); + spatial_coeff = pconfig->rb_flt.spatial_coeff[0] | + ((unsigned int)pconfig->rb_flt.spatial_coeff[1] << 8) | + ((unsigned int)pconfig->rb_flt.spatial_coeff[2] << 16) | + ((unsigned int)pconfig->rb_flt.spatial_coeff[3] << 24); + cifisp_iowrite32(spatial_coeff, CIF_ISP_DPF_S_WEIGHT_RB_1_4); + spatial_coeff = pconfig->rb_flt.spatial_coeff[4] | + ((unsigned int)pconfig->rb_flt.spatial_coeff[5] << 8); + cifisp_iowrite32(spatial_coeff, CIF_ISP_DPF_S_WEIGHT_RB_5_6); +} + +static void cifisp_dpf_strength_config(const struct cif_isp10_isp_dev *isp_dev) +{ + const struct cifisp_dpf_strength_config *pconfig = + &isp_dev->other_cfgs.last_or_new->dpf_strength_config; + + cifisp_iowrite32(pconfig->b, CIF_ISP_DPF_STRENGTH_B); + cifisp_iowrite32(pconfig->g, CIF_ISP_DPF_STRENGTH_G); + cifisp_iowrite32(pconfig->r, CIF_ISP_DPF_STRENGTH_R); +} + +static void cifisp_dpf_en(struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32OR(CIFISP_DPF_MODE_EN, + CIF_ISP_DPF_MODE); +} + +static void cifisp_dpf_end(struct cif_isp10_isp_dev *isp_dev) +{ + cifisp_iowrite32AND(~CIFISP_DPF_MODE_EN, + CIF_ISP_DPF_MODE); +} + +/* ================================QUEUE OPS ================== */ +static int cifisp_stat_vbq_setup(struct videobuf_queue *vq, + unsigned int *cnt, unsigned int *size) +{ + *size = sizeof(struct cifisp_stat_buffer); + + return 0; +} + +static void cifisp_stat_vbq_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + CIFISP_DPRINT(CIFISP_DEBUG, "Releasing buffer entry!\n"); + + videobuf_waiton(vq, vb, 0, 0); + + videobuf_vmalloc_free(vb); + + CIFISP_DPRINT(CIFISP_DEBUG, "Releasing buffer exit!\n"); +} + +static int cifisp_stat_vbq_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + int err = 0; + + vb->size = sizeof(struct cifisp_stat_buffer); + vb->width = 0; + vb->height = 0; + vb->field = field; + + if (vb->state == VIDEOBUF_NEEDS_INIT) + err = videobuf_iolock(vq, vb, NULL); + + if (!err) + vb->state = VIDEOBUF_PREPARED; + else + cifisp_stat_vbq_release(vq, vb); + + return err; +} + +static void cifisp_stat_vbq_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct cif_isp10_isp_dev *isp_dev = vq->priv_data; + + vb->state = VIDEOBUF_QUEUED; + + CIFISP_DPRINT(CIFISP_DEBUG, "Queueing stat buffer!\n"); + + list_add_tail(&vb->queue, &isp_dev->stat); +} + +/* Queue Ops */ +static struct videobuf_queue_ops cifisp_stat_qops = { + .buf_setup = cifisp_stat_vbq_setup, + .buf_prepare = cifisp_stat_vbq_prepare, + .buf_queue = cifisp_stat_vbq_queue, + .buf_release = cifisp_stat_vbq_release, +}; + +/* ================== IOCTL implementation ========================= */ +static int cifisp_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + CIFISP_DPRINT(CIFISP_DEBUG, + " %s: %s: p->type %d p->count %d\n", + ISP_VDEV_NAME, __func__, p->type, p->count); + + return videobuf_reqbufs(&isp_dev->vbq_stat, p); +} + +static int cifisp_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + CIFISP_DPRINT(CIFISP_DEBUG, + " %s: %s: p->type %d p->index %d\n", + ISP_VDEV_NAME, __func__, p->type, p->index); + + return videobuf_querybuf(&isp_dev->vbq_stat, p); +} + +static int cifisp_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + CIFISP_DPRINT(CIFISP_DEBUG, + " %s: %s: p->type %d p->index %d\n", + ISP_VDEV_NAME, __func__, p->type, p->index); + + return videobuf_qbuf(&isp_dev->vbq_stat, p); +} + +/* ========================================================== */ + +static int cifisp_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + CIFISP_DPRINT(CIFISP_DEBUG, + " %s: %s: p->type %d p->index %d\n", + ISP_VDEV_NAME, __func__, p->type, p->index); + + return videobuf_dqbuf(&isp_dev->vbq_stat, p, + file->f_flags & O_NONBLOCK); +} + +static int cifisp_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + int ret = videobuf_streamon(&isp_dev->vbq_stat); + + if (ret == 0) + isp_dev->streamon = true; + + CIFISP_DPRINT(CIFISP_DEBUG, + " %s: %s: ret %d\n", ISP_VDEV_NAME, __func__, ret); + + return ret; +} + +/* ========================================================== */ +static int cifisp_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + int ret; + + drain_workqueue(isp_dev->readout_wq); + + ret = videobuf_streamoff(&isp_dev->vbq_stat); + + if (ret == 0) + isp_dev->streamon = false; + + CIFISP_DPRINT(CIFISP_DEBUG, + " %s: %s: ret %d\n", ISP_VDEV_NAME, __func__, ret); + + return ret; +} + +static int cifisp_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc) +{ + int ret; + + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + switch (vc->id) { + case V4L2_CID_CIFISP_DPCC: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_DPCC); + break; + case V4L2_CID_CIFISP_BLS: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_BLS); + break; + case V4L2_CID_CIFISP_SDG: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_SDG); + break; + case V4L2_CID_CIFISP_LSC: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_LSC); + break; + case V4L2_CID_CIFISP_AWB_MEAS: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_AWB); + break; + case V4L2_CID_CIFISP_AWB_GAIN: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_AWB_GAIN); + break; + case V4L2_CID_CIFISP_FLT: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_FLT); + break; + case V4L2_CID_CIFISP_BDM: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_BDM); + break; + case V4L2_CID_CIFISP_CTK: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_CTK); + break; + case V4L2_CID_CIFISP_GOC: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_GOC); + break; + case V4L2_CID_CIFISP_HST: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_HST); + break; + case V4L2_CID_CIFISP_AEC: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_AEC); + break; + case V4L2_CID_CIFISP_CPROC: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_CPROC); + break; + case V4L2_CID_CIFISP_AFC: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_AFC); + break; + case V4L2_CID_CIFISP_IE: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_IE); + break; + case V4L2_CID_CIFISP_DPF: + ret = cifisp_module_enable( + isp_dev, + _GET_, + &vc->value, + CIFISP_MODULE_DPF); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int cifisp_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + int ret; + + switch (vc->id) { + case V4L2_CID_CIFISP_DPCC: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_DPCC); + break; + case V4L2_CID_CIFISP_BLS: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_BLS); + break; + case V4L2_CID_CIFISP_SDG: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_SDG); + break; + case V4L2_CID_CIFISP_LSC: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_LSC); + break; + case V4L2_CID_CIFISP_AWB_MEAS: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_AWB); + break; + case V4L2_CID_CIFISP_AWB_GAIN: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_AWB_GAIN); + break; + case V4L2_CID_CIFISP_FLT: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_FLT); + break; + case V4L2_CID_CIFISP_BDM: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_BDM); + break; + case V4L2_CID_CIFISP_CTK: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_CTK); + break; + case V4L2_CID_CIFISP_GOC: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_GOC); + break; + case V4L2_CID_CIFISP_HST: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_HST); + break; + case V4L2_CID_CIFISP_AEC: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_AEC); + break; + case V4L2_CID_CIFISP_CPROC: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_CPROC); + break; + case V4L2_CID_CIFISP_AFC: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_AFC); + break; + case V4L2_CID_CIFISP_IE: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_IE); + break; + case V4L2_CID_CIFISP_DPF: + ret = cifisp_module_enable( + isp_dev, + _SET_, + &vc->value, + CIFISP_MODULE_DPF); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static long cifisp_ioctl_default(struct file *file, + void *fh, bool valid_prio, unsigned int cmd, void *arg) +{ + struct cif_isp10_isp_dev *isp = video_get_drvdata(video_devdata(file)); + long ret; + + switch (cmd) { + case CIFISP_IOC_G_DPCC: + ret = cifisp_dpcc_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_DPCC: + ret = cifisp_dpcc_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_BLS: + ret = cifisp_bls_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_BLS: + ret = cifisp_bls_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_SDG: + ret = cifisp_sdg_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_SDG: + ret = cifisp_sdg_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_LSC: + ret = cifisp_lsc_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_LSC: + ret = cifisp_lsc_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_AWB_MEAS: + ret = cifisp_awb_meas_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_AWB_MEAS: + ret = cifisp_awb_meas_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_AWB_GAIN: + ret = cifisp_awb_gain_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_AWB_GAIN: + ret = cifisp_awb_gain_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_FLT: + ret = cifisp_flt_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_FLT: + ret = cifisp_flt_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_BDM: + ret = cifisp_bdm_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_BDM: + ret = cifisp_bdm_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_CTK: + ret = cifisp_ctk_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_CTK: + ret = cifisp_ctk_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_GOC: + ret = cifisp_goc_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_GOC: + ret = cifisp_goc_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_HST: + ret = cifisp_hst_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_HST: + ret = cifisp_hst_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_AEC: + ret = cifisp_aec_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_AEC: + ret = cifisp_aec_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_CPROC: + ret = cifisp_cproc_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_CPROC: + ret = cifisp_cproc_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_AFC: + ret = cifisp_afc_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_AFC: + ret = cifisp_afc_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_IE: + ret = cifisp_ie_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_IE: + ret = cifisp_ie_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_DPF: + ret = cifisp_dpf_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_DPF: + ret = cifisp_dpf_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_DPF_STRENGTH: + ret = cifisp_dpf_strength_param(isp, _GET_, arg); + break; + case CIFISP_IOC_S_DPF_STRENGTH: + ret = cifisp_dpf_strength_param(isp, _SET_, arg); + break; + case CIFISP_IOC_G_LAST_CONFIG: + ret = cifisp_last_capture_config(arg); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int cifisp_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + /* + * Dummy function needed to allow allocation of + * buffers on this device + */ + return 0; +} + +static int cifisp_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + struct cif_isp10_isp_dev *isp_dev = video_get_drvdata(vdev); + + strcpy(cap->driver, DRIVER_NAME); + strlcpy(cap->card, vdev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:" DRIVER_NAME "-%03i", + *isp_dev->dev_id); + + cap->capabilities = V4L2_CAP_DEVICE_CAPS; + cap->device_caps = V4L2_CAP_DEVICE_CAPS; + return 0; +} + +/* ISP video device IOCTLs */ +static const struct v4l2_ioctl_ops cifisp_ioctl = { + .vidioc_reqbufs = cifisp_reqbufs, + .vidioc_querybuf = cifisp_querybuf, + .vidioc_qbuf = cifisp_qbuf, + .vidioc_dqbuf = cifisp_dqbuf, + .vidioc_streamon = cifisp_streamon, + .vidioc_streamoff = cifisp_streamoff, + .vidioc_g_ctrl = cifisp_g_ctrl, + .vidioc_s_ctrl = cifisp_s_ctrl, + .vidioc_default = cifisp_ioctl_default, + .vidioc_g_fmt_vid_cap = cifisp_g_fmt_vid_cap, + .vidioc_querycap = cifisp_querycap +}; + +/* ======================================================== */ + +static unsigned int cifisp_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + unsigned int ret; + + ret = videobuf_poll_stream(file, &isp_dev->vbq_stat, wait); + + CIFISP_DPRINT(CIFISP_DEBUG, + "Polling on vbq_stat buffer %d\n", ret); + + return ret; +} + +/* ======================================================== */ +static int cifisp_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + return videobuf_mmap_mapper(&isp_dev->vbq_stat, vma); +} + +/* ddl@rock-chips.com: v1.0.8 */ +static int cifisp_reset(struct file *file) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + memset(isp_dev->other_cfgs.cfgs, 0, sizeof(isp_dev->other_cfgs.cfgs)); + memset(isp_dev->meas_cfgs.cfgs, 0, sizeof(isp_dev->meas_cfgs.cfgs)); + + isp_dev->other_cfgs.last_or_new = &isp_dev->other_cfgs.cfgs[0]; + isp_dev->other_cfgs.curr = &isp_dev->other_cfgs.cfgs[1]; + isp_dev->other_cfgs.module_updates = 0; + + isp_dev->meas_cfgs.last_or_new = &isp_dev->meas_cfgs.cfgs[0]; + isp_dev->meas_cfgs.curr = &isp_dev->meas_cfgs.cfgs[1]; + isp_dev->meas_cfgs.module_updates = 0; + isp_dev->active_lsc_width = 0; + isp_dev->active_lsc_height = 0; + + isp_dev->streamon = false; + isp_dev->active_meas = 0; + isp_dev->frame_id = 0; + isp_dev->cif_ism_cropping = false; + return 0; +} + +static int cifisp_open(struct file *file) +{ + CIFISP_DPRINT(CIFISP_DEBUG, "cifisp_open\n"); + + cifisp_reset(file); + + return 0; +} + +static int cifisp_close(struct file *file) +{ + struct cif_isp10_isp_dev *isp_dev = + video_get_drvdata(video_devdata(file)); + + CIFISP_DPRINT(CIFISP_DEBUG, "cifisp_close\n"); + + videobuf_stop(&isp_dev->vbq_stat); + videobuf_mmap_free(&isp_dev->vbq_stat); + + /* cifisp_reset(file); */ + return 0; +} + +struct v4l2_file_operations cifisp_fops = { + .mmap = cifisp_mmap, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif + .poll = cifisp_poll, + .open = cifisp_open, + .release = cifisp_close +}; + +static void cifisp_release(struct video_device *vdev) +{ + struct cif_isp10_isp_dev *isp_dev = video_get_drvdata(vdev); + + CIFISP_DPRINT(CIFISP_DEBUG, "cifisp_release\n"); + video_device_release(vdev); + destroy_workqueue(isp_dev->readout_wq); +} + +/************************************************************/ +int register_cifisp_device(struct cif_isp10_isp_dev *isp_dev, + struct video_device *vdev_cifisp, + struct v4l2_device *v4l2_dev, + void __iomem *cif_reg_baseaddress) +{ + isp_dev->base_addr = cif_reg_baseaddress; + WARN_ON(!(isp_dev->base_addr)); + + INIT_LIST_HEAD(&isp_dev->stat); + spin_lock_init(&isp_dev->irq_lock); + spin_lock_init(&isp_dev->config_lock); + strlcpy(vdev_cifisp->name, ISP_VDEV_NAME, sizeof(vdev_cifisp->name)); + vdev_cifisp->vfl_type = V4L2_CAP_VIDEO_CAPTURE; + video_set_drvdata(vdev_cifisp, isp_dev); + vdev_cifisp->ioctl_ops = &cifisp_ioctl; + vdev_cifisp->fops = &cifisp_fops; + + /* + * This might not release all resources, + * but unregistering is anyway not going to happen. + */ + vdev_cifisp->release = cifisp_release; + mutex_init(&isp_dev->mutex); + /* + * Provide a mutex to v4l2 core. It will be used + * to protect all fops and v4l2 ioctls. + */ + vdev_cifisp->lock = &isp_dev->mutex; + vdev_cifisp->v4l2_dev = v4l2_dev; + + videobuf_queue_vmalloc_init( + &isp_dev->vbq_stat, + &cifisp_stat_qops, + NULL, + &isp_dev->irq_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, + sizeof(struct videobuf_buffer), + isp_dev, + NULL); /* ext_lock: NULL */ + + if (video_register_device(vdev_cifisp, VFL_TYPE_GRABBER, -1) < 0) { + dev_err(&vdev_cifisp->dev, + "could not register Video for Linux device\n"); + return -ENODEV; + } + + CIFISP_DPRINT(CIFISP_DEBUG, + "%s: CIFISP vdev minor = %d\n", + __func__, vdev_cifisp->minor); + + isp_dev->readout_wq = + alloc_workqueue("measurement_queue", + WQ_UNBOUND | WQ_MEM_RECLAIM, 1); + + if (!isp_dev->readout_wq) + return -ENOMEM; + + isp_dev->v_blanking_us = CIFISP_MODULE_DEFAULT_VBLANKING_TIME; + + return 0; +} + +void unregister_cifisp_device(struct video_device *vdev_cifisp) +{ + if (!IS_ERR_OR_NULL(vdev_cifisp)) + video_unregister_device(vdev_cifisp); +} + +static void cifisp_dump_reg(struct cif_isp10_isp_dev *isp_dev, int level) +{ +#ifdef CIFISP_DEBUG_REG + if (isp_dev->dpcc_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_DPCC, level); + + if (isp_dev->lsc_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_LSC, level); + + if (isp_dev->bls_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_BLS, level); + + if (isp_dev->sdg_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_SDG, level); + + if (isp_dev->goc_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_GOC, level); + + if (isp_dev->bdm_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_BDM, level); + + if (isp_dev->flt_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_FLT, level); + + if (isp_dev->awb_meas_en || isp_dev->awb_gain_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_AWB, level); + + if (isp_dev->aec_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_AEC, level); + + if (isp_dev->ctk_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_CTK, level); + + if (isp_dev->cproc_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_CPROC, level); + + if (isp_dev->afc_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_AFC, level); + + if (isp_dev->hst_en) + cifisp_reg_dump(isp_dev, CIFISP_MODULE_HST, level); +#endif +} + +static inline void cifisp_meas_config_swap( + struct cif_isp10_isp_dev *isp_dev) +{ + struct cifisp_isp_meas_cfg *new_cfg; + + new_cfg = isp_dev->meas_cfgs.last_or_new; + new_cfg->s_frame_id = isp_dev->frame_id; + isp_dev->meas_cfgs.last_or_new = + isp_dev->meas_cfgs.curr; + isp_dev->meas_cfgs.curr = new_cfg; +} + +static inline void cifisp_other_config_swap( + struct cif_isp10_isp_dev *isp_dev) +{ + struct cifisp_isp_other_cfg *new_cfg; + + new_cfg = isp_dev->other_cfgs.last_or_new; + new_cfg->s_frame_id = isp_dev->frame_id; + isp_dev->other_cfgs.last_or_new = + isp_dev->other_cfgs.curr; + isp_dev->other_cfgs.curr = new_cfg; +} + +/* Not called when the camera active, thus not isr protection. */ +void cifisp_configure_isp( + struct cif_isp10_isp_dev *isp_dev, + enum cif_isp10_pix_fmt in_pix_fmt, + enum cif_isp10_pix_fmt_quantization quantization) +{ + unsigned int *other_ens, *other_updates; + unsigned int *meas_ens, *meas_updates; + + CIFISP_DPRINT(CIFISP_DEBUG, "%s\n", __func__); + + mutex_lock(&isp_dev->mutex); + spin_lock(&isp_dev->config_lock); + + other_ens = &isp_dev->other_cfgs.last_or_new->module_ens; + other_updates = &isp_dev->other_cfgs.module_updates; + meas_ens = &isp_dev->meas_cfgs.last_or_new->module_ens; + meas_updates = &isp_dev->meas_cfgs.module_updates; + isp_dev->quantization = quantization; + if (CIF_ISP10_PIX_FMT_IS_RAW_BAYER(in_pix_fmt)) { + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_DPCC)) { + cifisp_dpcc_config(isp_dev); + cifisp_dpcc_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_DPCC); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_LSC)) { + if (cifisp_lsc_config(isp_dev)) + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_LSC); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_BLS)) { + cifisp_bls_config(isp_dev); + cifisp_bls_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_BLS); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_SDG)) { + cifisp_sdg_config(isp_dev); + cifisp_sdg_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_SDG); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_GOC)) { + cifisp_goc_config(isp_dev); + cifisp_goc_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_GOC); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_BDM)) { + cifisp_bdm_config(isp_dev); + cifisp_bdm_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_BDM); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_FLT)) { + cifisp_flt_config(isp_dev); + cifisp_flt_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_FLT); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_AWB_GAIN)) { + cifisp_awb_gain_config(isp_dev); + cifisp_awb_gain_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_AWB_GAIN); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_CTK)) { + cifisp_ctk_config(isp_dev); + cifisp_ctk_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_CTK); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_CPROC)) { + cifisp_cproc_config(isp_dev, quantization); + cifisp_cproc_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_CPROC); + } + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_IE)) { + cifisp_ie_config(isp_dev); + cifisp_ie_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_IE); + } + + cifisp_csm_config(isp_dev, quantization); + + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_DPF)) { + cifisp_dpf_config(isp_dev); + cifisp_dpf_strength_config(isp_dev); + cifisp_dpf_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_DPF | CIFISP_MODULE_DPF_STRENGTH); + } + + if (CIFISP_MODULE_IS_EN(*meas_ens, CIFISP_MODULE_AFC)) { + cifisp_afc_config(isp_dev); + cifisp_afc_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_AFC); + } + + if (CIFISP_MODULE_IS_EN(*meas_ens, CIFISP_MODULE_AWB)) { + cifisp_awb_meas_config(isp_dev); + cifisp_awb_meas_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_AWB); + } + + if (CIFISP_MODULE_IS_EN(*meas_ens, CIFISP_MODULE_AEC)) { + cifisp_aec_config(isp_dev); + cifisp_aec_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_AEC); + } + + if (CIFISP_MODULE_IS_EN(*meas_ens, CIFISP_MODULE_HST)) { + cifisp_hst_config(isp_dev); + cifisp_hst_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_HST); + } + } else { + /* Disable modules for yuv */ + cifisp_dpcc_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_DPCC); + + cifisp_lsc_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_LSC); + + cifisp_bls_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_BLS); + + cifisp_sdg_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_SDG); + + cifisp_goc_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_GOC); + + cifisp_bdm_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_BDM); + + cifisp_flt_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_FLT); + + cifisp_awb_meas_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_AWB); + + cifisp_awb_gain_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_AWB_GAIN); + + cifisp_aec_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_AEC); + + cifisp_ctk_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_CTK); + + cifisp_dpf_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_DPF); + + /* cproc can be used for yuv in reduced range */ + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_CPROC)) { + cifisp_cproc_config(isp_dev, false); + cifisp_cproc_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_CPROC); + } + + cifisp_hst_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_HST); + + cifisp_afc_end(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*meas_updates, + CIFISP_MODULE_AFC); + /* ie can be used for yuv */ + if (CIFISP_MODULE_IS_EN(*other_ens, CIFISP_MODULE_IE)) { + cifisp_ie_config(isp_dev); + cifisp_ie_en(isp_dev); + CIFISP_MODULE_CLR_UPDATE(*other_updates, + CIFISP_MODULE_IE); + } else { + cifisp_ie_end(isp_dev); + } + } + + cifisp_dump_reg(isp_dev, CIFISP_DEBUG); + + cifisp_meas_config_swap(isp_dev); + cifisp_other_config_swap(isp_dev); + + memcpy(isp_dev->other_cfgs.last_or_new, + isp_dev->other_cfgs.curr, + sizeof(struct cifisp_isp_other_cfg)); + memcpy(isp_dev->meas_cfgs.last_or_new, + isp_dev->meas_cfgs.curr, + sizeof(struct cifisp_isp_meas_cfg)); + + spin_unlock(&isp_dev->config_lock); + mutex_unlock(&isp_dev->mutex); +} + +void cifisp_frame_in( + struct cif_isp10_isp_dev *isp_dev, + const struct timeval *fi_t) +{ + /* Called in an interrupt context. */ + isp_dev->fi_t = *fi_t; +} + +void cifisp_v_start( + struct cif_isp10_isp_dev *isp_dev, + const struct timeval *vs_t) +{ + /* Called in an interrupt context. */ + isp_dev->frame_id += 2; + isp_dev->vs_t = *vs_t; +} + +/* Not called when the camera active, thus not isr protection. */ +void cifisp_disable_isp(struct cif_isp10_isp_dev *isp_dev) +{ + CIFISP_DPRINT(CIFISP_DEBUG, "%s\n", __func__); + + mutex_lock(&isp_dev->mutex); + + cifisp_dpcc_end(isp_dev); + cifisp_lsc_end(isp_dev); + cifisp_bls_end(isp_dev); + cifisp_sdg_end(isp_dev); + cifisp_goc_end(isp_dev); + cifisp_bdm_end(isp_dev); + cifisp_flt_end(isp_dev); + cifisp_awb_meas_end(isp_dev); + cifisp_awb_gain_end(isp_dev); + cifisp_aec_end(isp_dev); + cifisp_ctk_end(isp_dev); + cifisp_cproc_end(isp_dev); + cifisp_hst_end(isp_dev); + cifisp_afc_end(isp_dev); + cifisp_ie_end(isp_dev); + cifisp_dpf_end(isp_dev); + + /* + * Isp isn't active, isp interrupt isn't enabled, spin_lock is enough; + */ + spin_lock(&isp_dev->config_lock); + + isp_dev->other_cfgs.last_or_new->module_ens = 0; + isp_dev->meas_cfgs.last_or_new->module_ens = 0; + + /* + * 1. Swap last_or_new and curr pointer; + * 2. Sync last_or_new and curr configuration; + */ + cifisp_meas_config_swap(isp_dev); + cifisp_other_config_swap(isp_dev); + + memcpy(isp_dev->other_cfgs.last_or_new, + isp_dev->other_cfgs.curr, + sizeof(struct cifisp_isp_other_cfg)); + memcpy(isp_dev->meas_cfgs.last_or_new, + isp_dev->meas_cfgs.curr, + sizeof(struct cifisp_isp_meas_cfg)); + + spin_unlock(&isp_dev->config_lock); + + mutex_unlock(&isp_dev->mutex); +} + +static void cifisp_send_measurement( + struct cif_isp10_isp_dev *isp_dev, + struct cif_isp10_isp_readout_work *meas_work) +{ + unsigned long lock_flags = 0; + struct videobuf_buffer *vb = NULL; + unsigned int active_meas = isp_dev->active_meas; + struct cifisp_stat_buffer *stat_buf; + struct cif_isp10_device *cif_dev = + container_of(isp_dev, struct cif_isp10_device, isp_dev); + + spin_lock_irqsave(&isp_dev->irq_lock, lock_flags); + if (isp_dev->frame_id != meas_work->frame_id) { + spin_unlock_irqrestore(&isp_dev->irq_lock, lock_flags); + CIFISP_DPRINT(CIFISP_ERROR, + "Measurement late(%d, %d)\n", + isp_dev->frame_id, + meas_work->frame_id); + goto end; + } + + if (!list_empty(&isp_dev->stat)) { + vb = list_first_entry(&isp_dev->stat, + struct videobuf_buffer, queue); + } else { + spin_unlock_irqrestore(&isp_dev->irq_lock, lock_flags); + CIFISP_DPRINT(CIFISP_DEBUG, + "Not enought measurement bufs\n"); + goto end; + } + + spin_unlock_irqrestore(&isp_dev->irq_lock, lock_flags); + vb->state = VIDEOBUF_ACTIVE; + + stat_buf = (struct cifisp_stat_buffer *)videobuf_to_vmalloc(vb); + memset(stat_buf, 0x00, sizeof(struct cifisp_stat_buffer)); + + if (active_meas & CIF_ISP_AWB_DONE) + cifisp_get_awb_meas(isp_dev, stat_buf); + + if (active_meas & CIF_ISP_AFM_FIN) + cifisp_get_afc_meas(isp_dev, stat_buf); + + if (active_meas & CIF_ISP_EXP_END) { + cifisp_get_aec_meas(isp_dev, stat_buf); + cifisp_bls_get_meas(isp_dev, stat_buf); + } + + if (active_meas & CIF_ISP_HIST_MEASURE_RDY) + cifisp_get_hst_meas(isp_dev, stat_buf); + + spin_lock_irqsave(&isp_dev->irq_lock, lock_flags); + + if (isp_dev->frame_id != meas_work->frame_id) { + spin_unlock_irqrestore(&isp_dev->irq_lock, lock_flags); + CIFISP_DPRINT(CIFISP_ERROR, + "Measurement late(%d, %d)\n", + isp_dev->frame_id, + meas_work->frame_id); + goto end; + } + + vb->ts = isp_dev->vs_t; + list_del(&vb->queue); + spin_unlock_irqrestore(&isp_dev->irq_lock, lock_flags); + + if (active_meas & CIF_ISP_AWB_DONE) { + memcpy(&isp_dev->meas_stats.stat.params.awb, + &stat_buf->params.awb, + sizeof(struct cifisp_awb_stat)); + isp_dev->meas_stats.stat.meas_type |= CIFISP_STAT_AWB; + } + if (active_meas & CIF_ISP_AFM_FIN) { + memcpy(&isp_dev->meas_stats.stat.params.af, + &stat_buf->params.af, + sizeof(struct cifisp_af_stat)); + isp_dev->meas_stats.stat.meas_type |= CIFISP_STAT_AFM_FIN; + } + if (active_meas & CIF_ISP_EXP_END) { + cif_isp10_sensor_mode_data_sync(cif_dev, + meas_work->frame_id, + &stat_buf->sensor_mode); + memcpy(&isp_dev->meas_stats.stat.params.ae, + &stat_buf->params.ae, + sizeof(struct cifisp_ae_stat)); + memcpy(&isp_dev->meas_stats.stat.sensor_mode, + &stat_buf->sensor_mode, + sizeof(struct isp_supplemental_sensor_mode_data)); + + isp_dev->meas_stats.stat.meas_type |= CIFISP_STAT_AUTOEXP; + } + if (active_meas & CIF_ISP_HIST_MEASURE_RDY) { + memcpy(&isp_dev->meas_stats.stat.params.hist, + &stat_buf->params.hist, + sizeof(struct cifisp_hist_stat)); + isp_dev->meas_stats.stat.meas_type |= CIFISP_STAT_HIST; + } + isp_dev->meas_stats.g_frame_id = meas_work->frame_id; + + vb->field_count = meas_work->frame_id; + vb->state = VIDEOBUF_DONE; + wake_up(&vb->done); + + CIFISP_DPRINT(CIFISP_DEBUG, + "Measurement done(%d, %d)\n", + vb->field_count, + vb->i); + vb = NULL; +end: + + if (vb && (vb->state == VIDEOBUF_ACTIVE)) + vb->state = VIDEOBUF_QUEUED; +} + +void cifisp_isp_readout_work(struct work_struct *work) +{ + struct cif_isp10_isp_readout_work *readout_work = + (struct cif_isp10_isp_readout_work *)work; + struct cif_isp10_isp_dev *isp_dev = + readout_work->isp_dev; + struct cif_isp10_device *cif_dev = + container_of(isp_dev, struct cif_isp10_device, isp_dev); + unsigned long int lock_flags; + + if (!isp_dev->streamon) + return; + + switch (readout_work->readout) { + case CIF_ISP10_ISP_READOUT_MEAS: + cifisp_send_measurement(isp_dev, readout_work); + break; + + case CIF_ISP10_ISP_READOUT_META: { + struct cifisp_isp_other_cfg *other_new = NULL; + struct cifisp_isp_meas_cfg *meas_new = NULL; + struct cifisp_stat_buffer *stat_new = NULL; + + spin_lock_irqsave(&isp_dev->config_lock, lock_flags); + + if (isp_dev->other_cfgs.module_updates == 0) { + if (readout_work->frame_id == + isp_dev->other_cfgs.curr->s_frame_id) + other_new = isp_dev->other_cfgs.last_or_new; + else if (readout_work->frame_id > + isp_dev->other_cfgs.curr->s_frame_id) + other_new = isp_dev->other_cfgs.curr; + else + other_new = NULL; + } + + if (isp_dev->meas_cfgs.module_updates == 0) { + if (readout_work->frame_id == + isp_dev->meas_cfgs.curr->s_frame_id) + meas_new = isp_dev->meas_cfgs.last_or_new; + else if (readout_work->frame_id > + isp_dev->meas_cfgs.curr->s_frame_id) + meas_new = isp_dev->meas_cfgs.curr; + else + meas_new = NULL; + } + + if ((isp_dev->meas_stats.g_frame_id == + readout_work->frame_id) && + isp_dev->meas_stats.stat.meas_type) + stat_new = &isp_dev->meas_stats.stat; + else + stat_new = NULL; + + cif_isp10_s_isp_metadata( + cif_dev, + readout_work, + other_new, + meas_new, + stat_new); + spin_unlock_irqrestore(&isp_dev->config_lock, lock_flags); + + break; + } + default: + break; + } + + kfree((void *)work); +} + +static inline bool cifisp_isp_isr_other_config( + struct cif_isp10_isp_dev *isp_dev, + unsigned int *time_left) +{ + unsigned int time_in = *time_left; + bool config_chk; + unsigned int *ens; + + ens = &isp_dev->other_cfgs.last_or_new->module_ens; + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPCC)) { + /*update dpc config */ + cifisp_dpcc_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_DPCC)) + cifisp_dpcc_en(isp_dev); + else + cifisp_dpcc_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPCC); + + *time_left -= CIFISP_MODULE_DPCC_PROC_TIME; + + CIFISP_DPRINT(CIFISP_DEBUG, + "dpcc time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_BLS) && + *time_left >= CIFISP_MODULE_BLS_PROC_TIME) { + /* update bls config */ + cifisp_bls_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_BLS)) + cifisp_bls_en(isp_dev); + else + cifisp_bls_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_BLS); + + *time_left -= CIFISP_MODULE_BLS_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "bls time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_SDG) && + *time_left >= CIFISP_MODULE_SDG_PROC_TIME) { + /* update sdg config */ + cifisp_sdg_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_SDG)) + cifisp_sdg_en(isp_dev); + else + cifisp_sdg_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_SDG); + + *time_left -= CIFISP_MODULE_SDG_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "sdg time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_LSC) && + *time_left >= CIFISP_MODULE_LSC_PROC_TIME) { + /* update lsc config */ + bool res = true; + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_LSC)) { + if (!cifisp_lsc_config(isp_dev)) + res = false; + } else { + cifisp_lsc_end(isp_dev); + } + + if (res) + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_LSC); + + *time_left -= CIFISP_MODULE_LSC_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "lsc time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_AWB_GAIN) && + *time_left >= CIFISP_MODULE_AWB_GAIN_PROC_TIME) { + /* update awb gains */ + cifisp_awb_gain_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_AWB_GAIN)) + cifisp_awb_gain_en(isp_dev); + else + cifisp_awb_gain_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_AWB_GAIN); + + *time_left -= CIFISP_MODULE_AWB_GAIN_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "awb-g time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_BDM) && + *time_left >= CIFISP_MODULE_BDM_PROC_TIME) { + /* update bdm config */ + cifisp_bdm_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_BDM)) + cifisp_bdm_en(isp_dev); + else + cifisp_bdm_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_BDM); + + *time_left -= CIFISP_MODULE_BDM_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "bdm time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_FLT) && + *time_left >= CIFISP_MODULE_FLT_PROC_TIME) { + /* update filter config */ + cifisp_flt_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_FLT)) + cifisp_flt_en(isp_dev); + else + cifisp_flt_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_FLT); + + *time_left -= CIFISP_MODULE_FLT_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "flt time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_CTK) && + *time_left >= CIFISP_MODULE_CTK_PROC_TIME) { + /* update ctk config */ + cifisp_ctk_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_CTK)) + cifisp_ctk_en(isp_dev); + else + cifisp_ctk_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_CTK); + + *time_left -= CIFISP_MODULE_CTK_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "ctk time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_GOC) && + *time_left >= CIFISP_MODULE_GOC_PROC_TIME) { + /* update goc config */ + cifisp_goc_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_GOC)) + cifisp_goc_en(isp_dev); + else + cifisp_goc_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_IE); + + *time_left -= CIFISP_MODULE_GOC_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "goc time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_CPROC) && + *time_left >= CIFISP_MODULE_CPROC_PROC_TIME) { + /* update cprc config */ + cifisp_cproc_config( + isp_dev, + isp_dev->quantization); + + cifisp_csm_config(isp_dev, + isp_dev->quantization); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_CPROC)) + cifisp_cproc_en(isp_dev); + else + cifisp_cproc_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_CPROC); + + *time_left -= CIFISP_MODULE_CPROC_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "cproc time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_IE) && + *time_left >= CIFISP_MODULE_IE_PROC_TIME) { + /* update ie config */ + cifisp_ie_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_IE)) + cifisp_ie_en(isp_dev); + else + cifisp_ie_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_IE); + + *time_left -= CIFISP_MODULE_IE_PROC_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "ie time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPF) && + *time_left >= CIFISP_MODULE_DPF_TIME) { + /* update dpf config */ + cifisp_dpf_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_DPF)) + cifisp_dpf_en(isp_dev); + else + cifisp_dpf_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPF); + + *time_left -= CIFISP_MODULE_DPF_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "dpf time-left :%d\n", + *time_left); + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPF_STRENGTH) && + *time_left >= CIFISP_MODULE_DPF_STRENGTH_TIME) { + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_DPF)) { + /* update dpf strength config */ + cifisp_dpf_strength_config(isp_dev); + cifisp_dpf_en(isp_dev); + } else { + cifisp_dpf_end(isp_dev); + } + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->other_cfgs.module_updates, + CIFISP_MODULE_DPF_STRENGTH); + + *time_left -= CIFISP_MODULE_DPF_STRENGTH_TIME; + CIFISP_DPRINT(CIFISP_DEBUG, + "dpf strength time-left :%d\n", + *time_left); + } + + config_chk = time_in > *time_left; + if (config_chk) + cifisp_other_config_swap(isp_dev); + + return config_chk; +} + +static inline bool cifisp_isp_isr_meas_config( + struct cif_isp10_isp_dev *isp_dev, + unsigned int *time_left) +{ + unsigned int time_in = *time_left; + bool config_chk; + unsigned int *ens; + + ens = &isp_dev->meas_cfgs.last_or_new->module_ens; + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AWB)) { + /* update awb config */ + cifisp_awb_meas_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_AWB)) + cifisp_awb_meas_en(isp_dev); + else + cifisp_awb_meas_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AWB); + *time_left -= CIFISP_MODULE_AWB_PROC_TIME; + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AFC)) { + /* update afc config */ + cifisp_afc_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_AFC)) + cifisp_afc_en(isp_dev); + else + cifisp_afc_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AFC); + *time_left -= CIFISP_MODULE_AFC_PROC_TIME; + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_HST)) { + /* update hst config */ + cifisp_hst_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_HST)) + cifisp_hst_en(isp_dev); + else + cifisp_hst_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_HST); + *time_left -= CIFISP_MODULE_HST_PROC_TIME; + } + + if (CIFISP_MODULE_IS_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AEC)) { + /* update aec config */ + cifisp_aec_config(isp_dev); + + if (CIFISP_MODULE_IS_EN(*ens, CIFISP_MODULE_AEC)) + cifisp_aec_en(isp_dev); + else + cifisp_aec_end(isp_dev); + + CIFISP_MODULE_CLR_UPDATE( + isp_dev->meas_cfgs.module_updates, + CIFISP_MODULE_AEC); + *time_left -= CIFISP_MODULE_AEC_PROC_TIME; + } + + config_chk = time_in > *time_left; + if (config_chk) + cifisp_meas_config_swap(isp_dev); + + return config_chk; +} + +int cifisp_isp_isr(struct cif_isp10_isp_dev *isp_dev, u32 isp_mis) +{ + unsigned int isp_mis_tmp = 0; + struct cif_isp10_isp_readout_work *work; + unsigned int time_left = isp_dev->v_blanking_us; +#ifdef LOG_ISR_EXE_TIME + ktime_t in_t = ktime_get(); +#endif + if (isp_mis & (CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR)) + return 0; + + if (isp_mis & CIF_ISP_FRAME) { + u32 isp_ris = cifisp_ioread32(CIF_ISP_RIS); + + cifisp_iowrite32( + (CIF_ISP_AWB_DONE | CIF_ISP_AFM_FIN | + CIF_ISP_EXP_END | CIF_ISP_HIST_MEASURE_RDY), + CIF_ISP_ICR); + isp_mis_tmp = cifisp_ioread32(CIF_ISP_MIS); + if (isp_mis_tmp & + (CIF_ISP_AWB_DONE | CIF_ISP_AFM_FIN | + CIF_ISP_EXP_END | CIF_ISP_HIST_MEASURE_RDY)) + CIFISP_DPRINT(CIFISP_ERROR, + "isp icr 3A info err: 0x%x\n", + isp_mis_tmp); + + CIFISP_DPRINT(CIFISP_DEBUG, "isp_ris 0x%x\n", isp_ris); + + if (((isp_dev->meas_cfgs.module_updates & + (CIFISP_MODULE_AWB | + CIFISP_MODULE_AEC | + CIFISP_MODULE_AFC)) == 0) && + isp_dev->active_meas && + ((isp_dev->active_meas & isp_ris) == + isp_dev->active_meas)) { + work = (struct cif_isp10_isp_readout_work *) + kmalloc(sizeof( + struct cif_isp10_isp_readout_work), + GFP_ATOMIC); + if (work) { + INIT_WORK((struct work_struct *)work, + cifisp_isp_readout_work); + work->readout = CIF_ISP10_ISP_READOUT_MEAS; + work->isp_dev = isp_dev; + work->frame_id = isp_dev->frame_id; + if (!queue_work(isp_dev->readout_wq, + (struct work_struct *)work)) { + CIFISP_DPRINT(CIFISP_ERROR, + "Could not schedule work\n"); + kfree((void *)work); + } + } else { + CIFISP_DPRINT(CIFISP_ERROR, + "Could not allocate work\n"); + } + } + + /* + * Then update changed configs. Some of them involve + * lot of register writes. Do those only one per frame. + * Do the updates in the order of the processing flow. + */ + spin_lock(&isp_dev->config_lock); + if (cifisp_isp_isr_other_config(isp_dev, &time_left) == false) + cifisp_isp_isr_meas_config(isp_dev, &time_left); + spin_unlock(&isp_dev->config_lock); + + cifisp_dump_reg(isp_dev, CIFISP_DEBUG); + } +#ifdef LOG_ISR_EXE_TIME + if (isp_mis & (CIF_ISP_EXP_END | CIF_ISP_AWB_DONE | + CIF_ISP_FRAME | CIF_ISP_HIST_MEASURE_RDY)) { + unsigned int diff_us = + ktime_to_us(ktime_sub(ktime_get(), in_t)); + + if (diff_us > g_longest_isr_time) + g_longest_isr_time = diff_us; + + pr_info("isp_isr time %d %d\n", diff_us, g_longest_isr_time); + } +#endif + + return 0; +} + +static void cifisp_param_dump(const void *config, unsigned int module) +{ +#ifdef CIFISP_DEBUG_PARAM + switch (module) { + case CIFISP_MODULE_AWB_GAIN:{ + struct cifisp_awb_gain_config *pconfig = + (struct cifisp_awb_gain_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: AWB Gain Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, "g_g: %d\n", + pconfig->gain_green_r); + CIFISP_DPRINT(CIFISP_DEBUG, "g_b: %d\n", + pconfig->gain_green_b); + CIFISP_DPRINT(CIFISP_DEBUG, "r: %d\n", + pconfig->gain_red); + CIFISP_DPRINT(CIFISP_DEBUG, "b: %d\n", + pconfig->gain_blue); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: AWB Gain Parameters - END ####\n", + ISP_VDEV_NAME); + } + break; + case CIFISP_MODULE_DPCC:{ + } + break; + + case CIFISP_MODULE_BLS:{ + struct cifisp_bls_config *pconfig = + (struct cifisp_bls_config *)config; + struct cifisp_bls_fixed_val *pval = &pconfig->fixed_val; + + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: BLS Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " enable_auto: %d\n", + pconfig->enable_auto); + CIFISP_DPRINT(CIFISP_DEBUG, " en_windows: %d\n", + pconfig->en_windows); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window1.h_offs: %d\n", + pconfig->bls_window1.h_offs); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window1.v_offs: %d\n", + pconfig->bls_window1.v_offs); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window1.h_size: %d\n", + pconfig->bls_window1.h_size); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window1.v_size: %d\n", + pconfig->bls_window1.v_size); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window2.h_offs: %d\n", + pconfig->bls_window2.h_offs); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window2.v_offs: %d\n", + pconfig->bls_window2.v_offs); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window2.h_size: %d\n", + pconfig->bls_window2.h_size); + CIFISP_DPRINT(CIFISP_DEBUG, + " bls_window2.v_size: %d\n", + pconfig->bls_window2.v_size); + CIFISP_DPRINT(CIFISP_DEBUG, " bls_samples: %d\n", + pconfig->bls_samples); + CIFISP_DPRINT(CIFISP_DEBUG, " fixed_A: %d\n", + pval->fixed_a); + CIFISP_DPRINT(CIFISP_DEBUG, " fixed_B: %d\n", + pval->fixed_b); + CIFISP_DPRINT(CIFISP_DEBUG, " fixed_C: %d\n", + pval->fixed_c); + CIFISP_DPRINT(CIFISP_DEBUG, " fixed_D: %d\n", + pval->fixed_d); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: BLS Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + case CIFISP_MODULE_LSC:{ + CIFISP_DPRINT(CIFISP_DEBUG, + "#### LSC Parameters - BEGIN ####\n"); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### LSC Parameters - END ####\n"); + } + break; + case CIFISP_MODULE_FLT:{ + struct cifisp_flt_config *pconfig = + (struct cifisp_flt_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: FLT Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_mask_sharp0: %d\n", + pconfig->flt_mask_sharp0); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_mask_sharp1: %d\n", + pconfig->flt_mask_sharp1); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_mask_diag: %d\n", + pconfig->flt_mask_diag); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_mask_blur_max: %d\n", + pconfig->flt_mask_blur_max); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_mask_blur: %d\n", + pconfig->flt_mask_blur); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_mask_lin: %d\n", + pconfig->flt_mask_lin); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_mask_orth: %d\n", + pconfig->flt_mask_orth); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_mask_v_diag: %d\n", + pconfig->flt_mask_v_diag); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_mask_h_diag: %d\n", + pconfig->flt_mask_h_diag); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_lum_weight: %d\n", + pconfig->flt_lum_weight); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_blur_th0: %d\n", + pconfig->flt_blur_th0); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_blur_th1: %d\n", + pconfig->flt_blur_th1); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_sharp0_th: %d\n", + pconfig->flt_sharp0_th); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_sharp1_th: %d\n", + pconfig->flt_sharp1_th); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_chrom_h_mode: %d\n", + pconfig->flt_chrom_h_mode); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_chrom_v_mode: %d\n", + pconfig->flt_chrom_v_mode); + CIFISP_DPRINT(CIFISP_DEBUG, + " flt_diag_sharp_mode: %d\n", + pconfig->flt_diag_sharp_mode); + CIFISP_DPRINT(CIFISP_DEBUG, " flt_mode: %d\n", + pconfig->flt_mode); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: FLT Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + + case CIFISP_MODULE_BDM:{ + struct cifisp_bdm_config *pconfig = + (struct cifisp_bdm_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: BDM Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " demosaic_th: %d\n", + pconfig->demosaic_th); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: BDM Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + + case CIFISP_MODULE_SDG:{ + struct cifisp_sdg_config *pconfig = + (struct cifisp_sdg_config *)config; + unsigned int i; + + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: SDG Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, + " RED -Curve parameters\n"); + for (i = 0; i < CIFISP_DEGAMMA_CURVE_SIZE; i++) { + CIFISP_DPRINT(CIFISP_DEBUG, + " gamma_y[%d]: %d\n", + pconfig->curve_r.gamma_y[i]); + } + CIFISP_DPRINT(CIFISP_DEBUG, + " GREEN -Curve parameters\n"); + for (i = 0; i < CIFISP_DEGAMMA_CURVE_SIZE; i++) { + CIFISP_DPRINT(CIFISP_DEBUG, + " gamma_y[%d]: %d\n", + pconfig->curve_g.gamma_y[i]); + } + CIFISP_DPRINT(CIFISP_DEBUG, + " BLUE -Curve parameters\n"); + for (i = 0; i < CIFISP_DEGAMMA_CURVE_SIZE; i++) { + CIFISP_DPRINT(CIFISP_DEBUG, + " gamma_y[%d]: %d\n", + pconfig->curve_b.gamma_y[i]); + } + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: SDG Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + + case CIFISP_MODULE_GOC:{ + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: GOC Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: GOC Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + + case CIFISP_MODULE_CTK:{ + struct cifisp_ctk_config *pconfig = + (struct cifisp_ctk_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: CTK Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff0: %d\n", + pconfig->coeff0); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff1: %d\n", + pconfig->coeff1); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff2: %d\n", + pconfig->coeff2); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff3: %d\n", + pconfig->coeff3); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff4: %d\n", + pconfig->coeff4); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff5: %d\n", + pconfig->coeff5); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff6: %d\n", + pconfig->coeff6); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff7: %d\n", + pconfig->coeff7); + CIFISP_DPRINT(CIFISP_DEBUG, " coeff8: %d\n", + pconfig->coeff8); + CIFISP_DPRINT(CIFISP_DEBUG, " ct_offset_r: %d\n", + pconfig->ct_offset_r); + CIFISP_DPRINT(CIFISP_DEBUG, " ct_offset_g: %d\n", + pconfig->ct_offset_g); + CIFISP_DPRINT(CIFISP_DEBUG, " ct_offset_b: %d\n", + pconfig->ct_offset_b); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: CTK Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + + case CIFISP_MODULE_AWB:{ + struct cifisp_awb_meas_config *pconfig = + (struct cifisp_awb_meas_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: AWB Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " awb_mode: %d\n", + pconfig->awb_mode); + CIFISP_DPRINT(CIFISP_DEBUG, " max_y: %d\n", + pconfig->max_y); + CIFISP_DPRINT(CIFISP_DEBUG, " min_y: %d\n", + pconfig->min_y); + CIFISP_DPRINT(CIFISP_DEBUG, " max_csum: %d\n", + pconfig->max_csum); + CIFISP_DPRINT(CIFISP_DEBUG, " min_c: %d\n", + pconfig->min_c); + CIFISP_DPRINT(CIFISP_DEBUG, " frames: %d\n", + pconfig->frames); + CIFISP_DPRINT(CIFISP_DEBUG, " awb_ref_cr: %d\n", + pconfig->awb_ref_cr); + CIFISP_DPRINT(CIFISP_DEBUG, " awb_ref_cb: %d\n", + pconfig->awb_ref_cb); + CIFISP_DPRINT(CIFISP_DEBUG, " gb_sat: %d\n", + pconfig->gb_sat); + CIFISP_DPRINT(CIFISP_DEBUG, " gr_sat: %d\n", + pconfig->gr_sat); + CIFISP_DPRINT(CIFISP_DEBUG, " r_sat: %d\n", + pconfig->b_sat); + CIFISP_DPRINT(CIFISP_DEBUG, " grid_h_dim: %d\n", + pconfig->grid_h_dim); + CIFISP_DPRINT(CIFISP_DEBUG, " grid_v_dim: %d\n", + pconfig->grid_v_dim); + CIFISP_DPRINT(CIFISP_DEBUG, " grid_h_dist: %d\n", + pconfig->grid_h_dist); + CIFISP_DPRINT(CIFISP_DEBUG, " grid_v_dist: %d\n", + pconfig->grid_v_dist); + CIFISP_DPRINT(CIFISP_DEBUG, + " enable_ymax_cmp: %d\n", + pconfig->enable_ymax_cmp); + CIFISP_DPRINT(CIFISP_DEBUG, " rgb_meas_pnt: %d\n", + pconfig->rgb_meas_pnt); + CIFISP_DPRINT(CIFISP_DEBUG, " AWB Window size\n"); + CIFISP_DPRINT(CIFISP_DEBUG, " h_offs: %d\n", + pconfig->awb_wnd.h_offs); + CIFISP_DPRINT(CIFISP_DEBUG, " v_offs: %d\n", + pconfig->awb_wnd.v_offs); + CIFISP_DPRINT(CIFISP_DEBUG, " h_size: %d\n", + pconfig->awb_wnd.h_size); + CIFISP_DPRINT(CIFISP_DEBUG, " v_size: %d\n", + pconfig->awb_wnd.v_size); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: AWB Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + + case CIFISP_MODULE_HST:{ + struct cifisp_hst_config *pconfig = + (struct cifisp_hst_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: HST Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " mode: %d\n", + pconfig->mode); + CIFISP_DPRINT(CIFISP_DEBUG, + " histogram_predivider: %d\n", + pconfig->histogram_predivider); + CIFISP_DPRINT(CIFISP_DEBUG, " HST Window size\n"); + CIFISP_DPRINT(CIFISP_DEBUG, " h_offs: %d\n", + pconfig->meas_window.h_offs); + CIFISP_DPRINT(CIFISP_DEBUG, " v_offs: %d\n", + pconfig->meas_window.v_offs); + CIFISP_DPRINT(CIFISP_DEBUG, " h_size: %d\n", + pconfig->meas_window.h_size); + CIFISP_DPRINT(CIFISP_DEBUG, " v_size: %d\n", + pconfig->meas_window.v_size); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: HST Parameters - END ####\n", + ISP_VDEV_NAME); + + } break; + + case CIFISP_MODULE_AEC:{ + struct cifisp_aec_config *pconfig = + (struct cifisp_aec_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: AEC Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " autostop: %d\n", + pconfig->autostop); + CIFISP_DPRINT(CIFISP_DEBUG, " AEC Window size\n"); + CIFISP_DPRINT(CIFISP_DEBUG, " h_offs: %d\n", + pconfig->meas_window.h_offs); + CIFISP_DPRINT(CIFISP_DEBUG, " v_offs: %d\n", + pconfig->meas_window.v_offs); + CIFISP_DPRINT(CIFISP_DEBUG, " h_size: %d\n", + pconfig->meas_window.h_size); + CIFISP_DPRINT(CIFISP_DEBUG, " v_size: %d\n", + pconfig->meas_window.v_size); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: AEC Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + + case CIFISP_MODULE_CPROC:{ + struct cifisp_cproc_config *pconfig = + (struct cifisp_cproc_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: CPROC Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " contrast: %d\n", + pconfig->contrast); + CIFISP_DPRINT(CIFISP_DEBUG, " hue: %d\n", + pconfig->hue); + CIFISP_DPRINT(CIFISP_DEBUG, " sat: %d\n", + pconfig->sat); + CIFISP_DPRINT(CIFISP_DEBUG, " brightness: %d\n", + pconfig->brightness); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: CPROC Parameters - END ####\n", + ISP_VDEV_NAME); + } break; + case CIFISP_MODULE_YCFLT:{ + struct cifisp_ycflt_config *pconfig = + (struct cifisp_ycflt_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: YCFLT Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, " chr_ss_ctrl: %d\n", + CIFISP_DPRINT(CIFISP_DEBUG, " ctrl: %d\n", + pconfig->ctrl); + CIFISP_DPRINT(CIFISP_DEBUG, " chr_ss_ctrl: %d\n", + pconfig->chr_ss_ctrl); + CIFISP_DPRINT(CIFISP_DEBUG, " chr_ss_fac: %d\n", + pconfig->chr_ss_fac); + CIFISP_DPRINT(CIFISP_DEBUG, " chr_ss_offs: %d\n", + pconfig->chr_ss_offs); + CIFISP_DPRINT(CIFISP_DEBUG, " chr_nr_ctrl: %d\n", + pconfig->chr_nr_ctrl); + CIFISP_DPRINT(CIFISP_DEBUG, + " lum_eenr_edge_gain: %d\n", + pconfig->lum_eenr_edge_gain); + CIFISP_DPRINT(CIFISP_DEBUG, + " lum_eenr_corner_gain: %d\n", + pconfig->lum_eenr_corner_gain); + CIFISP_DPRINT(CIFISP_DEBUG, + " lum_eenr_fc_crop_neg: %d\n", + pconfig->lum_eenr_fc_crop_neg); + CIFISP_DPRINT(CIFISP_DEBUG, + " lum_eenr_fc_crop_pos: %d\n", + pconfig->lum_eenr_fc_crop_pos); + CIFISP_DPRINT(CIFISP_DEBUG, + " lum_eenr_fc_gain_neg: %d\n", + pconfig->lum_eenr_fc_gain_neg); + CIFISP_DPRINT(CIFISP_DEBUG, + " lum_eenr_fc_gain_pos: %d\n", + pconfig->lum_eenr_fc_gain_pos); + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: YCFLT Parameters - END ####\n", + ISP_VDEV_NAME); + break; + } + case CIFISP_MODULE_AFC:{ + struct cifisp_afc_config *pconfig = + (struct cifisp_afc_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "#### %s: AFC Parameters - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(CIFISP_DEBUG, + " window A %d %d %d %d\n", + pconfig->afm_win[0].h_offs, + pconfig->afm_win[0].v_offs, + pconfig->afm_win[0].h_size, + pconfig->afm_win[0].v_size); + CIFISP_DPRINT(CIFISP_DEBUG, + " window B %d %d %d %d\n", + pconfig->afm_win[1].h_offs, + pconfig->afm_win[1].v_offs, + pconfig->afm_win[1].h_size, + pconfig->afm_win[1].v_size); + CIFISP_DPRINT(CIFISP_DEBUG, + " window C %d %d %d %d\n", + pconfig->afm_win[2].h_offs, + pconfig->afm_win[2].v_offs, + pconfig->afm_win[2].h_size, + pconfig->afm_win[2].v_size); + CIFISP_DPRINT(CIFISP_DEBUG, " thres: %d\n", + pconfig->thres); + CIFISP_DPRINT(CIFISP_DEBUG, " var_shift: %d\n", + pconfig->var_shift); + break; + } + case CIFISP_MODULE_IE: { + struct cifisp_ie_config *pconfig = + (struct cifisp_ie_config *)config; + CIFISP_DPRINT(CIFISP_DEBUG, + "effect %d, %x, %x, %x, %x, %x, %x %d\n", + pconfig->effect, pconfig->color_sel, + pconfig->eff_mat_1, pconfig->eff_mat_2, + pconfig->eff_mat_3, pconfig->eff_mat_4, + pconfig->eff_mat_5, pconfig->eff_tint); + break; + } + default: + CIFISP_DPRINT(CIFISP_DEBUG, + "####%s: Invalid Module ID ####\n", ISP_VDEV_NAME); + break; + } +#endif +} + +#ifdef LOG_CAPTURE_PARAMS +static void cifisp_reg_dump_capture(const struct cif_isp10_isp_dev *isp_dev) +{ + memset(&g_last_capture_config, 0, sizeof(g_last_capture_config)); + + if (isp_dev->bls_en) { + g_last_capture_config.bls.fixed_val.fixed_a = + cifisp_ioread32(CIF_ISP_BLS_A_FIXED); + g_last_capture_config.bls.fixed_val.fixed_b = + cifisp_ioread32(CIF_ISP_BLS_B_FIXED); + g_last_capture_config.bls.fixed_val.fixed_c = + cifisp_ioread32(CIF_ISP_BLS_C_FIXED); + g_last_capture_config.bls.fixed_val.fixed_d = + cifisp_ioread32(CIF_ISP_BLS_D_FIXED); + } + + if (isp_dev->lsc_en) + cifisp_lsc_config_read(isp_dev, &g_last_capture_config.lsc); + + if (isp_dev->flt_en) + cifisp_flt_config_read(isp_dev, &g_last_capture_config.flt); + + if (isp_dev->bdm_en) + g_last_capture_config.bdm.demosaic_th = + cifisp_ioread32(CIF_ISP_DEMOSAIC); + + if (isp_dev->sdg_en) + cifisp_sdg_config_read(isp_dev, &g_last_capture_config.sdg); + + if (isp_dev->goc_en) + cifisp_goc_config_read(isp_dev, &g_last_capture_config.goc); + + if (isp_dev->ctk_en) + cifisp_ctk_config_read(isp_dev, &g_last_capture_config.ctk); + + if (isp_dev->awb_meas_en) + cifisp_awb_meas_config_read(isp_dev, + &g_last_capture_config.awb_meas); + + if (isp_dev->awb_gain_en) + cifisp_awb_gain_config_read(isp_dev, + &g_last_capture_config.awb_gain); + + if (isp_dev->cproc_en) + cifisp_cproc_config_read(isp_dev, &g_last_capture_config.cproc); +} +#endif + +#ifdef CIFISP_DEBUG_REG +static void cifisp_reg_dump(const struct cif_isp10_isp_dev *isp_dev, + unsigned int module, int level) +{ + switch (module) { + case CIFISP_MODULE_DPCC: + CIFISP_DPRINT(level, "#### BPC Registers - BEGIN ####\n"); + CIFISP_DPRINT(level, "#### BPC Registers - END ####\n"); + break; + case CIFISP_MODULE_BLS: + CIFISP_DPRINT(level, "#### BLS Registers - BEGIN ####\n"); + CIFISP_DPRINT(level, " CIF_ISP_BLS_CTRL: %d\n", + cifisp_ioread32(CIF_ISP_BLS_CTRL)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_SAMPLES: %d\n", + cifisp_ioread32(CIF_ISP_BLS_SAMPLES)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_H1_START: %d\n", + cifisp_ioread32(CIF_ISP_BLS_H1_START)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_H1_STOP: %d\n", + cifisp_ioread32(CIF_ISP_BLS_H1_STOP)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_H1_START: %d\n", + cifisp_ioread32(CIF_ISP_BLS_H1_START)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_V1_START: %d\n", + cifisp_ioread32(CIF_ISP_BLS_V1_START)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_V1_STOP: %d\n", + cifisp_ioread32(CIF_ISP_BLS_V1_STOP)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_H2_START: %d\n", + cifisp_ioread32(CIF_ISP_BLS_H2_START)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_H2_STOP: %d\n", + cifisp_ioread32(CIF_ISP_BLS_H2_STOP)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_V2_START: %d\n", + cifisp_ioread32(CIF_ISP_BLS_V2_START)); + CIFISP_DPRINT(level, " CIF_ISP_BLS_V2_STOP: %d\n", + cifisp_ioread32(CIF_ISP_BLS_V2_STOP)); + CIFISP_DPRINT(level, "#### BLS Registers - END ####\n"); + break; + case CIFISP_MODULE_LSC: + CIFISP_DPRINT(level, "#### LSC Registers - BEGIN ####\n"); + CIFISP_DPRINT(level, "#### LSC Registers - END ####\n"); + break; + case CIFISP_MODULE_FLT:{ + CIFISP_DPRINT(level, + "#### %s: FLT Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, + " CIF_ISP_FILT_MODE: %d\n", + cifisp_ioread32(CIF_ISP_FILT_MODE)); + CIFISP_DPRINT(level, + " CIF_ISP_FILT_LUM_WEIGHT: %d\n", + cifisp_ioread32(CIF_ISP_FILT_LUM_WEIGHT)); + CIFISP_DPRINT(level, + "#### %s: FLT Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_BDM:{ + CIFISP_DPRINT(level, + "#### %s: BDM Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " CIF_ISP_DEMOSAIC: %d\n", + cifisp_ioread32(CIF_ISP_DEMOSAIC)); + CIFISP_DPRINT(level, + "#### %s: BDM Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_SDG:{ + CIFISP_DPRINT(level, + "#### %s: SDG Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_DX_LO: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_DX_LO)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_DX_HI: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_DX_HI)); + + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y0: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y0)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y1: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y1)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y2: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y2)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y3: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y3)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y4: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y4)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y5: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y5)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y6: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y6)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y7: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y7)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y8: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y8)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y9: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y9)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y10: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y10)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y11: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y11)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y12: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y12)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y13: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y13)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y14: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y14)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y15: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y15)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_R_Y16: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_R_Y16)); + + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y0: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y0)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y1: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y1)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y2: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y2)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y3: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y3)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y4: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y4)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y5: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y5)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y6: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y6)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y7: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y7)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y8: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y8)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y9: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y9)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y10: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y10)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y11: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y11)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y12: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y12)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y13: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y13)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y14: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y14)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y15: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y15)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_G_Y16: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_G_Y16)); + + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y0: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y0)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y1: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y1)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y2: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y2)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y3: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y3)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y4: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y4)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y5: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y5)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y6: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y6)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y7: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y7)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y8: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y8)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y9: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y9)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y10: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y10)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y11: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y11)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y12: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y12)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y13: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y13)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y14: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y14)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y15: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y15)); + CIFISP_DPRINT(level, " CIF_ISP_GAMMA_B_Y16: %d\n", + cifisp_ioread32(CIF_ISP_GAMMA_B_Y16)); + CIFISP_DPRINT(level, + "#### %s: SDG Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_GOC:{ + CIFISP_DPRINT(level, + "#### %s: GOC Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, + "#### %s: GOC registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_CTK:{ + CIFISP_DPRINT(level, + "#### %s: CTK Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_0: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_0)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_1: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_1)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_2: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_2)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_3: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_3)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_4: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_4)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_5: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_5)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_6: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_6)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_7: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_7)); + CIFISP_DPRINT(level, " CIF_ISP_CT_COEFF_8: %d\n", + cifisp_ioread32(CIF_ISP_CT_COEFF_8)); + CIFISP_DPRINT(level, " CIF_ISP_CT_OFFSET_R: %d\n", + cifisp_ioread32(CIF_ISP_CT_OFFSET_R)); + CIFISP_DPRINT(level, " CIF_ISP_CT_OFFSET_G: %d\n", + cifisp_ioread32(CIF_ISP_CT_OFFSET_G)); + CIFISP_DPRINT(level, " CIF_ISP_CT_OFFSET_B: %d\n", + cifisp_ioread32(CIF_ISP_CT_OFFSET_B)); + CIFISP_DPRINT(level, + "#### %s: CTK Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_AWB:{ + CIFISP_DPRINT(level, + "#### %s: AWB Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " CIF_ISP_AWB_PROP: %x\n", + cifisp_ioread32(CIF_ISP_AWB_PROP)); + CIFISP_DPRINT(level, " CIF_ISP_AWB_GAIN_G: %x\n", + cifisp_ioread32(CIF_ISP_AWB_GAIN_G)); + CIFISP_DPRINT(level, " CIF_ISP_AWB_GAIN_RB: %x\n", + cifisp_ioread32(CIF_ISP_AWB_GAIN_RB)); + CIFISP_DPRINT(level, " CIF_ISP_AWB_REF: %x\n", + cifisp_ioread32(CIF_ISP_AWB_REF)); + CIFISP_DPRINT(level, " CIF_ISP_AWB_GAIN_RB: %x\n", + cifisp_ioread32(CIF_ISP_AWB_PROP)); + CIFISP_DPRINT(level, " CIF_ISP_AWB_FRAMES: %x\n", + cifisp_ioread32(CIF_ISP_AWB_FRAMES)); + CIFISP_DPRINT(level, + "#### %s: AWB Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_HST:{ + CIFISP_DPRINT(level, + "#### %s: HST Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " CIF_ISP_HIST_PROP: %d\n", + cifisp_ioread32(CIF_ISP_HIST_PROP)); + CIFISP_DPRINT(level, " CIF_ISP_HIST_H_OFFS: %d\n", + cifisp_ioread32(CIF_ISP_HIST_H_OFFS)); + CIFISP_DPRINT(level, " CIF_ISP_HIST_H_SIZE: %d\n", + cifisp_ioread32(CIF_ISP_HIST_H_SIZE)); + CIFISP_DPRINT(level, " CIF_ISP_HIST_V_OFFS: %d\n", + cifisp_ioread32(CIF_ISP_HIST_V_OFFS)); + CIFISP_DPRINT(level, " CIF_ISP_HIST_V_SIZE: %d\n", + cifisp_ioread32(CIF_ISP_HIST_V_SIZE)); + CIFISP_DPRINT(level, + "#### %s: HST Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_AEC:{ + CIFISP_DPRINT(level, + "#### %s: AEC Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " CIF_ISP_EXP_CTRL: %d\n", + cifisp_ioread32(CIF_ISP_EXP_CTRL)); + CIFISP_DPRINT(level, " CIF_ISP_EXP_H_OFFSET: %d\n", + cifisp_ioread32(CIF_ISP_EXP_H_OFFSET)); + CIFISP_DPRINT(level, " CIF_ISP_EXP_V_OFFSET: %d\n", + cifisp_ioread32(CIF_ISP_EXP_V_OFFSET)); + CIFISP_DPRINT(level, " CIF_ISP_EXP_H_SIZE: %d\n", + cifisp_ioread32(CIF_ISP_EXP_H_SIZE)); + CIFISP_DPRINT(level, " CIF_ISP_EXP_V_SIZE: %d\n", + cifisp_ioread32(CIF_ISP_EXP_V_SIZE)); + CIFISP_DPRINT(level, + "#### %s: AEC Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + + case CIFISP_MODULE_CPROC:{ + CIFISP_DPRINT(level, + "#### %s: CPROC Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " ctrl: %d\n", + cifisp_ioread32(CIF_C_PROC_CTRL)); + CIFISP_DPRINT(level, " contrast: %d\n", + cifisp_ioread32(CIF_C_PROC_CONTRAST)); + CIFISP_DPRINT(level, " hue: %d\n", + cifisp_ioread32(CIF_C_PROC_HUE)); + CIFISP_DPRINT(level, " sat: %d\n", + cifisp_ioread32(CIF_C_PROC_SATURATION)); + CIFISP_DPRINT(level, " brightness: %d\n", + cifisp_ioread32(CIF_C_PROC_BRIGHTNESS)); + CIFISP_DPRINT(level, + "#### %s: CPROC Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + case CIFISP_MODULE_AFC:{ + CIFISP_DPRINT(level, + "#### %s: AFC Registers - BEGIN ####\n", + ISP_VDEV_NAME); + CIFISP_DPRINT(level, " afm_ctr: %d\n", + cifisp_ioread32(CIF_ISP_AFM_CTRL)); + CIFISP_DPRINT(level, " afm_lt_a: %d\n", + cifisp_ioread32(CIF_ISP_AFM_LT_A)); + CIFISP_DPRINT(level, " afm_rb_a: %d\n", + cifisp_ioread32(CIF_ISP_AFM_RB_A)); + CIFISP_DPRINT(level, " afm_lt_b: %d\n", + cifisp_ioread32(CIF_ISP_AFM_LT_B)); + CIFISP_DPRINT(level, " afm_rb_b: %d\n", + cifisp_ioread32(CIF_ISP_AFM_RB_B)); + CIFISP_DPRINT(level, " afm_lt_c: %d\n", + cifisp_ioread32(CIF_ISP_AFM_LT_C)); + CIFISP_DPRINT(level, " afm_rb_c: %d\n", + cifisp_ioread32(CIF_ISP_AFM_RB_C)); + CIFISP_DPRINT(level, " afm_thres: %d\n", + cifisp_ioread32(CIF_ISP_AFM_THRES)); + CIFISP_DPRINT(level, " afm_var_shift: %d\n", + cifisp_ioread32(CIF_ISP_AFM_VAR_SHIFT)); + CIFISP_DPRINT(level, + "#### %s: YCFLT Registers - END ####\n", + ISP_VDEV_NAME); + } + break; + default: + CIFISP_DPRINT(level, "####%s: Invalid Module ID ####\n", + ISP_VDEV_NAME); + break; + } +} +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_isp.h b/drivers/media/platform/rk-isp10/cif_isp10_isp.h new file mode 100644 index 000000000000..27f6bb6873c1 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_isp.h @@ -0,0 +1,133 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _CIF_ISP10_ISP_H +#define _CIF_ISP10_ISP_H + +#include +#include +#include +#include + +/* + * ISP device struct + */ +enum cif_isp10_pix_fmt; + +enum cif_isp10_pix_fmt_quantization { + CIF_ISP10_QUANTIZATION_DEFAULT = 0, + CIF_ISP10_QUANTIZATION_FULL_RANGE = 1, + CIF_ISP10_QUANTIZATION_LIM_RANGE = 2 +}; + +struct cif_isp10_isp_other_cfgs { + struct cifisp_isp_other_cfg *last_or_new; + struct cifisp_isp_other_cfg *curr; + struct cifisp_isp_other_cfg cfgs[2]; + unsigned int module_updates; +}; + +struct cif_isp10_isp_meas_cfgs { + struct cifisp_isp_meas_cfg *last_or_new; + struct cifisp_isp_meas_cfg *curr; + struct cifisp_isp_meas_cfg cfgs[2]; + unsigned int module_updates; +}; + +struct cif_isp10_isp_meas_stats { + unsigned int g_frame_id; + struct cifisp_stat_buffer stat; +}; + +struct cif_isp10_isp_dev { + /* + * Purpose of mutex is to protect and serialize use + * of isp data structure and CIF API calls. + */ + struct mutex mutex; + /* Current ISP parameters */ + spinlock_t config_lock; + struct cif_isp10_isp_other_cfgs other_cfgs; + struct cif_isp10_isp_meas_cfgs meas_cfgs; + struct cif_isp10_isp_meas_stats meas_stats; + + bool cif_ism_cropping; + + enum cif_isp10_pix_fmt_quantization quantization; + + /* input resolution needed for LSC param check */ + unsigned int input_width; + unsigned int input_height; + unsigned int active_lsc_width; + unsigned int active_lsc_height; + + /* ISP statistics related */ + spinlock_t irq_lock; + /* ISP statistics related */ + spinlock_t req_lock; + struct videobuf_queue vbq_stat; + struct list_head stat; + void __iomem *base_addr; /* registers base address */ + + bool streamon; + unsigned int v_blanking_us; + + unsigned int frame_id; + unsigned int frame_id_setexp; + unsigned int active_meas; + + struct timeval vs_t; /* updated each frame */ + struct timeval fi_t; /* updated each frame */ + struct workqueue_struct *readout_wq; + + unsigned int *dev_id; +}; + +enum cif_isp10_isp_readout_cmd { + CIF_ISP10_ISP_READOUT_MEAS = 0, + CIF_ISP10_ISP_READOUT_META = 1, +}; + +struct cif_isp10_isp_readout_work { + struct work_struct work; + struct cif_isp10_isp_dev *isp_dev; + + unsigned int frame_id; + enum cif_isp10_isp_readout_cmd readout; + struct videobuf_buffer *vb; + unsigned int stream_id; +}; + +int register_cifisp_device( + struct cif_isp10_isp_dev *isp_dev, + struct video_device *vdev_cifisp, + struct v4l2_device *v4l2_dev, + void __iomem *cif_reg_baseaddress); +void unregister_cifisp_device(struct video_device *vdev_cifisp); +void cifisp_configure_isp( + struct cif_isp10_isp_dev *isp_dev, + enum cif_isp10_pix_fmt in_pix_fmt, + enum cif_isp10_pix_fmt_quantization quantization); +void cifisp_disable_isp(struct cif_isp10_isp_dev *isp_dev); +int cifisp_isp_isr(struct cif_isp10_isp_dev *isp_dev, u32 isp_mis); +void cifisp_v_start(struct cif_isp10_isp_dev *isp_dev, + const struct timeval *timestamp); +void cifisp_frame_in( + struct cif_isp10_isp_dev *isp_dev, + const struct timeval *fi_t); +void cifisp_isp_readout_work(struct work_struct *work); + +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_pltfrm.c b/drivers/media/platform/rk-isp10/cif_isp10_pltfrm.c new file mode 100644 index 000000000000..126a0375faa9 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_pltfrm.c @@ -0,0 +1,1443 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef CONFIG_OF +#error "this driver requires a kernel with device tree support" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cif_isp10.h" +#include +#include "cif_isp10_regs.h" +#ifndef CONFIG_DEBUG_FS +#include +#include +#include +#ifdef CONFIG_CIF_ISP10_REG_TRACE +#include + +static struct { + char *reg_trace; + loff_t reg_trace_read_pos; + loff_t reg_trace_write_pos; + size_t reg_trace_max_size; + void __iomem *base_addr; + bool rtrace; + bool ftrace; + bool internal; + spinlock_t lock;/* spin lock */ +} cif_isp10_reg_trace; +#endif +#endif + +struct cif_isp10_pltfrm_csi_config { + struct list_head list; + u32 pps; + struct cif_isp10_csi_config csi_config; +}; + +struct cif_isp10_pltfrm_data { + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_sleep; + struct pinctrl_state *pins_inactive; + void __iomem *base_addr; + int irq; + struct { + int mis; + int (*isr)(unsigned int mis, void *cntxt); + } irq_handlers[4]; + struct list_head csi0_configs; + struct list_head csi1_configs; + s32 exp_time; + u16 gain; + +#ifndef CONFIG_DEBUG_FS + struct { + struct dentry *dir; + struct dentry *cif_isp10_file; + struct dentry *csi0_file; + struct dentry *csi1_file; +#ifdef CONFIG_CIF_ISP10_REG_TRACE + struct dentry *reg_trace_file; +#endif + void (*print_func)(void *cntxt, const char *block_name); + void *print_cntxt; + } dbgfs; +#endif +}; + +void cif_isp10_pltfrm_debug_register_print_cb( + struct device *dev, + void (*print)(void *cntxt, const char *block), + void *cntxt) { +#ifndef CONFIG_DEBUG_FS + struct cif_isp10_pltfrm_data *pdata = dev->platform_data; + + pdata->dbgfs.print_cntxt = cntxt; + pdata->dbgfs.print_func = print; +#endif +} + +#ifndef CONFIG_DEBUG_FS +#define CIF_ISP10_DBGFS_BUF_SIZE 1024 +static char cif_isp10_dbgfs_buf[CIF_ISP10_DBGFS_BUF_SIZE]; + +static int cif_isp10_dbgfs_fill_csi_config_from_string( + struct device *dev, + struct cif_isp10_csi_config *csi_config, + char *strp) +{ + char *token; + + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) + goto missing_token; + if (IS_ERR_VALUE(kstrtou32(token, 10, + &csi_config->vc))) + goto wrong_token_format; + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) + goto missing_token; + if (IS_ERR_VALUE(kstrtou32(token, 10, + &csi_config->nb_lanes))) + goto wrong_token_format; + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) + goto missing_token; + if (IS_ERR_VALUE(kstrtou32(token, 16, + &csi_config->dphy1))) + goto wrong_token_format; + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) + goto missing_token; + if (IS_ERR_VALUE(kstrtou32(token, 16, + &csi_config->dphy2))) + goto wrong_token_format; + token = strsep(&strp, " "); + if (!IS_ERR_OR_NULL(token)) { + if (IS_ERR_VALUE(kstrtou32(token, 10, + &csi_config->ana_bandgab_bias))) + goto wrong_token_format; + } else { + csi_config->ana_bandgab_bias = (u32)-1; + } + + return 0; +missing_token: + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'push <#lanes> '\n"); + return -EINVAL; +wrong_token_format: + cif_isp10_pltfrm_pr_err(dev, + "wrong token format, command format is 'push <#lanes> '\n"); + return -EINVAL; +} + +static int cif_isp10_dbgfs_csi_configs_init( + struct device *dev, + enum cif_isp10_inp inp, + struct list_head *csi_configs) +{ + int ret = 0; + struct device *img_src_dev = NULL; + struct device_node *parent_node = NULL; + struct device_node *child_node = NULL, *prev_node = NULL; + struct cif_isp10_pltfrm_csi_config *cfg = NULL; + u32 pps; + + img_src_dev = cif_isp10_pltfrm_get_img_src_device(dev, inp); + if (IS_ERR_OR_NULL(img_src_dev)) { + ret = -EFAULT; + goto err; + } + parent_node = of_node_get(img_src_dev->of_node); + put_device(img_src_dev); + img_src_dev = NULL; + + while (!IS_ERR_OR_NULL(child_node = + of_get_next_child(parent_node, prev_node))) { + if (!strncasecmp(child_node->name, + "intel,camera-module-csi-config", + strlen("intel,camera-module-csi-config"))) { + ret = of_property_read_u32(child_node, + "intel,csi-pixels-per-second", &pps); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(dev, + "reading property 'intel,csi-pixels-per-second'\n"); + goto err; + } + cfg = kmalloc( + sizeof(struct cif_isp10_pltfrm_csi_config), + GFP_KERNEL); + if (!cfg) { + cif_isp10_pltfrm_pr_err(dev, + "memory allocation failed\n"); + ret = -ENOMEM; + goto err; + } + cfg->pps = pps; + ret = cif_isp10_pltfrm_fill_csi_config_from_node( + dev, &cfg->csi_config, child_node); + if (IS_ERR_VALUE(ret)) + goto err; + list_add_tail(&cfg->list, csi_configs); + cfg = NULL; + } + of_node_put(prev_node); + prev_node = child_node; + } + of_node_put(prev_node); + of_node_put(parent_node); + + return 0; +err: + of_node_put(prev_node); + of_node_put(child_node); + of_node_put(parent_node); + kfree(cfg); + if (!IS_ERR_OR_NULL(img_src_dev)) + put_device(img_src_dev); + return ret; +} + +static ssize_t cif_isp10_dbgfs_csi_read( + struct file *f, + char __user *out, + size_t count, + loff_t *pos) +{ + u32 out_size = 0; + u32 str_len; + struct cif_isp10_pltfrm_csi_config *cfg; + u32 index = 0; + struct list_head *list_pos; + struct device *dev = f->f_inode->i_private; + struct cif_isp10_pltfrm_data *pdata = dev->platform_data; + struct list_head *csi_configs; + enum cif_isp10_inp inp; + + if (f->f_inode == pdata->dbgfs.csi0_file->d_inode) { + csi_configs = &pdata->csi0_configs; + inp = CIF_ISP10_INP_CSI_0; + } else if (f->f_inode == pdata->dbgfs.csi1_file->d_inode) { + csi_configs = &pdata->csi1_configs; + inp = CIF_ISP10_INP_CSI_1; + } else { + cif_isp10_pltfrm_pr_err(dev, "wrong file handle\n"); + return -EINVAL; + } + + if (list_empty(csi_configs)) + if (IS_ERR_VALUE(cif_isp10_dbgfs_csi_configs_init( + dev, inp, csi_configs))) + return -EFAULT; + + if (*pos) + return 0; + + list_for_each(list_pos, csi_configs) { + cfg = list_entry(list_pos, + struct cif_isp10_pltfrm_csi_config, list); + sprintf(cif_isp10_dbgfs_buf, + "csi-config-%d:\n" + " pps = %d\n" + " vc = %d\n" + " nb_lanes = %d\n" + " dphy1 = 0x%08x\n" + " dphy2 = 0x%08x\n" + " ana_bandgap_bias = %d\n", + index, + cfg->pps, cfg->csi_config.vc, cfg->csi_config.nb_lanes, + cfg->csi_config.dphy1, cfg->csi_config.dphy2, + cfg->csi_config.ana_bandgab_bias); + index++; + str_len = strnlen(cif_isp10_dbgfs_buf, + CIF_ISP10_DBGFS_BUF_SIZE); + if (str_len > count) { + *pos += out_size; + return 0; + } + *pos = 0; + if (IS_ERR_VALUE(simple_read_from_buffer( + out + out_size, str_len, pos, + cif_isp10_dbgfs_buf, str_len))) + break; + out_size += strnlen(cif_isp10_dbgfs_buf, + CIF_ISP10_DBGFS_BUF_SIZE); + count -= str_len; + } + + *pos += out_size; + return out_size; +} + +static ssize_t cif_isp10_dbgfs_csi_write( + struct file *f, + const char __user *in, + size_t count, + loff_t *pos) +{ + ssize_t ret; + char *strp = cif_isp10_dbgfs_buf; + char *token; + struct device *dev = f->f_inode->i_private; + struct cif_isp10_pltfrm_data *pdata = dev->platform_data; + struct list_head *csi_configs; + enum cif_isp10_inp inp; + + if (count > CIF_ISP10_DBGFS_BUF_SIZE) { + cif_isp10_pltfrm_pr_err(dev, "command line too large\n"); + return -EINVAL; + } + + if (f->f_inode == pdata->dbgfs.csi0_file->d_inode) { + csi_configs = &pdata->csi0_configs; + inp = CIF_ISP10_INP_CSI_0; + } else if (f->f_inode == pdata->dbgfs.csi1_file->d_inode) { + csi_configs = &pdata->csi1_configs; + inp = CIF_ISP10_INP_CSI_1; + } else { + cif_isp10_pltfrm_pr_err(dev, "wrong file handle\n"); + return -EINVAL; + } + + if (list_empty(csi_configs)) + if (IS_ERR_VALUE(cif_isp10_dbgfs_csi_configs_init( + dev, inp, csi_configs))) + return -EFAULT; + + memset(cif_isp10_dbgfs_buf, 0, CIF_ISP10_DBGFS_BUF_SIZE); + ret = simple_write_to_buffer(strp, + CIF_ISP10_DBGFS_BUF_SIZE, pos, in, count); + if (IS_ERR_VALUE(ret)) + return ret; + + token = strsep(&strp, " "); + if (!strcmp(token, "push")) { + struct cif_isp10_pltfrm_csi_config cfg; + + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'push <#lanes> '\n"); + return -EINVAL; + } + if (IS_ERR_VALUE(kstrtou32(token, 10, + &cfg.pps))) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'push <#lanes> '\n"); + return -EINVAL; + } + ret = cif_isp10_dbgfs_fill_csi_config_from_string( + dev, &cfg.csi_config, strp); + if (IS_ERR_VALUE(ret)) + return ret; + ret = cif_isp10_pltfrm_l_s_csi_config( + dev, inp, cfg.pps, &cfg.csi_config); + if (IS_ERR_VALUE(ret)) + return ret; + } else if (!strncmp(token, "reset", 5)) { + } else { + cif_isp10_pltfrm_pr_err(dev, "unknown command %s\n", token); + return -EINVAL; + } + + return count; +} + +void cif_isp10_dbgfs_fill_sensor_aec_para( + struct cif_isp10_device *cif_isp10_dev, + s32 exp_time, + u16 gain) +{ + struct cif_isp10_pltfrm_data *pdata; + + pdata = (struct cif_isp10_pltfrm_data *) + cif_isp10_dev->dev->platform_data; + pdata->exp_time = exp_time; + pdata->gain = gain; +} + +static ssize_t cif_isp10_dbgfs_sensor_read( + struct file *f, + char __user *out, + size_t count, + loff_t *pos) +{ + u32 out_size = 0; + u32 str_len; + struct device *dev = f->f_inode->i_private; + struct cif_isp10_pltfrm_data *pdata = dev->platform_data; + + if (*pos) + return 0; + + sprintf(cif_isp10_dbgfs_buf, + "sensor current exp_time: %d\n" + " gain = %d\n", + pdata->exp_time, + pdata->gain); + str_len = strnlen(cif_isp10_dbgfs_buf, + CIF_ISP10_DBGFS_BUF_SIZE); + if (str_len > count) { + *pos += out_size; + return 0; + } + *pos = 0; + if (IS_ERR_VALUE(simple_read_from_buffer( + out + out_size, str_len, pos, + cif_isp10_dbgfs_buf, str_len))) + goto ERR; + out_size += strnlen(cif_isp10_dbgfs_buf, + CIF_ISP10_DBGFS_BUF_SIZE); + count -= str_len; + + *pos += out_size; +ERR: + return out_size; +} + +static ssize_t cif_isp10_dbgfs_sensor_write( + struct file *f, + const char __user *in, + size_t count, + loff_t *pos) +{ + return 0; +} + +static ssize_t cif_isp10_dbgfs_write( + struct file *f, + const char __user *in, + size_t count, + loff_t *pos) +{ + ssize_t ret; + char *strp = cif_isp10_dbgfs_buf; + char *token; + struct device *dev = f->f_inode->i_private; + struct cif_isp10_pltfrm_data *pdata = dev->platform_data; + + if (count > CIF_ISP10_DBGFS_BUF_SIZE) { + cif_isp10_pltfrm_pr_err(dev, "command line too large\n"); + return -EINVAL; + } + + memset(cif_isp10_dbgfs_buf, 0, CIF_ISP10_DBGFS_BUF_SIZE); + ret = simple_write_to_buffer(strp, + CIF_ISP10_DBGFS_BUF_SIZE, pos, in, count); + if (IS_ERR_VALUE(ret)) + return ret; + + token = strsep(&strp, " "); + if (!strncmp(token, "print", 5)) { + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'print all|'\n"); + return -EINVAL; + } + if (!strncmp(token, "register", 8)) { + u32 addr; + struct cif_isp10_pltfrm_data *pdata = + dev->platform_data; + token = strsep(&strp, " "); + while (token) { + if (IS_ERR_VALUE(kstrtou32(token, + 16, &addr))) { + cif_isp10_pltfrm_pr_err(dev, + "malformed token, must be a hexadecimal register address\n"); + return -EINVAL; + } + pr_info("0x%04x: 0x%08x\n", + addr, + ioread32(pdata->base_addr + + addr)); + token = strsep(&strp, " "); + } + } else if (pdata->dbgfs.print_func) { + unsigned long flags; + + local_irq_save(flags); + while (token) { + pdata->dbgfs.print_func( + pdata->dbgfs.print_cntxt, + token); + token = strsep(&strp, " "); + } + local_irq_restore(flags); + } + } else if (!strncmp(token, "power", 5)) { + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'power [off|on]'\n"); + return -EINVAL; + } + if (!strncmp(token, "on", 2)) { + if (IS_ERR_VALUE(cif_isp10_pltfrm_pm_set_state(dev, + CIF_ISP10_PM_STATE_SW_STNDBY, NULL))) + cif_isp10_pltfrm_pr_err(dev, + "power on failed\n"); + else + cif_isp10_pltfrm_pr_info(dev, + "switched on\n"); + } else if (!strncmp(token, "off", 3)) { + if (IS_ERR_VALUE(cif_isp10_pltfrm_pm_set_state(dev, + CIF_ISP10_PM_STATE_OFF, NULL))) + cif_isp10_pltfrm_pr_err(dev, + "power off failed\n"); + else + cif_isp10_pltfrm_pr_info(dev, + "switched off\n"); + } else { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'power [off|on]'\n"); + return -EINVAL; + } + } else if (!strncmp(token, "set", 3)) { + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'set register ='\n"); + return -EINVAL; + } + if (!strncmp(token, "register", 8)) { + u32 addr; + u32 val; + struct cif_isp10_pltfrm_data *pdata = + dev->platform_data; + token = strsep(&strp, "="); + if (IS_ERR_VALUE(kstrtou32(token, + 16, &addr))) { + cif_isp10_pltfrm_pr_err(dev, + "malformed token, address must be a hexadecimal register address\n"); + return -EINVAL; + } + token = strp; + if (IS_ERR_VALUE(kstrtou32(token, + 16, &val))) { + cif_isp10_pltfrm_pr_err(dev, + "malformed token, value must be a hexadecimal value\n"); + return -EINVAL; + } + iowrite32(val, pdata->base_addr + addr); + } else { + cif_isp10_pltfrm_pr_err(dev, + "unknown command %s\n", token); + return -EINVAL; + } + } else { + cif_isp10_pltfrm_pr_err(dev, + "unknown command %s\n", token); + return -EINVAL; + } + return count; +} + +static const struct file_operations cif_isp10_dbgfs_csi_fops = { + .read = cif_isp10_dbgfs_csi_read, + .write = cif_isp10_dbgfs_csi_write +}; + +static const struct file_operations cif_isp10_dbgfs_fops = { + .write = cif_isp10_dbgfs_write +}; + +static const struct file_operations cif_isp10_dbgfs_sensor_fops = { + .read = cif_isp10_dbgfs_sensor_read, + .write = cif_isp10_dbgfs_sensor_write +}; + +#ifdef CONFIG_CIF_ISP10_REG_TRACE + +static inline int cif_isp10_pltfrm_trace_printf( + struct device *dev, + const char *fmt, + va_list args) +{ + int i; + u32 rem_size; + unsigned long flags = 0; + + if (!in_irq()) + spin_lock_irqsave(&cif_isp10_reg_trace.lock, flags); + cif_isp10_reg_trace.internal = true; + + rem_size = cif_isp10_reg_trace.reg_trace_max_size - + cif_isp10_reg_trace.reg_trace_write_pos; + + if (rem_size <= 0) { + if (!in_irq()) + spin_unlock_irqrestore( + &cif_isp10_reg_trace.lock, flags); + cif_isp10_reg_trace.internal = false; + return 0; + } + + i = vsnprintf(cif_isp10_reg_trace.reg_trace + + cif_isp10_reg_trace.reg_trace_write_pos, + rem_size, + fmt, args); + if (i == rem_size) /* buffer full */ + i = 0; + else if (i < 0) + cif_isp10_pltfrm_pr_err(dev, + "error writing trace buffer, error %d\n", i); + else + cif_isp10_reg_trace.reg_trace_write_pos += i; + cif_isp10_reg_trace.internal = false; + if (!in_irq()) + spin_unlock_irqrestore(&cif_isp10_reg_trace.lock, flags); + + return i; +} + +inline int cif_isp10_pltfrm_rtrace_printf( + struct device *dev, + const char *fmt, + ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = cif_isp10_pltfrm_trace_printf(dev, fmt, args); + va_end(args); + + return i; +} + +inline int cif_isp10_pltfrm_ftrace_printf( + struct device *dev, + const char *fmt, + ...) +{ + va_list args; + int i; + + if (!cif_isp10_reg_trace.ftrace || + cif_isp10_reg_trace.internal) + return 0; + + va_start(args, fmt); + i = cif_isp10_pltfrm_trace_printf(dev, fmt, args); + va_end(args); + + return i; +} + +static void cif_isp10_dbgfs_reg_trace_clear( + struct device *dev) +{ + cif_isp10_reg_trace.reg_trace_write_pos = 0; + cif_isp10_reg_trace.reg_trace_read_pos = 0; +} + +static ssize_t cif_isp10_dbgfs_reg_trace_read( + struct file *f, + char __user *out, + size_t count, + loff_t *pos) +{ + ssize_t bytes; + size_t available = cif_isp10_reg_trace.reg_trace_write_pos - + cif_isp10_reg_trace.reg_trace_read_pos; + size_t rem = count; + + cif_isp10_reg_trace.internal = true; + + if (!available) + cif_isp10_reg_trace.reg_trace_read_pos = 0; + + while (rem && available) { + bytes = simple_read_from_buffer( + out + (count - rem), count, + &cif_isp10_reg_trace.reg_trace_read_pos, + cif_isp10_reg_trace.reg_trace, + cif_isp10_reg_trace.reg_trace_write_pos); + if (bytes < 0) { + cif_isp10_pltfrm_pr_err(NULL, + "buffer read failed with error %d\n", + bytes); + cif_isp10_reg_trace.internal = false; + return bytes; + } + rem -= bytes; + available = cif_isp10_reg_trace.reg_trace_write_pos - + cif_isp10_reg_trace.reg_trace_read_pos; + } + + cif_isp10_reg_trace.internal = false; + return count - rem; +} + +static ssize_t cif_isp10_dbgfs_reg_trace_write( + struct file *f, + const char __user *in, + size_t count, + loff_t *pos) +{ + ssize_t ret; + char *strp = cif_isp10_dbgfs_buf; + char *token; + struct device *dev = f->f_inode->i_private; + u32 max_size; + unsigned long flags = 0; + + if (!in_irq()) + spin_lock_irqsave(&cif_isp10_reg_trace.lock, flags); + + cif_isp10_reg_trace.internal = true; + + if (count > CIF_ISP10_DBGFS_BUF_SIZE) { + cif_isp10_pltfrm_pr_err(dev, "command line too long\n"); + return -EINVAL; + } + + memset(cif_isp10_dbgfs_buf, 0, CIF_ISP10_DBGFS_BUF_SIZE); + ret = simple_write_to_buffer(strp, + CIF_ISP10_DBGFS_BUF_SIZE, pos, in, count); + if (IS_ERR_VALUE(ret)) + goto err; + + token = strsep(&strp, " "); + if (!strncmp(token, "clear", 5)) { + cif_isp10_dbgfs_reg_trace_clear(dev); + cif_isp10_pltfrm_pr_info(dev, + "register trace buffer cleared\n"); + } else if (!strcmp(token, "size")) { + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'size '\n"); + ret = -EINVAL; + goto err; + } + if (IS_ERR_VALUE(kstrtou32(token, 10, + &max_size))) { + cif_isp10_pltfrm_pr_err(dev, + "wrong token format, must be positive integer>'\n"); + ret = -EINVAL; + goto err; + } + if (cif_isp10_reg_trace.reg_trace) { + devm_kfree(dev, cif_isp10_reg_trace.reg_trace); + cif_isp10_reg_trace.reg_trace = NULL; + } + cif_isp10_dbgfs_reg_trace_clear(dev); + if (max_size > 0) { + cif_isp10_reg_trace.reg_trace = devm_kzalloc(dev, + max_size, GFP_KERNEL); + if (!cif_isp10_reg_trace.reg_trace) { + cif_isp10_pltfrm_pr_err(dev, + "memory allocation failed\n"); + ret = -ENOMEM; + goto err; + } + cif_isp10_reg_trace.reg_trace_max_size = max_size; + cif_isp10_pltfrm_pr_info(dev, + "register trace buffer size set to %d Byte\n", + max_size); + } + } else if (!strncmp(token, "rtrace", 6)) { + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'rtrace [off|on]'\n"); + ret = -EINVAL; + goto err; + } + if (!strncmp(token, "on", 2)) { + cif_isp10_reg_trace.rtrace = true; + cif_isp10_pltfrm_pr_info(dev, + "register trace enabled\n"); + } else if (!strncmp(token, "off", 3)) { + cif_isp10_reg_trace.rtrace = false; + cif_isp10_pltfrm_pr_info(dev, + "register trace disabled\n"); + } else { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'rtrace [off|on]'\n"); + ret = -EINVAL; + goto err; + } + } else if (!strncmp(token, "ftrace", 6)) { + token = strsep(&strp, " "); + if (IS_ERR_OR_NULL(token)) { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'ftrace [off|on]'\n"); + ret = -EINVAL; + goto err; + } + if (!strncmp(token, "on", 2)) { + cif_isp10_reg_trace.ftrace = true; + cif_isp10_pltfrm_pr_info(dev, + "function trace enabled\n"); + } else if (!strncmp(token, "off", 3)) { + cif_isp10_reg_trace.ftrace = false; + cif_isp10_pltfrm_pr_info(dev, + "function trace disabled\n"); + } else { + cif_isp10_pltfrm_pr_err(dev, + "missing token, command format is 'ftrace [off|on]'\n"); + ret = -EINVAL; + goto err; + } + } else { + cif_isp10_pltfrm_pr_err(dev, "unknown command %s\n", token); + ret = -EINVAL; + goto err; + } + cif_isp10_reg_trace.internal = false; + if (!in_irq()) + spin_unlock_irqrestore(&cif_isp10_reg_trace.lock, flags); + return count; +err: + cif_isp10_reg_trace.internal = false; + if (!in_irq()) + spin_unlock_irqrestore(&cif_isp10_reg_trace.lock, flags); + return ret; +} + +static const struct file_operations +cif_isp10_dbgfs_reg_trace_fops = { + .read = cif_isp10_dbgfs_reg_trace_read, + .write = cif_isp10_dbgfs_reg_trace_write +}; + +#endif +#endif + +static irqreturn_t cif_isp10_pltfrm_irq_handler(int irq, void *cntxt) +{ + unsigned int i, mis_val; + int ret; + struct device *dev = cntxt; + struct cif_isp10_pltfrm_data *pdata = + dev_get_platdata(dev); + void *cif_isp10_dev = dev_get_drvdata(dev); + + if (irq != pdata->irq) + return IRQ_NONE; + + for (i = 0; i < ARRAY_SIZE(pdata->irq_handlers); i++) { + if (IS_ERR_VALUE(pdata->irq_handlers[i].mis)) + break; + + if (IS_ERR_OR_NULL(pdata->irq_handlers[i].isr)) { + cif_isp10_pltfrm_pr_err(NULL, + "ISR for IRQ #%d not set\n", irq); + break; + } + + mis_val = cif_ioread32(pdata->base_addr + + pdata->irq_handlers[i].mis); + if (mis_val == 0) + continue; + + ret = pdata->irq_handlers[i].isr(mis_val, cif_isp10_dev); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(NULL, + "ISR for IRQ #%d failed with error %d\n", + irq, ret); + } + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +const char *cif_isp10_pltfrm_pm_state_string( + enum cif_isp10_pm_state pm_state) +{ + switch (pm_state) { + case CIF_ISP10_PM_STATE_OFF: + return "CIF_ISP10_PM_STATE_OFF"; + case CIF_ISP10_PM_STATE_SUSPENDED: + return "CIF_ISP10_PM_STATE_SUSPENDED"; + case CIF_ISP10_PM_STATE_SW_STNDBY: + return "CIF_ISP10_PM_STATE_SW_STNDBY"; + case CIF_ISP10_PM_STATE_STREAMING: + return "CIF_ISP10_PM_STATE_STREAMING"; + default: + return "PM_STATE_UNKNOWN"; + } +} + +inline void cif_isp10_pltfrm_write_reg( + struct device *dev, + u32 data, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr) +{ + iowrite32(data, addr); +#ifdef CONFIG_CIF_ISP10_REG_TRACE + { + unsigned long flags = 0; + + if (!in_irq()) + spin_lock_irqsave(&cif_isp10_reg_trace.lock, flags); + cif_isp10_reg_trace.internal = true; + if (((cif_isp10_reg_trace.reg_trace_write_pos + + (20 * sizeof(char))) < + cif_isp10_reg_trace.reg_trace_max_size) && + cif_isp10_reg_trace.rtrace) { + int bytes = + sprintf(cif_isp10_reg_trace.reg_trace + + cif_isp10_reg_trace.reg_trace_write_pos, + "%04x %08x\n", + addr - cif_isp10_reg_trace.base_addr, + data); + if (bytes > 0) + cif_isp10_reg_trace.reg_trace_write_pos += + bytes; + else + cif_isp10_pltfrm_pr_err(dev, + "error writing trace buffer, error %d\n", + bytes); + } + cif_isp10_reg_trace.internal = false; + if (!in_irq()) + spin_unlock_irqrestore( + &cif_isp10_reg_trace.lock, flags); + } +#endif +} + +inline void cif_isp10_pltfrm_write_reg_OR( + struct device *dev, + u32 data, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr) +{ + cif_isp10_pltfrm_write_reg(dev, + (ioread32(addr) | data), addr); +} + +inline void cif_isp10_pltfrm_write_reg_AND( + struct device *dev, + u32 data, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr) +{ + cif_isp10_pltfrm_write_reg(dev, + (ioread32(addr) & data), addr); +} + +inline u32 cif_isp10_pltfrm_read_reg( + struct device *dev, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr) +{ + return ioread32(addr); +} + +int cif_isp10_pltfrm_dev_init( + struct cif_isp10_device *cif_isp10_dev, + struct device **_dev, + void __iomem **reg_base_addr) +{ + int ret; + struct cif_isp10_pltfrm_data *pdata; + struct device *dev = *_dev; + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + struct resource *res; + void __iomem *base_addr; + unsigned int i, irq; + + dev_set_drvdata(dev, cif_isp10_dev); + cif_isp10_dev->dev = dev; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + cif_isp10_pltfrm_pr_err(dev, + "could not allocate memory for platform data\n"); + ret = -ENOMEM; + goto err; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "register"); + if (!res) { + cif_isp10_pltfrm_pr_err(NULL, + "platform_get_resource_byname failed\n"); + ret = -ENODEV; + goto err; + } + base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR_OR_NULL(base_addr)) { + cif_isp10_pltfrm_pr_err(NULL, "devm_ioremap_resource failed\n"); + if (IS_ERR(base_addr)) + ret = PTR_ERR(base_addr); + else + ret = -ENODEV; + } + *reg_base_addr = base_addr; + pdata->base_addr = base_addr; + + irq = platform_get_irq_byname(pdev, "cif_isp10_irq"); + if (IS_ERR_VALUE(irq)) { + ret = irq; + cif_isp10_pltfrm_pr_err(NULL, + "platform_get_irq_byname failed\n"); + goto err; + } + + ret = devm_request_threaded_irq(dev, + irq, + cif_isp10_pltfrm_irq_handler, + NULL, + 0, + dev_driver_string(dev), + dev); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(NULL, + "devm_request_threaded_irq failed\n"); + goto err; + } + pdata->irq = irq; + + pdata->pinctrl = devm_pinctrl_get(dev); + if (!IS_ERR_OR_NULL(pdata->pinctrl)) { + pdata->pins_default = pinctrl_lookup_state(pdata->pinctrl, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(pdata->pins_default)) + cif_isp10_pltfrm_pr_err(dev, + "could not get default pinstate\n"); + + pdata->pins_sleep = pinctrl_lookup_state(pdata->pinctrl, + PINCTRL_STATE_SLEEP); + if (IS_ERR(pdata->pins_sleep)) + cif_isp10_pltfrm_pr_warn(dev, + "could not get pins_sleep pinstate\n"); + + pdata->pins_inactive = pinctrl_lookup_state(pdata->pinctrl, + "inactive"); + if (IS_ERR(pdata->pins_inactive)) + cif_isp10_pltfrm_pr_warn(dev, + "could not get pins_inactive pinstate\n"); + + if (!IS_ERR_OR_NULL(pdata->pins_default)) + pinctrl_select_state(pdata->pinctrl, + pdata->pins_default); + } + + for (i = 0; i < ARRAY_SIZE(pdata->irq_handlers); i++) + pdata->irq_handlers[i].mis = -EINVAL; + + dev->platform_data = pdata; + + INIT_LIST_HEAD(&pdata->csi0_configs); + INIT_LIST_HEAD(&pdata->csi1_configs); + +#ifndef CONFIG_DEBUG_FS + pdata->dbgfs.dir = debugfs_create_dir("cif_isp10", NULL); + pdata->dbgfs.csi0_file = debugfs_create_file( + "csi-0", + 0644, + pdata->dbgfs.dir, + dev, + &cif_isp10_dbgfs_csi_fops); + pdata->dbgfs.csi1_file = debugfs_create_file( + "csi-1", + 0644, + pdata->dbgfs.dir, + dev, + &cif_isp10_dbgfs_csi_fops); + pdata->dbgfs.cif_isp10_file = debugfs_create_file( + "cif_isp20", + 0200, + pdata->dbgfs.dir, + dev, + &cif_isp10_dbgfs_fops); + pdata->dbgfs.cif_isp10_file = debugfs_create_file( + "sensor", + 0644, + pdata->dbgfs.dir, + dev, + &cif_isp10_dbgfs_sensor_fops); +#ifdef CONFIG_CIF_ISP10_REG_TRACE + pdata->dbgfs.reg_trace_file = debugfs_create_file( + "reg_trace", + 0644, + pdata->dbgfs.dir, + dev, + &cif_isp10_dbgfs_reg_trace_fops); + spin_lock_init(&cif_isp10_reg_trace.lock); + cif_isp10_reg_trace.reg_trace = NULL; + cif_isp10_dbgfs_reg_trace_clear(dev); + cif_isp10_reg_trace.reg_trace_max_size = 0; + cif_isp10_reg_trace.base_addr = base_addr; + cif_isp10_reg_trace.rtrace = true; + cif_isp10_reg_trace.ftrace = false; + cif_isp10_reg_trace.internal = false; +#endif +#endif + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, "failed with error %d\n", ret); + if (!IS_ERR_OR_NULL(pdata)) + devm_kfree(dev, pdata); + return ret; +} + +int cif_isp10_pltfrm_soc_init( + struct cif_isp10_device *cif_isp10_dev, + struct pltfrm_soc_cfg *soc_cfg) +{ + struct pltfrm_soc_cfg_para cfg_para; + struct device *dev = cif_isp10_dev->dev; + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + struct pltfrm_soc_init_para init_para; + int ret = 0; + + if (!IS_ERR_OR_NULL(soc_cfg) && !IS_ERR_OR_NULL(soc_cfg->soc_cfg)) { + cfg_para.cmd = PLTFRM_SOC_INIT; + cfg_para.cfg_para = &init_para; + init_para.pdev = pdev; + init_para.isp_base = cif_isp10_dev->config.base_addr; + ret = soc_cfg->soc_cfg(&cfg_para); + if (ret == 0) + cif_isp10_dev->soc_cfg = soc_cfg; + } + + return ret; +} + +int cif_isp10_pltfrm_mipi_dphy_config( + struct cif_isp10_device *cif_isp10_dev) +{ + struct pltfrm_soc_cfg_para cfg_para; + struct pltfrm_soc_cfg *soc_cfg; + int ret = 0; + + soc_cfg = cif_isp10_dev->soc_cfg; + if (!IS_ERR_OR_NULL(soc_cfg) && + !IS_ERR_OR_NULL(soc_cfg->soc_cfg)) { + cfg_para.cmd = + PLTFRM_MIPI_DPHY_CFG; + cfg_para.cfg_para = + (void *)(&cif_isp10_dev->config.cam_itf.cfg.mipi); + ret = soc_cfg->soc_cfg(&cfg_para); + } + + return ret; +} + +int cif_isp10_pltfrm_pm_set_state( + struct device *dev, + enum cif_isp10_pm_state pm_state) +{ + int ret; + struct cif_isp10_device *cif_isp10_dev = dev_get_drvdata(dev); + struct pltfrm_soc_cfg *soc_cfg = cif_isp10_dev->soc_cfg; + struct pltfrm_soc_cfg_para cfg_para; + + switch (pm_state) { + case CIF_ISP10_PM_STATE_OFF: + case CIF_ISP10_PM_STATE_SUSPENDED: + cfg_para.cmd = PLTFRM_CLKDIS; + cfg_para.cfg_para = NULL; + ret = soc_cfg->soc_cfg(&cfg_para); + break; + case CIF_ISP10_PM_STATE_SW_STNDBY: + case CIF_ISP10_PM_STATE_STREAMING: + cfg_para.cmd = PLTFRM_CLKEN; + cfg_para.cfg_para = NULL; + ret = soc_cfg->soc_cfg(&cfg_para); + break; + default: + cif_isp10_pltfrm_pr_err(dev, + "unknown or unsupported PM state %d\n", pm_state); + return -EINVAL; + } + + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_err(dev, + "setting pm state to %s failed with error %d\n", + cif_isp10_pltfrm_pm_state_string(pm_state), ret); + else + cif_isp10_pltfrm_pr_dbg(dev, + "successfully changed pm state to %s\n", + cif_isp10_pltfrm_pm_state_string(pm_state)); + return ret; +} + +int cif_isp10_pltfrm_g_interface_config( + struct cif_isp10_img_src *img_src, + struct pltfrm_cam_itf *cam_itf) +{ + int ret = 0; + + ret = cif_isp10_img_src_ioctl(img_src, + PLTFRM_CIFCAM_G_ITF_CFG, (void *)cam_itf); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err( + dev, + "cif_isp10_img_src_ioctl PLTFRM_CIFCAM_G_ITF_CFG failed!\n"); + return ret; + } + return 0; +} + +int cif_isp10_pltfrm_pinctrl_set_state( + struct device *dev, + enum cif_isp10_pinctrl_state pinctrl_state) +{ + int ret = 0; + struct cif_isp10_pltfrm_data *pdata = dev_get_platdata(dev); + + cif_isp10_pltfrm_pr_dbg(dev, + "set pinctrl state to %d\n", pinctrl_state); + + if (!pdata) { + cif_isp10_pltfrm_pr_err(dev, + "unable to retrieve CIF platform data\n"); + ret = -EINVAL; + goto err; + } + if (IS_ERR_OR_NULL(pdata->pinctrl)) + return 0; + + switch (pinctrl_state) { + case CIF_ISP10_PINCTRL_STATE_SLEEP: + if (!IS_ERR_OR_NULL(pdata->pins_sleep)) + ret = pinctrl_select_state(pdata->pinctrl, + pdata->pins_sleep); + break; + case CIF_ISP10_PINCTRL_STATE_ACTIVE: + case CIF_ISP10_PINCTRL_STATE_DEFAULT: + if (!IS_ERR_OR_NULL(pdata->pins_default)) + ret = pinctrl_select_state(pdata->pinctrl, + pdata->pins_default); + break; + case CIF_ISP10_PINCTRL_STATE_INACTIVE: + if (!IS_ERR_OR_NULL(pdata->pins_inactive)) + ret = pinctrl_select_state(pdata->pinctrl, + pdata->pins_inactive); + break; + default: + cif_isp10_pltfrm_pr_err(dev, + "unknown or unsupported pinctrl state %d\n", + pinctrl_state); + ret = -EINVAL; + goto err; + } + + if (IS_ERR_VALUE(ret)) + goto err; + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev, "failed with error %d\n", ret); + return ret; +} + +int cif_isp10_pltfrm_irq_register_isr( + struct device *dev, + unsigned int mis, + int (*isr)(unsigned int mis, void *cntxt), + void *cntxt) +{ + int ret = 0; + unsigned int i; + int slot = -EINVAL; + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + struct cif_isp10_pltfrm_data *pdata = + dev_get_platdata(&pdev->dev); + bool skip_request_irq = false; + const char *irq_name; + + switch (mis) { + case CIF_MIPI_MIS: + irq_name = "CIF_ISP10_MIPI_IRQ"; + break; + case CIF_ISP_MIS: + irq_name = "CIF_ISP10_ISP_IRQ"; + break; + case CIF_MI_MIS: + irq_name = "CIF_ISP10_MI_IRQ"; + break; + default: + cif_isp10_pltfrm_pr_err(dev, + "unknown or unsupported IRQ %d\n", mis); + ret = -EINVAL; + goto err; + } + cif_isp10_pltfrm_pr_dbg(dev, + "registering ISR for IRQ %s\n", irq_name); + + for (i = 0; i < ARRAY_SIZE(pdata->irq_handlers); i++) { + if (IS_ERR_VALUE(slot) && + IS_ERR_VALUE(pdata->irq_handlers[i].mis)) + slot = (int)i; + if (pdata->irq_handlers[i].mis == mis) { + cif_isp10_pltfrm_pr_dbg(dev, + "overwriting ISR for IRQ %s\n", irq_name); + slot = (int)i; + skip_request_irq = true; + break; + } + } + if (IS_ERR_VALUE(slot)) { + if (!isr) + return 0; + cif_isp10_pltfrm_pr_err(dev, + "cannot register ISR for IRQ %s, too many ISRs already registered\n", + irq_name); + ret = -EFAULT; + goto err; + } + pdata->irq_handlers[slot].isr = isr; + if (!isr) { + pdata->irq_handlers[slot].mis = -EINVAL; + skip_request_irq = true; + } else { + pdata->irq_handlers[slot].mis = mis; + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(dev, "failed with error %d\n", ret); + return ret; +} + +const char *cif_isp10_pltfrm_get_device_type( + struct device *dev) +{ + return dev->of_node->type; +} + +const char *cif_isp10_pltfrm_dev_string( + struct device *dev) +{ + return dev_driver_string(dev); +} + +int cif_isp10_pltfrm_get_img_src_device( + struct device *dev, + struct cif_isp10_img_src **img_src_array, + unsigned int array_len) +{ + struct device_node *node = NULL; + struct device_node *camera_list_node = NULL; + struct i2c_client *client = NULL; + int ret = 0; + int index, size = 0; + const __be32 *phandle; + int num_cameras = 0; + struct cif_isp10_device *cif_isp10_dev = dev_get_drvdata(dev); + + node = of_node_get(dev->of_node); + if (IS_ERR_OR_NULL(node)) { + dev_err(dev, "Unable to obtain CIF device node\n"); + ret = -EEXIST; + goto err; + } + + phandle = of_get_property(node, + "rockchip,camera-modules-attached", &size); + if (IS_ERR_OR_NULL(phandle)) { + cif_isp10_pltfrm_pr_err(dev, + "no camera-modules-attached'\n"); + ret = -EINVAL; + goto err; + } + + for (index = 0; index < size / sizeof(*phandle); index++) { + camera_list_node = of_parse_phandle(node, + "rockchip,camera-modules-attached", index); + of_node_put(node); + if (IS_ERR_OR_NULL(camera_list_node)) { + cif_isp10_pltfrm_pr_err(dev, + "invalid index %d for property 'rockchip,camera-modules-attached'\n", + index); + ret = -EINVAL; + goto err; + } + + if (!strcmp(camera_list_node->type, + "v4l2-i2c-subdev")) { + client = of_find_i2c_device_by_node( + camera_list_node); + of_node_put(camera_list_node); + if (IS_ERR_OR_NULL(client)) { + cif_isp10_pltfrm_pr_err(dev, + "could not get camera i2c client, maybe not yet created, deferring device probing...\n"); + continue; + } + } else { + cif_isp10_pltfrm_pr_dbg(dev, + "device of type %s not supported\n", + camera_list_node->type); + of_node_put(camera_list_node); + continue; + } + + img_src_array[num_cameras] = + cif_isp10_img_src_to_img_src( + &client->dev, + cif_isp10_dev->soc_cfg); + if (!IS_ERR_OR_NULL(img_src_array[num_cameras])) { + cif_isp10_pltfrm_pr_info(dev, + "%s attach to cif isp10 img_src_array[%d]\n", + cif_isp10_img_src_g_name( + img_src_array[num_cameras]), + num_cameras); + num_cameras++; + if (num_cameras >= array_len) { + cif_isp10_pltfrm_pr_err(dev, + "cif isp10 isn't support > %d 'camera modules attached'\n", + array_len); + break; + } + } else { + continue; + } + } + + return num_cameras; +err: + dev_err(dev, "failed with error %d\n", ret); + if (!IS_ERR_OR_NULL(client)) + put_device(&client->dev); + if (!IS_ERR_OR_NULL(camera_list_node)) + of_node_put(camera_list_node); + return ret; +} + +void cif_isp10_pltfrm_dev_release( + struct device *dev) +{ +#ifndef CONFIG_DEBUG_FS + { + struct cif_isp10_pltfrm_data *pdata = + dev->platform_data; + debugfs_remove(pdata->dbgfs.csi0_file); + debugfs_remove(pdata->dbgfs.csi1_file); + debugfs_remove_recursive(pdata->dbgfs.dir); + } +#endif +} + diff --git a/drivers/media/platform/rk-isp10/cif_isp10_pltfrm.h b/drivers/media/platform/rk-isp10/cif_isp10_pltfrm.h new file mode 100644 index 000000000000..4a205475958c --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_pltfrm.h @@ -0,0 +1,204 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _CIF_ISP10_PLTFRM_H +#define _CIF_ISP10_PLTFRM_H + +#include +#include +#include +#include +#include +#include + +struct cif_isp10_strm_fmt; +struct cif_isp10_csi_config; +struct cif_isp10_device; +struct cif_isp10_img_src; +struct pltfrm_cam_itf; +enum cif_isp10_pinctrl_state; +enum cif_isp10_inp; +enum cif_isp10_pm_state; + +#define CIF_ISP10_PLTFRM_DEVICE struct device * +#define CIF_ISP10_PLTFRM_MEM_IO_ADDR void __iomem * +#define CIF_ISP10_PLTFRM_EVENT wait_queue_head_t + +extern spinlock_t iowrite32_verify_lock; +#ifdef CONFIG_CIF_ISP10_REG_TRACE +int +cif_isp10_pltfrm_rtrace_printf( + struct device *dev, + const char *fmt, + ...); + +int +cif_isp10_pltfrm_ftrace_printf( + struct device *dev, + const char *fmt, + ...); + +#else +#define cif_isp10_pltfrm_rtrace_printf(dev, str, ...) +#define cif_isp10_pltfrm_ftrace_printf(dev, str, ...) +#endif + +#define cif_isp10_pltfrm_pr_dbg(dev, fmt, arg...) \ + do { \ + pr_debug("%s: " fmt, \ + __func__, ## arg); \ + cif_isp10_pltfrm_ftrace_printf(dev, "%s: " fmt, \ + __func__, ## arg); \ + } while (0) +#define cif_isp10_pltfrm_pr_info(dev, fmt, arg...) \ + do { \ + pr_info("%s: " fmt, \ + __func__, ## arg); \ + cif_isp10_pltfrm_ftrace_printf(dev, "%s: " fmt, \ + __func__, ## arg); \ + } while (0) +#define cif_isp10_pltfrm_pr_warn(dev, fmt, arg...) \ + do { \ + pr_warn("%s WARN: " fmt, \ + __func__, ## arg); \ + cif_isp10_pltfrm_ftrace_printf(dev, "%s WARN: " fmt, \ + __func__, ## arg); \ + } while (0) +#define cif_isp10_pltfrm_pr_err(dev, fmt, arg...) \ + do { \ + pr_err("%s(%d) ERR: " fmt, \ + __func__, __LINE__, ## arg); \ + cif_isp10_pltfrm_ftrace_printf(dev, "%s(%d) ERR: " fmt, \ + __func__, __LINE__, ## arg); \ + } while (0) + +void cif_isp10_pltfrm_write_reg( + struct device *dev, + u32 data, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr); + +void cif_isp10_pltfrm_write_reg_OR( + struct device *dev, + u32 data, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr); + +void cif_isp10_pltfrm_write_reg_AND( + struct device *dev, + u32 data, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr); + +u32 cif_isp10_pltfrm_read_reg( + struct device *dev, + CIF_ISP10_PLTFRM_MEM_IO_ADDR addr); + +#define cif_iowrite32(d, a) \ + cif_isp10_pltfrm_write_reg(NULL, (u32)(d), a) +#define cif_ioread32(a) \ + cif_isp10_pltfrm_read_reg(NULL, a) +#define cif_iowrite32OR(d, a) \ + cif_isp10_pltfrm_write_reg_OR(NULL, (u32)(d), a) +#define cif_iowrite32AND(d, a) \ + cif_isp10_pltfrm_write_reg_AND(NULL, (u32)(d), a) +/* BUG: Register write seems to fail sometimes w/o read before write. */ +#define cif_iowrite32_verify(d, a, mask) \ + { \ + unsigned int i = 0; \ + unsigned long flags = 0; \ + spin_lock_irqsave(&iowrite32_verify_lock, flags); \ + do { \ + cif_iowrite32(d, a); \ + udelay(1); \ + if (i++ == 50) { \ + pr_err("Error in writing %x@0x%p, read %x\n", \ + (d) & (mask), a, ioread32(a)); \ + WARN_ON(1); \ + } \ + } while ((ioread32(a) & mask) != ((d) & mask)); \ + spin_unlock_irqrestore(&iowrite32_verify_lock, flags);\ + } +#define cif_iowrite32OR_verify(d, a, mask) \ + cif_iowrite32_verify((u32)(d) | cif_ioread32(a), a, mask) +#define cif_iowrite32AND_verify(d, a, mask) \ + cif_iowrite32_verify((u32)(d) & cif_ioread32(a), a, mask) + +#define cif_isp10_pltfrm_event_init(_dev, _event) \ + init_waitqueue_head(_event) + +#define cif_isp10_pltfrm_event_clear(_dev, _event) + +#define cif_isp10_pltfrm_event_signal(_dev, _event) \ + wake_up_interruptible(_event) + +#define cif_isp10_pltfrm_event_wait_timeout( \ + _dev, _event, _condition, _timeout_us) \ + wait_event_interruptible_timeout( \ + *(_event), _condition, ((_timeout_us) * HZ) / 1000000) + +void +cif_isp10_pltfrm_debug_register_print_cb( + struct device *dev, + void (*print)(void *cntxt, const char *block_name), + void *cntxt); + +int cif_isp10_pltfrm_dev_init( + struct cif_isp10_device *cif_isp_dev, + struct device **dev, + void __iomem **reg_base_addr); + +void cif_isp10_pltfrm_dev_release( + struct device *dev); + +int cif_isp10_pltfrm_pm_set_state( + struct device *dev, + enum cif_isp10_pm_state state); + +int cif_isp10_pltfrm_write_cif_ana_bandgap_bias( + struct device *dev, + u32 val); + +int cif_isp10_pltfrm_pinctrl_set_state( + struct device *dev, + enum cif_isp10_pinctrl_state pinctrl_state); + +int cif_isp10_pltfrm_get_img_src_device( + struct device *dev, + struct cif_isp10_img_src **img_src_array, + unsigned int array_len); + +int cif_isp10_pltfrm_g_interface_config( + struct cif_isp10_img_src *img_src, + struct pltfrm_cam_itf *cam_itf); + +int cif_isp10_pltfrm_irq_register_isr( + struct device *dev, + unsigned int mis, + int (*isr)(unsigned int mis, void *cntxt), + void *cntxt); + +const char *cif_isp10_pltfrm_get_device_type( + struct device *dev); + +const char *cif_isp10_pltfrm_dev_string( + struct device *dev); + +int cif_isp10_pltfrm_soc_init( + struct cif_isp10_device *cif_isp10_dev, + struct pltfrm_soc_cfg *soc_cfg); + +int cif_isp10_pltfrm_mipi_dphy_config( + struct cif_isp10_device *cif_isp10_dev); + +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_regs.h b/drivers/media/platform/rk-isp10/cif_isp10_regs.h new file mode 100644 index 000000000000..f5ac74f4b9a2 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_regs.h @@ -0,0 +1,1203 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _RK_CIF_ISP10_REGS_H +#define _RK_CIF_ISP10_REGS_H + +/* ISP_CTRL */ +#define CIF_ISP_CTRL_ISP_ENABLE BIT(0) +#define CIF_ISP_CTRL_ISP_MODE_RAW_PICT (0 << 1) +#define CIF_ISP_CTRL_ISP_MODE_ITU656 BIT(1) +#define CIF_ISP_CTRL_ISP_MODE_ITU601 (2 << 1) +#define CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601 (3 << 1) +#define CIF_ISP_CTRL_ISP_MODE_DATA_MODE (4 << 1) +#define CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656 (5 << 1) +#define CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656 (6 << 1) +#define CIF_ISP_CTRL_ISP_INFORM_ENABLE BIT(4) +#define CIF_ISP_CTRL_ISP_GAMMA_IN_ENA BIT(6) +#define CIF_ISP_CTRL_ISP_GAMMA_IN_DIS (0 << 6) +#define CIF_ISP_CTRL_ISP_AWB_ENA BIT(7) +#define CIF_ISP_CTRL_ISP_AWB_DIS (0 << 7) +#define CIF_ISP_CTRL_ISP_CFG_UPD_PERMANENT BIT(8) +#define CIF_ISP_CTRL_ISP_CFG_UPD BIT(9) +#define CIF_ISP_CTRL_ISP_GEN_CFG_UPD BIT(10) +#define CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA BIT(11) +#define CIF_ISP_CTRL_ISP_GAMMA_OUT_DIS (0 << 11) +#define CIF_ISP_CTRL_ISP_FLASH_MODE_ENA BIT(12) +#define CIF_ISP_CTRL_ISP_FLASH_MODE_DIS (0 << 12) +#define CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA BIT(13) +#define CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA BIT(14) + +/* ISP_ACQ_PROP */ +#define CIF_ISP_ACQ_PROP_NEG_EDGE (0 << 0) +#define CIF_ISP_ACQ_PROP_POS_EDGE BIT(0) +#define CIF_ISP_ACQ_PROP_HSYNC_HIGH (0 << 1) +#define CIF_ISP_ACQ_PROP_HSYNC_LOW BIT(1) +#define CIF_ISP_ACQ_PROP_VSYNC_HIGH (0 << 2) +#define CIF_ISP_ACQ_PROP_VSYNC_LOW BIT(2) +#define CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB (0 << 3) +#define CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG BIT(3) +#define CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG (2 << 3) +#define CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR (3 << 3) +#define CIF_ISP_ACQ_PROP_YCBYCR (0 << 7) +#define CIF_ISP_ACQ_PROP_YCRYCB BIT(7) +#define CIF_ISP_ACQ_PROP_CBYCRY (2 << 7) +#define CIF_ISP_ACQ_PROP_CRYCBY (3 << 7) +#define CIF_ISP_ACQ_PROP_FIELD_SEL_ALL (0 << 9) +#define CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN BIT(9) +#define CIF_ISP_ACQ_PROP_FIELD_SEL_ODD (2 << 9) +#define CIF_ISP_ACQ_PROP_IN_SEL_12B (0 << 12) +#define CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO BIT(12) +#define CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12) +#define CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12) +#define CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12) + +/* VI_DPCL */ +#define CIF_VI_DPCL_DMA_JPEG (0 << 0) +#define CIF_VI_DPCL_MP_MUX_MRSZ_MI BIT(0) +#define CIF_VI_DPCL_MP_MUX_MRSZ_JPEG (2 << 0) +#define CIF_VI_DPCL_CHAN_MODE_MP BIT(2) +#define CIF_VI_DPCL_CHAN_MODE_SP (2 << 2) +#define CIF_VI_DPCL_CHAN_MODE_MPSP (3 << 2) +#define CIF_VI_DPCL_DMA_SW_SPMUX (0 << 4) +#define CIF_VI_DPCL_DMA_SW_SI BIT(4) +#define CIF_VI_DPCL_DMA_SW_IE (2 << 4) +#define CIF_VI_DPCL_DMA_SW_JPEG (3 << 4) +#define CIF_VI_DPCL_DMA_SW_ISP (4 << 4) +#define CIF_VI_DPCL_IF_SEL_PARALLEL (0 << 8) +#define CIF_VI_DPCL_IF_SEL_SMIA BIT(8) +#define CIF_VI_DPCL_IF_SEL_MIPI (2 << 8) +#define CIF_VI_DPCL_DMA_IE_MUX_CIF (0 << 10) +#define CIF_VI_DPCL_DMA_IE_MUX_DMA BIT(10) +#define CIF_VI_DPCL_DMA_SP_MUX_CIF (0 << 11) +#define CIF_VI_DPCL_DMA_SP_MUX_DMA BIT(11) + +/* ISP_IMSC - ISP_MIS - ISP_RIS - ISP_ICR - ISP_ISR */ +#define CIF_ISP_OFF BIT(0) +#define CIF_ISP_FRAME BIT(1) +#define CIF_ISP_DATA_LOSS BIT(2) +#define CIF_ISP_PIC_SIZE_ERROR BIT(3) +#define CIF_ISP_AWB_DONE BIT(4) +#define CIF_ISP_FRAME_IN BIT(5) +#define CIF_ISP_V_START BIT(6) +#define CIF_ISP_H_START BIT(7) +#define CIF_ISP_FLASH_ON BIT(8) +#define CIF_ISP_FLASH_OFF BIT(9) +#define CIF_ISP_SHUTTER_ON BIT(10) +#define CIF_ISP_SHUTTER_OFF BIT(11) +#define CIF_ISP_AFM_SUM_OF BIT(12) +#define CIF_ISP_AFM_LUM_OF BIT(13) +#define CIF_ISP_AFM_FIN BIT(14) +#define CIF_ISP_HIST_MEASURE_RDY BIT(15) +#define CIF_ISP_FLASH_CAP BIT(17) +#define CIF_ISP_EXP_END BIT(18) +#define CIF_ISP_VSM_END BIT(19) + +/* ISP_ERR */ +#define CIF_ISP_ERR_INFORM_SIZE BIT(0) +#define CIF_ISP_ERR_IS_SIZE BIT(1) +#define CIF_ISP_ERR_OUTFORM_SIZE BIT(2) + +/* MI_CTRL */ +#define CIF_MI_CTRL_MP_ENABLE_IN BIT(0) +#define CIF_MI_CTRL_MP_ENABLE_OUT BIT(16) +#define CIF_MI_CTRL_MP_DISABLE (0 << 0) +#define CIF_MI_CTRL_SP_ENABLE BIT(1) +#define CIF_MI_CTRL_SP_DISABLE (0 << 1) +#define CIF_MI_CTRL_JPEG_ENABLE BIT(2) +#define CIF_MI_CTRL_JPEG_DISABLE (0 << 2) +#define CIF_MI_CTRL_RAW_ENABLE BIT(3) +#define CIF_MI_CTRL_RAW_DISABLE (0 << 3) +#define CIF_MI_CTRL_HFLIP BIT(4) +#define CIF_MI_CTRL_VFLIP BIT(5) +#define CIF_MI_CTRL_ROT BIT(6) +#define CIF_MI_BYTE_SWAP BIT(7) +#define CIF_MI_NO_BYTE_SWAP (0 << 7) +#define CIF_MI_SP_Y_FULL_YUV2RGB BIT(8) +#define CIF_MI_SP_Y_REDUCED_YUV2RGB (0 << 8) +#define CIF_MI_SP_CBCR_FULL_YUV2RGB BIT(9) +#define CIF_MI_SP_CBCR_REDUCED_YUV2RGB (0 << 9) +#define CIF_MI_SP_422NONCOSITEED BIT(10) +#define CIF_MI_MP_PINGPONG_ENABEL BIT(11) +#define CIF_MI_MP_PINGPONG_DISABEL (0 << 11) +#define CIF_MI_SP_PINGPONG_ENABEL BIT(12) +#define CIF_MI_SP_PINGPONG_DISABEL (0 << 12) +#define CIF_MI_MP_AUTOUPDATE_ENABLE BIT(13) +#define CIF_MI_MP_AUTOUPDATE_DISABLE (0 << 13) +#define CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) +#define CIF_MI_SP_AUTOUPDATE_DISABLE (0 << 14) +#define CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) +#define CIF_MI_LAST_PIXEL_SIG_DISABLE (0 << 15) +#define CIF_MI_CTRL_BURST_LEN_LUM_16 (0 << 16) +#define CIF_MI_CTRL_BURST_LEN_LUM_32 BIT(16) +#define CIF_MI_CTRL_BURST_LEN_LUM_64 (2 << 16) +#define CIF_MI_CTRL_BURST_LEN_CHROM_16 (0 << 18) +#define CIF_MI_CTRL_BURST_LEN_CHROM_32 BIT(18) +#define CIF_MI_CTRL_BURST_LEN_CHROM_64 (2 << 18) +#define CIF_MI_CTRL_INIT_BASE_EN BIT(20) +#define CIF_MI_CTRL_INIT_BASE_DIS (0 << 20) +#define CIF_MI_CTRL_INIT_OFFSET_EN BIT(21) +#define CIF_MI_CTRL_INIT_OFFSET_DIS (0 << 21) +#define CIF_MI_CTRL_MP_WRITE_FMT(a) ((a) << 22) +#define CIF_MI_CTRL_MP_WRITE_FMT_PLA (0 << 22) +#define CIF_MI_CTRL_MP_WRITE_FMT_SPLA BIT(22) +#define CIF_MI_CTRL_MP_WRITE_FMT_INT (2 << 22) +#define CIF_MI_CTRL_SP_WRITE_FMT(a) ((a) << 24) +#define CIF_MI_CTRL_SP_WRITE_FMT_PLA (0 << 24) +#define CIF_MI_CTRL_SP_WRITE_FMT_SPLA BIT(24) +#define CIF_MI_CTRL_SP_WRITE_FMT_INT (2 << 24) +#define CIF_MI_CTRL_SP_INPUT_FMT_YUV400 (0 << 26) +#define CIF_MI_CTRL_SP_INPUT_FMT_YUV420 BIT(26) +#define CIF_MI_CTRL_SP_INPUT_FMT_YUV422 (2 << 26) +#define CIF_MI_CTRL_SP_INPUT_FMT_YUV444 (3 << 26) +#define CIF_MI_CTRL_SP_OUTPUT_FMT_YUV400 (0 << 28) +#define CIF_MI_CTRL_SP_OUTPUT_FMT_YUV420 BIT(28) +#define CIF_MI_CTRL_SP_OUTPUT_FMT_YUV422 (2 << 28) +#define CIF_MI_CTRL_SP_OUTPUT_FMT_YUV444 (3 << 28) +#define CIF_MI_CTRL_SP_OUTPUT_FMT_RGB565 (4 << 28) +#define CIF_MI_CTRL_SP_OUTPUT_FMT_RGB666 (5 << 28) +#define CIF_MI_CTRL_SP_OUTPUT_FMT_RGB888 (6 << 28) + +#define CIF_MI_CTRL_HFLIP_SHIFT 4 +#define CIF_MI_CTRL_VFLIP_SHIFT 5 + +/* MI_INIT */ +#define CIF_MI_INIT_SKIP BIT(2) +#define CIF_MI_INIT_SOFT_UPD BIT(4) + +/* RSZ_CTRL */ +#define CIF_RSZ_CTRL_SCALE_HY_ENABLE BIT(0) +#define CIF_RSZ_CTRL_SCALE_HC_ENABLE BIT(1) +#define CIF_RSZ_CTRL_SCALE_VY_ENABLE BIT(2) +#define CIF_RSZ_CTRL_SCALE_VC_ENABLE BIT(3) +#define CIF_RSZ_CTRL_SCALE_HY_UP BIT(4) +#define CIF_RSZ_CTRL_SCALE_HC_UP BIT(5) +#define CIF_RSZ_CTRL_SCALE_VY_UP BIT(6) +#define CIF_RSZ_CTRL_SCALE_VC_UP BIT(7) +#define CIF_RSZ_CTRL_CFG_UPD BIT(8) +#define CIF_RSZ_CTRL_CFG_UPD_AUTO BIT(9) +#define CIF_RSZ_SCALER_BYPASS BIT(16) + +/* MI_IMSC - MI_MIS - MI_RIS - MI_ICR - MI_ISR */ +#define CIF_MI_NOTHING (0 << 0) +#define CIF_MI_MP_FRAME BIT(0) +#define CIF_MI_SP_FRAME BIT(1) +#define CIF_MI_MBLK_LINE BIT(2) +#define CIF_MI_FILL_MP_Y BIT(3) +#define CIF_MI_WRAP_MP_Y BIT(4) +#define CIF_MI_WRAP_MP_CB BIT(5) +#define CIF_MI_WRAP_MP_CR BIT(6) +#define CIF_MI_WRAP_SP_Y BIT(7) +#define CIF_MI_WRAP_SP_CB BIT(8) +#define CIF_MI_WRAP_SP_CR BIT(9) +#define CIF_MI_DMA_READY BIT(11) + +/* MI_STATUS */ +#define CIF_MI_STATUS_MP_Y_FIFO_FULL BIT(0) +#define CIF_MI_STATUS_SP_Y_FIFO_FULL BIT(4) + +/* MI_DMA_CTRL */ +#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0) +#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 BIT(0) +#define CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0) +#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2) +#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 BIT(2) +#define CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2) +#define CIF_MI_DMA_CTRL_READ_FMT(a) ((a) << 4) +#define CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4) +#define CIF_MI_DMA_CTRL_READ_FMT_SPLANAR BIT(4) +#define CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) +#define CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6) +#define CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6) +#define CIF_MI_DMA_CTRL_FMT_YUV420 BIT(6) +#define CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) +#define CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8) +#define CIF_MI_DMA_CTRL_NO_BYTE_SWAP (0 << 8) +#define CIF_MI_DMA_CTRL_CONTINUOUS_ENA BIT(9) +#define CIF_MI_DMA_CTRL_CONTINUOUS_DIS (0 << 9) +#define CIF_MI_DMA_CTRL_RGB_BAYER_NO (0 << 12) +#define CIF_MI_DMA_CTRL_RGB_BAYER_8BIT BIT(12) +#define CIF_MI_DMA_CTRL_RGB_BAYER_16BIT (2 << 12) +/* MI_DMA_START */ +#define CIF_MI_DMA_START_ENABLE BIT(0) +/* MI_XTD_FORMAT_CTRL */ +#define CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP BIT(0) +#define CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1) +#define CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2) + +#define CIF_MI_ADDR_SIZE_ALIGN_MASK 0xfffffff8 + +/* CCL */ +#define CIF_CCL_CIF_CLK_ENA (0 << 2) +#define CIF_CCL_CIF_CLK_DIS BIT(2) +/* ICCL */ +#define CIF_ICCL_ISP_CLK BIT(0) +#define CIF_ICCL_CP_CLK BIT(1) +#define CIF_ICCL_RES_2 BIT(2) +#define CIF_ICCL_MRSZ_CLK BIT(3) +#define CIF_ICCL_SRSZ_CLK BIT(4) +#define CIF_ICCL_JPEG_CLK BIT(5) +#define CIF_ICCL_MI_CLK BIT(6) +#define CIF_ICCL_RES_7 BIT(7) +#define CIF_ICCL_IE_CLK BIT(8) +#define CIF_ICCL_SIMP_CLK BIT(9) +#define CIF_ICCL_SMIA_CLK BIT(10) +#define CIF_ICCL_MIPI_CLK BIT(11) +#define CIF_ICCL_ALL_CLK (-1) +#define CIF_ICCL_NO_CLK (0) +/* IRCL */ +#define CIF_IRCL_ISP_SW_RST BIT(0) +#define CIF_IRCL_CP_SW_RST BIT(1) +#define CIF_IRCL_YCS_SW_RST BIT(2) +#define CIF_IRCL_MRSZ_SW_RST BIT(3) +#define CIF_IRCL_SRSZ_SW_RST BIT(4) +#define CIF_IRCL_JPEG_SW_RST BIT(5) +#define CIF_IRCL_MI_SW_RST BIT(6) +#define CIF_IRCL_CIF_SW_RST BIT(7) +#define CIF_IRCL_IE_SW_RST BIT(8) +#define CIF_IRCL_SI_SW_RST BIT(9) +#define CIF_IRCL_MIPI_SW_RST BIT(11) + +/* C_PROC_CTR */ +#define CIF_C_PROC_CTR_ENABLE BIT(0) +#define CIF_C_PROC_CTR_DIS (0 << 0) +#define CIF_C_PROC_YOUT_FULL BIT(1) +#define CIF_C_PROC_YOUT_LIM (0 << 1) +#define CIF_C_PROC_YIN_FULL BIT(2) +#define CIF_C_PROC_YIN_LIM (0 << 2) +#define CIF_C_PROC_COUT_FULL BIT(3) +#define CIF_C_PROC_COUT_LIM (0 << 3) + +/* DUAL_CROP_CTRL */ +#define CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) +#define CIF_DUAL_CROP_MP_MODE_YUV BIT(0) +#define CIF_DUAL_CROP_MP_MODE_RAW (2 << 0) +#define CIF_DUAL_CROP_SP_MODE_BYPASS (0 << 2) +#define CIF_DUAL_CROP_SP_MODE_YUV BIT(2) +#define CIF_DUAL_CROP_SP_MODE_RAW (2 << 2) +#define CIF_DUAL_CROP_CFG_UPD_PERMANENT BIT(4) +#define CIF_DUAL_CROP_CFG_UPD BIT(5) +#define CIF_DUAL_CROP_GEN_CFG_UPD BIT(6) + +/* IMG_EFF_CTRL */ +#define CIF_IMG_EFF_CTRL_ENABLE BIT(0) +#define CIF_IMG_EFF_CTRL_MODE_BLACKWHITE (0 << 1) +#define CIF_IMG_EFF_CTRL_MODE_NEGATIVE BIT(1) +#define CIF_IMG_EFF_CTRL_MODE_SEPIA (2 << 1) +#define CIF_IMG_EFF_CTRL_MODE_COLOR_SEL (3 << 1) +#define CIF_IMG_EFF_CTRL_MODE_EMBOSS (4 << 1) +#define CIF_IMG_EFF_CTRL_MODE_SKETCH (5 << 1) +#define CIF_IMG_EFF_CTRL_MODE_SHARPEN (6 << 1) +#define CIF_IMG_EFF_CTRL_CFG_UPD BIT(4) +#define CIF_IMG_EFF_CTRL_YCBCR_FULL BIT(5) + +#define CIF_IMG_EFF_CTRL_MODE_BLACKWHITE_SHIFT (0) +#define CIF_IMG_EFF_CTRL_MODE_NEGATIVE_SHIFT (1) +#define CIF_IMG_EFF_CTRL_MODE_SEPIA_SHIFT (2) +#define CIF_IMG_EFF_CTRL_MODE_COLOR_SEL_SHIFT (3) +#define CIF_IMG_EFF_CTRL_MODE_EMBOSS_SHIFT (4) +#define CIF_IMG_EFF_CTRL_MODE_SKETCH_SHIFT (5) +#define CIF_IMG_EFF_CTRL_MODE_SHARPEN_SHIFT (6) + +/* IMG_EFF_COLOR_SEL */ +#define CIF_IMG_EFF_COLOR_RGB (0 << 0) +#define CIF_IMG_EFF_COLOR_B BIT(0) +#define CIF_IMG_EFF_COLOR_G (2 << 0) +#define CIF_IMG_EFF_COLOR_GB (3 << 0) +#define CIF_IMG_EFF_COLOR_R (4 << 0) +#define CIF_IMG_EFF_COLOR_RB (5 << 0) +#define CIF_IMG_EFF_COLOR_RG (6 << 0) +#define CIF_IMG_EFF_COLOR_RGB2 (7 << 0) + +/* JPE */ +#define CIF_JPE_GEN_HEADER_ENABLE BIT(0) +#define CIF_JPE_ENCODE_ENABLE BIT(0) +#define CIF_JPE_INIT_ENABLE BIT(0) +#define CIF_JPE_LUM_SCALE_ENABLE BIT(0) +#define CIF_JPE_CHROM_SCALE_ENABLE BIT(0) +#define CIF_JPE_PIC_FORMAT_YUV422 BIT(0) +#define CIF_JPE_PIC_FORMAT_YUV400 (4 << 0) + +#define CIF_JPE_TQ_TAB3 (3 << 0) +#define CIF_JPE_TQ_TAB2 (2 << 0) +#define CIF_JPE_TQ_TAB1 BIT(0) +#define CIF_JPE_TQ_TAB0 (0 << 0) + +#define CIF_TQ_Y_SELECT (3 << 0) +#define CIF_TQ_U_SELECT (3 << 0) +#define CIF_TQ_V_SELECT (3 << 0) +#define CIF_DC_V_TABLE (4 << 0) +#define CIF_DC_U_TABLE (2 << 0) +#define CIF_DC_Y_TABLE BIT(0) +#define CIF_AC_V_TABLE (4 << 0) +#define CIF_AC_U_TABLE (2 << 0) +#define CIF_AC_Y_TABLE BIT(0) + +/* JPE_TAB_ID */ +#define CIF_JPE_TAB_ID_HUFFAC1 (7 << 0) +#define CIF_JPE_TAB_ID_HUFFDC1 (6 << 0) +#define CIF_JPE_TAB_ID_HUFFAC0 (5 << 0) +#define CIF_JPE_TAB_ID_HUFFDC0 (4 << 0) +#define CIF_JPE_TAB_ID_QUANT3 (3 << 0) +#define CIF_JPE_TAB_ID_QUANT2 (2 << 0) +#define CIF_JPE_TAB_ID_QUANT1 BIT(0) +#define CIF_JPE_TAB_ID_QUANT0 (0 << 0) +/* JPE_ENCODER_BUSY */ +#define CIF_ENCODER_BUSY BIT(0) +/* JPE_HEADER_MODE */ +#define CIF_JPE_HEADER_MODE_NOAPPN (0 << 0) +#define CIF_JPE_HEADER_MODE_NOAPPN1 BIT(0) +#define CIF_JPE_HEADER_MODE_JFIF (2 << 0) +#define CIF_JPE_HEADER_MODE_JFIF1 (3 << 0) +/* JPE_ERROR_RIS */ +#define CIF_JPE_VLC_SYMB_ERROR BIT(4) +#define CIF_JPE_DCT_ERROR BIT(7) +#define CIF_JPE_R2B_IMG_SIZE_ERROR BIT(9) +#define CIF_JPE_VLC_TAB_ERROR BIT(10) +#define CIF_JPE_ERROR_MASK (CIF_JPE_VLC_SYMB_ERROR |\ + CIF_JPE_DCT_ERROR |\ + CIF_JPE_R2B_IMG_SIZE_ERROR |\ + CIF_JPE_VLC_TAB_ERROR) +/* JPE_STATUS_RIS */ +#define CIF_JPE_STATUS_ENCODE_DONE BIT(4) +#define CIF_JPE_STATUS_GENHEADER_DONE BIT(5) + +/* MIPI */ + +/* MIPI_DPHY1 */ + +/* MIPI_DPHY2 */ + +/* MIPI_CTRL */ +#define CIF_MIPI_CTRL_OUTPUT_ENA BIT(0) +#define CIF_MIPI_CTRL_SHUTDOWNLANES(a) ((a) << 8) +#define CIF_CSI_LANE_2 BIT(1) +#define CIF_CSI_LANE_3 BIT(2) +#define CIF_CSI_LANE_4 BIT(3) +#define CIF_MIPI_CTRL_NUM_LANES(a) ((a) << 12) +#define CIF_MIPI_CTRL_ERR_SOT_HS_ENA (0 << 16) +#define CIF_MIPI_CTRL_ERR_SOT_HS_SKIP BIT(16) +#define CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_ENA (0 << 17) +#define CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP BIT(17) +#define CIF_MIPI_CTRL_CLOCKLANE_ENA BIT(18) + +/* MIPI_DATA_SEL */ +#define CIF_MIPI_DATA_SEL_VC(a) ((a) << 6) +#define CIF_MIPI_DATA_SEL_DT(a) ((a) << 0) + +#define CIF_MIPI_INTERRUPT_ALL (-1) + +/* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ +#define CIF_MIPI_SYNC_FIFO_OVFLW(a) ((a) << 0) +#define CIF_MIPI_ERR_SOT(a) ((a) << 4) +#define CIF_MIPI_ERR_SOT_SYNC(a) ((a) << 8) +#define CIF_MIPI_ERR_EOT_SYNC(a) ((a) << 12) +#define CIF_MIPI_ERR_CTRL(a) ((a) << 16) +#define CIF_MIPI_ERR_PROTOCOL BIT(20) +#define CIF_MIPI_ERR_ECC1 BIT(21) +#define CIF_MIPI_ERR_ECC2 BIT(22) +#define CIF_MIPI_ERR_CS BIT(23) +#define CIF_MIPI_FRAME_END BIT(24) +#define CIF_MIPI_ADD_DATA_OVFLW BIT(25) +#define CIF_MIPI_ADD_DATA_WATER_MARK BIT(26) + +#define CIF_MIPI_ERR_CSI (CIF_MIPI_ERR_PROTOCOL | \ + CIF_MIPI_ERR_ECC1 | \ + CIF_MIPI_ERR_ECC2 | \ + CIF_MIPI_ERR_CS) + +#define CIF_MIPI_ERR_DPHY (CIF_MIPI_ERR_SOT(3) | \ + CIF_MIPI_ERR_SOT_SYNC(3) | \ + CIF_MIPI_ERR_EOT_SYNC(3) | \ + CIF_MIPI_ERR_CTRL(3)) + +/* SUPER_IMPOSE */ +#define CIF_SUPER_IMP_CTRL_NORMAL_MODE BIT(0) +#define CIF_SUPER_IMP_CTRL_BYPASS_MODE (0 << 0) +#define CIF_SUPER_IMP_CTRL_REF_IMG_MEM BIT(1) +#define CIF_SUPER_IMP_CTRL_REF_IMG_IE (0 << 1) +#define CIF_SUPER_IMP_CTRL_TRANSP_DIS BIT(2) +#define CIF_SUPER_IMP_CTRL_TRANSP_ENA (0 << 2) + +/* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */ +#define CIF_ISP_HIST_PROP_PDIV(a) ((a) << 3) +#define CIF_ISP_HIST_PROP_MODE_DIS (0 << 0) +#define CIF_ISP_HIST_PROP_MODE_RGB BIT(0) +#define CIF_ISP_HIST_PROP_MODE_RED (2 << 0) +#define CIF_ISP_HIST_PROP_MODE_GREEN (3 << 0) +#define CIF_ISP_HIST_PROP_MODE_BLUE (4 << 0) +#define CIF_ISP_HIST_PROP_MODE_LUM (5 << 0) + +/* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ +#define ISP_AFM_CTRL_ENABLE BIT(0) +#define ISP_AFM_CTRL_DISABLE (0 << 0) + +/* SHUTTER CONTROL */ +#define CIF_ISP_SH_CTRL_SH_ENA BIT(0) +#define CIF_ISP_SH_CTRL_SH_DIS (0 << 0) +#define CIF_ISP_SH_CTRL_REP_EN BIT(1) +#define CIF_ISP_SH_CTRL_REP_DIS (0 << 1) +#define CIF_ISP_SH_CTRL_SRC_SH_TRIG BIT(2) +#define CIF_ISP_SH_CTRL_SRC_VSYNC (0 << 2) +#define CIF_ISP_SH_CTRL_EDGE_POS BIT(3) +#define CIF_ISP_SH_CTRL_EDGE_NEG (0 << 3) +#define CIF_ISP_SH_CTRL_POL_LOW BIT(4) +#define CIF_ISP_SH_CTRL_POL_HIGH (0 << 4) + +/* FLASH MODULE */ +/* ISP_FLASH_CMD */ +#define CIF_FLASH_CMD_PRELIGHT_ON BIT(0) +#define CIF_FLASH_CMD_PRELIGHT_OFF (0 << 0) +#define CIF_FLASH_CMD_FLASH_ON BIT(1) +#define CIF_FLASH_CMD_FLASH_OFF (0 << 1) +#define CIF_FLASH_CMD_PRE_FLASH_ON BIT(2) +#define CIF_FLASH_CMD_PRE_FLASH_OFF (0 << 2) +/* ISP_FLASH_CONFIG */ +#define CIF_FLASH_CONFIG_PRELIGHT_BEG (0 << 1) +#define CIF_FLASH_CONFIG_PRELIGHT_END BIT(0) +#define CIF_FLASH_CONFIG_VSYNC_NEG (0 << 1) +#define CIF_FLASH_CONFIG_VSYNC_POS BIT(1) +#define CIF_FLASH_CONFIG_PRELIGHT_HIGH (0 << 2) +#define CIF_FLASH_CONFIG_PRELIGHT_LOW BIT(2) +#define CIF_FLASH_CONFIG_SRC_VSYNC (0 << 3) +#define CIF_FLASH_CONFIG_SRC_FL_TRIG BIT(3) +#define CIF_FLASH_CONFIG_DELAY(a) ((a) << 4) + +/* BAD PIXEL DETECTION */ + +/* =================================================================== */ +/* CIF Registers */ +/* =================================================================== */ +#define CIF_CTRL_BASE (0x00000000) +#define CIF_CCL ((CIF_CTRL_BASE + 0x00000000)) +#define CIF_VI_ID ((CIF_CTRL_BASE + 0x00000008)) +#define CIF_ICCL ((CIF_CTRL_BASE + 0x00000010)) +#define CIF_IRCL ((CIF_CTRL_BASE + 0x00000014)) +#define CIF_VI_DPCL ((CIF_CTRL_BASE + 0x00000018)) + +#define CIF_IMG_EFF_BASE (0x00000200) +#define CIF_IMG_EFF_CTRL ((CIF_IMG_EFF_BASE + 0x00000000)) +#define CIF_IMG_EFF_COLOR_SEL ((CIF_IMG_EFF_BASE + 0x00000004)) +#define CIF_IMG_EFF_MAT_1 ((CIF_IMG_EFF_BASE + 0x00000008)) +#define CIF_IMG_EFF_MAT_2 ((CIF_IMG_EFF_BASE + 0x0000000C)) +#define CIF_IMG_EFF_MAT_3 ((CIF_IMG_EFF_BASE + 0x00000010)) +#define CIF_IMG_EFF_MAT_4 ((CIF_IMG_EFF_BASE + 0x00000014)) +#define CIF_IMG_EFF_MAT_5 ((CIF_IMG_EFF_BASE + 0x00000018)) +#define CIF_IMG_EFF_TINT ((CIF_IMG_EFF_BASE + 0x0000001C)) +#define CIF_IMG_EFF_CTRL_SHD ((CIF_IMG_EFF_BASE + 0x00000020)) +#define CIF_IMG_EFF_SHARPEN ((CIF_IMG_EFF_BASE + 0x00000024)) + +#define CIF_SUPER_IMP_BASE (0x00000300) +#define CIF_SUPER_IMP_CTRL ((CIF_SUPER_IMP_BASE + 0x00000000)) +#define CIF_SUPER_IMP_OFFSET_X ((CIF_SUPER_IMP_BASE + 0x00000004)) +#define CIF_SUPER_IMP_OFFSET_Y ((CIF_SUPER_IMP_BASE + 0x00000008)) +#define CIF_SUPER_IMP_COLOR_Y ((CIF_SUPER_IMP_BASE + 0x0000000C)) +#define CIF_SUPER_IMP_COLOR_CB ((CIF_SUPER_IMP_BASE + 0x00000010)) +#define CIF_SUPER_IMP_COLOR_CR ((CIF_SUPER_IMP_BASE + 0x00000014)) + +#define CIF_ISP_BASE (0x00000400) +#define CIF_ISP_CTRL ((CIF_ISP_BASE + 0x00000000)) +#define CIF_ISP_ACQ_PROP ((CIF_ISP_BASE + 0x00000004)) +#define CIF_ISP_ACQ_H_OFFS ((CIF_ISP_BASE + 0x00000008)) +#define CIF_ISP_ACQ_V_OFFS ((CIF_ISP_BASE + 0x0000000C)) +#define CIF_ISP_ACQ_H_SIZE ((CIF_ISP_BASE + 0x00000010)) +#define CIF_ISP_ACQ_V_SIZE ((CIF_ISP_BASE + 0x00000014)) +#define CIF_ISP_ACQ_NR_FRAMES ((CIF_ISP_BASE + 0x00000018)) +#define CIF_ISP_GAMMA_DX_LO ((CIF_ISP_BASE + 0x0000001C)) +#define CIF_ISP_GAMMA_DX_HI ((CIF_ISP_BASE + 0x00000020)) +#define CIF_ISP_GAMMA_R_Y0 ((CIF_ISP_BASE + 0x00000024)) +#define CIF_ISP_GAMMA_R_Y1 ((CIF_ISP_BASE + 0x00000028)) +#define CIF_ISP_GAMMA_R_Y2 ((CIF_ISP_BASE + 0x0000002C)) +#define CIF_ISP_GAMMA_R_Y3 ((CIF_ISP_BASE + 0x00000030)) +#define CIF_ISP_GAMMA_R_Y4 ((CIF_ISP_BASE + 0x00000034)) +#define CIF_ISP_GAMMA_R_Y5 ((CIF_ISP_BASE + 0x00000038)) +#define CIF_ISP_GAMMA_R_Y6 ((CIF_ISP_BASE + 0x0000003C)) +#define CIF_ISP_GAMMA_R_Y7 ((CIF_ISP_BASE + 0x00000040)) +#define CIF_ISP_GAMMA_R_Y8 ((CIF_ISP_BASE + 0x00000044)) +#define CIF_ISP_GAMMA_R_Y9 ((CIF_ISP_BASE + 0x00000048)) +#define CIF_ISP_GAMMA_R_Y10 ((CIF_ISP_BASE + 0x0000004C)) +#define CIF_ISP_GAMMA_R_Y11 ((CIF_ISP_BASE + 0x00000050)) +#define CIF_ISP_GAMMA_R_Y12 ((CIF_ISP_BASE + 0x00000054)) +#define CIF_ISP_GAMMA_R_Y13 ((CIF_ISP_BASE + 0x00000058)) +#define CIF_ISP_GAMMA_R_Y14 ((CIF_ISP_BASE + 0x0000005C)) +#define CIF_ISP_GAMMA_R_Y15 ((CIF_ISP_BASE + 0x00000060)) +#define CIF_ISP_GAMMA_R_Y16 ((CIF_ISP_BASE + 0x00000064)) +#define CIF_ISP_GAMMA_G_Y0 ((CIF_ISP_BASE + 0x00000068)) +#define CIF_ISP_GAMMA_G_Y1 ((CIF_ISP_BASE + 0x0000006C)) +#define CIF_ISP_GAMMA_G_Y2 ((CIF_ISP_BASE + 0x00000070)) +#define CIF_ISP_GAMMA_G_Y3 ((CIF_ISP_BASE + 0x00000074)) +#define CIF_ISP_GAMMA_G_Y4 ((CIF_ISP_BASE + 0x00000078)) +#define CIF_ISP_GAMMA_G_Y5 ((CIF_ISP_BASE + 0x0000007C)) +#define CIF_ISP_GAMMA_G_Y6 ((CIF_ISP_BASE + 0x00000080)) +#define CIF_ISP_GAMMA_G_Y7 ((CIF_ISP_BASE + 0x00000084)) +#define CIF_ISP_GAMMA_G_Y8 ((CIF_ISP_BASE + 0x00000088)) +#define CIF_ISP_GAMMA_G_Y9 ((CIF_ISP_BASE + 0x0000008C)) +#define CIF_ISP_GAMMA_G_Y10 ((CIF_ISP_BASE + 0x00000090)) +#define CIF_ISP_GAMMA_G_Y11 ((CIF_ISP_BASE + 0x00000094)) +#define CIF_ISP_GAMMA_G_Y12 ((CIF_ISP_BASE + 0x00000098)) +#define CIF_ISP_GAMMA_G_Y13 ((CIF_ISP_BASE + 0x0000009C)) +#define CIF_ISP_GAMMA_G_Y14 ((CIF_ISP_BASE + 0x000000A0)) +#define CIF_ISP_GAMMA_G_Y15 ((CIF_ISP_BASE + 0x000000A4)) +#define CIF_ISP_GAMMA_G_Y16 ((CIF_ISP_BASE + 0x000000A8)) +#define CIF_ISP_GAMMA_B_Y0 ((CIF_ISP_BASE + 0x000000AC)) +#define CIF_ISP_GAMMA_B_Y1 ((CIF_ISP_BASE + 0x000000B0)) +#define CIF_ISP_GAMMA_B_Y2 ((CIF_ISP_BASE + 0x000000B4)) +#define CIF_ISP_GAMMA_B_Y3 ((CIF_ISP_BASE + 0x000000B8)) +#define CIF_ISP_GAMMA_B_Y4 ((CIF_ISP_BASE + 0x000000BC)) +#define CIF_ISP_GAMMA_B_Y5 ((CIF_ISP_BASE + 0x000000C0)) +#define CIF_ISP_GAMMA_B_Y6 ((CIF_ISP_BASE + 0x000000C4)) +#define CIF_ISP_GAMMA_B_Y7 ((CIF_ISP_BASE + 0x000000C8)) +#define CIF_ISP_GAMMA_B_Y8 ((CIF_ISP_BASE + 0x000000CC)) +#define CIF_ISP_GAMMA_B_Y9 ((CIF_ISP_BASE + 0x000000D0)) +#define CIF_ISP_GAMMA_B_Y10 ((CIF_ISP_BASE + 0x000000D4)) +#define CIF_ISP_GAMMA_B_Y11 ((CIF_ISP_BASE + 0x000000D8)) +#define CIF_ISP_GAMMA_B_Y12 ((CIF_ISP_BASE + 0x000000DC)) +#define CIF_ISP_GAMMA_B_Y13 ((CIF_ISP_BASE + 0x000000E0)) +#define CIF_ISP_GAMMA_B_Y14 ((CIF_ISP_BASE + 0x000000E4)) +#define CIF_ISP_GAMMA_B_Y15 ((CIF_ISP_BASE + 0x000000E8)) +#define CIF_ISP_GAMMA_B_Y16 ((CIF_ISP_BASE + 0x000000EC)) +#define CIF_ISP_AWB_PROP ((CIF_ISP_BASE + 0x00000110)) +#define CIF_ISP_AWB_WND_H_OFFS ((CIF_ISP_BASE + 0x00000114)) +#define CIF_ISP_AWB_WND_V_OFFS ((CIF_ISP_BASE + 0x00000118)) +#define CIF_ISP_AWB_WND_H_SIZE ((CIF_ISP_BASE + 0x0000011C)) +#define CIF_ISP_AWB_WND_V_SIZE ((CIF_ISP_BASE + 0x00000120)) +#define CIF_ISP_AWB_FRAMES ((CIF_ISP_BASE + 0x00000124)) +#define CIF_ISP_AWB_REF ((CIF_ISP_BASE + 0x00000128)) +#define CIF_ISP_AWB_THRESH ((CIF_ISP_BASE + 0x0000012C)) +#define CIF_ISP_AWB_GAIN_G ((CIF_ISP_BASE + 0x00000138)) +#define CIF_ISP_AWB_GAIN_RB ((CIF_ISP_BASE + 0x0000013C)) +#define CIF_ISP_AWB_WHITE_CNT ((CIF_ISP_BASE + 0x00000140)) +#define CIF_ISP_AWB_MEAN ((CIF_ISP_BASE + 0x00000144)) +#define CIF_ISP_CC_COEFF_0 ((CIF_ISP_BASE + 0x00000170)) +#define CIF_ISP_CC_COEFF_1 ((CIF_ISP_BASE + 0x00000174)) +#define CIF_ISP_CC_COEFF_2 ((CIF_ISP_BASE + 0x00000178)) +#define CIF_ISP_CC_COEFF_3 ((CIF_ISP_BASE + 0x0000017C)) +#define CIF_ISP_CC_COEFF_4 ((CIF_ISP_BASE + 0x00000180)) +#define CIF_ISP_CC_COEFF_5 ((CIF_ISP_BASE + 0x00000184)) +#define CIF_ISP_CC_COEFF_6 ((CIF_ISP_BASE + 0x00000188)) +#define CIF_ISP_CC_COEFF_7 ((CIF_ISP_BASE + 0x0000018C)) +#define CIF_ISP_CC_COEFF_8 ((CIF_ISP_BASE + 0x00000190)) +#define CIF_ISP_OUT_H_OFFS ((CIF_ISP_BASE + 0x00000194)) +#define CIF_ISP_OUT_V_OFFS ((CIF_ISP_BASE + 0x00000198)) +#define CIF_ISP_OUT_H_SIZE ((CIF_ISP_BASE + 0x0000019C)) +#define CIF_ISP_OUT_V_SIZE ((CIF_ISP_BASE + 0x000001A0)) +#define CIF_ISP_DEMOSAIC ((CIF_ISP_BASE + 0x000001A4)) +#define CIF_ISP_FLAGS_SHD ((CIF_ISP_BASE + 0x000001A8)) +#define CIF_ISP_OUT_H_OFFS_SHD ((CIF_ISP_BASE + 0x000001AC)) +#define CIF_ISP_OUT_V_OFFS_SHD ((CIF_ISP_BASE + 0x000001B0)) +#define CIF_ISP_OUT_H_SIZE_SHD ((CIF_ISP_BASE + 0x000001B4)) +#define CIF_ISP_OUT_V_SIZE_SHD ((CIF_ISP_BASE + 0x000001B8)) +#define CIF_ISP_IMSC ((CIF_ISP_BASE + 0x000001BC)) +#define CIF_ISP_RIS ((CIF_ISP_BASE + 0x000001C0)) +#define CIF_ISP_MIS ((CIF_ISP_BASE + 0x000001C4)) +#define CIF_ISP_ICR ((CIF_ISP_BASE + 0x000001C8)) +#define CIF_ISP_ISR ((CIF_ISP_BASE + 0x000001CC)) +#define CIF_ISP_CT_COEFF_0 ((CIF_ISP_BASE + 0x000001D0)) +#define CIF_ISP_CT_COEFF_1 ((CIF_ISP_BASE + 0x000001D4)) +#define CIF_ISP_CT_COEFF_2 ((CIF_ISP_BASE + 0x000001D8)) +#define CIF_ISP_CT_COEFF_3 ((CIF_ISP_BASE + 0x000001DC)) +#define CIF_ISP_CT_COEFF_4 ((CIF_ISP_BASE + 0x000001E0)) +#define CIF_ISP_CT_COEFF_5 ((CIF_ISP_BASE + 0x000001E4)) +#define CIF_ISP_CT_COEFF_6 ((CIF_ISP_BASE + 0x000001E8)) +#define CIF_ISP_CT_COEFF_7 ((CIF_ISP_BASE + 0x000001EC)) +#define CIF_ISP_CT_COEFF_8 ((CIF_ISP_BASE + 0x000001F0)) +#define CIF_ISP_GAMMA_OUT_MODE ((CIF_ISP_BASE + 0x000001F4)) +#define CIF_ISP_GAMMA_OUT_Y_0 ((CIF_ISP_BASE + 0x000001F8)) +#define CIF_ISP_GAMMA_OUT_Y_1 ((CIF_ISP_BASE + 0x000001FC)) +#define CIF_ISP_GAMMA_OUT_Y_2 ((CIF_ISP_BASE + 0x00000200)) +#define CIF_ISP_GAMMA_OUT_Y_3 ((CIF_ISP_BASE + 0x00000204)) +#define CIF_ISP_GAMMA_OUT_Y_4 ((CIF_ISP_BASE + 0x00000208)) +#define CIF_ISP_GAMMA_OUT_Y_5 ((CIF_ISP_BASE + 0x0000020C)) +#define CIF_ISP_GAMMA_OUT_Y_6 ((CIF_ISP_BASE + 0x00000210)) +#define CIF_ISP_GAMMA_OUT_Y_7 ((CIF_ISP_BASE + 0x00000214)) +#define CIF_ISP_GAMMA_OUT_Y_8 ((CIF_ISP_BASE + 0x00000218)) +#define CIF_ISP_GAMMA_OUT_Y_9 ((CIF_ISP_BASE + 0x0000021C)) +#define CIF_ISP_GAMMA_OUT_Y_10 ((CIF_ISP_BASE + 0x00000220)) +#define CIF_ISP_GAMMA_OUT_Y_11 ((CIF_ISP_BASE + 0x00000224)) +#define CIF_ISP_GAMMA_OUT_Y_12 ((CIF_ISP_BASE + 0x00000228)) +#define CIF_ISP_GAMMA_OUT_Y_13 ((CIF_ISP_BASE + 0x0000022C)) +#define CIF_ISP_GAMMA_OUT_Y_14 ((CIF_ISP_BASE + 0x00000230)) +#define CIF_ISP_GAMMA_OUT_Y_15 ((CIF_ISP_BASE + 0x00000234)) +#define CIF_ISP_GAMMA_OUT_Y_16 ((CIF_ISP_BASE + 0x00000238)) +#define CIF_ISP_ERR ((CIF_ISP_BASE + 0x0000023C)) +#define CIF_ISP_ERR_CLR ((CIF_ISP_BASE + 0x00000240)) +#define CIF_ISP_FRAME_COUNT ((CIF_ISP_BASE + 0x00000244)) +#define CIF_ISP_CT_OFFSET_R ((CIF_ISP_BASE + 0x00000248)) +#define CIF_ISP_CT_OFFSET_G ((CIF_ISP_BASE + 0x0000024C)) +#define CIF_ISP_CT_OFFSET_B ((CIF_ISP_BASE + 0x00000250)) + +#define CIF_ISP_FLASH_BASE (0x00000660) +#define CIF_ISP_FLASH_CMD ((CIF_ISP_FLASH_BASE + 0x00000000)) +#define CIF_ISP_FLASH_CONFIG ((CIF_ISP_FLASH_BASE + 0x00000004)) +#define CIF_ISP_FLASH_PREDIV ((CIF_ISP_FLASH_BASE + 0x00000008)) +#define CIF_ISP_FLASH_DELAY ((CIF_ISP_FLASH_BASE + 0x0000000C)) +#define CIF_ISP_FLASH_TIME ((CIF_ISP_FLASH_BASE + 0x00000010)) +#define CIF_ISP_FLASH_MAXP ((CIF_ISP_FLASH_BASE + 0x00000014)) + +#define CIF_ISP_SH_BASE (0x00000680) +#define CIF_ISP_SH_CTRL ((CIF_ISP_SH_BASE + 0x00000000)) +#define CIF_ISP_SH_PREDIV ((CIF_ISP_SH_BASE + 0x00000004)) +#define CIF_ISP_SH_DELAY ((CIF_ISP_SH_BASE + 0x00000008)) +#define CIF_ISP_SH_TIME ((CIF_ISP_SH_BASE + 0x0000000C)) + +#define CIF_C_PROC_BASE (0x00000800) +#define CIF_C_PROC_CTRL ((CIF_C_PROC_BASE + 0x00000000)) +#define CIF_C_PROC_CONTRAST ((CIF_C_PROC_BASE + 0x00000004)) +#define CIF_C_PROC_BRIGHTNESS ((CIF_C_PROC_BASE + 0x00000008)) +#define CIF_C_PROC_SATURATION ((CIF_C_PROC_BASE + 0x0000000C)) +#define CIF_C_PROC_HUE ((CIF_C_PROC_BASE + 0x00000010)) + +#define CIF_DUAL_CROP_BASE (0x00000880) +#define CIF_DUAL_CROP_CTRL (CIF_DUAL_CROP_BASE + 0x00000000) +#define CIF_DUAL_CROP_M_H_OFFS (CIF_DUAL_CROP_BASE + 0x00000004) +#define CIF_DUAL_CROP_M_V_OFFS (CIF_DUAL_CROP_BASE + 0x00000008) +#define CIF_DUAL_CROP_M_H_SIZE (CIF_DUAL_CROP_BASE + 0x0000000C) +#define CIF_DUAL_CROP_M_V_SIZE (CIF_DUAL_CROP_BASE + 0x00000010) +#define CIF_DUAL_CROP_S_H_OFFS (CIF_DUAL_CROP_BASE + 0x00000014) +#define CIF_DUAL_CROP_S_V_OFFS (CIF_DUAL_CROP_BASE + 0x00000018) +#define CIF_DUAL_CROP_S_H_SIZE (CIF_DUAL_CROP_BASE + 0x0000001C) +#define CIF_DUAL_CROP_S_V_SIZE (CIF_DUAL_CROP_BASE + 0x00000020) +#define CIF_DUAL_CROP_M_H_OFFS_SHD (CIF_DUAL_CROP_BASE + 0x00000024) +#define CIF_DUAL_CROP_M_V_OFFS_SHD (CIF_DUAL_CROP_BASE + 0x00000028) +#define CIF_DUAL_CROP_M_H_SIZE_SHD (CIF_DUAL_CROP_BASE + 0x0000002C) +#define CIF_DUAL_CROP_M_V_SIZE_SHD (CIF_DUAL_CROP_BASE + 0x00000030) +#define CIF_DUAL_CROP_S_H_OFFS_SHD (CIF_DUAL_CROP_BASE + 0x00000034) +#define CIF_DUAL_CROP_S_V_OFFS_SHD (CIF_DUAL_CROP_BASE + 0x00000038) +#define CIF_DUAL_CROP_S_H_SIZE_SHD (CIF_DUAL_CROP_BASE + 0x0000003C) +#define CIF_DUAL_CROP_S_V_SIZE_SHD \ + (CIF_DUAL_CROP_BASE + 0x00000040) + +#define CIF_MRSZ_BASE (0x00000C00) +#define CIF_MRSZ_CTRL ((CIF_MRSZ_BASE + 0x00000000)) +#define CIF_MRSZ_SCALE_HY ((CIF_MRSZ_BASE + 0x00000004)) +#define CIF_MRSZ_SCALE_HCB ((CIF_MRSZ_BASE + 0x00000008)) +#define CIF_MRSZ_SCALE_HCR ((CIF_MRSZ_BASE + 0x0000000C)) +#define CIF_MRSZ_SCALE_VY ((CIF_MRSZ_BASE + 0x00000010)) +#define CIF_MRSZ_SCALE_VC ((CIF_MRSZ_BASE + 0x00000014)) +#define CIF_MRSZ_PHASE_HY ((CIF_MRSZ_BASE + 0x00000018)) +#define CIF_MRSZ_PHASE_HC ((CIF_MRSZ_BASE + 0x0000001C)) +#define CIF_MRSZ_PHASE_VY ((CIF_MRSZ_BASE + 0x00000020)) +#define CIF_MRSZ_PHASE_VC ((CIF_MRSZ_BASE + 0x00000024)) +#define CIF_MRSZ_SCALE_LUT_ADDR ((CIF_MRSZ_BASE + 0x00000028)) +#define CIF_MRSZ_SCALE_LUT ((CIF_MRSZ_BASE + 0x0000002C)) +#define CIF_MRSZ_CTRL_SHD ((CIF_MRSZ_BASE + 0x00000030)) +#define CIF_MRSZ_SCALE_HY_SHD ((CIF_MRSZ_BASE + 0x00000034)) +#define CIF_MRSZ_SCALE_HCB_SHD ((CIF_MRSZ_BASE + 0x00000038)) +#define CIF_MRSZ_SCALE_HCR_SHD ((CIF_MRSZ_BASE + 0x0000003C)) +#define CIF_MRSZ_SCALE_VY_SHD ((CIF_MRSZ_BASE + 0x00000040)) +#define CIF_MRSZ_SCALE_VC_SHD ((CIF_MRSZ_BASE + 0x00000044)) +#define CIF_MRSZ_PHASE_HY_SHD ((CIF_MRSZ_BASE + 0x00000048)) +#define CIF_MRSZ_PHASE_HC_SHD ((CIF_MRSZ_BASE + 0x0000004C)) +#define CIF_MRSZ_PHASE_VY_SHD ((CIF_MRSZ_BASE + 0x00000050)) +#define CIF_MRSZ_PHASE_VC_SHD ((CIF_MRSZ_BASE + 0x00000054)) + +#define CIF_SRSZ_BASE (0x00001000) +#define CIF_SRSZ_CTRL ((CIF_SRSZ_BASE + 0x00000000)) +#define CIF_SRSZ_SCALE_HY ((CIF_SRSZ_BASE + 0x00000004)) +#define CIF_SRSZ_SCALE_HCB ((CIF_SRSZ_BASE + 0x00000008)) +#define CIF_SRSZ_SCALE_HCR ((CIF_SRSZ_BASE + 0x0000000C)) +#define CIF_SRSZ_SCALE_VY ((CIF_SRSZ_BASE + 0x00000010)) +#define CIF_SRSZ_SCALE_VC ((CIF_SRSZ_BASE + 0x00000014)) +#define CIF_SRSZ_PHASE_HY ((CIF_SRSZ_BASE + 0x00000018)) +#define CIF_SRSZ_PHASE_HC ((CIF_SRSZ_BASE + 0x0000001C)) +#define CIF_SRSZ_PHASE_VY ((CIF_SRSZ_BASE + 0x00000020)) +#define CIF_SRSZ_PHASE_VC ((CIF_SRSZ_BASE + 0x00000024)) +#define CIF_SRSZ_SCALE_LUT_ADDR ((CIF_SRSZ_BASE + 0x00000028)) +#define CIF_SRSZ_SCALE_LUT ((CIF_SRSZ_BASE + 0x0000002C)) +#define CIF_SRSZ_CTRL_SHD ((CIF_SRSZ_BASE + 0x00000030)) +#define CIF_SRSZ_SCALE_HY_SHD ((CIF_SRSZ_BASE + 0x00000034)) +#define CIF_SRSZ_SCALE_HCB_SHD ((CIF_SRSZ_BASE + 0x00000038)) +#define CIF_SRSZ_SCALE_HCR_SHD ((CIF_SRSZ_BASE + 0x0000003C)) +#define CIF_SRSZ_SCALE_VY_SHD ((CIF_SRSZ_BASE + 0x00000040)) +#define CIF_SRSZ_SCALE_VC_SHD ((CIF_SRSZ_BASE + 0x00000044)) +#define CIF_SRSZ_PHASE_HY_SHD ((CIF_SRSZ_BASE + 0x00000048)) +#define CIF_SRSZ_PHASE_HC_SHD ((CIF_SRSZ_BASE + 0x0000004C)) +#define CIF_SRSZ_PHASE_VY_SHD ((CIF_SRSZ_BASE + 0x00000050)) +#define CIF_SRSZ_PHASE_VC_SHD ((CIF_SRSZ_BASE + 0x00000054)) + +#define CIF_MI_BASE (0x00001400) +#define CIF_MI_CTRL ((CIF_MI_BASE + 0x00000000)) +#define CIF_MI_INIT ((CIF_MI_BASE + 0x00000004)) +#define CIF_MI_MP_Y_BASE_AD_INIT ((CIF_MI_BASE + 0x00000008)) +#define CIF_MI_MP_Y_SIZE_INIT ((CIF_MI_BASE + 0x0000000C)) +#define CIF_MI_MP_Y_OFFS_CNT_INIT ((CIF_MI_BASE + 0x00000010)) +#define CIF_MI_MP_Y_OFFS_CNT_START ((CIF_MI_BASE + 0x00000014)) +#define CIF_MI_MP_Y_IRQ_OFFS_INIT ((CIF_MI_BASE + 0x00000018)) +#define CIF_MI_MP_CB_BASE_AD_INIT ((CIF_MI_BASE + 0x0000001C)) +#define CIF_MI_MP_CB_SIZE_INIT ((CIF_MI_BASE + 0x00000020)) +#define CIF_MI_MP_CB_OFFS_CNT_INIT ((CIF_MI_BASE + 0x00000024)) +#define CIF_MI_MP_CB_OFFS_CNT_START ((CIF_MI_BASE + 0x00000028)) +#define CIF_MI_MP_CR_BASE_AD_INIT ((CIF_MI_BASE + 0x0000002C)) +#define CIF_MI_MP_CR_SIZE_INIT ((CIF_MI_BASE + 0x00000030)) +#define CIF_MI_MP_CR_OFFS_CNT_INIT ((CIF_MI_BASE + 0x00000034)) +#define CIF_MI_MP_CR_OFFS_CNT_START ((CIF_MI_BASE + 0x00000038)) +#define CIF_MI_SP_Y_BASE_AD_INIT ((CIF_MI_BASE + 0x0000003C)) +#define CIF_MI_SP_Y_SIZE_INIT ((CIF_MI_BASE + 0x00000040)) +#define CIF_MI_SP_Y_OFFS_CNT_INIT ((CIF_MI_BASE + 0x00000044)) +#define CIF_MI_SP_Y_OFFS_CNT_START ((CIF_MI_BASE + 0x00000048)) +#define CIF_MI_SP_Y_LLENGTH ((CIF_MI_BASE + 0x0000004C)) +#define CIF_MI_SP_CB_BASE_AD_INIT ((CIF_MI_BASE + 0x00000050)) +#define CIF_MI_SP_CB_SIZE_INIT ((CIF_MI_BASE + 0x00000054)) +#define CIF_MI_SP_CB_OFFS_CNT_INIT ((CIF_MI_BASE + 0x00000058)) +#define CIF_MI_SP_CB_OFFS_CNT_START ((CIF_MI_BASE + 0x0000005C)) +#define CIF_MI_SP_CR_BASE_AD_INIT ((CIF_MI_BASE + 0x00000060)) +#define CIF_MI_SP_CR_SIZE_INIT ((CIF_MI_BASE + 0x00000064)) +#define CIF_MI_SP_CR_OFFS_CNT_INIT ((CIF_MI_BASE + 0x00000068)) +#define CIF_MI_SP_CR_OFFS_CNT_START ((CIF_MI_BASE + 0x0000006C)) +#define CIF_MI_BYTE_CNT ((CIF_MI_BASE + 0x00000070)) +#define CIF_MI_CTRL_SHD ((CIF_MI_BASE + 0x00000074)) +#define CIF_MI_MP_Y_BASE_AD_SHD ((CIF_MI_BASE + 0x00000078)) +#define CIF_MI_MP_Y_SIZE_SHD ((CIF_MI_BASE + 0x0000007C)) +#define CIF_MI_MP_Y_OFFS_CNT_SHD ((CIF_MI_BASE + 0x00000080)) +#define CIF_MI_MP_Y_IRQ_OFFS_SHD ((CIF_MI_BASE + 0x00000084)) +#define CIF_MI_MP_CB_BASE_AD_SHD ((CIF_MI_BASE + 0x00000088)) +#define CIF_MI_MP_CB_SIZE_SHD ((CIF_MI_BASE + 0x0000008C)) +#define CIF_MI_MP_CB_OFFS_CNT_SHD ((CIF_MI_BASE + 0x00000090)) +#define CIF_MI_MP_CR_BASE_AD_SHD ((CIF_MI_BASE + 0x00000094)) +#define CIF_MI_MP_CR_SIZE_SHD ((CIF_MI_BASE + 0x00000098)) +#define CIF_MI_MP_CR_OFFS_CNT_SHD ((CIF_MI_BASE + 0x0000009C)) +#define CIF_MI_SP_Y_BASE_AD_SHD ((CIF_MI_BASE + 0x000000A0)) +#define CIF_MI_SP_Y_SIZE_SHD ((CIF_MI_BASE + 0x000000A4)) +#define CIF_MI_SP_Y_OFFS_CNT_SHD ((CIF_MI_BASE + 0x000000A8)) +#define CIF_MI_SP_CB_BASE_AD_SHD ((CIF_MI_BASE + 0x000000B0)) +#define CIF_MI_SP_CB_SIZE_SHD ((CIF_MI_BASE + 0x000000B4)) +#define CIF_MI_SP_CB_OFFS_CNT_SHD ((CIF_MI_BASE + 0x000000B8)) +#define CIF_MI_SP_CR_BASE_AD_SHD ((CIF_MI_BASE + 0x000000BC)) +#define CIF_MI_SP_CR_SIZE_SHD ((CIF_MI_BASE + 0x000000C0)) +#define CIF_MI_SP_CR_OFFS_CNT_SHD ((CIF_MI_BASE + 0x000000C4)) +#define CIF_MI_DMA_Y_PIC_START_AD ((CIF_MI_BASE + 0x000000C8)) +#define CIF_MI_DMA_Y_PIC_WIDTH ((CIF_MI_BASE + 0x000000CC)) +#define CIF_MI_DMA_Y_LLENGTH ((CIF_MI_BASE + 0x000000D0)) +#define CIF_MI_DMA_Y_PIC_SIZE ((CIF_MI_BASE + 0x000000D4)) +#define CIF_MI_DMA_CB_PIC_START_AD ((CIF_MI_BASE + 0x000000D8)) +#define CIF_MI_DMA_CR_PIC_START_AD ((CIF_MI_BASE + 0x000000E8)) +#define CIF_MI_IMSC ((CIF_MI_BASE + 0x000000F8)) +#define CIF_MI_RIS ((CIF_MI_BASE + 0x000000FC)) +#define CIF_MI_MIS ((CIF_MI_BASE + 0x00000100)) +#define CIF_MI_ICR ((CIF_MI_BASE + 0x00000104)) +#define CIF_MI_ISR ((CIF_MI_BASE + 0x00000108)) +#define CIF_MI_STATUS ((CIF_MI_BASE + 0x0000010C)) +#define CIF_MI_STATUS_CLR ((CIF_MI_BASE + 0x00000110)) +#define CIF_MI_SP_Y_PIC_WIDTH ((CIF_MI_BASE + 0x00000114)) +#define CIF_MI_SP_Y_PIC_HEIGHT ((CIF_MI_BASE + 0x00000118)) +#define CIF_MI_SP_Y_PIC_SIZE ((CIF_MI_BASE + 0x0000011C)) +#define CIF_MI_DMA_CTRL ((CIF_MI_BASE + 0x00000120)) +#define CIF_MI_DMA_START ((CIF_MI_BASE + 0x00000124)) +#define CIF_MI_DMA_STATUS ((CIF_MI_BASE + 0x00000128)) +#define CIF_MI_PIXEL_COUNT ((CIF_MI_BASE + 0x0000012C)) +#define CIF_MI_MP_Y_BASE_AD_INIT2 ((CIF_MI_BASE + 0x00000130)) +#define CIF_MI_MP_CB_BASE_AD_INIT2 ((CIF_MI_BASE + 0x00000134)) +#define CIF_MI_MP_CR_BASE_AD_INIT2 ((CIF_MI_BASE + 0x00000138)) +#define CIF_MI_SP_Y_BASE_AD_INIT2 ((CIF_MI_BASE + 0x0000013C)) +#define CIF_MI_SP_CB_BASE_AD_INIT2 ((CIF_MI_BASE + 0x00000140)) +#define CIF_MI_SP_CR_BASE_AD_INIT2 ((CIF_MI_BASE + 0x00000144)) +#define CIF_MI_XTD_FORMAT_CTRL ((CIF_MI_BASE + 0x00000148)) + +#define CIF_JPE_BASE (0x00001800) +#define CIF_JPE_GEN_HEADER ((CIF_JPE_BASE + 0x00000000)) +#define CIF_JPE_ENCODE ((CIF_JPE_BASE + 0x00000004)) +#define CIF_JPE_INIT ((CIF_JPE_BASE + 0x00000008)) +#define CIF_JPE_Y_SCALE_EN ((CIF_JPE_BASE + 0x0000000C)) +#define CIF_JPE_CBCR_SCALE_EN ((CIF_JPE_BASE + 0x00000010)) +#define CIF_JPE_TABLE_FLUSH ((CIF_JPE_BASE + 0x00000014)) +#define CIF_JPE_ENC_HSIZE ((CIF_JPE_BASE + 0x00000018)) +#define CIF_JPE_ENC_VSIZE ((CIF_JPE_BASE + 0x0000001C)) +#define CIF_JPE_PIC_FORMAT ((CIF_JPE_BASE + 0x00000020)) +#define CIF_JPE_RESTART_INTERVAL ((CIF_JPE_BASE + 0x00000024)) +#define CIF_JPE_TQ_Y_SELECT ((CIF_JPE_BASE + 0x00000028)) +#define CIF_JPE_TQ_U_SELECT ((CIF_JPE_BASE + 0x0000002C)) +#define CIF_JPE_TQ_V_SELECT ((CIF_JPE_BASE + 0x00000030)) +#define CIF_JPE_DC_TABLE_SELECT ((CIF_JPE_BASE + 0x00000034)) +#define CIF_JPE_AC_TABLE_SELECT ((CIF_JPE_BASE + 0x00000038)) +#define CIF_JPE_TABLE_DATA ((CIF_JPE_BASE + 0x0000003C)) +#define CIF_JPE_TABLE_ID ((CIF_JPE_BASE + 0x00000040)) +#define CIF_JPE_TAC0_LEN ((CIF_JPE_BASE + 0x00000044)) +#define CIF_JPE_TDC0_LEN ((CIF_JPE_BASE + 0x00000048)) +#define CIF_JPE_TAC1_LEN ((CIF_JPE_BASE + 0x0000004C)) +#define CIF_JPE_TDC1_LEN ((CIF_JPE_BASE + 0x00000050)) +#define CIF_JPE_ENCODER_BUSY ((CIF_JPE_BASE + 0x00000058)) +#define CIF_JPE_HEADER_MODE ((CIF_JPE_BASE + 0x0000005C)) +#define CIF_JPE_ENCODE_MODE ((CIF_JPE_BASE + 0x00000060)) +#define CIF_JPE_DEBUG ((CIF_JPE_BASE + 0x00000064)) +#define CIF_JPE_ERROR_IMSC ((CIF_JPE_BASE + 0x00000068)) +#define CIF_JPE_ERROR_RIS ((CIF_JPE_BASE + 0x0000006C)) +#define CIF_JPE_ERROR_MIS ((CIF_JPE_BASE + 0x00000070)) +#define CIF_JPE_ERROR_ICR ((CIF_JPE_BASE + 0x00000074)) +#define CIF_JPE_ERROR_ISR ((CIF_JPE_BASE + 0x00000078)) +#define CIF_JPE_STATUS_IMSC ((CIF_JPE_BASE + 0x0000007C)) +#define CIF_JPE_STATUS_RIS ((CIF_JPE_BASE + 0x00000080)) +#define CIF_JPE_STATUS_MIS ((CIF_JPE_BASE + 0x00000084)) +#define CIF_JPE_STATUS_ICR ((CIF_JPE_BASE + 0x00000088)) +#define CIF_JPE_STATUS_ISR ((CIF_JPE_BASE + 0x0000008C)) +#define CIF_JPE_CONFIG ((CIF_JPE_BASE + 0x00000090)) + +#define CIF_SMIA_BASE (0x00001A00) +#define CIF_SMIA_CTRL ((CIF_SMIA_BASE + 0x00000000)) +#define CIF_SMIA_STATUS ((CIF_SMIA_BASE + 0x00000004)) +#define CIF_SMIA_IMSC ((CIF_SMIA_BASE + 0x00000008)) +#define CIF_SMIA_RIS ((CIF_SMIA_BASE + 0x0000000C)) +#define CIF_SMIA_MIS ((CIF_SMIA_BASE + 0x00000010)) +#define CIF_SMIA_ICR ((CIF_SMIA_BASE + 0x00000014)) +#define CIF_SMIA_ISR ((CIF_SMIA_BASE + 0x00000018)) +#define CIF_SMIA_DATA_FORMAT_SEL ((CIF_SMIA_BASE + 0x0000001C)) +#define CIF_SMIA_SOF_EMB_DATA_LINES ((CIF_SMIA_BASE + 0x00000020)) +#define CIF_SMIA_EMB_HSTART ((CIF_SMIA_BASE + 0x00000024)) +#define CIF_SMIA_EMB_HSIZE ((CIF_SMIA_BASE + 0x00000028)) +#define CIF_SMIA_EMB_VSTART ((CIF_SMIA_BASE + 0x0000002c)) +#define CIF_SMIA_NUM_LINES ((CIF_SMIA_BASE + 0x00000030)) +#define CIF_SMIA_EMB_DATA_FIFO ((CIF_SMIA_BASE + 0x00000034)) +#define CIF_SMIA_EMB_DATA_WATERMARK ((CIF_SMIA_BASE + 0x00000038)) + +#define CIF_MIPI_BASE (0x00001C00) +#define CIF_MIPI_CTRL ((CIF_MIPI_BASE + 0x00000000)) +#define CIF_MIPI_STATUS ((CIF_MIPI_BASE + 0x00000004)) +#define CIF_MIPI_IMSC ((CIF_MIPI_BASE + 0x00000008)) +#define CIF_MIPI_RIS ((CIF_MIPI_BASE + 0x0000000C)) +#define CIF_MIPI_MIS ((CIF_MIPI_BASE + 0x00000010)) +#define CIF_MIPI_ICR ((CIF_MIPI_BASE + 0x00000014)) +#define CIF_MIPI_ISR ((CIF_MIPI_BASE + 0x00000018)) +#define CIF_MIPI_CUR_DATA_ID ((CIF_MIPI_BASE + 0x0000001C)) +#define CIF_MIPI_IMG_DATA_SEL ((CIF_MIPI_BASE + 0x00000020)) +#define CIF_MIPI_ADD_DATA_SEL_1 ((CIF_MIPI_BASE + 0x00000024)) +#define CIF_MIPI_ADD_DATA_SEL_2 ((CIF_MIPI_BASE + 0x00000028)) +#define CIF_MIPI_ADD_DATA_SEL_3 ((CIF_MIPI_BASE + 0x0000002C)) +#define CIF_MIPI_ADD_DATA_SEL_4 ((CIF_MIPI_BASE + 0x00000030)) +#define CIF_MIPI_ADD_DATA_FIFO ((CIF_MIPI_BASE + 0x00000034)) +#define CIF_MIPI_FIFO_FILL_LEVEL ((CIF_MIPI_BASE + 0x00000038)) +#define CIF_MIPI_COMPRESSED_MODE ((CIF_MIPI_BASE + 0x0000003C)) +#define CIF_MIPI_FRAME ((CIF_MIPI_BASE + 0x00000040)) +#define CIF_MIPI_GEN_SHORT_DT ((CIF_MIPI_BASE + 0x00000044)) +#define CIF_MIPI_GEN_SHORT_8_9 ((CIF_MIPI_BASE + 0x00000048)) +#define CIF_MIPI_GEN_SHORT_A_B ((CIF_MIPI_BASE + 0x0000004C)) +#define CIF_MIPI_GEN_SHORT_C_D ((CIF_MIPI_BASE + 0x00000050)) +#define CIF_MIPI_GEN_SHORT_E_F ((CIF_MIPI_BASE + 0x00000054)) + +#define CIF_ISP_AFM_BASE (0x00002000) +#define CIF_ISP_AFM_CTRL ((CIF_ISP_AFM_BASE + 0x00000000)) +#define CIF_ISP_AFM_LT_A ((CIF_ISP_AFM_BASE + 0x00000004)) +#define CIF_ISP_AFM_RB_A ((CIF_ISP_AFM_BASE + 0x00000008)) +#define CIF_ISP_AFM_LT_B ((CIF_ISP_AFM_BASE + 0x0000000C)) +#define CIF_ISP_AFM_RB_B ((CIF_ISP_AFM_BASE + 0x00000010)) +#define CIF_ISP_AFM_LT_C ((CIF_ISP_AFM_BASE + 0x00000014)) +#define CIF_ISP_AFM_RB_C ((CIF_ISP_AFM_BASE + 0x00000018)) +#define CIF_ISP_AFM_THRES ((CIF_ISP_AFM_BASE + 0x0000001C)) +#define CIF_ISP_AFM_VAR_SHIFT ((CIF_ISP_AFM_BASE + 0x00000020)) +#define CIF_ISP_AFM_SUM_A ((CIF_ISP_AFM_BASE + 0x00000024)) +#define CIF_ISP_AFM_SUM_B ((CIF_ISP_AFM_BASE + 0x00000028)) +#define CIF_ISP_AFM_SUM_C ((CIF_ISP_AFM_BASE + 0x0000002C)) +#define CIF_ISP_AFM_LUM_A ((CIF_ISP_AFM_BASE + 0x00000030)) +#define CIF_ISP_AFM_LUM_B ((CIF_ISP_AFM_BASE + 0x00000034)) +#define CIF_ISP_AFM_LUM_C ((CIF_ISP_AFM_BASE + 0x00000038)) + +#define CIF_ISP_LSC_BASE (0x00002200) +#define CIF_ISP_LSC_CTRL ((CIF_ISP_LSC_BASE + 0x00000000)) +#define CIF_ISP_LSC_R_TABLE_ADDR ((CIF_ISP_LSC_BASE + 0x00000004)) +#define CIF_ISP_LSC_GR_TABLE_ADDR ((CIF_ISP_LSC_BASE + 0x00000008)) +#define CIF_ISP_LSC_B_TABLE_ADDR ((CIF_ISP_LSC_BASE + 0x0000000C)) +#define CIF_ISP_LSC_GB_TABLE_ADDR ((CIF_ISP_LSC_BASE + 0x00000010)) +#define CIF_ISP_LSC_R_TABLE_DATA ((CIF_ISP_LSC_BASE + 0x00000014)) +#define CIF_ISP_LSC_GR_TABLE_DATA ((CIF_ISP_LSC_BASE + 0x00000018)) +#define CIF_ISP_LSC_B_TABLE_DATA ((CIF_ISP_LSC_BASE + 0x0000001C)) +#define CIF_ISP_LSC_GB_TABLE_DATA ((CIF_ISP_LSC_BASE + 0x00000020)) +#define CIF_ISP_LSC_XGRAD_01 ((CIF_ISP_LSC_BASE + 0x00000024)) +#define CIF_ISP_LSC_XGRAD_23 ((CIF_ISP_LSC_BASE + 0x00000028)) +#define CIF_ISP_LSC_XGRAD_45 ((CIF_ISP_LSC_BASE + 0x0000002C)) +#define CIF_ISP_LSC_XGRAD_67 ((CIF_ISP_LSC_BASE + 0x00000030)) +#define CIF_ISP_LSC_YGRAD_01 ((CIF_ISP_LSC_BASE + 0x00000034)) +#define CIF_ISP_LSC_YGRAD_23 ((CIF_ISP_LSC_BASE + 0x00000038)) +#define CIF_ISP_LSC_YGRAD_45 ((CIF_ISP_LSC_BASE + 0x0000003C)) +#define CIF_ISP_LSC_YGRAD_67 ((CIF_ISP_LSC_BASE + 0x00000040)) +#define CIF_ISP_LSC_XSIZE_01 ((CIF_ISP_LSC_BASE + 0x00000044)) +#define CIF_ISP_LSC_XSIZE_23 ((CIF_ISP_LSC_BASE + 0x00000048)) +#define CIF_ISP_LSC_XSIZE_45 ((CIF_ISP_LSC_BASE + 0x0000004C)) +#define CIF_ISP_LSC_XSIZE_67 ((CIF_ISP_LSC_BASE + 0x00000050)) +#define CIF_ISP_LSC_YSIZE_01 ((CIF_ISP_LSC_BASE + 0x00000054)) +#define CIF_ISP_LSC_YSIZE_23 ((CIF_ISP_LSC_BASE + 0x00000058)) +#define CIF_ISP_LSC_YSIZE_45 ((CIF_ISP_LSC_BASE + 0x0000005C)) +#define CIF_ISP_LSC_YSIZE_67 ((CIF_ISP_LSC_BASE + 0x00000060)) +#define CIF_ISP_LSC_TABLE_SEL ((CIF_ISP_LSC_BASE + 0x00000064)) +#define CIF_ISP_LSC_STATUS ((CIF_ISP_LSC_BASE + 0x00000068)) + +#define CIF_ISP_IS_BASE (0x00002300) +#define CIF_ISP_IS_CTRL ((CIF_ISP_IS_BASE + 0x00000000)) +#define CIF_ISP_IS_RECENTER ((CIF_ISP_IS_BASE + 0x00000004)) +#define CIF_ISP_IS_H_OFFS ((CIF_ISP_IS_BASE + 0x00000008)) +#define CIF_ISP_IS_V_OFFS ((CIF_ISP_IS_BASE + 0x0000000C)) +#define CIF_ISP_IS_H_SIZE ((CIF_ISP_IS_BASE + 0x00000010)) +#define CIF_ISP_IS_V_SIZE ((CIF_ISP_IS_BASE + 0x00000014)) +#define CIF_ISP_IS_MAX_DX ((CIF_ISP_IS_BASE + 0x00000018)) +#define CIF_ISP_IS_MAX_DY ((CIF_ISP_IS_BASE + 0x0000001C)) +#define CIF_ISP_IS_DISPLACE ((CIF_ISP_IS_BASE + 0x00000020)) +#define CIF_ISP_IS_H_OFFS_SHD ((CIF_ISP_IS_BASE + 0x00000024)) +#define CIF_ISP_IS_V_OFFS_SHD ((CIF_ISP_IS_BASE + 0x00000028)) +#define CIF_ISP_IS_H_SIZE_SHD ((CIF_ISP_IS_BASE + 0x0000002C)) +#define CIF_ISP_IS_V_SIZE_SHD ((CIF_ISP_IS_BASE + 0x00000030)) + +#define CIF_ISP_HIST_BASE (0x00002400) + +#define CIF_ISP_HIST_PROP ((CIF_ISP_HIST_BASE + 0x00000000)) +#define CIF_ISP_HIST_H_OFFS ((CIF_ISP_HIST_BASE + 0x00000004)) +#define CIF_ISP_HIST_V_OFFS ((CIF_ISP_HIST_BASE + 0x00000008)) +#define CIF_ISP_HIST_H_SIZE ((CIF_ISP_HIST_BASE + 0x0000000C)) +#define CIF_ISP_HIST_V_SIZE ((CIF_ISP_HIST_BASE + 0x00000010)) +#define CIF_ISP_HIST_BIN_0 ((CIF_ISP_HIST_BASE + 0x00000014)) +#define CIF_ISP_HIST_BIN_1 ((CIF_ISP_HIST_BASE + 0x00000018)) +#define CIF_ISP_HIST_BIN_2 ((CIF_ISP_HIST_BASE + 0x0000001C)) +#define CIF_ISP_HIST_BIN_3 ((CIF_ISP_HIST_BASE + 0x00000020)) +#define CIF_ISP_HIST_BIN_4 ((CIF_ISP_HIST_BASE + 0x00000024)) +#define CIF_ISP_HIST_BIN_5 ((CIF_ISP_HIST_BASE + 0x00000028)) +#define CIF_ISP_HIST_BIN_6 ((CIF_ISP_HIST_BASE + 0x0000002C)) +#define CIF_ISP_HIST_BIN_7 ((CIF_ISP_HIST_BASE + 0x00000030)) +#define CIF_ISP_HIST_BIN_8 ((CIF_ISP_HIST_BASE + 0x00000034)) +#define CIF_ISP_HIST_BIN_9 ((CIF_ISP_HIST_BASE + 0x00000038)) +#define CIF_ISP_HIST_BIN_10 ((CIF_ISP_HIST_BASE + 0x0000003C)) +#define CIF_ISP_HIST_BIN_11 ((CIF_ISP_HIST_BASE + 0x00000040)) +#define CIF_ISP_HIST_BIN_12 ((CIF_ISP_HIST_BASE + 0x00000044)) +#define CIF_ISP_HIST_BIN_13 ((CIF_ISP_HIST_BASE + 0x00000048)) +#define CIF_ISP_HIST_BIN_14 ((CIF_ISP_HIST_BASE + 0x0000004C)) +#define CIF_ISP_HIST_BIN_15 ((CIF_ISP_HIST_BASE + 0x00000050)) +#define CIF_ISP_HIST_WEIGHT_00TO30 ((CIF_ISP_HIST_BASE + 0x00000054)) +#define CIF_ISP_HIST_WEIGHT_40TO21 ((CIF_ISP_HIST_BASE + 0x00000058)) +#define CIF_ISP_HIST_WEIGHT_31TO12 ((CIF_ISP_HIST_BASE + 0x0000005C)) +#define CIF_ISP_HIST_WEIGHT_22TO03 ((CIF_ISP_HIST_BASE + 0x00000060)) +#define CIF_ISP_HIST_WEIGHT_13TO43 ((CIF_ISP_HIST_BASE + 0x00000064)) +#define CIF_ISP_HIST_WEIGHT_04TO34 ((CIF_ISP_HIST_BASE + 0x00000068)) +#define CIF_ISP_HIST_WEIGHT_44 ((CIF_ISP_HIST_BASE + 0x0000006C)) + +#define CIF_ISP_FILT_BASE (0x00002500) +#define CIF_ISP_FILT_MODE ((CIF_ISP_FILT_BASE + 0x00000000)) +#define CIF_ISP_FILT_THRESH_BL0 ((CIF_ISP_FILT_BASE + 0x00000028)) +#define CIF_ISP_FILT_THRESH_BL1 ((CIF_ISP_FILT_BASE + 0x0000002c)) +#define CIF_ISP_FILT_THRESH_SH0 ((CIF_ISP_FILT_BASE + 0x00000030)) +#define CIF_ISP_FILT_THRESH_SH1 ((CIF_ISP_FILT_BASE + 0x00000034)) +#define CIF_ISP_FILT_LUM_WEIGHT ((CIF_ISP_FILT_BASE + 0x00000038)) +#define CIF_ISP_FILT_FAC_SH1 ((CIF_ISP_FILT_BASE + 0x0000003c)) +#define CIF_ISP_FILT_FAC_SH0 ((CIF_ISP_FILT_BASE + 0x00000040)) +#define CIF_ISP_FILT_FAC_MID ((CIF_ISP_FILT_BASE + 0x00000044)) +#define CIF_ISP_FILT_FAC_BL0 ((CIF_ISP_FILT_BASE + 0x00000048)) +#define CIF_ISP_FILT_FAC_BL1 ((CIF_ISP_FILT_BASE + 0x0000004C)) + +#define CIF_ISP_CAC_BASE (0x00002580) +#define CIF_ISP_CAC_CTRL (CIF_ISP_CAC_BASE + 0x00000000) +#define CIF_ISP_CAC_COUNT_START (CIF_ISP_CAC_BASE + 0x00000004) +#define CIF_ISP_CAC_A (CIF_ISP_CAC_BASE + 0x00000008) +#define CIF_ISP_CAC_B (CIF_ISP_CAC_BASE + 0x0000000C) +#define CIF_ISP_CAC_C (CIF_ISP_CAC_BASE + 0x00000010) +#define CIF_ISP_X_NORM (CIF_ISP_CAC_BASE + 0x00000014) +#define CIF_ISP_Y_NORM (CIF_ISP_CAC_BASE + 0x00000018) + +#define CIF_ISP_EXP_BASE (0x00002600) +#define CIF_ISP_EXP_CTRL ((CIF_ISP_EXP_BASE + 0x00000000)) +#define CIF_ISP_EXP_H_OFFSET ((CIF_ISP_EXP_BASE + 0x00000004)) +#define CIF_ISP_EXP_V_OFFSET ((CIF_ISP_EXP_BASE + 0x00000008)) +#define CIF_ISP_EXP_H_SIZE ((CIF_ISP_EXP_BASE + 0x0000000C)) +#define CIF_ISP_EXP_V_SIZE ((CIF_ISP_EXP_BASE + 0x00000010)) +#define CIF_ISP_EXP_MEAN_00 ((CIF_ISP_EXP_BASE + 0x00000014)) +#define CIF_ISP_EXP_MEAN_10 ((CIF_ISP_EXP_BASE + 0x00000018)) +#define CIF_ISP_EXP_MEAN_20 ((CIF_ISP_EXP_BASE + 0x0000001c)) +#define CIF_ISP_EXP_MEAN_30 ((CIF_ISP_EXP_BASE + 0x00000020)) +#define CIF_ISP_EXP_MEAN_40 ((CIF_ISP_EXP_BASE + 0x00000024)) +#define CIF_ISP_EXP_MEAN_01 ((CIF_ISP_EXP_BASE + 0x00000028)) +#define CIF_ISP_EXP_MEAN_11 ((CIF_ISP_EXP_BASE + 0x0000002c)) +#define CIF_ISP_EXP_MEAN_21 ((CIF_ISP_EXP_BASE + 0x00000030)) +#define CIF_ISP_EXP_MEAN_31 ((CIF_ISP_EXP_BASE + 0x00000034)) +#define CIF_ISP_EXP_MEAN_41 ((CIF_ISP_EXP_BASE + 0x00000038)) +#define CIF_ISP_EXP_MEAN_02 ((CIF_ISP_EXP_BASE + 0x0000003c)) +#define CIF_ISP_EXP_MEAN_12 ((CIF_ISP_EXP_BASE + 0x00000040)) +#define CIF_ISP_EXP_MEAN_22 ((CIF_ISP_EXP_BASE + 0x00000044)) +#define CIF_ISP_EXP_MEAN_32 ((CIF_ISP_EXP_BASE + 0x00000048)) +#define CIF_ISP_EXP_MEAN_42 ((CIF_ISP_EXP_BASE + 0x0000004c)) +#define CIF_ISP_EXP_MEAN_03 ((CIF_ISP_EXP_BASE + 0x00000050)) +#define CIF_ISP_EXP_MEAN_13 ((CIF_ISP_EXP_BASE + 0x00000054)) +#define CIF_ISP_EXP_MEAN_23 ((CIF_ISP_EXP_BASE + 0x00000058)) +#define CIF_ISP_EXP_MEAN_33 ((CIF_ISP_EXP_BASE + 0x0000005c)) +#define CIF_ISP_EXP_MEAN_43 ((CIF_ISP_EXP_BASE + 0x00000060)) +#define CIF_ISP_EXP_MEAN_04 ((CIF_ISP_EXP_BASE + 0x00000064)) +#define CIF_ISP_EXP_MEAN_14 ((CIF_ISP_EXP_BASE + 0x00000068)) +#define CIF_ISP_EXP_MEAN_24 ((CIF_ISP_EXP_BASE + 0x0000006c)) +#define CIF_ISP_EXP_MEAN_34 ((CIF_ISP_EXP_BASE + 0x00000070)) +#define CIF_ISP_EXP_MEAN_44 ((CIF_ISP_EXP_BASE + 0x00000074)) + +#define CIF_ISP_BLS_BASE (0x00002700) +#define CIF_ISP_BLS_CTRL ((CIF_ISP_BLS_BASE + 0x00000000)) +#define CIF_ISP_BLS_SAMPLES ((CIF_ISP_BLS_BASE + 0x00000004)) +#define CIF_ISP_BLS_H1_START ((CIF_ISP_BLS_BASE + 0x00000008)) +#define CIF_ISP_BLS_H1_STOP ((CIF_ISP_BLS_BASE + 0x0000000c)) +#define CIF_ISP_BLS_V1_START ((CIF_ISP_BLS_BASE + 0x00000010)) +#define CIF_ISP_BLS_V1_STOP ((CIF_ISP_BLS_BASE + 0x00000014)) +#define CIF_ISP_BLS_H2_START ((CIF_ISP_BLS_BASE + 0x00000018)) +#define CIF_ISP_BLS_H2_STOP ((CIF_ISP_BLS_BASE + 0x0000001c)) +#define CIF_ISP_BLS_V2_START ((CIF_ISP_BLS_BASE + 0x00000020)) +#define CIF_ISP_BLS_V2_STOP ((CIF_ISP_BLS_BASE + 0x00000024)) +#define CIF_ISP_BLS_A_FIXED ((CIF_ISP_BLS_BASE + 0x00000028)) +#define CIF_ISP_BLS_B_FIXED ((CIF_ISP_BLS_BASE + 0x0000002c)) +#define CIF_ISP_BLS_C_FIXED ((CIF_ISP_BLS_BASE + 0x00000030)) +#define CIF_ISP_BLS_D_FIXED ((CIF_ISP_BLS_BASE + 0x00000034)) +#define CIF_ISP_BLS_A_MEASURED ((CIF_ISP_BLS_BASE + 0x00000038)) +#define CIF_ISP_BLS_B_MEASURED ((CIF_ISP_BLS_BASE + 0x0000003c)) +#define CIF_ISP_BLS_C_MEASURED ((CIF_ISP_BLS_BASE + 0x00000040)) +#define CIF_ISP_BLS_D_MEASURED ((CIF_ISP_BLS_BASE + 0x00000044)) + +#define CIF_ISP_DPF_BASE (0x00002800) +#define CIF_ISP_DPF_MODE (CIF_ISP_DPF_BASE + 0x00000000) +#define CIF_ISP_DPF_STRENGTH_R (CIF_ISP_DPF_BASE + 0x00000004) +#define CIF_ISP_DPF_STRENGTH_G (CIF_ISP_DPF_BASE + 0x00000008) +#define CIF_ISP_DPF_STRENGTH_B (CIF_ISP_DPF_BASE + 0x0000000C) +#define CIF_ISP_DPF_S_WEIGHT_G_1_4 (CIF_ISP_DPF_BASE + 0x00000010) +#define CIF_ISP_DPF_S_WEIGHT_G_5_6 (CIF_ISP_DPF_BASE + 0x00000014) +#define CIF_ISP_DPF_S_WEIGHT_RB_1_4 (CIF_ISP_DPF_BASE + 0x00000018) +#define CIF_ISP_DPF_S_WEIGHT_RB_5_6 (CIF_ISP_DPF_BASE + 0x0000001C) +#define CIF_ISP_DPF_NULL_COEFF_0 (CIF_ISP_DPF_BASE + 0x00000020) +#define CIF_ISP_DPF_NULL_COEFF_1 (CIF_ISP_DPF_BASE + 0x00000024) +#define CIF_ISP_DPF_NULL_COEFF_2 (CIF_ISP_DPF_BASE + 0x00000028) +#define CIF_ISP_DPF_NULL_COEFF_3 (CIF_ISP_DPF_BASE + 0x0000002C) +#define CIF_ISP_DPF_NULL_COEFF_4 (CIF_ISP_DPF_BASE + 0x00000030) +#define CIF_ISP_DPF_NULL_COEFF_5 (CIF_ISP_DPF_BASE + 0x00000034) +#define CIF_ISP_DPF_NULL_COEFF_6 (CIF_ISP_DPF_BASE + 0x00000038) +#define CIF_ISP_DPF_NULL_COEFF_7 (CIF_ISP_DPF_BASE + 0x0000003C) +#define CIF_ISP_DPF_NULL_COEFF_8 (CIF_ISP_DPF_BASE + 0x00000040) +#define CIF_ISP_DPF_NULL_COEFF_9 (CIF_ISP_DPF_BASE + 0x00000044) +#define CIF_ISP_DPF_NULL_COEFF_10 (CIF_ISP_DPF_BASE + 0x00000048) +#define CIF_ISP_DPF_NULL_COEFF_11 (CIF_ISP_DPF_BASE + 0x0000004C) +#define CIF_ISP_DPF_NULL_COEFF_12 (CIF_ISP_DPF_BASE + 0x00000050) +#define CIF_ISP_DPF_NULL_COEFF_13 (CIF_ISP_DPF_BASE + 0x00000054) +#define CIF_ISP_DPF_NULL_COEFF_14 (CIF_ISP_DPF_BASE + 0x00000058) +#define CIF_ISP_DPF_NULL_COEFF_15 (CIF_ISP_DPF_BASE + 0x0000005C) +#define CIF_ISP_DPF_NULL_COEFF_16 (CIF_ISP_DPF_BASE + 0x00000060) +#define CIF_ISP_DPF_NF_GAIN_R (CIF_ISP_DPF_BASE + 0x00000064) +#define CIF_ISP_DPF_NF_GAIN_GR (CIF_ISP_DPF_BASE + 0x00000068) +#define CIF_ISP_DPF_NF_GAIN_GB (CIF_ISP_DPF_BASE + 0x0000006C) +#define CIF_ISP_DPF_NF_GAIN_B (CIF_ISP_DPF_BASE + 0x00000070) + +#define CIF_ISP_DPCC_BASE (0x00002900) +#define CIF_ISP_DPCC_MODE (CIF_ISP_DPCC_BASE + 0x00000000) +#define CIF_ISP_DPCC_OUTPUT_MODE (CIF_ISP_DPCC_BASE + 0x00000004) +#define CIF_ISP_DPCC_SET_USE (CIF_ISP_DPCC_BASE + 0x00000008) +#define CIF_ISP_DPCC_METHODS_SET_1 (CIF_ISP_DPCC_BASE + 0x0000000C) +#define CIF_ISP_DPCC_METHODS_SET_2 (CIF_ISP_DPCC_BASE + 0x00000010) +#define CIF_ISP_DPCC_METHODS_SET_3 (CIF_ISP_DPCC_BASE + 0x00000014) +#define CIF_ISP_DPCC_LINE_THRESH_1 (CIF_ISP_DPCC_BASE + 0x00000018) +#define CIF_ISP_DPCC_LINE_MAD_FAC_1 (CIF_ISP_DPCC_BASE + 0x0000001C) +#define CIF_ISP_DPCC_PG_FAC_1 (CIF_ISP_DPCC_BASE + 0x00000020) +#define CIF_ISP_DPCC_RND_THRESH_1 (CIF_ISP_DPCC_BASE + 0x00000024) +#define CIF_ISP_DPCC_RG_FAC_1 (CIF_ISP_DPCC_BASE + 0x00000028) +#define CIF_ISP_DPCC_LINE_THRESH_2 (CIF_ISP_DPCC_BASE + 0x0000002C) +#define CIF_ISP_DPCC_LINE_MAD_FAC_2 (CIF_ISP_DPCC_BASE + 0x00000030) +#define CIF_ISP_DPCC_PG_FAC_2 (CIF_ISP_DPCC_BASE + 0x00000034) +#define CIF_ISP_DPCC_RND_THRESH_2 (CIF_ISP_DPCC_BASE + 0x00000038) +#define CIF_ISP_DPCC_RG_FAC_2 (CIF_ISP_DPCC_BASE + 0x0000003C) +#define CIF_ISP_DPCC_LINE_THRESH_3 (CIF_ISP_DPCC_BASE + 0x00000040) +#define CIF_ISP_DPCC_LINE_MAD_FAC_3 (CIF_ISP_DPCC_BASE + 0x00000044) +#define CIF_ISP_DPCC_PG_FAC_3 (CIF_ISP_DPCC_BASE + 0x00000048) +#define CIF_ISP_DPCC_RND_THRESH_3 (CIF_ISP_DPCC_BASE + 0x0000004C) +#define CIF_ISP_DPCC_RG_FAC_3 (CIF_ISP_DPCC_BASE + 0x00000050) +#define CIF_ISP_DPCC_RO_LIMITS (CIF_ISP_DPCC_BASE + 0x00000054) +#define CIF_ISP_DPCC_RND_OFFS (CIF_ISP_DPCC_BASE + 0x00000058) +#define CIF_ISP_DPCC_BPT_CTRL (CIF_ISP_DPCC_BASE + 0x0000005C) +#define CIF_ISP_DPCC_BPT_NUMBER (CIF_ISP_DPCC_BASE + 0x00000060) +#define CIF_ISP_DPCC_BPT_ADDR (CIF_ISP_DPCC_BASE + 0x00000064) +#define CIF_ISP_DPCC_BPT_DATA (CIF_ISP_DPCC_BASE + 0x00000068) + +#define CIF_ISP_WDR_BASE (0x00002A00) +#define CIF_ISP_WDR_CTRL (CIF_ISP_WDR_BASE + 0x00000000) +#define CIF_ISP_WDR_TONECURVE_1 (CIF_ISP_WDR_BASE + 0x00000004) +#define CIF_ISP_WDR_TONECURVE_2 (CIF_ISP_WDR_BASE + 0x00000008) +#define CIF_ISP_WDR_TONECURVE_3 (CIF_ISP_WDR_BASE + 0x0000000C) +#define CIF_ISP_WDR_TONECURVE_4 (CIF_ISP_WDR_BASE + 0x00000010) +#define CIF_ISP_WDR_TONECURVE_YM_0 (CIF_ISP_WDR_BASE + 0x00000014) +#define CIF_ISP_WDR_TONECURVE_YM_1 (CIF_ISP_WDR_BASE + 0x00000018) +#define CIF_ISP_WDR_TONECURVE_YM_2 (CIF_ISP_WDR_BASE + 0x0000001C) +#define CIF_ISP_WDR_TONECURVE_YM_3 (CIF_ISP_WDR_BASE + 0x00000020) +#define CIF_ISP_WDR_TONECURVE_YM_4 (CIF_ISP_WDR_BASE + 0x00000024) +#define CIF_ISP_WDR_TONECURVE_YM_5 (CIF_ISP_WDR_BASE + 0x00000028) +#define CIF_ISP_WDR_TONECURVE_YM_6 (CIF_ISP_WDR_BASE + 0x0000002C) +#define CIF_ISP_WDR_TONECURVE_YM_7 (CIF_ISP_WDR_BASE + 0x00000030) +#define CIF_ISP_WDR_TONECURVE_YM_8 (CIF_ISP_WDR_BASE + 0x00000034) +#define CIF_ISP_WDR_TONECURVE_YM_9 (CIF_ISP_WDR_BASE + 0x00000038) +#define CIF_ISP_WDR_TONECURVE_YM_10 (CIF_ISP_WDR_BASE + 0x0000003C) +#define CIF_ISP_WDR_TONECURVE_YM_11 (CIF_ISP_WDR_BASE + 0x00000040) +#define CIF_ISP_WDR_TONECURVE_YM_12 (CIF_ISP_WDR_BASE + 0x00000044) +#define CIF_ISP_WDR_TONECURVE_YM_13 (CIF_ISP_WDR_BASE + 0x00000048) +#define CIF_ISP_WDR_TONECURVE_YM_14 (CIF_ISP_WDR_BASE + 0x0000004C) +#define CIF_ISP_WDR_TONECURVE_YM_15 (CIF_ISP_WDR_BASE + 0x00000050) +#define CIF_ISP_WDR_TONECURVE_YM_16 (CIF_ISP_WDR_BASE + 0x00000054) +#define CIF_ISP_WDR_TONECURVE_YM_17 (CIF_ISP_WDR_BASE + 0x00000058) +#define CIF_ISP_WDR_TONECURVE_YM_18 (CIF_ISP_WDR_BASE + 0x0000005C) +#define CIF_ISP_WDR_TONECURVE_YM_19 (CIF_ISP_WDR_BASE + 0x00000060) +#define CIF_ISP_WDR_TONECURVE_YM_20 (CIF_ISP_WDR_BASE + 0x00000064) +#define CIF_ISP_WDR_TONECURVE_YM_21 (CIF_ISP_WDR_BASE + 0x00000068) +#define CIF_ISP_WDR_TONECURVE_YM_22 (CIF_ISP_WDR_BASE + 0x0000006C) +#define CIF_ISP_WDR_TONECURVE_YM_23 (CIF_ISP_WDR_BASE + 0x00000070) +#define CIF_ISP_WDR_TONECURVE_YM_24 (CIF_ISP_WDR_BASE + 0x00000074) +#define CIF_ISP_WDR_TONECURVE_YM_25 (CIF_ISP_WDR_BASE + 0x00000078) +#define CIF_ISP_WDR_TONECURVE_YM_26 (CIF_ISP_WDR_BASE + 0x0000007C) +#define CIF_ISP_WDR_TONECURVE_YM_27 (CIF_ISP_WDR_BASE + 0x00000080) +#define CIF_ISP_WDR_TONECURVE_YM_28 (CIF_ISP_WDR_BASE + 0x00000084) +#define CIF_ISP_WDR_TONECURVE_YM_29 (CIF_ISP_WDR_BASE + 0x00000088) +#define CIF_ISP_WDR_TONECURVE_YM_30 (CIF_ISP_WDR_BASE + 0x0000008C) +#define CIF_ISP_WDR_TONECURVE_YM_31 (CIF_ISP_WDR_BASE + 0x00000090) +#define CIF_ISP_WDR_TONECURVE_YM_32 (CIF_ISP_WDR_BASE + 0x00000094) +#define CIF_ISP_WDR_OFFSET (CIF_ISP_WDR_BASE + 0x00000098) +#define CIF_ISP_WDR_DELTAMIN (CIF_ISP_WDR_BASE + 0x0000009C) +#define CIF_ISP_WDR_TONECURVE_1_SHD (CIF_ISP_WDR_BASE + 0x000000A0) +#define CIF_ISP_WDR_TONECURVE_2_SHD (CIF_ISP_WDR_BASE + 0x000000A4) +#define CIF_ISP_WDR_TONECURVE_3_SHD (CIF_ISP_WDR_BASE + 0x000000A8) +#define CIF_ISP_WDR_TONECURVE_4_SHD (CIF_ISP_WDR_BASE + 0x000000AC) +#define CIF_ISP_WDR_TONECURVE_YM_0_SHD (CIF_ISP_WDR_BASE + 0x000000B0) +#define CIF_ISP_WDR_TONECURVE_YM_1_SHD (CIF_ISP_WDR_BASE + 0x000000B4) +#define CIF_ISP_WDR_TONECURVE_YM_2_SHD (CIF_ISP_WDR_BASE + 0x000000B8) +#define CIF_ISP_WDR_TONECURVE_YM_3_SHD (CIF_ISP_WDR_BASE + 0x000000BC) +#define CIF_ISP_WDR_TONECURVE_YM_4_SHD (CIF_ISP_WDR_BASE + 0x000000C0) +#define CIF_ISP_WDR_TONECURVE_YM_5_SHD (CIF_ISP_WDR_BASE + 0x000000C4) +#define CIF_ISP_WDR_TONECURVE_YM_6_SHD (CIF_ISP_WDR_BASE + 0x000000C8) +#define CIF_ISP_WDR_TONECURVE_YM_7_SHD (CIF_ISP_WDR_BASE + 0x000000CC) +#define CIF_ISP_WDR_TONECURVE_YM_8_SHD (CIF_ISP_WDR_BASE + 0x000000D0) +#define CIF_ISP_WDR_TONECURVE_YM_9_SHD (CIF_ISP_WDR_BASE + 0x000000D4) +#define CIF_ISP_WDR_TONECURVE_YM_10_SHD (CIF_ISP_WDR_BASE + 0x000000D8) +#define CIF_ISP_WDR_TONECURVE_YM_11_SHD (CIF_ISP_WDR_BASE + 0x000000DC) +#define CIF_ISP_WDR_TONECURVE_YM_12_SHD (CIF_ISP_WDR_BASE + 0x000000E0) +#define CIF_ISP_WDR_TONECURVE_YM_13_SHD (CIF_ISP_WDR_BASE + 0x000000E4) +#define CIF_ISP_WDR_TONECURVE_YM_14_SHD (CIF_ISP_WDR_BASE + 0x000000E8) +#define CIF_ISP_WDR_TONECURVE_YM_15_SHD (CIF_ISP_WDR_BASE + 0x000000EC) +#define CIF_ISP_WDR_TONECURVE_YM_16_SHD (CIF_ISP_WDR_BASE + 0x000000F0) +#define CIF_ISP_WDR_TONECURVE_YM_17_SHD (CIF_ISP_WDR_BASE + 0x000000F4) +#define CIF_ISP_WDR_TONECURVE_YM_18_SHD (CIF_ISP_WDR_BASE + 0x000000F8) +#define CIF_ISP_WDR_TONECURVE_YM_19_SHD (CIF_ISP_WDR_BASE + 0x000000FC) +#define CIF_ISP_WDR_TONECURVE_YM_20_SHD (CIF_ISP_WDR_BASE + 0x00000100) +#define CIF_ISP_WDR_TONECURVE_YM_21_SHD (CIF_ISP_WDR_BASE + 0x00000104) +#define CIF_ISP_WDR_TONECURVE_YM_22_SHD (CIF_ISP_WDR_BASE + 0x00000108) +#define CIF_ISP_WDR_TONECURVE_YM_23_SHD (CIF_ISP_WDR_BASE + 0x0000010C) +#define CIF_ISP_WDR_TONECURVE_YM_24_SHD (CIF_ISP_WDR_BASE + 0x00000110) +#define CIF_ISP_WDR_TONECURVE_YM_25_SHD (CIF_ISP_WDR_BASE + 0x00000114) +#define CIF_ISP_WDR_TONECURVE_YM_26_SHD (CIF_ISP_WDR_BASE + 0x00000118) +#define CIF_ISP_WDR_TONECURVE_YM_27_SHD (CIF_ISP_WDR_BASE + 0x0000011C) +#define CIF_ISP_WDR_TONECURVE_YM_28_SHD (CIF_ISP_WDR_BASE + 0x00000120) +#define CIF_ISP_WDR_TONECURVE_YM_29_SHD (CIF_ISP_WDR_BASE + 0x00000124) +#define CIF_ISP_WDR_TONECURVE_YM_30_SHD (CIF_ISP_WDR_BASE + 0x00000128) +#define CIF_ISP_WDR_TONECURVE_YM_31_SHD (CIF_ISP_WDR_BASE + 0x0000012C) +#define CIF_ISP_WDR_TONECURVE_YM_32_SHD (CIF_ISP_WDR_BASE + 0x00000130) + +#define CIF_ISP_VSM_BASE (0x00002F00) +#define CIF_ISP_VSM_MODE (CIF_ISP_VSM_BASE + 0x00000000) +#define CIF_ISP_VSM_H_OFFS (CIF_ISP_VSM_BASE + 0x00000004) +#define CIF_ISP_VSM_V_OFFS (CIF_ISP_VSM_BASE + 0x00000008) +#define CIF_ISP_VSM_H_SIZE (CIF_ISP_VSM_BASE + 0x0000000C) +#define CIF_ISP_VSM_V_SIZE (CIF_ISP_VSM_BASE + 0x00000010) +#define CIF_ISP_VSM_H_SEGMENTS (CIF_ISP_VSM_BASE + 0x00000014) +#define CIF_ISP_VSM_V_SEGMENTS (CIF_ISP_VSM_BASE + 0x00000018) +#define CIF_ISP_VSM_DELTA_H (CIF_ISP_VSM_BASE + 0x0000001C) +#define CIF_ISP_VSM_DELTA_V (CIF_ISP_VSM_BASE + 0x00000020) +#endif diff --git a/drivers/media/platform/rk-isp10/cif_isp10_rk3288.c b/drivers/media/platform/rk-isp10/cif_isp10_rk3288.c new file mode 100644 index 000000000000..b6160595448d --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_rk3288.c @@ -0,0 +1,616 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ONE_LANE_ENABLE_BIT 0x1 +#define TWO_LANE_ENABLE_BIT 0x2 +#define FOUR_LANE_ENABLE_BIT 0x4 + +#define MRV_MIPI_BASE 0x1C00 +#define MRV_MIPI_CTRL 0x00 + +/* + * GRF_SOC_CON14 + * bit 0 dphy_rx0_testclr + * bit 1 dphy_rx0_testclk + * bit 2 dphy_rx0_testen + * bit 3:10 dphy_rx0_testdin + */ +#define GRF_SOC_CON14_OFFSET (0x027c) +#define DPHY_RX0_TESTCLR_MASK (0x1 << 16) +#define DPHY_RX0_TESTCLK_MASK (0x1 << 17) +#define DPHY_RX0_TESTEN_MASK (0x1 << 18) +#define DPHY_RX0_TESTDIN_MASK (0xff << 19) + +#define DPHY_RX0_TESTCLR BIT(0) +#define DPHY_RX0_TESTCLK BIT(1) +#define DPHY_RX0_TESTEN BIT(2) +#define DPHY_RX0_TESTDIN_OFFSET (3) + +#define DPHY_TX1RX1_ENABLECLK_MASK (0x1 << 28) +#define DPHY_RX1_SRC_SEL_MASK (0x1 << 29) +#define DPHY_TX1RX1_MASTERSLAVEZ_MASK (0x1 << 30) +#define DPHY_TX1RX1_BASEDIR_OFFSET (0x1 << 31) + +#define DPHY_TX1RX1_ENABLECLK (0x1 << 12) +#define DPHY_TX1RX1_DISABLECLK (0x0 << 12) +#define DPHY_RX1_SRC_SEL_ISP (0x1 << 13) +#define DPHY_TX1RX1_SLAVEZ (0x0 << 14) +#define DPHY_TX1RX1_BASEDIR_REC (0x1 << 15) + +/* + * GRF_SOC_CON6 + * bit 0 grf_con_disable_isp + * bit 1 grf_con_isp_dphy_sel 1'b0 mipi phy rx0 + */ +#define GRF_SOC_CON6_OFFSET (0x025c) +#define MIPI_PHY_DISABLE_ISP_MASK (0x1 << 16) +#define MIPI_PHY_DISABLE_ISP (0x0 << 0) + +#define DSI_CSI_TESTBUS_SEL_MASK (0x1 << 30) +#define DSI_CSI_TESTBUS_SEL_OFFSET_BIT (14) + +#define MIPI_PHY_DPHYSEL_OFFSET_MASK (0x1 << 17) +#define MIPI_PHY_DPHYSEL_OFFSET_BIT (0x1) + +/* + * GRF_SOC_CON10 + * bit12:15 grf_dphy_rx0_enable + * bit 0:3 turn disable + */ +#define GRF_SOC_CON10_OFFSET (0x026c) +#define DPHY_RX0_TURN_DISABLE_MASK (0xf << 16) +#define DPHY_RX0_TURN_DISABLE_OFFSET_BITS (0x0) +#define DPHY_RX0_ENABLE_MASK (0xf << 28) +#define DPHY_RX0_ENABLE_OFFSET_BITS (12) + +/* + * GRF_SOC_CON9 + * bit12:15 grf_dphy_rx0_enable + * bit 0:3 turn disable + */ +#define GRF_SOC_CON9_OFFSET (0x0268) +#define DPHY_TX1RX1_TURN_DISABLE_MASK (0xf << 16) +#define DPHY_TX1RX1_TURN_DISABLE_OFFSET_BITS (0x0) +#define DPHY_TX1RX1_ENABLE_MASK (0xf << 28) +#define DPHY_TX1RX1_ENABLE_OFFSET_BITS (12) + +/* + * GRF_SOC_CON15 + * bit 0:3 turn request + */ +#define GRF_SOC_CON15_OFFSET (0x03a4) +#define DPHY_RX0_TURN_REQUEST_MASK (0xf << 16) +#define DPHY_RX0_TURN_REQUEST_OFFSET_BITS (0x0) + +#define DPHY_TX1RX1_TURN_REQUEST_MASK (0xf << 20) +#define DPHY_TX1RX1_TURN_REQUEST_OFFSET_BITS (0x0) + +/* + * GRF_SOC_STATUS21 + * bit0:7 dphy_rx0_testdout + */ +#define GRF_SOC_STATUS21_OFFSET (0x2D4) +#define DPHY_RX0_TESTDOUT(a) ((a) & 0xff) + +/* + * GRF_IO_VSEL + */ +#define GRF_IO_VSEL_OFFSET (0x0380) +#define DVP_V18SEL ((1 << 1) | (1 << 17)) +#define DVP_V33SEL ((0 << 1) | (1 << 17)) + +/* + * GRF_IO_VSEL + */ +#define GRF_GPIO2B_E_OFFSET (0x0380) +#define CIF_CLKOUT_STRENGTH(a) ((((a) & 0x03) << 3) | (0x03 << 19)) + +/* + * CSI HOST + */ + +#define CSIHOST_PHY_TEST_CTRL0 (0x30) +#define CSIHOST_PHY_TEST_CTRL1 (0x34) +#define CSIHOST_PHY_SHUTDOWNZ (0x08) +#define CSIHOST_DPHY_RSTZ (0x0c) +#define CSIHOST_N_LANES (0x04) +#define CSIHOST_CSI2_RESETN (0x10) +#define CSIHOST_PHY_STATE (0x14) +#define CSIHOST_DATA_IDS1 (0x18) +#define CSIHOST_DATA_IDS2 (0x1C) +#define CSIHOST_ERR1 (0x20) +#define CSIHOST_ERR2 (0x24) + +#define write_cifisp_reg(addr, val) \ + __raw_writel(val, (addr) + rk3288->isp_base) +#define read_cifisp_reg(addr) \ + __raw_readl((addr) + rk3288->isp_base) + +#define write_grf_reg(addr, val) \ + regmap_write(rk3288->regmap_grf, addr, val) +#define read_grf_reg(addr, val) regmap_read(rk3288->regmap_grf, addr, val) + +#define write_csihost_reg(addr, val) \ + __raw_writel(val, (addr) + rk3288->csihost_base) +#define read_csihost_reg(addr) __raw_readl((addr) + rk3288->csihost_base) + +struct cif_isp10_clk_rst_rk3288 { + struct clk *aclk_isp; + struct clk *hclk_isp; + struct clk *sclk_isp; + struct clk *sclk_isp_jpe; + struct clk *sclk_mipidsi_24m; + struct clk *pclk_mipi_csi; + struct clk *pclk_isp_in; + struct reset_control *isp_rst; +}; + +struct cif_isp10_rk3288 { + struct regmap *regmap_grf; + void __iomem *csihost_base; + void __iomem *isp_base; + struct cif_isp10_clk_rst_rk3288 clk_rst; + struct cif_isp10_device *cif_isp10; +}; + +struct mipi_dphy_hsfreqrange { + unsigned int range_l; + unsigned int range_h; + unsigned char cfg_bit; +}; + +static struct mipi_dphy_hsfreqrange mipi_dphy_hsfreq_range[] = { + {80, 90, 0x00}, + {90, 100, 0x10}, + {100, 110, 0x20}, + {110, 130, 0x01}, + {130, 140, 0x11}, + {140, 150, 0x21}, + {150, 170, 0x02}, + {170, 180, 0x12}, + {180, 200, 0x22}, + {200, 220, 0x03}, + {220, 240, 0x13}, + {240, 250, 0x23}, + {250, 270, 0x4}, + {270, 300, 0x14}, + {300, 330, 0x5}, + {330, 360, 0x15}, + {360, 400, 0x25}, + {400, 450, 0x06}, + {450, 500, 0x16}, + {500, 550, 0x07}, + {550, 600, 0x17}, + {600, 650, 0x08}, + {650, 700, 0x18}, + {700, 750, 0x09}, + {750, 800, 0x19}, + {800, 850, 0x29}, + {850, 900, 0x39}, + {900, 950, 0x0a}, + {950, 1000, 0x1a} +}; + +static struct cif_isp10_rk3288 *rk3288; +static int mipi_dphy0_wr_reg(unsigned char addr, unsigned char data) +{ + /* + * TESTCLK=1 + * TESTEN =1,TESTDIN=addr + * TESTCLK=0 + */ + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_RX0_TESTCLK_MASK | DPHY_RX0_TESTCLK); + write_grf_reg(GRF_SOC_CON14_OFFSET, + ((addr << DPHY_RX0_TESTDIN_OFFSET) | DPHY_RX0_TESTDIN_MASK + | DPHY_RX0_TESTEN | DPHY_RX0_TESTEN_MASK)); + write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLK_MASK); + + /* + * write data: + * TESTEN =0,TESTDIN=data + * TESTCLK=1 + */ + if (data != 0xff) { + write_grf_reg(GRF_SOC_CON14_OFFSET, + ((data << DPHY_RX0_TESTDIN_OFFSET) | + DPHY_RX0_TESTDIN_MASK | DPHY_RX0_TESTEN_MASK)); + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_RX0_TESTCLK_MASK | DPHY_RX0_TESTCLK); + } + return 0; +} + +static int mipi_dphy1_wr_reg(unsigned char addr, unsigned char data) +{ + /* + * TESTEN =1,TESTDIN=addr + * TESTCLK=0 + * TESTEN =0,TESTDIN=data + * TESTCLK=1 + */ + write_csihost_reg(CSIHOST_PHY_TEST_CTRL1, (0x00010000 | addr)); + write_csihost_reg(CSIHOST_PHY_TEST_CTRL0, 0x00000000); + write_csihost_reg(CSIHOST_PHY_TEST_CTRL1, (0x00000000 | data)); + write_csihost_reg(CSIHOST_PHY_TEST_CTRL0, 0x00000002); + + return 0; +} + +static int mipi_dphy1_rd_reg(unsigned char addr) +{ + return (read_csihost_reg(((CSIHOST_PHY_TEST_CTRL1) & 0xff00)) >> 8); +} + +static int mipi_dphy_cfg(struct pltfrm_cam_mipi_config *para) +{ + unsigned char hsfreqrange = 0xff, i; + struct mipi_dphy_hsfreqrange *hsfreqrange_p; + unsigned char datalane_en, input_sel; + + hsfreqrange_p = mipi_dphy_hsfreq_range; + for (i = 0; + i < (sizeof(mipi_dphy_hsfreq_range) / + sizeof(struct mipi_dphy_hsfreqrange)); + i++) { + if ((para->bit_rate > hsfreqrange_p->range_l) && + (para->bit_rate <= hsfreqrange_p->range_h)) { + hsfreqrange = hsfreqrange_p->cfg_bit; + break; + } + hsfreqrange_p++; + } + + if (hsfreqrange == 0xff) + hsfreqrange = 0x00; + + hsfreqrange <<= 1; + + input_sel = para->dphy_index; + datalane_en = 0; + for (i = 0; i < para->nb_lanes; i++) + datalane_en |= (1 << i); + + if (input_sel == 0) { + write_grf_reg(GRF_SOC_CON6_OFFSET, + MIPI_PHY_DPHYSEL_OFFSET_MASK | + (input_sel << MIPI_PHY_DPHYSEL_OFFSET_BIT)); + /* set lane num */ + write_grf_reg(GRF_SOC_CON10_OFFSET, + DPHY_RX0_ENABLE_MASK | + (datalane_en << DPHY_RX0_ENABLE_OFFSET_BITS)); + /* set lan turndisab as 1 */ + write_grf_reg(GRF_SOC_CON10_OFFSET, + DPHY_RX0_TURN_DISABLE_MASK | + (0xf << DPHY_RX0_TURN_DISABLE_OFFSET_BITS)); + write_grf_reg(GRF_SOC_CON10_OFFSET, + (0x0 << 4) | (0xf << 20)); + /* set lan turnrequest as 0 */ + write_grf_reg(GRF_SOC_CON15_OFFSET, + DPHY_RX0_TURN_REQUEST_MASK | + (0x0 << DPHY_RX0_TURN_REQUEST_OFFSET_BITS)); + + /* phy start */ + /* + * TESTCLK=1 + * TESTCLR=1 + * delay 100us + * TESTCLR=0 + */ + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_RX0_TESTCLK_MASK | DPHY_RX0_TESTCLK); + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_RX0_TESTCLR_MASK | DPHY_RX0_TESTCLR); + usleep_range(100, 150); + write_grf_reg(GRF_SOC_CON14_OFFSET, DPHY_RX0_TESTCLR_MASK); + usleep_range(100, 150); + + /* set clock lane */ + mipi_dphy0_wr_reg(0x34, 0x15); + if (datalane_en == ONE_LANE_ENABLE_BIT) { + mipi_dphy0_wr_reg(0x44, hsfreqrange); + } else if (datalane_en == TWO_LANE_ENABLE_BIT) { + mipi_dphy0_wr_reg(0x44, hsfreqrange); + mipi_dphy0_wr_reg(0x54, hsfreqrange); + } else if (datalane_en == FOUR_LANE_ENABLE_BIT) { + mipi_dphy0_wr_reg(0x44, hsfreqrange); + mipi_dphy0_wr_reg(0x54, hsfreqrange); + mipi_dphy0_wr_reg(0x84, hsfreqrange); + mipi_dphy0_wr_reg(0x94, hsfreqrange); + } + + /* Normal operation */ + /* + * TESTCLK=1 + * TESTEN =0 + */ + mipi_dphy0_wr_reg(0x0, -1); + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_RX0_TESTCLK_MASK | DPHY_RX0_TESTCLK); + write_grf_reg(GRF_SOC_CON14_OFFSET, + (DPHY_RX0_TESTEN_MASK)); + + write_cifisp_reg((MRV_MIPI_BASE + MRV_MIPI_CTRL), + read_cifisp_reg(MRV_MIPI_BASE + MRV_MIPI_CTRL) | + (0x0f << 8)); + + } else if (input_sel == 1) { + write_grf_reg(GRF_SOC_CON6_OFFSET, + MIPI_PHY_DPHYSEL_OFFSET_MASK | + (input_sel << MIPI_PHY_DPHYSEL_OFFSET_BIT)); + write_grf_reg(GRF_SOC_CON6_OFFSET, + DSI_CSI_TESTBUS_SEL_MASK | + (1 << DSI_CSI_TESTBUS_SEL_OFFSET_BIT)); + + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_RX1_SRC_SEL_ISP | DPHY_RX1_SRC_SEL_MASK); + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_TX1RX1_SLAVEZ | DPHY_TX1RX1_MASTERSLAVEZ_MASK); + write_grf_reg(GRF_SOC_CON14_OFFSET, + DPHY_TX1RX1_BASEDIR_REC | DPHY_TX1RX1_BASEDIR_OFFSET); + + /* set lane num */ + write_grf_reg(GRF_SOC_CON9_OFFSET, + DPHY_TX1RX1_ENABLE_MASK | + (datalane_en << DPHY_TX1RX1_ENABLE_OFFSET_BITS)); + /* set lan turndisab as 1 */ + write_grf_reg(GRF_SOC_CON9_OFFSET, + DPHY_TX1RX1_TURN_DISABLE_MASK | + (0xf << DPHY_TX1RX1_TURN_DISABLE_OFFSET_BITS)); + /* set lan turnrequest as 0 */ + write_grf_reg(GRF_SOC_CON15_OFFSET, + DPHY_TX1RX1_TURN_REQUEST_MASK | + (0x0 << DPHY_TX1RX1_TURN_REQUEST_OFFSET_BITS)); + + /* phy1 start */ + /* + * SHUTDOWNZ=0 + * RSTZ=0 + * TESTCLK=1 + * TESTCLR=1 TESTCLK=1 + * TESTCLR=0 TESTCLK=1 + */ + write_csihost_reg(CSIHOST_PHY_SHUTDOWNZ, 0x00000000); + write_csihost_reg(CSIHOST_DPHY_RSTZ, 0x00000000); + write_csihost_reg(CSIHOST_PHY_TEST_CTRL0, 0x00000002); + write_csihost_reg(CSIHOST_PHY_TEST_CTRL0, 0x00000003); + usleep_range(100, 150); + write_csihost_reg(CSIHOST_PHY_TEST_CTRL0, 0x00000002); + usleep_range(100, 150); + + /* set clock lane */ + mipi_dphy1_wr_reg(0x34, 0x15); + + if (datalane_en == ONE_LANE_ENABLE_BIT) { + mipi_dphy1_wr_reg(0x44, hsfreqrange); + } else if (datalane_en == TWO_LANE_ENABLE_BIT) { + mipi_dphy1_wr_reg(0x44, hsfreqrange); + mipi_dphy1_wr_reg(0x54, hsfreqrange); + } else if (datalane_en == FOUR_LANE_ENABLE_BIT) { + mipi_dphy1_wr_reg(0x44, hsfreqrange); + mipi_dphy1_wr_reg(0x54, hsfreqrange); + mipi_dphy1_wr_reg(0x84, hsfreqrange); + mipi_dphy1_wr_reg(0x94, hsfreqrange); + } + + mipi_dphy1_rd_reg(0x0); + /* + * TESTCLK=1 + * TESTEN =0 + * SHUTDOWNZ=1 + * RSTZ=1 + */ + write_csihost_reg(CSIHOST_PHY_TEST_CTRL0, 0x00000002); + write_csihost_reg(CSIHOST_PHY_TEST_CTRL1, 0x00000000); + write_csihost_reg(CSIHOST_PHY_SHUTDOWNZ, 0x00000001); + write_csihost_reg(CSIHOST_DPHY_RSTZ, 0x00000001); + } else { + goto fail; + } + + return 0; +fail: + return -1; +} + +static int soc_clk_enable(void) +{ + struct cif_isp10_clk_rst_rk3288 *clk_rst = &rk3288->clk_rst; + + clk_prepare_enable(clk_rst->hclk_isp); + clk_prepare_enable(clk_rst->aclk_isp); + clk_prepare_enable(clk_rst->sclk_isp); + clk_prepare_enable(clk_rst->sclk_isp_jpe); + clk_prepare_enable(clk_rst->sclk_mipidsi_24m); + clk_prepare_enable(clk_rst->pclk_isp_in); + clk_prepare_enable(clk_rst->pclk_mipi_csi); + return 0; +} + +static int soc_clk_disable(void) +{ + struct cif_isp10_clk_rst_rk3288 *clk_rst = &rk3288->clk_rst; + + clk_disable_unprepare(clk_rst->hclk_isp); + clk_disable_unprepare(clk_rst->aclk_isp); + clk_disable_unprepare(clk_rst->sclk_isp); + clk_disable_unprepare(clk_rst->sclk_isp_jpe); + clk_disable_unprepare(clk_rst->sclk_mipidsi_24m); + clk_disable_unprepare(clk_rst->pclk_isp_in); + clk_disable_unprepare(clk_rst->pclk_mipi_csi); + return 0; +} + +static int soc_init(struct pltfrm_soc_init_para *init) +{ + struct cif_isp10_clk_rst_rk3288 *clk_rst; + struct platform_device *pdev = init->pdev; + struct device_node *np = pdev->dev.of_node, *node; + struct resource *res; + int err; + + rk3288 = (struct cif_isp10_rk3288 *)devm_kzalloc( + &pdev->dev, + sizeof(struct cif_isp10_rk3288), + GFP_KERNEL); + if (!rk3288) { + dev_err(&pdev->dev, "Can't allocate cif_isp10_rk3288\n"); + err = -ENOMEM; + goto alloc_failed; + } + + node = of_parse_phandle(np, "rockchip,grf", 0); + if (node) { + rk3288->regmap_grf = syscon_node_to_regmap(node); + if (IS_ERR(rk3288->regmap_grf)) { + dev_err(&pdev->dev, "Can't allocate cif_isp10_rk3288\n"); + err = -ENODEV; + goto regmap_failed; + } + } + + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csihost-register"); + if (!res) { + dev_err(&pdev->dev, + "platform_get_resource_byname csihost-register failed\n"); + err = -ENODEV; + goto regmap_failed; + } + rk3288->csihost_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR_OR_NULL(rk3288->csihost_base)) { + dev_err(&pdev->dev, "devm_ioremap_resource failed\n"); + if (IS_ERR(rk3288->csihost_base)) + err = PTR_ERR(rk3288->csihost_base); + else + err = -ENODEV; + goto regmap_failed; + } + + clk_rst = &rk3288->clk_rst; + clk_rst->aclk_isp = devm_clk_get(&pdev->dev, "aclk_isp"); + clk_rst->hclk_isp = devm_clk_get(&pdev->dev, "hclk_isp"); + clk_rst->sclk_isp = devm_clk_get(&pdev->dev, "sclk_isp"); + clk_rst->sclk_isp_jpe = devm_clk_get(&pdev->dev, "sclk_isp_jpe"); + clk_rst->sclk_mipidsi_24m = + devm_clk_get(&pdev->dev, "sclk_mipidsi_24m"); + clk_rst->pclk_mipi_csi = devm_clk_get(&pdev->dev, "pclk_mipi_csi"); + clk_rst->isp_rst = devm_reset_control_get(&pdev->dev, "rst_isp"); + clk_rst->pclk_isp_in = devm_clk_get(&pdev->dev, "pclk_isp_in"); + + if (IS_ERR_OR_NULL(clk_rst->aclk_isp) || + IS_ERR_OR_NULL(clk_rst->hclk_isp) || + IS_ERR_OR_NULL(clk_rst->sclk_isp) || + IS_ERR_OR_NULL(clk_rst->sclk_isp_jpe) || + IS_ERR_OR_NULL(clk_rst->pclk_mipi_csi) || + IS_ERR_OR_NULL(clk_rst->isp_rst) || + IS_ERR_OR_NULL(clk_rst->pclk_isp_in) || + IS_ERR_OR_NULL(clk_rst->sclk_mipidsi_24m)) { + dev_err(&pdev->dev, "Get rk3288 cif isp10 clock resouce failed !\n"); + err = -EINVAL; + goto clk_failed; + } + + clk_set_rate(clk_rst->sclk_isp, 400000000); + clk_set_rate(clk_rst->sclk_isp_jpe, 400000000); + reset_control_deassert(clk_rst->isp_rst); + + rk3288->isp_base = init->isp_base; + return 0; + +clk_failed: + if (!IS_ERR_OR_NULL(clk_rst->aclk_isp)) + devm_clk_put(&pdev->dev, clk_rst->aclk_isp); + if (!IS_ERR_OR_NULL(clk_rst->hclk_isp)) + devm_clk_put(&pdev->dev, clk_rst->hclk_isp); + if (!IS_ERR_OR_NULL(clk_rst->sclk_isp)) + devm_clk_put(&pdev->dev, clk_rst->sclk_isp); + if (!IS_ERR_OR_NULL(clk_rst->sclk_isp_jpe)) + devm_clk_put(&pdev->dev, clk_rst->sclk_isp_jpe); + if (!IS_ERR_OR_NULL(clk_rst->pclk_mipi_csi)) + devm_clk_put(&pdev->dev, clk_rst->pclk_mipi_csi); + if (!IS_ERR_OR_NULL(clk_rst->pclk_isp_in)) + devm_clk_put(&pdev->dev, clk_rst->pclk_isp_in); + if (!IS_ERR_OR_NULL(clk_rst->sclk_mipidsi_24m)) + devm_clk_put(&pdev->dev, clk_rst->sclk_mipidsi_24m); + + if (!IS_ERR_OR_NULL(clk_rst->isp_rst)) + reset_control_put(clk_rst->isp_rst); + +regmap_failed: + +alloc_failed: + + return err; +} + +int pltfrm_rk3288_cfg( + struct pltfrm_soc_cfg_para *cfg) +{ + switch (cfg->cmd) { + case PLTFRM_MCLK_CFG: { + struct pltfrm_soc_mclk_para *mclk_para; + + mclk_para = (struct pltfrm_soc_mclk_para *)cfg->cfg_para; + if (mclk_para->io_voltage == PLTFRM_IO_1V8) + write_grf_reg(GRF_IO_VSEL_OFFSET, DVP_V18SEL); + else + write_grf_reg(GRF_IO_VSEL_OFFSET, DVP_V33SEL); + + write_grf_reg(GRF_GPIO2B_E_OFFSET, + CIF_CLKOUT_STRENGTH(mclk_para->drv_strength)); + break; + } + case PLTFRM_MIPI_DPHY_CFG: + mipi_dphy_cfg((struct pltfrm_cam_mipi_config *)cfg->cfg_para); + break; + + case PLTFRM_CLKEN: + soc_clk_enable(); + break; + + case PLTFRM_CLKDIS: + soc_clk_disable(); + break; + + case PLTFRM_CLKRST: + reset_control_assert(rk3288->clk_rst.isp_rst); + usleep_range(10, 15); + reset_control_deassert(rk3288->clk_rst.isp_rst); + break; + + case PLTFRM_SOC_INIT: + soc_init((struct pltfrm_soc_init_para *)cfg->cfg_para); + break; + + default: + break; + } + + return 0; +} + diff --git a/drivers/media/platform/rk-isp10/cif_isp10_rk3399.c b/drivers/media/platform/rk-isp10/cif_isp10_rk3399.c new file mode 100644 index 000000000000..1188891e0583 --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_rk3399.c @@ -0,0 +1,630 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VI_IRCL 0x0014 +#define MRV_MIPI_BASE 0x1C00 +#define MRV_MIPI_CTRL 0x00 +/* + * GRF_IO_VSEL + */ +#define GRF_IO_VSEL_OFFSET (0x0900) +#define DVP_V18SEL ((1 << 1) | (1 << 17)) +#define DVP_V33SEL ((0 << 1) | (1 << 17)) +/* + * GRF_IO_VSEL + */ +#define GRF_GPIO2B_E_OFFSET (0x0204) +#define CIF_CLKOUT_STRENGTH(a) \ + ((((a) & 0x03) << 3) | (0x03 << 19)) +#define GRF_SOC_STATUS1 (0x0e2a4) + +#define GRF_SOC_CON9_OFFSET (0x6224) +#define DPHY_RX0_TURNREQUEST_MASK (0xF << 16) +#define DPHY_RX0_TURNREQUEST_BIT (0) + +#define GRF_SOC_CON21_OFFSET (0x6254) +#define DPHY_RX0_FORCERXMODE_MASK (0xF << 20) +#define DPHY_RX0_FORCERXMODE_BIT (4) +#define DPHY_RX0_FORCETXSTOPMODE_MASK (0xF << 24) +#define DPHY_RX0_FORCETXSTOPMODE_BIT (8) +#define DPHY_RX0_TURNDISABLE_MASK (0xF << 28) +#define DPHY_RX0_TURNDISABLE_BIT (12) +#define DPHY_RX0_ENABLE_MASK (0xF << 16) +#define DPHY_RX0_ENABLE_BIT (0) + +#define GRF_SOC_CON23_OFFSET (0x625c) +#define DPHY_TX1RX1_TURNDISABLE_MASK (0xF << 28) +#define DPHY_TX1RX1_TURNDISABLE_BIT (12) +#define DPHY_TX1RX1_FORCERXMODE_MASK (0xF << 20) +#define DPHY_TX1RX1_FORCERXMODE_BIT (4) +#define DPHY_TX1RX1_FORCETXSTOPMODE_MASK (0xF << 24) +#define DPHY_TX1RX1_FORCETXSTOPMODE_BIT (8) +#define DPHY_TX1RX1_ENABLE_MASK (0xF << 16) +#define DPHY_TX1RX1_ENABLE_BIT (0) + +#define GRF_SOC_CON24_OFFSET (0x6260) +#define DPHY_TX1RX1_MASTERSLAVEZ_MASK (0x1 << 23) +#define DPHY_TX1RX1_MASTERSLAVEZ_BIT (7) +#define DPHY_TX1RX1_BASEDIR_MASK (0x1 << 21) +#define DPHY_TX1RX1_BASEDIR_BIT (5) +#define DPHY_RX1_MASK (0x1 << 20) +#define DPHY_RX1_SEL_BIT (4) + +#define GRF_SOC_CON25_OFFSET (0x6264) +#define DPHY_RX0_TESTCLK_MASK (0x1 << 25) +#define DPHY_RX0_TESTCLK_BIT (9) +#define DPHY_RX0_TESTCLR_MASK (0x1 << 26) +#define DPHY_RX0_TESTCLR_BIT (10) +#define DPHY_RX0_TESTDIN_MASK (0xFF << 16) +#define DPHY_RX0_TESTDIN_BIT (0) +#define DPHY_RX0_TESTEN_MASK (0x1 << 24) +#define DPHY_RX0_TESTEN_BIT (8) + +#define DPHY_TX1RX1_TURNREQUEST_MASK (0xF << 16) +#define DPHY_TX1RX1_TURNREQUEST_BIT (0) + +#define DSIHOST_PHY_SHUTDOWNZ (0x00a0) +#define DSIHOST_DPHY_RSTZ (0x00a0) +#define DSIHOST_PHY_TEST_CTRL0 (0x00b4) +#define DSIHOST_PHY_TEST_CTRL1 (0x00b8) + +#define write_cifisp_reg(addr, val) \ + __raw_writel(val, (addr) + rk3399->isp_base) +#define read_cifisp_reg(addr) \ + __raw_readl((addr) + rk3399->isp_base) + +#define write_grf_reg(addr, val) \ + regmap_write(rk3399->regmap_grf, addr, val) +#define read_grf_reg(addr, val) \ + regmap_read(rk3399->regmap_grf, addr, val) + +#define write_dsihost_reg(addr, val) \ + __raw_writel(val, (addr) + rk3399->dsihost_base) +#define read_dsihost_reg(addr) \ + __raw_readl((addr) + rk3399->dsihost_base) + +struct cif_isp10_clk_rst_rk3399 { + struct clk *hclk_isp0_noc; + struct clk *hclk_isp0_wrapper; + struct clk *hclk_isp1_noc; + struct clk *hclk_isp1_wrapper; + struct clk *aclk_isp0_noc; + struct clk *aclk_isp0_wrapper; + struct clk *aclk_isp1_noc; + struct clk *aclk_isp1_wrapper; + struct clk *clk_isp0; + struct clk *clk_isp1; + struct clk *pclkin_isp1; + struct clk *pclk_dphy_ref; + struct clk *pclk_dphytxrx; + struct clk *pclk_dphyrx; + struct clk *cif_clk_out; + struct clk *cif_clk_pll; + struct clk *cif_clk_mipi_dsi; + struct clk *cif_clk_mipi_dphy_cfg; +}; + +struct cif_isp10_rk3399 { + struct regmap *regmap_grf; + void __iomem *dsihost_base; + void __iomem *isp_base; + struct cif_isp10_clk_rst_rk3399 clk_rst; + struct cif_isp10_device *cif_isp10; +}; + +struct mipi_dphy_hsfreqrange { + unsigned int range_l; + unsigned int range_h; + unsigned char cfg_bit; +}; + +static struct mipi_dphy_hsfreqrange mipi_dphy_hsfreq_range[] = { + {80, 90, 0x00}, + {90, 100, 0x10}, + {100, 110, 0x20}, + {110, 130, 0x01}, + {130, 140, 0x11}, + {140, 150, 0x21}, + {150, 170, 0x02}, + {170, 180, 0x12}, + {180, 200, 0x22}, + {200, 220, 0x03}, + {220, 240, 0x13}, + {240, 250, 0x23}, + {250, 270, 0x4}, + {270, 300, 0x14}, + {300, 330, 0x5}, + {330, 360, 0x15}, + {360, 400, 0x25}, + {400, 450, 0x06}, + {450, 500, 0x16}, + {500, 550, 0x07}, + {550, 600, 0x17}, + {600, 650, 0x08}, + {650, 700, 0x18}, + {700, 750, 0x09}, + {750, 800, 0x19}, + {800, 850, 0x29}, + {850, 900, 0x39}, + {900, 950, 0x0a}, + {950, 1000, 0x1a}, + {1000, 1050, 0x2a}, + {1100, 1150, 0x3a}, + {1150, 1200, 0x0b}, + {1200, 1250, 0x1b}, + {1250, 1300, 0x2b}, + {1300, 1350, 0x0c}, + {1350, 1400, 0x1c}, + {1400, 1450, 0x2c}, + {1450, 1500, 0x3c} +}; + +static struct cif_isp10_rk3399 *rk3399; +static int mipi_dphy0_wr_reg(unsigned char addr, unsigned char data) +{ + /* + * TESTCLK=1 + * TESTEN =1,TESTDIN=addr + * TESTCLK=0 + */ + write_grf_reg(GRF_SOC_CON25_OFFSET, + DPHY_RX0_TESTCLK_MASK | (1 << DPHY_RX0_TESTCLK_BIT)); + write_grf_reg(GRF_SOC_CON25_OFFSET, + ((addr << DPHY_RX0_TESTDIN_BIT) | DPHY_RX0_TESTDIN_MASK + | (1 << DPHY_RX0_TESTEN_BIT) | DPHY_RX0_TESTEN_MASK)); + write_grf_reg(GRF_SOC_CON25_OFFSET, DPHY_RX0_TESTCLK_MASK); + + /* + * write data: + * TESTEN =0,TESTDIN=data + * TESTCLK=1 + */ + if (data != 0xff) { + write_grf_reg(GRF_SOC_CON25_OFFSET, + ((data << DPHY_RX0_TESTDIN_BIT) | + DPHY_RX0_TESTDIN_MASK | DPHY_RX0_TESTEN_MASK)); + write_grf_reg(GRF_SOC_CON25_OFFSET, + DPHY_RX0_TESTCLK_MASK | (1 << DPHY_RX0_TESTCLK_BIT)); + } + return 0; +} + +static int mipi_dphy0_rd_reg(unsigned char addr) +{ + int val = 0; + /*TESTCLK=1*/ + write_grf_reg(GRF_SOC_CON25_OFFSET, DPHY_RX0_TESTCLK_MASK | + (1 << DPHY_RX0_TESTCLK_BIT)); + /*TESTEN =1,TESTDIN=addr*/ + write_grf_reg(GRF_SOC_CON25_OFFSET, + ((addr << DPHY_RX0_TESTDIN_BIT) | + DPHY_RX0_TESTDIN_MASK | + (1 << DPHY_RX0_TESTEN_BIT) | + DPHY_RX0_TESTEN_MASK)); + /*TESTCLK=0*/ + write_grf_reg(GRF_SOC_CON25_OFFSET, DPHY_RX0_TESTCLK_MASK); + read_grf_reg(GRF_SOC_STATUS1, &val); + return val & 0xff; +} + +static int mipi_dphy1_wr_reg(unsigned char addr, unsigned char data) +{ + /* + * TESTEN =1,TESTDIN=addr + * TESTCLK=0 + * TESTEN =0,TESTDIN=data + * TESTCLK=1 + */ + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL1, (0x00010000 | addr)); + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL0, 0x00000000); + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL1, (0x00000000 | data)); + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL0, 0x00000002); + + return 0; +} + +static int mipi_dphy1_rd_reg(unsigned char addr) +{ + /* TESTEN =1,TESTDIN=addr */ + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL1, (0x00010000 | addr)); + /* TESTCLK=0 */ + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL0, 0x00000000); + return (read_dsihost_reg(DSIHOST_PHY_TEST_CTRL1) >> 8); +} + +static int mipi_dphy_cfg(struct pltfrm_cam_mipi_config *para) +{ + unsigned char hsfreqrange = 0xff, i; + struct mipi_dphy_hsfreqrange *hsfreqrange_p; + unsigned char datalane_en, input_sel; + + hsfreqrange_p = mipi_dphy_hsfreq_range; + for (i = 0; + i < (sizeof(mipi_dphy_hsfreq_range) / + sizeof(struct mipi_dphy_hsfreqrange)); + i++) { + if ((para->bit_rate > hsfreqrange_p->range_l) && + (para->bit_rate <= hsfreqrange_p->range_h)) { + hsfreqrange = hsfreqrange_p->cfg_bit; + break; + } + hsfreqrange_p++; + } + + if (hsfreqrange == 0xff) + hsfreqrange = 0x00; + + hsfreqrange <<= 1; + + input_sel = para->dphy_index; + datalane_en = 0; + for (i = 0; i < para->nb_lanes; i++) + datalane_en |= (1 << i); + + if (input_sel == 0) { + write_grf_reg(GRF_SOC_CON21_OFFSET, + DPHY_RX0_FORCERXMODE_MASK | + (0x0 << DPHY_RX0_FORCERXMODE_BIT) | + DPHY_RX0_FORCETXSTOPMODE_MASK | + (0x0 << DPHY_RX0_FORCETXSTOPMODE_BIT)); + + /* set lane num */ + write_grf_reg(GRF_SOC_CON21_OFFSET, + DPHY_RX0_ENABLE_MASK | + (datalane_en << DPHY_RX0_ENABLE_BIT)); + + /* set lan turndisab as 1 */ + write_grf_reg(GRF_SOC_CON21_OFFSET, + DPHY_RX0_TURNDISABLE_MASK | + (0xf << DPHY_RX0_TURNDISABLE_BIT)); + write_grf_reg(GRF_SOC_CON21_OFFSET, (0x0 << 4) | (0xf << 20)); + + /* set lan turnrequest as 0 */ + write_grf_reg(GRF_SOC_CON9_OFFSET, + DPHY_RX0_TURNREQUEST_MASK | + (0x0 << DPHY_RX0_TURNREQUEST_BIT)); + + /* phy start */ + /* + * TESTCLK=1 + * TESTCLR=1 + * delay 100us + * TESTCLR=0 + */ + write_grf_reg(GRF_SOC_CON25_OFFSET, + DPHY_RX0_TESTCLK_MASK | + (0x1 << DPHY_RX0_TESTCLK_BIT)); /* TESTCLK=1 */ + write_grf_reg(GRF_SOC_CON25_OFFSET, + DPHY_RX0_TESTCLR_MASK | + (0x1 << DPHY_RX0_TESTCLR_BIT)); /* TESTCLR=1 */ + usleep_range(100, 150); + /* TESTCLR=0 zyc */ + write_grf_reg(GRF_SOC_CON25_OFFSET, + DPHY_RX0_TESTCLR_MASK); + usleep_range(100, 150); + + /* set clock lane */ + mipi_dphy0_wr_reg + (0x34, 0); + /* HS hsfreqrange & lane 0 settle bypass */ + mipi_dphy0_wr_reg(0x44, hsfreqrange); + mipi_dphy0_wr_reg(0x54, 0); + mipi_dphy0_wr_reg(0x84, 0); + mipi_dphy0_wr_reg(0x94, 0); + mipi_dphy0_wr_reg(0x75, 0x04); + mipi_dphy0_rd_reg(0x75); + + /* Normal operation */ + /* + * TESTCLK=1 + * TESTEN =0 + */ + mipi_dphy0_wr_reg(0x0, -1); + write_grf_reg(GRF_SOC_CON25_OFFSET, + DPHY_RX0_TESTCLK_MASK | (1 << DPHY_RX0_TESTCLK_BIT)); + write_grf_reg(GRF_SOC_CON25_OFFSET, + (DPHY_RX0_TESTEN_MASK)); + + write_cifisp_reg((MRV_MIPI_BASE + MRV_MIPI_CTRL), + read_cifisp_reg(MRV_MIPI_BASE + MRV_MIPI_CTRL) + | (0x0f << 8)); + + } else if (input_sel == 1) { + write_grf_reg(GRF_SOC_CON23_OFFSET, + DPHY_RX0_FORCERXMODE_MASK | + (0x0 << DPHY_RX0_FORCERXMODE_BIT) | + DPHY_RX0_FORCETXSTOPMODE_MASK | + (0x0 << DPHY_RX0_FORCETXSTOPMODE_BIT)); + write_grf_reg(GRF_SOC_CON24_OFFSET, + DPHY_TX1RX1_MASTERSLAVEZ_MASK | + (0x0 << DPHY_TX1RX1_MASTERSLAVEZ_BIT) | + DPHY_TX1RX1_BASEDIR_MASK | + (0x1 << DPHY_TX1RX1_BASEDIR_BIT) | + DPHY_RX1_MASK | 0x0 << DPHY_RX1_SEL_BIT); + + /* set lane num */ + write_grf_reg(GRF_SOC_CON23_OFFSET, + DPHY_TX1RX1_ENABLE_MASK | + (datalane_en << DPHY_TX1RX1_ENABLE_BIT)); + + /* set lan turndisab as 1 */ + write_grf_reg(GRF_SOC_CON23_OFFSET, + DPHY_TX1RX1_TURNDISABLE_MASK | + (0xf << DPHY_TX1RX1_TURNDISABLE_BIT)); + write_grf_reg(GRF_SOC_CON23_OFFSET, (0x0 << 4) | (0xf << 20)); + + /* set lan turnrequest as 0 */ + write_grf_reg(GRF_SOC_CON24_OFFSET, + DPHY_TX1RX1_TURNREQUEST_MASK | + (0x0 << DPHY_TX1RX1_TURNREQUEST_BIT)); + + /* phy1 start */ + /* + * SHUTDOWNZ=0 + * RSTZ=0 + * TESTCLK=1 + * TESTCLR=1 TESTCLK=1 + * TESTCLR=0 TESTCLK=1 + */ + write_dsihost_reg(DSIHOST_PHY_SHUTDOWNZ, 0x00000000); + write_dsihost_reg(DSIHOST_DPHY_RSTZ, 0x00000000); + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL0, 0x00000002); + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL1, 0x00000003); + usleep_range(100, 150); + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL0, 0x00000002); + usleep_range(100, 150); + + /* set clock lane */ + mipi_dphy1_wr_reg(0x34, 0x00); + mipi_dphy1_wr_reg(0x44, hsfreqrange); + mipi_dphy1_wr_reg(0x54, 0); + mipi_dphy1_wr_reg(0x84, 0); + mipi_dphy1_wr_reg(0x94, 0); + mipi_dphy1_wr_reg(0x75, 0x04); + + mipi_dphy1_rd_reg(0x0); + /* + * TESTCLK=1 + * TESTEN =0 + * SHUTDOWNZ=1 + * RSTZ=1 + */ + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL0, 0x00000002); + write_dsihost_reg(DSIHOST_PHY_TEST_CTRL1, 0x00000000); + write_dsihost_reg(DSIHOST_PHY_SHUTDOWNZ, 0x00000001); + write_dsihost_reg(DSIHOST_DPHY_RSTZ, 0x00000001); + } else { + goto fail; + } + + return 0; +fail: + return -1; +} + +static int soc_clk_enable(void) +{ + struct cif_isp10_clk_rst_rk3399 *clk_rst = &rk3399->clk_rst; + + clk_prepare_enable(clk_rst->hclk_isp0_noc); + clk_prepare_enable(clk_rst->hclk_isp0_wrapper); + clk_prepare_enable(clk_rst->aclk_isp0_noc); + clk_prepare_enable(clk_rst->aclk_isp0_wrapper); + clk_prepare_enable(clk_rst->clk_isp0); + clk_prepare_enable(clk_rst->cif_clk_out); + clk_prepare_enable(clk_rst->pclk_dphyrx); + clk_prepare_enable(clk_rst->pclk_dphy_ref); + + return 0; +} + +static int soc_clk_disable(void) +{ + struct cif_isp10_clk_rst_rk3399 *clk_rst = &rk3399->clk_rst; + + clk_disable_unprepare(clk_rst->hclk_isp0_noc); + clk_disable_unprepare(clk_rst->hclk_isp0_wrapper); + clk_disable_unprepare(clk_rst->aclk_isp0_noc); + clk_disable_unprepare(clk_rst->aclk_isp0_wrapper); + clk_disable_unprepare(clk_rst->clk_isp0); + clk_disable_unprepare(clk_rst->pclk_dphyrx); + clk_disable_unprepare(clk_rst->pclk_dphy_ref); + if (!IS_ERR_OR_NULL(clk_rst->cif_clk_pll)) { + clk_set_parent(clk_rst->cif_clk_out, + clk_rst->cif_clk_pll); + } + clk_disable_unprepare(clk_rst->cif_clk_out); + + return 0; +} + +static int soc_init(struct pltfrm_soc_init_para *init) +{ + struct cif_isp10_clk_rst_rk3399 *clk_rst; + struct platform_device *pdev = init->pdev; + struct device_node *np = pdev->dev.of_node, *node; + struct resource *res; + int err; + + rk3399 = (struct cif_isp10_rk3399 *)devm_kzalloc( + &pdev->dev, + sizeof(struct cif_isp10_rk3399), + GFP_KERNEL); + if (!rk3399) { + dev_err(&pdev->dev, "Can't allocate cif_isp10_rk3399\n"); + err = -ENOMEM; + goto alloc_failed; + } + + node = of_parse_phandle(np, "rockchip,grf", 0); + if (node) { + rk3399->regmap_grf = syscon_node_to_regmap(node); + if (IS_ERR(rk3399->regmap_grf)) { + dev_err(&pdev->dev, "Can't allocate cif_isp10_rk3399\n"); + err = -ENODEV; + goto regmap_failed; + } + } + + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "dsihost-register"); + if (!res) { + dev_err(&pdev->dev, + "platform_get_resource_byname dsihost-register failed\n"); + err = -ENODEV; + goto regmap_failed; + } + rk3399->dsihost_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR_OR_NULL(rk3399->dsihost_base)) { + dev_err(&pdev->dev, "devm_ioremap_resource failed\n"); + if (IS_ERR(rk3399->dsihost_base)) + err = PTR_ERR(rk3399->dsihost_base); + else + err = -ENODEV; + goto regmap_failed; + } + + clk_rst = &rk3399->clk_rst; + + clk_rst->hclk_isp0_noc = + devm_clk_get(&pdev->dev, "hclk_isp0_noc"); + clk_rst->hclk_isp0_wrapper = + devm_clk_get(&pdev->dev, "hclk_isp0_wrapper"); + clk_rst->aclk_isp0_noc = + devm_clk_get(&pdev->dev, "aclk_isp0_noc"); + clk_rst->aclk_isp0_wrapper = + devm_clk_get(&pdev->dev, "aclk_isp0_wrapper"); + clk_rst->clk_isp0 = + devm_clk_get(&pdev->dev, "clk_isp0"); + clk_rst->cif_clk_out = + devm_clk_get(&pdev->dev, "clk_cif_out"); + clk_rst->cif_clk_pll = + devm_clk_get(&pdev->dev, "cif_clk_pll"); + clk_rst->pclk_dphyrx = + devm_clk_get(&pdev->dev, "pclk_dphyrx"); + clk_rst->pclk_dphy_ref = + devm_clk_get(&pdev->dev, "pclk_dphy_ref"); + + if (IS_ERR_OR_NULL(clk_rst->hclk_isp0_noc) || + IS_ERR_OR_NULL(clk_rst->hclk_isp0_wrapper) || + IS_ERR_OR_NULL(clk_rst->aclk_isp0_noc) || + IS_ERR_OR_NULL(clk_rst->aclk_isp0_wrapper) || + IS_ERR_OR_NULL(clk_rst->clk_isp0) || + IS_ERR_OR_NULL(clk_rst->cif_clk_out) || + IS_ERR_OR_NULL(clk_rst->pclk_dphy_ref) || + IS_ERR_OR_NULL(clk_rst->pclk_dphyrx)) { + dev_err(&pdev->dev, "Get rk3399 cif isp10 clock resouce failed !\n"); + err = -EINVAL; + goto clk_failed; + } + + clk_set_rate(clk_rst->clk_isp0, 420000000); + + rk3399->isp_base = init->isp_base; + return 0; + +clk_failed: + if (!IS_ERR_OR_NULL(clk_rst->hclk_isp0_noc)) + devm_clk_put(&pdev->dev, clk_rst->hclk_isp0_noc); + + if (!IS_ERR_OR_NULL(clk_rst->hclk_isp0_wrapper)) + devm_clk_put(&pdev->dev, clk_rst->hclk_isp0_wrapper); + + if (!IS_ERR_OR_NULL(clk_rst->aclk_isp0_noc)) + devm_clk_put(&pdev->dev, clk_rst->aclk_isp0_noc); + + if (!IS_ERR_OR_NULL(clk_rst->aclk_isp0_wrapper)) + devm_clk_put(&pdev->dev, clk_rst->aclk_isp0_wrapper); + + if (!IS_ERR_OR_NULL(clk_rst->clk_isp0)) + devm_clk_put(&pdev->dev, clk_rst->clk_isp0); + + if (!IS_ERR_OR_NULL(clk_rst->cif_clk_out)) + devm_clk_put(&pdev->dev, clk_rst->cif_clk_out); + + if (!IS_ERR_OR_NULL(clk_rst->cif_clk_pll)) + devm_clk_put(&pdev->dev, clk_rst->cif_clk_pll); + + if (!IS_ERR_OR_NULL(clk_rst->pclk_dphyrx)) + devm_clk_put(&pdev->dev, clk_rst->pclk_dphyrx); + + if (!IS_ERR_OR_NULL(clk_rst->pclk_dphy_ref)) + devm_clk_put(&pdev->dev, clk_rst->pclk_dphy_ref); + +regmap_failed: + +alloc_failed: + + return err; +} + +int pltfrm_rk3399_cfg( + struct pltfrm_soc_cfg_para *cfg) +{ + switch (cfg->cmd) { + case PLTFRM_MCLK_CFG: { + struct pltfrm_soc_mclk_para *mclk_para; + + mclk_para = (struct pltfrm_soc_mclk_para *)cfg->cfg_para; + if (mclk_para->io_voltage == PLTFRM_IO_1V8) + write_grf_reg(GRF_IO_VSEL_OFFSET, DVP_V18SEL); + else + write_grf_reg(GRF_IO_VSEL_OFFSET, DVP_V33SEL); + + write_grf_reg(GRF_GPIO2B_E_OFFSET, + CIF_CLKOUT_STRENGTH(mclk_para->drv_strength)); + break; + } + case PLTFRM_MIPI_DPHY_CFG: + mipi_dphy_cfg((struct pltfrm_cam_mipi_config *)cfg->cfg_para); + break; + + case PLTFRM_CLKEN: + soc_clk_enable(); + break; + + case PLTFRM_CLKDIS: + soc_clk_disable(); + break; + + case PLTFRM_CLKRST: + write_cifisp_reg(VI_IRCL, 0x80); + usleep_range(10, 15); + write_cifisp_reg(VI_IRCL, 0x00); + break; + + case PLTFRM_SOC_INIT: + soc_init((struct pltfrm_soc_init_para *)cfg->cfg_para); + break; + + default: + break; + } + + return 0; +} diff --git a/drivers/media/platform/rk-isp10/cif_isp10_v4l2.c b/drivers/media/platform/rk-isp10/cif_isp10_v4l2.c new file mode 100644 index 000000000000..448ecfe4852f --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_v4l2.c @@ -0,0 +1,1854 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#include +#include +#include +#include +#include +#include "cif_isp10.h" +#include "cif_isp10_regs.h" +#include "cif_isp10_version.h" +#include +#include +#include +#include +#include +#include + +#define CIF_ISP10_V4L2_SP_DEV_MAJOR 0 +#define CIF_ISP10_V4L2_ISP_DEV_MAJOR 1 +#define CIF_ISP10_V4L2_MP_DEV_MAJOR 2 +#define CIF_ISP10_V4L2_DMA_DEV_MAJOR 3 + +#define SP_DEV 0 +#define MP_DEV 1 +#define DMA_DEV 2 +#define ISP_DEV 3 + +/* One structure per open file handle */ +struct cif_isp10_v4l2_fh { + enum cif_isp10_stream_id stream_id; + struct v4l2_fh fh; +}; + +/* One structure per video node */ +struct cif_isp10_v4l2_node { + struct videobuf_queue buf_queue; + struct video_device vdev; + int users; + struct cif_isp10_v4l2_fh *owner; +}; + +/* One structure per device */ +struct cif_isp10_v4l2_device { + struct cif_isp10_v4l2_node node[4]; +}; + +/* spinlock define */ +spinlock_t iowrite32_verify_lock; + +static struct cif_isp10_v4l2_fh *to_fh(struct file *file) +{ + if (!file || !file->private_data) + return NULL; + + return container_of(file->private_data, struct cif_isp10_v4l2_fh, fh); +} + +static struct cif_isp10_v4l2_node *to_node(struct cif_isp10_v4l2_fh *fh) +{ + struct video_device *vdev = fh ? fh->fh.vdev : NULL; + + if (!fh || !vdev) + return NULL; + + return container_of(vdev, struct cif_isp10_v4l2_node, vdev); +} + +static struct videobuf_queue *to_videobuf_queue( + struct file *file) +{ + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct video_device *vdev = fh ? fh->fh.vdev : NULL; + struct cif_isp10_v4l2_node *node = to_node(fh); + struct videobuf_queue *q; + + if (unlikely(!vdev)) { + cif_isp10_pltfrm_pr_err(NULL, + "vdev is NULL\n"); + WARN_ON(1); + } + q = &node->buf_queue; + if (unlikely(!q)) { + cif_isp10_pltfrm_pr_err(NULL, + "buffer queue is NULL\n"); + WARN_ON(1); + } + + return q; +} + +static enum cif_isp10_stream_id to_stream_id( + struct file *file) +{ + struct cif_isp10_v4l2_fh *fh; + + if (unlikely(!file)) { + cif_isp10_pltfrm_pr_err(NULL, + "NULL file handle\n"); + WARN_ON(1); + } + fh = to_fh(file); + if (unlikely(!fh)) { + cif_isp10_pltfrm_pr_err(NULL, + "fh is NULL\n"); + WARN_ON(1); + } + + return fh->stream_id; +} + +static struct cif_isp10_device *to_cif_isp10_device( + struct videobuf_queue *queue) +{ + return queue->priv_data; +} + +static enum cif_isp10_stream_id to_cif_isp10_stream_id( + struct videobuf_queue *queue) +{ + struct cif_isp10_v4l2_node *node = + container_of(queue, struct cif_isp10_v4l2_node, buf_queue); + struct video_device *vdev = + &node->vdev; + + if (!strcmp(vdev->name, SP_VDEV_NAME)) + return CIF_ISP10_STREAM_SP; + if (!strcmp(vdev->name, MP_VDEV_NAME)) + return CIF_ISP10_STREAM_MP; + if (!strcmp(vdev->name, DMA_VDEV_NAME)) + return CIF_ISP10_STREAM_DMA; + + cif_isp10_pltfrm_pr_err(NULL, + "unsupported/unknown device name %s\n", vdev->name); + return -EINVAL; +} + +static const char *cif_isp10_v4l2_buf_type_string( + enum v4l2_buf_type buf_type) +{ + switch (buf_type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return "VIDEO_CAPTURE"; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + return "VIDEO_OVERLAY"; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return "VIDEO_OUTPUT"; + default: + break; + } + return "UNKNOWN/UNSUPPORTED"; +} + +const char *cif_isp10_v4l2_pix_fmt_string( + int pix_fmt) +{ + switch (pix_fmt) { + case V4L2_PIX_FMT_RGB332: + return "V4L2-RGB332"; + case V4L2_PIX_FMT_RGB555: + return "V4L2-RGB555"; + case V4L2_PIX_FMT_RGB565: + return "V4L2-RGB565"; + case V4L2_PIX_FMT_RGB555X: + return "V4L2-RGB555X"; + case V4L2_PIX_FMT_RGB565X: + return "V4L2-RGB565X"; + case V4L2_PIX_FMT_BGR24: + return "V4L2-BGR24"; + case V4L2_PIX_FMT_RGB24: + return "V4L2-RGB24"; + case V4L2_PIX_FMT_BGR32: + return "V4L2-BGR32"; + case V4L2_PIX_FMT_RGB32: + return "V4L2-RGB32"; + case V4L2_PIX_FMT_GREY: + return "V4L2-GREY"; + case V4L2_PIX_FMT_YVU410: + return "V4L2-YVU410"; + case V4L2_PIX_FMT_YVU420: + return "V4L2-YVU420"; + case V4L2_PIX_FMT_YUYV: + return "V4L2-YUYV"; + case V4L2_PIX_FMT_UYVY: + return "V4L2-UYVY"; + case V4L2_PIX_FMT_YUV422P: + return "V4L2-YUV422P"; + case V4L2_PIX_FMT_YUV411P: + return "V4L2-YUV411P"; + case V4L2_PIX_FMT_Y41P: + return "V4L2-Y41P"; + case V4L2_PIX_FMT_NV12: + return "V4L2-NV12"; + case V4L2_PIX_FMT_NV21: + return "V4L2-NV21"; + case V4L2_PIX_FMT_YUV410: + return "V4L2-YUV410"; + case V4L2_PIX_FMT_YUV420: + return "V4L2--YUV420"; + case V4L2_PIX_FMT_YYUV: + return "V4L2-YYUV"; + case V4L2_PIX_FMT_HI240: + return "V4L2-HI240"; + case V4L2_PIX_FMT_WNVA: + return "V4L2-WNVA"; + case V4L2_PIX_FMT_NV16: + return "V4L2-NV16"; + case V4L2_PIX_FMT_YUV444: + return "V4L2-YUV444P"; + case V4L2_PIX_FMT_NV24: + return "M5-YUV444SP"; + case V4L2_PIX_FMT_JPEG: + return "V4L2-JPEG"; + case V4L2_PIX_FMT_SGRBG10: + return "RAW-BAYER-10Bits"; + case V4L2_PIX_FMT_SGRBG8: + return "RAW-BAYER-8Bits"; + } + return "UNKNOWN/UNSUPPORTED"; +} + +static int cif_isp10_v4l2_cid2cif_isp10_cid(u32 v4l2_cid) +{ + switch (v4l2_cid) { + case V4L2_CID_FLASH_LED_MODE: + return CIF_ISP10_CID_FLASH_MODE; + case V4L2_CID_AUTOGAIN: + return CIF_ISP10_CID_AUTO_GAIN; + case V4L2_EXPOSURE_AUTO: + return CIF_ISP10_CID_AUTO_EXPOSURE; + case V4L2_CID_AUTO_WHITE_BALANCE: + return CIF_ISP10_CID_AUTO_WHITE_BALANCE; + case V4L2_CID_BLACK_LEVEL: + return CIF_ISP10_CID_BLACK_LEVEL; + case V4L2_CID_WHITE_BALANCE_TEMPERATURE: + return CIF_ISP10_CID_WB_TEMPERATURE; + case V4L2_CID_EXPOSURE: + return CIF_ISP10_CID_EXPOSURE_TIME; + case V4L2_CID_GAIN: + return CIF_ISP10_CID_ANALOG_GAIN; + case V4L2_CID_FOCUS_ABSOLUTE: + return CIF_ISP10_CID_FOCUS_ABSOLUTE; + case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: + return CIF_ISP10_CID_AUTO_N_PRESET_WHITE_BALANCE; + case V4L2_CID_SCENE_MODE: + return CIF_ISP10_CID_SCENE_MODE; + case V4L2_CID_COLORFX: + return CIF_ISP10_CID_IMAGE_EFFECT; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + return CIF_ISP10_CID_JPEG_QUALITY; + case V4L2_CID_HFLIP: + return CIF_ISP10_CID_HFLIP; + case V4L2_CID_VFLIP: + return CIF_ISP10_CID_VFLIP; + case V4L2_CID_ISO_SENSITIVITY: + return CIF_ISP10_CID_ISO_SENSITIVITY; + case RK_V4L2_CID_AUTO_FPS: + return CIF_ISP10_CID_AUTO_FPS; + default: + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported V4L2 CID 0x%x\n", + v4l2_cid); + break; + } + return -EINVAL; +} + +static enum cif_isp10_image_effect cif_isp10_v4l2_colorfx2cif_isp10_ie( + u32 v4l2_colorfx) +{ + switch (v4l2_colorfx) { + case V4L2_COLORFX_SEPIA: + return CIF_ISP10_IE_SEPIA; + case V4L2_COLORFX_BW: + return CIF_ISP10_IE_BW; + case V4L2_COLORFX_NEGATIVE: + return CIF_ISP10_IE_NEGATIVE; + case V4L2_COLORFX_EMBOSS: + return CIF_ISP10_IE_EMBOSS; + case V4L2_COLORFX_SKETCH: + return CIF_ISP10_IE_SKETCH; + case V4L2_COLORFX_NONE: + return CIF_ISP10_IE_NONE; + default: + cif_isp10_pltfrm_pr_err(NULL, + "unknown/unsupported V4L2 COLORFX %d\n", + v4l2_colorfx); + break; + } + return -EINVAL; +} + +static enum cif_isp10_pix_fmt cif_isp10_v4l2_pix_fmt2cif_isp10_pix_fmt( + u32 v4l2_pix_fmt, struct videobuf_queue *queue) +{ +/*struct cif_isp10_v4l2_node *node = + * container_of(queue, struct cif_isp10_v4l2_node, buf_queue); + * struct video_device *vdev = + * &node->vdev; + */ + + switch (v4l2_pix_fmt) { + case V4L2_PIX_FMT_GREY: + return CIF_YUV400; + case V4L2_PIX_FMT_YUV420: + return CIF_YUV420P; + case V4L2_PIX_FMT_YVU420: + return CIF_YVU420P; + case V4L2_PIX_FMT_NV12: + return CIF_YUV420SP; + case V4L2_PIX_FMT_NV21: + return CIF_YVU420SP; + case V4L2_PIX_FMT_YUYV: + return CIF_YUV422I; + case V4L2_PIX_FMT_UYVY: + return CIF_UYV422I; + case V4L2_PIX_FMT_YUV422P: + return CIF_YUV422P; + case V4L2_PIX_FMT_NV16: + return CIF_YUV422SP; + case V4L2_PIX_FMT_YUV444: + return CIF_YUV444P; + case V4L2_PIX_FMT_NV24: + return CIF_YUV444SP; + case V4L2_PIX_FMT_RGB565: + return CIF_RGB565; + case V4L2_PIX_FMT_RGB24: + return CIF_RGB888; + case V4L2_PIX_FMT_SBGGR8: + return CIF_BAYER_SBGGR8; + case V4L2_PIX_FMT_SGBRG8: + return CIF_BAYER_SGBRG8; + case V4L2_PIX_FMT_SGRBG8: + return CIF_BAYER_SGRBG8; + case V4L2_PIX_FMT_SRGGB8: + return CIF_BAYER_SRGGB8; + case V4L2_PIX_FMT_SBGGR10: + return CIF_BAYER_SBGGR10; + case V4L2_PIX_FMT_SGBRG10: + return CIF_BAYER_SGBRG10; + case V4L2_PIX_FMT_SGRBG10: + return CIF_BAYER_SGRBG10; + case V4L2_PIX_FMT_SRGGB10: + return CIF_BAYER_SRGGB10; + case V4L2_PIX_FMT_SBGGR12: + return CIF_BAYER_SBGGR12; + case V4L2_PIX_FMT_SGBRG12: + return CIF_BAYER_SGBRG12; + case V4L2_PIX_FMT_SGRBG12: + return CIF_BAYER_SGRBG12; + case V4L2_PIX_FMT_SRGGB12: + return CIF_BAYER_SRGGB12; + case V4L2_PIX_FMT_JPEG: + return CIF_JPEG; + default: + cif_isp10_pltfrm_pr_err(NULL, + "unknown or unsupported V4L2 pixel format %c%c%c%c\n", + (u8)(v4l2_pix_fmt & 0xff), + (u8)((v4l2_pix_fmt >> 8) & 0xff), + (u8)((v4l2_pix_fmt >> 16) & 0xff), + (u8)((v4l2_pix_fmt >> 24) & 0xff)); + return CIF_UNKNOWN_FORMAT; + } +} + +static int cif_isp10_v4l2_register_video_device( + struct cif_isp10_device *dev, + struct video_device *vdev, + const char *name, + int qtype, + int major, + const struct v4l2_file_operations *fops, + const struct v4l2_ioctl_ops *ioctl_ops) +{ + int ret; + + vdev->release = video_device_release; + strlcpy(vdev->name, name, sizeof(vdev->name)); + vdev->vfl_type = qtype; + vdev->fops = fops; + video_set_drvdata(vdev, dev); + vdev->minor = -1; + vdev->ioctl_ops = ioctl_ops; + vdev->v4l2_dev = &dev->v4l2_dev; + if (qtype == V4L2_BUF_TYPE_VIDEO_OUTPUT) + vdev->vfl_dir = VFL_DIR_TX; + else + vdev->vfl_dir = VFL_DIR_RX; + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, major); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(NULL, + "video_register_device failed with error %d\n", ret); + goto err; + } + + cif_isp10_pltfrm_pr_info(NULL, + "video device video%d.%d (%s) successfully registered\n", + major, vdev->minor, name); + + return 0; +err: + video_device_release(vdev); + cif_isp10_pltfrm_pr_err(NULL, + "failed with err %d\n", ret); + return ret; +} + +static int cif_isp10_v4l2_streamon( + struct file *file, + void *priv, + enum v4l2_buf_type buf_type) +{ + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + static u32 streamon_cnt_sp; + static u32 streamon_cnt_mp; + static u32 streamon_cnt_dma; + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct cif_isp10_v4l2_node *node = to_node(fh); + u32 stream_ids = to_stream_id(file); + + if (node->owner != fh) + return -EBUSY; + + cif_isp10_pltfrm_pr_dbg(dev->dev, "%s(%d)\n", + cif_isp10_v4l2_buf_type_string(queue->type), + (stream_ids & CIF_ISP10_STREAM_MP) ? ++streamon_cnt_mp : + ((stream_ids & CIF_ISP10_STREAM_SP) ? ++streamon_cnt_sp : + ++streamon_cnt_dma)); + + ret = videobuf_streamon(queue); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "videobuf_streamon failed\n"); + goto err; + } + + ret = cif_isp10_streamon(dev, stream_ids); + if (IS_ERR_VALUE(ret)) { + videobuf_queue_cancel(queue); + goto err; + } + + return 0; +err: + (void)videobuf_mmap_free(queue); + cif_isp10_pltfrm_pr_err(dev->dev, "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_v4l2_do_streamoff( + struct file *file) +{ + int ret = 0; + int err; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct cif_isp10_v4l2_node *node = to_node(fh); + u32 stream_ids = to_stream_id(file); + + cif_isp10_pltfrm_pr_dbg(dev->dev, "%s\n", + cif_isp10_v4l2_buf_type_string(queue->type)); + + if (node->owner != fh) + return -EBUSY; + + err = cif_isp10_streamoff(dev, stream_ids); + if (IS_ERR_VALUE(err)) + ret = -EFAULT; + err = videobuf_streamoff(queue); + if (IS_ERR_VALUE(err)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "videobuf_streamoff failed with error %d\n", err); + ret = -EFAULT; + } + err = videobuf_mmap_free(queue); + if (IS_ERR_VALUE(err)) { + cif_isp10_pltfrm_pr_err(dev->dev, + "videobuf_mmap_free failed with error %d\n", err); + ret = -EFAULT; + } + + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + + return ret; +} + +static int cif_isp10_v4l2_streamoff( + struct file *file, + void *priv, + enum v4l2_buf_type buf_type) +{ + int ret = cif_isp10_v4l2_do_streamoff(file); + + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + + return ret; +} + +static int cif_isp10_v4l2_qbuf( + struct file *file, + void *priv, + struct v4l2_buffer *buf) +{ + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct cif_isp10_v4l2_node *node = to_node(fh); + + cif_isp10_pltfrm_pr_dbg(NULL, + "%s buffer type %s, index %d, length %d\n", + cif_isp10_v4l2_buf_type_string(queue->type), + cif_isp10_v4l2_buf_type_string(buf->type), + buf->index, buf->length); + + if (node->owner != fh) + return -EBUSY; + + ret = videobuf_qbuf(queue, buf); + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_err(NULL, + "videobuf_qbuf failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_v4l2_dqbuf( + struct file *file, + void *priv, + struct v4l2_buffer *buf) +{ + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct cif_isp10_v4l2_node *node = to_node(fh); + + cif_isp10_pltfrm_pr_dbg(NULL, "%s\n", + cif_isp10_v4l2_buf_type_string(queue->type)); + + if (node->owner != fh) + return -EBUSY; + + ret = videobuf_dqbuf(queue, buf, file->f_flags & O_NONBLOCK); + if (IS_ERR_VALUE(ret) && (ret != -EAGAIN)) + cif_isp10_pltfrm_pr_err(NULL, + "videobuf_dqbuf failed with error %d\n", ret); + else + cif_isp10_pltfrm_pr_dbg(NULL, + "dequeued buffer %d, size %d\n", + buf->index, buf->length); + return ret; +} + +static void cif_isp10_v4l2_buf_release( + struct videobuf_queue *queue, + struct videobuf_buffer *buf) +{ + cif_isp10_pltfrm_pr_dbg(NULL, + "%s\n", + cif_isp10_v4l2_buf_type_string(queue->type)); + + if (in_interrupt()) + WARN_ON(1); + + videobuf_dma_contig_free(queue, buf); + + buf->state = VIDEOBUF_NEEDS_INIT; +} + +static void cif_isp10_v4l2_buf_queue( + struct videobuf_queue *queue, + struct videobuf_buffer *buf) +{ + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + enum cif_isp10_stream_id strm = to_cif_isp10_stream_id(queue); + + cif_isp10_pltfrm_pr_dbg(NULL, + "%s %dx%d, size %lu, bytesperline %d\n", + cif_isp10_v4l2_buf_type_string(queue->type), + buf->width, buf->height, buf->size, buf->bytesperline); + + if (!IS_ERR_VALUE(cif_isp10_qbuf(dev, strm, buf))) + buf->state = VIDEOBUF_QUEUED; + else + cif_isp10_pltfrm_pr_err(NULL, "failed\n"); +} + +static int cif_isp10_v4l2_buf_setup( + struct videobuf_queue *queue, + unsigned int *cnt, + unsigned int *size) +{ + int ret; + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + enum cif_isp10_stream_id strm = to_cif_isp10_stream_id(queue); + + cif_isp10_pltfrm_pr_dbg(NULL, "%s count %d, size %d\n", + cif_isp10_v4l2_buf_type_string(queue->type), + *cnt, *size); + + ret = cif_isp10_calc_min_out_buff_size( + dev, strm, size); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(NULL, "failed with error %d\n", ret); + return ret; + } + + cif_isp10_pltfrm_pr_dbg(NULL, "%s count %d, size %d\n", + cif_isp10_v4l2_buf_type_string(queue->type), + *cnt, *size); + + return 0; +} + +static int cif_isp10_v4l2_buf_prepare( + struct videobuf_queue *queue, + struct videobuf_buffer *buf, + enum v4l2_field field) +{ + int ret; + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + enum cif_isp10_stream_id strm = to_cif_isp10_stream_id(queue); + u32 size; + + cif_isp10_pltfrm_pr_dbg(NULL, "%s\n", + cif_isp10_v4l2_buf_type_string(queue->type)); + + ret = cif_isp10_calc_min_out_buff_size( + dev, strm, &size); + if (IS_ERR_VALUE(ret)) + goto err; + buf->size = size; + if (strm == CIF_ISP10_STREAM_SP) { + buf->width = + dev->config.mi_config.sp.output.width; + buf->height = + dev->config.mi_config.sp.output.height; + } else if (strm == CIF_ISP10_STREAM_MP) { + buf->width = + dev->config.mi_config.mp.output.width; + buf->height = + dev->config.mi_config.mp.output.height; + } else if (strm == CIF_ISP10_STREAM_DMA) { + buf->width = + dev->config.mi_config.dma.output.width; + buf->height = + dev->config.mi_config.dma.output.height; + } else { + cif_isp10_pltfrm_pr_err(NULL, + "wrong buffer queue %d\n", queue->type); + ret = -EINVAL; + goto err; + } + buf->field = field; + + cif_isp10_pltfrm_pr_dbg(NULL, "%s buffer prepared %dx%d, size %d\n", + cif_isp10_v4l2_buf_type_string(queue->type), + buf->width, buf->height, size); + + if (buf->state == VIDEOBUF_NEEDS_INIT) { + ret = videobuf_iolock(queue, buf, NULL); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(NULL, + "videobuf_iolock failed with error %d\n", ret); + goto err; + } + } + buf->state = VIDEOBUF_PREPARED; + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, "failed with error %d\n", ret); + cif_isp10_v4l2_buf_release(queue, buf); + return ret; +} + +static int cif_isp10_v4l2_reqbufs( + struct file *file, + void *priv, + struct v4l2_requestbuffers *req) +{ + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct cif_isp10_v4l2_node *node = to_node(fh); + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + enum cif_isp10_stream_id strm = to_cif_isp10_stream_id(queue); + + cif_isp10_pltfrm_pr_dbg(NULL, + "%s requested type %s, count %d\n", + cif_isp10_v4l2_buf_type_string(queue->type), + cif_isp10_v4l2_buf_type_string(req->type), + req->count); + + if (node->owner && node->owner != fh) + return -EBUSY; + node->owner = fh; + + ret = videobuf_reqbufs(queue, req); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(NULL, + "videobuf_reqbufs failed with error %d\n", ret); + } + cif_isp10_reqbufs(dev, strm, req); + return ret; +} + +static int cif_isp10_v4l2_querybuf( + struct file *file, + void *priv, + struct v4l2_buffer *buf) +{ + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + + cif_isp10_pltfrm_pr_dbg(NULL, + "%s, index %d\n", + cif_isp10_v4l2_buf_type_string(queue->type), buf->index); + + ret = videobuf_querybuf(queue, buf); + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_err(NULL, + "videobuf_querybuf failed with error %d\n", ret); + + return ret; +} + +static int cif_isp10_v4l2_s_ctrl( + struct file *file, + void *priv, + struct v4l2_control *vc) +{ + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + enum cif_isp10_cid id = + cif_isp10_v4l2_cid2cif_isp10_cid(vc->id); + int val = vc->value; + + if (IS_ERR_VALUE(id)) + return id; + + switch (vc->id) { + case V4L2_CID_COLORFX: + val = cif_isp10_v4l2_colorfx2cif_isp10_ie(val); + break; + case V4L2_CID_FLASH_LED_MODE: + if (vc->value == V4L2_FLASH_LED_MODE_NONE) + val = CIF_ISP10_FLASH_MODE_OFF; + else if (vc->value == V4L2_FLASH_LED_MODE_FLASH) + val = CIF_ISP10_FLASH_MODE_FLASH; + else if (vc->value == V4L2_FLASH_LED_MODE_TORCH) + val = CIF_ISP10_FLASH_MODE_TORCH; + else + val = -EINVAL; + break; + default: + break; + } + + return cif_isp10_s_ctrl(dev, id, val); +} + +static int cif_isp10_v4l2_s_fmt( + struct file *file, + void *priv, + struct v4l2_format *f) +{ + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct cif_isp10_v4l2_node *node = to_node(fh); + struct cif_isp10_strm_fmt strm_fmt; + + cif_isp10_pltfrm_pr_dbg(NULL, + "%s\n", + cif_isp10_v4l2_buf_type_string(queue->type)); + + if (node->owner && node->owner != fh) + return -EBUSY; + + strm_fmt.frm_fmt.pix_fmt = + cif_isp10_v4l2_pix_fmt2cif_isp10_pix_fmt( + f->fmt.pix.pixelformat, queue); + strm_fmt.frm_fmt.width = f->fmt.pix.width; + strm_fmt.frm_fmt.height = f->fmt.pix.height; +/* strm_fmt.frm_fmt.quantization = f->fmt.pix.quantization; */ + strm_fmt.frm_fmt.quantization = 0; + ret = cif_isp10_s_fmt(dev, + to_stream_id(file), + &strm_fmt, + f->fmt.pix.bytesperline); + if (IS_ERR_VALUE(ret)) + goto err; + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + return ret; +} + +/* existence of this function is checked by V4L2 */ +static int cif_isp10_v4l2_g_fmt( + struct file *file, + void *priv, + struct v4l2_format *f) +{ + return -EFAULT; +} + +static int cif_isp10_v4l2_s_input( + struct file *file, + void *priv, + unsigned int i) +{ + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + + cif_isp10_pltfrm_pr_dbg(dev->dev, "setting input to %d\n", i); + + ret = cif_isp10_s_input(dev, i); + if (IS_ERR_VALUE(ret)) + goto err; + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_v4l2_enum_framesizes( + struct file *file, + void *priv, + struct v4l2_frmsizeenum *fsize) +{ + /* THIS FUNCTION IS UNDER CONSTRUCTION */ + int ret; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + + if (IS_ERR_OR_NULL(dev->img_src)) { + cif_isp10_pltfrm_pr_err(NULL, + "input has not yet been selected, cannot enumerate formats\n"); + ret = -ENODEV; + goto err; + } + + return -EINVAL; +err: + cif_isp10_pltfrm_pr_err(NULL, "failed with error %d\n", ret); + return ret; +} + +/* fops **********************************************************************/ + +const struct videobuf_queue_ops cif_isp10_qops = { + .buf_setup = cif_isp10_v4l2_buf_setup, + .buf_prepare = cif_isp10_v4l2_buf_prepare, + .buf_queue = cif_isp10_v4l2_buf_queue, + .buf_release = cif_isp10_v4l2_buf_release, +}; + +static int cif_isp10_v4l2_open( + struct file *file) +{ + int ret; + struct video_device *vdev = video_devdata(file); + struct cif_isp10_device *dev = video_get_drvdata(vdev); + struct cif_isp10_v4l2_fh *fh; + struct cif_isp10_v4l2_node *node; + enum v4l2_buf_type buf_type; + enum cif_isp10_stream_id stream_id; + struct cif_isp10_v4l2_device *cif_isp10_v4l2_dev = + (struct cif_isp10_v4l2_device *)dev->nodes; + + cif_isp10_pltfrm_pr_dbg(NULL, + "video device video%d.%d (%s)\n", + vdev->num, vdev->minor, vdev->name); + + if (vdev->minor == cif_isp10_v4l2_dev->node[SP_DEV].vdev.minor) { + buf_type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + stream_id = CIF_ISP10_STREAM_SP; + } else if (vdev->minor == cif_isp10_v4l2_dev->node[MP_DEV].vdev.minor) { + buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + stream_id = CIF_ISP10_STREAM_MP; + } else if (vdev->minor == + cif_isp10_v4l2_dev->node[DMA_DEV].vdev.minor) { + buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + stream_id = CIF_ISP10_STREAM_DMA; + } else { + cif_isp10_pltfrm_pr_err(NULL, + "invalid video device video%d.%d (%s)\n", + vdev->num, vdev->minor, vdev->name); + ret = -EINVAL; + goto err; + } + + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) { + cif_isp10_pltfrm_pr_err(NULL, + "memory allocation failed\n"); + ret = -ENOMEM; + goto err; + } + fh->stream_id = stream_id; + + file->private_data = &fh->fh; + v4l2_fh_init(&fh->fh, vdev); + v4l2_fh_add(&fh->fh); + + node = to_node(fh); + if (++node->users > 1) + return 0; + + /* First open of the device, so initialize everything */ + node->owner = NULL; + + videobuf_queue_dma_contig_init( + to_videobuf_queue(file), + &cif_isp10_qops, + dev->dev, + &dev->vbq_lock, + buf_type, + V4L2_FIELD_NONE, + sizeof(struct videobuf_buffer), + dev, NULL); + + ret = cif_isp10_init(dev, to_stream_id(file)); + if (IS_ERR_VALUE(ret)) { + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); + kfree(fh); + node->users--; + goto err; + } + + return 0; +err: + cif_isp10_pltfrm_pr_err(NULL, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_v4l2_release(struct file *file) +{ + int ret = 0; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + struct cif_isp10_v4l2_fh *fh = to_fh(file); + struct cif_isp10_v4l2_node *node = to_node(fh); + enum cif_isp10_stream_id stream_id = to_stream_id(file); + + cif_isp10_pltfrm_pr_dbg(dev->dev, "%s\n", + cif_isp10_v4l2_buf_type_string(queue->type)); + + if (node->users) { + --node->users; + } else { + cif_isp10_pltfrm_pr_warn(dev->dev, + "number of users for this device is already 0\n"); + return 0; + } + + if (!node->users) { + if (queue->streaming) + if (IS_ERR_VALUE(cif_isp10_v4l2_do_streamoff(file))) + cif_isp10_pltfrm_pr_warn(dev->dev, + "streamoff failed\n"); + + /* Last close, so uninitialize hardware */ + ret = cif_isp10_release(dev, stream_id); + } + + if (node->owner == fh) + node->owner = NULL; + + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); + kfree(fh); + + if (IS_ERR_VALUE(ret)) + cif_isp10_pltfrm_pr_err(dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static unsigned int cif_isp10_v4l2_poll( + struct file *file, + struct poll_table_struct *wait) +{ + struct cif_isp10_v4l2_fh *fh = to_fh(file); + int ret = 0; + struct videobuf_queue *queue = to_videobuf_queue(file); + unsigned long req_events = poll_requested_events(wait); + + cif_isp10_pltfrm_pr_dbg(NULL, "%s\n", + cif_isp10_v4l2_buf_type_string(queue->type)); + + if (v4l2_event_pending(&fh->fh)) + ret = POLLPRI; + else if (req_events & POLLPRI) + poll_wait(file, &fh->fh.wait, wait); + + if (!(req_events & (POLLIN | POLLOUT | POLLRDNORM))) + return ret; + + ret |= videobuf_poll_stream(file, queue, wait); + if (ret & POLLERR) { + cif_isp10_pltfrm_pr_err(NULL, + "videobuf_poll_stream failed with error 0x%x\n", ret); + } + return ret; +} + +/* + * VMA operations. + */ +static void cif_isp10_v4l2_vm_open(struct vm_area_struct *vma) +{ + struct cif_isp10_metadata_s *metadata = + (struct cif_isp10_metadata_s *)vma->vm_private_data; + + metadata->vmas++; +} + +static void cif_isp10_v4l2_vm_close(struct vm_area_struct *vma) +{ + struct cif_isp10_metadata_s *metadata = + (struct cif_isp10_metadata_s *)vma->vm_private_data; + + metadata->vmas--; +} + +static const struct vm_operations_struct cif_isp10_vm_ops = { + .open = cif_isp10_v4l2_vm_open, + .close = cif_isp10_v4l2_vm_close, +}; + +int cif_isp10_v4l2_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + enum cif_isp10_stream_id strm = to_stream_id(file); + int retval; + + retval = cif_isp10_mmap(dev, strm, vma); + if (retval < 0) + goto done; + + vma->vm_ops = &cif_isp10_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + cif_isp10_v4l2_vm_open(vma); + +done: + return retval; +} + +const struct v4l2_file_operations cif_isp10_v4l2_fops = { + .open = cif_isp10_v4l2_open, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif + .release = cif_isp10_v4l2_release, + .poll = cif_isp10_v4l2_poll, + .mmap = cif_isp10_v4l2_mmap, +}; + +/*TBD: clean up code below this line******************************************/ + +static int v4l2_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + int ret = 0; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct video_device *vdev = video_devdata(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + u32 stream_ids = to_stream_id(file); + + strcpy(cap->driver, DRIVER_NAME); + strlcpy(cap->card, vdev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:" DRIVER_NAME "-%03i", + dev->dev_id); + + if (stream_ids == CIF_ISP10_STREAM_SP) + cap->capabilities = V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING; + else if (stream_ids == CIF_ISP10_STREAM_MP) + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING; + else if (stream_ids == CIF_ISP10_STREAM_DMA) + cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | + V4L2_CAP_VIDEO_M2M; + cap->capabilities |= V4L2_CAP_DEVICE_CAPS; + cap->device_caps = V4L2_CAP_DEVICE_CAPS; + return ret; +} + +static int cif_isp10_v4l2_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + if (sub->type != V4L2_EVENT_FRAME_SYNC) + return -EINVAL; + return v4l2_event_subscribe(fh, sub, 16, NULL); +} + +static int cif_isp10_v4l2_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static void cif_isp10_v4l2_event( + struct cif_isp10_device *dev, + __u32 frame_sequence) +{ + struct cif_isp10_v4l2_device *cif_isp10_v4l2_dev = + (struct cif_isp10_v4l2_device *)dev->nodes; + struct v4l2_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.type = V4L2_EVENT_FRAME_SYNC; + ev.u.frame_sync.frame_sequence = frame_sequence; + v4l2_event_queue(&cif_isp10_v4l2_dev->node[SP_DEV].vdev, &ev); +} + +static void cif_isp10_v4l2_requeue_bufs( + struct cif_isp10_device *dev, + enum cif_isp10_stream_id stream_id) +{ + struct videobuf_buffer *buf; + struct videobuf_queue *q = NULL; + struct cif_isp10_v4l2_device *cif_isp10_v4l2_dev = + (struct cif_isp10_v4l2_device *)dev->nodes; + + if (stream_id == CIF_ISP10_STREAM_SP) + q = &cif_isp10_v4l2_dev->node[SP_DEV].buf_queue; + else if (stream_id == CIF_ISP10_STREAM_MP) + q = &cif_isp10_v4l2_dev->node[MP_DEV].buf_queue; + else if (stream_id == CIF_ISP10_STREAM_DMA) + q = &cif_isp10_v4l2_dev->node[DMA_DEV].buf_queue; + else + WARN_ON(1); + + dev = to_cif_isp10_device(q); + + list_for_each_entry(buf, &q->stream, stream) { + if (!IS_ERR_VALUE(cif_isp10_qbuf( + to_cif_isp10_device(q), stream_id, buf))) { + spin_lock(&dev->vbreq_lock); + if ((buf->state == VIDEOBUF_QUEUED) || + (buf->state == VIDEOBUF_ACTIVE) || + (buf->state == VIDEOBUF_DONE)) + buf->state = VIDEOBUF_QUEUED; + else + cif_isp10_pltfrm_pr_err(NULL, + "ERR: buf->state is: %d\n", + buf->state); + spin_unlock(&dev->vbreq_lock); + } else { + cif_isp10_pltfrm_pr_err(NULL, + "failed for buffer %d\n", buf->i); + } + } +} + +static long v4l2_default_ioctl(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + int ret = -EINVAL; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + + if (!arg) { + cif_isp10_pltfrm_pr_err(dev->dev, + "NULL Pointer Violation from IOCTL arg:0x%lx\n", + (unsigned long)arg); + return ret; + } + + if (cmd == RK_VIDIOC_SENSOR_MODE_DATA) { + struct isp_supplemental_sensor_mode_data *p_mode_data = + (struct isp_supplemental_sensor_mode_data *)arg; + + ret = (int)cif_isp10_img_src_ioctl(dev->img_src, + RK_VIDIOC_SENSOR_MODE_DATA, p_mode_data); + + if (ret < 0) { + cif_isp10_pltfrm_pr_err(dev->dev, + "failed to get sensor mode data\n"); + return ret; + } + + p_mode_data->isp_input_width = + dev->config.isp_config.input->defrect.width; + p_mode_data->isp_input_height = + dev->config.isp_config.input->defrect.height; + p_mode_data->isp_input_horizontal_start = + dev->config.isp_config.input->defrect.left; + p_mode_data->isp_input_vertical_start = + dev->config.isp_config.input->defrect.top; + + p_mode_data->isp_output_width = + dev->config.isp_config.output.width; + p_mode_data->isp_output_height = + dev->config.isp_config.output.height; + + if (ret < 0) { + cif_isp10_pltfrm_pr_err(dev->dev, + "failed to get isp input info\n"); + return ret; + } + } else if (cmd == RK_VIDIOC_CAMERA_MODULEINFO) { + struct camera_module_info_s *p_camera_module = + (struct camera_module_info_s *)arg; + + ret = (int)cif_isp10_img_src_ioctl(dev->img_src, + RK_VIDIOC_CAMERA_MODULEINFO, p_camera_module); + + if (ret < 0) { + cif_isp10_pltfrm_pr_err(dev->dev, + "failed to get camera module information\n"); + return ret; + } + } + + return ret; +} + +static int v4l2_s_parm( + struct file *file, + void *priv, + struct v4l2_streamparm *a) +{ + return 0; +} + +static int v4l2_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + const char *inp_name; + + if ((queue->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (queue->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)) { + cif_isp10_pltfrm_pr_err(NULL, + "wrong buffer queue %d\n", queue->type); + return -EINVAL; + } + + inp_name = cif_isp10_g_input_name(dev, input->index); + if (IS_ERR_OR_NULL(inp_name)) + return -EINVAL; + + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = V4L2_STD_UNKNOWN; + strncpy(input->name, inp_name, sizeof(input->name)-1); + + return 0; +} + +/* ================================================================= */ + +static int mainpath_g_ctrl( + struct file *file, + void *priv, + struct v4l2_control *vc) +{ + int ret = -EINVAL; + + switch (vc->id) { + default: + return -EINVAL; + } + return ret; +} + +#ifdef NOT_YET +static int mainpath_try_fmt_cap(struct v4l2_format *f) +{ + int ifmt = 0; + struct v4l2_pix_format *pix = &f->fmt.pix; + + cif_isp10_pltfrm_pr_dbg(NULL, "\n"); + + for (ifmt = 0; ifmt < get_cif_isp10_output_format_size(); ifmt++) { + if (pix->pixelformat == + get_cif_isp10_output_format(ifmt)->fourcc) + break; + } + + if (ifmt == get_cif_isp10_output_format_size()) + ifmt = 0; + + pix->bytesperline = pix->width * + get_cif_isp10_output_format(ifmt)->depth / 8; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_JPEG: + pix->colorspace = V4L2_COLORSPACE_JPEG; + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_SGRBG10: + pix->colorspace = V4L2_COLORSPACE_SRGB; + break; + default: + WARN_ON(1); + break; + } + + return 0; +} +#endif + +static int v4l2_enum_fmt_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + int ret = 0; + int xgold_num_format = 0; + + xgold_num_format = get_cif_isp10_output_format_desc_size(); + if ((f->index >= xgold_num_format) || + (get_cif_isp10_output_format_desc(f->index)->pixelformat == 0)) { + cif_isp10_pltfrm_pr_err(NULL, "index %d\n", f->index); + return -EINVAL; + } + strlcpy(f->description, + get_cif_isp10_output_format_desc(f->index)->description, + sizeof(f->description)); + f->pixelformat = + get_cif_isp10_output_format_desc(f->index)->pixelformat; + f->flags = get_cif_isp10_output_format_desc(f->index)->flags; + + return ret; +} + +static int v4l2_g_ctrl(struct file *file, void *priv, + struct v4l2_control *vc) +{ + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + enum cif_isp10_cid id = + cif_isp10_v4l2_cid2cif_isp10_cid(vc->id); + + return cif_isp10_img_src_g_ctrl(dev->img_src, + id, &vc->value); +} + +static int v4l2_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *vc_ext) +{ + struct cif_isp10_img_src_ctrl *ctrls; + struct cif_isp10_img_src_ext_ctrl *ctrl; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + int ret = -EINVAL; + unsigned int i; + + /* The only use-case is gain and exposure to sensor. Thus no check if + * this shall go to img_src or not as of now. + */ + cif_isp10_pltfrm_pr_dbg(dev->dev, "count %d\n", + vc_ext->count); + + if (vc_ext->count == 0) + return ret; + + ctrl = kmalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + ctrls = kmalloc(vc_ext->count * + sizeof(struct cif_isp10_img_src_ctrl), GFP_KERNEL); + if (!ctrls) { + kfree(ctrl); + return -ENOMEM; + } + + ctrl->cnt = vc_ext->count; + /*current kernel version don't define + *this member for struct v4l2_ext_control. + */ + /*ctrl->class = vc_ext->ctrl_class;*/ + ctrl->ctrls = ctrls; + + for (i = 0; i < vc_ext->count; i++) { + ctrls[i].id = vc_ext->controls[i].id; + ctrls[i].val = vc_ext->controls[i].value; + } + + ret = cif_isp10_s_exp(dev, ctrl); + return ret; +} + +int cif_isp10_v4l2_cropcap( + struct file *file, + void *fh, + struct v4l2_cropcap *a) +{ + int ret = 0; + struct videobuf_queue *queue = to_videobuf_queue(file); + struct cif_isp10_device *dev = to_cif_isp10_device(queue); + u32 target_width, target_height; + u32 h_offs, v_offs; + + if ((dev->config.input_sel == CIF_ISP10_INP_DMA) || + (dev->config.input_sel == CIF_ISP10_INP_DMA_IE)) { + /* calculate cropping for aspect ratio */ + ret = cif_isp10_calc_isp_cropping(dev, + &dev->isp_dev.input_width, &dev->isp_dev.input_height, + &h_offs, &v_offs); + + /* Get output size */ + ret = cif_isp10_get_target_frm_size(dev, + &target_width, &target_height); + if (ret < 0) { + cif_isp10_pltfrm_pr_err(dev->dev, + "failed to get target frame size\n"); + return ret; + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "CIF_IN_W=%d, CIF_IN_H=%d, ISP_IN_W=%d, ISP_IN_H=%d, target_width=%d, target_height=%d\n", + dev->config.isp_config.input->width, + dev->config.isp_config.input->height, + dev->isp_dev.input_width, + dev->isp_dev.input_height, + target_width, + target_height); + + /* This is the input to Bayer after input formatter cropping */ + a->defrect.top = 0; + a->defrect.left = 0; + a->defrect.width = dev->isp_dev.input_width; + a->defrect.height = dev->isp_dev.input_height; + /* This is the minimum cropping window for the IS module */ + a->bounds.width = 2; + a->bounds.height = 2; + a->bounds.top = (a->defrect.height - a->bounds.height) / 2; + a->bounds.left = (a->defrect.width - a->bounds.width) / 2; + + a->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + } else if (!CIF_ISP10_INP_IS_DMA(dev->config.input_sel)) { + /* calculate cropping for aspect ratio */ + ret = cif_isp10_calc_isp_cropping(dev, + &dev->isp_dev.input_width, &dev->isp_dev.input_height, + &h_offs, &v_offs); + + /* Get output size */ + ret = cif_isp10_get_target_frm_size(dev, + &target_width, &target_height); + if (ret < 0) { + cif_isp10_pltfrm_pr_err(dev->dev, + "failed to get target frame size\n"); + return ret; + } + + /* This is the input to Bayer after input formatter cropping */ + a->defrect.top = + v_offs + dev->config.isp_config.input->defrect.top; + a->defrect.left = + h_offs + dev->config.isp_config.input->defrect.left; + a->defrect.width = dev->isp_dev.input_width; + a->defrect.height = dev->isp_dev.input_height; + + a->bounds.top = 0; + a->bounds.left = 0; + a->bounds.width = dev->config.isp_config.input->width; + a->bounds.height = dev->config.isp_config.input->height; + a->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + } else { + cif_isp10_pltfrm_pr_err(dev->dev, + "invalid input\n"); + } + + cif_isp10_pltfrm_pr_dbg(dev->dev, + "v4l2_cropcap: defrect(%d,%d,%d,%d) bounds(%d,%d,%d,%d)\n", + a->defrect.width, + a->defrect.height, + a->defrect.left, + a->defrect.top, + a->bounds.width, + a->bounds.height, + a->bounds.left, + a->bounds.top); + + return ret; +} + +int cif_isp10_v4l2_g_crop(struct file *file, void *fh, struct v4l2_crop *a) +{ + return 0; +} + +/* + * This is a write only function, so the upper layer + * will ignore the changes to 'a'. So don't use 'a' to pass + * the actual cropping parameters, the upper layer + * should call g_crop to get the actual window. + */ +int cif_isp10_v4l2_s_crop( + struct file *file, + void *fh, + const struct v4l2_crop *a) +{ + return 0; +} + +const struct v4l2_ioctl_ops cif_isp10_v4l2_sp_ioctlops = { + .vidioc_reqbufs = cif_isp10_v4l2_reqbufs, + .vidioc_querybuf = cif_isp10_v4l2_querybuf, + .vidioc_qbuf = cif_isp10_v4l2_qbuf, + .vidioc_dqbuf = cif_isp10_v4l2_dqbuf, + .vidioc_streamon = cif_isp10_v4l2_streamon, + .vidioc_streamoff = cif_isp10_v4l2_streamoff, + .vidioc_s_input = cif_isp10_v4l2_s_input, + .vidioc_enum_input = v4l2_enum_input, + .vidioc_g_ctrl = v4l2_g_ctrl, + .vidioc_s_ctrl = cif_isp10_v4l2_s_ctrl, + .vidioc_s_fmt_vid_overlay = cif_isp10_v4l2_s_fmt, + .vidioc_g_fmt_vid_overlay = cif_isp10_v4l2_g_fmt, + .vidioc_s_ext_ctrls = v4l2_s_ext_ctrls, + .vidioc_querycap = v4l2_querycap, + .vidioc_cropcap = cif_isp10_v4l2_cropcap, + .vidioc_s_crop = cif_isp10_v4l2_s_crop, + .vidioc_g_crop = cif_isp10_v4l2_g_crop, + .vidioc_subscribe_event = cif_isp10_v4l2_subscribe_event, + .vidioc_unsubscribe_event = cif_isp10_v4l2_unsubscribe_event, + .vidioc_default = v4l2_default_ioctl, +}; + +const struct v4l2_ioctl_ops cif_isp10_v4l2_mp_ioctlops = { + .vidioc_reqbufs = cif_isp10_v4l2_reqbufs, + .vidioc_querybuf = cif_isp10_v4l2_querybuf, + .vidioc_qbuf = cif_isp10_v4l2_qbuf, + .vidioc_dqbuf = cif_isp10_v4l2_dqbuf, + .vidioc_streamon = cif_isp10_v4l2_streamon, + .vidioc_streamoff = cif_isp10_v4l2_streamoff, + .vidioc_s_input = cif_isp10_v4l2_s_input, + .vidioc_enum_input = v4l2_enum_input, + .vidioc_g_ctrl = mainpath_g_ctrl, + .vidioc_s_ctrl = cif_isp10_v4l2_s_ctrl, + .vidioc_s_fmt_vid_cap = cif_isp10_v4l2_s_fmt, + .vidioc_g_fmt_vid_cap = cif_isp10_v4l2_g_fmt, + .vidioc_enum_fmt_vid_cap = v4l2_enum_fmt_cap, + .vidioc_enum_framesizes = cif_isp10_v4l2_enum_framesizes, + .vidioc_s_parm = v4l2_s_parm, + .vidioc_querycap = v4l2_querycap, + .vidioc_cropcap = cif_isp10_v4l2_cropcap, + .vidioc_s_crop = cif_isp10_v4l2_s_crop, + .vidioc_g_crop = cif_isp10_v4l2_g_crop, + .vidioc_default = v4l2_default_ioctl, +}; + +const struct v4l2_ioctl_ops cif_isp10_v4l2_dma_ioctlops = { + .vidioc_reqbufs = cif_isp10_v4l2_reqbufs, + .vidioc_querybuf = cif_isp10_v4l2_querybuf, + .vidioc_qbuf = cif_isp10_v4l2_qbuf, + .vidioc_dqbuf = cif_isp10_v4l2_dqbuf, + .vidioc_streamon = cif_isp10_v4l2_streamon, + .vidioc_streamoff = cif_isp10_v4l2_streamoff, + .vidioc_s_fmt_vid_out = cif_isp10_v4l2_s_fmt, + .vidioc_g_fmt_vid_out = cif_isp10_v4l2_g_fmt, + .vidioc_cropcap = cif_isp10_v4l2_cropcap, + .vidioc_s_crop = cif_isp10_v4l2_s_crop, + .vidioc_g_crop = cif_isp10_v4l2_g_crop, +}; + +static struct pltfrm_soc_cfg rk3288_cfg = { + .name = CIF_ISP10_SOC_RK3288, + .soc_cfg = pltfrm_rk3288_cfg, +}; + +static struct pltfrm_soc_cfg rk3399_cfg = { + .name = CIF_ISP10_SOC_RK3399, + .soc_cfg = pltfrm_rk3399_cfg, +}; + +static const struct of_device_id cif_isp10_v4l2_of_match[] = { + {.compatible = "rockchip,rk3288-cif-isp", + .data = (void *)&rk3288_cfg}, + {.compatible = "rockchip,rk3399-cif-isp", + .data = (void *)&rk3399_cfg}, + {}, +}; + +static unsigned int cif_isp10_v4l2_dev_cnt; +static int cif_isp10_v4l2_drv_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device_node *node = pdev->dev.of_node; + struct cif_isp10_device *dev = NULL; + struct cif_isp10_v4l2_device *cif_isp10_v4l2_dev; + int ret; + + cif_isp10_pltfrm_pr_info(NULL, "probing...\n"); + + cif_isp10_v4l2_dev = devm_kzalloc( + &pdev->dev, + sizeof(struct cif_isp10_v4l2_device), + GFP_KERNEL); + if (IS_ERR_OR_NULL(cif_isp10_v4l2_dev)) { + ret = -ENOMEM; + goto err; + } + + match = of_match_node(cif_isp10_v4l2_of_match, node); + dev = cif_isp10_create(&pdev->dev, + cif_isp10_v4l2_event, + cif_isp10_v4l2_requeue_bufs, + (struct pltfrm_soc_cfg *)match->data); + if (IS_ERR_OR_NULL(dev)) { + ret = -ENODEV; + goto err; + } + + dev->dev_id = cif_isp10_v4l2_dev_cnt; + dev->isp_dev.dev_id = &dev->dev_id; + dev->nodes = (void *)cif_isp10_v4l2_dev; + spin_lock_init(&dev->vbq_lock); + spin_lock_init(&dev->vbreq_lock); + spin_lock_init(&iowrite32_verify_lock); + + ret = v4l2_device_register(dev->dev, &dev->v4l2_dev); + if (IS_ERR_VALUE(ret)) { + cif_isp10_pltfrm_pr_err(NULL, + "V4L2 device registration failed\n"); + goto err; + } + + ret = cif_isp10_v4l2_register_video_device( + dev, + &cif_isp10_v4l2_dev->node[SP_DEV].vdev, + SP_VDEV_NAME, + V4L2_CAP_VIDEO_OVERLAY, + CIF_ISP10_V4L2_SP_DEV_MAJOR, + &cif_isp10_v4l2_fops, + &cif_isp10_v4l2_sp_ioctlops); + if (ret) + goto err; + + ret = register_cifisp_device(&dev->isp_dev, + &cif_isp10_v4l2_dev->node[ISP_DEV].vdev, + &dev->v4l2_dev, + dev->config.base_addr); + if (ret) + goto err; + + ret = cif_isp10_v4l2_register_video_device( + dev, + &cif_isp10_v4l2_dev->node[MP_DEV].vdev, + MP_VDEV_NAME, + V4L2_CAP_VIDEO_CAPTURE, + CIF_ISP10_V4L2_MP_DEV_MAJOR, + &cif_isp10_v4l2_fops, + &cif_isp10_v4l2_mp_ioctlops); + if (ret) + goto err; + + ret = cif_isp10_v4l2_register_video_device( + dev, + &cif_isp10_v4l2_dev->node[DMA_DEV].vdev, + DMA_VDEV_NAME, + V4L2_CAP_VIDEO_OUTPUT, + CIF_ISP10_V4L2_DMA_DEV_MAJOR, + &cif_isp10_v4l2_fops, + &cif_isp10_v4l2_dma_ioctlops); + if (ret) + goto err; + + pm_runtime_enable(&pdev->dev); + + cif_isp10_v4l2_dev_cnt++; + return 0; +err: + cif_isp10_destroy(dev); + return ret; +} + +/* ======================================================================== */ + +static int cif_isp10_v4l2_drv_remove(struct platform_device *pdev) +{ + struct cif_isp10_device *cif_isp10_dev = + (struct cif_isp10_device *)platform_get_drvdata(pdev); + struct cif_isp10_v4l2_device *cif_isp10_v4l2_dev = + (struct cif_isp10_v4l2_device *)cif_isp10_dev->nodes; + + if (IS_ERR_VALUE(cif_isp10_release(cif_isp10_dev, + CIF_ISP10_ALL_STREAMS))) + cif_isp10_pltfrm_pr_warn(cif_isp10_dev->dev, + "CIF power off failed\n"); + + video_unregister_device(&cif_isp10_v4l2_dev->node[SP_DEV].vdev); + video_unregister_device(&cif_isp10_v4l2_dev->node[MP_DEV].vdev); + video_unregister_device(&cif_isp10_v4l2_dev->node[DMA_DEV].vdev); + unregister_cifisp_device(&cif_isp10_v4l2_dev->node[ISP_DEV].vdev); + v4l2_device_unregister(&cif_isp10_dev->v4l2_dev); + cif_isp10_pltfrm_dev_release(&pdev->dev); + cif_isp10_destroy(cif_isp10_dev); + + cif_isp10_v4l2_dev_cnt--; + return 0; +} + +static int cif_isp10_v4l2_drv_suspend(struct platform_device *pdev, + pm_message_t state) +{ + int ret = 0; + struct cif_isp10_device *cif_isp10_dev = + (struct cif_isp10_device *)platform_get_drvdata(pdev); + + cif_isp10_pltfrm_pr_dbg(cif_isp10_dev->dev, "\n"); + + ret = cif_isp10_suspend(cif_isp10_dev); + if (IS_ERR_VALUE(ret)) + goto err; + + cif_isp10_pltfrm_pinctrl_set_state(&pdev->dev, + CIF_ISP10_PINCTRL_STATE_SLEEP); + + return 0; +err: + cif_isp10_pltfrm_pr_err(cif_isp10_dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_v4l2_drv_resume(struct platform_device *pdev) +{ + int ret = 0; + struct cif_isp10_device *cif_isp10_dev = + (struct cif_isp10_device *)platform_get_drvdata(pdev); + + cif_isp10_pltfrm_pr_dbg(cif_isp10_dev->dev, "\n"); + + if (!cif_isp10_dev->img_src) { + cif_isp10_pltfrm_pr_err( + cif_isp10_dev->dev, + "cif_isp10_dev img_src is null!\n"); + goto err; + } + + ret = cif_isp10_resume(cif_isp10_dev); + if (IS_ERR_VALUE(ret)) + goto err; + + cif_isp10_pltfrm_pinctrl_set_state(&pdev->dev, + CIF_ISP10_PINCTRL_STATE_DEFAULT); + + return 0; +err: + cif_isp10_pltfrm_pr_err(cif_isp10_dev->dev, + "failed with error %d\n", ret); + return ret; +} + +static int cif_isp10_runtime_suspend(struct device *dev) +{ + cif_isp10_pltfrm_pr_dbg(dev, "\n"); + return cif_isp10_pltfrm_pm_set_state(dev, CIF_ISP10_PM_STATE_SUSPENDED); +} + +static int cif_isp10_runtime_resume(struct device *dev) +{ + cif_isp10_pltfrm_pr_dbg(dev, "\n"); + return cif_isp10_pltfrm_pm_set_state(dev, CIF_ISP10_PM_STATE_SW_STNDBY); +} + +static const struct dev_pm_ops cif_isp10_dev_pm_ops = { + SET_RUNTIME_PM_OPS(cif_isp10_runtime_suspend, + cif_isp10_runtime_resume, NULL) +}; + +static struct platform_driver cif_isp10_v4l2_plat_drv = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(cif_isp10_v4l2_of_match), + .pm = &cif_isp10_dev_pm_ops, + }, + .probe = cif_isp10_v4l2_drv_probe, + .remove = cif_isp10_v4l2_drv_remove, + .suspend = cif_isp10_v4l2_drv_suspend, + .resume = cif_isp10_v4l2_drv_resume, +}; + +/* ======================================================================== */ +static int cif_isp10_v4l2_init(void) +{ + int ret; + + ret = platform_driver_register(&cif_isp10_v4l2_plat_drv); + if (ret) { + cif_isp10_pltfrm_pr_err(NULL, + "cannot register platform driver, failed with %d\n", + ret); + return -ENODEV; + } + + return ret; +} + +/* ======================================================================== */ +static void __exit cif_isp10_v4l2_exit(void) +{ + platform_driver_unregister(&cif_isp10_v4l2_plat_drv); +} + +device_initcall_sync(cif_isp10_v4l2_init); +module_exit(cif_isp10_v4l2_exit); + +MODULE_DESCRIPTION("V4L2 interface for CIF ISP10 driver"); +MODULE_AUTHOR("George"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/rk-isp10/cif_isp10_version.h b/drivers/media/platform/rk-isp10/cif_isp10_version.h new file mode 100644 index 000000000000..4a01ec307b9b --- /dev/null +++ b/drivers/media/platform/rk-isp10/cif_isp10_version.h @@ -0,0 +1,64 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + #ifndef _CIF_ISP10_RK_VERSION_H_ +#define _CIF_ISP10_RK_VERSION_H_ +#include + +/* + * CIF DRIVER VERSION NOTE + * + *v0.1.0: + *1. New mi register update mode is invalidate in raw/jpeg for rk1108, + * All path used old mode for rk1108; + *v0.1.1: + *1. Modify CIF stop sequence for fix isp bus may dead when switch isp: + *Original stop sequence: Stop ISP(mipi) -> Stop ISP(isp) ->wait for ISP + *isp off -> Stop ISP(mi) + *Current stop sequence: ISP(mi) stop in mi frame end -> Stop ISP(mipi) + *-> Stop ISP(isp) ->wait for ISP isp off; + * Current stop sequence is only match sensor stream v-blanking >= 1.5ms; + * + *v0.1.2: + *1. Disable CIF_MIPI_ERR_DPHY interrupt here temporary for + *isp bus may be dead when switch isp; + *2. Cancel hw restart isp operation in mipi isr, only notice error log; + * + *v0.1.3: + *1. fix camerahal query exp info failed from cifisp_stat_buffer, because + *wake_up buffer before cif_isp11_sensor_mode_data_sync; + * + *v0.1.4: + *1. Disable DPHY errctrl interrupt, because this dphy erctrl signal + *is assert and until the next changes in line state. This time is may + *be too long and cpu is hold in this interrupt. Enable DPHY errctrl + *interrupt again, if mipi have receive the whole frame without any error. + *2. Modify mipi_dphy_cfg follow vendor recommended process in + *document. + *3. Select the limit dphy setting if sensor mipi datarate is overflow, + *and print warning information to user. + * + *v0.1.5: + *Exposure list must be queue operation, not stack. list_add switch to + *list_add_tail in cif_isp11_s_exp; + * + *v0.1.6: + *Add isp output size in struct isp_supplemental_sensor_mode_data. + * + */ + +#define CONFIG_CIFISP10_DRIVER_VERSION KERNEL_VERSION(0, 1, 6) + +#endif diff --git a/include/linux/platform_data/rk_isp10_platform.h b/include/linux/platform_data/rk_isp10_platform.h new file mode 100644 index 000000000000..8974945f9441 --- /dev/null +++ b/include/linux/platform_data/rk_isp10_platform.h @@ -0,0 +1,180 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ +#ifndef _CIF_ISP10_PLATFORM_H +#define _CIF_ISP10_PLATFORM_H +#include + +#define CIF_ISP10_SOC_RK3288 "rk3288" +#define CIF_ISP10_SOC_RK3368 "rk3368" +#define CIF_ISP10_SOC_RK3399 "rk3399" + +#define DRIVER_NAME "rkisp10" +#define ISP_VDEV_NAME DRIVER_NAME "_ispdev" +#define SP_VDEV_NAME DRIVER_NAME "_selfpath" +#define MP_VDEV_NAME DRIVER_NAME "_mainpath" +#define DMA_VDEV_NAME DRIVER_NAME "_dmapath" + +enum pltfrm_cam_signal_polarity { + PLTFRM_CAM_SIGNAL_HIGH_LEVEL = 0, + PLTFRM_CAM_SIGNAL_LOW_LEVEL = 1, +}; + +enum pltfrm_cam_sample_type { + PLTFRM_CAM_SDR_NEG_EDG = 0x10000001, + PLTFRM_CAM_SDR_POS_EDG = 0x10000002, + PLTFRM_CAM_DDR = 0x20000000 +}; + +enum pltfrm_cam_itf_type { + PLTFRM_CAM_ITF_MIPI = 0x10000000, + PLTFRM_CAM_ITF_BT601_8 = 0x20000071, + PLTFRM_CAM_ITF_BT656_8 = 0x20000072, + PLTFRM_CAM_ITF_BT601_10 = 0x20000091, + PLTFRM_CAM_ITF_BT656_10 = 0x20000092, + PLTFRM_CAM_ITF_BT601_12 = 0x200000B1, + PLTFRM_CAM_ITF_BT656_12 = 0x200000B2, + PLTFRM_CAM_ITF_BT601_16 = 0x200000F1, + PLTFRM_CAM_ITF_BT656_16 = 0x200000F2 +}; + +#define PLTFRM_CAM_ITF_MAIN_MASK 0xf0000000 +#define PLTFRM_CAM_ITF_SUB_MASK 0x0000000f +#define PLTFRM_CAM_ITF_DVP_BW_MASK 0x000000f0 + +#define PLTFRM_CAM_ITF_IS_MIPI(a) \ + (((a) & PLTFRM_CAM_ITF_MAIN_MASK) == 0x10000000) +#define PLTFRM_CAM_ITF_IS_DVP(a) \ + (((a) & PLTFRM_CAM_ITF_MAIN_MASK) == 0x20000000) +#define PLTFRM_CAM_ITF_IS_BT656(a) (PLTFRM_CAM_ITF_IS_DVP(a) &&\ + (((a) & PLTFRM_CAM_ITF_SUB_MASK) == 0x02)) +#define PLTFRM_CAM_ITF_IS_BT601(a) (PLTFRM_CAM_ITF_IS_DVP(a) &&\ + (((a) & PLTFRM_CAM_ITF_SUB_MASK) == 0x01)) +#define PLTFRM_CAM_ITF_DVP_BW(a) \ + ((((a) & PLTFRM_CAM_ITF_DVP_BW_MASK) >> 4) + 1) + +struct pltfrm_cam_mipi_config { + u32 dphy_index; + u32 vc; + u32 nb_lanes; + u32 bit_rate; +}; + +struct pltfrm_cam_dvp_config { + enum pltfrm_cam_signal_polarity vsync; + enum pltfrm_cam_signal_polarity hsync; + enum pltfrm_cam_sample_type pclk; +}; + +struct pltfrm_cam_itf { + enum pltfrm_cam_itf_type type; + + union { + struct pltfrm_cam_mipi_config mipi; + struct pltfrm_cam_dvp_config dvp; + } cfg; + unsigned int mclk_hz; +}; + +#define PLTFRM_CAM_ITF_MIPI_CFG(v, nb, br, mk)\ + .itf_cfg = {\ + .type = PLTFRM_CAM_ITF_MIPI,\ + .cfg = {\ + .mipi = {\ + .dphy_index = 0,\ + .vc = v,\ + .nb_lanes = nb,\ + .bit_rate = br,\ + } \ + },\ + .mclk_hz = mk\ + } +#define PLTFRM_CAM_ITF_DVP_CFG(ty, vs, hs, ck, mk)\ + .itf_cfg = {\ + .type = ty,\ + .cfg = {\ + .dvp = {\ + .vsync = vs,\ + .hsync = hs,\ + .pclk = ck,\ + } \ + },\ + .mclk_hz = mk\ + } + +#define PLTFRM_CIFCAM_IOCTL_INTERNAL_BASE 0x00 +#define PLTFRM_CIFCAM_G_ITF_CFG \ + (PLTFRM_CIFCAM_IOCTL_INTERNAL_BASE + 1) +#define PLTFRM_CIFCAM_G_DEFRECT \ + (PLTFRM_CIFCAM_IOCTL_INTERNAL_BASE + 2) +#define PLTFRM_CIFCAM_ATTACH \ + (PLTFRM_CIFCAM_IOCTL_INTERNAL_BASE + 3) + +struct pltfrm_cam_defrect { + unsigned int width; + unsigned int height; + struct v4l2_rect defrect; +}; + +enum pltfrm_soc_cfg_cmd { + PLTFRM_MCLK_CFG = 0, + PLTFRM_MIPI_DPHY_CFG, + + PLTFRM_CLKEN, + PLTFRM_CLKDIS, + PLTFRM_CLKRST, + + PLTFRM_SOC_INIT +}; + +enum pltfrm_soc_io_voltage { + PLTFRM_IO_1V8 = 0, + PLTFRM_IO_3V3 = 1 +}; + +enum pltfrm_soc_drv_strength { + PLTFRM_DRV_STRENGTH_0 = 0, + PLTFRM_DRV_STRENGTH_1 = 1, + PLTFRM_DRV_STRENGTH_2 = 2, + PLTFRM_DRV_STRENGTH_3 = 3 + +}; + +struct pltfrm_soc_init_para { + struct platform_device *pdev; + void __iomem *isp_base; +}; + +struct pltfrm_soc_mclk_para { + enum pltfrm_soc_io_voltage io_voltage; + enum pltfrm_soc_drv_strength drv_strength; +}; + +struct pltfrm_soc_cfg_para { + enum pltfrm_soc_cfg_cmd cmd; + void *cfg_para; +}; + +struct pltfrm_soc_cfg { + char name[32]; + int (*soc_cfg)(struct pltfrm_soc_cfg_para *cfg); +}; + +int pltfrm_rk3288_cfg( + struct pltfrm_soc_cfg_para *cfg); +int pltfrm_rk3399_cfg( + struct pltfrm_soc_cfg_para *cfg); + +#endif diff --git a/include/linux/platform_data/rk_isp10_platform_camera_module.h b/include/linux/platform_data/rk_isp10_platform_camera_module.h new file mode 100644 index 000000000000..276d2189bef7 --- /dev/null +++ b/include/linux/platform_data/rk_isp10_platform_camera_module.h @@ -0,0 +1,126 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef PLATFORM_CAMERA_MODULE_H +#define PLATFORM_CAMERA_MODULE_H +#include + +#define PLTFRM_CAMERA_MODULE_REG_TYPE_DATA 0 +#define PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT 1 + +extern const char *PLTFRM_CAMERA_MODULE_PIN_PD; +extern const char *PLTFRM_CAMERA_MODULE_PIN_PWR; +extern const char *PLTFRM_CAMERA_MODULE_PIN_FLASH; +extern const char *PLTFRM_CAMERA_MODULE_PIN_TORCH; +extern const char *PLTFRM_CAMERA_MODULE_PIN_RESET; +extern const char *PLTFRM_CAMERA_MODULE_PIN_VSYNC; + +enum pltfrm_camera_module_pin_state { + PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE = 0, + PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE = 1 +}; + +struct pltfrm_camera_module_reg { + u32 flag; + u16 reg; + u16 val; +}; + +struct pltfrm_camera_module_reg_table { + u32 reg_table_num_entries; + struct pltfrm_camera_module_reg *reg_table; +}; + +int pltfrm_camera_module_set_pm_state( + struct v4l2_subdev *sd, + int on); + +int pltfrm_camera_module_set_pin_state( + struct v4l2_subdev *sd, + const char *pin, + enum pltfrm_camera_module_pin_state state); + +int pltfrm_camera_module_get_pin_state( + struct v4l2_subdev *sd, + const char *pin); + +int pltfrm_camera_module_s_power( + struct v4l2_subdev *sd, + int on); + +int pltfrm_camera_module_patch_config( + struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *frm_fmt, + struct v4l2_subdev_frame_interval *frm_intrvl); + +struct v4l2_subdev *pltfrm_camera_module_get_af_ctrl( + struct v4l2_subdev *sd); + +struct v4l2_subdev *pltfrm_camera_module_get_fl_ctrl( + struct v4l2_subdev *sd); + +char *pltfrm_camera_module_get_flash_driver_name( + struct v4l2_subdev *sd); + +int pltfrm_camera_module_init( + struct v4l2_subdev *sd, + void **pldata); + +void pltfrm_camera_module_release( + struct v4l2_subdev *sd); + +int pltfrm_camera_module_read_reg(struct v4l2_subdev *sd, + u16 data_length, + u16 reg, + u32 *val); + +int pltfrm_superpix_camera_module_read_reg(struct v4l2_subdev *sd, + u16 data_length, + u8 reg, + u8 *val); + +int pltfrm_camera_module_write_reg(struct v4l2_subdev *sd, + u16 reg, u8 val); + +int pltfrm_camera_module_write_reglist( + struct v4l2_subdev *sd, + const struct pltfrm_camera_module_reg reglist[], + int len); + +long pltfrm_camera_module_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, + void *arg); + +const char *pltfrm_dev_string(struct v4l2_subdev *sd); + +int pltfrm_camera_module_get_flip_mirror( + struct v4l2_subdev *sd); + +#define pltfrm_camera_module_pr_debug(dev, fmt, arg...) \ + pr_debug("%s.%s: " fmt, \ + pltfrm_dev_string(dev), __func__, ## arg) +#define pltfrm_camera_module_pr_info(dev, fmt, arg...) \ + pr_info("%s.%s: " fmt, \ + pltfrm_dev_string(dev), __func__, ## arg) +#define pltfrm_camera_module_pr_warn(dev, fmt, arg...) \ + pr_warn("%s.%s WARN: " fmt, \ + pltfrm_dev_string(dev), __func__, ## arg) +#define pltfrm_camera_module_pr_err(dev, fmt, arg...) \ + pr_err("%s.%s(%d) ERR: " fmt, \ + pltfrm_dev_string(dev), __func__, __LINE__, \ + ## arg) + +#endif diff --git a/include/media/rk-isp10-config.h b/include/media/rk-isp10-config.h new file mode 100644 index 000000000000..6cdad63de5d2 --- /dev/null +++ b/include/media/rk-isp10-config.h @@ -0,0 +1,550 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ +#ifndef _RK_ISP11_CONFIG_H +#define _RK_ISP11_CONFIG_H + +#include + +#define CIFISP_MODULE_DPCC BIT(0) +#define CIFISP_MODULE_BLS BIT(1) +#define CIFISP_MODULE_SDG BIT(2) +#define CIFISP_MODULE_HST BIT(3) +#define CIFISP_MODULE_LSC BIT(4) +#define CIFISP_MODULE_AWB_GAIN BIT(5) +#define CIFISP_MODULE_FLT BIT(6) +#define CIFISP_MODULE_BDM BIT(7) +#define CIFISP_MODULE_CTK BIT(8) +#define CIFISP_MODULE_GOC BIT(9) +#define CIFISP_MODULE_CPROC BIT(10) +#define CIFISP_MODULE_AFC BIT(11) +#define CIFISP_MODULE_AWB BIT(12) +#define CIFISP_MODULE_IE BIT(13) +#define CIFISP_MODULE_AEC BIT(14) +#define CIFISP_MODULE_WDR BIT(15) +#define CIFISP_MODULE_DPF BIT(16) +#define CIFISP_MODULE_DPF_STRENGTH BIT(17) + +#define CIFISP_CTK_COEFF_MAX 0x100 +#define CIFISP_CTK_OFFSET_MAX 0x800 + +#define CIFISP_AE_MEAN_MAX 25 +#define CIFISP_HIST_BIN_N_MAX 16 +#define CIFISP_AFM_MAX_WINDOWS 3 +#define CIFISP_DEGAMMA_CURVE_SIZE 17 + +#define CIFISP_BDM_MAX_TH 0xFF + +/* maximum value for horizontal start address */ +#define CIFISP_BLS_START_H_MAX (0x00000FFF) +/* maximum value for horizontal stop address */ +#define CIFISP_BLS_STOP_H_MAX (0x00000FFF) +/* maximum value for vertical start address */ +#define CIFISP_BLS_START_V_MAX (0x00000FFF) +/* maximum value for vertical stop address */ +#define CIFISP_BLS_STOP_V_MAX (0x00000FFF) +/* maximum is 2^18 = 262144*/ +#define CIFISP_BLS_SAMPLES_MAX (0x00000012) +/* maximum value for fixed black level */ +#define CIFISP_BLS_FIX_SUB_MAX (0x00000FFF) +/* minimum value for fixed black level */ +#define CIFISP_BLS_FIX_SUB_MIN (0xFFFFF000) +/* 13 bit range (signed)*/ +#define CIFISP_BLS_FIX_MASK (0x00001FFF) +/* AWB */ +#define CIFISP_AWB_MAX_GRID 1 +#define CIFISP_AWB_MAX_FRAMES 7 + +/* Gamma out*/ +/* Maximum number of color samples supported */ +#define CIFISP_GAMMA_OUT_MAX_SAMPLES 17 + +/* LSC */ +#define CIFISP_LSC_GRAD_TBL_SIZE 8 +#define CIFISP_LSC_SIZE_TBL_SIZE 8 +/* + * The following matches the tuning process, + * not the max capabilities of the chip. + */ +#define CIFISP_LSC_DATA_TBL_SIZE 289 +/* HIST */ +#define CIFISP_HISTOGRAM_WEIGHT_GRIDS_SIZE 25 + +/* DPCC */ +#define CIFISP_DPCC_METHODS_MAX (3) + +/* DPF */ +#define CIFISP_DPF_MAX_NLF_COEFFS 17 +#define CIFISP_DPF_MAX_SPATIAL_COEFFS 6 + +#define CIFISP_STAT_AWB BIT(0) +#define CIFISP_STAT_AUTOEXP BIT(1) +#define CIFISP_STAT_AFM_FIN BIT(2) +#define CIFISP_STAT_HIST BIT(3) + +enum cifisp_histogram_mode { + CIFISP_HISTOGRAM_MODE_DISABLE = 0, + CIFISP_HISTOGRAM_MODE_RGB_COMBINED = 1, + CIFISP_HISTOGRAM_MODE_R_HISTOGRAM = 2, + CIFISP_HISTOGRAM_MODE_G_HISTOGRAM = 3, + CIFISP_HISTOGRAM_MODE_B_HISTOGRAM = 4, + CIFISP_HISTOGRAM_MODE_Y_HISTOGRAM = 5 +}; + +enum cifisp_exp_ctrl_autostop { + CIFISP_EXP_CTRL_AUTOSTOP_0 = 0, + CIFISP_EXP_CTRL_AUTOSTOP_1 = 1 +}; + +enum cifisp_exp_meas_mode { +/* < Y = 16 + 0.25R + 0.5G + 0.1094B */ + CIFISP_EXP_MEASURING_MODE_0 = 0, +/* < Y = (R + G + B) x (85/256) */ + CIFISP_EXP_MEASURING_MODE_1 = 1, +}; + +struct cifisp_window { + unsigned short h_offs; + unsigned short v_offs; + unsigned short h_size; + unsigned short v_size; +}; + +enum cifisp_awb_mode_type { + CIFISP_AWB_MODE_MANUAL = 0, + CIFISP_AWB_MODE_RGB = 1, + CIFISP_AWB_MODE_YCBCR = 2 +}; + +enum cifisp_bls_win_enable { + ISP_BLS_CTRL_WINDOW_ENABLE_0 = 0, + ISP_BLS_CTRL_WINDOW_ENABLE_1 = 1, + ISP_BLS_CTRL_WINDOW_ENABLE_2 = 2, + ISP_BLS_CTRL_WINDOW_ENABLE_3 = 3 +}; + +enum cifisp_flt_mode { + CIFISP_FLT_STATIC_MODE, + CIFISP_FLT_DYNAMIC_MODE +}; + +struct cifisp_awb_meas { + unsigned int cnt; + unsigned char mean_y; + unsigned char mean_cb; + unsigned char mean_cr; + unsigned short mean_r; + unsigned short mean_b; + unsigned short mean_g; +}; + +struct cifisp_awb_stat { + struct cifisp_awb_meas awb_mean[CIFISP_AWB_MAX_GRID]; +}; + +struct cifisp_hist_stat { + unsigned short hist_bins[CIFISP_HIST_BIN_N_MAX]; +}; + +/*! BLS mean measured values */ +struct cifisp_bls_meas_val { + /*! Mean measured value for Bayer pattern R.*/ + unsigned short meas_r; + /*! Mean measured value for Bayer pattern Gr.*/ + unsigned short meas_gr; + /*! Mean measured value for Bayer pattern Gb.*/ + unsigned short meas_gb; + /*! Mean measured value for Bayer pattern B.*/ + unsigned short meas_b; +}; + +/* + * BLS fixed subtraction values. The values will be subtracted from the sensor + * values. Therefore a negative value means addition instead of subtraction! + */ +struct cifisp_bls_fixed_val { + /*! Fixed (signed!) subtraction value for Bayer pattern R. */ + signed short r; + /*! Fixed (signed!) subtraction value for Bayer pattern Gr. */ + signed short gr; + /*! Fixed (signed!) subtraction value for Bayer pattern Gb. */ + signed short gb; + /*! Fixed (signed!) subtraction value for Bayer pattern B. */ + signed short b; +}; + +/* Configuration used by black level subtraction */ +struct cifisp_bls_config { + /* + * Automatic mode activated means that the measured values + * are subtracted.Otherwise the fixed subtraction + * values will be subtracted. + */ + bool enable_auto; + unsigned char en_windows; + struct cifisp_window bls_window1; /* < Measurement window 1. */ + struct cifisp_window bls_window2; /* !< Measurement window 2 */ + /* + * Set amount of measured pixels for each Bayer position + * (A, B,C and D) to 2^bls_samples. + */ + unsigned char bls_samples; + /* !< Fixed subtraction values. */ + struct cifisp_bls_fixed_val fixed_val; +}; + +struct cifisp_ae_stat { + unsigned char exp_mean[CIFISP_AE_MEAN_MAX]; + struct cifisp_bls_meas_val bls_val; /* available wit exposure results */ +}; + +struct cifisp_af_meas_val { + unsigned int sum; + unsigned int lum; +}; + +struct cifisp_af_stat { + struct cifisp_af_meas_val window[CIFISP_AFM_MAX_WINDOWS]; +}; + +struct cifisp_stat { + struct cifisp_awb_stat awb; + struct cifisp_ae_stat ae; + struct cifisp_af_stat af; + struct cifisp_hist_stat hist; +}; + +struct cifisp_stat_buffer { + unsigned int meas_type; + struct cifisp_stat params; + struct isp_supplemental_sensor_mode_data sensor_mode; +}; + +struct cifisp_dpcc_methods_config { + unsigned int method; + unsigned int line_thresh; + unsigned int line_mad_fac; + unsigned int pg_fac; + unsigned int rnd_thresh; + unsigned int rg_fac; +}; + +struct cifisp_dpcc_config { + unsigned int mode; + unsigned int output_mode; + unsigned int set_use; + struct cifisp_dpcc_methods_config methods[CIFISP_DPCC_METHODS_MAX]; + unsigned int ro_limits; + unsigned int rnd_offs; +}; + +struct cifisp_gamma_corr_curve { + unsigned short gamma_y[CIFISP_DEGAMMA_CURVE_SIZE]; +}; + +struct cifisp_gamma_curve_x_axis_pnts { + unsigned int gamma_dx0; + unsigned int gamma_dx1; +}; + +/* Configuration used by sensor degamma */ +struct cifisp_sdg_config { + struct cifisp_gamma_corr_curve curve_r; + struct cifisp_gamma_corr_curve curve_g; + struct cifisp_gamma_corr_curve curve_b; + struct cifisp_gamma_curve_x_axis_pnts xa_pnts; +}; + +/* Configuration used by Lens shading correction */ +struct cifisp_lsc_config { + unsigned int r_data_tbl[CIFISP_LSC_DATA_TBL_SIZE]; + unsigned int gr_data_tbl[CIFISP_LSC_DATA_TBL_SIZE]; + unsigned int gb_data_tbl[CIFISP_LSC_DATA_TBL_SIZE]; + unsigned int b_data_tbl[CIFISP_LSC_DATA_TBL_SIZE]; + + unsigned int x_grad_tbl[CIFISP_LSC_GRAD_TBL_SIZE]; + unsigned int y_grad_tbl[CIFISP_LSC_GRAD_TBL_SIZE]; + + unsigned int x_size_tbl[CIFISP_LSC_SIZE_TBL_SIZE]; + unsigned int y_size_tbl[CIFISP_LSC_SIZE_TBL_SIZE]; + unsigned short config_width; + unsigned short config_height; +}; + +struct cifisp_ie_config { + enum v4l2_colorfx effect; + unsigned short color_sel; + /* 3x3 Matrix Coefficients for Emboss Effect 1 */ + unsigned short eff_mat_1; + /* 3x3 Matrix Coefficients for Emboss Effect 2 */ + unsigned short eff_mat_2; + /* 3x3 Matrix Coefficients for Emboss 3/Sketch 1 */ + unsigned short eff_mat_3; + /* 3x3 Matrix Coefficients for Sketch Effect 2 */ + unsigned short eff_mat_4; + /* 3x3 Matrix Coefficients for Sketch Effect 3 */ + unsigned short eff_mat_5; + /* Chrominance increment values of tint (used for sepia effect) */ + unsigned short eff_tint; +}; + +/* Configuration used by auto white balance */ +struct cifisp_awb_meas_config { + /* + * white balance measurement window (in pixels) + * Note: currently the h and v offsets are mapped to grid offsets + */ + struct cifisp_window awb_wnd; + enum cifisp_awb_mode_type awb_mode; + /* + * only pixels values < max_y contribute to awb measurement + * (set to 0 to disable this feature) + */ + unsigned char max_y; + /* only pixels values > min_y contribute to awb measurement */ + unsigned char min_y; + /* + * Chrominance sum maximum value, only consider pixels with Cb+Cr + * smaller than threshold for awb measurements + */ + unsigned char max_csum; + /* + * Chrominance minimum value, only consider pixels with Cb/Cr + * each greater than threshold value for awb measurements + */ + unsigned char min_c; + /* + * number of frames - 1 used for mean value calculation + * (ucFrames=0 means 1 Frame) + */ + unsigned char frames; + /* reference Cr value for AWB regulation, target for AWB */ + unsigned char awb_ref_cr; + /* reference Cb value for AWB regulation, target for AWB */ + unsigned char awb_ref_cb; + bool enable_ymax_cmp; +}; + +struct cifisp_awb_gain_config { + unsigned short gain_red; + unsigned short gain_green_r; + unsigned short gain_blue; + unsigned short gain_green_b; +}; + +/* Configuration used by ISP filtering */ +struct cifisp_flt_config { + enum cifisp_flt_mode mode; /* ISP_FILT_MODE register fields */ + unsigned char grn_stage1; /* ISP_FILT_MODE register fields */ + unsigned char chr_h_mode; /* ISP_FILT_MODE register fields */ + unsigned char chr_v_mode; /* ISP_FILT_MODE register fields */ + unsigned int thresh_bl0; + unsigned int thresh_bl1; + unsigned int thresh_sh0; + unsigned int thresh_sh1; + unsigned int lum_weight; + unsigned int fac_sh1; + unsigned int fac_sh0; + unsigned int fac_mid; + unsigned int fac_bl0; + unsigned int fac_bl1; +}; + +/* Configuration used by Bayer DeMosaic */ +struct cifisp_bdm_config { + unsigned char demosaic_th; +}; + +/* Configuration used by Cross Talk correction */ +struct cifisp_ctk_config { + unsigned short coeff0; + unsigned short coeff1; + unsigned short coeff2; + unsigned short coeff3; + unsigned short coeff4; + unsigned short coeff5; + unsigned short coeff6; + unsigned short coeff7; + unsigned short coeff8; + /* offset for the crosstalk correction matrix */ + unsigned short ct_offset_r; + unsigned short ct_offset_g; + unsigned short ct_offset_b; +}; + +enum cifisp_goc_mode { + CIFISP_GOC_MODE_LOGARITHMIC, + CIFISP_GOC_MODE_EQUIDISTANT +}; + +/* Configuration used by Gamma Out correction */ +struct cifisp_goc_config { + enum cifisp_goc_mode mode; + unsigned short gamma_y[CIFISP_GAMMA_OUT_MAX_SAMPLES]; +}; + +/* CCM (Color Correction) */ +struct cifisp_cproc_config { + unsigned char c_out_range; + unsigned char y_in_range; + unsigned char y_out_range; + unsigned char contrast; + unsigned char brightness; + unsigned char sat; + unsigned char hue; +}; + +/* Configuration used by Histogram */ +struct cifisp_hst_config { + enum cifisp_histogram_mode mode; + unsigned char histogram_predivider; + struct cifisp_window meas_window; + unsigned char hist_weight[CIFISP_HISTOGRAM_WEIGHT_GRIDS_SIZE]; +}; + +/* Configuration used by Auto Exposure Control */ +struct cifisp_aec_config { + enum cifisp_exp_meas_mode mode; + enum cifisp_exp_ctrl_autostop autostop; + struct cifisp_window meas_window; +}; + +struct cifisp_afc_config { + unsigned char num_afm_win; /* max CIFISP_AFM_MAX_WINDOWS */ + struct cifisp_window afm_win[CIFISP_AFM_MAX_WINDOWS]; + unsigned int thres; + unsigned int var_shift; +}; + +enum cifisp_dpf_gain_usage { +/* don't use any gains in preprocessing stage */ + CIFISP_DPF_GAIN_USAGE_DISABLED = 1, +/* use only the noise function gains from registers DPF_NF_GAIN_R, ... */ + CIFISP_DPF_GAIN_USAGE_NF_GAINS = 2, +/* use only the gains from LSC module */ + CIFISP_DPF_GAIN_USAGE_LSC_GAINS = 3, +/* use the moise function gains and the gains from LSC module */ + CIFISP_DPF_GAIN_USAGE_NF_LSC_GAINS = 4, +/* use only the gains from AWB module */ + CIFISP_DPF_GAIN_USAGE_AWB_GAINS = 5, +/* use the gains from AWB and LSC module */ + CIFISP_DPF_GAIN_USAGE_AWB_LSC_GAINS = 6, +/* upper border (only for an internal evaluation) */ + CIFISP_DPF_GAIN_USAGE_MAX +}; + +enum cifisp_dpf_rb_filtersize { +/* red and blue filter kernel size 13x9 (means 7x5 active pixel) */ + CIFISP_DPF_RB_FILTERSIZE_13x9 = 0, +/* red and blue filter kernel size 9x9 (means 5x5 active pixel) */ + CIFISP_DPF_RB_FILTERSIZE_9x9 = 1, +}; + +enum cifisp_dpf_nll_scale_mode { +/* use a linear scaling */ + CIFISP_NLL_SCALE_LINEAR = 0, +/* use a logarithmic scaling */ + CIFISP_NLL_SCALE_LOGARITHMIC = 1, +}; + +struct cifisp_dpf_nll { + unsigned short coeff[CIFISP_DPF_MAX_NLF_COEFFS]; + enum cifisp_dpf_nll_scale_mode scale_mode; +}; + +struct cifisp_dpf_rb_flt { + enum cifisp_dpf_rb_filtersize fltsize; + unsigned char spatial_coeff[CIFISP_DPF_MAX_SPATIAL_COEFFS]; + bool r_enable; + bool b_enable; +}; + +struct cifisp_dpf_g_flt { + unsigned char spatial_coeff[CIFISP_DPF_MAX_SPATIAL_COEFFS]; + bool gr_enable; + bool gb_enable; +}; + +struct cifisp_dpf_gain { + enum cifisp_dpf_gain_usage mode; + unsigned short nf_r_gain; + unsigned short nf_b_gain; + unsigned short nf_gr_gain; + unsigned short nf_gb_gain; +}; + +struct cifisp_dpf_config { + struct cifisp_dpf_gain gain; + struct cifisp_dpf_g_flt g_flt; + struct cifisp_dpf_rb_flt rb_flt; + struct cifisp_dpf_nll nll; +}; + +struct cifisp_dpf_strength_config { + unsigned char r; + unsigned char g; + unsigned char b; +}; + +struct cifisp_last_capture_config { + struct cifisp_cproc_config cproc; + struct cifisp_goc_config goc; + struct cifisp_ctk_config ctk; + struct cifisp_bdm_config bdm; + struct cifisp_flt_config flt; + struct cifisp_awb_gain_config awb_gain; + struct cifisp_awb_meas_config awb_meas; + struct cifisp_lsc_config lsc; + struct cifisp_sdg_config sdg; + struct cifisp_bls_config bls; +}; + +struct cifisp_isp_other_cfg { + unsigned int s_frame_id;/* Set isp hardware frame id */ + + unsigned int module_ens; + + struct cifisp_dpcc_config dpcc_config; + struct cifisp_bls_config bls_config; + struct cifisp_sdg_config sdg_config; + struct cifisp_lsc_config lsc_config; + struct cifisp_awb_gain_config awb_gain_config; + struct cifisp_flt_config flt_config; + struct cifisp_bdm_config bdm_config; + struct cifisp_ctk_config ctk_config; + struct cifisp_goc_config goc_config; + struct cifisp_cproc_config cproc_config; + struct cifisp_ie_config ie_config; + struct cifisp_dpf_config dpf_config; + struct cifisp_dpf_strength_config dpf_strength_config; +}; + +struct cifisp_isp_meas_cfg { + unsigned int s_frame_id; /* Set isp hardware frame id */ + + unsigned int module_ens; + + struct cifisp_awb_meas_config awb_meas_config; + struct cifisp_hst_config hst_config; + struct cifisp_aec_config aec_config; + struct cifisp_afc_config afc_config; +}; + +struct cifisp_isp_metadata { + struct cifisp_isp_other_cfg other_cfg; + struct cifisp_isp_meas_cfg meas_cfg; + struct cifisp_stat_buffer meas_stat; +}; +#endif diff --git a/include/media/rk-isp10-ioctl.h b/include/media/rk-isp10-ioctl.h new file mode 100644 index 000000000000..22e2e6e8d8a5 --- /dev/null +++ b/include/media/rk-isp10-ioctl.h @@ -0,0 +1,133 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ +#include +#include +#include + +#ifndef _RK_ISP10_IOCTL_H +#define _RK_ISP10_IOCTL_H + +/* Private IOCTLs */ +/* DPCC */ +#define CIFISP_IOC_G_DPCC \ + _IOR('v', BASE_VIDIOC_PRIVATE + 0, struct cifisp_dpcc_config) +#define CIFISP_IOC_S_DPCC \ + _IOW('v', BASE_VIDIOC_PRIVATE + 1, struct cifisp_dpcc_config) +/* Black Level Subtraction */ +#define CIFISP_IOC_G_BLS \ + _IOR('v', BASE_VIDIOC_PRIVATE + 2, struct cifisp_bls_config) +#define CIFISP_IOC_S_BLS \ + _IOW('v', BASE_VIDIOC_PRIVATE + 3, struct cifisp_bls_config) +/* Sensor DeGamma */ +#define CIFISP_IOC_G_SDG \ + _IOR('v', BASE_VIDIOC_PRIVATE + 4, struct cifisp_sdg_config) +#define CIFISP_IOC_S_SDG \ + _IOW('v', BASE_VIDIOC_PRIVATE + 5, struct cifisp_sdg_config) +/* Lens Shading Correction */ +#define CIFISP_IOC_G_LSC \ + _IOR('v', BASE_VIDIOC_PRIVATE + 6, struct cifisp_lsc_config) +#define CIFISP_IOC_S_LSC \ + _IOW('v', BASE_VIDIOC_PRIVATE + 7, struct cifisp_lsc_config) +/* Auto White Balance */ +#define CIFISP_IOC_G_AWB_MEAS \ + _IOR('v', BASE_VIDIOC_PRIVATE + 8, struct cifisp_awb_meas_config) +#define CIFISP_IOC_S_AWB_MEAS \ + _IOW('v', BASE_VIDIOC_PRIVATE + 9, struct cifisp_awb_meas_config) +/* ISP Filtering( Sharpening & Noise reduction */ +#define CIFISP_IOC_G_FLT \ + _IOR('v', BASE_VIDIOC_PRIVATE + 10, struct cifisp_flt_config) +#define CIFISP_IOC_S_FLT \ + _IOW('v', BASE_VIDIOC_PRIVATE + 11, struct cifisp_flt_config) +/* Bayer Demosaic */ +#define CIFISP_IOC_G_BDM \ + _IOR('v', BASE_VIDIOC_PRIVATE + 12, struct cifisp_bdm_config) +#define CIFISP_IOC_S_BDM \ + _IOW('v', BASE_VIDIOC_PRIVATE + 13, struct cifisp_bdm_config) +/* Cross Talk correction */ +#define CIFISP_IOC_G_CTK \ + _IOR('v', BASE_VIDIOC_PRIVATE + 14, struct cifisp_ctk_config) +#define CIFISP_IOC_S_CTK \ + _IOW('v', BASE_VIDIOC_PRIVATE + 15, struct cifisp_ctk_config) +/* Gamma Out Correction */ +#define CIFISP_IOC_G_GOC \ + _IOR('v', BASE_VIDIOC_PRIVATE + 16, struct cifisp_goc_config) +#define CIFISP_IOC_S_GOC \ + _IOW('v', BASE_VIDIOC_PRIVATE + 17, struct cifisp_goc_config) +/* Histogram Measurement */ +#define CIFISP_IOC_G_HST \ + _IOR('v', BASE_VIDIOC_PRIVATE + 18, struct cifisp_hst_config) +#define CIFISP_IOC_S_HST \ + _IOW('v', BASE_VIDIOC_PRIVATE + 19, struct cifisp_hst_config) +/* Auto Exposure Measurements */ +#define CIFISP_IOC_G_AEC \ + _IOR('v', BASE_VIDIOC_PRIVATE + 20, struct cifisp_aec_config) +#define CIFISP_IOC_S_AEC \ + _IOW('v', BASE_VIDIOC_PRIVATE + 21, struct cifisp_aec_config) +#define CIFISP_IOC_G_BPL \ + _IOR('v', BASE_VIDIOC_PRIVATE + 22, struct cifisp_aec_config) +#define CIFISP_IOC_G_AWB_GAIN \ + _IOR('v', BASE_VIDIOC_PRIVATE + 23, struct cifisp_awb_gain_config) +#define CIFISP_IOC_S_AWB_GAIN \ + _IOW('v', BASE_VIDIOC_PRIVATE + 24, struct cifisp_awb_gain_config) +#define CIFISP_IOC_G_CPROC \ + _IOR('v', BASE_VIDIOC_PRIVATE + 25, struct cifisp_cproc_config) +#define CIFISP_IOC_S_CPROC \ + _IOW('v', BASE_VIDIOC_PRIVATE + 26, struct cifisp_cproc_config) +#define CIFISP_IOC_G_AFC \ + _IOR('v', BASE_VIDIOC_PRIVATE + 27, struct cifisp_afc_config) +#define CIFISP_IOC_S_AFC \ + _IOW('v', BASE_VIDIOC_PRIVATE + 28, struct cifisp_afc_config) +#define CIFISP_IOC_G_IE \ + _IOR('v', BASE_VIDIOC_PRIVATE + 29, struct cifisp_ie_config) +#define CIFISP_IOC_S_IE \ + _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct cifisp_ie_config) +#define CIFISP_IOC_G_DPF \ + _IOR('v', BASE_VIDIOC_PRIVATE + 31, struct cifisp_dpf_config) +#define CIFISP_IOC_S_DPF \ + _IOW('v', BASE_VIDIOC_PRIVATE + 32, struct cifisp_dpf_config) +#define CIFISP_IOC_G_DPF_STRENGTH \ + _IOR('v', BASE_VIDIOC_PRIVATE + 33, struct cifisp_dpf_strength_config) +#define CIFISP_IOC_S_DPF_STRENGTH \ + _IOW('v', BASE_VIDIOC_PRIVATE + 34, struct cifisp_dpf_strength_config) +#define CIFISP_IOC_G_LAST_CONFIG \ + _IOR('v', BASE_VIDIOC_PRIVATE + 35, struct cifisp_last_capture_config) + +/* CIF-ISP Private control IDs */ +#define V4L2_CID_CIFISP_DPCC (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_CIFISP_BLS (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_CIFISP_SDG (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_CIFISP_LSC (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_CIFISP_AWB_MEAS (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_CIFISP_FLT (V4L2_CID_PRIVATE_BASE + 5) +#define V4L2_CID_CIFISP_BDM (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_CIFISP_CTK (V4L2_CID_PRIVATE_BASE + 7) +#define V4L2_CID_CIFISP_GOC (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_CIFISP_HST (V4L2_CID_PRIVATE_BASE + 9) +#define V4L2_CID_CIFISP_AEC (V4L2_CID_PRIVATE_BASE + 10) +#define V4L2_CID_CIFISP_AWB_GAIN (V4L2_CID_PRIVATE_BASE + 11) +#define V4L2_CID_CIFISP_CPROC (V4L2_CID_PRIVATE_BASE + 12) +#define V4L2_CID_CIFISP_AFC (V4L2_CID_PRIVATE_BASE + 13) +#define V4L2_CID_CIFISP_IE (V4L2_CID_PRIVATE_BASE + 14) +#define V4L2_CID_CIFISP_DPF (V4L2_CID_PRIVATE_BASE + 15) + +/* Camera Sensors' running modes */ +#define CI_MODE_PREVIEW 0x8000 +#define CI_MODE_VIDEO 0x4000 +#define CI_MODE_STILL_CAPTURE 0x2000 +#define CI_MODE_CONTINUOUS 0x1000 +#define CI_MODE_NONE 0x0000 + +#endif diff --git a/include/media/v4l2-config_rockchip.h b/include/media/v4l2-config_rockchip.h new file mode 100644 index 000000000000..fb668027e4e2 --- /dev/null +++ b/include/media/v4l2-config_rockchip.h @@ -0,0 +1,95 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _V4L2_CONFIG_ROCKCHIP_H +#define _V4L2_CONFIG_ROCKCHIP_H + +#define CAMERA_STRLEN 32 +#define CAMERA_METADATA_LEN (2 * PAGE_SIZE) + +/* Sensor resolution specific data for AE calculation.*/ +struct isp_supplemental_sensor_mode_data { + unsigned int coarse_integration_time_min; + unsigned int coarse_integration_time_max_margin; + unsigned int fine_integration_time_min; + unsigned int fine_integration_time_max_margin; + unsigned int frame_length_lines; + unsigned int line_length_pck; + unsigned int vt_pix_clk_freq_hz; + unsigned int crop_horizontal_start; /* Sensor crop start cord. (x0,y0)*/ + unsigned int crop_vertical_start; + unsigned int crop_horizontal_end; /* Sensor crop end cord. (x1,y1)*/ + unsigned int crop_vertical_end; + unsigned int sensor_output_width; /* input size to ISP */ + unsigned int sensor_output_height; + unsigned int isp_input_horizontal_start; /* cif isp input */ + unsigned int isp_input_vertical_start; + unsigned int isp_input_width; + unsigned int isp_input_height; + unsigned int isp_output_width; /* cif isp output */ + unsigned int isp_output_height; + unsigned char binning_factor_x; /* horizontal binning factor used */ + unsigned char binning_factor_y; /* vertical binning factor used */ + unsigned char exposure_valid_frame; + int exp_time; + unsigned short gain; +}; + +struct camera_module_info_s { + char sensor_name[CAMERA_STRLEN]; + char module_name[CAMERA_STRLEN]; + char len_name[CAMERA_STRLEN]; + char fov_h[CAMERA_STRLEN]; + char fov_v[CAMERA_STRLEN]; + char focal_length[CAMERA_STRLEN]; + char focus_distance[CAMERA_STRLEN]; + int facing; + int orientation; + bool iq_mirror; + bool iq_flip; + int flash_support; + int flash_exp_percent; +}; + +struct flash_timeinfo_s { + struct timeval preflash_start_t; + struct timeval preflash_end_t; + struct timeval mainflash_start_t; + struct timeval mainflash_end_t; + int flash_turn_on_time; + int flash_on_timeout; +}; + +struct frame_timeinfo_s { + struct timeval vs_t; + struct timeval fi_t; +}; + +struct sensor_metadata_s { + unsigned int exp_time; + unsigned int gain; +}; + +struct v4l2_buffer_metadata_s { + unsigned int frame_id; + struct frame_timeinfo_s frame_t; + struct flash_timeinfo_s flash_t; + struct sensor_metadata_s sensor; + unsigned char isp[CAMERA_METADATA_LEN - 512]; +}; + +#endif + diff --git a/include/media/v4l2-controls_rockchip.h b/include/media/v4l2-controls_rockchip.h new file mode 100644 index 000000000000..a30d1569d7bd --- /dev/null +++ b/include/media/v4l2-controls_rockchip.h @@ -0,0 +1,32 @@ +/* + ************************************************************************* + * Rockchip driver for CIF ISP 1.0 + * (Based on Intel driver for sofiaxxx) + * + * Copyright (C) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + ************************************************************************* + */ + +#ifndef _V4L2_CONTROLS_ROCKCHIP_H +#define _V4L2_CONTROLS_ROCKCHIP_H + +#include +#include + +#define RK_VIDIOC_CAMERA_MODULEINFO \ + _IOWR('v', BASE_VIDIOC_PRIVATE + 10, struct camera_module_info_s) +#define RK_VIDIOC_SENSOR_MODE_DATA \ + _IOR('v', BASE_VIDIOC_PRIVATE, struct isp_supplemental_sensor_mode_data) + +#define V4L2_CID_USER_RK_BASE (V4L2_CID_USER_BASE + 0x1080) +#define RK_V4L2_CID_VBLANKING (V4L2_CID_USER_RK_BASE + 1) +#define RK_V4L2_CID_GAIN_PERCENT (V4L2_CID_USER_RK_BASE + 2) +#define RK_V4L2_CID_AUTO_FPS (V4L2_CID_USER_RK_BASE + 3) +#endif -- 2.34.1