From 9866a4e0f6858fd01b95cfd355129b7cf40a661f Mon Sep 17 00:00:00 2001 From: Tao Jing Date: Thu, 17 Nov 2011 22:16:23 +0800 Subject: [PATCH] atomisp: adding atomisp driver from r2 branch uploaded origin driver: 78646f18af816f8aee68cb6acb1003bffc8fdf8d This fit for 0930 CSS FW Change-Id: I8a7095375eca284edf78771d363723e879822d76 Signed-off-by: Tao Jing Reviewed-on: http://android.intel.com:8080/24500 Reviewed-by: Gross, Mark Tested-by: Gross, Mark Reviewed-on: http://android.intel.com:8080/24687 --- drivers/media/video/atomisp/Kconfig | 19 + drivers/media/video/atomisp/Makefile | 46 + drivers/media/video/atomisp/atomisp_cmd.c | 3774 ++++++++++++++++ drivers/media/video/atomisp/atomisp_cmd.h | 278 ++ drivers/media/video/atomisp/atomisp_common.h | 183 + drivers/media/video/atomisp/atomisp_csi2.c | 423 ++ drivers/media/video/atomisp/atomisp_csi2.h | 54 + drivers/media/video/atomisp/atomisp_file.c | 365 ++ drivers/media/video/atomisp/atomisp_file.h | 44 + drivers/media/video/atomisp/atomisp_fops.c | 716 +++ drivers/media/video/atomisp/atomisp_fops.h | 58 + drivers/media/video/atomisp/atomisp_ioctl.c | 1689 +++++++ drivers/media/video/atomisp/atomisp_ioctl.h | 46 + drivers/media/video/atomisp/atomisp_subdev.c | 685 +++ drivers/media/video/atomisp/atomisp_subdev.h | 81 + drivers/media/video/atomisp/atomisp_tpg.c | 281 ++ drivers/media/video/atomisp/atomisp_tpg.h | 44 + drivers/media/video/atomisp/atomisp_v4l2.c | 957 ++++ drivers/media/video/atomisp/css/hrt/bits.h | 113 + drivers/media/video/atomisp/css/hrt/cell_params.h | 51 + .../video/atomisp/css/hrt/css_receiver_ahb_defs.h | 216 + drivers/media/video/atomisp/css/hrt/defs.h | 45 + drivers/media/video/atomisp/css/hrt/dma_v1_defs.h | 245 + drivers/media/video/atomisp/css/hrt/embed.h | 38 + drivers/media/video/atomisp/css/hrt/gdc_defs.h | 111 + drivers/media/video/atomisp/css/hrt/gp_regs_defs.h | 30 + .../video/atomisp/css/hrt/hive_isp_css_defs.h | 197 + .../atomisp/css/hrt/hive_isp_css_host_ids_hrt.h | 67 + .../video/atomisp/css/hrt/hive_isp_css_if_hrt.h | 43 + .../atomisp/css/hrt/hive_isp_css_irq_types_hrt.h | 79 + .../video/atomisp/css/hrt/hive_isp_css_mm_hrt.h | 69 + .../hive_isp_css_streaming_monitors_types_hrt.h | 72 + .../hrt/hive_isp_css_streaming_to_mipi_types_hrt.h | 37 + drivers/media/video/atomisp/css/hrt/if_defs.h | 73 + .../video/atomisp/css/hrt/irq_controller_defs.h | 36 + .../atomisp/css/hrt/isp2300_medfield_params.h | 178 + drivers/media/video/atomisp/css/hrt/master_port.h | 149 + drivers/media/video/atomisp/css/hrt/mmu_defs.h | 32 + .../atomisp/css/hrt/scalar_processor_params.h | 29 + drivers/media/video/atomisp/css/hrt/sp.map.h | 355 ++ drivers/media/video/atomisp/css/hrt/sp_hrt.h | 32 + .../video/atomisp/css/hrt/streaming_to_mipi_defs.h | 37 + drivers/media/video/atomisp/css/sh_css.c | 4699 ++++++++++++++++++++ drivers/media/video/atomisp/css/sh_css.h | 540 +++ .../media/video/atomisp/css/sh_css_accelerate.c | 245 + .../media/video/atomisp/css/sh_css_accelerate.h | 76 + drivers/media/video/atomisp/css/sh_css_binary.c | 584 +++ drivers/media/video/atomisp/css/sh_css_binary.h | 189 + .../media/video/atomisp/css/sh_css_binary_info.h | 741 +++ drivers/media/video/atomisp/css/sh_css_debug.c | 676 +++ drivers/media/video/atomisp/css/sh_css_debug.h | 42 + drivers/media/video/atomisp/css/sh_css_defs.h | 330 ++ drivers/media/video/atomisp/css/sh_css_firmware.c | 115 + drivers/media/video/atomisp/css/sh_css_firmware.h | 63 + drivers/media/video/atomisp/css/sh_css_hrt.c | 1922 ++++++++ drivers/media/video/atomisp/css/sh_css_hrt.h | 394 ++ drivers/media/video/atomisp/css/sh_css_hw.h | 139 + drivers/media/video/atomisp/css/sh_css_internal.h | 290 ++ drivers/media/video/atomisp/css/sh_css_metrics.c | 179 + drivers/media/video/atomisp/css/sh_css_metrics.h | 60 + drivers/media/video/atomisp/css/sh_css_params.c | 2119 +++++++++ drivers/media/video/atomisp/css/sh_css_params.h | 174 + drivers/media/video/atomisp/css/sh_css_rx.c | 388 ++ drivers/media/video/atomisp/css/sh_css_rx.h | 53 + drivers/media/video/atomisp/css/sh_css_sp.c | 584 +++ drivers/media/video/atomisp/css/sh_css_sp.h | 127 + drivers/media/video/atomisp/css/sh_css_sp_start.c | 129 + drivers/media/video/atomisp/css/sh_css_sp_start.h | 87 + drivers/media/video/atomisp/css/sh_css_types.h | 778 ++++ drivers/media/video/atomisp/hmm/hmm.c | 388 ++ drivers/media/video/atomisp/hmm/hmm_bo.c | 1077 +++++ drivers/media/video/atomisp/hmm/hmm_bo_dev.c | 279 ++ drivers/media/video/atomisp/hmm/hmm_vm.c | 210 + .../atomisp/hrt/hive_isp_css_custom_host_hrt.h | 102 + .../media/video/atomisp/hrt/hive_isp_css_mm_hrt.c | 179 + .../atomisp/include/atomisp/atomisp_internal.h | 284 ++ .../video/atomisp/include/atomisp/atomisp_tables.h | 265 ++ .../video/atomisp/include/atomisp/atomisp_v4l2.h | 58 + drivers/media/video/atomisp/include/hmm/hmm.h | 74 + drivers/media/video/atomisp/include/hmm/hmm_bo.h | 291 ++ .../media/video/atomisp/include/hmm/hmm_bo_dev.h | 112 + .../media/video/atomisp/include/hmm/hmm_common.h | 67 + drivers/media/video/atomisp/include/hmm/hmm_vm.h | 67 + drivers/media/video/atomisp/include/mmu/isp_mmu.h | 168 + drivers/media/video/atomisp/include/mmu/sh_mmu.h | 74 + drivers/media/video/atomisp/mmu/isp_mmu.c | 512 +++ 86 files changed, 32007 insertions(+) create mode 100644 drivers/media/video/atomisp/Kconfig create mode 100644 drivers/media/video/atomisp/Makefile create mode 100644 drivers/media/video/atomisp/atomisp_cmd.c create mode 100644 drivers/media/video/atomisp/atomisp_cmd.h create mode 100644 drivers/media/video/atomisp/atomisp_common.h create mode 100644 drivers/media/video/atomisp/atomisp_csi2.c create mode 100644 drivers/media/video/atomisp/atomisp_csi2.h create mode 100644 drivers/media/video/atomisp/atomisp_file.c create mode 100644 drivers/media/video/atomisp/atomisp_file.h create mode 100644 drivers/media/video/atomisp/atomisp_fops.c create mode 100644 drivers/media/video/atomisp/atomisp_fops.h create mode 100644 drivers/media/video/atomisp/atomisp_ioctl.c create mode 100644 drivers/media/video/atomisp/atomisp_ioctl.h create mode 100644 drivers/media/video/atomisp/atomisp_subdev.c create mode 100644 drivers/media/video/atomisp/atomisp_subdev.h create mode 100644 drivers/media/video/atomisp/atomisp_tpg.c create mode 100644 drivers/media/video/atomisp/atomisp_tpg.h create mode 100644 drivers/media/video/atomisp/atomisp_v4l2.c create mode 100644 drivers/media/video/atomisp/css/hrt/bits.h create mode 100644 drivers/media/video/atomisp/css/hrt/cell_params.h create mode 100644 drivers/media/video/atomisp/css/hrt/css_receiver_ahb_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/dma_v1_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/embed.h create mode 100644 drivers/media/video/atomisp/css/hrt/gdc_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/gp_regs_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/hive_isp_css_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/hive_isp_css_host_ids_hrt.h create mode 100644 drivers/media/video/atomisp/css/hrt/hive_isp_css_if_hrt.h create mode 100644 drivers/media/video/atomisp/css/hrt/hive_isp_css_irq_types_hrt.h create mode 100644 drivers/media/video/atomisp/css/hrt/hive_isp_css_mm_hrt.h create mode 100644 drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_monitors_types_hrt.h create mode 100644 drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_to_mipi_types_hrt.h create mode 100644 drivers/media/video/atomisp/css/hrt/if_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/irq_controller_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/isp2300_medfield_params.h create mode 100644 drivers/media/video/atomisp/css/hrt/master_port.h create mode 100644 drivers/media/video/atomisp/css/hrt/mmu_defs.h create mode 100644 drivers/media/video/atomisp/css/hrt/scalar_processor_params.h create mode 100644 drivers/media/video/atomisp/css/hrt/sp.map.h create mode 100644 drivers/media/video/atomisp/css/hrt/sp_hrt.h create mode 100644 drivers/media/video/atomisp/css/hrt/streaming_to_mipi_defs.h create mode 100644 drivers/media/video/atomisp/css/sh_css.c create mode 100644 drivers/media/video/atomisp/css/sh_css.h create mode 100644 drivers/media/video/atomisp/css/sh_css_accelerate.c create mode 100644 drivers/media/video/atomisp/css/sh_css_accelerate.h create mode 100644 drivers/media/video/atomisp/css/sh_css_binary.c create mode 100644 drivers/media/video/atomisp/css/sh_css_binary.h create mode 100644 drivers/media/video/atomisp/css/sh_css_binary_info.h create mode 100644 drivers/media/video/atomisp/css/sh_css_debug.c create mode 100644 drivers/media/video/atomisp/css/sh_css_debug.h create mode 100644 drivers/media/video/atomisp/css/sh_css_defs.h create mode 100644 drivers/media/video/atomisp/css/sh_css_firmware.c create mode 100644 drivers/media/video/atomisp/css/sh_css_firmware.h create mode 100644 drivers/media/video/atomisp/css/sh_css_hrt.c create mode 100644 drivers/media/video/atomisp/css/sh_css_hrt.h create mode 100644 drivers/media/video/atomisp/css/sh_css_hw.h create mode 100644 drivers/media/video/atomisp/css/sh_css_internal.h create mode 100644 drivers/media/video/atomisp/css/sh_css_metrics.c create mode 100644 drivers/media/video/atomisp/css/sh_css_metrics.h create mode 100644 drivers/media/video/atomisp/css/sh_css_params.c create mode 100644 drivers/media/video/atomisp/css/sh_css_params.h create mode 100644 drivers/media/video/atomisp/css/sh_css_rx.c create mode 100644 drivers/media/video/atomisp/css/sh_css_rx.h create mode 100644 drivers/media/video/atomisp/css/sh_css_sp.c create mode 100644 drivers/media/video/atomisp/css/sh_css_sp.h create mode 100644 drivers/media/video/atomisp/css/sh_css_sp_start.c create mode 100644 drivers/media/video/atomisp/css/sh_css_sp_start.h create mode 100644 drivers/media/video/atomisp/css/sh_css_types.h create mode 100644 drivers/media/video/atomisp/hmm/hmm.c create mode 100644 drivers/media/video/atomisp/hmm/hmm_bo.c create mode 100644 drivers/media/video/atomisp/hmm/hmm_bo_dev.c create mode 100644 drivers/media/video/atomisp/hmm/hmm_vm.c create mode 100644 drivers/media/video/atomisp/hrt/hive_isp_css_custom_host_hrt.h create mode 100644 drivers/media/video/atomisp/hrt/hive_isp_css_mm_hrt.c create mode 100644 drivers/media/video/atomisp/include/atomisp/atomisp_internal.h create mode 100644 drivers/media/video/atomisp/include/atomisp/atomisp_tables.h create mode 100644 drivers/media/video/atomisp/include/atomisp/atomisp_v4l2.h create mode 100644 drivers/media/video/atomisp/include/hmm/hmm.h create mode 100644 drivers/media/video/atomisp/include/hmm/hmm_bo.h create mode 100644 drivers/media/video/atomisp/include/hmm/hmm_bo_dev.h create mode 100644 drivers/media/video/atomisp/include/hmm/hmm_common.h create mode 100644 drivers/media/video/atomisp/include/hmm/hmm_vm.h create mode 100644 drivers/media/video/atomisp/include/mmu/isp_mmu.h create mode 100644 drivers/media/video/atomisp/include/mmu/sh_mmu.h create mode 100644 drivers/media/video/atomisp/mmu/isp_mmu.c diff --git a/drivers/media/video/atomisp/Kconfig b/drivers/media/video/atomisp/Kconfig new file mode 100644 index 0000000..0af43bf --- /dev/null +++ b/drivers/media/video/atomisp/Kconfig @@ -0,0 +1,19 @@ +config VIDEO_ATOMISP + tristate "Medfield Penwell Image Signal Processor Driver" + depends on VIDEO_V4L2 + select VIDEOBUF_VMALLOC + select VIDEO_OV2720 + select VIDEO_DIS71430M + select VIDEO_AS3645A + select VIDEO_LM3554 + select VIDEO_MT9E013 + select VIDEO_MT9M114 + + default m + + ---help--- + Say Y here if your platform support camera imaging subsystem on + the intel Medifield platform. + + To compile this driver as a module, choose M here: the + module will be called atomisp. diff --git a/drivers/media/video/atomisp/Makefile b/drivers/media/video/atomisp/Makefile new file mode 100644 index 0000000..cd276ba --- /dev/null +++ b/drivers/media/video/atomisp/Makefile @@ -0,0 +1,46 @@ +atomisp-objs := \ + css/sh_css.o \ + css/sh_css_binary.o \ + css/sh_css_debug.o \ + css/sh_css_hrt.o \ + css/sh_css_params.o \ + css/sh_css_sp.o \ + css/sh_css_rx.o \ + css/sh_css_sp_start.o \ + css/sh_css_metrics.o \ + css/sh_css_firmware.o \ + css/sh_css_accelerate.o \ + mmu/isp_mmu.o \ + hmm/hmm.o \ + hmm/hmm_bo.o \ + hmm/hmm_bo_dev.o \ + hmm/hmm_vm.o \ + hrt/hive_isp_css_mm_hrt.o \ + atomisp_ioctl.o \ + atomisp_cmd.o \ + atomisp_fops.o \ + atomisp_subdev.o \ + atomisp_csi2.o \ + atomisp_tpg.o \ + atomisp_file.o \ + atomisp_v4l2.o + +obj-$(CONFIG_VIDEO_ATOMISP) = atomisp.o + +INC := $(src)/include +INCLUDES := -I$(INC) \ + -I$(INC)/atomisp \ + -I$(src) \ + -I$(src)/hrt \ + -I$(src)/css \ + -I$(src)/css/hrt \ + -I$(src)/../../../staging/mrst/bc_video + +DEFINES := -DHRT_HW -DHRT_ISP_CSS_CUSTOM_HOST -DHRT_USE_VIR_ADDRS -DHRT_KERNEL +DEFINES += -DUSE_DYNAMIC_BIN +DEFINES += -DISP_POWER_GATING +DEFINES += -DUSE_INTERRUPTS +DEFINES += -DUSE_SSSE3 +DEFINES += -DPUNIT_CAMERA_BUSY + +EXTRA_CFLAGS := $(INCLUDES) $(DEFINES) -fno-common diff --git a/drivers/media/video/atomisp/atomisp_cmd.c b/drivers/media/video/atomisp/atomisp_cmd.c new file mode 100644 index 0000000..6b10bb5 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_cmd.c @@ -0,0 +1,3774 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#include "atomisp_tables.h" +#include "atomisp_ioctl.h" +#include "atomisp_cmd.h" +#include "atomisp_fops.h" +#include "hrt/css_receiver_ahb_defs.h" +#include "css/sh_css_debug.h" +#include "css/sh_css_hrt.h" +#include "css/sh_css_binary_info.h" +#include "css/sh_css_accelerate.h" +#include "hrt/bits.h" +#include "linux/intel_mid_pm.h" +#include + +/* We should never need to run the flash for more than 2 frames. + * At 15fps this means 133ms. We set the timeout a bit longer. + * Each flash driver is supposed to set its own timeout, but + * just in case someone else changed the timeout, we set it + * here to make sure we don't damage the flash hardware. */ +#define FLASH_TIMEOUT 800 /* ms */ + +union host { + struct { + void *kernel_ptr; + void __user *user_ptr; + int size; + } scalar; + struct { + void *hmm_ptr; + } ptr; +}; + +static void +atomisp_acc_fw_free_args(struct atomisp_device *isp, struct sh_css_acc_fw *fw); +static void +atomisp_acc_fw_free(struct atomisp_device *isp, struct sh_css_acc_fw *fw); + +/* + * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field. + * subdev->priv is set in mrst.c + */ +struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd) +{ + return (struct camera_mipi_info *)v4l2_get_subdev_hostdata(sd); +} + +/* + * get struct atomisp_video_pipe from v4l2 video_device + */ +struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev) +{ + return (struct atomisp_video_pipe *) + container_of(dev, struct atomisp_video_pipe, vdev); +} + +/* + * interrupt enable/disable functions + */ +static void enable_isp_irq(enum hrt_isp_css_irq irq, bool enable) +{ + if (enable) { + sh_css_hrt_irq_enable(irq, true, false); + switch (irq) { /*We only have sp interrupt right now*/ + case hrt_isp_css_irq_sp: + sh_css_hrt_irq_enable_sp(true); + break; + default: + break; + } + + } else { + sh_css_hrt_irq_disable(irq); + switch (irq) { + case hrt_isp_css_irq_sp: + sh_css_hrt_irq_enable_sp(false); + break; + default: + break; + } + } + +} + +/* + * interrupt clean function + */ +static void clear_isp_irq(enum hrt_isp_css_irq irq) +{ + switch (irq) { + case hrt_isp_css_irq_sp: + sh_css_hrt_irq_clear_sp(); + default: + break; + } +} + +void atomisp_msi_irq_init(struct atomisp_device *isp, struct pci_dev *dev) +{ + u32 msg_ret; + u32 msi_address; + u16 msi_data; + + pci_read_config_dword(dev, PCI_MSI_ADDR, &msi_address); + pci_read_config_word(dev, PCI_MSI_DATA, &msi_data); + msi_data = msi_data & 0xffff; + + atomisp_msg_write32(isp, IUNIT_PORT, MSI_ADDRESS, msi_address); + + msg_ret = atomisp_msg_read32(isp, IUNIT_PORT, MSI_CAPID); + msg_ret |= 1 << MSI_ENABLE_BIT; + atomisp_msg_write32(isp, IUNIT_PORT, MSI_CAPID, msg_ret); + + msg_ret = (1 << INTR_IER) | (1 << INTR_IIR); + atomisp_msg_write32(isp, IUNIT_PORT, INTR_CTL, msg_ret); + + msg_ret = atomisp_msg_read32(isp, IUNIT_PORT, PCICMDSTS); + msg_ret |= (1 << MEMORY_SPACE_ENABLE | + 1 << BUS_MASTER_ENABLE | + 1 << INTR_DISABLE_BIT); + atomisp_msg_write32(isp, IUNIT_PORT, PCICMDSTS, msg_ret); + + atomisp_msg_write32(isp, IUNIT_PORT, MSI_DATA, msi_data); +} + +void atomisp_msi_irq_uninit(struct atomisp_device *isp, struct pci_dev *dev) +{ + u32 msg_ret; + + msg_ret = atomisp_msg_read32(isp, IUNIT_PORT, MSI_CAPID); + msg_ret &= ~(1 << MSI_ENABLE_BIT); + atomisp_msg_write32(isp, IUNIT_PORT, MSI_CAPID, msg_ret); + + msg_ret = 0x0; + atomisp_msg_write32(isp, IUNIT_PORT, INTR_CTL, msg_ret); + + msg_ret = atomisp_msg_read32(isp, IUNIT_PORT, PCICMDSTS); + msg_ret &= ~(1 << INTR_DISABLE_BIT | + 1 << BUS_MASTER_ENABLE); + atomisp_msg_write32(isp, IUNIT_PORT, PCICMDSTS, msg_ret); +} + +static void print_csi_rx_errors(void) +{ + u32 infos = 0; + sh_css_rx_get_interrupt_info(&infos); + + v4l2_info(&atomisp_dev, "CSI Receiver errors:\n"); + if (infos & SH_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) + v4l2_err(&atomisp_dev, " buffer overrun"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_SOT) + v4l2_err(&atomisp_dev, + " start-of-transmission error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_SOT_SYNC) + v4l2_err(&atomisp_dev, + " start-of-transmission sync error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_CONTROL) + v4l2_err(&atomisp_dev, " control error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) + v4l2_err(&atomisp_dev, " 2 or more ECC errors"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_CRC) + v4l2_err(&atomisp_dev, " CRC mismatch"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) + v4l2_err(&atomisp_dev, " unknown error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) + v4l2_err(&atomisp_dev, " frame sync error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_FRAME_DATA) + v4l2_err(&atomisp_dev, " frame data error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) + v4l2_err(&atomisp_dev, " data timeout"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) + v4l2_err(&atomisp_dev, + " unknown escape command entry"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_LINE_SYNC) + v4l2_err(&atomisp_dev, " line sync error"); +} + +/* interrupt handling function*/ +irqreturn_t atomisp_isr(int irq, void *dev) +{ + u32 msg_ret; + struct atomisp_device *isp = (struct atomisp_device *)dev; + enum sh_css_err err; + unsigned int irq_infos = 0; + bool signal_worker = false; + bool signal_statistics = false; + bool signal_acceleration = false; + + spin_lock(&isp->irq_lock); + /*got triggered interrupt*/ + err = sh_css_translate_interrupt(&irq_infos); + if (err != sh_css_success) { + v4l2_warn(&atomisp_dev, "%s:failed to translate irq (err = %d," + " infos = %d)\n", __func__, err, irq_infos); + spin_unlock(&isp->irq_lock); + return IRQ_NONE; + } + + isp->irq_infos = irq_infos; + if (irq_infos & SH_CSS_IRQ_INFO_FRAME_DONE || + irq_infos & SH_CSS_IRQ_INFO_START_NEXT_STAGE) { + /* Wake up sleep thread for next binary */ + signal_worker = true; + if (irq_infos & SH_CSS_IRQ_INFO_STATISTICS_READY) { + signal_statistics = true; + isp->isp3a_stat_ready = true; + } + if (irq_infos & SH_CSS_IRQ_INFO_FW_ACC_DONE) { + signal_acceleration = true; + } + } else if (irq_infos & SH_CSS_IRQ_INFO_CSS_RECEIVER_ERROR) { + /* handle mipi receiver error*/ + u32 rx_infos; + print_csi_rx_errors(); + sh_css_rx_get_interrupt_info(&rx_infos); + sh_css_rx_clear_interrupt_info(rx_infos); + if (rx_infos & SH_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) { + signal_worker = true; + signal_statistics = true; + signal_acceleration = true; + } + } + + /* + * After every iteration of acceleration there will be an interrupt + * which needs priority. + */ + if (signal_acceleration) + /* wake up acceleration api */ + complete(&isp->acc_fw_complete); + + if (signal_worker) + /*make work queue run*/ + complete(&isp->wq_frame_complete); + if (signal_statistics) + /*make work queue run*/ + complete(&isp->dis_state_complete); + + /* Clear irq reg at PENWELL B0 */ + msg_ret = atomisp_msg_read32(isp, IUNIT_PORT, INTR_CTL); + msg_ret |= (1 << INTR_IIR); + atomisp_msg_write32(isp, IUNIT_PORT, INTR_CTL, msg_ret); + + spin_unlock(&isp->irq_lock); + return IRQ_HANDLED; +} +/* + * dequeue a buffer from video buffer list + * if no buffer queued, wait for queue_buf is called + * will return 1 when streaming off. + */ +static int atomisp_buf_pre_dequeue(struct atomisp_video_pipe *pipe, + struct videobuf_buffer **vb) +{ + unsigned long flags; + struct atomisp_device *isp = pipe->isp; + + spin_lock_irqsave(&pipe->irq_lock, flags); + if (list_empty(&pipe->activeq)) { + spin_unlock_irqrestore(&pipe->irq_lock, flags); + if (wait_event_interruptible(pipe->capq.wait, + (!list_empty(&pipe->activeq) && + !isp->sw_contex.updating_uptr) || + !isp->sw_contex.isp_streaming)) + return -EINVAL; + + spin_lock_irqsave(&pipe->irq_lock, flags); + if (list_empty(&pipe->activeq)) { + spin_unlock_irqrestore(&pipe->irq_lock, flags); + return -EINVAL; + } + } + + if (!isp->sw_contex.isp_streaming) { + spin_unlock_irqrestore(&pipe->irq_lock, flags); + return 1; + } + + /*retrieve video buffer from activeq, keep video buffer on capq*/ + *vb = list_entry(pipe->activeq.next, struct videobuf_buffer, queue); + list_del(&(*vb)->queue); + (*vb)->state = VIDEOBUF_ACTIVE; + spin_unlock_irqrestore(&pipe->irq_lock, flags); + return 0; +} + +/* set the bit range [lsb, lsb+num_bits] of in_val to new_val + * and return the result. + */ +static uint32_t u32_set_bits(uint32_t in_val, unsigned int lsb, + unsigned int num_bits, uint32_t new_val) +{ + unsigned int bit_mask; + /* avoid overflow in calculating the bit masks */ + if (num_bits > 32) + return in_val; + if (num_bits == 32) + return new_val; + /* calculate number of 1 bits in mask */ + bit_mask = (1<<(num_bits+1)) - 1; + /* make sure new_val doesn't contain more than num_bits */ + new_val &= bit_mask; + /* shift bits into the target place */ + bit_mask <<= lsb; + /* clear old bits */ + in_val &= ~bit_mask; + /* assign new_val to the output position */ + in_val |= new_val << lsb; + return in_val; +} + +/* The term_en_count is set via 2 registers, one for the 4lane port and one + for the 1lane port. */ +#define TERM_EN_COUNT_1LANE_START_BIT 16 +#define PNW_B0_TERM_EN_COUNT_4LANE_START_BIT 20 +#define PNW_B0_TERM_EN_COUNT_NUM_BITS 4 +#define TERM_EN_COUNT_4LANE_START_BIT 24 +#define TERM_EN_COUNT_NUM_BITS 7 + +static void set_term_en_count(struct atomisp_device *isp, int b0) +{ + uint32_t val; + unsigned int lane1_start_bit, + lane4_start_bit, + num_bits; + + lane1_start_bit = TERM_EN_COUNT_1LANE_START_BIT; + if (b0) { + lane4_start_bit = PNW_B0_TERM_EN_COUNT_4LANE_START_BIT; + num_bits = PNW_B0_TERM_EN_COUNT_NUM_BITS; + } else { + lane4_start_bit = TERM_EN_COUNT_4LANE_START_BIT; + num_bits = TERM_EN_COUNT_NUM_BITS; + } + + val = atomisp_msg_read32(isp, IUNITPHY_PORT, CSI_CONTROL); + /* 1 lane CSI port */ + val = u32_set_bits(val, lane1_start_bit, num_bits, 0xF); + /* 4 lane CSI port */ + val = u32_set_bits(val, lane4_start_bit, num_bits, 0xF); + atomisp_msg_write32(isp, IUNITPHY_PORT, CSI_CONTROL, val); +} + +static int atomisp_buffer_dequeue(struct atomisp_device *isp, + struct videobuf_buffer **vb_capture, + struct videobuf_buffer **vb_preview) +{ + struct videobuf_vmalloc_memory *vmem; + struct atomisp_video_pipe *vf_pipe = NULL; + struct atomisp_video_pipe *mo_pipe = NULL; + int ret; + + if (!(*vb_capture)) { + mo_pipe = &isp->isp_subdev.video_out_mo; + ret = atomisp_buf_pre_dequeue(mo_pipe, vb_capture); + if (ret) + return -EINVAL; + + vmem = (*vb_capture)->priv; + if (vmem->vmalloc == NULL) + return -EINVAL; + + /*frame structure is stored in videobuf->priv->vmalloc*/ + isp->regular_output_frame = vmem->vmalloc; + } + + if (atomisp_is_viewfinder_support(isp) && !(*vb_preview)) { + vf_pipe = &isp->isp_subdev.video_out_vf; + ret = atomisp_buf_pre_dequeue(vf_pipe, vb_preview); + if (ret) + return -EINVAL; + + vmem = (*vb_preview)->priv; + isp->vf_frame = vmem->vmalloc; + } + return 0; +} + +static int atomisp_start_binary(struct atomisp_device *isp) +{ + int ret; + + /*Start the isp binary*/ + switch (isp->sw_contex.run_mode) { + case CI_MODE_STILL_CAPTURE: + ret = sh_css_capture_start(isp->raw_output_frame, + isp->regular_output_frame, + isp->vf_frame); + if (sh_css_success != ret) { + v4l2_err(&atomisp_dev, + "start capture error!\n"); + + return -EINVAL; + } + break; + case CI_MODE_PREVIEW: + sh_css_preview_start(NULL, isp->regular_output_frame); + break; + case CI_MODE_VIDEO: + if (isp->params.video_dis_en) { + sh_css_video_set_dis_vector(isp->params.dis_x, + isp->params.dis_y); + } + sh_css_video_start(NULL, isp->regular_output_frame, + isp->vf_frame); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int atomisp_streamon_input(struct atomisp_device *isp) +{ + int is_b0, ret; + + if (isp->sw_contex.file_input) { + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, s_stream, 1); + return ret; + } + + if (isp->sw_contex.sensor_streaming == false) { + is_b0 = (isp->pdev->revision == 6) ? 0 : 1; + set_term_en_count(isp, is_b0); + /* + * stream on the sensor, power on is called before + * work queue start + */ + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, s_stream, 1); + if (ret) + return -EINVAL; + + isp->sw_contex.sensor_streaming = true; + } + return 0; +} + +static void atomisp_pipe_reset(struct atomisp_device *isp) +{ + v4l2_warn(&atomisp_dev, "ISP timeout. Recovering\n"); + + /* clear irq */ + enable_isp_irq(hrt_isp_css_irq_sp, false); + clear_isp_irq(hrt_isp_css_irq_sp); + /* stream off sensor */ + if (!isp->sw_contex.file_input) { + v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, s_stream, 0); + isp->sw_contex.sensor_streaming = false; + } + /* power cycle ISP */ + sh_css_suspend(); + pm_runtime_put_sync(isp->dev); + pm_runtime_get_sync(isp->dev); + sh_css_resume(); +} + +static int atomisp_timeout_handler(struct atomisp_device *isp, int cnt) +{ + u32 rx_infos; + + v4l2_err(&atomisp_dev, "ISP timeout\n"); + + /* Try 5 times for autorecovery */ + if (cnt < 5) { + atomisp_pipe_reset(isp); + return 0; + } + + /* Can't recover from isp timeout, error will be reported*/ + if (!sh_css_hrt_sp_is_idle()) + v4l2_err(&atomisp_dev, + "error: SP is not idle\n"); + else + v4l2_err(&atomisp_dev, + "error: lost interrupt\n"); + + sh_css_dump_debug_info(); + print_csi_rx_errors(); + sh_css_rx_get_interrupt_info(&rx_infos); + sh_css_rx_clear_interrupt_info(rx_infos); + return -ETIMEDOUT; +} + +static bool atomisp_flash_error(struct atomisp_device *isp) +{ + struct v4l2_control ctrl; + + ctrl.id = V4L2_CID_FLASH_STATUS; + if (v4l2_subdev_call(isp->flash, core, g_ctrl, &ctrl)) + return true; + if (ctrl.value != ATOMISP_FLASH_STATUS_OK) + v4l2_err(&atomisp_dev, "flash failed (%d)\n", ctrl.value); + return ctrl.value != ATOMISP_FLASH_STATUS_OK; +} + +static int atomisp_stop_flash(struct atomisp_device *isp) +{ + struct v4l2_control ctrl; + + ctrl.id = V4L2_CID_FLASH_STROBE; + ctrl.value = 0; + if (v4l2_subdev_call(isp->flash, core, s_ctrl, &ctrl)) { + v4l2_err(&atomisp_dev, "flash failed\n"); + return -EINVAL; + } + return 0; +} + +static int atomisp_start_flash(struct atomisp_device *isp) +{ + struct v4l2_control ctrl; + + /* switch flash into flash mode */ + ctrl.id = V4L2_CID_FLASH_MODE; + ctrl.value = ATOMISP_FLASH_MODE_FLASH; + + if (v4l2_subdev_call(isp->flash, core, s_ctrl, &ctrl)) { + v4l2_err(&atomisp_dev, "flash failed\n"); + return -EINVAL; + } + + /* make sure the timeout is set */ + ctrl.id = V4L2_CID_FLASH_TIMEOUT; + ctrl.value = FLASH_TIMEOUT; + + if (v4l2_subdev_call(isp->flash, core, s_ctrl, &ctrl)) { + v4l2_err(&atomisp_dev, "flash failed\n"); + return -EINVAL; + } + + /* trigger the flash */ + ctrl.id = V4L2_CID_FLASH_STROBE; + ctrl.value = 1; + /* for now we treat it as on/off */ + if (v4l2_subdev_call(isp->flash, core, s_ctrl, &ctrl)) { + v4l2_err(&atomisp_dev, "flash failed\n"); + return -EINVAL; + } + return 0; +} + +void atomisp_work(struct work_struct *work) +{ + struct atomisp_device *isp = container_of(work, struct atomisp_device, + work); + struct videobuf_buffer *vb_preview = NULL; + struct videobuf_buffer *vb_capture = NULL; + int ret, timeout_cnt = 0; + bool timeout_flag, + flash_in_progress = false, + flash_enabled = false; + enum atomisp_frame_status fr_status = ATOMISP_FRAME_STATUS_OK; + + isp->sw_contex.error = false; + for (;;) { + timeout_flag = false; + ret = atomisp_buffer_dequeue(isp, &vb_capture, + &vb_preview); + if (ret) + goto error; + + INIT_COMPLETION(isp->wq_frame_complete); + /* Hold the locker when ISP is running, when dis and digital + * zoom can not be configured + */ + mutex_lock(&isp->isp_lock); + + ret = atomisp_start_binary(isp); + if (ret) { + mutex_unlock(&isp->isp_lock); + goto error; + } + + ret = atomisp_streamon_input(isp); + if (ret) { + mutex_unlock(&isp->isp_lock); + v4l2_err(&atomisp_dev, + "stream on input error.\n"); + goto error; + } + + /* if the previous frame was partially exposed, this one is + * going to be fully exposed. */ + if (flash_in_progress && + fr_status == ATOMISP_FRAME_STATUS_FLASH_PARTIAL) { + /* If flash is in progress and the previous frame + * was partially exposed, then this frame will be + * correctly exposed. */ + fr_status = ATOMISP_FRAME_STATUS_FLASH_EXPOSED; + } else if (flash_in_progress && + fr_status == ATOMISP_FRAME_STATUS_FLASH_EXPOSED) { + /* If the previous frame was flash-exposed, we assume + * that some of the flash leaked into the current frame + * so we tell the app not to use this frame. */ + fr_status = ATOMISP_FRAME_STATUS_FLASH_PARTIAL; + flash_in_progress = false; + } else { + fr_status = ATOMISP_FRAME_STATUS_OK; + } + + if (isp->params.num_flash_frames) { + int ret = atomisp_start_flash(isp); + + /* The flash failed frame status is needed to signal to + * the appication that flash has been attempted but no + * flash frames will be generated. Without this, the + * applicaton would end up an in endless loop waiting + * for a flash-exposed frame. + */ + if (ret) + fr_status = ATOMISP_FRAME_STATUS_FLASH_FAILED; + else { + fr_status = ATOMISP_FRAME_STATUS_FLASH_PARTIAL; + flash_in_progress = true; + flash_enabled = true; + } + isp->params.num_flash_frames = 0; + } + + /*Check ISP processing pipeline if any binary left*/ + do { + long time_left; + /* wait for different binary to be processed */ + time_left = + wait_for_completion_timeout(&isp->wq_frame_complete, + 1 * HZ); + + if (time_left == 0) { + ret = atomisp_timeout_handler(isp, + timeout_cnt++); + if (ret) { + mutex_unlock(&isp->isp_lock); + goto error; + } + timeout_flag = true; + break; + } + + INIT_COMPLETION(isp->acc_fw_complete); + if (isp->irq_infos & SH_CSS_IRQ_INFO_FW_ACC_DONE) + sh_css_terminate_firmware(); + + /* + * If there is any firware marked for deletion, do it + * now. Firware cannot be unloaded in the middle of a + * frame, so it has to be done when a frame done + * interrupt is processed. + * TODO: Check if this is the correct location. + * TODO: Check how to handle multiple firmware cases. + */ + if (isp->marked_fw_for_unload != NULL) { + atomisp_acc_fw_free_args(isp, + isp->marked_fw_for_unload); + sh_css_unload_acceleration( + isp->marked_fw_for_unload); + atomisp_acc_fw_free(isp, + isp->marked_fw_for_unload); + isp->marked_fw_for_unload = NULL; + complete(&isp->acc_unload_fw_complete); + } + + /* regardless of timeout or not, we disable the flash */ + if (flash_enabled && fr_status == + ATOMISP_FRAME_STATUS_FLASH_EXPOSED) { + atomisp_stop_flash(isp); + /* always check the result, this clears any + * errors that may have occurred. + */ + if (atomisp_flash_error(isp)) + fr_status = + ATOMISP_FRAME_STATUS_FLASH_FAILED; + flash_enabled = false; + } + + /* proc interrupt */ + INIT_COMPLETION(isp->wq_frame_complete); + if (isp->irq_infos & + SH_CSS_IRQ_INFO_START_NEXT_STAGE) { + sh_css_start_next_stage(); + + /* Getting 3A statistics if ready */ + if (isp->isp3a_stat_ready) { + mutex_lock(&isp->isp3a_lock); + ret = sh_css_get_3a_statistics + (isp->params.s3a_output_buf); + mutex_unlock(&isp->isp3a_lock); + + isp->isp3a_stat_ready = false; + if (ret != sh_css_success) + v4l2_err(&atomisp_dev, + "get 3a statistics" + " failed, not " + "enough memory.\n"); + } + } + } while (!(isp->irq_infos & SH_CSS_IRQ_INFO_FRAME_DONE)); + + mutex_unlock(&isp->isp_lock); + + if (!timeout_flag) { + if (vb_capture) { + isp->frame_status[vb_capture->i] = fr_status; + do_gettimeofday(&vb_capture->ts); + vb_capture->field_count++; + /*mark videobuffer done for dequeue*/ + vb_capture->state = VIDEOBUF_DONE; + } + + if (vb_preview) { + do_gettimeofday(&vb_preview->ts); + vb_preview->field_count++; + /*mark videobuffer done for dequeue*/ + vb_preview->state = VIDEOBUF_DONE; + } + + /* + * Frame capture done, wake up any process block on + * current active buffer + */ + if (vb_preview) + wake_up(&vb_preview->done); + if (vb_capture) + wake_up(&vb_capture->done); + + vb_preview = NULL; + vb_capture = NULL; + timeout_cnt = 0; + } + } + +error: + if (isp->isp_subdev.video_out_vf.opened) + isp->vf_frame = NULL; + + isp->sw_contex.error = true; + timeout_cnt = 0; + + if (vb_preview) + vb_preview->state = VIDEOBUF_ERROR; + if (vb_capture) + vb_capture->state = VIDEOBUF_ERROR; + + /* + * Frame capture error, wake up any process block on current + * active buffer + */ + if (vb_preview) + wake_up(&vb_preview->done); + if (vb_capture) + wake_up(&vb_capture->done); + return; +} + +/* + * utils for buffer allocation/free + */ +#define bytes_to_pgnr_ceil(bytes) \ + (((bytes) + ((1<> PAGE_SHIFT) + +int atomisp_get_frame_pgnr(const struct sh_css_frame *frame, u32 * p_pgnr) +{ + if (!frame) { + v4l2_err(&atomisp_dev, + "%s: NULL frame pointer ERROR.\n", + __func__); + return -EINVAL; + } + + (*p_pgnr) = bytes_to_pgnr_ceil(frame->data_bytes); + return 0; +} + +/* + * Get internal fmt according to V4L2 fmt + */ +enum sh_css_frame_format v4l2_fmt_to_sh_fmt(u32 fmt) +{ + switch (fmt) { + case V4L2_PIX_FMT_YUV420: + return SH_CSS_FRAME_FORMAT_YUV420; + case V4L2_PIX_FMT_YVU420: + return SH_CSS_FRAME_FORMAT_YV12; + case V4L2_PIX_FMT_YUV422P: + return SH_CSS_FRAME_FORMAT_YUV422; + case V4L2_PIX_FMT_YUV444: + return SH_CSS_FRAME_FORMAT_YUV444; + case V4L2_PIX_FMT_NV12: + return SH_CSS_FRAME_FORMAT_NV12; + case V4L2_PIX_FMT_NV21: + return SH_CSS_FRAME_FORMAT_NV21; + case V4L2_PIX_FMT_NV16: + return SH_CSS_FRAME_FORMAT_NV16; + case V4L2_PIX_FMT_NV61: + return SH_CSS_FRAME_FORMAT_NV61; + case V4L2_PIX_FMT_UYVY: + return SH_CSS_FRAME_FORMAT_UYVY; + case V4L2_PIX_FMT_YUYV: + return SH_CSS_FRAME_FORMAT_YUYV; + case V4L2_PIX_FMT_RGB24: + return SH_CSS_FRAME_FORMAT_PLANAR_RGB888; + case V4L2_PIX_FMT_RGB32: + return SH_CSS_FRAME_FORMAT_RGBA888; + case V4L2_PIX_FMT_RGB565: + return SH_CSS_FRAME_FORMAT_RGB565; + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return SH_CSS_FRAME_FORMAT_RAW; + default: + return -EINVAL; + } +} +/* + * raw format match between SH format and V4L2 format + */ +static int raw_output_format_match_input(u32 input, u32 output) +{ + if ((input == SH_CSS_INPUT_FORMAT_RAW_12) && + ((output == V4L2_PIX_FMT_SRGGB12) || + (output == V4L2_PIX_FMT_SGRBG12) || + (output == V4L2_PIX_FMT_SBGGR12) || + (output == V4L2_PIX_FMT_SGBRG12))) + return 0; + + if ((input == SH_CSS_INPUT_FORMAT_RAW_10) && + ((output == V4L2_PIX_FMT_SRGGB10) || + (output == V4L2_PIX_FMT_SGRBG10) || + (output == V4L2_PIX_FMT_SBGGR10) || + (output == V4L2_PIX_FMT_SGBRG10))) + return 0; + + if ((input == SH_CSS_INPUT_FORMAT_RAW_8) && + ((output == V4L2_PIX_FMT_SRGGB8) || + (output == V4L2_PIX_FMT_SGRBG8) || + (output == V4L2_PIX_FMT_SBGGR8) || + (output == V4L2_PIX_FMT_SGBRG8))) + return 0; + + if ((input == SH_CSS_INPUT_FORMAT_RAW_16) && + (output == V4L2_PIX_FMT_SBGGR16)) + return 0; + + return -EINVAL; +} +/* + * 2 types of format: SH format, v4l2 format + * atomisp_format_bridge is a wrapper format for the other 2 + */ +struct atomisp_format_bridge *get_atomisp_format_bridge( + unsigned int pixelformat) +{ + u32 i; + for (i = 0; i < atomisp_output_fmts_num; i++) { + if (atomisp_output_fmts[i].pixelformat == pixelformat) + return (struct atomisp_format_bridge *) + (&(atomisp_output_fmts[i])); + } + return NULL; +} + +struct atomisp_format_bridge *get_atomisp_format_bridge_from_mbus( + enum v4l2_mbus_pixelcode mbus_code) +{ + int i; + for (i = 0; i < atomisp_output_fmts_num; i++) { + if (atomisp_output_fmts[i].mbus_code == mbus_code) + return (struct atomisp_format_bridge *) + (&(atomisp_output_fmts[i])); + } + return NULL; +} +static u32 get_pixel_depth(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YVU420: + return 12; + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + return 16; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_YUV444: + return 24; + case V4L2_PIX_FMT_RGB32: + return 32; + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return 8; + default: + return 8 * 2; /* raw type now */ + } +} + +static int is_pixelformat_raw(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return 1; + default: + return 0; + } +} + +static int is_mbusformat_raw(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_MBUS_FMT_SBGGR8_1X8: + case V4L2_MBUS_FMT_SGRBG8_1X8: + case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: + case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: + case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: + case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE: + case V4L2_MBUS_FMT_SBGGR10_1X10: + case V4L2_MBUS_FMT_SGBRG10_1X10: + case V4L2_MBUS_FMT_SGRBG10_1X10: + case V4L2_MBUS_FMT_SRGGB10_1X10: + case V4L2_MBUS_FMT_SBGGR12_1X12: + return 1; + default: + return 0; + } +} + +static int get_sh_input_format(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + return SH_CSS_INPUT_FORMAT_YUV420_8; + + case V4L2_PIX_FMT_YUV422P: + return SH_CSS_INPUT_FORMAT_YUV422_8; + + case V4L2_PIX_FMT_RGB565: + return SH_CSS_INPUT_FORMAT_RGB_565; + + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return SH_CSS_INPUT_FORMAT_RAW_8; + + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + return SH_CSS_INPUT_FORMAT_RAW_10; + + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + return SH_CSS_INPUT_FORMAT_RAW_12; + + case V4L2_PIX_FMT_SBGGR16: + return SH_CSS_INPUT_FORMAT_RAW_16; + + default: + return -EINVAL; + } +} + +/* return whether v4l2 format is supported */ +int atomisp_is_pixelformat_supported(u32 pixelformat) +{ + int i; + + for (i = 0; i < atomisp_output_fmts_num; i++) { + if (pixelformat == atomisp_output_fmts[i].pixelformat) + return 1; + } + return 0; +} +/* + * for different isp run mode: preview/still/video. + * return which mode support viewfinder output + * still/video support dual stream output + */ +bool atomisp_is_viewfinder_support(struct atomisp_device *isp) +{ + if (isp->sw_contex.run_mode == CI_MODE_PREVIEW) + return false; + + if ((isp->sw_contex.run_mode == CI_MODE_STILL_CAPTURE) && + (isp->main_format->out_sh_fmt == SH_CSS_FRAME_FORMAT_RAW) && + (isp->sw_contex.bypass)) + return false; + + if (!isp->isp_subdev.video_out_vf.opened) + return false; + + return true; +} + +/* + * ISP features control function + */ + +/* + * Function to enable/disable lens geometry distortion correction (GDC) and + * chromatic aberration correction (CAC) + */ +int atomisp_gdc_cac(struct atomisp_device *isp, int flag, __s32 * value) +{ + struct sh_css_morph_table *tab; + + if (flag == 0) { + *value = isp->params.gdc_cac_en; + return 0; + } + + isp->params.gdc_cac_en = (*value == 0) ? 0 : 1; + if (isp->params.gdc_cac_en) { + tab = isp->inputs[isp->input_curr].morph_table; + if (tab) { + sh_css_morph_table_free(tab); + isp->inputs[isp->input_curr].morph_table = NULL; + } + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_ADVANCED); + } else { + sh_css_set_morph_table(NULL); + if (!isp->params.macc_en) + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_PRIMARY); + } + + return 0; +} + +/* + * Function to enable/disable extra nosie reduction (XNR) in low light + * condition + */ +int atomisp_xnr(struct atomisp_device *isp, int flag, int *arg) +{ + int xnr_enable = (*arg == 0) ? 0 : 1; + + if (flag == 0) { + *arg = isp->params.xnr_en; + return 0; + } + + sh_css_capture_enable_xnr(xnr_enable); + + return 0; +} + +/* + * Function to configure bayer nosie reduction + */ +int atomisp_bayer_nr(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_nr_config *arg = (struct atomisp_nr_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.nr_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + /* Get nr config from current setup */ + if (flag == 0) { + memcpy(arg, &isp->params.nr_config, sizeof(*arg)); + } else { + /* Set nr config to isp parameters */ + memcpy(&isp->params.nr_config, arg, + sizeof(struct sh_css_nr_config)); + sh_css_set_nr_config(&isp->params.nr_config); + } + return 0; +} + +/* + * Function to configure temporal nosie reduction (TNR) + */ +int atomisp_tnr(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_tnr_config *arg = (struct atomisp_tnr_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.tnr_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + /* Get tnr config from current setup */ + if (flag == 0) { + /* Get tnr config from current setup */ + memcpy(arg, &isp->params.tnr_config, sizeof(*arg)); + } else { + /* Set tnr config to isp parameters */ + memcpy(&isp->params.tnr_config, arg, + sizeof(struct sh_css_tnr_config)); + sh_css_set_tnr_config(&isp->params.tnr_config); + } + + return 0; +} + +/* + * Function to get histogram data for image frame + */ +int atomisp_histogram(struct atomisp_device *isp, int flag, void *config) +{ + struct atomisp_histogram *arg = (struct atomisp_histogram *)config; + struct sh_css_histogram *histogram; + int ret = 0; + unsigned int *buffer; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(*histogram)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + buffer = kzalloc(2048 * sizeof(unsigned int), GFP_KERNEL); + if (buffer == NULL) { + v4l2_err(&atomisp_dev, + "buffer allocate error\n"); + return -ENOMEM; + } + + ret = sh_css_histogram_allocate(2048, &histogram); + if (ret != sh_css_success) { + v4l2_err(&atomisp_dev, + "sh_css_histogram_allocate failed\n"); + goto buffer_free; + } + + if (isp->vf_frame == NULL) { + v4l2_err(&atomisp_dev, + "No frame for histogram\n"); + ret = -EINVAL; + goto histogram_free; + } + + ret = sh_css_histogram_start(isp->vf_frame, histogram); + if (ret != sh_css_success) { + v4l2_err(&atomisp_dev, + "sh_css_get_y_histogram failed\n"); + goto histogram_free; + } + sh_css_wait_for_completion(); + + ret = hmm_load(histogram->data, buffer, + histogram->num_elements * sizeof(unsigned int)); + if (ret) { + v4l2_err(&atomisp_dev, "hmm_load failed\n"); + goto histogram_free; + } + + ret = copy_to_user(arg->data, buffer, + histogram->num_elements * sizeof(unsigned int)); + if (ret) { + v4l2_err(&atomisp_dev, + "copy to user failed\n"); + ret = -EFAULT; + goto histogram_free; + } + + ret = 0; + arg->num_elements = histogram->num_elements; + +histogram_free: + sh_css_histogram_free(histogram); +buffer_free: + kfree(buffer); + + return ret; + } + + isp->params.histogram_elenum = arg->num_elements; + + return 0; +} + +/* + * Function to configure black level compensation + */ +int atomisp_black_level(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_ob_config *arg = (struct atomisp_ob_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.ob_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get ob config from current setup */ + const struct sh_css_ob_config *ob_config; + sh_css_get_ob_config(&ob_config); + memcpy(arg, ob_config, sizeof(*arg)); + } else { + /* Set ob config to isp parameters */ + memcpy(&isp->params.ob_config, arg, + sizeof(struct sh_css_ob_config)); + sh_css_set_ob_config(&isp->params.ob_config); + } + + return 0; +} + +/* + * Function to configure Ycc nosie reduction + */ +int atomisp_ycc_nr(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_nr_config *arg = (struct atomisp_nr_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.nr_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get nr config from current setup */ + const struct sh_css_nr_config *nr_config; + sh_css_get_nr_config(&nr_config); + memcpy(arg, nr_config, sizeof(*arg)); + } else { + /* Set nr config to isp parameters */ + memcpy(&isp->params.nr_config, arg, + sizeof(isp->params.nr_config)); + sh_css_set_nr_config(&isp->params.nr_config); + } + + return 0; +} + +/* + * Function to configure edge enhancement + */ +int atomisp_ee(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_ee_config *arg = (struct atomisp_ee_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.ee_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get ee config from current setup */ + const struct sh_css_ee_config *ee_config; + sh_css_get_ee_config(&ee_config); + memcpy(arg, ee_config, sizeof(*arg)); + } else { + /* Set ee config to isp parameters */ + memcpy(&isp->params.ee_config, arg, + sizeof(isp->params.ee_config)); + sh_css_set_ee_config(&isp->params.ee_config); + } + + return 0; +} + +/* + * Function to update Gamma table for gamma, brightness and contrast config + */ +int atomisp_gamma(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_gamma_table *arg = (struct atomisp_gamma_table *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.gamma_table)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get gamma table from current setup */ + const struct sh_css_gamma_table *tab; + sh_css_get_gamma_table(&tab); + memcpy(arg, tab, sizeof(*arg)); + } else { + /* Set gamma table to isp parameters */ + memcpy(&isp->params.gamma_table, arg, + sizeof(isp->params.gamma_table)); + sh_css_set_gamma_table(&isp->params.gamma_table); + } + + return 0; +} + +/* + * Function to update Ctc table for Chroma Enhancement + */ +int atomisp_ctc(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_ctc_table *arg = (struct atomisp_ctc_table *) config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.ctc_table)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get ctc table from current setup */ + const struct sh_css_ctc_table *tab; + sh_css_get_ctc_table(&tab); + memcpy(arg, tab, sizeof(*arg)); + } else { + /* Set gamma table to isp parameters */ + memcpy(&isp->params.ctc_table, arg, + sizeof(isp->params.ctc_table)); + sh_css_set_ctc_table(&isp->params.ctc_table); + } + + return 0; +} + +void atomisp_free_internal_buffers(struct atomisp_device *isp) +{ + struct sh_css_morph_table *tab; + + tab = isp->inputs[isp->input_curr].morph_table; + if (tab) { + sh_css_morph_table_free(tab); + isp->inputs[isp->input_curr].morph_table = NULL; + } + + if (isp->params.vf_overlay) { + if (isp->params.vf_overlay->frame) + sh_css_frame_free(isp->params.vf_overlay->frame); + kfree(isp->params.vf_overlay); + isp->params.vf_overlay = NULL; + } + + if (isp->raw_output_frame) { + sh_css_frame_free(isp->raw_output_frame); + isp->raw_output_frame = NULL; + } +} + +void atomisp_free_3a_buffers(struct atomisp_device *isp) +{ + /* 3A statistics use vmalloc, DIS use kmalloc */ + if (isp->params.s3a_output_buf) + vfree(isp->params.s3a_output_buf); + isp->params.s3a_output_buf = NULL; + isp->params.s3a_output_bytes = 0; +} + +void atomisp_free_dis_buffers(struct atomisp_device *isp) +{ + if (isp->params.dis_hor_proj_buf) + kfree(isp->params.dis_hor_proj_buf); + if (isp->params.dis_ver_proj_buf) + kfree(isp->params.dis_ver_proj_buf); + if (isp->params.dis_hor_coef_buf) + kfree(isp->params.dis_hor_coef_buf); + if (isp->params.dis_ver_coef_buf) + kfree(isp->params.dis_ver_coef_buf); + isp->params.dis_hor_proj_buf = NULL; + isp->params.dis_ver_proj_buf = NULL; + isp->params.dis_hor_coef_buf = NULL; + isp->params.dis_ver_coef_buf = NULL; + isp->params.dis_hor_proj_bytes = 0; + isp->params.dis_ver_proj_bytes = 0; + isp->params.dis_hor_coef_bytes = 0; + isp->params.dis_ver_coef_bytes = 0; +} + +static void atomisp_update_grid_info(struct atomisp_device *isp) +{ + struct sh_css_grid_info old_info = isp->params.curr_grid_info; + + switch (isp->sw_contex.run_mode) { + case CI_MODE_PREVIEW: + sh_css_preview_get_grid_info(&isp->params.curr_grid_info); + break; + case CI_MODE_VIDEO: + sh_css_video_get_grid_info(&isp->params.curr_grid_info); + break; + default: + sh_css_capture_get_grid_info(&isp->params.curr_grid_info); + break; + } + /* If the grid info has changed, we need to reallocate + the buffers for 3A and DIS statistics. */ + if (memcmp(&old_info, &isp->params.curr_grid_info, sizeof(old_info)) || + !isp->params.s3a_output_buf || !isp->params.dis_hor_coef_buf) { + /* We must free all buffers because they no longer match + the grid size. */ + atomisp_free_3a_buffers(isp); + atomisp_free_dis_buffers(isp); + /* 3A statistics. These can be big, so we use vmalloc. */ + isp->params.s3a_output_bytes = + isp->params.curr_grid_info.s3a_width * + isp->params.curr_grid_info.s3a_height * + sizeof(*isp->params.s3a_output_buf); + + isp->params.s3a_output_buf = vmalloc( + isp->params.s3a_output_bytes); + + if (isp->params.s3a_output_buf == NULL) + goto err_3a; + + /* DIS coefficients. */ + isp->params.dis_hor_coef_bytes = + isp->params.curr_grid_info.dis_hor_coef_num * + SH_CSS_DIS_NUM_COEF_TYPES * + sizeof(*isp->params.dis_hor_coef_buf); + + isp->params.dis_ver_coef_bytes = + isp->params.curr_grid_info.dis_ver_coef_num * + SH_CSS_DIS_NUM_COEF_TYPES * + sizeof(*isp->params.dis_ver_coef_buf); + + isp->params.dis_hor_coef_buf = + kzalloc(isp->params.dis_hor_coef_bytes, GFP_KERNEL); + if (isp->params.dis_hor_coef_buf == NULL) + goto err_dis; + + isp->params.dis_ver_coef_buf = + kzalloc(isp->params.dis_ver_coef_bytes, GFP_KERNEL); + if (isp->params.dis_ver_coef_buf == NULL) + goto err_dis; + + /* DIS projections. */ + isp->params.dis_hor_proj_bytes = + isp->params.curr_grid_info.dis_height * + SH_CSS_DIS_NUM_COEF_TYPES * + sizeof(*isp->params.dis_hor_proj_buf); + + isp->params.dis_ver_proj_bytes = + isp->params.curr_grid_info.dis_width * + SH_CSS_DIS_NUM_COEF_TYPES * + sizeof(*isp->params.dis_ver_proj_buf); + + isp->params.dis_hor_proj_buf = + kzalloc(isp->params.dis_hor_proj_bytes, GFP_KERNEL); + if (isp->params.dis_hor_proj_buf == NULL) + goto err_dis; + + isp->params.dis_ver_proj_buf = + kzalloc(isp->params.dis_ver_proj_bytes, GFP_KERNEL); + if (isp->params.dis_ver_proj_buf == NULL) + goto err_dis; + } + return; + /* Failure for 3A buffers does not influence DIS buffers */ +err_3a: + v4l2_err(&atomisp_dev, + "Failed allocate memory for 3A statistics\n"); + atomisp_free_3a_buffers(isp); + return; +err_dis: + v4l2_err(&atomisp_dev, + "Failed allocate memory for DIS statistics\n"); + atomisp_free_dis_buffers(isp); + +} + +static void atomisp_curr_user_grid_info(struct atomisp_device *isp, + struct atomisp_grid_info_user *info) +{ + info->s3a_width = isp->params.curr_grid_info.s3a_width; + info->s3a_height = isp->params.curr_grid_info.s3a_height; + info->s3a_bqs_per_grid_cell = + isp->params.curr_grid_info.s3a_bqs_per_grid_cell; + info->dis_width = isp->params.curr_grid_info.dis_width; + info->dis_height = isp->params.curr_grid_info.dis_height; + info->dis_bqs_per_grid_cell = + isp->params.curr_grid_info.dis_bqs_per_grid_cell; + info->dis_hor_coef_num = + isp->params.curr_grid_info.dis_hor_coef_num; + info->dis_ver_coef_num = + isp->params.curr_grid_info.dis_ver_coef_num; +} + +/* + * Function to update Gdc table for gdc + */ +int atomisp_gdc_cac_table(struct atomisp_device *isp, int flag, + void *config) +{ + int ret; + int i; + struct atomisp_morph_table *arg = (struct atomisp_morph_table *)config; + + if (flag == 0) { + /* Get gamma table from current setup */ + const struct sh_css_morph_table *tab; + sh_css_get_morph_table(&tab); + + arg->width = tab->width; + arg->height = tab->height; + + for (i = 0; i < SH_CSS_MORPH_TABLE_NUM_PLANES; i++) { + ret = copy_to_user(arg->coordinates_x[i], + tab->coordinates_x[i], tab->height * + tab->width * sizeof(*tab->coordinates_x[i])); + if (ret) { + v4l2_err(&atomisp_dev, + "Failed to copy to User for x\n"); + return -EFAULT; + } + ret = copy_to_user(arg->coordinates_y[i], + tab->coordinates_y[i], tab->height * + tab->width * sizeof(*tab->coordinates_y[i])); + if (ret) { + v4l2_err(&atomisp_dev, + "Failed to copy to User for y\n"); + return -EFAULT; + } + } + } else { + struct sh_css_morph_table *tab; + tab = isp->inputs[isp->input_curr].morph_table; + /* free first if we have one */ + if (tab) { + sh_css_morph_table_free(tab); + isp->inputs[isp->input_curr].morph_table = NULL; + } + + /* allocate new one */ + tab = sh_css_morph_table_allocate(arg->width, arg->height); + + if (!tab) { + v4l2_err(&atomisp_dev, "out of memory\n"); + return -EINVAL; + } + + for (i = 0; i < SH_CSS_MORPH_TABLE_NUM_PLANES; i++) { + ret = copy_from_user(tab->coordinates_x[i], + (void __user *)arg->coordinates_x[i], + arg->height * arg->width * + sizeof(*arg->coordinates_x[i])); + if (ret) { + v4l2_err(&atomisp_dev, + "Failed to copy from User for x, ret %d\n", + ret); + sh_css_morph_table_free(tab); + return -EFAULT; + } + ret = copy_from_user(tab->coordinates_y[i], + (void __user *)arg->coordinates_y[i], + arg->height * arg->width * + sizeof(*arg->coordinates_y[i])); + if (ret) { + v4l2_err(&atomisp_dev, + "Failed to copy from User for y, ret is %d\n", + ret); + sh_css_morph_table_free(tab); + return -EFAULT; + } + } + isp->inputs[isp->input_curr].morph_table = tab; + sh_css_set_morph_table(tab); + } + + return 0; +} + +int atomisp_macc_table(struct atomisp_device *isp, int flag, + void *config) +{ + struct sh_css_macc_table *macc_table; + struct atomisp_macc_config *arg = (struct atomisp_macc_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(arg->table) != sizeof(*macc_table)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + switch (arg->color_effect) { + case V4L2_COLORFX_SKY_BLUE: + macc_table = &blue_macc_table; + break; + case V4L2_COLORFX_GRASS_GREEN: + macc_table = &green_macc_table; + break; + case V4L2_COLORFX_SKIN_WHITEN_LOW: + macc_table = &skin_low_macc_table; + break; + case V4L2_COLORFX_SKIN_WHITEN: + macc_table = &skin_medium_macc_table; + break; + case V4L2_COLORFX_SKIN_WHITEN_HIGH: + macc_table = &skin_high_macc_table; + break; + default: + return -EINVAL; + } + + if (flag == 0) { + /* Get macc table from current setup */ + memcpy(&arg->table, macc_table, + sizeof(struct sh_css_macc_table)); + } else { + memcpy(macc_table, &arg->table, + sizeof(struct sh_css_macc_table)); + } + + return 0; +} + +int atomisp_dis_vector(struct atomisp_device *isp, + void *config) +{ + struct atomisp_dis_config *arg = (struct atomisp_dis_config *)config; + + /* The dis parameter is initialized at start_video_capture + * in atomisp_work + */ + mutex_lock(&isp->isp_lock); + isp->params.dis_x = arg->dis_x; + isp->params.dis_y = arg->dis_y; + mutex_unlock(&isp->isp_lock); + return 0; +} + +/* + * Function to set/get image stablization statistics + */ +int atomisp_dis_stat(struct atomisp_device *isp, int flag, + void *config) +{ + int error; + struct atomisp_dis_config *arg = (struct atomisp_dis_config *)config; + + if (flag == 0) { + long time_left; + + if (arg->w_sdis_vertproj_tbl == NULL || + arg->w_sdis_horiproj_tbl == NULL || + isp->params.dis_hor_proj_buf == NULL || + isp->params.dis_ver_proj_buf == NULL) + return -EINVAL; + + /* isp need to be streaming to get DIS statistics */ + if (!isp->sw_contex.isp_streaming) + return -EINVAL; + if (!isp->params.video_dis_en) + return -EINVAL; + + INIT_COMPLETION(isp->dis_state_complete); + + time_left = + wait_for_completion_timeout(&isp->dis_state_complete, + 1 * HZ); + + /* Timeout to get the statistics */ + if (time_left == 0) { + v4l2_err(&atomisp_dev, + "Failed to wait frame DIS state\n"); + return -EINVAL; + } + + + sh_css_get_dis_projections(isp->params.dis_hor_proj_buf, + isp->params.dis_ver_proj_buf); + + error = copy_to_user(arg->w_sdis_vertproj_tbl, + isp->params.dis_ver_proj_buf, + isp->params.dis_ver_proj_bytes); + if (error) + return -EFAULT; + + error = copy_to_user(arg->w_sdis_horiproj_tbl, + isp->params.dis_hor_proj_buf, + isp->params.dis_hor_proj_bytes); + if (error) + return -EFAULT; + } else { + if (arg->sdis_vertcoef_tbl == NULL || + arg->sdis_horicoef_tbl == NULL || + isp->params.dis_hor_coef_buf == NULL || + isp->params.dis_ver_coef_buf == NULL) + return -EINVAL; + + error = copy_from_user(isp->params.dis_hor_coef_buf, + (void __user *)arg->sdis_horicoef_tbl, + isp->params.dis_hor_coef_bytes); + if (error) + return -EFAULT; + error = copy_from_user(isp->params.dis_ver_coef_buf, + (void __user *)arg->sdis_vertcoef_tbl, + isp->params.dis_ver_coef_bytes); + if (error) + return -EFAULT; + sh_css_set_dis_coefficients(isp->params.dis_hor_coef_buf, + isp->params.dis_ver_coef_buf); + } + return 0; +} + +/* + * Function to set/get 3A stat from isp + */ +int atomisp_3a_stat(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_3a_statistics *arg = + (struct atomisp_3a_statistics *)config; + unsigned long ret; + + if (flag != 0) + return -EINVAL; + + if (arg == NULL) + return -EINVAL; + + /* sanity check to avoid writing into unallocated memory. */ + if (isp->params.s3a_output_bytes == 0) + return -EINVAL; + + /* If the grid info in the argument differs from the current + grid info, we tell the caller to reset the grid size and + try again. */ + if (memcmp(&arg->grid_info, &isp->params.curr_grid_info, + sizeof(isp->params.curr_grid_info)) != 0) + return -EAGAIN; + + mutex_lock(&isp->isp3a_lock); + ret = copy_to_user(arg->data, isp->params.s3a_output_buf, + isp->params.s3a_output_bytes); + mutex_unlock(&isp->isp3a_lock); + if (ret) { + v4l2_err(&atomisp_dev, + "copy to user failed: copied %lu bytes\n", ret); + return -EFAULT; + } + return 0; +} + +/* + * Function to set/get isp parameters to isp + */ +int atomisp_param(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_parm *arg = (struct atomisp_parm *)config; + + /* Read parameter for 3A bianry info */ + if (flag == 0) { + if (&arg->info == NULL) { + v4l2_err(&atomisp_dev, + "ERROR: NULL pointer in grid_info\n"); + return -EINVAL; + } + atomisp_curr_user_grid_info(isp, &arg->info); + return 0; + } + + if (sizeof(arg->wb_config) != sizeof(isp->params.wb_config)) + goto INVALID_PARM; + if (sizeof(arg->cc_config) != sizeof(isp->params.cc_config)) + goto INVALID_PARM; + if (sizeof(arg->ob_config) != sizeof(isp->params.ob_config)) + goto INVALID_PARM; + if (sizeof(arg->de_config) != sizeof(isp->params.de_config)) + goto INVALID_PARM; + if (sizeof(arg->dp_config) != sizeof(isp->params.dp_config)) + goto INVALID_PARM; + if (sizeof(arg->nr_config) != sizeof(isp->params.nr_config)) + goto INVALID_PARM; + if (sizeof(arg->ee_config) != sizeof(isp->params.ee_config)) + goto INVALID_PARM; + if (sizeof(arg->tnr_config) != sizeof(isp->params.tnr_config)) + goto INVALID_PARM; + + memcpy(&isp->params.wb_config, &arg->wb_config, + sizeof(struct sh_css_wb_config)); + memcpy(&isp->params.ob_config, &arg->ob_config, + sizeof(struct sh_css_ob_config)); + memcpy(&isp->params.dp_config, &arg->dp_config, + sizeof(struct sh_css_dp_config)); + memcpy(&isp->params.de_config, &arg->de_config, + sizeof(struct sh_css_de_config)); + memcpy(&isp->params.nr_config, &arg->nr_config, + sizeof(struct sh_css_nr_config)); + memcpy(&isp->params.ee_config, &arg->ee_config, + sizeof(struct sh_css_ee_config)); + memcpy(&isp->params.tnr_config, &arg->tnr_config, + sizeof(struct sh_css_tnr_config)); + + if (isp->params.color_effect == V4L2_COLORFX_NEGATIVE) { + arg->cc_config.matrix[3] = -arg->cc_config.matrix[3]; + arg->cc_config.matrix[4] = -arg->cc_config.matrix[4]; + arg->cc_config.matrix[5] = -arg->cc_config.matrix[5]; + arg->cc_config.matrix[6] = -arg->cc_config.matrix[6]; + arg->cc_config.matrix[7] = -arg->cc_config.matrix[7]; + arg->cc_config.matrix[8] = -arg->cc_config.matrix[8]; + } + + if (isp->params.color_effect != V4L2_COLORFX_SEPIA && + isp->params.color_effect != V4L2_COLORFX_BW) { + memcpy(&isp->params.cc_config, &arg->cc_config, + sizeof(struct sh_css_cc_config)); + sh_css_set_cc_config(&isp->params.cc_config); + } + + sh_css_set_wb_config(&isp->params.wb_config); + sh_css_set_ob_config(&isp->params.ob_config); + sh_css_set_de_config(&isp->params.de_config); + sh_css_set_dp_config(&isp->params.dp_config); + sh_css_set_nr_config(&isp->params.nr_config); + sh_css_set_ee_config(&isp->params.ee_config); + sh_css_set_tnr_config(&isp->params.tnr_config); + + return 0; + +INVALID_PARM: + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; +} + +/* + * Function to configure color effect of the image + */ +int atomisp_color_effect(struct atomisp_device *isp, int flag, __s32 *effect) +{ + const struct sh_css_cc_config *cc_config = NULL; + const struct sh_css_macc_table *macc_table = NULL; + const struct sh_css_ctc_table *ctc_table = NULL; + + if (flag == 0) { + *effect = isp->params.color_effect; + return 0; + } + + if (*effect == isp->params.color_effect) + return 0; + + switch (*effect) { + case V4L2_COLORFX_NONE: + cc_config = isp->params.default_cc_config; + macc_table = isp->params.default_macc_table; + ctc_table = isp->params.default_ctc_table; + isp->params.macc_en = false; + if (!isp->params.gdc_cac_en) + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_PRIMARY); + break; + case V4L2_COLORFX_SEPIA: + cc_config = &sepia_cc_config; + break; + case V4L2_COLORFX_NEGATIVE: + cc_config = &nega_cc_config; + break; + case V4L2_COLORFX_BW: + cc_config = &mono_cc_config; + break; + case V4L2_COLORFX_SKY_BLUE: + macc_table = &blue_macc_table; + isp->params.macc_en = true; + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_ADVANCED); + break; + case V4L2_COLORFX_GRASS_GREEN: + macc_table = &green_macc_table; + isp->params.macc_en = true; + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_ADVANCED); + break; + case V4L2_COLORFX_SKIN_WHITEN_LOW: + macc_table = &skin_low_macc_table; + isp->params.macc_en = true; + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_ADVANCED); + break; + case V4L2_COLORFX_SKIN_WHITEN: + macc_table = &skin_medium_macc_table; + isp->params.macc_en = true; + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_ADVANCED); + break; + case V4L2_COLORFX_SKIN_WHITEN_HIGH: + macc_table = &skin_high_macc_table; + isp->params.macc_en = true; + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_ADVANCED); + break; + case V4L2_COLORFX_VIVID: + ctc_table = &vivid_ctc_table; + break; + default: + return -EINVAL; + } + + if (cc_config) + sh_css_set_cc_config(cc_config); + if (macc_table) + sh_css_set_macc_table(macc_table); + if (ctc_table) + sh_css_set_ctc_table(ctc_table); + isp->params.color_effect = (u32)*effect; + return 0; +} + +/* + * Function to configure bad pixel correction + */ +int atomisp_bad_pixel(struct atomisp_device *isp, int flag, __s32 *value) +{ + + if (flag == 0) { + *value = isp->params.bad_pixel_en; + return 0; + } + isp->params.bad_pixel_en = (*value == 0) ? 0 : 1; + + return 0; +} + +/* + * Function to configure bad pixel correction params + */ +int atomisp_bad_pixel_param(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_dp_config *arg = (struct atomisp_dp_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.dp_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get bad pixel from current setup */ + memcpy(arg, &isp->params.dp_config, sizeof(*arg)); + } else { + /* Set bad pixel to isp parameters */ + memcpy(&isp->params.dp_config, arg, sizeof(*arg)); + sh_css_set_dp_config(&isp->params.dp_config); + } + + return 0; +} + +/* + * Function to enable/disable video image stablization + */ +int atomisp_video_stable(struct atomisp_device *isp, int flag, __s32 * value) +{ + if (flag == 0) + *value = isp->params.video_dis_en; + else + isp->params.video_dis_en = (*value == 0) ? 0 : 1; + + return 0; +} + +/* + * Function to configure fixed pattern noise + */ +int atomisp_fixed_pattern(struct atomisp_device *isp, int flag, __s32 * value) +{ + + if (flag == 0) { + *value = isp->params.fpn_en; + return 0; + } + + if (*value == 0) { + isp->params.fpn_en = 0; + return 0; + } + + /* Add function to get black from from sensor with shutter off */ + return 0; +} + +/* + * Function to configure fixed pattern noise table + */ +int atomisp_fixed_pattern_table(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_frame *arg = (struct atomisp_frame *)config; + struct sh_css_frame *raw_black_frame = NULL; + struct sh_css_frame_info info; + char *tmp_buf; + int ret = 0; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(*raw_black_frame)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) + return -EINVAL; + else { + memcpy(&info, &arg->info, sizeof(struct sh_css_frame_info)); + + tmp_buf = vmalloc(arg->data_bytes); + if (!tmp_buf) + return -ENOMEM; + + if (sh_css_frame_allocate_from_info(&raw_black_frame, &info)) { + ret = -ENOMEM; + goto failed1; + } + + if (copy_from_user(tmp_buf, arg->data, arg->data_bytes)) { + ret = -EFAULT; + goto failed2; + } + + if (hmm_store(raw_black_frame->data, tmp_buf, + arg->data_bytes)){ + ret = -EINVAL; + goto failed2; + } + + sh_css_set_black_frame(raw_black_frame); +failed2: + sh_css_frame_free(raw_black_frame); +failed1: + vfree(tmp_buf); + } + + return ret; +} + +/* + * Function to configure vf overlay image + */ +int atomisp_vf_overlay(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_overlay *arg = (struct atomisp_overlay *)config; + int ret = 0; + struct sh_css_frame vf_frame; + char *tmp_buf; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(*isp->params.vf_overlay)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (!arg->frame) + /* from siliconhive, passing NULL means disable the feature */ + sh_css_overlay_set_for_viewfinder(NULL); + + if (copy_from_user(&vf_frame, arg->frame, + sizeof(struct sh_css_frame))) + return -EFAULT; + + tmp_buf = vmalloc(vf_frame.data_bytes); + if (!tmp_buf) + return -ENOMEM; + + if (isp->params.vf_overlay) { + if (isp->params.vf_overlay->frame) + sh_css_frame_free(isp->params.vf_overlay->frame); + kfree(isp->params.vf_overlay); + } + + isp->params.vf_overlay = kmalloc(sizeof(struct sh_css_overlay), + GFP_KERNEL); + if (!isp->params.vf_overlay) { + ret = -ENOMEM; + goto fail1; + } + + if (sh_css_frame_allocate_from_info(&isp->params.vf_overlay->frame, + &vf_frame.info)) { + ret = -ENOMEM; + goto fail2; + } + + isp->params.vf_overlay->bg_y = arg->bg_y; + isp->params.vf_overlay->bg_u = arg->bg_u; + isp->params.vf_overlay->bg_v = arg->bg_v; + isp->params.vf_overlay->blend_input_perc_y = arg->blend_input_perc_y; + isp->params.vf_overlay->blend_input_perc_u = arg->blend_input_perc_u; + isp->params.vf_overlay->blend_input_perc_v = arg->blend_input_perc_v; + isp->params.vf_overlay->blend_overlay_perc_y = + arg->blend_overlay_perc_y; + isp->params.vf_overlay->blend_overlay_perc_u = + arg->blend_overlay_perc_u; + isp->params.vf_overlay->blend_overlay_perc_v = + arg->blend_overlay_perc_v; + isp->params.vf_overlay->overlay_start_x = arg->overlay_start_x; + isp->params.vf_overlay->overlay_start_y = arg->overlay_start_y; + + /* copy for YUV 420 */ + if (copy_from_user(tmp_buf, vf_frame.data, vf_frame.data_bytes)) { + ret = -EFAULT; + goto fail2; + } + + if (hmm_store(isp->params.vf_overlay->frame->data, tmp_buf, + vf_frame.data_bytes)){ + ret = -EINVAL; + goto fail2; + } + + sh_css_overlay_set_for_viewfinder(isp->params.vf_overlay); + + vfree(tmp_buf); + + return ret; + +fail2: + kfree(isp->params.vf_overlay); +fail1: + vfree(tmp_buf); + return ret; +} + +/* + * Function to configure false color correction + */ +int atomisp_false_color(struct atomisp_device *isp, int flag, __s32 *value) +{ + /* Get nr config from current setup */ + if (flag == 0) { + *value = isp->params.false_color; + return 0; + } + + /* Set nr config to isp parameters */ + if (*value) { + sh_css_set_de_config(isp->params.default_de_config); + } else { + isp->params.de_config.pixelnoise = 0; + sh_css_set_de_config(&isp->params.de_config); + } + isp->params.false_color = *value; + return 0; +} + +/* + * Function to configure bad pixel correction params + */ +int atomisp_false_color_param(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_de_config *arg = + (struct atomisp_de_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.de_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get false color from current setup */ + memcpy(arg, &isp->params.de_config, sizeof(*arg)); + } else { + /* Set false color to isp parameters */ + memcpy(&isp->params.de_config, arg, sizeof(*arg)); + sh_css_set_de_config(&isp->params.de_config); + } + + return 0; +} + +/* + * Function to configure white balance params + */ +int atomisp_white_balance_param(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_wb_config *arg = (struct atomisp_wb_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.wb_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get white balance from current setup */ + memcpy(arg, &isp->params.wb_config, sizeof(*arg)); + } else { + /* Set white balance to isp parameters */ + memcpy(&isp->params.wb_config, arg, sizeof(*arg)); + sh_css_set_wb_config(&isp->params.wb_config); + } + + return 0; +} + +int atomisp_3a_config_param(struct atomisp_device *isp, int flag, + void *config) +{ + struct atomisp_3a_config *arg = (struct atomisp_3a_config *)config; + + if (arg == NULL) + return -EINVAL; + + if (sizeof(*arg) != sizeof(isp->params.s3a_config)) { + v4l2_err(&atomisp_dev, + "%s: incompatible param.\n", __func__); + return -EINVAL; + } + + if (flag == 0) { + /* Get white balance from current setup */ + memcpy(arg, &isp->params.s3a_config, sizeof(*arg)); + } else { + /* Set white balance to isp parameters */ + memcpy(&isp->params.s3a_config, arg, sizeof(*arg)); + sh_css_set_3a_config(&isp->params.s3a_config); + } + + return 0; +} + +/* + * Function to enable/disable lens shading correction + */ +int atomisp_shading_correction(struct atomisp_device *isp, int flag, + __s32 *value) +{ + if (flag == 0) { + *value = isp->params.sc_en; + return 0; + } + + if (*value == 0) { + sh_css_set_shading_table(NULL); + } else { + sh_css_set_shading_table( + isp->inputs[isp->input_curr].shading_table); + } + + isp->params.sc_en = *value; + + return 0; +} + +/* + * Function to setup digital zoom + */ +int atomisp_digital_zoom(struct atomisp_device *isp, int flag, __s32 *value) +{ + u32 zoom; + + if (flag == 0) { + sh_css_get_zoom_factor(&zoom, &zoom); + *value = 64 - zoom; + } else { + if (*value < 0) + return -EINVAL; + + zoom = *value; + if (zoom >= 64) + zoom = 64; + zoom = 64 - zoom; + + sh_css_set_zoom_factor(zoom, zoom); + } + + return 0; +} + +/* + * Function to get sensor specific info for current resolution, + * which will be used for auto exposure conversion. + */ +int atomisp_get_sensor_mode_data(struct atomisp_device *isp, + void *config) +{ + struct atomisp_sensor_mode_data *arg = + (struct atomisp_sensor_mode_data *)config; + struct camera_mipi_info *mipi_info; + + mipi_info = + atomisp_to_sensor_mipi_info(isp->inputs[isp->input_curr].camera); + if (mipi_info == NULL) + return -EINVAL; + + memcpy(arg, &mipi_info->data, sizeof(*arg)); + return 0; +} + +int atomisp_get_fmt(struct video_device *vdev, struct v4l2_format *f) +{ + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&atomisp_dev, + "unsupported v4l2 buf type\n"); + return -EINVAL; + } + + memset(f, 0, sizeof(struct v4l2_format)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* VIDIOC_S_FMT already called,*/ + /* return fmt setted by app */ + if ((pipe->format) && (pipe->format->out.width != 0)) + memcpy(&f->fmt.pix, &pipe->format->out, + sizeof(struct v4l2_pix_format)); + else { + f->fmt.pix.width = 640; + f->fmt.pix.height = 480; + f->fmt.pix.pixelformat = atomisp_output_fmts[0].pixelformat; + f->fmt.pix.bytesperline = + get_pixel_depth(f->fmt.pix.pixelformat) * + f->fmt.pix.width; + f->fmt.pix.sizeimage = f->fmt.pix.height * + f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + } + + return 0; +} + + +/* This function looks up the closest available resolution. */ +int atomisp_try_fmt(struct video_device *vdev, struct v4l2_format *f, + bool *res_overflow) +{ + struct atomisp_device *isp = video_get_drvdata(vdev); + struct v4l2_mbus_framefmt snr_mbus_fmt; + struct atomisp_format_bridge *fmt; + u32 out_width = f->fmt.pix.width; + u32 out_height = f->fmt.pix.height; + u32 pixelformat = f->fmt.pix.pixelformat; + u32 in_width = 0; + u32 in_height = 0; + int ret; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_err(&atomisp_dev, "Wrong v4l2 buf type\n"); + return -EINVAL; + } + + if (isp->inputs[isp->input_curr].camera == NULL) + return -EINVAL; + + fmt = get_atomisp_format_bridge(pixelformat); + if (fmt == NULL) { + v4l2_err(&atomisp_dev, "unsupported pixelformat!\n"); + fmt = (struct atomisp_format_bridge *)&atomisp_output_fmts[0]; + } + + + /*set TPG format*/ + if (isp->inputs[isp->input_curr].type == TEST_PATTERN) { + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, try_fmt, f); + in_width = f->fmt.pix.width; + in_height = f->fmt.pix.height; + goto done; + } + + snr_mbus_fmt.code = fmt->mbus_code; + snr_mbus_fmt.height = out_height; + snr_mbus_fmt.width = out_width; + + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, try_mbus_fmt, &snr_mbus_fmt); + if (ret) { + /*In case camera sensor driver don't support try_mbus_fmt*/ + v4l2_err(&atomisp_dev, + "failed to try_mbus_fmt for sensor\n"); + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, try_fmt, f); + if (ret) + return ret; + in_width = f->fmt.pix.width; + in_height = f->fmt.pix.height; + } else { + in_width = snr_mbus_fmt.width; + in_height = snr_mbus_fmt.height; + fmt = get_atomisp_format_bridge_from_mbus(snr_mbus_fmt.code); + if (fmt == NULL) { + f->fmt.pix.pixelformat = pixelformat; + v4l2_err(&atomisp_dev, "unknown sensor format.\n"); + } else + f->fmt.pix.pixelformat = fmt->pixelformat; + } + +done: + v4l2_info(&atomisp_dev, "return snr_try_fmt, (wxh: %d*%d)\n", + in_width, in_height); + if ((in_width < out_width) && (in_height < out_height)) { + out_width = in_width; + out_height = in_height; + /* Set the flag when resolution requested is + * beyond the max value supported by sensor + */ + if (res_overflow != NULL) + *res_overflow = true; + } + + /* app vs isp */ + out_width = min(out_width, (u32)ATOM_ISP_MAX_WIDTH); + out_height = min(out_height, (u32)ATOM_ISP_MAX_HEIGHT); + + out_width = max(out_width, (u32)ATOM_ISP_MIN_WIDTH); + out_height = max(out_height, (u32)ATOM_ISP_MIN_HEIGHT); + + out_width = out_width - out_width % ATOM_ISP_STEP_WIDTH; + out_height = out_height - out_height % ATOM_ISP_STEP_HEIGHT; + + f->fmt.pix.width = out_width; + f->fmt.pix.height = out_height; + + return 0; +} + +int atomisp_try_fmt_file(struct atomisp_device *isp, struct v4l2_format *f) +{ + u32 width = f->fmt.pix.width; + u32 height = f->fmt.pix.height; + u32 pixelformat = f->fmt.pix.pixelformat; + enum v4l2_field field = f->fmt.pix.field; + u32 depth; + + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&atomisp_dev, "Wrong v4l2 buf type\n"); + return -EINVAL; + } + + if (!atomisp_is_pixelformat_supported(pixelformat)) { + v4l2_err(&atomisp_dev, "Wrong output pixelformat\n"); + return -EINVAL; + } + + depth = get_pixel_depth(pixelformat); + + if (!field || field == V4L2_FIELD_ANY) + field = V4L2_FIELD_NONE; + else if (field != V4L2_FIELD_NONE) { + v4l2_err(&atomisp_dev, "Wrong output field\n"); + return -EINVAL; + } + + f->fmt.pix.field = field; + + if (width > ATOM_ISP_MAX_WIDTH) + width = ATOM_ISP_MAX_WIDTH; + else if (width < ATOM_ISP_MIN_WIDTH) + width = ATOM_ISP_MIN_WIDTH; + + if (height > ATOM_ISP_MAX_HEIGHT) + height = ATOM_ISP_MAX_HEIGHT; + else if (height < ATOM_ISP_MIN_HEIGHT) + height = ATOM_ISP_MIN_HEIGHT; + + width = width - width % ATOM_ISP_STEP_WIDTH; + height = height - height % ATOM_ISP_STEP_HEIGHT; + + f->fmt.pix.width = width; + f->fmt.pix.height = height; + + f->fmt.pix.bytesperline = (width * depth) >> 3; + + return 0; +} + +static bool atomisp_input_format_is_raw(enum atomisp_input_format format) +{ + switch (format) { + case ATOMISP_INPUT_FORMAT_RAW_6: + case ATOMISP_INPUT_FORMAT_RAW_7: + case ATOMISP_INPUT_FORMAT_RAW_8: + case ATOMISP_INPUT_FORMAT_RAW_10: + case ATOMISP_INPUT_FORMAT_RAW_12: + case ATOMISP_INPUT_FORMAT_RAW_14: + case ATOMISP_INPUT_FORMAT_RAW_16: + return true; + default: + return false; + } +} + +static inline void +atomisp_set_sensor_mipi_to_isp(struct camera_mipi_info *mipi_info) +{ + if (mipi_info) { + v4l2_info(&atomisp_dev, + "MIPI info from sensor:\n" + " port: %d\n" + " number of lanes: %d\n" + " input format: %d\n" + " bayer order: %d\n", + mipi_info->port, + mipi_info->num_lanes, + mipi_info->input_format, + mipi_info->raw_bayer_order); + if (atomisp_input_format_is_raw(mipi_info->input_format)) + sh_css_input_set_bayer_order( + mipi_info->raw_bayer_order); + sh_css_input_set_format(mipi_info->input_format); + sh_css_input_configure_port(mipi_info->port, + mipi_info->num_lanes, + 0xffff4); + } else { + /*Use default MIPI configuration*/ + v4l2_info(&atomisp_dev, + "no sensor config info\n"); + sh_css_input_set_bayer_order(sh_css_bayer_order_grbg); + sh_css_input_set_format(SH_CSS_INPUT_FORMAT_RAW_10); + v4l2_info(&atomisp_dev, "MIPI 2 lane\n"); + sh_css_input_configure_port(SH_CSS_MIPI_PORT_4LANE, + 2, 0xffff4); + } +} + +static int atomisp_set_fmt_to_isp(struct video_device *vdev, + struct sh_css_frame_info *output_info, + struct sh_css_frame_info *raw_output_info, + int width, int height, + unsigned int pixelformat) +{ + struct camera_mipi_info *mipi_info; + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_format_bridge *format; + int effective_input_width = pipe->format->in.width; + int effective_input_height = pipe->format->in.height; + int ret; + + format = get_atomisp_format_bridge(pixelformat); + if (format == NULL) + return -EINVAL; + + isp->main_format->out_sh_fmt = format->sh_fmt; + pipe->format->out.pixelformat = pixelformat; + + if (isp->inputs[isp->input_curr].type != TEST_PATTERN && + isp->inputs[isp->input_curr].type != FILE_INPUT) { + mipi_info = atomisp_to_sensor_mipi_info( + isp->inputs[isp->input_curr].camera); + atomisp_set_sensor_mipi_to_isp(mipi_info); + + if ((format->sh_fmt == SH_CSS_FRAME_FORMAT_RAW) && + raw_output_format_match_input( + mipi_info->input_format, pixelformat)) + return -EINVAL; + } + + sh_css_input_set_resolution(isp->input_format->out.width, + isp->input_format->out.height); + + if (sh_css_input_set_effective_resolution(effective_input_width, + effective_input_height)) + return -EINVAL; + + v4l2_info(&atomisp_dev, "effective resolution %dx%d\n", + effective_input_width, effective_input_height); + + if (!isp->vf_format) + isp->vf_format = + kzalloc(sizeof(struct atomisp_video_pipe_format), + GFP_KERNEL); + if (!isp->vf_format) { + v4l2_err(&atomisp_dev, "Failed to alloc vf_format memory\n"); + return -ENOMEM; + } + + isp->vf_format->out.width = 640; + isp->vf_format->out.height = 480; + isp->vf_format->out_sh_fmt = SH_CSS_FRAME_FORMAT_YUV420; + + if ((isp->vf_format->out.width > width) || + (isp->vf_format->out.height > height)) { + if ((width < 640) || (height < 480)) { + isp->vf_format->out.width = width; + isp->vf_format->out.height = height; + } else { + isp->vf_format->out.width = 640; + isp->vf_format->out.height = 480; + } + } + + switch (isp->sw_contex.run_mode) { + case CI_MODE_PREVIEW: + if (sh_css_preview_configure_pp_input( + effective_input_width, effective_input_height)) + return -EINVAL; + + if (sh_css_preview_configure_output(width, height, + format->sh_fmt)) + return -EINVAL; + + if (sh_css_preview_get_output_frame_info(output_info)) + return -EINVAL; + break; + case CI_MODE_VIDEO: + if (sh_css_video_configure_viewfinder( + isp->vf_format->out.width, + isp->vf_format->out.height, + isp->vf_format->out_sh_fmt)) + return -EINVAL; + + if (sh_css_video_configure_output(width, height, + format->sh_fmt)) + return -EINVAL; + + if (sh_css_video_get_output_frame_info(output_info)) + return -EINVAL; + break; + default: + if (format->sh_fmt == SH_CSS_FRAME_FORMAT_RAW) { + v4l2_info(&atomisp_dev, "ISP raw mode\n"); + sh_css_capture_set_mode(SH_CSS_CAPTURE_MODE_RAW); + } + + sh_css_capture_enable_online(isp->params.online_process); + + if (sh_css_capture_configure_pp_input( + effective_input_width, + effective_input_height)) + return -EINVAL; + + if (sh_css_capture_configure_viewfinder( + isp->vf_format->out.width, + isp->vf_format->out.height, + isp->vf_format->out_sh_fmt)) + return -EINVAL; + + if (sh_css_capture_configure_output(width, height, + format->sh_fmt)) + return -EINVAL; + + ret = sh_css_capture_get_output_frame_info(output_info); + if (ret) { + v4l2_err(&atomisp_dev, + "Resolution set mismatach error %d\n", + ret); + return -EINVAL; + } + + if (!isp->params.online_process) + if (sh_css_capture_get_output_raw_frame_info( + raw_output_info)) + return -EINVAL; + if (isp->sw_contex.run_mode != CI_MODE_STILL_CAPTURE) { + v4l2_err(&atomisp_dev, + "Need to set the running mode first\n"); + isp->sw_contex.run_mode = CI_MODE_STILL_CAPTURE; + } + break; + } + + atomisp_update_grid_info(isp); + + /* Free the raw_dump buffer first */ + sh_css_frame_free(isp->raw_output_frame); + isp->raw_output_frame = NULL; + + if (!isp->params.online_process && !isp->sw_contex.file_input) { + if (sh_css_frame_allocate_from_info(&isp->raw_output_frame, + raw_output_info)) + return -ENOMEM; + } + + return 0; +} + +static int atomisp_get_effective_resolution(struct atomisp_device *isp, + unsigned int pixelformat, + int out_width, int out_height, + int padding_w, int padding_h) +{ + struct atomisp_format_bridge *format; + struct v4l2_pix_format *in_fmt = &isp->main_format->in; + struct v4l2_pix_format *out_fmt = &isp->input_format->out; + unsigned int no_padding_w, no_padding_h; + + format = get_atomisp_format_bridge(pixelformat); + if (format == NULL) + return -EINVAL; + if (!isp->params.yuv_ds_en) { + in_fmt->width = out_width; + in_fmt->height = out_height; + return 0; + } + no_padding_w = out_fmt->width - padding_w; + no_padding_h = out_fmt->height - padding_h; + /* enable YUV downscaling automatically */ + if (no_padding_w > out_width || no_padding_h > out_height) { + /* keep a right ratio of width and height*/ + in_fmt->width = no_padding_w; + in_fmt->height = DIV_RND_UP(in_fmt->width * out_height, + out_width); + if (in_fmt->height > no_padding_h) { + in_fmt->height = no_padding_h; + in_fmt->width = DIV_RND_UP(in_fmt->height * out_width, + out_height); + + } + in_fmt->width = (in_fmt->width & + ~(ATOM_ISP_STEP_WIDTH - 1)); + in_fmt->height = (in_fmt->height & + ~(ATOM_ISP_STEP_HEIGHT - 1)); + if (isp->params.gdc_cac_en) { + if (in_fmt->width > ISP_POST_GDC_MAX_OUTPUT_WIDTH) + in_fmt->width = ISP_POST_GDC_MAX_OUTPUT_WIDTH; + if (in_fmt->height > ISP_POST_GDC_MAX_OUTPUT_HEIGHT) + in_fmt->height = ISP_POST_GDC_MAX_OUTPUT_HEIGHT; + } + } else { + in_fmt->width = out_width; + in_fmt->height = out_height; + } + return 0; +} + +static void atomisp_set_dis_envelop(struct atomisp_device *isp, + unsigned int width, unsigned int height, + unsigned int *dvs_env_w, + unsigned int *dvs_env_h) +{ + /* if subdev type is SOC camera,we do not need to set DVS */ + if (isp->inputs[isp->input_curr].type == SOC_CAMERA) + isp->params.video_dis_en = 0; + + if (isp->params.video_dis_en && + isp->sw_contex.run_mode == CI_MODE_VIDEO) { + /* envelope is 20% of the output resolution */ + /* + * dvs envelope cannot be round up. + * it would cause ISP timeout and color switch issue + */ + *dvs_env_w = width / 5; + *dvs_env_h = height / 5; + sh_css_video_set_dis_envelope(*dvs_env_w, *dvs_env_h); + } else { + /* if DVS gets disabled, make sure it's indeed turned off */ + sh_css_video_set_dis_envelope(0, 0); + } +} + +static int atomisp_set_fmt_to_snr(struct atomisp_device *isp, + struct v4l2_format *f, unsigned int pixelformat, + unsigned int padding_w, unsigned int padding_h, + unsigned int dvs_env_w, unsigned int dvs_env_h) +{ + struct atomisp_format_bridge *format; + struct v4l2_mbus_framefmt snr_mbus_fmt; + struct v4l2_format snr_fmt; + struct atomisp_video_pipe *out_pipe = &isp->isp_subdev.video_in; + int ret; + + format = get_atomisp_format_bridge(pixelformat); + if (format == NULL) + return -EINVAL; + + if (!isp->sw_contex.file_input) { + v4l2_fill_mbus_format(&snr_mbus_fmt, &f->fmt.pix, + format->mbus_code); + snr_mbus_fmt.height += padding_h + dvs_env_h; + snr_mbus_fmt.width += padding_w + dvs_env_w; + + ret = v4l2_subdev_call( + isp->inputs[isp->input_curr].camera, + video, s_mbus_fmt, &snr_mbus_fmt); + if (ret) { + v4l2_err(&atomisp_dev, + "call s_mbus_fmt for sensor failed\n"); + + snr_fmt = *f; + snr_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + snr_fmt.fmt.pix.height += padding_h + dvs_env_h; + snr_fmt.fmt.pix.width += padding_w + dvs_env_w; + + /* + * In case the camera driver + * not support mbus function + */ + ret = v4l2_subdev_call( + isp->inputs[isp->input_curr].camera, + video, s_fmt, &snr_fmt); + if (ret) { + v4l2_err(&atomisp_dev, + "call s_fmt for sensor failed\n"); + return ret; + } + isp->input_format->out.width = + snr_fmt.fmt.pix.width; + isp->input_format->out.height = + snr_fmt.fmt.pix.height; + isp->input_format->out.pixelformat = + snr_fmt.fmt.pix.pixelformat; + } else { + isp->input_format->out.width = snr_mbus_fmt.width; + isp->input_format->out.height = snr_mbus_fmt.height; + isp->input_format->out.pixelformat = + snr_mbus_fmt.code; + } + + v4l2_info(&atomisp_dev, + "sensor output resolution %dx%d\n", + isp->input_format->out.width, + isp->input_format->out.height); + + } else { /* file input case */ + isp->input_format->out.width = out_pipe->out_fmt->width; + isp->input_format->out.height = out_pipe->out_fmt->height; + } + + if (isp->input_format->out.width < ATOM_ISP_STEP_WIDTH || + isp->input_format->out.height < ATOM_ISP_STEP_HEIGHT) + return -EINVAL; + + return 0; +} +void atomisp_get_yuv_ds_status(struct atomisp_device *isp, + unsigned int width, unsigned int height) +{ + /* no YUV downscaling if sensor output is 10% larger than isp output */ + unsigned int w_tmp = isp->input_format->out.width - + DIV_RND_UP(isp->input_format->out.width, 10); + unsigned int h_tmp = isp->input_format->out.height - + DIV_RND_UP(isp->input_format->out.height , 10); + /* + * yuv downscaling is not enabled in video binary, + * ,raw format output, soc sensor. effective resolution should + * be the same as isp output. + */ + if ((w_tmp < width && h_tmp < height) + || isp->sw_contex.run_mode == CI_MODE_VIDEO + || isp->sw_contex.bypass + || isp->sw_contex.file_input) + isp->params.yuv_ds_en = false; + else + isp->params.yuv_ds_en = true; + v4l2_info(&atomisp_dev, "yuv downscaling is %s.\n", + isp->params.yuv_ds_en ? "enabled" : "disabled"); + +} +int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) +{ + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_format_bridge *format_bridge; + struct sh_css_frame_info output_info, raw_output_info; + struct v4l2_format snr_fmt = *f; + unsigned int width = f->fmt.pix.width; + unsigned int height = f->fmt.pix.height; + unsigned int pixelformat = f->fmt.pix.pixelformat; + unsigned int sh_format; + unsigned int dvs_env_w = 0, + dvs_env_h = 0; + unsigned int padding_w = pad_w, + padding_h = pad_h; + bool res_overflow = false; + struct v4l2_streamparm sensor_parm; + int ret; + + if ((f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (f->type != V4L2_BUF_TYPE_PRIVATE)) { + v4l2_err(&atomisp_dev, "Wrong v4l2 buf type\n"); + return -EINVAL; + } + + format_bridge = get_atomisp_format_bridge(pixelformat); + if (format_bridge == NULL) + return -EINVAL; + + sh_format = format_bridge->sh_fmt; + if (!pipe->is_main) { + switch (isp->sw_contex.run_mode) { + case CI_MODE_VIDEO: + sh_css_video_configure_viewfinder( + width, height, sh_format); + sh_css_video_get_viewfinder_frame_info(&output_info); + break; + case CI_MODE_STILL_CAPTURE: + sh_css_capture_configure_viewfinder( + width, height, sh_format); + sh_css_capture_get_viewfinder_frame_info(&output_info); + break; + } + goto done; + } + + /* V4L2_BUF_TYPE_PRIVATE will set offline processing */ + if (f->type == V4L2_BUF_TYPE_PRIVATE) + isp->params.online_process = 0; + else + isp->params.online_process = 1; + + /* setting run mode to the sensor */ + sensor_parm.parm.capture.capturemode = isp->sw_contex.run_mode; + v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, s_parm, &sensor_parm); + + /* get sensor resolution and format */ + snr_fmt = *f; + atomisp_try_fmt(vdev, &snr_fmt, &res_overflow); + width = snr_fmt.fmt.pix.width; + height = snr_fmt.fmt.pix.height; + + /* + * bypass mode is enabled when sensor output format is not raw + * or isp output format is raw. + */ + if (isp->inputs[isp->input_curr].type != TEST_PATTERN && + (!is_pixelformat_raw(snr_fmt.fmt.pix.pixelformat) || + is_pixelformat_raw(pixelformat))) { + isp->sw_contex.bypass = true; + padding_h = 0; + padding_w = 0; + } else + isp->sw_contex.bypass = false; + + /* construct resolution supported by isp */ + if (res_overflow) { + width -= padding_w; + height -= padding_h; + /* app vs isp */ + width = min(width, (u32)ATOM_ISP_MAX_WIDTH); + height = min(height, (u32)ATOM_ISP_MAX_HEIGHT); + + width = max(width, (u32)ATOM_ISP_MIN_WIDTH); + height = max(height, (u32)ATOM_ISP_MIN_HEIGHT); + + width = width - width % ATOM_ISP_STEP_WIDTH; + height = height - height % ATOM_ISP_STEP_HEIGHT; + + f->fmt.pix.width = width; + f->fmt.pix.height = height; + } + + /* set dis envelop if video and dis are enabled */ + atomisp_set_dis_envelop(isp, width, height, &dvs_env_w, &dvs_env_h); + + if (!isp->input_format) + isp->input_format = + kzalloc(sizeof(struct atomisp_video_pipe_format), GFP_KERNEL); + if (!isp->input_format) { + v4l2_err(&atomisp_dev, "Failed to alloc input_format memory\n"); + return -ENOMEM; + } + + /* set format info to sensor */ + ret = atomisp_set_fmt_to_snr(isp, f, pixelformat, + padding_w, padding_h, + dvs_env_w, dvs_env_h); + if (ret) + return -EINVAL; + + /* Only main stream pipe will be here */ + isp->main_format = pipe->format; + if (!isp->main_format) { + v4l2_err(&atomisp_dev, "Internal error\n"); + return -EINVAL; + } + + atomisp_get_yuv_ds_status(isp, width, height); + + /* + * calculate effective solution to enable yuv downscaling and keep + * ratio of width and height + */ + ret = atomisp_get_effective_resolution(isp, pixelformat, width, height, + padding_w, padding_h); + if (ret) + return -EINVAL; + + /* set format to isp */ + ret = atomisp_set_fmt_to_isp(vdev, &output_info, &raw_output_info, + width, height, pixelformat); + if (ret) + return -EINVAL; +done: + pipe->format->out.width = width; + pipe->format->out.height = height; + pipe->format->out.pixelformat = pixelformat; + pipe->format->out.bytesperline = + DIV_RND_UP(format_bridge->depth * output_info.padded_width, 8); + pipe->format->out.sizeimage = + PAGE_ALIGN(height * pipe->format->out. bytesperline); + if (f->fmt.pix.field == V4L2_FIELD_ANY) + f->fmt.pix.field = V4L2_FIELD_NONE; + pipe->format->out.field = f->fmt.pix.field; + pipe->format->out_sh_fmt = sh_format; + + memcpy(&f->fmt.pix, &pipe->format->out, + sizeof(struct v4l2_pix_format)); + f->fmt.pix.priv = PAGE_ALIGN(pipe->format->out.width * + pipe->format->out.height * 2); + + pipe->capq.field = f->fmt.pix.field; + + v4l2_info(&atomisp_dev, + "ISP output resolution: %dx%d, format = %s\n", + pipe->format->out.width, pipe->format->out.height, + format_bridge->description); + return 0; +} + +int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f) +{ + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + enum sh_css_input_format sh_input_format; + int ret = 0; + + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&atomisp_dev, + "Wrong v4l2 buf type for output\n"); + return -EINVAL; + } + + switch (isp->sw_contex.output_mode) { + case OUTPUT_MODE_FILE: + ret = atomisp_try_fmt_file(isp, f); + if (ret) + return ret; + + pipe->out_fmt->pixelformat = f->fmt.pix.pixelformat; + pipe->out_fmt->framesize = f->fmt.pix.sizeimage; + pipe->out_fmt->imagesize = f->fmt.pix.sizeimage; + pipe->out_fmt->depth = get_pixel_depth(f->fmt.pix.pixelformat); + pipe->out_fmt->bytesperline = f->fmt.pix.bytesperline; + + pipe->out_fmt->bayer_order = f->fmt.pix.priv; + pipe->out_fmt->width = f->fmt.pix.width; + pipe->out_fmt->height = f->fmt.pix.height; + sh_input_format = get_sh_input_format( + pipe->out_fmt->pixelformat); + if (sh_input_format == -EINVAL) { + v4l2_err(&atomisp_dev, + "Wrong v4l2 format for output\n"); + return -EINVAL; + } + + sh_css_input_set_format(sh_input_format); + sh_css_input_set_mode(SH_CSS_INPUT_MODE_FIFO); + sh_css_input_set_bayer_order(pipe->out_fmt->bayer_order); + sh_css_input_configure_port(SH_CSS_MIPI_PORT_4LANE, 2, 0xffff4); + return 0; + + case OUTPUT_MODE_TEXT: + pipe->out_fmt->framesize = f->fmt.pix.sizeimage; + pipe->out_fmt->imagesize = f->fmt.pix.sizeimage; + return 0; + + default: + v4l2_err(&atomisp_dev, "Unspported output mode\n"); + return -EINVAL; + } +} + +/* + * atomisp_acc_get_fw - Search for firmware with given handle + * + * This function will search for given handle until: + * - Handle is found + * - Reached end of isp->acc_fw[] array + * - Function has found total number of non-NULL slots + */ +static struct sh_css_acc_fw * +atomisp_acc_get_fw(struct atomisp_device *isp, unsigned int handle) +{ + int i, count; + + if (isp->acc_fw_count == 0) + return NULL; + + for (i = 0, count = isp->acc_fw_count; + count > 0 && i < ATOMISP_ACC_FW_MAX; i++) { + if (isp->acc_fw[i] == NULL) + continue; + if (isp->acc_fw[i]->handle == handle) + break; + count--; + } + + return i < ATOMISP_ACC_FW_MAX || count > 0 ? isp->acc_fw[i] : NULL; +} + +/* + * atomisp_acc_get_index - Search for firmware index in isp->acc_fw[] array + * + * This function will search for firmware index until: + * - Given firmware is found + * - Reached end of isp->acc_fw[] array + * - Function has searched all non-NULL slots + */ +static int +atomisp_acc_get_index(struct atomisp_device *isp, struct sh_css_acc_fw *fw) +{ + int i, count; + + if (isp->acc_fw_count == 0) + return -EINVAL; + + for (i = 0, count = isp->acc_fw_count; + count > 0 && i < ATOMISP_ACC_FW_MAX; i++) { + if (isp->acc_fw[i] == fw) + break; + if (isp->acc_fw[i] != NULL) + count--; + } + + return i < ATOMISP_ACC_FW_MAX || count > 0 ? i : -EINVAL; +} + +static void +atomisp_acc_fw_free_args(struct atomisp_device *isp, struct sh_css_acc_fw *fw) +{ + int i = atomisp_acc_get_index(isp, fw); + + /* Sanity check */ + if (i < 0) { + WARN_ON(1); + return; + } + + /* Free `host' data for all arguments */ + for (i = 0; ; i++) { + union host *host; + enum sh_css_acc_arg_type type; + + host = sh_css_argument_get_host(fw, i); + if (sh_css_argument_set_host(fw, i, NULL)) + break; /* Failure: all arguments freed */ + if (!host) + continue; + type = sh_css_argument_type(fw, i); + switch (type) { + case SH_CSS_ACC_ARG_SCALAR_IN: + kfree(host->scalar.kernel_ptr); + break; + case ATOMISP_ACC_ARG_FRAME: + case SH_CSS_ACC_ARG_PTR_IN: + case SH_CSS_ACC_ARG_PTR_OUT: + case SH_CSS_ACC_ARG_PTR_IO: + hrt_isp_css_mm_free(host->ptr.hmm_ptr); + break; + default: + v4l2_err(&atomisp_dev, "%s: Invalid argument type.\n", + __func__); + break; + } + kfree(host); + } +} + +static void +atomisp_acc_fw_free(struct atomisp_device *isp, struct sh_css_acc_fw *fw) +{ + int i = atomisp_acc_get_index(isp, fw); + + /* Sanity check */ + if (i < 0) { + WARN_ON(1); + return; + } + + isp->acc_fw[i] = NULL; + isp->acc_fw_count--; + + kfree(fw); +} + +static struct sh_css_acc_fw * +atomisp_acc_fw_alloc(struct atomisp_device *isp, + struct atomisp_acc_fw_load *user_fw) +{ + struct sh_css_acc_fw *fw; + int ret; + int i; + + /* REVISIT: does size need to be multiple of page size? */ + fw = kzalloc(user_fw->size, GFP_KERNEL); + + if (fw == NULL) { + v4l2_err(&atomisp_dev, "%s: Failed to alloc acc fw blob\n", + __func__); + ret = -ENOMEM; + goto err; + } + + ret = copy_from_user(fw, user_fw->data, user_fw->size); + if (ret) { + v4l2_err(&atomisp_dev, "%s: Failed to copy acc fw blob\n", + __func__); + ret = -EIO; + goto err; + } + + mutex_lock(&isp->isp_lock); + if (isp->acc_fw_count >= ATOMISP_ACC_FW_MAX) { + mutex_unlock(&isp->isp_lock); + ret = -EINVAL; + goto err; + } + + /* Find first free slot */ + for (i = 0; i < ATOMISP_ACC_FW_MAX; i++) { + if (isp->acc_fw[i] == NULL) + break; + } + user_fw->fw_handle = isp->acc_fw_handle; + fw->handle = isp->acc_fw_handle; + isp->acc_fw[i] = fw; + + isp->acc_fw_handle++; + isp->acc_fw_count++; + mutex_unlock(&isp->isp_lock); + + return fw; + +err: + kfree(fw); + return ERR_PTR(ret); +} + +int atomisp_acc_load(struct atomisp_device *isp, + struct atomisp_acc_fw_load *user_fw) +{ + struct sh_css_acc_fw *fw; + int ret; + + mutex_lock(&isp->input_lock); + fw = atomisp_acc_fw_alloc(isp, user_fw); + if (IS_ERR(fw)) { + v4l2_err(&atomisp_dev, "%s: Acceleration firmware allocation " + "failed\n", __func__); + ret = PTR_ERR(fw); + goto out; + } + + mutex_lock(&isp->isp_lock); + ret = sh_css_load_acceleration(fw); + if (ret) { + atomisp_acc_fw_free(isp, fw); + mutex_unlock(&isp->isp_lock); + v4l2_err(&atomisp_dev, "%s: Failed to load acceleration " + "firmware\n", __func__); + ret = -EAGAIN; + goto out; + } + mutex_unlock(&isp->isp_lock); + init_completion(&isp->acc_fw_complete); + +out: + mutex_unlock(&isp->input_lock); + return ret; +} + +int atomisp_acc_unload(struct atomisp_device *isp, unsigned int *handle) +{ + struct sh_css_acc_fw *fw; + int ret = 0; + + mutex_lock(&isp->input_lock); + fw = atomisp_acc_get_fw(isp, *handle); + + if (fw == NULL) { + v4l2_err(&atomisp_dev, "%s: Invalid acceleration firmware " + "handle\n", __func__); + ret = -EINVAL; + goto out; + } + + if (!fw->header.loaded) { + ret = -EINVAL; + goto out; + } + + if (isp->marked_fw_for_unload != NULL) { + v4l2_err(&atomisp_dev, "%s: Acceleration firmware unload " + "pending\n", __func__); + ret = -EBUSY; + goto out; + } + + if (isp->sw_contex.isp_streaming == false) { + /* We're not streaming, so it's safe to unload now */ + mutex_lock(&isp->isp_lock); + atomisp_acc_fw_free_args(isp, fw); + sh_css_unload_acceleration(fw); + atomisp_acc_fw_free(isp, fw); + mutex_unlock(&isp->isp_lock); + ret = 0; + goto out; + } + + /* + * If we're streaming, unload should be synced with end of frame. + * We mark it for unload on atomisp_work() and wait for it. + */ + init_completion(&isp->acc_unload_fw_complete); + isp->marked_fw_for_unload = fw; + mutex_unlock(&isp->input_lock); + wait_for_completion_timeout(&isp->acc_unload_fw_complete, 1 * HZ); + + return 0; + +out: + mutex_unlock(&isp->input_lock); + return ret; +} + +int atomisp_acc_set_arg(struct atomisp_device *isp, + struct atomisp_acc_fw_arg *fw_arg) +{ + struct sh_css_acc_fw *fw; + enum atomisp_acc_arg_type type; + void *frame_ptr; + unsigned int handle = fw_arg->fw_handle; + unsigned int index = fw_arg->index; + unsigned int size = fw_arg->size; + unsigned int pgnr; + union host *host; + int ret; + + mutex_lock(&isp->input_lock); + fw = atomisp_acc_get_fw(isp, handle); + if (fw == NULL) { + v4l2_err(&atomisp_dev, "Invalid fw handle\n"); + ret = -EINVAL; + goto out; + } + + ret = sh_css_set_acceleration_argument(fw, index, NULL, 0); + if (ret != 0) + goto out; + + /* Allocate `host' union if not already done so */ + host = (union host *)sh_css_argument_get_host(fw, index); + + if (!host) { + /* Allocate new */ + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) { + ret = -ENOMEM; + goto out; + } + ret = sh_css_argument_set_host(fw, index, host); + if (ret != 0) { + kfree(host); + goto out; + } + } + + type = sh_css_argument_type(fw, index); + switch (type) { + case SH_CSS_ACC_ARG_SCALAR_IN: + /* Free old argument data if one already exists */# + kfree(host->scalar.kernel_ptr); + + /* Allocate and copy data into kernel space */ + host->scalar.kernel_ptr = kmalloc(size, GFP_KERNEL); + if (!host->scalar.kernel_ptr) + return -ENOMEM; + if (copy_from_user(host->scalar.kernel_ptr, + fw_arg->value, size)) { + kfree(host->scalar.kernel_ptr); + host->scalar.kernel_ptr = NULL; + return -EFAULT; + } + host->scalar.size = size; + host->scalar.user_ptr = fw_arg->value; + ret = sh_css_set_acceleration_argument(fw, index, + host->scalar.kernel_ptr, size); + break; + case ATOMISP_ACC_ARG_FRAME: + case SH_CSS_ACC_ARG_PTR_IN: + case SH_CSS_ACC_ARG_PTR_OUT: + case SH_CSS_ACC_ARG_PTR_IO: + /* Free old argument data if one already exists */ + hrt_isp_css_mm_free(host->ptr.hmm_ptr); + pgnr = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + + mutex_lock(&isp->isp_lock); + hrt_isp_css_mm_set_user_ptr((unsigned int)fw_arg->value, pgnr); + frame_ptr = hrt_isp_css_mm_alloc(size); + hrt_isp_css_mm_set_user_ptr(0, 0); + mutex_unlock(&isp->isp_lock); + + if (IS_ERR_OR_NULL(frame_ptr)) { + v4l2_err(&atomisp_dev, "%s: Failed to allocate frame " + "for acceleration firmware\n", __func__); + ret = -EINVAL; + goto out; + } + + host->ptr.hmm_ptr = frame_ptr; + ret = sh_css_set_acceleration_argument(fw, index, frame_ptr, + size); + break; + + + default: + v4l2_err(&atomisp_dev, "Invalid fw argument type\n"); + ret = -EINVAL; + break; + } + +out: + mutex_unlock(&isp->input_lock); + return ret; +} + +int atomisp_acc_start(struct atomisp_device *isp, unsigned int *handle) +{ + struct sh_css_acc_fw *fw; + unsigned int ret; + + mutex_lock(&isp->input_lock); + mutex_lock(&isp->isp_lock); + fw = atomisp_acc_get_fw(isp, *handle); + if (fw == NULL) { + v4l2_err(&atomisp_dev, "%s: Invalid firmware handle\n", + __func__); + mutex_unlock(&isp->isp_lock); + ret = -EINVAL; + goto out; + } + + ret = sh_css_start_acceleration(fw); + mutex_unlock(&isp->isp_lock); + if (ret) { + v4l2_err(&atomisp_dev, "%s: Failed to start acceleration " + "firmware\n", __func__); + ret = -EINVAL; + goto out; + } + + /* Initialize the interrupt here if it's a standalone binary */ + if (fw->header.type == ATOMISP_ACC_STANDALONE) + INIT_COMPLETION(isp->acc_fw_complete); + +out: + mutex_unlock(&isp->input_lock); + return ret; +} + +int atomisp_acc_wait(struct atomisp_device *isp, unsigned int *handle) +{ + struct sh_css_acc_fw *fw; + unsigned int time_left; + + mutex_lock(&isp->input_lock); + mutex_lock(&isp->isp_lock); + + fw = atomisp_acc_get_fw(isp, *handle); + + mutex_unlock(&isp->isp_lock); + mutex_unlock(&isp->input_lock); + + if (fw == NULL) { + v4l2_err(&atomisp_dev, "Invalid fw handle\n"); + return -EINVAL; + } + + if (fw->header.type != ATOMISP_ACC_STANDALONE) + return -EINVAL; + + time_left = + wait_for_completion_timeout(&isp->acc_fw_complete, + 1 * HZ); + + /* Timeout to get the acc fw */ + if (time_left == 0) { + v4l2_err(&atomisp_dev, + "%s: Acceleration firmware timeout to finish\n", + __func__); + return -EINVAL; + } + + mutex_lock(&isp->isp_lock); + sh_css_acceleration_done(fw); + mutex_unlock(&isp->isp_lock); + + return 0; +} + +int atomisp_acc_abort(struct atomisp_device *isp, + struct atomisp_acc_fw_abort *abort) +{ + struct sh_css_acc_fw *fw; + int ret = 0; + + mutex_lock(&isp->input_lock); + mutex_lock(&isp->isp_lock); + + fw = atomisp_acc_get_fw(isp, abort->fw_handle); + if (fw == NULL) { + v4l2_err(&atomisp_dev, "%s: Invalid firmware handle\n", + __func__); + ret = -EINVAL; + goto out; + } + + sh_css_abort_acceleration(fw, abort->timeout); + +out: + mutex_unlock(&isp->isp_lock); + mutex_unlock(&isp->input_lock); + + return ret; +} + +int atomisp_save_iunit_reg(struct atomisp_device *isp) +{ + /*Clear those register value first*/ + isp->hw_contex.pcicmdsts = 0; + isp->hw_contex.ispmmadr = 0; + isp->hw_contex.msicap = 0; + isp->hw_contex.msi_addr = 0; + isp->hw_contex.msi_data = 0; + isp->hw_contex.intr = 0; + isp->hw_contex.interrupt_control = 0; + isp->hw_contex.pmcs = 0; + isp->hw_contex.cg_dis = 0; + isp->hw_contex.i_control = 0; + isp->hw_contex.pci_cmd = 0; + isp->hw_contex.csi_rcomp_config = 0; + isp->hw_contex.csi_afe_dly = 0; + isp->hw_contex.csi_control = 0; + + isp->hw_contex.pcicmdsts = atomisp_msg_read32(isp, IUNIT_PORT, + PCICMDSTS); + isp->hw_contex.ispmmadr = atomisp_msg_read32(isp, IUNIT_PORT, + ISPMMADR); + isp->hw_contex.msicap = atomisp_msg_read32(isp, IUNIT_PORT, + MSI_CAPID); + isp->hw_contex.msi_addr = atomisp_msg_read32(isp, IUNIT_PORT, + MSI_ADDRESS); + isp->hw_contex.msi_data = atomisp_msg_read32(isp, IUNIT_PORT, + MSI_DATA); + isp->hw_contex.intr = atomisp_msg_read32(isp, IUNIT_PORT, INTR); + isp->hw_contex.interrupt_control = atomisp_msg_read32(isp, IUNIT_PORT, + INTR_CTL); + isp->hw_contex.pmcs = atomisp_msg_read32(isp, IUNIT_PORT, PMCS); + isp->hw_contex.cg_dis = atomisp_msg_read32(isp, IUNIT_PORT, CG_DIS); + isp->hw_contex.i_control = atomisp_msg_read32(isp, IUNIT_PORT, + I_CONTROL); + isp->hw_contex.csi_rcomp_config = atomisp_msg_read32(isp, IUNITPHY_PORT, + CSI_RCOMP); + isp->hw_contex.csi_afe_dly = atomisp_msg_read32(isp, IUNITPHY_PORT, + CSI_AFE); + isp->hw_contex.csi_control = atomisp_msg_read32(isp, IUNITPHY_PORT, + CSI_CONTROL); + + pci_read_config_word(isp->pdev, PCI_COMMAND, &isp->hw_contex.pci_cmd); + + + return 0; +} + +int atomisp_restore_iunit_reg(struct atomisp_device *isp) +{ + pci_write_config_word(isp->pdev, PCI_COMMAND, isp->hw_contex.pci_cmd); + + atomisp_msg_write32(isp, IUNIT_PORT, PCICMDSTS, + isp->hw_contex.pcicmdsts); + atomisp_msg_write32(isp, IUNIT_PORT, ISPMMADR, + isp->hw_contex.ispmmadr); + atomisp_msg_write32(isp, IUNIT_PORT, MSI_CAPID, + isp->hw_contex.msicap); + atomisp_msg_write32(isp, IUNIT_PORT, MSI_ADDRESS, + isp->hw_contex.msi_addr); + atomisp_msg_write32(isp, IUNIT_PORT, MSI_DATA, + isp->hw_contex.msi_data); + atomisp_msg_write32(isp, IUNITPHY_PORT, CSI_CONTROL, 0xFF0003); + atomisp_msg_write32(isp, IUNIT_PORT, INTR, isp->hw_contex.intr); + atomisp_msg_write32(isp, IUNIT_PORT, INTR_CTL, + isp->hw_contex.interrupt_control); + atomisp_msg_write32(isp, IUNIT_PORT, PMCS, isp->hw_contex.pmcs); + atomisp_msg_write32(isp, IUNIT_PORT, CG_DIS, isp->hw_contex.cg_dis); + atomisp_msg_write32(isp, IUNIT_PORT, I_CONTROL, + isp->hw_contex.i_control); + atomisp_msg_write32(isp, IUNITPHY_PORT, CSI_RCOMP, + isp->hw_contex.csi_rcomp_config); + atomisp_msg_write32(isp, IUNITPHY_PORT, CSI_AFE, + isp->hw_contex.csi_afe_dly); + atomisp_msg_write32(isp, IUNITPHY_PORT, CSI_CONTROL, + isp->hw_contex.csi_control); + + return 0; +} + +/*Turn off ISP power island*/ +int atomisp_ospm_power_island_down(struct atomisp_device *isp) +{ + u32 pwr_cnt = 0; + + /* power down DPHY */ + pwr_cnt = atomisp_msg_read32(isp, IUNITPHY_PORT, CSI_CONTROL); + pwr_cnt |= 0x300; + atomisp_msg_write32(isp, IUNITPHY_PORT, CSI_CONTROL, pwr_cnt); + + /* Power down IPH/ISP */ + if (pmu_nc_set_power_state(APM_ISP_ISLAND | APM_IPH_ISLAND, + OSPM_ISLAND_DOWN, APM_REG_TYPE)) + return -EINVAL; + + isp->sw_contex.power_state = ATOM_ISP_POWER_DOWN; + return 0; +} + +/*Turn on ISP power island*/ +int atomisp_ospm_power_island_up(struct atomisp_device *isp) +{ + u32 pwr_cnt = 0; + + /* Power up IPH/ISP */ + if (pmu_nc_set_power_state(APM_ISP_ISLAND | APM_IPH_ISLAND, + OSPM_ISLAND_UP, APM_REG_TYPE)) + return -EINVAL; + + /* power on DPHY */ + pwr_cnt = atomisp_msg_read32(isp, IUNITPHY_PORT, CSI_CONTROL); + pwr_cnt &= ~0x300; + atomisp_msg_write32(isp, IUNITPHY_PORT, CSI_CONTROL, pwr_cnt); + + isp->sw_contex.power_state = ATOM_ISP_POWER_UP; + return 0; +} + + +int atomisp_exif_makernote(struct atomisp_device *isp, + void *config) +{ + struct atomisp_makernote_info *arg = + (struct atomisp_makernote_info *)config; + struct v4l2_control ctrl; + + ctrl.id = V4L2_CID_FOCAL_ABSOLUTE; + if (v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, g_ctrl, &ctrl)) + v4l2_warn(&atomisp_dev, "failed to g_ctrl for focal length\n"); + else + arg->focal_length = ctrl.value; + + ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE; + if (v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, g_ctrl, &ctrl)) + v4l2_warn(&atomisp_dev, "failed to g_ctrl for f-number\n"); + else + arg->f_number_curr = ctrl.value; + + ctrl.id = V4L2_CID_FNUMBER_RANGE; + if (v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, g_ctrl, &ctrl)) + v4l2_warn(&atomisp_dev, + "failed to g_ctrl for f number range\n"); + else + arg->f_number_range = ctrl.value; + + return 0; +} + +int atomisp_flash_enable(struct atomisp_device *isp, int num_frames) +{ + if (num_frames <= 0) + return -EINVAL; + /* a requested flash is still in progress. */ + if (isp->params.num_flash_frames) + return -EBUSY; + + isp->params.num_flash_frames = num_frames; + return 0; +} diff --git a/drivers/media/video/atomisp/atomisp_cmd.h b/drivers/media/video/atomisp/atomisp_cmd.h new file mode 100644 index 0000000..7598c8a --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_cmd.h @@ -0,0 +1,278 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __ATOMISP_CMD_H__ +#define __ATOMISP_CMD_H__ + +#include "atomisp_common.h" +#include + +#define DIV_RND_UP(a, b) (((a) + (b) - 1) / b) +#define MSI_ENABLE_BIT 16 +#define INTR_DISABLE_BIT 10 +#define BUS_MASTER_ENABLE 2 +#define MEMORY_SPACE_ENABLE 1 +#define INTR_IER 24 +#define INTR_IIR 16 + +/* + * Helper function + */ + +struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd); +struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev); + + +extern void __iomem *atomisp_io_base; + +static inline void __iomem *atomisp_get_io_virt_addr(unsigned int address) +{ + unsigned int ret = 0; + ret = ((unsigned int)atomisp_io_base) + (address & 0x003FFFFF); + return (void __iomem *)ret; +} + +/* + * Interrupt functions + */ +void atomisp_msi_irq_init(struct atomisp_device *isp, struct pci_dev *dev); +void atomisp_msi_irq_uninit(struct atomisp_device *isp, struct pci_dev *dev); +irqreturn_t atomisp_isr(int irq, void *dev); +void atomisp_work(struct work_struct *work); +int atomisp_get_frame_pgnr(const struct sh_css_frame *frame, u32 * p_pgnr); + +/* + * Get internal fmt according to V4L2 fmt + */ + +int atomisp_is_pixelformat_supported(u32 pixelformat); +bool atomisp_is_viewfinder_support(struct atomisp_device *isp); + +/* + * ISP features control function + */ + +/* + * Function to enable/disable lens geometry distortion correction (GDC) and + * chromatic aberration correction (CAC) + */ +int atomisp_gdc_cac(struct atomisp_device *isp, int flag, __s32 * value); + +/* + * Function to enable/disable extra nosie reduction (XNR) in low light + * condition + */ +int atomisp_xnr(struct atomisp_device *isp, int flag, int *arg); + +/* + * Function to configure bayer nosie reduction + */ +int atomisp_bayer_nr(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to configure temporal nosie reduction (TNR) + */ +int atomisp_tnr(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to get histogram data for image frame + */ +int atomisp_histogram(struct atomisp_device *isp, + int flag, void *config); + +/* + * Function to configure black level compensation + */ +int atomisp_black_level(struct atomisp_device *isp, int flag, void *config); + +/* + * Function to configure Ycc nosie reduction + */ +int atomisp_ycc_nr(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to configure edge enhancement + */ +int atomisp_ee(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to update Gamma table for gamma, brightness and contrast config + */ +int atomisp_gamma(struct atomisp_device *isp, int flag, + void *config); +/* + * Function to update Ctc table for Chroma Enhancement + */ +int atomisp_ctc(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to update Gdc table for gdc + */ +int atomisp_gdc_cac_table(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to update table for macc + */ +int atomisp_macc_table(struct atomisp_device *isp, int flag, + void *config); +/* + * Function to set/get image stablization statistics + */ +int atomisp_dis_stat(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to set/get 3A stat from isp + */ +int atomisp_3a_stat(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to set/get isp parameters to isp + */ +int atomisp_param(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to configure color effect of the image + */ +int atomisp_color_effect(struct atomisp_device *isp, int flag, __s32 *effect); + +/* + * Function to configure bad pixel correction + */ +int atomisp_bad_pixel(struct atomisp_device *isp, int flag, __s32 *value); + +/* + * Function to configure bad pixel correction params + */ +int atomisp_bad_pixel_param(struct atomisp_device *isp, int flag, + void *config); + +int atomisp_dis_vector(struct atomisp_device *isp, + void *arg); + +/* + * Function to enable/disable video image stablization + */ +int atomisp_video_stable(struct atomisp_device *isp, int flag, __s32 * value); + +/* + * Function to configure fixed pattern noise + */ +int atomisp_fixed_pattern(struct atomisp_device *isp, int flag, __s32 * value); + +/* + * Function to configure fixed pattern noise table + */ +int atomisp_fixed_pattern_table(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to configure vf overlay image + */ +int atomisp_vf_overlay(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to configure false color correction + */ +int atomisp_false_color(struct atomisp_device *isp, int flag, __s32 * value); + +/* + * Function to configure false color correction params + */ +int atomisp_false_color_param(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to configure white balance params + */ +int atomisp_white_balance_param(struct atomisp_device *isp, int flag, + void *config); + +int atomisp_3a_config_param(struct atomisp_device *isp, int flag, + void *config); + +/* + * Function to enable/disable lens shading correction + */ +int atomisp_shading_correction(struct atomisp_device *isp, int flag, + __s32 *value); + +/* + * Function to setup digital zoom + */ +int atomisp_digital_zoom(struct atomisp_device *isp, int flag, __s32 * value); + +int atomisp_get_sensor_mode_data(struct atomisp_device *isp, + void *config); + +int atomisp_get_fmt(struct video_device *vdev, struct v4l2_format *f); + + +/* This function looks up the closest available resolution. */ +int atomisp_try_fmt(struct video_device *vdev, struct v4l2_format *f, + bool *res_overflow); + +int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f); +int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f); + +int atomisp_save_iunit_reg(struct atomisp_device *isp); +int atomisp_restore_iunit_reg(struct atomisp_device *isp); + +int atomisp_ospm_power_island_down(struct atomisp_device *isp); +int atomisp_ospm_power_island_up(struct atomisp_device *isp); +int atomisp_exif_makernote(struct atomisp_device *isp, + void *config); + +void atomisp_free_internal_buffers(struct atomisp_device *isp); +void atomisp_free_3a_buffers(struct atomisp_device *isp); +void atomisp_free_dis_buffers(struct atomisp_device *isp); + +int atomisp_flash_enable(struct atomisp_device *isp, int num_frames); + +int atomisp_acc_load(struct atomisp_device *isp, + struct atomisp_acc_fw_load *fw); + +int atomisp_acc_unload(struct atomisp_device *isp, + unsigned int *handler); + +int atomisp_acc_set_arg(struct atomisp_device *isp, + struct atomisp_acc_fw_arg *fw_arg); + +int atomisp_acc_start(struct atomisp_device *isp, + unsigned int *handler); + +int atomisp_acc_wait(struct atomisp_device *isp, + unsigned int *handler); + +int atomisp_acc_abort(struct atomisp_device *isp, + struct atomisp_acc_fw_abort *abort); +#endif diff --git a/drivers/media/video/atomisp/atomisp_common.h b/drivers/media/video/atomisp/atomisp_common.h new file mode 100644 index 0000000..6db77ad --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_common.h @@ -0,0 +1,183 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __ATOMISP_COMMON_H__ +#define __ATOMISP_COMMON_H__ + +#include +#include +#include +#include +#include /* atomisp_dbg */ +#include /* atomisp_dbg */ +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for kmalloc */ +#include /* for GFP_ATOMIC */ +#include /* for DMA */ +#include /* for runtime pm */ +#include +#include /* ioremap */ +#include /* access_ok */ +#include /* access_ok */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "atomisp_internal.h" + +extern int dbg_level; +extern int mipicsi_flag; +extern int pad_w; +extern int pad_h; + +#define PUNIT_PORT 0x04 +#define IUNIT_PORT 0x08 +#define IUNITPHY_PORT 0x09 + +#define CSI_RCOMP 0x00 +#define PCICMDSTS 0x01 +#define CSI_AFE 0x02 +#define CSI_CONTROL 0x03 +#define ISPMMADR 0x04 +#define INTR 0x0f +#define MSI_CAPID 0x24 +#define MSI_ADDRESS 0x25 +#define MSI_DATA 0x26 +#define INTR_CTL 0x27 +#define PMCS 0x35 +#define CG_DIS 0x36 +#define I_CONTROL 0x3f +#define OR1 0x72 +#define APMBA 0x7a + +#define PCI_MSI_ADDR 0x94 +#define PCI_MSI_DATA 0x98 +#define PCI_PRI_D0 0xd0 +#define PCI_PRI_D4 0xd4 +#define PCI_MEM_ACCESS 0x100002 + +struct atomisp_tvnorm { + char *name; + v4l2_std_id id; + u32 cxiformat; + u32 cxoformat; +}; + +struct atomisp_format_bridge { + unsigned int pixelformat; + unsigned int depth; + enum v4l2_mbus_pixelcode mbus_code; + enum sh_css_frame_format sh_fmt; + unsigned char description[32]; /* the same as struct v4l2_fmtdesc */ +}; + +struct atomisp_resolution { + u32 width; + u32 height; +}; + +struct atomisp_fmt { + u32 pixelformat; + u32 depth; + u32 bytesperline; + u32 framesize; + u32 imagesize; + u32 width; + u32 height; + u32 bayer_order; +}; + +struct atomisp_buffer { + struct videobuf_buffer vb; + struct sh_css_frame *handle; + struct atomisp_fmt *fmt; +}; + +/*Message bus access functions*/ +static inline u32 atomisp_msg_read32(struct atomisp_device *isp, + uint port, uint offset) +{ + int mcr; + uint32_t ret_val; + struct pci_dev *pci_root; + + ret_val = 0; + mcr = (0x10<<24) | (port << 16) | (offset << 8); + if (isp == NULL) + pci_root = pci_get_bus_and_slot(0, 0); + else + pci_root = isp->hw_contex.pci_dev; + + pci_write_config_dword(pci_root, 0xD0, mcr); + pci_read_config_dword(pci_root, 0xD4, &ret_val); + if (isp == NULL) + pci_dev_put(pci_root); + return ret_val; +} + +static inline void atomisp_msg_write32(struct atomisp_device *isp, + uint port, uint offset, u32 value) +{ + int mcr; + struct pci_dev *pci_root; + mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0; + + if (isp == NULL) + pci_root = pci_get_bus_and_slot(0, 0); + else + pci_root = isp->hw_contex.pci_dev; + pci_write_config_dword(pci_root, 0xD4, value); + pci_write_config_dword(pci_root, 0xD0, mcr); + if (isp == NULL) + pci_dev_put(pci_root); +} + +/* + * supported V4L2 fmts and resolutions + */ +extern const struct atomisp_format_bridge atomisp_output_fmts[]; +extern const u32 atomisp_output_fmts_num; +extern struct v4l2_device atomisp_dev; +#endif diff --git a/drivers/media/video/atomisp/atomisp_csi2.c b/drivers/media/video/atomisp/atomisp_csi2.c new file mode 100644 index 0000000..f7af2e0 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_csi2.c @@ -0,0 +1,423 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include "atomisp_internal.h" + +static const unsigned int csi2_input_fmts[] = { + V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SGBRG10_1X10, +}; + +static const unsigned int csi2_output_fmts[] = { + V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SGBRG10_1X10, +}; + + +/* V4L2 subdev operations */ + +static struct v4l2_mbus_framefmt * +__csi2_get_format(struct atomisp_mipi_csi2_device *csi2, + struct v4l2_subdev_fh *fh, + unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(fh, pad); + else + return &csi2->formats[pad]; +} + +enum v4l2_mbus_pixelcode +isp_video_uncompressed_code(enum v4l2_mbus_pixelcode code) +{ + switch (code) { + case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: + return V4L2_MBUS_FMT_SBGGR10_1X10; + case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: + return V4L2_MBUS_FMT_SGRBG10_1X10; + case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: + return V4L2_MBUS_FMT_SRGGB10_1X10; + case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: + return V4L2_MBUS_FMT_SGBRG10_1X10; + default: + return code; + } +} + +static void +csi2_try_format(struct atomisp_mipi_csi2_device *csi2, + struct v4l2_subdev_fh *fh, + unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + enum v4l2_mbus_pixelcode pixelcode; + struct v4l2_mbus_framefmt *format; + unsigned int i; + + switch (pad) { + case CSI2_PAD_SINK: + /* Clamp the width and height to valid range (1-8191). */ + for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) { + if (fmt->code == csi2_input_fmts[i]) + break; + } + + /* If not found, use SGRBG10 as default */ + if (i >= ARRAY_SIZE(csi2_input_fmts)) + fmt->code = V4L2_MBUS_FMT_SBGGR10_1X10; + + fmt->width = clamp_t(u32, fmt->width, 1, 4608); + fmt->height = clamp_t(u32, fmt->height, 1, 8191); + break; + + case CSI2_PAD_SOURCE: + /* Source format same as sink format, except for DPCM + * compression. + */ + pixelcode = fmt->code; + format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + + /* allow dpcm decompression */ + if (isp_video_uncompressed_code(fmt->code) == pixelcode) + fmt->code = pixelcode; + + break; + default: + break; + } + + /* RGB, non-interlaced */ + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->field = V4L2_FIELD_NONE; +} + +/* + * csi2_enum_mbus_code - Handle pixel format enumeration + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @code : pointer to v4l2_subdev_pad_mbus_code_enum structure + * return -EINVAL or zero on success +*/ +static int csi2_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + if (code->pad == CSI2_PAD_SINK) { + if (code->index >= ARRAY_SIZE(csi2_input_fmts)) + return -EINVAL; + code->code = csi2_input_fmts[code->index]; + } else { + format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, + V4L2_SUBDEV_FORMAT_TRY); + switch (code->index) { + case 0: + /* Passthrough sink pad code */ + code->code = format->code; + break; + case 1: + /* Uncompressed code */ + code->code = isp_video_uncompressed_code(format->code); + break; + default: + /* Fallthrough if above is false */ + return -EINVAL; + } + } + + return 0; +} + +static int csi2_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * csi2_get_format - Handle get format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @pad: pad num + * @fmt: pointer to v4l2 format structure + * return -EINVAL or zero on sucess +*/ +static int csi2_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) +{ + struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + return 0; +} + +/* + * csi2_set_format - Handle set format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @pad: pad num + * @fmt: pointer to v4l2 format structure + * return -EINVAL or zero on success +*/ +static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == CSI2_PAD_SINK) { + format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, + fmt->which); + *format = fmt->format; + csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); + } + + return 0; +} + +/* + * csi2_set_stream - Enable/Disable streaming on the CSI2 module + * @sd: ISP CSI2 V4L2 subdevice + * @enable: Enable/disable stream (1/0) + * + * Return 0 on success or a negative error code otherwise. +*/ +static int csi2_set_stream(struct v4l2_subdev *sd, int enable) +{ + v4l2_info(&atomisp_dev, "csi2_set_stream\n"); + return 0; +} + +/* subdev core operations */ +static const struct v4l2_subdev_core_ops csi2_core_ops = { + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, +}; + +/* subdev video operations */ +static const struct v4l2_subdev_video_ops csi2_video_ops = { + .s_stream = csi2_set_stream, +}; + +/* subdev pad operations */ +static const struct v4l2_subdev_pad_ops csi2_pad_ops = { + .enum_mbus_code = csi2_enum_mbus_code, + .enum_frame_size = csi2_enum_frame_size, + .get_fmt = csi2_get_format, + .set_fmt = csi2_set_format, +}; + +/* subdev operations */ +static const struct v4l2_subdev_ops csi2_ops = { + .core = &csi2_core_ops, + .video = &csi2_video_ops, + .pad = &csi2_pad_ops, +}; + + +/* + * csi2_link_setup - Setup CSI2 connections. + * @entity : Pointer to media entity structure + * @local : Pointer to local pad array + * @remote : Pointer to remote pad array + * @flags : Link flags + * return -EINVAL or zero on success +*/ +static int csi2_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); + u32 result = local->index | media_entity_type(remote->entity); + + switch (result) { + case CSI2_PAD_SOURCE | MEDIA_ENTITY_TYPE_DEVNODE: + /* not supported yet */ + return -EINVAL; + + case CSI2_PAD_SOURCE | MEDIA_ENTITY_TYPE_V4L2_SUBDEV: + if (flags & MEDIA_LINK_FLAG_ENABLED) { + if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV) + return -EBUSY; + csi2->output |= CSI2_OUTPUT_ISP_SUBDEV; + } else { + csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV; + } + break; + + default: + /* Link from camera to CSI2 is fixed... */ + return -EINVAL; + } + return 0; +} + +/* media operations */ +static const struct media_entity_operations csi2_media_ops = { + .link_setup = csi2_link_setup, +}; + +/* +* ispcsi2_init_entities - Initialize subdev and media entity. +* @csi2: Pointer to ispcsi2 structure. +* return -ENOMEM or zero on success +*/ +static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2, + int port) +{ + struct v4l2_subdev *sd = &csi2->subdev; + struct media_pad *pads = csi2->pads; + struct media_entity *me = &sd->entity; + int ret; + + v4l2_subdev_init(sd, &csi2_ops); + if (port == ATOMISP_CAMERA_PORT_SECONDARY) + strlcpy(sd->name, "ATOM ISP CSI2-1p", sizeof(sd->name)); + else if (port == ATOMISP_CAMERA_PORT_PRIMARY) + strlcpy(sd->name, "ATOM ISP CSI2-4p", sizeof(sd->name)); + + v4l2_set_subdevdata(sd, csi2); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FLAG_OUTPUT; + pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FLAG_INPUT; + + me->ops = &csi2_media_ops; + me->type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; + ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0); + if (ret < 0) + return ret; + + csi2->formats[CSI2_PAD_SINK].code = V4L2_MBUS_FMT_SBGGR10_1X10; + csi2->formats[CSI2_PAD_SOURCE].code = V4L2_MBUS_FMT_SBGGR10_1X10; + + return 0; +} + +void +atomisp_mipi_csi2_unregister_entities(struct atomisp_mipi_csi2_device *csi2) +{ + media_entity_cleanup(&csi2->subdev.entity); + v4l2_device_unregister_subdev(&csi2->subdev); +} + +int atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device *csi2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &csi2->subdev); + if (ret < 0) + goto error; + + return 0; + +error: + atomisp_mipi_csi2_unregister_entities(csi2); + return ret; +} + +/* + * atomisp_mipi_csi2_cleanup - Routine for module driver cleanup +*/ +void atomisp_mipi_csi2_cleanup(struct atomisp_device *isp) +{ +} + + +int atomisp_mipi_csi2_init(struct atomisp_device *isp) +{ + struct atomisp_mipi_csi2_device *csi2_4p = &isp->csi2_4p; + struct atomisp_mipi_csi2_device *csi2_1p = &isp->csi2_1p; + int ret; + + csi2_4p->isp = isp; + csi2_1p->isp = isp; + + ret = mipi_csi2_init_entities(csi2_4p, ATOMISP_CAMERA_PORT_PRIMARY); + if (ret < 0) + goto fail; + + ret = mipi_csi2_init_entities(csi2_1p, ATOMISP_CAMERA_PORT_SECONDARY); + if (ret < 0) + goto fail; + return 0; + +fail: + atomisp_mipi_csi2_cleanup(isp); + return ret; +} + diff --git a/drivers/media/video/atomisp/atomisp_csi2.h b/drivers/media/video/atomisp/atomisp_csi2.h new file mode 100644 index 0000000..cb3ba46 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_csi2.h @@ -0,0 +1,54 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#ifndef _MIPI_CSI2_H_ +#define _MIPI_CSI2_H_ + +#include +#include +#include +#include + +#define CSI2_PAD_SINK 0 +#define CSI2_PAD_SOURCE 1 +#define CSI2_PADS_NUM 2 + +#define CSI2_OUTPUT_ISP_SUBDEV (1 << 0) +#define CSI2_OUTPUT_MEMORY (1 << 1) + +struct atomisp_mipi_csi2_device { + struct v4l2_subdev subdev; + struct media_pad pads[CSI2_PADS_NUM]; + struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM]; + + struct v4l2_ctrl_handler ctrls; + struct atomisp_device *isp; + + u32 output; /* output direction */ +}; + +int atomisp_mipi_csi2_init(struct atomisp_device *isp); +void atomisp_mipi_csi2_cleanup(struct atomisp_device *isp); +void atomisp_mipi_csi2_unregister_entities( + struct atomisp_mipi_csi2_device *csi2); +int atomisp_mipi_csi2_register_entities(struct atomisp_mipi_csi2_device *csi2, + struct v4l2_device *vdev); + +#endif diff --git a/drivers/media/video/atomisp/atomisp_file.c b/drivers/media/video/atomisp/atomisp_file.c new file mode 100644 index 0000000..41d9ead --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_file.c @@ -0,0 +1,365 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include "atomisp_internal.h" +#include "atomisp_common.h" +#include "atomisp_subdev.h" +#include "atomisp_cmd.h" +#include "atomisp_file.h" + +static int file_input_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd); + struct atomisp_device *isp = file_dev->isp; + struct atomisp_video_pipe *out_pipe = &isp->isp_subdev.video_in; + unsigned char *buf = + videobuf_to_vmalloc(out_pipe->outq.bufs[0]); + int width = isp->input_format->out.width; + int height = isp->input_format->out.height; + unsigned short *data = (unsigned short *)buf; + int i, j; + + /* extend RAW8 pixel type to unsigned short */ + if (out_pipe->out_fmt->depth == 8) { + data = vmalloc(width*height*2); + if (!data) { + v4l2_err(&atomisp_dev, + "Failed to allocate memory for file input\n"); + return -ENOMEM; + } + + for (i = 0; i < height; i++) + for (j = 0; j < width; j++) + *data++ = (unsigned short)*buf++; + data -= width*height; + } + + while (!sh_css_isp_has_started()) + /* we are facing ISP timeout, if removed this delay */ + mdelay(1); + + sh_css_send_input_frame(data, width, height); + + if (out_pipe->out_fmt->depth == 8) + vfree(data); + return 0; +} + +static int file_input_enum_fmt(struct v4l2_subdev *sd, + struct v4l2_fmtdesc *fmtdesc) +{ + /*to fake*/ + return 0; +} + +static int file_input_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + /*to fake*/ + return 0; +} +static int file_input_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + /*to fake*/ + return 0; +} +static int file_input_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + /*to fake*/ + return 0; +} + +static int file_input_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + /*to fake*/ + return 0; +} + +static int file_input_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + /*to fake*/ + return 0; +} + +static int file_input_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_frmsizeenum *fsize) +{ + /*to fake*/ + return 0; +} + +static int file_input_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_frmivalenum *fival) +{ + /*to fake*/ + return 0; +} + +static int file_input_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + /*to fake*/ + return 0; +} + +static int file_input_try_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd); + struct atomisp_device *isp = file_dev->isp; + struct atomisp_video_pipe *out_pipe = &isp->isp_subdev.video_in; + + if (fmt == NULL) + return -EINVAL; + + if ((fmt->width > out_pipe->out_fmt->width) || + (fmt->height > out_pipe->out_fmt->height)) + return -EINVAL; + + fmt->width = out_pipe->out_fmt->width; + fmt->height = out_pipe->out_fmt->height; + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int file_input_g_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd); + struct atomisp_device *isp = file_dev->isp; + struct atomisp_video_pipe *out_pipe = &isp->isp_subdev.video_in; + + if (fmt == NULL) + return -EINVAL; + + fmt->width = out_pipe->out_fmt->width; + fmt->height = out_pipe->out_fmt->height; + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int file_input_s_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + /*to fake*/ + struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd); + struct atomisp_device *isp = file_dev->isp; + struct atomisp_video_pipe *out_pipe = &isp->isp_subdev.video_in; + int ret; + + if (fmt == NULL) + return -EINVAL; + + ret = file_input_try_mbus_fmt(sd, fmt); + if (ret) { + v4l2_err(sd, "file input try fmt failed\n"); + return ret; + } + + fmt->width = out_pipe->out_fmt->width; + fmt->height = out_pipe->out_fmt->height; + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + + sh_css_input_set_mode(SH_CSS_INPUT_MODE_FIFO); + return 0; +} + +static int file_input_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct atomisp_file_device *dev; + dev = container_of(sd, struct atomisp_file_device, sd); + + if (!chip) + return -EINVAL; + + return 0; +} + +static int file_input_log_status(struct v4l2_subdev *sd) +{ + /*to fake*/ + return 0; +} + +static int file_input_s_config(struct v4l2_subdev *sd, int irq, + void *platform_data) +{ + /*to fake*/ + return 0; +} + +static int file_input_queryctrl(struct v4l2_subdev *sd, + struct v4l2_queryctrl *qc) +{ + /*to fake*/ + return -EINVAL; +} + +static int file_input_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + /*to fake*/ + return -EINVAL; +} + +static int file_input_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + /*to fake*/ + return 0; +} + +static int file_input_s_power(struct v4l2_subdev *sd, int on) +{ + /* to fake */ + return 0; +} + +static int file_input_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + /*to fake*/ + return 0; +} + +static int file_input_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + /*to fake*/ + return 0; +} + +static int file_input_enum_frame_ival(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_interval_enum *fie) +{ + /*to fake*/ + return 0; +} + +static const struct v4l2_subdev_video_ops file_input_video_ops = { + .s_stream = file_input_s_stream, + .enum_fmt = file_input_enum_fmt, + .try_fmt = file_input_try_fmt, + .g_fmt = file_input_g_fmt, + .s_fmt = file_input_s_fmt, + .g_parm = file_input_g_parm, + .s_parm = file_input_s_parm, + .enum_framesizes = file_input_enum_framesizes, + .enum_frameintervals = file_input_enum_frameintervals, + .enum_mbus_fmt = file_input_enum_mbus_fmt, + .try_mbus_fmt = file_input_try_mbus_fmt, + .g_mbus_fmt = file_input_g_mbus_fmt, + .s_mbus_fmt = file_input_s_mbus_fmt, +}; + +static const struct v4l2_subdev_core_ops file_input_core_ops = { + .g_chip_ident = file_input_g_chip_ident, + .log_status = file_input_log_status, + .s_config = file_input_s_config, + .queryctrl = file_input_queryctrl, + .g_ctrl = file_input_g_ctrl, + .s_ctrl = file_input_s_ctrl, + .s_power = file_input_s_power, +}; + +static const struct v4l2_subdev_pad_ops file_input_pad_ops = { + .enum_mbus_code = file_input_enum_mbus_code, + .enum_frame_size = file_input_enum_frame_size, + .enum_frame_interval = file_input_enum_frame_ival, +}; + +static const struct v4l2_subdev_ops file_input_ops = { + .core = &file_input_core_ops, + .video = &file_input_video_ops, + .pad = &file_input_pad_ops, +}; + +static const struct media_entity_operations file_input_entity_ops = { + .set_power = v4l2_subdev_set_power, +}; + +void +atomisp_file_input_unregister_entities(struct atomisp_file_device *file_dev) +{ + v4l2_device_unregister_subdev(&file_dev->sd); +} + +int atomisp_file_input_register_entities(struct atomisp_file_device *file_dev, + struct v4l2_device *vdev) +{ + /* Register the subdev and video nodes. */ + return v4l2_device_register_subdev(vdev, &file_dev->sd); +} + +void atomisp_file_input_cleanup(struct atomisp_device *isp) +{ + return; +} + +int atomisp_file_input_init(struct atomisp_device *isp) +{ + struct atomisp_file_device *file_dev = &isp->file_dev; + struct v4l2_subdev *sd = &file_dev->sd; + struct media_pad *pads = file_dev->pads; + struct media_entity *me = &sd->entity; + struct camera_mipi_info *file_input_info = NULL; + int ret; + + file_dev->isp = isp; + v4l2_subdev_init(sd, &file_input_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + strcpy(sd->name, "file_input_subdev"); + v4l2_set_subdevdata(sd, file_dev); + + file_input_info = kzalloc(sizeof(*file_input_info), GFP_KERNEL); + if (!file_input_info) { + v4l2_err(&atomisp_dev, + "Failed to allocate memory for file input\n"); + return -ENOMEM; + } + + file_input_info->port = ATOMISP_CAMERA_PORT_PRIMARY; + file_input_info->input_format = SH_CSS_INPUT_FORMAT_RAW_10; + file_input_info->raw_bayer_order = sh_css_bayer_order_bggr; + v4l2_set_subdev_hostdata(sd, (void *)file_input_info); + + pads[0].flags = MEDIA_PAD_FLAG_INPUT; + me->type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; + + ret = media_entity_init(me, 1, pads, 0); + if (ret < 0) + goto fail; + return 0; +fail: + kfree(file_input_info); + atomisp_file_input_cleanup(isp); + return ret; +} diff --git a/drivers/media/video/atomisp/atomisp_file.h b/drivers/media/video/atomisp/atomisp_file.h new file mode 100644 index 0000000..6346a20 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_file.h @@ -0,0 +1,44 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __FILE_INPUT_H__ +#define __FILE_INPUT_H__ + +#include +#include +#include +#include + +struct atomisp_file_device { + struct v4l2_subdev sd; + struct atomisp_device *isp; + struct media_pad pads[1]; +}; + +void atomisp_file_input_cleanup(struct atomisp_device *isp); +int atomisp_file_input_init(struct atomisp_device *isp); +void atomisp_file_input_unregister_entities( + struct atomisp_file_device *file_dev); +int atomisp_file_input_register_entities(struct atomisp_file_device *file_dev, + struct v4l2_device *vdev); +#endif diff --git a/drivers/media/video/atomisp/atomisp_fops.c b/drivers/media/video/atomisp/atomisp_fops.c new file mode 100644 index 0000000..28ef74c --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_fops.c @@ -0,0 +1,716 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include "atomisp_ioctl.h" +#include "atomisp_cmd.h" +#include "atomisp_fops.h" +#include "atomisp_common.h" +#include "hrt/hive_isp_css_mm_hrt.h" + +#define ISP_LEFT_PAD 128 /* equal to 2*NWAY */ + +/* + * input image data, and current frame resolution for test + */ +#define ISP_PARAM_MMAP_OFFSET 0xfffff000 + +#define MAGIC_CHECK(is, should) \ + if (unlikely((is) != (should))) { \ + printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ + is, should); \ + BUG(); \ + } + +/* + * Videobuf ops + */ +int atomisp_buf_setup(struct videobuf_queue *vq, + unsigned int *count, + unsigned int *size) +{ + struct atomisp_video_pipe *pipe = vq->priv_data; + + *size = pipe->format->out.sizeimage; + + return 0; +} + +int atomisp_buf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct atomisp_video_pipe *pipe = vq->priv_data; + + vb->size = pipe->format->out.sizeimage; + vb->width = pipe->format->out.width; + vb->height = pipe->format->out.height; + vb->field = field; + vb->state = VIDEOBUF_PREPARED; + + return 0; +} + +void atomisp_buf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct atomisp_video_pipe *pipe = vq->priv_data; + + list_add_tail(&vb->queue, &pipe->activeq); + vb->state = VIDEOBUF_QUEUED; +} + +void atomisp_buf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + /* + * only set flag here. buffer free will done by req 0 buffer + */ + vb->state = VIDEOBUF_NEEDS_INIT; +} + +int atomisp_buf_setup_output(struct videobuf_queue *vq, + unsigned int *count, + unsigned int *size) +{ + struct atomisp_video_pipe *pipe = vq->priv_data; + + *size = pipe->out_fmt->imagesize; + + return 0; +} + +int atomisp_buf_prepare_output(struct videobuf_queue *vq, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct atomisp_video_pipe *pipe = vq->priv_data; + + vb->size = pipe->out_fmt->imagesize; + vb->width = pipe->out_fmt->width; + vb->height = pipe->out_fmt->height; + vb->field = field; + vb->state = VIDEOBUF_PREPARED; + + return 0; +} + +void atomisp_buf_queue_output(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct atomisp_video_pipe *pipe = vq->priv_data; + + list_add_tail(&vb->queue, &pipe->activeq_out); + vb->state = VIDEOBUF_QUEUED; +} + +void atomisp_buf_release_output(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + videobuf_vmalloc_free(vb); + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops videobuf_qops = { + .buf_setup = atomisp_buf_setup, + .buf_prepare = atomisp_buf_prepare, + .buf_queue = atomisp_buf_queue, + .buf_release = atomisp_buf_release, +}; + +static struct videobuf_queue_ops videobuf_qops_output = { + .buf_setup = atomisp_buf_setup_output, + .buf_prepare = atomisp_buf_prepare_output, + .buf_queue = atomisp_buf_queue_output, + .buf_release = atomisp_buf_release_output, +}; + +static int atomisp_uninit_pipe(struct atomisp_video_pipe *pipe) +{ + if (pipe->format) { + kfree(pipe->format); + pipe->format = NULL; + } + + if (pipe->out_fmt) { + kfree(pipe->out_fmt); + pipe->out_fmt = NULL; + } + + pipe->opened = false; + return 0; +} + +static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) +{ + + pipe->out_fmt = kzalloc(sizeof(struct atomisp_fmt), GFP_KERNEL); + if (pipe->out_fmt == NULL) { + v4l2_err(&atomisp_dev, "fail to allocte memory\n"); + return -ENOMEM; + } + + pipe->format = + kzalloc(sizeof(struct atomisp_video_pipe_format), GFP_KERNEL); + if (pipe->format == NULL) { + v4l2_err(&atomisp_dev, "failed to alloca memory\n"); + kfree(pipe->out_fmt); + return -ENOMEM; + } + + videobuf_queue_vmalloc_init(&pipe->capq, &videobuf_qops, NULL, + &pipe->irq_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, + sizeof(struct atomisp_buffer), + pipe); + + videobuf_queue_vmalloc_init(&pipe->outq, + &videobuf_qops_output, NULL, + &pipe->irq_lock, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_FIELD_NONE, + sizeof(struct atomisp_buffer), + pipe); + + /* init locks */ + spin_lock_init(&pipe->irq_lock); + mutex_init(&pipe->mutex); + INIT_LIST_HEAD(&pipe->activeq); + INIT_LIST_HEAD(&pipe->activeq_out); + pipe->opened = true; + + return 0; +} + +int atomisp_init_struct(struct atomisp_device *isp) +{ + if (isp == NULL) + return -EINVAL; + + isp->main_format = NULL; + isp->vf_format = NULL; + isp->input_format = NULL; + isp->sw_contex.run_mode = CI_MODE_STILL_CAPTURE; + isp->params.color_effect = V4L2_COLORFX_NONE; + isp->params.bad_pixel_en = 1; + isp->params.gdc_cac_en = 0; + isp->params.video_dis_en = 0; + isp->params.sc_en = 0; + isp->params.fpn_en = 0; + isp->params.xnr_en = 0; + isp->params.false_color = 0; + isp->params.online_process = 1; + isp->params.yuv_ds_en = 0; + isp->params.vf_overlay = NULL; + isp->sw_contex.sensor_streaming = false; + isp->sw_contex.isp_streaming = false; + isp->sw_contex.work_queued = false; + isp->sw_contex.error = false; + isp->sw_contex.file_input = 0; + + /* Add for channel */ + if (isp->inputs[0].camera) + isp->input_curr = 0; + + /* obtain the pointers to the default configurations */ + sh_css_get_tnr_config(&isp->params.default_tnr_config); + sh_css_get_nr_config(&isp->params.default_nr_config); + sh_css_get_ee_config(&isp->params.default_ee_config); + sh_css_get_ob_config(&isp->params.default_ob_config); + sh_css_get_dp_config(&isp->params.default_dp_config); + sh_css_get_wb_config(&isp->params.default_wb_config); + sh_css_get_cc_config(&isp->params.default_cc_config); + sh_css_get_de_config(&isp->params.default_de_config); + sh_css_get_gc_config(&isp->params.default_gc_config); + sh_css_get_3a_config(&isp->params.default_3a_config); + sh_css_get_macc_table(&isp->params.default_macc_table); + sh_css_get_ctc_table(&isp->params.default_ctc_table); + sh_css_get_gamma_table(&isp->params.default_gamma_table); + + /* we also initialize our configurations with the defaults */ + isp->params.tnr_config = *isp->params.default_tnr_config; + isp->params.nr_config = *isp->params.default_nr_config; + isp->params.ee_config = *isp->params.default_ee_config; + isp->params.ob_config = *isp->params.default_ob_config; + isp->params.dp_config = *isp->params.default_dp_config; + isp->params.wb_config = *isp->params.default_wb_config; + isp->params.cc_config = *isp->params.default_cc_config; + isp->params.de_config = *isp->params.default_de_config; + isp->params.gc_config = *isp->params.default_gc_config; + isp->params.s3a_config = *isp->params.default_3a_config; + isp->params.macc_table = *isp->params.default_macc_table; + isp->params.ctc_table = *isp->params.default_ctc_table; + isp->params.gamma_table = *isp->params.default_gamma_table; + + return 0; +} + +/*Wrap functions to pass into css framework*/ +static void *kernel_malloc(size_t bytes) +{ + return kzalloc(bytes, GFP_KERNEL); +} + +/* kfree is declared with const void * argument even though it's + clearly not const. We work around this here. */ +static void kernel_free(void *ptr) +{ + kfree(ptr); +} + +/* + * file operation functions + */ +static int atomisp_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + int ret = -EINVAL; + + if (!isp || isp->sw_contex.probed == 0) + return -ENODEV; + + /* if (atomisp_get(isp) == NULL) { */ + mutex_lock(&isp->input_lock); + + if (!isp->input_cnt) { + v4l2_err(&atomisp_dev, "no camera attached\n"); + goto error; + } + + if (pipe->opened) + goto done; + + if (atomisp_init_pipe(pipe) < 0) + goto error; + + if (isp->sw_contex.init) { + v4l2_err(&atomisp_dev, "skip init isp in open\n"); + goto done; + } + +#ifdef CONFIG_PM + /* runtime power management, turn on ISP */ + if (pm_runtime_get_sync(vdev->v4l2_dev->dev) < 0) { + v4l2_err(&atomisp_dev, + "Failed to power on device\n"); + goto runtime_get_failed; + } +#endif + /* if the driver gets closed and reopened, the HMM is not reinitialized + * This means we need to put the L1 page table base address back into + * the ISP. */ + if (isp->hw_contex.mmu_l1_base) + sh_css_mmu_set_page_table_base_address( + isp->hw_contex.mmu_l1_base); + + /* Init ISP */ + if (sh_css_init(kernel_malloc, + kernel_free, + SH_CSS_INTERRUPT_SETTING_PULSE, + isp->firmware->data, + isp->firmware->size)) + goto css_init_failed; + /* CSS has default zoom factor of 61x61, we want no zoom + because the zoom binary for capture is broken (XNR). */ + sh_css_set_zoom_factor(64, 64); + + atomisp_init_struct(isp); + + isp->sw_contex.init = true; + v4l2_dbg(1, dbg_level, &atomisp_dev, "open done\n"); +done: + mutex_unlock(&isp->input_lock); + + return 0; + +css_init_failed: +#ifdef CONFIG_PM + pm_runtime_put(vdev->v4l2_dev->dev); +#endif +runtime_get_failed: + atomisp_uninit_pipe(pipe); +error: + mutex_unlock(&isp->input_lock); + return ret; +} + +static int atomisp_release(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct v4l2_requestbuffers req; + int ret = 0; + + req.count = 0; + if (isp == NULL) + return -EBADF; + + mutex_lock(&isp->input_lock); + + if (pipe->capq.streaming && + atomisp_streamoff(file, NULL, + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + goto error; + + if (pipe->opened == false) + goto done; + + if (atomisp_reqbufs(file, NULL, &req)) + goto error; + + /* in case image buf is not freed */ + if (pipe->capq.bufs[0]) { + mutex_lock(&pipe->capq.vb_lock); + videobuf_queue_cancel(&pipe->capq); + mutex_unlock(&pipe->capq.vb_lock); + } + + if (pipe->format) { + kfree(pipe->format); + pipe->format = NULL; + isp->main_format = NULL; + } + + if (pipe->outq.bufs[0]) { + mutex_lock(&pipe->outq.vb_lock); + videobuf_queue_cancel(&pipe->outq); + mutex_unlock(&pipe->outq.vb_lock); + } + + if (pipe->out_fmt) { + kfree(pipe->out_fmt); + pipe->out_fmt = NULL; + } + + if (isp->vf_format) { + kfree(isp->vf_format); + isp->vf_format = NULL; + } + + if (isp->input_format) { + kfree(isp->input_format); + isp->input_format = NULL; + } + + if (!pipe->is_main) + goto done; + + if (isp->sw_contex.init == false) { + v4l2_info(&atomisp_dev, + "device already closed\n"); + goto done; + } + if ((!isp->isp_subdev.video_out_vf.opened) && + (isp->vf_frame)) { + sh_css_frame_free(isp->vf_frame); + isp->vf_frame = NULL; + } + + + atomisp_free_3a_buffers(isp); + atomisp_free_dis_buffers(isp); + atomisp_free_internal_buffers(isp); + sh_css_uninit(); + hrt_isp_css_mm_clear(); + + /*uninit the camera subdev*/ + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, init, 0); + if (ret == -1 || ret == -EINVAL) + v4l2_err(&atomisp_dev, "sensor firmware failed\n"); + + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, s_power, 0); + if (ret) + v4l2_warn(&atomisp_dev, "Failed to power-off sensor\n"); + + /* store L1 base address for next time we init the CSS */ + isp->hw_contex.mmu_l1_base = sh_css_mmu_get_page_table_base_address(); + isp->sw_contex.init = false; + +#ifdef CONFIG_PM + if (pm_runtime_put_sync(vdev->v4l2_dev->dev)) + v4l2_err(&atomisp_dev, + "Failed to power off device\n"); +#endif +done: + pipe->opened = false; + mutex_unlock(&isp->input_lock); + + return 0; +error: + mutex_unlock(&isp->input_lock); + return ret; +} + +/* + * Memory help functions for image frame and private parameters + */ +static int do_isp_mm_remap(struct vm_area_struct *vma, + void *isp_virt, u32 host_virt, u32 pgnr) +{ + u32 pfn; + + while (pgnr) { + pfn = hmm_virt_to_phys(isp_virt) >> PAGE_SHIFT; + if (remap_pfn_range(vma, host_virt, pfn, + PAGE_SIZE, PAGE_SHARED)) { + v4l2_err(&atomisp_dev, + "remap_pfn_range err.\n"); + return -EAGAIN; + } + + isp_virt += PAGE_SIZE; + host_virt += PAGE_SIZE; + pgnr--; + } + + return 0; +} + +static int frame_mmap(const struct sh_css_frame *frame, + struct vm_area_struct *vma) +{ + void *isp_virt; + u32 host_virt; + u32 pgnr; + + if (!frame) { + v4l2_err(&atomisp_dev, + "%s: NULL frame pointer.\n", __func__); + return -EINVAL; + } + + host_virt = vma->vm_start; + isp_virt = frame->data; + atomisp_get_frame_pgnr(frame, &pgnr); + + if (do_isp_mm_remap(vma, isp_virt, host_virt, pgnr)) + return -EAGAIN; + + return 0; +} + +int atomisp_videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + u32 offset = vma->vm_pgoff << PAGE_SHIFT; + int ret = -EINVAL, i; + struct videobuf_vmalloc_memory *vm_mem; + struct videobuf_mapping *map; + + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) { + v4l2_err(&atomisp_dev, "map appl bug:" + " PROT_WRITE and MAP_SHARED are required\n"); + return -EINVAL; + } + + mutex_lock(&q->vb_lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + struct videobuf_buffer *buf = q->bufs[i]; + if (buf == NULL) + continue; + + map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); + if (map == NULL) { + mutex_unlock(&q->vb_lock); + return -ENOMEM; + } + + buf->map = map; + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + + buf->baddr = vma->vm_start; + + if (buf && buf->memory == V4L2_MEMORY_MMAP && + buf->boff == offset) { + vm_mem = buf->priv; + ret = frame_mmap(vm_mem->vmalloc, vma); + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + break; + } + } + mutex_unlock(&q->vb_lock); + + return ret; +} + +/* The input frame contains left and right padding that need to be removed. + * There is always ISP_LEFT_PAD padding on the left side. + * There is also padding on the right (padded_width - width). + */ +static int +remove_pad_from_frame(struct sh_css_frame *in_frame, __u32 width, __u32 height) +{ + unsigned int i; + unsigned short *buffer; + int ret = 0; + unsigned short *load = in_frame->data; + unsigned short *store = load; + + buffer = kmalloc(width*sizeof(*load), GFP_KERNEL); + if (!buffer) { + v4l2_err(&atomisp_dev, "out of memory.\n"); + return -ENOMEM; + } + + load += ISP_LEFT_PAD; + for (i = 0; i < height; i++) { + ret = hrt_isp_css_mm_load(load, buffer, width*sizeof(*load)); + if (ret < 0) + goto remove_pad_error; + + ret = hrt_isp_css_mm_store(store, buffer, width*sizeof(*store)); + if (ret < 0) + goto remove_pad_error; + + load += in_frame->info.padded_width; + store += width; + } + +remove_pad_error: + kfree(buffer); + return ret; +} + +static int atomisp_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct sh_css_frame *raw_virt_addr; + u32 start = vma->vm_start; + u32 end = vma->vm_end; + u32 size = end - start; + u32 origin_size, new_size; + + if (!(vma->vm_flags & (VM_WRITE | VM_READ))) + return -EACCES; + + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + new_size = pipe->format->out.width * + pipe->format->out.height * 2; + + /* mmap for ISP offline raw data */ + if ((pipe->is_main) && + (vma->vm_pgoff == (ISP_PARAM_MMAP_OFFSET >> PAGE_SHIFT))) { + int ret; + if (isp->params.online_process != 0) + return -EINVAL; + raw_virt_addr = isp->raw_output_frame; + if (raw_virt_addr == NULL) { + v4l2_err(&atomisp_dev, + "Failed to request RAW frame\n"); + return -EINVAL; + } + + ret = remove_pad_from_frame(raw_virt_addr, + pipe->format->out.width, + pipe->format->out.height); + if (ret < 0) { + v4l2_err(&atomisp_dev, "remove pad failed.\n"); + return ret; + } + origin_size = raw_virt_addr->data_bytes; + raw_virt_addr->data_bytes = new_size; + + v4l2_info(&atomisp_dev, + "raw = %x, size = %d, ALIGN = %d\n", + (unsigned int)raw_virt_addr, size, + PAGE_ALIGN(raw_virt_addr->data_bytes)); + if (size != PAGE_ALIGN(new_size)) { + v4l2_err(&atomisp_dev, + "incorrect size for mmap ISP" + " Raw Frame\n"); + return -EINVAL; + } + + if (frame_mmap(raw_virt_addr, vma)) { + v4l2_err(&atomisp_dev, + "frame_mmap failed.\n"); + raw_virt_addr->data_bytes = origin_size; + return -EAGAIN; + } + raw_virt_addr->data_bytes = origin_size; + vma->vm_flags |= VM_RESERVED; + return 0; + } + + /* + * mmap for normal frames + */ + if (size != pipe->format->out.sizeimage) { + v4l2_err(&atomisp_dev, + "incorrect size for mmap ISP frames\n"); + return -EINVAL; + } + + return atomisp_videobuf_mmap_mapper(&pipe->capq, vma); +} + +int atomisp_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + + return videobuf_mmap_mapper(&pipe->outq, vma); +} + +static unsigned int +atomisp_poll(struct file *file, struct poll_table_struct *pt) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + + if (pipe->capq.streaming != 1) + return POLLERR; + + return videobuf_poll_stream(file, &pipe->capq, pt); +} + +const struct v4l2_file_operations atomisp_fops = { + .owner = THIS_MODULE, + .open = atomisp_open, + .release = atomisp_release, + .mmap = atomisp_mmap, + .ioctl = video_ioctl2, + .poll = atomisp_poll, +}; + +const struct v4l2_file_operations atomisp_file_fops = { + .owner = THIS_MODULE, + .open = atomisp_open, + .release = atomisp_release, + .mmap = atomisp_file_mmap, + .ioctl = video_ioctl2, + .poll = atomisp_poll, +}; + diff --git a/drivers/media/video/atomisp/atomisp_fops.h b/drivers/media/video/atomisp/atomisp_fops.h new file mode 100644 index 0000000..d3ed1de --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_fops.h @@ -0,0 +1,58 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __ATOMISP_FCTRL_H__ +#define __ATOMISP_FCTRL_H__ + +#include "atomisp_common.h" + +/* + * Videobuf ops + */ +int atomisp_buf_setup(struct videobuf_queue *vq, + unsigned int *count, + unsigned int *size); + +int atomisp_buf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, + enum v4l2_field field); + +void atomisp_buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb); + +void atomisp_buf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb); + +int atomisp_init_struct(struct atomisp_device *isp); + +/* + * Memory help functions for image frame and private parameters + */ + +int atomisp_videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma); + +int atomisp_file_mmap(struct file *file, struct vm_area_struct *vma); + +extern struct v4l2_device atomisp_dev; + +#endif diff --git a/drivers/media/video/atomisp/atomisp_ioctl.c b/drivers/media/video/atomisp/atomisp_ioctl.c new file mode 100644 index 0000000..d4798f9 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_ioctl.c @@ -0,0 +1,1689 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include "atomisp_ioctl.h" +#include "atomisp_cmd.h" +#include "atomisp_fops.h" +#include "css/sh_css.h" +#include +#include "bufferclass_video_linux.h" + +/* for v4l2_capability */ +static const char *DRIVER = "atomisp"; /* max size 15 */ +static const char *CARD = "ATOM ISP"; /* max size 31 */ +static const char *BUS_INFO = "PCI-3"; /* max size 31 */ +static const u32 VERSION = DRIVER_VERSION; + +static struct v4l2_queryctrl ci_v4l2_controls[] = { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic White Balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x00, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x00, + }, + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x00, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Image h-flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Image v-flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_COLORFX, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Image Color Effect", + .minimum = 0, + .maximum = 9, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Bad Pixel Correction", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_ATOMISP_POSTPROCESS_GDC_CAC, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "GDC/CAC", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_ATOMISP_VIDEO_STABLIZATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Video Stablization", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_ATOMISP_FIXED_PATTERN_NR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Fixed Pattern Noise Reduction", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_ATOMISP_FALSE_COLOR_CORRECTION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "False Color Correction", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_ATOMISP_SHADING_CORRECTION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Lens Shading Correction", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_REQUEST_FLASH, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Request flash frames", + .minimum = 0, + .maximum = 10, + .step = 1, + .default_value = 1, + } +}; +static const u32 ctrls_num = ARRAY_SIZE(ci_v4l2_controls); + +/* + * v4l2 ioctls + * return ISP capabilities + * + * FIXME: capabilities should be different for video0/video2/video3 + */ +static int atomisp_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + int ret = 0; + + memset(cap, 0, sizeof(struct v4l2_capability)); + strncpy(cap->driver, DRIVER, strlen(DRIVER)); + strncpy(cap->card, CARD, strlen(CARD)); + strncpy(cap->bus_info, BUS_INFO, strlen(BUS_INFO)); + cap->version = VERSION; + + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OUTPUT; + + return ret; +} + +/* + * return sensor chip identification + */ +static int atomisp_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + int ret = 0; + + mutex_lock(&isp->input_lock); + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, g_chip_ident, chip); + mutex_unlock(&isp->input_lock); + + if (ret) + v4l2_err(&atomisp_dev, + "failed to g_chip_ident for sensor\n"); + return ret; +} + +/* + * crop capability is the max resolution both ISP and Sensor supported + */ +static int atomisp_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cropcap) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct v4l2_mbus_framefmt snr_mbus_fmt; + int ret; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_err(&atomisp_dev, "unsupport v4l2 buf type\n"); + return -EINVAL; + } + + /*Only capture node supports cropcap*/ + if (!pipe->is_main) + return 0; + + cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + + snr_mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + snr_mbus_fmt.height = ATOM_ISP_MAX_HEIGHT_TMP; + snr_mbus_fmt.width = ATOM_ISP_MAX_WIDTH_TMP; + + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, try_mbus_fmt, &snr_mbus_fmt); + if (ret) { + v4l2_err(&atomisp_dev, + "failed to try_mbus_fmt for sensor" + ", try try_fmt\n"); + } else { + cropcap->bounds.width = snr_mbus_fmt.width; + cropcap->bounds.height = snr_mbus_fmt.height; + isp->snr_max_width = snr_mbus_fmt.width; + isp->snr_max_height = snr_mbus_fmt.height; + isp->snr_pixelformat = snr_mbus_fmt.code; + } + + memcpy(&cropcap->defrect, &cropcap->bounds, sizeof(struct v4l2_rect)); + cropcap->pixelaspect.numerator = 1; + cropcap->pixelaspect.denominator = 1; + return 0; +} +/* + * FIXME:G_CROP and S_CROP are used for bayer downscaling case + */ +static int atomisp_g_crop(struct file *file, void *fh, + struct v4l2_crop *crop) +{ + /* + * g_crop is used to enable bayer downscaling previously. + * current bayer ds is replaced by yuv ds. + * so remove the support of cropping. + */ + v4l2_err(&atomisp_dev, + "crop is unavailable now\n"); + return -EINVAL; + +} + +static int atomisp_s_crop(struct file *file, void *fh, + struct v4l2_crop *crop) +{ + /* + * s_crop is used to enable bayer downscaling previously. + * current bayer ds is replaced by yuv ds. + * so remove the support of cropping. + */ + v4l2_err(&atomisp_dev, + "crop is unavailable now\n"); + return -EINVAL; +} +/* + * enum input are used to check primary/secondary camera + */ +static int atomisp_enum_input(struct file *file, void *fh, + struct v4l2_input *input) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + int index = input->index; + + if (index >= isp->input_cnt) + return -EINVAL; + + if (!isp->inputs[index].camera) + return -EINVAL; + + memset(input, 0, sizeof(struct v4l2_input)); + strcpy(input->name, isp->inputs[index].camera->name); + input->type = V4L2_INPUT_TYPE_CAMERA; + input->index = index; + input->reserved[0] = isp->inputs[index].type; + input->reserved[1] = isp->inputs[index].port; + + return 0; +} +/* + * get input are used to get current primary/secondary camera + */ +static int atomisp_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + + *input = isp->input_curr; + + return 0; +} +/* + * set input are used to set current primary/secondary camera + */ +static int atomisp_s_input(struct file *file, void *fh, unsigned int input) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct v4l2_subdev *camera = NULL; + int ret; + + if (input >= ATOM_ISP_MAX_INPUTS || input > isp->input_cnt) + return -EINVAL; + + mutex_lock(&isp->input_lock); + camera = isp->inputs[input].camera; + if (!camera) { + mutex_unlock(&isp->input_lock); + return -EINVAL; + } + + if ((isp->isp_subdev.video_out_vf.capq.streaming == 1) || + (isp->isp_subdev.video_out_mo.capq.streaming == 1) || + (isp->isp_subdev.video_in.capq.streaming == 1)) { + v4l2_err(&atomisp_dev, + "ISP is still streaming, stop first\n"); + mutex_unlock(&isp->input_lock); + return -EINVAL; + } + + /* power off the current sensor, as it is not used this time */ + if (isp->input_curr != input) { + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, s_power, 0); + if (ret) + v4l2_warn(&atomisp_dev, + "Failed to power-off sensor\n"); + } + + /* powe on the new sensor */ + if (!isp->sw_contex.file_input) { + ret = v4l2_subdev_call(isp->inputs[input].camera, + core, s_power, 1); + if (ret) { + v4l2_err(&atomisp_dev, + "Failed to power-on sensor\n"); + mutex_unlock(&isp->input_lock); + return -EINVAL; + } + } + + isp->input_curr = input; + + mutex_unlock(&isp->input_lock); + + return 0; +} + +static int atomisp_g_std(struct file *file, void *fh, v4l2_std_id * id) +{ + return -EINVAL; +} + +static int atomisp_s_std(struct file *file, void *fh, v4l2_std_id * id) +{ + return -EINVAL; +} + +static int atomisp_enum_fmt_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + u32 index = f->index; + + /* check buf index */ + if (index >= atomisp_output_fmts_num) { + v4l2_err(&atomisp_dev, + "fmt index extends maxiumn" + " supported fmts number\n"); + return -EINVAL; + } + /* check buf type */ + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_err(&atomisp_dev, + "unsupported v4l2 buf type\n"); + return -EINVAL; + } + + f->pixelformat = atomisp_output_fmts[index].pixelformat; + memset(f->description, 0, sizeof(char)*32); + strncpy(f->description, atomisp_output_fmts[index].description, + strlen(atomisp_output_fmts[index].description)); + + return 0; +} + +static int atomisp_g_fmt_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + + int ret; + + ret = atomisp_get_fmt(vdev, f); + return ret; +} + +static int atomisp_g_fmt_file(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + int ret; + + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&atomisp_dev, + "unsupported v4l2 buf type\n"); + return -EINVAL; + } + + memset(f, 0, sizeof(struct v4l2_format)); + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + switch (isp->sw_contex.output_mode) { + case OUTPUT_MODE_FILE: + f->fmt.pix.width = pipe->out_fmt->width; + f->fmt.pix.height = pipe->out_fmt->height; + f->fmt.pix.pixelformat = pipe->out_fmt->pixelformat; + f->fmt.pix.bytesperline = pipe->out_fmt->bytesperline; + f->fmt.pix.sizeimage = pipe->out_fmt->imagesize; + break; + case OUTPUT_MODE_TEXT: + f->fmt.pix.sizeimage = pipe->out_fmt->framesize; + break; + default: + v4l2_err(&atomisp_dev, "Unspported output mode\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +/* This function looks up the closest available resolution. */ +static int atomisp_try_fmt_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + int ret; + + ret = atomisp_try_fmt(vdev, f, NULL); + return ret; +} + +static int atomisp_s_fmt_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + int ret; + + ret = atomisp_set_fmt(vdev, f); + return ret; +} + +static int atomisp_s_fmt_file(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + int ret; + + ret = atomisp_set_fmt_file(vdev, f); + return ret; +} + +/* + * This ioctl allows applications to enumerate all frame sizes that the + * device supports for the given pixel format. + * discrete means the applicatons should increase the index until EINVAL is + * returned. + */ +static int atomisp_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *arg) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + + if (!atomisp_is_pixelformat_supported(arg->pixel_format)) + return -EINVAL; + + return v4l2_subdev_call(isp->inputs[isp->input_curr].camera, video, + enum_framesizes, arg); +} + +/* + * is_resolution_supported - Check whether resolution is supported + * @width: check resolution width + * @height: check resolution height + * + * Return 1 on supported or 0 otherwise. +*/ +static int is_resolution_supported(u32 width, u32 height) +{ + if ((width > ATOM_ISP_MIN_WIDTH) && (width <= ATOM_ISP_MAX_WIDTH) && + (height > ATOM_ISP_MIN_HEIGHT) && (height <= ATOM_ISP_MAX_HEIGHT)) { + if (!(width % ATOM_ISP_STEP_WIDTH) && + !(height % ATOM_ISP_STEP_HEIGHT)) + return 1; + } + + return 0; +} + +/* + * This ioctl allows applications to enumerate all frame intervals that the + * device supports for the given pixel format and frame size. + * + * framerate = 1 / frameintervals + */ +static int atomisp_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *arg) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + int ret; + + if (arg->index != 0) + return -EINVAL; + + if (!atomisp_is_pixelformat_supported(arg->pixel_format)) + return -EINVAL; + + if (!is_resolution_supported(arg->width, arg->height)) + return -EINVAL; + + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, enum_frameintervals, arg); + + if (ret) { + /* set the FPS to default 15*/ + arg->type = V4L2_FRMIVAL_TYPE_DISCRETE; + arg->discrete.numerator = 1; + arg->discrete.denominator = 15; + } + + v4l2_info(&atomisp_dev, "%s: sensor_support:%d " + "FPS:%d\n", __func__, ret, arg->discrete.denominator); + + return 0; +} +/* + * this function is used to free video buffer + */ +static void atomisp_videobuf_free(struct videobuf_queue *q) +{ + int i; + struct videobuf_vmalloc_memory *vm_mem; + + mutex_lock(&q->vb_lock); + + if (!q) { + mutex_unlock(&q->vb_lock); + return; + } + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + vm_mem = q->bufs[i]->priv; + + if (vm_mem && vm_mem->vmalloc) { + sh_css_frame_free(vm_mem->vmalloc); + vm_mem->vmalloc = NULL; + } + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + + mutex_unlock(&q->vb_lock); +} + +/* + * Initiate Memory Mapping or User Pointer I/O + */ +int atomisp_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *req) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct sh_css_frame_info out_info, vf_info; + struct sh_css_frame *frame; + struct videobuf_vmalloc_memory *vm_mem; + int ret = 0, i = 0; + + if (req->count == 0) { + atomisp_videobuf_free(&pipe->capq); + if ((!isp->isp_subdev.video_out_vf.opened) && + (isp->vf_frame)) { + sh_css_frame_free(isp->vf_frame); + isp->vf_frame = NULL; + } + return 0; + } + + if ((!pipe->is_main) && (!atomisp_is_viewfinder_support(isp))) + return -EINVAL; + + ret = videobuf_reqbufs(&pipe->capq, req); + if (ret) + return ret; + + switch (isp->sw_contex.run_mode) { + case CI_MODE_STILL_CAPTURE: + if (isp->main_format->out_sh_fmt != SH_CSS_FRAME_FORMAT_RAW) { + if (sh_css_capture_get_viewfinder_frame_info(&vf_info)) + goto error; + if ((!isp->isp_subdev.video_out_vf.opened) && + (sh_css_frame_allocate_from_info(&isp->vf_frame, + &vf_info))) + goto error; + } + if (sh_css_capture_get_output_frame_info(&out_info)) + goto error; + break; + case CI_MODE_VIDEO: + if (sh_css_video_get_viewfinder_frame_info(&vf_info)) + goto error; + + if ((!isp->isp_subdev.video_out_vf.opened) && + (sh_css_frame_allocate_from_info(&isp->vf_frame, &vf_info))) + goto error; + + if (sh_css_video_get_output_frame_info(&out_info)) + goto error; + break; + case CI_MODE_PREVIEW: + if (sh_css_preview_get_output_frame_info(&out_info)) + goto error; + break; + default: + return -EINVAL; + } + + /* + * for user pointer type, buffers are not really allcated here, + * buffers are setup in QBUF operation through v4l2_buffer structure + */ + if (req->memory == V4L2_MEMORY_USERPTR) { + v4l2_info(&atomisp_dev, + "user pointer, not really allocate" + " memory here.\n"); + return 0; + } + + if (!pipe->is_main) + /* + * Allocate the real frame here for preview node using our + * memery management function + */ + for (i = 0; i < req->count; i++) { + if (sh_css_frame_allocate_from_info(&frame, &vf_info)) + goto error; + vm_mem = pipe->capq.bufs[i]->priv; + vm_mem->vmalloc = frame; + } + else + /* + * Allocate the real frame here for capture node using our + * memery management function + */ + for (i = 0; i < req->count; i++) { + if (sh_css_frame_allocate_from_info(&frame, &out_info)) + goto error; + vm_mem = pipe->capq.bufs[i]->priv; + vm_mem->vmalloc = frame; + } + + return ret; + +error: + while (i--) { + vm_mem = pipe->capq.bufs[i]->priv; + sh_css_frame_free(vm_mem->vmalloc); + } + + if (isp->vf_frame) + sh_css_frame_free(isp->vf_frame); + return -ENOMEM; +} + +static int atomisp_reqbufs_file(struct file *file, void *fh, + struct v4l2_requestbuffers *req) +{ + int ret; + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + + if (req->count == 0) { + atomisp_videobuf_free(&pipe->outq); + return 0; + } + + ret = videobuf_reqbufs(&pipe->outq, req); + if (ret) + return ret; + + if (isp->sw_contex.output_mode == OUTPUT_MODE_TEXT) + return 0; + + /* + * TODO: Implement file input function + */ + + return 0; +} + +/* application query the status of a buffer */ +static int atomisp_querybuf(struct file *file, void *fh, + struct v4l2_buffer *buf) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + + return videobuf_querybuf(&pipe->capq, buf); +} + +static int atomisp_querybuf_file(struct file *file, void *fh, + struct v4l2_buffer *buf) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + + return videobuf_querybuf(&pipe->outq, buf); +} + +/* + * Applications call the VIDIOC_QBUF ioctl to enqueue an empty (capturing) or + * filled (output) buffer in the drivers incoming queue. + */ +static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + unsigned long userptr = buf->m.userptr; + struct videobuf_buffer *vb; + struct videobuf_vmalloc_memory *vm_mem; + struct sh_css_frame_info out_info, vf_info; + struct sh_css_frame *handle = NULL; + u32 length; + u32 pgnr; + int ret = 0; + + if ((!pipe->is_main) && + (!atomisp_is_viewfinder_support(isp))) + return -EINVAL; + + if (!buf || buf->index >= VIDEO_MAX_FRAME || + !pipe->capq.bufs[buf->index]) { + v4l2_err(&atomisp_dev, + "Invalid index for qbuf.\n"); + return -EINVAL; + } + + v4l2_dbg(2, dbg_level, &atomisp_dev, "%s\n", __func__); + /* + * For userptr type frame, we convert user space address to physic + * address and reprograme out page table properly + */ + if (buf->memory == V4L2_MEMORY_USERPTR) { + vb = pipe->capq.bufs[buf->index]; + vm_mem = vb->priv; + if (!vm_mem) + return -EINVAL; + + length = vb->bsize; + pgnr = (length + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + + /* We must stop to atomisp to remove the + * race condition when updating the new userptr. */ + if (buf->flags & V4L2_BUF_FLAG_BUFFER_INVALID) { + isp->sw_contex.updating_uptr = true; + return 0; + } + /* Check whether need to start the atomisp_work */ + if (buf->flags & V4L2_BUF_FLAG_BUFFER_VALID) { + isp->sw_contex.updating_uptr = false; + wake_up_interruptible_sync(&pipe->capq.wait); + return 0; + } + + if ((vb->baddr == userptr) && (vm_mem->vmalloc)) + goto done; + + switch (isp->sw_contex.run_mode) { + case CI_MODE_STILL_CAPTURE: + if ((isp->main_format->out_sh_fmt != + SH_CSS_FRAME_FORMAT_RAW) && + sh_css_capture_get_viewfinder_frame_info(&vf_info)) + goto error; + + if (sh_css_capture_get_output_frame_info(&out_info)) + goto error; + break; + case CI_MODE_VIDEO: + if (sh_css_video_get_viewfinder_frame_info(&vf_info)) + goto error; + if (sh_css_video_get_output_frame_info(&out_info)) + goto error; + break; + case CI_MODE_PREVIEW: + if (sh_css_preview_get_output_frame_info(&out_info)) + goto error; + break; + } + + hrt_isp_css_mm_set_user_ptr(userptr, pgnr); + if (!pipe->is_main) + sh_css_frame_allocate_from_info(&handle, &vf_info); + else + sh_css_frame_allocate_from_info(&handle, &out_info); + + hrt_isp_css_mm_set_user_ptr(0, 0); + if (IS_ERR(handle)) { + v4l2_err(&atomisp_dev, "Error to allocate" + " frame for userptr capture %ld\n", + PTR_ERR(handle)); + + return PTR_ERR(handle); + } + + if (vm_mem->vmalloc) { + mutex_lock(&pipe->capq.vb_lock); + sh_css_frame_free(vm_mem->vmalloc); + vm_mem->vmalloc = NULL; + vb->state = VIDEOBUF_NEEDS_INIT; + mutex_unlock(&pipe->capq.vb_lock); + } + + vm_mem->vmalloc = handle; + + buf->flags &= ~V4L2_BUF_FLAG_MAPPED; + buf->flags |= V4L2_BUF_FLAG_QUEUED; + buf->flags &= ~V4L2_BUF_FLAG_DONE; + + } else if (buf->memory == V4L2_MEMORY_MMAP) { + buf->flags |= V4L2_BUF_FLAG_MAPPED; + buf->flags |= V4L2_BUF_FLAG_QUEUED; + buf->flags &= ~V4L2_BUF_FLAG_DONE; + } + +done: + ret = videobuf_qbuf(&pipe->capq, buf); + return ret; + +error: + v4l2_err(&atomisp_dev, "get_output_frame_info error\n"); + return -EINVAL; +} + +static int atomisp_qbuf_file(struct file *file, void *fh, + struct v4l2_buffer *buf) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + + if (!buf || buf->index >= VIDEO_MAX_FRAME || + !pipe->outq.bufs[buf->index]) { + v4l2_err(&atomisp_dev, + "Invalid index for qbuf.\n"); + return -EINVAL; + } + + if (buf->memory != V4L2_MEMORY_MMAP) { + v4l2_err(&atomisp_dev, "Unsupported memory method\n"); + return -EINVAL; + } + + if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&atomisp_dev, "Unsupported buffer type\n"); + return -EINVAL; + } + + return videobuf_qbuf(&pipe->outq, buf); +} + +/* + * Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or + * displayed (output buffer)from the driver's outgoing queue + */ +static int atomisp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_device *isp = video_get_drvdata(vdev); + int ret = 0; + + v4l2_dbg(2, dbg_level, &atomisp_dev, "%s\n", __func__); + + if ((!pipe->is_main) && + (!atomisp_is_viewfinder_support(isp))) + return -EINVAL; + + if (isp->sw_contex.error) { + v4l2_err(&atomisp_dev, "ISP ERROR\n"); + return -EINVAL; + } + + ret = videobuf_dqbuf(&pipe->capq, buf, file->f_flags & O_NONBLOCK); + if (ret) + return ret; + buf->bytesused = pipe->format->out.sizeimage; + buf->reserved = isp->frame_status[buf->index]; + + return 0; +} + +/* + * This ioctl start the capture during streaming I/O. + */ +static int atomisp_streamon(struct file *file, void *fh, + enum v4l2_buf_type type) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_device *isp = video_get_drvdata(vdev); + int ret; +#ifdef PUNIT_CAMERA_BUSY + u32 msg_ret; +#endif + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_err(&atomisp_dev, + "unsupported v4l2 buf type\n"); + return -EINVAL; + } + + if (list_empty(&(pipe->capq.stream))) { + v4l2_err(&atomisp_dev, + "no buffer in the queue\n"); + return -EINVAL; + } + + ret = videobuf_streamon(&pipe->capq); + if (ret) + return ret; + isp->sw_contex.isp_streaming = true; + + if (isp->sw_contex.work_queued) + goto done; + +#ifdef PUNIT_CAMERA_BUSY + /* + * As per h/w architect and ECO 697611 we need to throttle the + * GFX performance (freq) while camera is up to prevent peak + * current issues. this is done by setting the camera busy bit. + */ + msg_ret = atomisp_msg_read32(isp, PUNIT_PORT, OR1); + msg_ret |= 0x100; + atomisp_msg_write32(isp, PUNIT_PORT, OR1, msg_ret); +#endif + + /*stream on sensor in work thread*/ + queue_work(isp->work_queue, &isp->work); + isp->sw_contex.work_queued = true; + +done: + return 0; +} + +/*This ioctl stop the capture or output process during streaming I/O.*/ +int atomisp_streamoff(struct file *file, void *fh, + enum v4l2_buf_type type) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_video_pipe *vf_pipe = NULL; + struct atomisp_video_pipe *mo_pipe = NULL; + int ret; +#ifdef PUNIT_CAMERA_BUSY + u32 msg_ret; +#endif + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_err(&atomisp_dev, + "unsupported v4l2 buf type\n"); + return -EINVAL; + } + + isp->sw_contex.isp_streaming = false; + + /* cancel work queue*/ + if (isp->sw_contex.work_queued) { + mo_pipe = &isp->isp_subdev.video_out_mo; + wake_up_interruptible(&mo_pipe->capq.wait); + if (atomisp_is_viewfinder_support(isp)) { + vf_pipe = &isp->isp_subdev.video_out_vf; + wake_up_interruptible(&vf_pipe->capq.wait); + } + cancel_work_sync(&isp->work); + isp->sw_contex.work_queued = false; + } + + ret = videobuf_streamoff(&pipe->capq); + if (ret) + return ret; + /*stream off sensor, power off is called in senor driver*/ + if (!pipe->is_main) + return 0; + if (!isp->sw_contex.file_input) + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + video, s_stream, 0); + + if (isp->flash) + ret += v4l2_subdev_call(isp->flash, core, s_power, 0); + + isp->sw_contex.sensor_streaming = false; + +#ifdef PUNIT_CAMERA_BUSY + /* Free camera_busy bit */ + msg_ret = atomisp_msg_read32(isp, PUNIT_PORT, OR1); + msg_ret &= ~0x100; + atomisp_msg_write32(isp, PUNIT_PORT, OR1, msg_ret); +#endif + + /* ISP work around, need to power cycle isp*/ + if (pipe->is_main && isp->sw_contex.power_state == ATOM_ISP_POWER_UP) { + sh_css_suspend(); + pm_runtime_put_sync(vdev->v4l2_dev->dev); + pm_runtime_get_sync(vdev->v4l2_dev->dev); + sh_css_resume(); + } + + return ret; +} + +/* + * To get the current value of a control. + * applications initialize the id field of a struct v4l2_control and + * call this ioctl with a pointer to this structure + */ +static int atomisp_g_ctrl(struct file *file, void *fh, + struct v4l2_control *control) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + int i, ret = -EINVAL; + + mutex_lock(&isp->input_lock); + + for (i = 0; i < ctrls_num; i++) { + if (ci_v4l2_controls[i].id == control->id) { + ret = 0; + break; + } + } + + if (ret) { + mutex_unlock(&isp->input_lock); + return ret; + } + + switch (control->id) { + case V4L2_CID_IRIS_ABSOLUTE: + case V4L2_CID_EXPOSURE_ABSOLUTE: + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, g_ctrl, control); + break; + case V4L2_CID_COLORFX: + ret = atomisp_color_effect(isp, 0, &control->value); + break; + case V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION: + ret = atomisp_bad_pixel(isp, 0, &control->value); + break; + case V4L2_CID_ATOMISP_POSTPROCESS_GDC_CAC: + ret = atomisp_gdc_cac(isp, 0, &control->value); + break; + case V4L2_CID_ATOMISP_VIDEO_STABLIZATION: + ret = atomisp_video_stable(isp, 0, &control->value); + break; + case V4L2_CID_ATOMISP_FIXED_PATTERN_NR: + ret = atomisp_fixed_pattern(isp, 0, &control->value); + break; + case V4L2_CID_ATOMISP_FALSE_COLOR_CORRECTION: + ret = atomisp_false_color(isp, 0, &control->value); + break; + case V4L2_CID_ATOMISP_SHADING_CORRECTION: + ret = atomisp_shading_correction(isp, 0, &control->value); + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&isp->input_lock); + return ret; +} + +/* + * To change the value of a control. + * applications initialize the id and value fields of a struct v4l2_control + * and call this ioctl. + */ +static int atomisp_s_ctrl(struct file *file, void *fh, + struct v4l2_control *control) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + int i, ret = -EINVAL; + + mutex_lock(&isp->input_lock); + + for (i = 0; i < ctrls_num; i++) { + if (ci_v4l2_controls[i].id == control->id) { + ret = 0; + break; + } + } + + if (ret) { + mutex_unlock(&isp->input_lock); + return ret; + } + + switch (control->id) { + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, s_ctrl, control); + break; + case V4L2_CID_COLORFX: + ret = atomisp_color_effect(isp, 1, &control->value); + break; + case V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION: + ret = atomisp_bad_pixel(isp, 1, &control->value); + break; + case V4L2_CID_ATOMISP_POSTPROCESS_GDC_CAC: + ret = atomisp_gdc_cac(isp, 1, &control->value); + break; + case V4L2_CID_ATOMISP_VIDEO_STABLIZATION: + ret = atomisp_video_stable(isp, 1, &control->value); + break; + case V4L2_CID_ATOMISP_FIXED_PATTERN_NR: + ret = atomisp_fixed_pattern(isp, 1, &control->value); + break; + case V4L2_CID_ATOMISP_FALSE_COLOR_CORRECTION: + ret = atomisp_false_color(isp, 1, &control->value); + break; + case V4L2_CID_ATOMISP_SHADING_CORRECTION: + ret = atomisp_shading_correction(isp, 1, &control->value); + break; + case V4L2_CID_REQUEST_FLASH: + ret = atomisp_flash_enable(isp, control->value); + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&isp->input_lock); + return ret; +} +/* + * To query the attributes of a control. + * applications set the id field of a struct v4l2_queryctrl and call the + * this ioctl with a pointer to this structure. The driver fills + * the rest of the structure. + */ +static int atomisp_queryctl(struct file *file, void *fh, + struct v4l2_queryctrl *qc) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + int i, ret = -EINVAL; + + if (qc->id & V4L2_CTRL_FLAG_NEXT_CTRL) + return ret; + + mutex_lock(&isp->input_lock); + + for (i = 0; i < ctrls_num; i++) { + if (ci_v4l2_controls[i].id == qc->id) { + memcpy(qc, &ci_v4l2_controls[i], + sizeof(struct v4l2_queryctrl)); + qc->reserved[0] = 0; + ret = 0; + break; + } + } + if (ret != 0) + qc->flags = V4L2_CTRL_FLAG_DISABLED; + + mutex_unlock(&isp->input_lock); + return ret; +} + +static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh, + struct v4l2_ext_controls *c) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct v4l2_control ctrl; + int i; + int ret = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + switch (ctrl.id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + case V4L2_CID_IRIS_ABSOLUTE: + /* + * Exposure related control will be handled by sensor + * driver + */ + ret = v4l2_subdev_call(isp->inputs + [isp->input_curr].camera, + core, g_ctrl, &ctrl); + break; + case V4L2_CID_FOCUS_ABSOLUTE: + case V4L2_CID_FOCUS_RELATIVE: + case V4L2_CID_FOCUS_STATUS: + case V4L2_CID_FOCUS_AUTO: + if (isp->motor) + ret = v4l2_subdev_call( + isp->motor, core, g_ctrl, &ctrl); + else + ret = v4l2_subdev_call( + isp->inputs[isp->input_curr].camera, + core, g_ctrl, &ctrl); + break; + case V4L2_CID_FLASH_STATUS: + case V4L2_CID_FLASH_INTENSITY: + case V4L2_CID_FLASH_TORCH_INTENSITY: + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + case V4L2_CID_FLASH_TIMEOUT: + case V4L2_CID_FLASH_STROBE: + case V4L2_CID_FLASH_MODE: + if (isp->flash) + ret = v4l2_subdev_call( + isp->flash, core, g_ctrl, &ctrl); + break; + case V4L2_CID_ZOOM_ABSOLUTE: + ret = atomisp_digital_zoom(isp, 0, &ctrl.value); + break; + default: + ret = -EINVAL; + } + + if (ret) { + c->error_idx = i; + break; + } + c->controls[i].value = ctrl.value; + } + return ret; +} + +/* This ioctl allows the application to get multiple controls by class */ +static int atomisp_g_ext_ctrls(struct file *file, void *fh, + struct v4l2_ext_controls *c) +{ + struct v4l2_control ctrl; + int i, ret = 0; + + /* input_lock is not need for the Camera releated IOCTLs + * The input_lock downgrade the FPS of 3A*/ + if (c->ctrl_class == V4L2_CTRL_CLASS_CAMERA) { + ret = atomisp_camera_g_ext_ctrls(file, fh, c); + return ret; + } + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + ret = atomisp_g_ctrl(file, fh, &ctrl); + c->controls[i].value = ctrl.value; + if (ret) { + c->error_idx = i; + break; + } + } + return ret; + } + return -EINVAL; +} + +static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh, + struct v4l2_ext_controls *c) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + struct v4l2_control ctrl; + int i; + int ret = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + switch (ctrl.id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + case V4L2_CID_IRIS_ABSOLUTE: + case V4L2_CID_VCM_TIMEING: + case V4L2_CID_VCM_SLEW: + case V4L2_CID_TEST_PATTERN: + ret = v4l2_subdev_call( + isp->inputs[isp->input_curr].camera, + core, s_ctrl, &ctrl); + break; + case V4L2_CID_FOCUS_ABSOLUTE: + case V4L2_CID_FOCUS_RELATIVE: + case V4L2_CID_FOCUS_STATUS: + case V4L2_CID_FOCUS_AUTO: + if (isp->motor) + ret = v4l2_subdev_call(isp->motor, + core, s_ctrl, &ctrl); + else + ret = v4l2_subdev_call( + isp->inputs[isp->input_curr].camera, + core, s_ctrl, &ctrl); + break; + case V4L2_CID_FLASH_STATUS: + case V4L2_CID_FLASH_INTENSITY: + case V4L2_CID_FLASH_TORCH_INTENSITY: + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + case V4L2_CID_FLASH_TIMEOUT: + case V4L2_CID_FLASH_STROBE: + case V4L2_CID_FLASH_MODE: + if (isp->flash) + ret = v4l2_subdev_call(isp->flash, + core, s_ctrl, &ctrl); + break; + case V4L2_CID_ZOOM_ABSOLUTE: + ret = atomisp_digital_zoom(isp, 1, &ctrl.value); + break; + default: + ret = -EINVAL; + } + + if (ret) { + c->error_idx = i; + break; + } + c->controls[i].value = ctrl.value; + } + return ret; +} + +/* This ioctl allows the application to set multiple controls by class */ +static int atomisp_s_ext_ctrls(struct file *file, void *fh, + struct v4l2_ext_controls *c) +{ + struct v4l2_control ctrl; + int i, ret = 0; + + /* input_lock is not need for the Camera releated IOCTLs + * The input_lock downgrade the FPS of 3A*/ + if (c->ctrl_class == V4L2_CTRL_CLASS_CAMERA) { + ret = atomisp_camera_s_ext_ctrls(file, fh, c); + return ret; + } + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + ret = atomisp_s_ctrl(file, fh, &ctrl); + c->controls[i].value = ctrl.value; + if (ret) { + c->error_idx = i; + break; + } + } + return ret; + } + + return -EINVAL; +} + +/* + * vidioc_g/s_param are used to switch isp running mode + */ +static int atomisp_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + + mutex_lock(&isp->input_lock); + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_err(&atomisp_dev, + "unsupport v4l2 buf type\n"); + mutex_unlock(&isp->input_lock); + return -EINVAL; + } + + parm->parm.capture.capturemode = isp->sw_contex.run_mode; + + mutex_unlock(&isp->input_lock); + return 0; +} + +static int atomisp_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + int ret = 0; + + mutex_lock(&isp->input_lock); + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_err(&atomisp_dev, + "unsupport v4l2 buf type\n"); + mutex_unlock(&isp->input_lock); + return -EINVAL; + } + + isp->sw_contex.run_mode = parm->parm.capture.capturemode; + + mutex_unlock(&isp->input_lock); + return ret; +} + +static int atomisp_s_parm_file(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + + if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_err(&atomisp_dev, + "unsupport v4l2 buf type for output\n"); + return -EINVAL; + } + + isp->sw_contex.output_mode = parm->parm.output.outputmode; + if (isp->sw_contex.output_mode == OUTPUT_MODE_FILE) + isp->sw_contex.file_input = 1; + + + return 0; +} + +/* set default atomisp ioctl value */ +static long atomisp_vidioc_default(struct file *file, void *fh, + int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct atomisp_device *isp = video_get_drvdata(vdev); + + switch (cmd) { + case ATOMISP_IOC_G_XNR: + return atomisp_xnr(isp, 0, arg); + + case ATOMISP_IOC_S_XNR: + return atomisp_xnr(isp, 1, arg); + + case ATOMISP_IOC_G_BAYER_NR: + return atomisp_bayer_nr(isp, 0, arg); + + case ATOMISP_IOC_S_BAYER_NR: + return atomisp_bayer_nr(isp, 1, arg); + + case ATOMISP_IOC_G_TNR: + return atomisp_tnr(isp, 0, arg); + + case ATOMISP_IOC_S_TNR: + return atomisp_tnr(isp, 1, arg); + + case ATOMISP_IOC_G_HISTOGRAM: + return atomisp_histogram(isp, 0, arg); + + case ATOMISP_IOC_S_HISTOGRAM: + return atomisp_histogram(isp, 1, arg); + + case ATOMISP_IOC_G_BLACK_LEVEL_COMP: + return atomisp_black_level(isp, 0, arg); + + case ATOMISP_IOC_S_BLACK_LEVEL_COMP: + return atomisp_black_level(isp, 1, arg); + + case ATOMISP_IOC_G_YCC_NR: + return atomisp_ycc_nr(isp, 0, arg); + + case ATOMISP_IOC_S_YCC_NR: + return atomisp_ycc_nr(isp, 1, arg); + + case ATOMISP_IOC_G_EE: + return atomisp_ee(isp, 0, arg); + + case ATOMISP_IOC_S_EE: + return atomisp_ee(isp, 1, arg); + + case ATOMISP_IOC_G_DIS_STAT: + return atomisp_dis_stat(isp, 0, arg); + + case ATOMISP_IOC_S_DIS_STAT: + return atomisp_dis_stat(isp, 1, arg); + + case ATOMISP_IOC_S_DIS_VECTOR: + return atomisp_dis_vector(isp, arg); + + case ATOMISP_IOC_G_ISP_PARM: + return atomisp_param(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_PARM: + return atomisp_param(isp, 1, arg); + + case ATOMISP_IOC_G_3A_STAT: + return atomisp_3a_stat(isp, 0, arg); + + case ATOMISP_IOC_G_ISP_GAMMA: + return atomisp_gamma(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_GAMMA: + return atomisp_gamma(isp, 1, arg); + + case ATOMISP_IOC_G_ISP_GDC_TAB: + return atomisp_gdc_cac_table(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_GDC_TAB: + return atomisp_gdc_cac_table(isp, 1, arg); + + case ATOMISP_IOC_G_ISP_MACC: + return atomisp_macc_table(isp, 0, + (struct atomisp_macc_config *)arg); + + case ATOMISP_IOC_S_ISP_MACC: + return atomisp_macc_table(isp, 1, + (struct atomisp_macc_config *)arg); + + case ATOMISP_IOC_G_ISP_BAD_PIXEL_DETECTION: + return atomisp_bad_pixel_param(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_BAD_PIXEL_DETECTION: + return atomisp_bad_pixel_param(isp, 1, arg); + + case ATOMISP_IOC_G_ISP_FALSE_COLOR_CORRECTION: + return atomisp_false_color_param(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_FALSE_COLOR_CORRECTION: + return atomisp_false_color_param(isp, 1, arg); + + case ATOMISP_IOC_G_ISP_CTC: + return atomisp_ctc(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_CTC: + return atomisp_ctc(isp, 1, arg); + + case ATOMISP_IOC_G_ISP_WHITE_BALANCE: + return atomisp_white_balance_param(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_WHITE_BALANCE: + return atomisp_white_balance_param(isp, 1, arg); + + case ATOMISP_IOC_G_3A_CONFIG: + return atomisp_3a_config_param(isp, 0, arg); + + case ATOMISP_IOC_S_3A_CONFIG: + return atomisp_3a_config_param(isp, 1, arg); + + case ATOMISP_IOC_G_ISP_FPN_TABLE: + return atomisp_fixed_pattern_table(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_FPN_TABLE: + return atomisp_fixed_pattern_table(isp, 1, arg); + + case ATOMISP_IOC_G_ISP_OVERLAY: + return atomisp_vf_overlay(isp, 0, arg); + + case ATOMISP_IOC_S_ISP_OVERLAY: + return atomisp_vf_overlay(isp, 1, arg); + + case ATOMISP_IOC_ISP_MAKERNOTE: + return atomisp_exif_makernote(isp, arg); + + case ATOMISP_IOC_G_SENSOR_MODE_DATA: + return atomisp_get_sensor_mode_data(isp, arg); + + case ATOMISP_IOC_S_EXPOSURE: + case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP: + case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: + return v4l2_subdev_call(isp->inputs[isp->input_curr].camera, + core, ioctl, cmd, arg); + + case ATOMISP_IOC_ACC_LOAD: + return atomisp_acc_load(isp, arg); + + case ATOMISP_IOC_ACC_UNLOAD: + return atomisp_acc_unload(isp, arg); + + case ATOMISP_IOC_ACC_S_ARG: + return atomisp_acc_set_arg(isp, arg); + + case ATOMISP_IOC_ACC_START: + return atomisp_acc_start(isp, arg); + + case ATOMISP_IOC_ACC_WAIT: + return atomisp_acc_wait(isp, arg); + + case ATOMISP_IOC_ACC_ABORT: + return atomisp_acc_abort(isp, arg); + + case ATOMISP_IOC_CAMERA_BRIDGE: + /* here we convert the atomisp struct to a BC_Video struct. + * We do this to avoid exporting the BC_Video struct in + * atomisp.h which causes duplicate structure compilation + * errors. */ + return BC_Camera_Bridge((BC_Video_ioctl_package *)arg, + (unsigned long) NULL); + + default: + return -EINVAL; + } +} + +const struct v4l2_ioctl_ops atomisp_ioctl_ops = { + .vidioc_querycap = atomisp_querycap, + .vidioc_g_chip_ident = atomisp_g_chip_ident, + .vidioc_enum_input = atomisp_enum_input, + .vidioc_g_input = atomisp_g_input, + .vidioc_s_input = atomisp_s_input, + .vidioc_queryctrl = atomisp_queryctl, + .vidioc_s_ctrl = atomisp_s_ctrl, + .vidioc_g_ctrl = atomisp_g_ctrl, + .vidioc_s_ext_ctrls = atomisp_s_ext_ctrls, + .vidioc_g_ext_ctrls = atomisp_g_ext_ctrls, + .vidioc_enum_fmt_vid_cap = atomisp_enum_fmt_cap, + .vidioc_try_fmt_vid_cap = atomisp_try_fmt_cap, + .vidioc_g_fmt_vid_cap = atomisp_g_fmt_cap, + .vidioc_s_fmt_vid_cap = atomisp_s_fmt_cap, + .vidioc_s_fmt_type_private = atomisp_s_fmt_cap, + .vidioc_reqbufs = atomisp_reqbufs, + .vidioc_querybuf = atomisp_querybuf, + .vidioc_qbuf = atomisp_qbuf, + .vidioc_dqbuf = atomisp_dqbuf, + .vidioc_streamon = atomisp_streamon, + .vidioc_streamoff = atomisp_streamoff, + .vidioc_default = atomisp_vidioc_default, + .vidioc_cropcap = atomisp_cropcap, + .vidioc_enum_framesizes = atomisp_enum_framesizes, + .vidioc_enum_frameintervals = atomisp_enum_frameintervals, + .vidioc_s_parm = atomisp_s_parm, + .vidioc_g_parm = atomisp_g_parm, + .vidioc_g_std = atomisp_g_std, + .vidioc_s_std = atomisp_s_std, + .vidioc_g_crop = atomisp_g_crop, + .vidioc_s_crop = atomisp_s_crop, +}; + +const struct v4l2_ioctl_ops atomisp_file_ioctl_ops = { + .vidioc_querycap = atomisp_querycap, + .vidioc_g_fmt_vid_out = atomisp_g_fmt_file, + .vidioc_s_fmt_vid_out = atomisp_s_fmt_file, + .vidioc_s_parm = atomisp_s_parm_file, + .vidioc_reqbufs = atomisp_reqbufs_file, + .vidioc_querybuf = atomisp_querybuf_file, + .vidioc_qbuf = atomisp_qbuf_file, + /* .vidioc_streamon = atomisp_streamon_out, */ +}; diff --git a/drivers/media/video/atomisp/atomisp_ioctl.h b/drivers/media/video/atomisp/atomisp_ioctl.h new file mode 100644 index 0000000..6a7e1bd --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_ioctl.h @@ -0,0 +1,46 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __ATOMISP_CTRL_H__ +#define __ATOMISP_CTRL_H__ + +#include "atomisp_common.h" + +/* + * v4l2 ioctls + */ +int atomisp_streamoff(struct file *file, void *fh, + enum v4l2_buf_type type); + +int atomisp_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *req); + +extern const struct v4l2_file_operations atomisp_fops; + +extern const struct v4l2_file_operations atomisp_file_fops; + +extern const struct v4l2_ioctl_ops atomisp_ioctl_ops; + +extern const struct v4l2_ioctl_ops atomisp_file_ioctl_ops; + +#endif diff --git a/drivers/media/video/atomisp/atomisp_subdev.c b/drivers/media/video/atomisp/atomisp_subdev.c new file mode 100644 index 0000000..c41fb46 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_subdev.c @@ -0,0 +1,685 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "atomisp_internal.h" + +static const unsigned int isp_subdev_input_fmts[] = { + V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SGBRG10_1X10, +}; + +static const unsigned int isp_subdev_vf_output_fmts[] = { + /* yuv420, nv12, yv12, nv21, rgb565 */ + V4L2_MBUS_FMT_UYVY8_1X16, + V4L2_MBUS_FMT_YUYV8_1X16, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_NV21, +}; + +static const unsigned int isp_subdev_mo_output_fmts[] = { + /* yuv420, nv12, yv12, nv21, rgb565, nv11, yuv422, nv16, yv16, yuy2 */ + /* rgb565, rgb888 */ + V4L2_MBUS_FMT_UYVY8_1X16, + V4L2_MBUS_FMT_YUYV8_1X16, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_YUV422P, + V4L2_PIX_FMT_YUV444, + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_NV21, + V4L2_PIX_FMT_NV16, + V4L2_PIX_FMT_NV61, + V4L2_PIX_FMT_YUYV, + V4L2_PIX_FMT_UYVY, + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB32 +}; + +/* +* V4L2 subdev operations +*/ + +/* + * isp_subdev_get_ctrl - V4L2 control get handler + * @sd: ISP V4L2 subdevice + * @ctrl: V4L2 control + * + * Return 0 on success or a negative error code otherwise. +*/ +static int isp_subdev_get_ctrl(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + return -EINVAL; +} + +/* + * isp_subdev_set_ctrl - V4L2 control set handler + * @sd: ISP CCDC V4L2 subdevice + * @ctrl: V4L2 control + * + * Return 0 on success or a negative error code otherwise. +*/ +static int isp_subdev_set_ctrl(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + return -EINVAL; +} + +/* + * isp_subdev_ioctl - CCDC module private ioctl's + * @sd: ISP V4L2 subdevice + * @cmd: ioctl command + * @arg: ioctl argument + * + * Return 0 on success or a negative error code otherwise. +*/ +static long isp_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int ret = 0; + + return ret; +} + +/* + * isp_subdev_set_power - Power on/off the CCDC module + * @sd: ISP V4L2 subdevice + * @on: power on/off + * + * Return 0 on success or a negative error code otherwise. +*/ +static int isp_subdev_set_power(struct v4l2_subdev *sd, int on) +{ + return 0; +} + +static int isp_subdev_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + + /* TBD + return v4l2_event_subscribe(fh, sub); + */ + return 0; +} + +static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +/* +* isp_subdev_set_stream - Enable/Disable streaming on the isp sub module +* @sd: ISP V4L2 subdevice +* @enable: Enable/disable stream +*/ +static int isp_subdev_set_stream(struct v4l2_subdev *sd, int enable) +{ + int ret = 0; + + /* handle continuous, single shot or stopped state */ + return ret; +} + +static struct v4l2_mbus_framefmt * +__isp_subdev_get_format(struct atomisp_sub_device *isp_subdev, + struct v4l2_subdev_fh *fh, unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + if (pad == ATOMISP_SUBDEV_PAD_SINK || + pad == ATOMISP_SUBDEV_PAD_SOURCE_VF || + pad == ATOMISP_SUBDEV_PAD_SOURCE_MO) + return &isp_subdev->formats[pad]; + else + return NULL; + default: + return NULL; + } +} + +/* + * isp_subdev_try_format - Try video format on a pad + * @isp_subdev: ISP v4l2 sub device + * @fh : V4L2 subdev file handle + * @pad: Pad number + * @fmt: Format +*/ +static void +isp_subdev_try_format(struct atomisp_sub_device *isp_subdev, + struct v4l2_subdev_fh *fh, + unsigned int pad, struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + unsigned int width = fmt->width; + unsigned int height = fmt->height; + enum v4l2_mbus_pixelcode pixelcode; + unsigned int i; + + switch (pad) { + case ATOMISP_SUBDEV_PAD_SINK: + if (isp_subdev->input == ATOMISP_SUBDEV_INPUT_MEMORY) { + fmt->width = clamp_t(u32, fmt->width, + ATOM_ISP_MIN_WIDTH, ATOM_ISP_MAX_WIDTH); + fmt->height = clamp_t(u32, fmt->height, + ATOM_ISP_MIN_HEIGHT, ATOM_ISP_MAX_HEIGHT); + } + + fmt->colorspace = V4L2_COLORSPACE_SRGB; + for (i = 0; i < ARRAY_SIZE(isp_subdev_input_fmts); i++) { + if (fmt->code == isp_subdev_input_fmts[i]) + break; + } + + /* If not found, use SGRBG10 as default */ + if (i >= ARRAY_SIZE(isp_subdev_input_fmts)) + fmt->code = V4L2_MBUS_FMT_SBGGR10_1X10; + + /* Clamp the input size. */ + fmt->width = clamp_t(u32, width, 32, 4096); + fmt->height = clamp_t(u32, height, 32, 4096); + + break; + + case ATOMISP_SUBDEV_PAD_SOURCE_VF: + pixelcode = fmt->code; + format = __isp_subdev_get_format(isp_subdev, fh, + ATOMISP_SUBDEV_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + + switch (pixelcode) { + /* yuv420, nv12, yv12, nv21, rgb565 */ + case V4L2_MBUS_FMT_YUYV8_1X16: + case V4L2_MBUS_FMT_UYVY8_1X16: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + case V4L2_MBUS_FMT_YUYV8_1_5X8: + fmt->code = pixelcode; + break; + default: + fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; + break; + } + + /* The data formatter truncates the number of horizontal output + * pixels to a multiple of 16. To avoid clipping data, allow + * callers to request an output size bigger than the input size + * up to the nearest multiple of 16. + */ + fmt->width = clamp_t(u32, width, 256, 1920); + fmt->height = clamp_t(u32, height, 0, 1080); + break; + + case ATOMISP_SUBDEV_PAD_SOURCE_MO: + pixelcode = fmt->code; + format = __isp_subdev_get_format(isp_subdev, fh, + ATOMISP_SUBDEV_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + switch (pixelcode) { + /* yuv420, nv12, yv12, nv21, rgb565, nv11, yuv422 */ + /* nv16, yv16, yuy2 */ + /* rgb565, rgb888 */ + case V4L2_MBUS_FMT_YUYV8_1X16: + case V4L2_MBUS_FMT_UYVY8_1X16: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + case V4L2_MBUS_FMT_YUYV8_1_5X8: + fmt->code = pixelcode; + break; + default: + fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; + break; + } + + /* The number of lines that can be clocked out from the video + * port output must be at least one line less than the number + * of input lines. + */ + fmt->width = clamp_t(u32, width, 256, 4608); + fmt->height = clamp_t(u32, height, 0, fmt->height - 1); + break; + } + + /* Data is written to memory unpacked, each 10-bit pixel is stored on + * 2 bytes. + */ + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->field = V4L2_FIELD_NONE; +} + +/* + * isp_subdev_enum_mbus_code - Handle pixel format enumeration + * @sd: pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure + * return -EINVAL or zero on success +*/ +static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + switch (code->pad) { + case ATOMISP_SUBDEV_PAD_SINK: + if (code->index >= ARRAY_SIZE(isp_subdev_input_fmts)) + return -EINVAL; + + code->code = isp_subdev_input_fmts[code->index]; + break; + + case ATOMISP_SUBDEV_PAD_SOURCE_VF: + /* format conversion inside isp subdev */ + if (code->index >= ARRAY_SIZE(isp_subdev_vf_output_fmts)) + return -EINVAL; + + code->code = isp_subdev_vf_output_fmts[code->index]; + break; + case ATOMISP_SUBDEV_PAD_SOURCE_MO: + /* format conversion inside isp subdev */ + if (code->index >= ARRAY_SIZE(isp_subdev_mo_output_fmts)) + return -EINVAL; + + code->code = isp_subdev_mo_output_fmts[code->index]; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int isp_subdev_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct atomisp_sub_device *isp_subdev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + isp_subdev_try_format(isp_subdev, fh, fse->pad, + &format, V4L2_SUBDEV_FORMAT_TRY); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + isp_subdev_try_format(isp_subdev, fh, fse->pad, + &format, V4L2_SUBDEV_FORMAT_TRY); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * isp_subdev_get_format - Retrieve the video format on a pad + * @sd : ISP V4L2 subdevice + * @fh : V4L2 subdev file handle + * @pad: Pad number + * @fmt: Format + * + * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond + * to the format type. +*/ +static int isp_subdev_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) +{ + struct atomisp_sub_device *isp_subdev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __isp_subdev_get_format(isp_subdev, fh, fmt->pad, fmt->which); + if (format == NULL) { + v4l2_err(&atomisp_dev, "no format available\n"); + return -EINVAL; + } + + fmt->format = *format; + return 0; +} + +/* + * isp_subdev_set_format - Set the video format on a pad + * @sd : ISP subdev V4L2 subdevice + * @fh : V4L2 subdev file handle + * @pad: Pad number + * @fmt: Format + * + * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond + * to the format type. +*/ +static int isp_subdev_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) +{ + struct atomisp_sub_device *isp_subdev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __isp_subdev_get_format(isp_subdev, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + isp_subdev_try_format(isp_subdev, fh, fmt->pad, + &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == ATOMISP_SUBDEV_PAD_SINK) { + format = __isp_subdev_get_format(isp_subdev, fh, + ATOMISP_SUBDEV_PAD_SOURCE_VF, fmt->which); + *format = fmt->format; + isp_subdev_try_format(isp_subdev, fh, + ATOMISP_SUBDEV_PAD_SOURCE_VF, format, fmt->which); + + format = __isp_subdev_get_format(isp_subdev, fh, + ATOMISP_SUBDEV_PAD_SOURCE_MO, fmt->which); + *format = fmt->format; + isp_subdev_try_format(isp_subdev, fh, + ATOMISP_SUBDEV_PAD_SOURCE_MO, format, fmt->which); + } + + return 0; +} + + /* V4L2 subdev core operations */ + static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = { + .g_ctrl = isp_subdev_get_ctrl, + .s_ctrl = isp_subdev_set_ctrl, + .ioctl = isp_subdev_ioctl, + .s_power = isp_subdev_set_power, + .subscribe_event = isp_subdev_subscribe_event, + .unsubscribe_event = isp_subdev_unsubscribe_event, + }; + + /* V4L2 subdev video operations */ + static const struct v4l2_subdev_video_ops isp_subdev_v4l2_video_ops = { + .s_stream = isp_subdev_set_stream, + }; + + /* V4L2 subdev pad operations */ + static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = { + .enum_mbus_code = isp_subdev_enum_mbus_code, + .enum_frame_size = isp_subdev_enum_frame_size, + .get_fmt = isp_subdev_get_format, + .set_fmt = isp_subdev_set_format, + }; + + /* V4L2 subdev operations */ + static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = { + .core = &isp_subdev_v4l2_core_ops, + .video = &isp_subdev_v4l2_video_ops, + .pad = &isp_subdev_v4l2_pad_ops, + }; + +static void isp_subdev_init_params(struct atomisp_sub_device *isp_subdev) +{ + /* parameters initialization */ + +} + +/* +* isp_subdev_link_setup - Setup isp subdev connections +* @entity: ispsubdev media entity +* @local: Pad at the local end of the link +* @remote: Pad at the remote end of the link +* @flags: Link flags +* +* return -EINVAL or zero on success +*/ +static int isp_subdev_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); + struct atomisp_device *isp = isp_sd->isp; + + switch (local->index | media_entity_type(remote->entity)) { + case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENTITY_TYPE_V4L2_SUBDEV: + /* Read from the sensor CSI2-4p or CSI2-1p. */ + if (!(flags & MEDIA_LINK_FLAG_ENABLED)) { + isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; + break; + } + + if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE) + return -EBUSY; + + if (remote->entity == &isp->csi2_4p.subdev.entity) + isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_4P; + else if (remote->entity == &isp->csi2_1p.subdev.entity) + isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_1P; + else + isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_4P; + + break; + + case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENTITY_TYPE_DEVNODE: + /* read from memory */ + if (flags & MEDIA_LINK_FLAG_ENABLED) { + if (isp_sd->input == ATOMISP_SUBDEV_INPUT_CSI2_4P + || isp_sd->input == ATOMISP_SUBDEV_INPUT_CSI2_1P) + return -EBUSY; + isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY; + } else { + if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY) + isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; + } + break; + + case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENTITY_TYPE_DEVNODE: + /* always write to memory */ + break; + + case ATOMISP_SUBDEV_PAD_SOURCE_MO | MEDIA_ENTITY_TYPE_DEVNODE: + /* always write to memory */ + break; + + default: + return -EINVAL; + } + + return 0; +} + + /* media operations */ + static const struct media_entity_operations isp_subdev_media_ops = { + .link_setup = isp_subdev_link_setup, + .set_power = v4l2_subdev_set_power, + }; + +/* + * isp_subdev_init_entities - Initialize V4L2 subdev and media entity + * @isp_subdev: ISP CCDC module + * + * Return 0 on success and a negative error code on failure. +*/ +static int isp_subdev_init_entities(struct atomisp_sub_device *isp_subdev) +{ + struct v4l2_subdev *sd = &isp_subdev->subdev; + struct media_pad *pads = isp_subdev->pads; + struct media_entity *me = &sd->entity; + int ret; + + isp_subdev->input = ATOMISP_SUBDEV_INPUT_NONE; + + v4l2_subdev_init(sd, &isp_subdev_v4l2_ops); + strlcpy(sd->name, "ATOM ISP SUBDEV", sizeof(sd->name)); + v4l2_set_subdevdata(sd, isp_subdev); + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->nevents = 16; /* TBD */ + + pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FLAG_INPUT; + pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FLAG_OUTPUT; + pads[ATOMISP_SUBDEV_PAD_SOURCE_MO].flags = MEDIA_PAD_FLAG_OUTPUT; + + isp_subdev->formats[ATOMISP_SUBDEV_PAD_SINK].code = + V4L2_MBUS_FMT_SBGGR10_1X10; + isp_subdev->formats[ATOMISP_SUBDEV_PAD_SOURCE_VF].code = + V4L2_MBUS_FMT_SBGGR10_1X10; + isp_subdev->formats[ATOMISP_SUBDEV_PAD_SOURCE_MO].code = + V4L2_MBUS_FMT_SBGGR10_1X10; + + me->ops = &isp_subdev_media_ops; + me->type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; + ret = media_entity_init(me, ATOMISP_SUBDEV_PADS_NUM, pads, 0); + if (ret < 0) + return ret; + + isp_subdev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + isp_subdev->video_in.isp = isp_subdev->isp; + + isp_subdev->video_out_vf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + isp_subdev->video_out_vf.isp = isp_subdev->isp; + isp_subdev->video_out_vf.is_main = false; + + isp_subdev->video_out_mo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + isp_subdev->video_out_mo.isp = isp_subdev->isp; + isp_subdev->video_out_mo.is_main = true; + + + ret = atomisp_video_init(&isp_subdev->video_in, "MEMORY"); + if (ret < 0) + return ret; + + ret = atomisp_video_init(&isp_subdev->video_out_mo, "MAINOUTPUT"); + if (ret < 0) + return ret; + + ret = atomisp_video_init(&isp_subdev->video_out_vf, "VIEWFINDER"); + if (ret < 0) + return ret; + + /* Connect the isp subdev to the video node. */ + ret = media_entity_create_link(&isp_subdev->video_in.vdev.entity, + 0, &isp_subdev->subdev.entity, ATOMISP_SUBDEV_PAD_SINK, 0); + if (ret < 0) + return ret; + ret = media_entity_create_link(&isp_subdev->subdev.entity, + ATOMISP_SUBDEV_PAD_SOURCE_VF, + &isp_subdev->video_out_vf.vdev.entity, 0, 0); + if (ret < 0) + return ret; + + ret = media_entity_create_link(&isp_subdev->subdev.entity, + ATOMISP_SUBDEV_PAD_SOURCE_MO, + &isp_subdev->video_out_mo.vdev.entity, 0, 0); + if (ret < 0) + return ret; + + return 0; +} + +void atomisp_subdev_unregister_entities(struct atomisp_sub_device *isp_subdev) +{ + media_entity_cleanup(&isp_subdev->subdev.entity); + + v4l2_device_unregister_subdev(&isp_subdev->subdev); + atomisp_video_unregister(&isp_subdev->video_in); + atomisp_video_unregister(&isp_subdev->video_out_vf); + atomisp_video_unregister(&isp_subdev->video_out_mo); +} + +int atomisp_subdev_register_entities(struct atomisp_sub_device *isp_subdev, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video node. */ + ret = v4l2_device_register_subdev(vdev, &isp_subdev->subdev); + if (ret < 0) + goto error; + + ret = atomisp_video_register(&isp_subdev->video_out_mo, vdev); + if (ret < 0) + goto error; + + ret = atomisp_video_register(&isp_subdev->video_out_vf, vdev); + if (ret < 0) + goto error; + + ret = atomisp_video_register(&isp_subdev->video_in, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + atomisp_subdev_unregister_entities(isp_subdev); + return ret; +} + + +/* + * atomisp_subdev_init - ISP Subdevice initialization. + * @dev: Device pointer specific to the ATOM ISP. + * + * TODO: Get the initialisation values from platform data. + * + * Return 0 on success or a negative error code otherwise. +*/ +int atomisp_subdev_init(struct atomisp_device *isp) +{ + struct atomisp_sub_device *isp_subdev = &isp->isp_subdev; + int ret; + + spin_lock_init(&isp_subdev->lock); + isp_subdev->isp = isp; + isp_subdev_init_params(isp_subdev); + ret = isp_subdev_init_entities(isp_subdev); + if (ret < 0) + atomisp_subdev_cleanup(isp); + + return ret; +} + +void atomisp_subdev_cleanup(struct atomisp_device *isp) +{ + +} + diff --git a/drivers/media/video/atomisp/atomisp_subdev.h b/drivers/media/video/atomisp/atomisp_subdev.h new file mode 100644 index 0000000..a35cb0c --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_subdev.h @@ -0,0 +1,81 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#ifndef ATOMISP_SUBDEV_H_ +#define ATOMISP_SUBDEV_H_ + +#include +#include +#include + +enum atomisp_subdev_input_entity { + ATOMISP_SUBDEV_INPUT_NONE, + ATOMISP_SUBDEV_INPUT_MEMORY, + ATOMISP_SUBDEV_INPUT_CSI2, + ATOMISP_SUBDEV_INPUT_CSI2_4P, + ATOMISP_SUBDEV_INPUT_CSI2_1P +}; + +#define ATOMISP_SUBDEV_PAD_SINK 0 +#define ATOMISP_SUBDEV_PAD_SOURCE_VF 1 /* viewfinder output*/ +#define ATOMISP_SUBDEV_PAD_SOURCE_MO 2 /* regular output */ +#define ATOMISP_SUBDEV_PADS_NUM 3 + +struct atomisp_video_pipe { + struct video_device vdev; + enum v4l2_buf_type type; + struct media_pad pad; + struct videobuf_queue capq; + struct videobuf_queue outq; + struct list_head activeq; + struct list_head activeq_out; + struct mutex mutex; + + spinlock_t irq_lock; + bool opened; + bool is_main; + + struct atomisp_device *isp; + struct atomisp_fmt *out_fmt; + struct atomisp_video_pipe_format *format; +}; + +struct atomisp_sub_device { + struct v4l2_subdev subdev; + struct media_pad pads[ATOMISP_SUBDEV_PADS_NUM]; + struct v4l2_mbus_framefmt formats[ATOMISP_SUBDEV_PADS_NUM]; + + enum atomisp_subdev_input_entity input; + unsigned int output; + struct atomisp_video_pipe video_in; + struct atomisp_video_pipe video_out_vf; /* view finder */ + struct atomisp_video_pipe video_out_mo; /* main output */ + /* struct isp_subdev_params params; */ + spinlock_t lock; + struct atomisp_device *isp; +}; + +void atomisp_subdev_unregister_entities(struct atomisp_sub_device *isp_subdev); +int atomisp_subdev_register_entities(struct atomisp_sub_device *isp_subdev, + struct v4l2_device *vdev); +int atomisp_subdev_init(struct atomisp_device *isp); +void atomisp_subdev_cleanup(struct atomisp_device *isp); + +#endif diff --git a/drivers/media/video/atomisp/atomisp_tpg.c b/drivers/media/video/atomisp/atomisp_tpg.c new file mode 100644 index 0000000..7d98c82 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_tpg.c @@ -0,0 +1,281 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include "atomisp_internal.h" +#include "atomisp_tpg.h" + +static int tpg_s_stream(struct v4l2_subdev *sd, int enable) +{ + return 0; +} + +static int tpg_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmtdesc) +{ + /*to fake*/ + return 0; +} + +static int tpg_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + /*to fake*/ + return 0; +} +static int tpg_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + /*to fake*/ + return 0; +} +static int tpg_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + /*to fake*/ + return 0; +} + +static int tpg_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) +{ + /*to fake*/ + return 0; +} + +static int tpg_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) +{ + /*to fake*/ + return 0; +} + +static int tpg_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_frmsizeenum *fsize) +{ + /*to fake*/ + return 0; +} + +static int tpg_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_frmivalenum *fival) +{ + /*to fake*/ + return 0; +} + +static int tpg_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + /*to fake*/ + return 0; +} + +static int tpg_try_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + /*to fake*/ + return 0; +} + +static int tpg_g_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + /*to fake*/ + return 0; +} + +static int tpg_s_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + /*to fake*/ + return 0; +} + +static int tpg_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct atomisp_tpg_device *dev; + dev = container_of(sd, struct atomisp_tpg_device, sd); + + if (!chip) + return -EINVAL; + return 0; +} + +static int tpg_log_status(struct v4l2_subdev *sd) +{ + /*to fake*/ + return 0; +} + +static int tpg_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) +{ + /*to fake*/ + return 0; +} + +static int tpg_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + /*to fake*/ + return -EINVAL; +} + +static int tpg_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + /*to fake*/ + return -EINVAL; +} + +static int tpg_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + /*to fake*/ + return 0; +} + +static int tpg_s_power(struct v4l2_subdev *sd, int on) +{ + int x_delta = -2; + int y_delta = 3; + unsigned int x_mask = (1 << 4) - 1; + unsigned int y_mask = (1 << 4) - 1; + unsigned int xy_mask = (1 << 8) - 1; + + sh_css_tpg_configure(x_mask, x_delta, y_mask, y_delta, xy_mask); + sh_css_input_set_mode(SH_CSS_INPUT_MODE_TPG); + return 0; +} + +static int tpg_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + /*to fake*/ + return 0; +} + +static int tpg_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + /*to fake*/ + return 0; +} + +static int tpg_enum_frame_ival(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_interval_enum *fie) +{ + /*to fake*/ + return 0; +} + +static const struct v4l2_subdev_video_ops tpg_video_ops = { + .s_stream = tpg_s_stream, + .enum_fmt = tpg_enum_fmt, + .try_fmt = tpg_try_fmt, + .g_fmt = tpg_g_fmt, + .s_fmt = tpg_s_fmt, + .g_parm = tpg_g_parm, + .s_parm = tpg_s_parm, + .enum_framesizes = tpg_enum_framesizes, + .enum_frameintervals = tpg_enum_frameintervals, + .enum_mbus_fmt = tpg_enum_mbus_fmt, + .try_mbus_fmt = tpg_try_mbus_fmt, + .g_mbus_fmt = tpg_g_mbus_fmt, + .s_mbus_fmt = tpg_s_mbus_fmt, +}; + +static const struct v4l2_subdev_core_ops tpg_core_ops = { + .g_chip_ident = tpg_g_chip_ident, + .log_status = tpg_log_status, + .s_config = tpg_s_config, + .queryctrl = tpg_queryctrl, + .g_ctrl = tpg_g_ctrl, + .s_ctrl = tpg_s_ctrl, + .s_power = tpg_s_power, +}; + +static const struct v4l2_subdev_pad_ops tpg_pad_ops = { + .enum_mbus_code = tpg_enum_mbus_code, + .enum_frame_size = tpg_enum_frame_size, + .enum_frame_interval = tpg_enum_frame_ival, +}; + +static const struct v4l2_subdev_ops tpg_ops = { + .core = &tpg_core_ops, + .video = &tpg_video_ops, + .pad = &tpg_pad_ops, +}; + +static const struct media_entity_operations tpg_entity_ops = { + .set_power = v4l2_subdev_set_power, +}; + +void atomisp_tpg_unregister_entities(struct atomisp_tpg_device *tpg) +{ + v4l2_device_unregister_subdev(&tpg->sd); +} + +int atomisp_tpg_register_entities(struct atomisp_tpg_device *tpg, + struct v4l2_device *vdev) +{ + int ret; + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &tpg->sd); + if (ret < 0) + goto error; + + return 0; + +error: + atomisp_tpg_unregister_entities(tpg); + return ret; +} + +void atomisp_tpg_cleanup(struct atomisp_device *isp) +{ + +} + +int atomisp_tpg_init(struct atomisp_device *isp) +{ + struct atomisp_tpg_device *tpg = &isp->tpg; + struct v4l2_subdev *sd = &tpg->sd; + struct media_pad *pads = tpg->pads; + struct media_entity *me = &sd->entity; + int ret; + + tpg->isp = isp; + v4l2_subdev_init(sd, &tpg_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + strcpy(sd->name, "tpg_subdev"); + v4l2_set_subdevdata(sd, tpg); + + pads[0].flags = MEDIA_PAD_FLAG_INPUT; + me->type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; + + ret = media_entity_init(me, 1, pads, 0); + if (ret < 0) + goto fail; + return 0; +fail: + atomisp_tpg_cleanup(isp); + return ret; +} diff --git a/drivers/media/video/atomisp/atomisp_tpg.h b/drivers/media/video/atomisp/atomisp_tpg.h new file mode 100644 index 0000000..65740af --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_tpg.h @@ -0,0 +1,44 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __TPG_H__ +#define __TPG_H__ + +#include +#include +#include +#include + +struct atomisp_tpg_device { + struct v4l2_subdev sd; + struct atomisp_device *isp; + struct media_pad pads[1]; +}; + +void atomisp_tpg_cleanup(struct atomisp_device *isp); +int atomisp_tpg_init(struct atomisp_device *isp); +void atomisp_tpg_unregister_entities(struct atomisp_tpg_device *tpg); +int atomisp_tpg_register_entities(struct atomisp_tpg_device *tpg, + struct v4l2_device *vdev); + +#endif diff --git a/drivers/media/video/atomisp/atomisp_v4l2.c b/drivers/media/video/atomisp/atomisp_v4l2.c new file mode 100644 index 0000000..44c9742 --- /dev/null +++ b/drivers/media/video/atomisp/atomisp_v4l2.c @@ -0,0 +1,957 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#include +#include "atomisp_ioctl.h" +#include "atomisp_cmd.h" +#include "atomisp_fops.h" +#include "atomisp_file.h" + +/* cross componnet debug message flag */ +int dbg_level; +module_param(dbg_level, int, 0644); +MODULE_PARM_DESC(dbg_level, "debug message on/off (default:off)"); + +int mipicsi_flag; +module_param(mipicsi_flag, int, 0644); +MODULE_PARM_DESC(mipicsi_flag, "mipi csi compression predictor algorithm"); + +int pad_w = 8; +module_param(pad_w, int, 0644); +MODULE_PARM_DESC(pad_w, "extra data for ISP processing"); + +int pad_h = 10; +module_param(pad_h, int, 0644); +MODULE_PARM_DESC(pad_h, "extra data for ISP processing"); + +struct v4l2_device atomisp_dev = { + .name = "atomisp", +}; + +void __iomem *atomisp_io_base; + +/* + * supported V4L2 fmts and resolutions + */ +const struct atomisp_format_bridge atomisp_output_fmts[] = { + { + .pixelformat = V4L2_PIX_FMT_YUV420, + .depth = 12, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_YUV420, + .description = "YUV420, planner"}, + { + .pixelformat = V4L2_PIX_FMT_YVU420, + .depth = 12, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_YV12, + .description = "YVU420, planner"}, + { + .pixelformat = V4L2_PIX_FMT_YUV422P, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_YUV422, + .description = "YUV422, planner"}, + { + .pixelformat = V4L2_PIX_FMT_YUV444, + .depth = 24, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_YUV444, + .description = "YUV444"}, + { + .pixelformat = V4L2_PIX_FMT_NV12, + .depth = 12, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_NV12, + .description = "NV12, interleaved"}, + { + .pixelformat = V4L2_PIX_FMT_NV21, + .depth = 12, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_NV21, + .description = "NV21, interleaved"}, + { + .pixelformat = V4L2_PIX_FMT_NV16, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_NV16, + .description = "NV16, interleaved"}, + { + .pixelformat = V4L2_PIX_FMT_YUYV, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_YUYV, + .description = "YUYV, interleaved"}, + { + .pixelformat = V4L2_PIX_FMT_UYVY, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .sh_fmt = SH_CSS_FRAME_FORMAT_UYVY, + .description = "UYVY, interleaved"}, + { + .pixelformat = V4L2_PIX_FMT_SBGGR16, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 16"}, + { + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .depth = 8, + .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 8"}, + { + .pixelformat = V4L2_PIX_FMT_SGBRG8, + .depth = 8, + .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 8"}, + { + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .depth = 8, + .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 8"}, + { + .pixelformat = V4L2_PIX_FMT_SRGGB8, + .depth = 8, + .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 8"}, + { + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 10"}, + { + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 10"}, + { + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 10"}, + { + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 10"}, + { + .pixelformat = V4L2_PIX_FMT_SBGGR12, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SBGGR12_1X12, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 12"}, + { + .pixelformat = V4L2_PIX_FMT_SGBRG12, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SBGGR12_1X12, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 12"}, + { + .pixelformat = V4L2_PIX_FMT_SGRBG12, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SBGGR12_1X12, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 12"}, + { + .pixelformat = V4L2_PIX_FMT_SRGGB12, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_SBGGR12_1X12, + .sh_fmt = SH_CSS_FRAME_FORMAT_RAW, + .description = "Bayer 12"}, + { + .pixelformat = V4L2_PIX_FMT_RGB32, + .depth = 32, + .mbus_code = V4L2_MBUS_FMT_FIXED, + .sh_fmt = SH_CSS_FRAME_FORMAT_RGBA888, + .description = "32 RGB 8-8-8-8"}, + { + .pixelformat = V4L2_PIX_FMT_RGB565, + .depth = 16, + .mbus_code = V4L2_MBUS_FMT_BGR565_2X8_LE, + .sh_fmt = SH_CSS_FRAME_FORMAT_RGB565, + .description = "16 RGB 5-6-5"} +}; + +const u32 atomisp_output_fmts_num = ARRAY_SIZE(atomisp_output_fmts); + +static struct atomisp_tvnorm tvnorms[] = { + { + .name = "atomisp format", + .id = V4L2_STD_NTSC_M, + .cxiformat = 0, + .cxoformat = 0x181f0008, + }, + { + .name = "atomisp format NULL", + .id = V4L2_STD_NTSC_M_JP, + .cxiformat = 1, + .cxoformat = 0x181f0008, + } +}; + +static const struct video_device atomisp_video_dev = { + .name = "atomisp", + .minor = -1, + .fops = &atomisp_fops, + .release = video_device_release_empty, + .ioctl_ops = &atomisp_ioctl_ops +}; + +int atomisp_video_init(struct atomisp_video_pipe *video, const char *name) +{ + int ret; + const char *direction; + + switch (video->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + direction = "output"; + video->pad.flags = MEDIA_PAD_FLAG_INPUT; + video->vdev.fops = &atomisp_fops; + video->vdev.ioctl_ops = &atomisp_ioctl_ops; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + direction = "input"; + video->pad.flags = MEDIA_PAD_FLAG_OUTPUT; + video->vdev.fops = &atomisp_file_fops; + video->vdev.ioctl_ops = &atomisp_file_ioctl_ops; + break; + default: + return -EINVAL; + } + + ret = media_entity_init(&video->vdev.entity, 1, &video->pad, 0); + if (ret < 0) + return ret; + + /* Initialize the video device. */ + snprintf(video->vdev.name, sizeof(video->vdev.name), + "ATOMISP ISP %s %s", name, direction); + video->vdev.vfl_type = VFL_TYPE_GRABBER; + video->vdev.release = video_device_release; + video_set_drvdata(&video->vdev, video->isp); + video->opened = false; + + return 0; +} + +int atomisp_video_register(struct atomisp_video_pipe *video, + struct v4l2_device *vdev) +{ + int ret; + + video->vdev.v4l2_dev = vdev; + + ret = video_register_device(&video->vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) + v4l2_err(&atomisp_dev, + "%s: could not register video device (%d)\n", + __func__, ret); + + return ret; +} + +void atomisp_video_unregister(struct atomisp_video_pipe *video) +{ + if (video_is_registered(&video->vdev)) { + media_entity_cleanup(&video->vdev.entity); + video_unregister_device(&video->vdev); + } +} + +#ifdef CONFIG_PM +static int atomisp_runtime_suspend(struct device *dev) +{ + struct atomisp_device *isp = (struct atomisp_device *) + dev_get_drvdata(dev); + int ret; + + /* save IUnit context */ + atomisp_save_iunit_reg(isp); + + /*Turn off the ISP power island*/ + ret = atomisp_ospm_power_island_down(isp); + + return ret; +} + +static int atomisp_runtime_resume(struct device *dev) +{ + struct atomisp_device *isp = (struct atomisp_device *) + dev_get_drvdata(dev); + int ret; + + if (isp->sw_contex.power_state == ATOM_ISP_POWER_DOWN) { + /*Turn on ISP power island*/ + ret = atomisp_ospm_power_island_up(isp); + if (ret) { + v4l2_err(&atomisp_dev, + "Failed to power up ISP!.\n"); + return -EINVAL; + } + } + + /*restore register values for iUnit and iUnitPHY registers*/ + if (isp->hw_contex.pcicmdsts) + atomisp_restore_iunit_reg(isp); + atomisp_save_iunit_reg(isp); + + return 0; +} + +static int atomisp_suspend(struct device *dev) +{ + struct atomisp_device *isp = (struct atomisp_device *) + dev_get_drvdata(dev); + int ret; + + /* + * FIXME: Suspend is not supported by sensors. Abort if any video + * node was opened. + */ + if (isp->sw_contex.init == true) + return -EBUSY; + + if (isp->sw_contex.isp_streaming) { + v4l2_err(&atomisp_dev, + "atomisp cannot suspend at this time.\n"); + return -EINVAL; + } + + /* save IUnit context */ + atomisp_save_iunit_reg(isp); + + /*Turn off the ISP power island*/ + ret = atomisp_ospm_power_island_down(isp); + if (ret) + v4l2_err(&atomisp_dev, + "fail to power off ISP\n"); + + return ret; +} + +static int atomisp_resume(struct device *dev) +{ + struct atomisp_device *isp = (struct atomisp_device *) + dev_get_drvdata(dev); + int ret; + + /*Turn on ISP power island*/ + ret = atomisp_ospm_power_island_up(isp); + if (ret) { + v4l2_err(&atomisp_dev, + "Failed to power up ISP!.\n"); + return -EINVAL; + } + + /*restore register values for iUnit and iUnitPHY registers*/ + if (isp->hw_contex.pcicmdsts) + atomisp_restore_iunit_reg(isp); + atomisp_save_iunit_reg(isp); + + return 0; +} +#endif + +static int atomisp_subdev_probe(struct atomisp_device *isp) +{ + struct atomisp_platform_data *pdata = NULL; + struct intel_v4l2_subdev_table *subdevs; + struct v4l2_subdev *subdev = NULL; + struct i2c_adapter *adapter = NULL; + struct i2c_board_info *board_info; + + pdata = (struct atomisp_platform_data *)intel_get_v4l2_subdev_table(); + if (pdata == NULL) { + v4l2_err(&atomisp_dev, "no platform data available\n"); + return -ENODEV; + } + + for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) { + board_info = &subdevs->v4l2_subdev.board_info; + v4l2_info(&atomisp_dev, "name %s, addr %d, id %d\n", + board_info->type, + board_info->addr, + subdevs->v4l2_subdev.i2c_adapter_id); + + adapter = i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id); + if (adapter == NULL) { + v4l2_err(&atomisp_dev, + "Failed to find i2c adapter for subdev %s\n" + , board_info->type); + break; + } + v4l2_info(&atomisp_dev, "Found adapter %s for subdev %s\n", + adapter->name, board_info->type); + + subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, + board_info, NULL, 1); + + if (subdev == NULL) { + v4l2_info(&atomisp_dev, + "Subdev %s detection fail\n", + board_info->type); + continue; + } + + v4l2_info(&atomisp_dev, + "Subdev %s successfully register\n", + board_info->type); + + switch (subdevs->type) { + case RAW_CAMERA: + case SOC_CAMERA: + if (isp->input_cnt >= ATOM_ISP_MAX_INPUTS) { + v4l2_warn(&atomisp_dev, + "too many atomisp inputs, ignored\n"); + break; + } + + v4l2_info(&atomisp_dev, + "still camera sensor detected\n"); + isp->inputs[isp->input_cnt].type = subdevs->type; + isp->inputs[isp->input_cnt].port = subdevs->port; + isp->inputs[isp->input_cnt].camera = subdev; + isp->inputs[isp->input_cnt].shading_table = NULL; + isp->inputs[isp->input_cnt].morph_table = NULL; + isp->input_cnt++; + break; + case CAMERA_MOTOR: + v4l2_info(&atomisp_dev, "lens/motor probed\n"); + isp->motor = subdev; + break; + case LED_FLASH: + case XENON_FLASH: + v4l2_info(&atomisp_dev, "flash probed\n"); + isp->flash = subdev; + break; + default: + v4l2_info(&atomisp_dev, "unkonw subdev probed\n"); + break; + } + + } + + /*Check camera for at least one subdev in it */ + if (!isp->inputs[0].camera) { + v4l2_info(&atomisp_dev, "atomisp: " + "no camera attached or fail to detect\n"); + return -ENODEV; + } + v4l2_info(&atomisp_dev, "%d camera(s) detect\n", isp->input_cnt); + return 0; +} + +static void atomisp_unregister_entities(struct atomisp_device *isp) +{ + atomisp_mipi_csi2_unregister_entities(&isp->csi2_4p); + atomisp_mipi_csi2_unregister_entities(&isp->csi2_1p); + atomisp_tpg_unregister_entities(&isp->tpg); + atomisp_subdev_unregister_entities(&isp->isp_subdev); + + v4l2_device_unregister(&isp->v4l2_dev); + media_device_unregister(&isp->media_dev); +} + +static int atomisp_register_entities(struct atomisp_device *isp) +{ + int ret = 0; + int i = 0; + struct v4l2_subdev *subdev = NULL; + struct media_entity *input = NULL; + unsigned int flags; + unsigned int pad; + + isp->media_dev.dev = isp->dev; + + strlcpy(isp->media_dev.model, "Intel Atom ISP", + sizeof(isp->media_dev.model)); + + ret = media_device_register(&isp->media_dev); + if (ret < 0) { + v4l2_err(&atomisp_dev, "%s: Media device registration " + "failed (%d)\n", __func__, ret); + return ret; + } + + isp->v4l2_dev.mdev = &isp->media_dev; + ret = v4l2_device_register(isp->dev, &isp->v4l2_dev); + if (ret < 0) { + v4l2_err(&atomisp_dev, + "%s: V4L2 device registration failed (%d)\n", + __func__, ret); + goto v4l2_device_failed; + } + + ret = atomisp_subdev_probe(isp); + if (ret < 0) + goto lane4_and_subdev_probe_failed; + + /* Register internal entities */ + ret = + atomisp_mipi_csi2_register_entities(&isp->csi2_4p, &isp->v4l2_dev); + if (ret < 0) { + v4l2_err(&atomisp_dev, + "atomisp_mipi_csi2_register_entities 4p\n"); + goto lane4_and_subdev_probe_failed; + } + + ret = + atomisp_mipi_csi2_register_entities(&isp->csi2_1p, &isp->v4l2_dev); + if (ret < 0) { + v4l2_err(&atomisp_dev, + "atomisp_mipi_csi2_register_entities 1p\n"); + goto lane1_failed; + } + + ret = + atomisp_file_input_register_entities(&isp->file_dev, &isp->v4l2_dev); + if (ret < 0) { + v4l2_err(&atomisp_dev, + "atomisp_file_input_register_entities\n"); + goto file_input_register_failed; + } + + ret = atomisp_tpg_register_entities(&isp->tpg, &isp->v4l2_dev); + if (ret < 0) { + v4l2_err(&atomisp_dev, "atomisp_tpg_register_entities\n"); + goto tpg_register_failed; + } + + ret = + atomisp_subdev_register_entities(&isp->isp_subdev, &isp->v4l2_dev); + if (ret < 0) { + v4l2_err(&atomisp_dev, + "atomisp_subdev_register_entities fail\n"); + goto subdev_register_failed; + } + + for (i = 0; i < isp->input_cnt; i++) { + subdev = isp->inputs[i].camera; + switch (isp->inputs[i].port) { + case ATOMISP_CAMERA_PORT_PRIMARY: + input = &isp->csi2_4p.subdev.entity; + pad = CSI2_PAD_SINK; + flags = 0; + break; + case ATOMISP_CAMERA_PORT_SECONDARY: + input = &isp->csi2_1p.subdev.entity; + pad = CSI2_PAD_SINK; + flags = 0; + break; + default: + v4l2_info(&atomisp_dev, + "isp->inputs type not supported\n"); + break; + } + ret = media_entity_create_link(&subdev->entity, 0, + input, pad, flags); + if (ret < 0) { + v4l2_err(&atomisp_dev, + "snr to mipi csi link failed\n"); + goto link_failed; + } + } + + v4l2_info(&atomisp_dev, + "FILE_INPUT enable, camera_cnt: %d\n", isp->input_cnt); + isp->inputs[isp->input_cnt].type = FILE_INPUT; + isp->inputs[isp->input_cnt].port = -1; + isp->inputs[isp->input_cnt].shading_table = NULL; + isp->inputs[isp->input_cnt].morph_table = NULL; + isp->inputs[isp->input_cnt++].camera = &isp->file_dev.sd; + + if (isp->input_cnt < ATOM_ISP_MAX_INPUTS) { + v4l2_info(&atomisp_dev, + "TPG detected, camera_cnt: %d\n", isp->input_cnt); + isp->inputs[isp->input_cnt].type = TEST_PATTERN; + isp->inputs[isp->input_cnt].port = -1; + isp->inputs[isp->input_cnt].shading_table = NULL; + isp->inputs[isp->input_cnt].morph_table = NULL; + isp->inputs[isp->input_cnt++].camera = &isp->tpg.sd; + } else { + v4l2_warn(&atomisp_dev, + "too many atomisp inputs, TPG ignored.\n"); + } + + return ret; + +link_failed: + atomisp_subdev_unregister_entities(&isp->isp_subdev); +subdev_register_failed: + atomisp_tpg_unregister_entities(&isp->tpg); +tpg_register_failed: + atomisp_file_input_unregister_entities(&isp->file_dev); +file_input_register_failed: + atomisp_mipi_csi2_unregister_entities(&isp->csi2_1p); +lane1_failed: + atomisp_mipi_csi2_unregister_entities(&isp->csi2_4p); +lane4_and_subdev_probe_failed: + v4l2_device_unregister(&isp->v4l2_dev); +v4l2_device_failed: + media_device_unregister(&isp->media_dev); + return ret; +} + +static int atomisp_initialize_modules(struct atomisp_device *isp) +{ + int ret; + + ret = atomisp_mipi_csi2_init(isp); + if (ret < 0) { + v4l2_err(&atomisp_dev, "mipi csi2 initialization failed\n"); + goto error_mipi_csi2; + } + + ret = atomisp_file_input_init(isp); + if (ret < 0) { + v4l2_err(&atomisp_dev, + "file input device initialization failed\n"); + goto error_file_input; + } + + ret = atomisp_tpg_init(isp); + if (ret < 0) { + v4l2_err(&atomisp_dev, "tpg initialization failed\n"); + goto error_tpg; + } + + ret = atomisp_subdev_init(isp); + if (ret < 0) { + v4l2_err(&atomisp_dev, "ISP subdev initialization failed\n"); + goto error_isp_subdev; + } + + /* connet submoduels */ + ret = media_entity_create_link( + &isp->csi2_4p.subdev.entity, + CSI2_PAD_SOURCE, + &isp->isp_subdev.subdev.entity, + ATOMISP_SUBDEV_PAD_SINK, + 0); + if (ret < 0) + goto error_link; + ret = media_entity_create_link( + &isp->csi2_1p.subdev.entity, + CSI2_PAD_SOURCE, + &isp->isp_subdev.subdev.entity, + ATOMISP_SUBDEV_PAD_SINK, + 0); + if (ret < 0) + goto error_link; + return 0; + +error_link: +error_isp_subdev: + atomisp_subdev_cleanup(isp); +error_tpg: + atomisp_tpg_cleanup(isp); +error_file_input: + atomisp_file_input_cleanup(isp); +error_mipi_csi2: + atomisp_mipi_csi2_cleanup(isp); + return ret; +} + +static const struct firmware * +load_firmware(struct device *dev) +{ + const struct firmware *fw; + int rc; + + v4l2_info(&atomisp_dev, "loading ISP firmware ...\n"); + + rc = request_firmware(&fw, FW_PATH, dev); + if (rc) { + if (rc == -ENOENT) + v4l2_info(&atomisp_dev, + "Error ISP firmware %s not found.\n", + FW_PATH); + else + v4l2_info(&atomisp_dev, + "atomisp: Error %d while requesting" + " firmware %s\n", rc, FW_PATH); + return NULL; + } + + if (fw->data != NULL) { + v4l2_info(&atomisp_dev, + "isp_fw_file info: file:%p, size:%x\n", + fw->data, fw->size); + } else { + return NULL; + } + + v4l2_info(&atomisp_dev, "loading isp firmware ... done\n"); + return fw; +} + +static struct pci_driver atomisp_pci_driver; +static int __devinit atomisp_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct atomisp_device *isp = NULL; + unsigned int start, len; + void __iomem *base = NULL; + int err; + uint32_t ispmmadr; + + if (!dev) { + v4l2_err(&atomisp_dev, "atomisp: erorr device ptr\n"); + return -EINVAL; + } + + err = pci_enable_device(dev); + if (err) { + v4l2_err(&atomisp_dev, + "Failed to enable CI ISP device\n"); + return err; + } + + start = pci_resource_start(dev, 0); + len = pci_resource_len(dev, 0); + + /* + * Read ISP memory base address from Iunit register ISPMMADR message + * bus port 0x08, offset 0x04 + */ + ispmmadr = atomisp_msg_read32(isp, IUNIT_PORT, ISPMMADR); + ispmmadr &= 0xFFC00000; + if (start != ispmmadr) { + start = ispmmadr; + len = 0x400000; + } + v4l2_info(&atomisp_dev, + "ATOM ISP resource start 0x%x, len %d\n", + start, len); + + err = pci_request_region(dev, 0, atomisp_pci_driver.name); + if (err) { + v4l2_err(&atomisp_dev, + "Failed to request region 0x%1x-0x%Lx\n", + start, (unsigned long long)pci_resource_end(dev, + 0)); + goto request_region_fail; + } + + base = ioremap_nocache(start, len); + if (!base) { + v4l2_err(&atomisp_dev, + "Failed to I/O memory remapping\n"); + err = -ENOMEM; + goto ioremap_fail; + } + + isp = kzalloc(sizeof(struct atomisp_device), GFP_KERNEL); + if (!isp) { + v4l2_err(&atomisp_dev, "Failed to alloc CI ISP structure\n"); + goto kzalloc_fail; + } + isp->sw_contex.probed = false; + isp->sw_contex.init = false; + isp->pdev = dev; + isp->dev = &dev->dev; + isp->sw_contex.power_state = ATOM_ISP_POWER_UP; + isp->hw_contex.pci_dev = pci_get_bus_and_slot(0, 0); + + /* Load isp firmware from user space */ + isp->firmware = load_firmware(&dev->dev); + if (!isp->firmware) { + v4l2_err(&atomisp_dev, "Load firmwares failed\n"); + goto load_fw_fail; + } + + err = atomisp_initialize_modules(isp); + if (err < 0) { + v4l2_err(&atomisp_dev, "atomisp_initialize_modules\n"); + goto init_mod_fail; + } + + err = atomisp_register_entities(isp); + if (err < 0) { + v4l2_err(&atomisp_dev, "atomisp_register_entities failed\n"); + goto init_mod_fail; + } + + init_completion(&isp->wq_frame_complete); + init_completion(&isp->dis_state_complete); + spin_lock_init(&isp->irq_lock); + + isp->work_queue = create_singlethread_workqueue(isp->v4l2_dev.name); + if (isp->work_queue == NULL) { + v4l2_err(&atomisp_dev, "Failed to initialize work queue\n"); + goto work_queue_fail; + } + INIT_WORK(&isp->work, atomisp_work); + + isp->hw_contex.ispmmadr = ispmmadr; + v4l2_info(&atomisp_dev, "isp memory address = %x\n", + isp->hw_contex.ispmmadr); + + pci_set_master(dev); + atomisp_io_base = base; + v4l2_info(&atomisp_dev, "ATOM ISP base address %p\n", base); + + isp->tvnorm = tvnorms; + mutex_init(&isp->input_lock); + /* isp_lock is to protect race access of css functions */ + mutex_init(&isp->isp_lock); + mutex_init(&isp->isp3a_lock); + isp->sw_contex.updating_uptr = false; + isp->isp3a_stat_ready = false; + + pci_set_drvdata(dev, isp); + + err = pci_enable_msi(dev); + if (err) { + v4l2_err(&atomisp_dev, + "Failed to enable msi\n"); + goto enable_msi_fail; + } + err = request_irq(dev->irq, atomisp_isr, + IRQF_SHARED, "isp_irq", isp); + if (err) { + v4l2_err(&atomisp_dev, + "Failed to request irq\n"); + goto request_irq_fail; + } + atomisp_msi_irq_init(isp, dev); + +#ifdef CONFIG_PM + pm_runtime_set_active(&dev->dev); + pm_runtime_enable(&dev->dev); + pm_runtime_put_sync(&dev->dev); +#endif + isp->sw_contex.probed = true; + + return 0; + +request_irq_fail: + pci_disable_msi(dev); +enable_msi_fail: + pci_set_drvdata(dev, NULL); + destroy_workqueue(isp->work_queue); +work_queue_fail: + atomisp_unregister_entities(isp); +init_mod_fail: + release_firmware(isp->firmware); +load_fw_fail: + kfree(isp); +kzalloc_fail: + iounmap(base); +ioremap_fail: + pci_release_region(dev, 0); +request_region_fail: + pci_disable_device(dev); + return err; +} + +static void __devexit atomisp_pci_remove(struct pci_dev *dev) +{ + struct atomisp_device *isp = (struct atomisp_device *) + pci_get_drvdata(dev); + + atomisp_msi_irq_uninit(isp, dev); + free_irq(dev->irq, isp); + pci_disable_msi(dev); + pci_dev_put(isp->hw_contex.pci_dev); + + atomisp_unregister_entities(isp); + + flush_workqueue(isp->work_queue); + destroy_workqueue(isp->work_queue); + + iounmap(atomisp_io_base); + pci_set_drvdata(dev, NULL); + pci_release_region(dev, 0); + pci_disable_device(dev); + + /* in case user forget to close */ + release_firmware(isp->firmware); + isp->pdev = NULL; + kfree(isp); +} + +static DEFINE_PCI_DEVICE_TABLE(atomisp_pci_tbl) = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0148)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0149)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014A)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014B)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014C)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014D)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014E)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014F)}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); + +#ifdef CONFIG_PM +static const struct dev_pm_ops atomisp_pm_ops = { + .runtime_suspend = atomisp_runtime_suspend, + .runtime_resume = atomisp_runtime_resume, + .suspend = atomisp_suspend, + .resume = atomisp_resume, +}; + +#define DEV_PM_OPS (&atomisp_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +static struct pci_driver atomisp_pci_driver = { + .driver = { + .pm = DEV_PM_OPS, + }, + .name = "atomisp", + .id_table = atomisp_pci_tbl, + .probe = atomisp_pci_probe, + .remove = atomisp_pci_remove, +}; + +static int __init atomisp_init(void) +{ + v4l2_info(&atomisp_dev, "Init ATOM ISP device driver," + " version: %s-%x\n", DRIVER_VERSION_STR, MAGIC_NUMBER); + return pci_register_driver(&atomisp_pci_driver); +} + +static void __exit atomisp_exit(void) +{ + v4l2_info(&atomisp_dev, "Exit ATOM ISP device driver\n"); + pci_unregister_driver(&atomisp_pci_driver); +} + +late_initcall_async(atomisp_init); +module_exit(atomisp_exit); + +MODULE_AUTHOR("Wen Wang "); +MODULE_AUTHOR("Xiaolin Zhang "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver"); diff --git a/drivers/media/video/atomisp/css/hrt/bits.h b/drivers/media/video/atomisp/css/hrt/bits.h new file mode 100644 index 0000000..321dff8 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/bits.h @@ -0,0 +1,113 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _HRT_BITS_H_ +#define _HRT_BITS_H_ + +#include "defs.h" + +#define _hrt_ones(n) HRTCAT(_hrt_ones_, n) +#define _hrt_ones_0x0 0x00000000U +#define _hrt_ones_0x1 0x00000001U +#define _hrt_ones_0x2 0x00000003U +#define _hrt_ones_0x3 0x00000007U +#define _hrt_ones_0x4 0x0000000FU +#define _hrt_ones_0x5 0x0000001FU +#define _hrt_ones_0x6 0x0000003FU +#define _hrt_ones_0x7 0x0000007FU +#define _hrt_ones_0x8 0x000000FFU +#define _hrt_ones_0x9 0x000001FFU +#define _hrt_ones_0xA 0x000003FFU +#define _hrt_ones_0xB 0x000007FFU +#define _hrt_ones_0xC 0x00000FFFU +#define _hrt_ones_0xD 0x00001FFFU +#define _hrt_ones_0xE 0x00003FFFU +#define _hrt_ones_0xF 0x00007FFFU +#define _hrt_ones_0x10 0x0000FFFFU +#define _hrt_ones_0x11 0x0001FFFFU +#define _hrt_ones_0x12 0x0003FFFFU +#define _hrt_ones_0x13 0x0007FFFFU +#define _hrt_ones_0x14 0x000FFFFFU +#define _hrt_ones_0x15 0x001FFFFFU +#define _hrt_ones_0x16 0x003FFFFFU +#define _hrt_ones_0x17 0x007FFFFFU +#define _hrt_ones_0x18 0x00FFFFFFU +#define _hrt_ones_0x19 0x01FFFFFFU +#define _hrt_ones_0x1A 0x03FFFFFFU +#define _hrt_ones_0x1B 0x07FFFFFFU +#define _hrt_ones_0x1C 0x0FFFFFFFU +#define _hrt_ones_0x1D 0x1FFFFFFFU +#define _hrt_ones_0x1E 0x3FFFFFFFU +#define _hrt_ones_0x1F 0x7FFFFFFFU +#define _hrt_ones_0x20 0xFFFFFFFFU + +#define _hrt_ones_0 _hrt_ones_0x0 +#define _hrt_ones_1 _hrt_ones_0x1 +#define _hrt_ones_2 _hrt_ones_0x2 +#define _hrt_ones_3 _hrt_ones_0x3 +#define _hrt_ones_4 _hrt_ones_0x4 +#define _hrt_ones_5 _hrt_ones_0x5 +#define _hrt_ones_6 _hrt_ones_0x6 +#define _hrt_ones_7 _hrt_ones_0x7 +#define _hrt_ones_8 _hrt_ones_0x8 +#define _hrt_ones_9 _hrt_ones_0x9 +#define _hrt_ones_10 _hrt_ones_0xA +#define _hrt_ones_11 _hrt_ones_0xB +#define _hrt_ones_12 _hrt_ones_0xC +#define _hrt_ones_13 _hrt_ones_0xD +#define _hrt_ones_14 _hrt_ones_0xE +#define _hrt_ones_15 _hrt_ones_0xF +#define _hrt_ones_16 _hrt_ones_0x10 +#define _hrt_ones_17 _hrt_ones_0x11 +#define _hrt_ones_18 _hrt_ones_0x12 +#define _hrt_ones_19 _hrt_ones_0x13 +#define _hrt_ones_20 _hrt_ones_0x14 +#define _hrt_ones_21 _hrt_ones_0x15 +#define _hrt_ones_22 _hrt_ones_0x16 +#define _hrt_ones_23 _hrt_ones_0x17 +#define _hrt_ones_24 _hrt_ones_0x18 +#define _hrt_ones_25 _hrt_ones_0x19 +#define _hrt_ones_26 _hrt_ones_0x1A +#define _hrt_ones_27 _hrt_ones_0x1B +#define _hrt_ones_28 _hrt_ones_0x1C +#define _hrt_ones_29 _hrt_ones_0x1D +#define _hrt_ones_30 _hrt_ones_0x1E +#define _hrt_ones_31 _hrt_ones_0x1F +#define _hrt_ones_32 _hrt_ones_0x20 + +#define _hrt_mask(b, n) \ + (_hrt_ones(n) << (b)) +#define _hrt_get_bits(w, b, n) \ + (((w) >> (b)) & _hrt_ones(n)) +#define _hrt_set_bits(w, b, n, v) \ + (((w) & ~_hrt_mask(b, n)) | (((v) & _hrt_ones(n)) << (b))) +#define _hrt_get_bit(w, b) \ + (((w) >> (b)) & 1) +#define _hrt_set_bit(w, b, v) \ + (((w) & (~(1 << (b)))) | (((v)&1) << (b))) +#define _hrt_set_lower_half(w, v) \ + _hrt_set_bits(w, 0, 16, v) +#define _hrt_set_upper_half(w, v) \ + _hrt_set_bits(w, 16, 16, v) + +#endif /* _HRT_BITS_H_ */ diff --git a/drivers/media/video/atomisp/css/hrt/cell_params.h b/drivers/media/video/atomisp/css/hrt/cell_params.h new file mode 100644 index 0000000..eabfc9f --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/cell_params.h @@ -0,0 +1,51 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _cell_params_h +#define _cell_params_h + +#define SP_PMEM_LOG_WIDTH_BITS 6 /*Width of PC, 64 bits, 8 bytes*/ +#define SP_ICACHE_TAG_BITS 4 /*size of tag*/ +#define SP_ICACHE_SET_BITS 8 /* 256 sets*/ +#define SP_ICACHE_BLOCKS_PER_SET_BITS 1 /* 2 way associative*/ +#define SP_ICACHE_BLOCK_ADDRESS_BITS 11 /* 2048 lines capacity*/ + +#define SP_ICACHE_ADDRESS_BITS \ + (SP_ICACHE_TAG_BITS+SP_ICACHE_BLOCK_ADDRESS_BITS) + +#define SP_PMEM_DEPTH (1< (b)) ? (a) : (b)) +#endif + +#endif /* _HRT_DEFS_H_ */ diff --git a/drivers/media/video/atomisp/css/hrt/dma_v1_defs.h b/drivers/media/video/atomisp/css/hrt/dma_v1_defs.h new file mode 100644 index 0000000..ba7b7ea --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/dma_v1_defs.h @@ -0,0 +1,245 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _dma_v1_defs_h +#define _dma_v1_defs_h + +/* if this file is included from a C source file, you need to include + * first. We cannot include that here because this file is + * also included from CHDL sources which do not have access to HRT. + */ +#define _DMA_V1_NUM_CHANNELS_ID MaxNumChannels +#define _DMA_V1_CONNECTIONS_ID Connections +#define _DMA_V1_DEV_ELEM_WIDTHS_ID DevElemWidths +#define _DMA_V1_DEV_FIFO_DEPTH_ID DevFifoDepth +#define _DMA_V1_DEV_FIFO_RD_LAT_ID DevFifoRdLat +#define _DMA_V1_DEV_FIFO_LAT_BYPASS_ID DevFifoRdLatBypass +#define _DMA_V1_DEV_2_CIO_ID DevConnectedToCIO +#define _DMA_V1_DEV_HAS_CRUN_ID CRunMasters +#define _DMA_V1_CONN_GROUPS_ID ConnectionGroups +#define _DMA_V1_CONN_GROUP_FIFO_DEPTH_ID ConnectionGroupFifoDepth +#define _DMA_V1_CONN_GROUP_FIFO_RD_LAT_ID ConnectionGroupFifoRdLat +#define _DMA_V1_CONN_GROUP_FIFO_LAT_BYPASS_ID ConnectionGroupFifoRdLatBypass + +#define _DMA_V1_REG_ALIGN 4 +#define _DMA_V1_REG_ADDR_BITS 2 + +/* Command word */ +#define _DMA_CMD_IDX 0 +#define _DMA_CMD_BITS 4 +#define _DMA_CHANNEL_IDX (_DMA_CMD_IDX + _DMA_CMD_BITS) +#define _DMA_CHANNEL_BITS 8 +#define _DMA_PARAM_IDX (_DMA_CHANNEL_IDX + _DMA_CHANNEL_BITS) +#define _DMA_PARAM_BITS 4 +#define _DMA_CRUN_IDX (_DMA_PARAM_IDX + _DMA_PARAM_BITS) +#define _DMA_CRUN_BITS 1 + +/* Packing setup word */ +#define _DMA_CONNECTION_IDX 0 +#define _DMA_CONNECTION_BITS 8 +#define _DMA_EXTENSION_IDX (_DMA_CONNECTION_IDX + _DMA_CONNECTION_BITS) +#define _DMA_EXTENSION_BITS 4 +#define _DMA_ELEM_ORDER_IDX (_DMA_EXTENSION_IDX + _DMA_EXTENSION_BITS) +#define _DMA_ELEM_ORDER_BITS 4 + +/* Elements packing word */ +#define _DMA_ELEMENTS_IDX 0 +#define _DMA_ELEMENTS_BITS 12 +#define _DMA_LEFT_CROPPING_IDX (_DMA_ELEMENTS_IDX + _DMA_ELEMENTS_BITS) +#define _DMA_LEFT_CROPPING_BITS 12 + +#define _DMA_WIDTH_IDX 0 +#define _DMA_WIDTH_BITS 16 + +#define _DMA_HEIGHT_IDX 0 +#define _DMA_HEIGHT_BITS 16 + +#define _DMA_STRIDE_IDX 0 +#define _DMA_STRIDE_BITS 32 + +/* Command IDs */ +#define _DMA_READ_COMMAND 0 +#define _DMA_WRITE_COMMAND 1 +#define _DMA_CONFIG_CHANNEL_COMMAND 2 +#define _DMA_SET_CHANNEL_PARAM_COMMAND 3 +#define _DMA_INIT_COMMAND 8 +#define _DMA_RESET_COMMAND 15 + +/* Channel Parameter IDs */ +#define _DMA_PACKING_SETUP_PARAM 0 +#define _DMA_STRIDE_A_PARAM 1 +#define _DMA_ELEM_CROPPING_A_PARAM 2 +#define _DMA_WIDTH_A_PARAM 3 +#define _DMA_STRIDE_B_PARAM 4 +#define _DMA_ELEM_CROPPING_B_PARAM 5 +#define _DMA_WIDTH_B_PARAM 6 +#define _DMA_HEIGHT_PARAM 7 + +/* Parameter Constants */ +#define _DMA_ZERO_EXTEND 0 +#define _DMA_SIGN_EXTEND 1 +#define _DMA_REVERSE_ELEMS 1 +#define _DMA_KEEP_ELEM_ORDER 0 + + /* SLAVE address map */ +#define _DMA_SEL_FSM_CMD 0 +#define _DMA_SEL_CH_REG 1 +#define _DMA_SEL_CONN_GROUP 2 +#define _DMA_SEL_DEV_INTERF 3 +#define _DMA_SEL_RESET 15 + +#define _DMA_RESET_TOKEN 0xDEADCAFE + +#define _DMA_SEL_CONN_CMD 0 +#define _DMA_SEL_CONN_ADDRESS_A 1 +#define _DMA_SEL_CONN_ADDRESS_B 2 +#define _DMA_SEL_FSM_CONN_CTRL 3 +#define _DMA_SEL_FSM_PACK 4 +#define _DMA_SEL_FSM_REQ 5 +#define _DMA_SEL_FSM_WR 6 + +#define _DMA_ADDR_SEL_COMP_IDX 12 +#define _DMA_ADDR_SEL_COMP_BITS 4 +#define _DMA_ADDR_SEL_CH_REG_IDX 2 +#define _DMA_ADDR_SEL_CH_REG_BITS 6 +#define _DMA_ADDR_SEL_PARAM_IDX 8 +#define _DMA_ADDR_SEL_PARAM_BITS 4 + +#define _DMA_ADDR_SEL_GROUP_IDX 2 +#define _DMA_ADDR_SEL_GROUP_BITS 3 +#define _DMA_ADDR_SEL_GROUP_COMP_IDX 5 +#define _DMA_ADDR_SEL_GROUP_COMP_BITS 3 +#define _DMA_ADDR_SEL_GROUP_COMP_INFO_IDX 8 +#define _DMA_ADDR_SEL_GROUP_COMP_INFO_BITS 4 + +#define _DMA_ADDR_SEL_DEV_INTERF_IDX_IDX 2 +#define _DMA_ADDR_SEL_DEV_INTERF_IDX_BITS 6 +#define _DMA_ADDR_SEL_DEV_INTERF_INFO_IDX 8 +#define _DMA_ADDR_SEL_DEV_INTERF_INFO_BITS 4 + +#define _DMA_FSM_GROUP_CMD_IDX 0 +#define _DMA_FSM_GROUP_ADDR_A_IDX 1 +#define _DMA_FSM_GROUP_ADDR_B_IDX 2 +#define _DMA_FSM_GROUP_FSM_CTRL_IDX 3 +#define _DMA_FSM_GROUP_FSM_PACK_IDX 4 +#define _DMA_FSM_GROUP_FSM_REQ_IDX 5 +#define _DMA_FSM_GROUP_FSM_WR_IDX 6 + +#define _DMA_FSM_GROUP_FSM_CTRL_STATE_IDX 0 +#define _DMA_FSM_GROUP_FSM_CTRL_REQ_DEV_IDX 1 +#define _DMA_FSM_GROUP_FSM_CTRL_REQ_ADDR_IDX 2 +#define _DMA_FSM_GROUP_FSM_CTRL_REQ_STRIDE_IDX 3 +#define _DMA_FSM_GROUP_FSM_CTRL_REQ_XB_IDX 4 +#define _DMA_FSM_GROUP_FSM_CTRL_REQ_YB_IDX 5 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_REQ_DEV_IDX 6 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_WR_DEV_IDX 7 +#define _DMA_FSM_GROUP_FSM_CTRL_WR_ADDR_IDX 8 +#define _DMA_FSM_GROUP_FSM_CTRL_WR_STRIDE_IDX 9 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_REQ_XB_IDX 10 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_WR_YB_IDX 11 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_WR_XB_IDX 12 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_ELEM_REQ_IDX 13 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_ELEM_WR_IDX 14 +#define _DMA_FSM_GROUP_FSM_CTRL_PACK_S_Z_REV_IDX 15 + +#define _DMA_FSM_GROUP_FSM_PACK_STATE_IDX 0 +#define _DMA_FSM_GROUP_FSM_PACK_CNT_YB_IDX 1 +#define _DMA_FSM_GROUP_FSM_PACK_CNT_XB_REQ_IDX 2 +#define _DMA_FSM_GROUP_FSM_PACK_CNT_XB_WR_IDX 3 + +#define _DMA_FSM_GROUP_FSM_REQ_STATE_IDX 0 +#define _DMA_FSM_GROUP_FSM_REQ_CNT_YB_IDX 1 +#define _DMA_FSM_GROUP_FSM_REQ_CNT_XB_IDX 2 + +#define _DMA_FSM_GROUP_FSM_WR_STATE_IDX 0 +#define _DMA_FSM_GROUP_FSM_WR_CNT_YB_IDX 1 +#define _DMA_FSM_GROUP_FSM_WR_CNT_XB_IDX 2 + +#define _DMA_DEV_INTERF_REQ_SIDE_STATUS_IDX 0 +#define _DMA_DEV_INTERF_SEND_SIDE_STATUS_IDX 1 +#define _DMA_DEV_INTERF_FIFO_STATUS_IDX 2 +#define _DMA_DEV_INTERF_MAX_BURST_IDX 3 +#define _DMA_DEV_INTERF_CHK_ADDR_ALIGN 4 + +/* constants */ +#define hrt_dma_v1_zero_extension _DMA_ZERO_EXTEND +#define hrt_dma_v1_sign_extension _DMA_SIGN_EXTEND +#define hrt_dma_v1_reverse_elements _DMA_REVERSE_ELEMS +#define hrt_dma_v1_keep_element_order _DMA_KEEP_ELEM_ORDER + +/* Construct address from field type */ +#define _hrt_dma_v1_sel_comp(comp) \ + (((comp) & _hrt_ones(_DMA_ADDR_SEL_COMP_BITS)) << \ + _DMA_ADDR_SEL_COMP_IDX) +#define _hrt_dma_v1_sel_ch(ch) \ + (((ch) & _hrt_ones(_DMA_ADDR_SEL_CH_REG_BITS)) << \ + _DMA_ADDR_SEL_CH_REG_IDX) +#define _hrt_dma_v1_sel_param(param) \ + (((param) & _hrt_ones(_DMA_ADDR_SEL_PARAM_BITS)) << \ + _DMA_ADDR_SEL_PARAM_IDX) +#define _hrt_dma_v1_sel_cg_info(info) \ + (((info) & _hrt_ones(_DMA_ADDR_SEL_GROUP_COMP_INFO_BITS)) << \ + _DMA_ADDR_SEL_GROUP_COMP_INFO_IDX) +#define _hrt_dma_v1_sel_cg_comp(comp) \ + (((comp) & _hrt_ones(_DMA_ADDR_SEL_GROUP_COMP_BITS)) << \ + _DMA_ADDR_SEL_GROUP_COMP_IDX) +#define _hrt_dma_v1_sel_cg_id(gr) \ + (((gr) & _hrt_ones(_DMA_ADDR_SEL_GROUP_BITS)) << \ + _DMA_ADDR_SEL_GROUP_IDX) +#define _hrt_dma_v1_sel_dev_info(info) \ + (((info) & _hrt_ones(_DMA_ADDR_SEL_DEV_INTERF_INFO_BITS)) << \ + _DMA_ADDR_SEL_DEV_INTERF_INFO_IDX) +#define _hrt_dma_v1_sel_dev_id(dev) \ + (((dev) & _hrt_ones(_DMA_ADDR_SEL_DEV_INTERF_IDX_BITS)) << \ + _DMA_ADDR_SEL_DEV_INTERF_IDX_IDX) + +/* Retrieve return values from packed fields */ +#define _hrt_dma_v1_get_connection(val) \ + _hrt_get_bits(val, _DMA_CONNECTION_IDX, _DMA_CONNECTION_BITS) +#define _hrt_dma_v1_get_extension(val) \ + _hrt_get_bits(val, _DMA_EXTENSION_IDX, _DMA_EXTENSION_BITS) +#define _hrt_dma_v1_get_element_order(val) \ + _hrt_get_bits(val, _DMA_ELEM_ORDER_IDX, _DMA_ELEM_ORDER_BITS) +#define _hrt_dma_v1_get_elements(val) \ + _hrt_get_bits(val, _DMA_ELEMENTS_IDX, _DMA_ELEMENTS_BITS) +#define _hrt_dma_v1_get_cropping(val) \ + _hrt_get_bits(val, _DMA_LEFT_CROPPING_IDX, _DMA_LEFT_CROPPING_BITS) + +#define hrt_dma_v1_command_fsm_register_address \ + _hrt_dma_v1_sel_comp(_DMA_SEL_FSM_CMD) +#define hrt_dma_v1_channel_parameter_register_address(ch, param) \ + (_hrt_dma_v1_sel_comp(_DMA_SEL_CH_REG) | _hrt_dma_v1_sel_ch(ch) | \ + _hrt_dma_v1_sel_param(param)) +#define hrt_dma_v1_conn_group_info_register_address(info_id, comp_id, gr_id) \ + (_hrt_dma_v1_sel_comp(_DMA_SEL_CONN_GROUP) | \ + _hrt_dma_v1_sel_cg_info(info_id) | \ + _hrt_dma_v1_sel_cg_comp(comp_id) | \ + _hrt_dma_v1_sel_cg_id(gr_id)) +#define hrt_dma_v1_device_interface_info_register_address(info_id, dev_id) \ + (_hrt_dma_v1_sel_comp(_DMA_SEL_DEV_INTERF) | \ + _hrt_dma_v1_sel_dev_info(info_id) | \ + _hrt_dma_v1_sel_dev_id(dev_id)) +#define hrt_dma_v1_reset_register_address \ + _hrt_dma_v1_sel_comp(_DMA_SEL_RESET) + +#endif /* _dma_v1_defs_h */ diff --git a/drivers/media/video/atomisp/css/hrt/embed.h b/drivers/media/video/atomisp/css/hrt/embed.h new file mode 100644 index 0000000..a63d2bb --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/embed.h @@ -0,0 +1,38 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _HRT_EMBED_H_ +#define _HRT_EMBED_H_ + +#define _hrt_cell_dummy_use_blob(prog) \ + HRTCAT(_hrt_dummy_use_blob_, prog)() +#define _hrt_program_transfer_func(prog) \ + HRTCAT(_hrt_transfer_embedded_, prog) +#define _hrt_program_blob(prog) \ + (HRTCAT(_hrt_blob_, prog).data) +#define hrt_embedded_program_size(prog) \ + HRTCAT(_hrt_size_of_, prog) +#define hrt_embedded_program_text_size(prog) \ + HRTCAT(_hrt_text_size_of_, prog) + +#endif /* _HRT_EMBED_H_ */ diff --git a/drivers/media/video/atomisp/css/hrt/gdc_defs.h b/drivers/media/video/atomisp/css/hrt/gdc_defs.h new file mode 100644 index 0000000..864dacf --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/gdc_defs.h @@ -0,0 +1,111 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _GDC_DEFS_H_ +#define _GDC_DEFS_H_ + +/* This file contains the settings for both the gdc (64-way fixed) + and the gdc_param (variable nway) devices. */ + +#define HRT_GDC_N_BITS 6 +#define HRT_GDC_N 64 + +/* GDC lookup tables entries are 10 bits values, but they're + stored 2 by 2 as 32 bit values, yielding 16 bits per entry. + A GDC lookup table contains 64 * 4 elements */ +#define HRT_GDC_LUT_BYTES ((HRT_GDC_N * 4) * 2) + +#define HRT_GDC_BLI_COEF_BITS 5 +#define HRT_GDC_BLI_COEF_SHIFT (HRT_GDC_BLI_COEF_BITS - 1) +#define HRT_GDC_BLI_COEF_ONE (1 << HRT_GDC_BLI_COEF_SHIFT) + +#define HRT_GDC_BCI_COEF_BITS 10 +#define HRT_GDC_BCI_COEF_MASK ((1 << HRT_GDC_BCI_COEF_BITS) - 1) +#define HRT_GDC_BCI_COEF_SHIFT (HRT_GDC_BCI_COEF_BITS - 2) +#define HRT_GDC_BCI_COEF_ONE (1 << HRT_GDC_BCI_COEF_SHIFT) + +#define HRT_GDC_GDCAC_BITS (6 + 4) +#define HRT_GDC_GDCAC_ONE (1 << (HRT_GDC_GDCAC_BITS-1)) + +#define HRT_GDC_COORD_FRAC_BITS 4 +#define HRT_GDC_COORD_ONE (1 << HRT_GDC_COORD_FRAC_BITS) + +#define HRT_GDC_MAX_GDC_IPY_16NWAY (15*HRT_GDC_COORD_ONE - 1) +#define HRT_GDC_MAX_GDC_IPY_64NWAY (49*HRT_GDC_COORD_ONE - 1) + +#define _HRT_GDC_REG_ALIGN 4 + +#define HRT_GDC_NND_CMD 4 +#define HRT_GDC_BLI_CMD 5 +#define HRT_GDC_BCI_CMD 6 +#define HRT_GDC_GD_CAC_CMD 7 +#define HRT_GDC_CONFIG_CMD 8 + +/* This is how commands are packed into one fifo token */ +#define HRT_GDC_CMD_DATA_POS 16 +#define HRT_GDC_CMD_DATA_BITS 16 +#define HRT_GDC_CMD_BITS 4 +#define HRT_GDC_REG_ID_BITS 8 +#define HRT_GDC_CRUN_BIT (HRT_GDC_CMD_BITS + HRT_GDC_REG_ID_BITS) + +#define HRT_GDC_MODE_IDX 0 +#define HRT_GDC_BPP_IDX 1 +#define HRT_GDC_END_IDX 2 +#define HRT_GDC_WOIX_IDX 3 +#define HRT_GDC_WOIY_IDX 4 +#define HRT_GDC_STX_IDX 5 +#define HRT_GDC_STY_IDX 6 +#define HRT_GDC_OXDIM_IDX 7 +#define HRT_GDC_OYDIM_IDX 8 +#define HRT_GDC_SRC_ADDR_IDX 9 +#define HRT_GDC_SRC_END_ADDR_IDX 10 +#define HRT_GDC_SRC_WRAP_ADDR_IDX 11 +#define HRT_GDC_SRC_STRIDE_IDX 12 +#define HRT_GDC_DST_ADDR_IDX 13 +#define HRT_GDC_DST_STRIDE_IDX 14 +#define HRT_GDC_DX_IDX 15 +#define HRT_GDC_DY_IDX 16 +#define HRT_GDC_P0X_IDX 17 +#define HRT_GDC_P1X_IDX 18 +#define HRT_GDC_P2X_IDX 19 +#define HRT_GDC_P3X_IDX 20 +#define HRT_GDC_P0Y_IDX 21 +#define HRT_GDC_P1Y_IDX 22 +#define HRT_GDC_P2Y_IDX 23 +#define HRT_GDC_P3Y_IDX 24 +#define HRT_GDC_SOFT_RST_IDX 25 +#ifndef __HIVECC +#define HRT_GDC_ELEM_WIDTH_IDX 26 /* Only for csim */ +#define HRT_GDC_ELEMS_PER_WORD_IDX 27 /* Only for csim */ +#define HRT_GDC_BYTES_PER_WORD_IDX 28 /* Only for csim */ +#define HRT_GDC_CRUN_IDX 29 /* Only for csim */ +#endif +#define HRT_GDC_LUT_IDX 32 + +#ifdef __HIVECC +#define HRT_GDC_PACK_CMD(cmd) (cmd) +#else +#define HRT_GDC_PACK_CMD(cmd) ((cmd) | (1 << HRT_GDC_CRUN_BIT)) +#endif + +#endif /* _GDC_DEFS_H_ */ diff --git a/drivers/media/video/atomisp/css/hrt/gp_regs_defs.h b/drivers/media/video/atomisp/css/hrt/gp_regs_defs.h new file mode 100644 index 0000000..fd4a124 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/gp_regs_defs.h @@ -0,0 +1,30 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _gp_regs_defs_h +#define _gp_regs_defs_h + +#define _HRT_GP_REGS_IS_FWD_REG_IDX 0 +#define _HRT_GP_REGS_REG_ALIGN 4 + +#endif /* _gp_regs_defs_h */ diff --git a/drivers/media/video/atomisp/css/hrt/hive_isp_css_defs.h b/drivers/media/video/atomisp/css/hrt/hive_isp_css_defs.h new file mode 100644 index 0000000..7af93b4 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/hive_isp_css_defs.h @@ -0,0 +1,197 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _hive_isp_css_defs_h +#define _hive_isp_css_defs_h + +#define HIVE_ISP_CTRL_DATA_WIDTH 32 +#define HIVE_ISP_CTRL_ADDRESS_WIDTH 32 +#define HIVE_ISP_CTRL_MAX_BURST_SIZE 1 +#define HIVE_ISP_NUM_GPIO_PINS 10 + +/* This list of vector num_elems/elem_bits pairs is valid both + in C as initializer and in the DMA parameter list */ +#define HIVE_ISP_DDR_DMA_SPECS { {32, 8}, {16, 16}, {18, 14}, \ + {25, 10}, {21, 12} } +#define HIVE_ISP_DDR_WORD_BITS 256 +#define HIVE_ISP_DDR_BYTES (256 * 1024 * 1024) +#define HIVE_ISP_PAGE_SHIFT 12 +#define HIVE_ISP_PAGE_SIZE (1< +#endif +#include + +int hrt_isp_css_mm_set(void *virt_addr, int c, size_t bytes); + +/* Allocate memory, returns a virtual address */ +void *hrt_isp_css_mm_alloc(size_t bytes); +void *hrt_isp_css_mm_alloc_cached(size_t bytes); + +/* allocate memory and initialize with zeros, + returns a virtual address */ +void *hrt_isp_css_mm_calloc(size_t bytes); +void *hrt_isp_css_mm_calloc_cached(size_t bytes); + +/* Free memory, given a virtual address */ +void hrt_isp_css_mm_free(void *virt_addr); + +/* Store data to a virtual address */ +int hrt_isp_css_mm_load(void *virt_addr, void *data, size_t bytes); + +/* Load data from a virtual address */ +int hrt_isp_css_mm_store(void *virt_addr, const void *data, size_t bytes); + +int hrt_isp_css_mm_load_int(void *virt_addr, int *data); +int hrt_isp_css_mm_load_short(void *virt_addr, short *data); +int hrt_isp_css_mm_load_char(void *virt_addr, char *data); + +int hrt_isp_css_mm_store_char(void *virt_addr, char data); +int hrt_isp_css_mm_store_short(void *virt_addr, short data); +int hrt_isp_css_mm_store_int(void *virt_addr, int data); + +/* translate a virtual to a physical address, used to program + the display driver on the FPGA system */ +void *hrt_isp_css_virt_to_phys(void *virt_addr); + +void *hrt_isp_css_mm_alloc_contiguous(size_t bytes); +void *hrt_isp_css_mm_calloc_contiguous(size_t bytes); + +void hrt_isp_css_mm_clear(void); +#endif /* _hive_isp_css_mm_hrt_h_ */ diff --git a/drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_monitors_types_hrt.h b/drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_monitors_types_hrt.h new file mode 100644 index 0000000..1d21beb --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_monitors_types_hrt.h @@ -0,0 +1,72 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _hive_isp_css_streaming_monitors_types_hrt_h +#define _hive_isp_css_streaming_monitors_types_hrt_h + +#define _hive_str_mon_valid_offset 0 +#define _hive_str_mon_accept_offset 1 + +#define SP_STR_MON_PORT_SND_PIF_A 0 +#define SP_STR_MON_PORT_RCV_PIF_A 1 +#define SP_STR_MON_PORT_SND_SIF 2 +#define SP_STR_MON_PORT_RCV_SIF 3 +#define SP_STR_MON_PORT_SND_MC 4 +#define SP_STR_MON_PORT_RCV_MC 5 +#define SP_STR_MON_PORT_SND_DMA 6 +#define SP_STR_MON_PORT_RCV_DMA 7 +#define SP_STR_MON_PORT_SND_GDC 8 +#define SP_STR_MON_PORT_RCV_GDC 9 +#define SP_STR_MON_PORT_SND_ISP 10 +#define SP_STR_MON_PORT_RCV_ISP 11 +#define SP_STR_MON_PORT_SND_GPD 12 +#define SP_STR_MON_PORT_RCV_GPD 13 +#define SP_STR_MON_PORT_SND_PIF_B 14 +#define SP_STR_MON_PORT_RCV_PIF_B 15 + +#define MOD_STR_MON_PORT_SND_PIF_A 0 +#define MOD_STR_MON_PORT_RCV_PIF_A 1 +#define MOD_STR_MON_PORT_SND_SIF 2 +#define MOD_STR_MON_PORT_RCV_SIF 3 +#define MOD_STR_MON_PORT_SND_MC 4 +#define MOD_STR_MON_PORT_RCV_MC 5 +#define MOD_STR_MON_PORT_SND_DMA 6 +#define MOD_STR_MON_PORT_RCV_DMA 7 +#define MOD_STR_MON_PORT_SND_GDC 8 +#define MOD_STR_MON_PORT_RCV_GDC 9 +#define MOD_STR_MON_PORT_SND_CSS_REC 10 + +#define ISP_STR_MON_PORT_SND_PIF_A 0 +#define ISP_STR_MON_PORT_RCV_PIF_A 1 +#define ISP_STR_MON_PORT_SND_PIF_B 2 +#define ISP_STR_MON_PORT_RCV_PIF_B 3 +#define ISP_STR_MON_PORT_SND_DMA 4 +#define ISP_STR_MON_PORT_RCV_DMA 5 +#define ISP_STR_MON_PORT_SND_GDC 6 +#define ISP_STR_MON_PORT_RCV_GDC 7 +#define ISP_STR_MON_PORT_SND_GPD 8 +#define ISP_STR_MON_PORT_RCV_GPD 9 +#define ISP_STR_MON_PORT_SND_SP 10 +#define ISP_STR_MON_PORT_RCV_SP 11 + +#endif /* _hive_isp_css_streaming_monitors_types_hrt_h */ diff --git a/drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_to_mipi_types_hrt.h b/drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_to_mipi_types_hrt.h new file mode 100644 index 0000000..47750f0 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/hive_isp_css_streaming_to_mipi_types_hrt.h @@ -0,0 +1,37 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _hive_isp_css_streaming_to_mipi_types_hrt_h_ +#define _hive_isp_css_streaming_to_mipi_types_hrt_h_ + +#include + +#define _HIVE_ISP_CH_ID_MASK ((1U << HIVE_ISP_CH_ID_BITS)-1) +#define _HIVE_ISP_FMT_TYPE_MASK ((1U << HIVE_ISP_FMT_TYPE_BITS)-1) + +#define _HIVE_STR_TO_MIPI_FMT_TYPE_LSB \ + (HIVE_STR_TO_MIPI_CH_ID_LSB + HIVE_ISP_CH_ID_BITS) +#define _HIVE_STR_TO_MIPI_DATA_B_LSB \ + (HIVE_STR_TO_MIPI_DATA_A_LSB + HIVE_IF_PIXEL_WIDTH) + +#endif /* _hive_isp_css_streaming_to_mipi_types_hrt_h_ */ diff --git a/drivers/media/video/atomisp/css/hrt/if_defs.h b/drivers/media/video/atomisp/css/hrt/if_defs.h new file mode 100644 index 0000000..9641e31 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/if_defs.h @@ -0,0 +1,73 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _IF_DEFS_H +#define _IF_DEFS_H + +/* Hardware registers */ +#define HIVE_IF_RESET_ADDRESS 0x000 +#define HIVE_IF_START_LINE_ADDRESS 0x004 +#define HIVE_IF_START_COLUMN_ADDRESS 0x008 +#define HIVE_IF_CROPPED_HEIGHT_ADDRESS 0x00C +#define HIVE_IF_CROPPED_WIDTH_ADDRESS 0x010 +#define HIVE_IF_VERTICAL_DECIMATION_ADDRESS 0x014 +#define HIVE_IF_HORIZONTAL_DECIMATION_ADDRESS 0x018 +#define HIVE_IF_H_DEINTERLEAVING_ADDRESS 0x01C +#define HIVE_IF_LEFTPADDING_WIDTH_ADDRESS 0x020 +#define HIVE_IF_END_OF_LINE_OFFSET_ADDRESS 0x024 +#define HIVE_IF_VMEM_START_ADDRESS_ADDRESS 0x028 +#define HIVE_IF_VMEM_END_ADDRESS_ADDRESS 0x02C +#define HIVE_IF_VMEM_INCREMENT_ADDRESS 0x030 +#define HIVE_IF_YUV_420_FORMAT_ADDRESS 0x034 +#define HIVE_IF_VSYNCK_ACTIVE_LOW_ADDRESS 0x038 +#define HIVE_IF_HSYNCK_ACTIVE_LOW_ADDRESS 0x03C +#define HIVE_IF_ALLOW_FIFO_OVERFLOW_ADDRESS 0x040 +#define HIVE_IF_BLOCK_FIFO_NO_REQ_ADDRESS 0x044 +#define HIVE_IF_V_DEINTERLEAVING_ADDRESS 0x048 +#define HIVE_IF_FSM_SYNC_STATUS 0x100 +#define HIVE_IF_FSM_SYNC_COUNTER 0x104 +#define HIVE_IF_FSM_CROP_STATUS 0x108 +#define HIVE_IF_FSM_CROP_LINE_COUNTER 0x10C +#define HIVE_IF_FSM_CROP_PIXEL_COUNTER 0x110 +#define HIVE_IF_FSM_DEINTERLEAVING_IDX 0x114 +#define HIVE_IF_FSM_DECIMATION_H_COUNTER 0x118 +#define HIVE_IF_FSM_DECIMATION_V_COUNTER 0x11C +#define HIVE_IF_FSM_DECIMATION_BLOCK_V_COUNTER 0x120 +#define HIVE_IF_FSM_PADDING_STATUS 0x124 +#define HIVE_IF_FSM_PADDING_ELEMENT_COUNTER 0x128 +#define HIVE_IF_FSM_VECTOR_SUPPORT_ERROR 0x12C +#define HIVE_IF_FSM_VECTOR_SUPPORT_BUFF_FULL 0x130 +#define HIVE_IF_FSM_VECTOR_SUPPORT 0x134 +#define HIVE_IF_FIFO_SENSOR_DATA_LOST 0x138 + +/* Registers only for simulation */ +#define HIVE_IF_CRUN_MODE_ADDRESS 0x04C +#define HIVE_IF_DUMP_OUTPUT_ADDRESS 0x050 + +#define HIVE_IF_FRAME_REQUEST 0xA000 +#define HIVE_IF_LINES_REQUEST 0xB000 +#define HIVE_IF_VECTORS_REQUEST 0xC000 + +#define _HRT_IF_VEC_ALIGN(if_id) HRTCAT(if_id, _vector_alignment) + +#endif /* _IF_DEFS_H */ diff --git a/drivers/media/video/atomisp/css/hrt/irq_controller_defs.h b/drivers/media/video/atomisp/css/hrt/irq_controller_defs.h new file mode 100644 index 0000000..2287a29 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/irq_controller_defs.h @@ -0,0 +1,36 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _irq_controller_defs_h +#define _irq_controller_defs_h + +#define _HRT_IRQ_CONTROLLER_EDGE_REG_IDX 0 +#define _HRT_IRQ_CONTROLLER_MASK_REG_IDX 1 +#define _HRT_IRQ_CONTROLLER_STATUS_REG_IDX 2 +#define _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX 3 +#define _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX 4 +#define _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX 5 + +#define _HRT_IRQ_CONTROLLER_REG_ALIGN 4 + +#endif /* _irq_controller_defs_h */ diff --git a/drivers/media/video/atomisp/css/hrt/isp2300_medfield_params.h b/drivers/media/video/atomisp/css/hrt/isp2300_medfield_params.h new file mode 100644 index 0000000..a02d0c2 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/isp2300_medfield_params.h @@ -0,0 +1,178 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +/* Version */ +#define ISP_VERSION RTL_VERSION + +/* Cell name */ + +#define ISP_CELL_TYPE isp2300_medfield +#define ISP_VMEM simd_vmem +#define _HRT_ISP_VMEM isp2300_medfield_simd_vmem + +/* instruction pipeline depth */ +#define ISP_BRANCHDELAY 3 + +/* bus */ +#define ISP_BUS_PROT CIO +#define ISP_BUS_WIDTH 32 +#define ISP_BUS_ADDR_WIDTH 32 +#define ISP_BUS_BURST_SIZE 1 + +/* data-path */ +#define ISP_SCALAR_WIDTH 32 +#define ISP_SLICE_NELEMS 4 +#define ISP_VEC_NELEMS 64 +#define ISP_VEC_ELEMBITS 14 +#define ISP_VEC_ELEM8BITS 16 +#define ISP_ALPHA_BLEND_SHIFT 13 + +/* memories */ +#define ISP_DMEM_DEPTH 4096 +#define ISP_VMEM_DEPTH 2048 +#define ISP_VMEM_ELEMBITS 14 +#define ISP_VMEM_ELEM_PRECISION 14 +#define ISP_PMEM_DEPTH 2048 +#define ISP_PMEM_WIDTH 448 +#define ISP_VAMEM_ADDRESS_BITS 13 +#define ISP_VAMEM_ELEMBITS 12 +#define ISP_VAMEM_DEPTH 4096 +#define ISP_VAMEM_ALIGNMENT 2 +#define ISP_VA_ADDRESS_WIDTH 896 +#define ISP_VEC_VALSU_LATENCY ISP_VEC_NELEMS + +/* program counter */ +#define ISP_PC_WIDTH 12 + +/* RSN pipelining */ +#define ISP_RSN_PIPE 0 + +/* shrink instruction set */ +#define ISP_SHRINK_IS 0 + +/* Template experiments */ +#define ISP_HAS_VARU_SIMD_IS1 0 +#define ISP_HAS_SIMD_IS5 1 +#define ISP_HAS_SIMD6_FLGU 0 +#define ISP_HAS_VALSU 1 +#define ISP_SRU_GUARDING 1 +#define ISP_VRF_RAM 1 +#define ISP_SRF_RAM 1 +#define ISP_REDUCE_VARUS 0 +#define ISP_COMBINE_MAC_SHIFT 0 +#define ISP_COMBINE_MAC_VARU 1 +#define ISP_COMBINE_SHIFT_VARU 0 +#define ISP_SLICE_LATENCY 1 +#define ISP_RFSPLIT_EXP 0 +#define ISP_SPILL_MEM_EXP 0 +#define ISP_VHSU_NO_WIDE 0 +#define ISP_NO_SLICE 0 +#define ISP_BLOCK_SLICE 0 +#define ISP_IF 1 +#define ISP_IF_B 1 +#define ISP_DMA 0 +#define ISP_OF 0 +#define ISP_SYS_OF 1 +#define ISP_GDC 1 +#define ISP_GPIO 1 +#define ISP_SP 1 +#define ISP_HAS_IRQ 1 + +/* derived values */ +#define ISP_VEC_WIDTH 896 +#define ISP_SLICE_WIDTH 56 +#define ISP_VMEM_WIDTH 896 +#define ISP_SIMDLSU 1 +#define ISP_LSU_IMM_BITS 12 + +/* convenient shortcuts for software*/ +#define ISP_NWAY ISP_VEC_NELEMS +#define NBITS ISP_VEC_ELEMBITS + +#define _isp_ceil_div(a, b) (((a)+(b)-1)/(b)) + +#ifdef C_RUN +#define ISP_VEC_ALIGN (_isp_ceil_div(ISP_VEC_WIDTH, 64)*8) +#define ISP_VMEM_ALIGN (_isp_ceil_div(ISP_VMEM_WIDTH, 64)*8) +#else +#define ISP_VEC_ALIGN 128 +#define ISP_VMEM_ALIGN ISP_VEC_ALIGN +#endif + +/* HRT specific vector support */ +#define isp2300_medfield_vector_alignment ISP_VEC_ALIGN +#define isp2300_medfield_vector_elem_bits ISP_VMEM_ELEMBITS +#define isp2300_medfield_vector_elem_precision ISP_VMEM_ELEM_PRECISION +#define isp2300_medfield_vector_num_elems ISP_VEC_NELEMS + +/* register file sizes */ +#define ISP_RF0_SIZE 64 +#define ISP_RF1_SIZE 8 +#define ISP_RF2_SIZE 64 +#define ISP_RF3_SIZE 32 +#define ISP_RF4_SIZE 32 +#define ISP_RF5_SIZE 32 +#define ISP_RF6_SIZE 16 +#define ISP_VRF0_SIZE 16 +#define ISP_VRF1_SIZE 16 +#define ISP_VRF2_SIZE 16 +#define ISP_VRF3_SIZE 16 +#define ISP_VRF4_SIZE 16 +#define ISP_VRF5_SIZE 16 +#define ISP_VRF6_SIZE 16 +#define ISP_VRF7_SIZE 16 +#define ISP_VRF8_SIZE 16 +#define ISP_SRF0_SIZE 64 +#define ISP_SRF1_SIZE 64 +#define ISP_FRF0_SIZE 16 +#define ISP_FRF1_SIZE 16 +/* register file read latency */ +#define ISP_VRF0_READ_LAT 0 +#define ISP_VRF1_READ_LAT 0 +#define ISP_VRF2_READ_LAT 0 +#define ISP_VRF3_READ_LAT 0 +#define ISP_VRF4_READ_LAT 0 +#define ISP_VRF5_READ_LAT 0 +#define ISP_VRF6_READ_LAT 0 +#define ISP_VRF7_READ_LAT 0 +#define ISP_VRF8_READ_LAT 0 +#define ISP_SRF0_READ_LAT 0 +#define ISP_SRF1_READ_LAT 0 +/* immediate sizes */ +#define ISP_IS1_IMM_BITS 13 +#define ISP_IS2_IMM_BITS 10 +#define ISP_IS3_IMM_BITS 7 +#define ISP_IS4_IMM_BITS 7 +#define ISP_IS5_IMM_BITS 13 +#define ISP_IS6_IMM_BITS 7 +#define ISP_IS7_IMM_BITS 7 +#define ISP_IS8_IMM_BITS 7 +#define ISP_IS9_IMM_BITS 7 +/* fifo depths */ +#define ISP_IF_FIFO_DEPTH 0 +#define ISP_IF_B_FIFO_DEPTH 0 +#define ISP_DMA_FIFO_DEPTH 0 +#define ISP_OF_FIFO_DEPTH 0 +#define ISP_GDC_FIFO_DEPTH 0 +#define ISP_GPIO_FIFO_DEPTH 0 +#define ISP_SP_FIFO_DEPTH 0 diff --git a/drivers/media/video/atomisp/css/hrt/master_port.h b/drivers/media/video/atomisp/css/hrt/master_port.h new file mode 100644 index 0000000..0823774 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/master_port.h @@ -0,0 +1,149 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _HRT_MASTER_PORT_H_ +#define _HRT_MASTER_PORT_H_ + +/* This file contains the end of the HRT. + * Here we split between the hardware implementation (memcpy / assignments) + * and the software backends (_hrt_master_port_load / _hrt_master_port_store) + */ + +/* If HRT_USE_VIR_ADDRS is defined, the OS needs to implement the following + functions for us: + _hrt_master_port_store_8(addr,data) + _hrt_master_port_store_16(addr,data) + _hrt_master_port_store_32(addr,data) + _hrt_master_port_load_8(addr) + _hrt_master_port_uload_8(addr) + _hrt_master_port_load_16(addr) + _hrt_master_port_uload_16(addr) + _hrt_master_port_load_32(addr) + _hrt_master_port_uload_32(addr) + _hrt_master_port_store_8_volatile(addr,data) + _hrt_master_port_load_8_volatile(addr) + _hrt_master_port_uload_8_volatile(addr) + _hrt_master_port_store_16_volatile(addr,data) + _hrt_master_port_load_16_volatile(addr) + _hrt_master_port_uload_16_volatile(addr) + _hrt_master_port_store_32_volatile(addr,data) + _hrt_master_port_load_32_volatile(addr) + _hrt_master_port_uload_32_volatile(addr) + _hrt_mem_store(addr,data,size) + _hrt_mem_load(addr,data,size) + _hrt_mem_set(addr,val,size) +*/ + +#define hrt_master_port_store_8(addr, data) \ + _hrt_master_port_store_8(addr, data) +#define hrt_master_port_store_16(addr, data) \ + _hrt_master_port_store_16(addr, data) +#define hrt_master_port_store_32(addr, data) \ + _hrt_master_port_store_32(addr, data) +#define hrt_master_port_load_8(addr) \ + _hrt_master_port_load_8(addr) +#define hrt_master_port_load_16(addr) \ + _hrt_master_port_load_16(addr) +#define hrt_master_port_load_32(addr) \ + _hrt_master_port_load_32(addr) +#define hrt_master_port_uload_8(addr) \ + _hrt_master_port_uload_8(addr) +#define hrt_master_port_uload_16(addr) \ + _hrt_master_port_uload_16(addr) +#define hrt_master_port_uload_32(addr) \ + _hrt_master_port_uload_32(addr) + +#define hrt_master_port_store(addr, data, bytes) \ + _hrt_master_port_unaligned_store((void *)(addr), \ + (const void *)(data), bytes) +#define hrt_master_port_load(addr, data, bytes) \ + _hrt_master_port_unaligned_load((const void *)(addr), \ + (void *)(data), bytes) +#define hrt_master_port_set(addr, data, bytes) \ + _hrt_master_port_unaligned_set((void *)(addr), \ + (int)(data), bytes) + +#ifdef HRT_HW +/* on real hardware, we cannot print messages, so we get rid of them here. */ +#define _hrt_master_port_unaligned_store_msg(a, d, s, m) \ + _hrt_master_port_unaligned_store(a, d, s) +#define _hrt_master_port_unaligned_load_msg(a, d, s, m) \ + _hrt_master_port_unaligned_load(a, d, s) +#define _hrt_master_port_unaligned_set_msg(a, d, s, m) \ + _hrt_master_port_unaligned_set(a, d, s) +#define _hrt_master_port_store_8_msg(a, d, m) \ + _hrt_master_port_store_8(a, d) +#define _hrt_master_port_store_16_msg(a, d, m) \ + _hrt_master_port_store_16(a, d) +#define _hrt_master_port_store_32_msg(a, d, m) \ + _hrt_master_port_store_32(a, d) +#define _hrt_master_port_load_8_msg(a, m) \ + _hrt_master_port_load_8(a) +#define _hrt_master_port_load_16_msg(a, m) \ + _hrt_master_port_load_16(a) +#define _hrt_master_port_load_32_msg(a, m) \ + _hrt_master_port_load_32(a) +#define _hrt_master_port_uload_8_msg(a, m) \ + _hrt_master_port_uload_8(a) +#define _hrt_master_port_uload_16_msg(a, m) \ + _hrt_master_port_uload_16(a) +#define _hrt_master_port_uload_32_msg(a, m) \ + _hrt_master_port_uload_32(a) +#define _hrt_master_port_store_8_volatile_msg(a, d, m) \ + _hrt_master_port_store_8_volatile(a, d) +#define _hrt_master_port_load_8_volatile_msg(a, m) \ + _hrt_master_port_load_8_volatile(a) +#define _hrt_master_port_uload_8_volatile_msg(a, m) \ + _hrt_master_port_uload_8_volatile(a) +#define _hrt_master_port_store_16_volatile_msg(a, d, m) \ + _hrt_master_port_store_16_volatile(a, d) +#define _hrt_master_port_load_16_volatile_msg(a, m) \ + _hrt_master_port_load_16_volatile(a) +#define _hrt_master_port_uload_16_volatile_msg(a, m) \ + _hrt_master_port_uload_16_volatile(a) +#define _hrt_master_port_store_32_volatile_msg(a, d, m) \ + _hrt_master_port_store_32_volatile(a, d) +#define _hrt_master_port_load_32_volatile_msg(a, m) \ + _hrt_master_port_load_32_volatile(a) +#define _hrt_master_port_uload_32_volatile_msg(a, m) \ + _hrt_master_port_uload_32_volatile(a) +/* reduce number of functions */ +#define _hrt_master_port_unaligned_store(address, data, size) \ + _hrt_mem_store(address, data, size) +#define _hrt_master_port_unaligned_load(address, data, size) \ + _hrt_mem_load(address, data, size) +#define _hrt_master_port_unaligned_set(address, data, size) \ + _hrt_mem_set(address, data, size) +#endif /* HRT_HW */ + +#if defined(__HIVECC) +#include "master_port_hivecc.h" +#elif defined(HRT_USE_VIR_ADDRS) +/* do nothing, hrt backend is already included */ +#elif defined(HRT_HW) +#include "master_port_hw.h" +#else +#include "master_port_sim.h" +#endif + +#endif /* _HRT_MASTER_PORT_H_ */ diff --git a/drivers/media/video/atomisp/css/hrt/mmu_defs.h b/drivers/media/video/atomisp/css/hrt/mmu_defs.h new file mode 100644 index 0000000..6aa8ed5 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/mmu_defs.h @@ -0,0 +1,32 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _mmu_defs_h +#define _mmu_defs_h + +#define _HRT_MMU_INVALIDATE_TLB_REG_IDX 0 +#define _HRT_MMU_PAGE_TABLE_BASE_ADDRESS_REG_IDX 1 + +#define _HRT_MMU_REG_ALIGN 4 + +#endif /* _mmu_defs_h */ diff --git a/drivers/media/video/atomisp/css/hrt/scalar_processor_params.h b/drivers/media/video/atomisp/css/hrt/scalar_processor_params.h new file mode 100644 index 0000000..2eb5166 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/scalar_processor_params.h @@ -0,0 +1,29 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _scalar_processor_params_h +#define _scalar_processor_params_h + +#include "cell_params.h" + +#endif /* _scalar_processor_params_h */ diff --git a/drivers/media/video/atomisp/css/hrt/sp.map.h b/drivers/media/video/atomisp/css/hrt/sp.map.h new file mode 100644 index 0000000..7b1821f --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/sp.map.h @@ -0,0 +1,355 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _SP_MAP_H_ +#define _SP_MAP_H_ + + +#ifndef _hrt_dummy_use_blob_sp +#define _hrt_dummy_use_blob_sp() +#endif + +#define _hrt_cell_load_program_sp(proc) \ + _hrt_cell_load_program_from_elf_file(proc, "sp") + +#define HIVE_MEM_isp_vectors_per_input_line scalar_processor_dmem +#define HIVE_ADDR_isp_vectors_per_input_line 0xF38 +#define HIVE_SIZE_isp_vectors_per_input_line 4 +#define HIVE_MEM_sp_raw_copy_thread scalar_processor_dmem +#define HIVE_ADDR_sp_raw_copy_thread 0xA8 +#define HIVE_SIZE_sp_raw_copy_thread 4 +#define HIVE_MEM_sp_input_v_addr scalar_processor_dmem +#define HIVE_ADDR_sp_input_v_addr 0xF3C +#define HIVE_SIZE_sp_input_v_addr 4 +#define HIVE_MEM_dma_proxy_status scalar_processor_dmem +#define HIVE_ADDR_dma_proxy_status 0xCC +#define HIVE_SIZE_dma_proxy_status 4 +#define HIVE_MEM_sp_bin_copy_bytes_available scalar_processor_dmem +#define HIVE_ADDR_sp_bin_copy_bytes_available 0x3914 +#define HIVE_SIZE_sp_bin_copy_bytes_available 4 +#define HIVE_MEM_sp_error scalar_processor_dmem +#define HIVE_ADDR_sp_error 0x39C0 +#define HIVE_SIZE_sp_error 4 +#define HIVE_MEM_sp_read_sp_group_from_ddr scalar_processor_dmem +#define HIVE_ADDR_sp_read_sp_group_from_ddr 0xF40 +#define HIVE_SIZE_sp_read_sp_group_from_ddr 4 +#define HIVE_MEM_sp_raw_copy_width scalar_processor_dmem +#define HIVE_ADDR_sp_raw_copy_width 0x3990 +#define HIVE_SIZE_sp_raw_copy_width 4 +#define HIVE_MEM_sp_if_a scalar_processor_dmem +#define HIVE_ADDR_sp_if_a 0x3928 +#define HIVE_SIZE_sp_if_a 48 +#define HIVE_MEM_sp_no_side_band scalar_processor_dmem +#define HIVE_ADDR_sp_no_side_band 0xF44 +#define HIVE_SIZE_sp_no_side_band 4 +#define HIVE_MEM_sp_raw_copy_max_input_width scalar_processor_dmem +#define HIVE_ADDR_sp_raw_copy_max_input_width 0x3994 +#define HIVE_SIZE_sp_raw_copy_max_input_width 4 +#define HIVE_MEM_sp_ch_id scalar_processor_dmem +#define HIVE_ADDR_sp_ch_id 0xF48 +#define HIVE_SIZE_sp_ch_id 4 +#define HIVE_MEM_sp_sync_gen_vblank_cycles scalar_processor_dmem +#define HIVE_ADDR_sp_sync_gen_vblank_cycles 0xF4C +#define HIVE_SIZE_sp_sync_gen_vblank_cycles 4 +#define HIVE_MEM_sp_prbs_seed scalar_processor_dmem +#define HIVE_ADDR_sp_prbs_seed 0xF50 +#define HIVE_SIZE_sp_prbs_seed 4 +#define HIVE_MEM_sp_tpg_x_mask scalar_processor_dmem +#define HIVE_ADDR_sp_tpg_x_mask 0xF54 +#define HIVE_SIZE_sp_tpg_x_mask 4 +#define HIVE_MEM_xmem_bin_addr scalar_processor_dmem +#define HIVE_ADDR_xmem_bin_addr 0xF58 +#define HIVE_SIZE_xmem_bin_addr 4 +#define HIVE_MEM_sp_fmt_type scalar_processor_dmem +#define HIVE_ADDR_sp_fmt_type 0xF5C +#define HIVE_SIZE_sp_fmt_type 4 +#define HIVE_MEM_sp_uds_config scalar_processor_dmem +#define HIVE_ADDR_sp_uds_config 0x39B0 +#define HIVE_SIZE_sp_uds_config 16 +#define HIVE_MEM_sp_isp_started scalar_processor_dmem +#define HIVE_ADDR_sp_isp_started 0xF60 +#define HIVE_SIZE_sp_isp_started 4 +#define HIVE_MEM_sp_obarea_start_bq scalar_processor_dmem +#define HIVE_ADDR_sp_obarea_start_bq 0xF64 +#define HIVE_SIZE_sp_obarea_start_bq 4 +#define HIVE_MEM_sp_start_isp_thread scalar_processor_dmem +#define HIVE_ADDR_sp_start_isp_thread 0x188 +#define HIVE_SIZE_sp_start_isp_thread 4 +#define HIVE_MEM_sp_proxy_thread scalar_processor_dmem +#define HIVE_ADDR_sp_proxy_thread 0xD4 +#define HIVE_SIZE_sp_proxy_thread 4 +#define HIVE_MEM_sp_bin_copy_bytes_copied scalar_processor_dmem +#define HIVE_ADDR_sp_bin_copy_bytes_copied 0x3918 +#define HIVE_SIZE_sp_bin_copy_bytes_copied 4 +#define HIVE_MEM_sp_raw_copy_height scalar_processor_dmem +#define HIVE_ADDR_sp_raw_copy_height 0x3998 +#define HIVE_SIZE_sp_raw_copy_height 4 +#define HIVE_MEM_sp_raw_copy_out scalar_processor_dmem +#define HIVE_ADDR_sp_raw_copy_out 0x399C +#define HIVE_SIZE_sp_raw_copy_out 4 +#define HIVE_MEM_isp_sh_dma_cmd_buffer scalar_processor_dmem +#define HIVE_ADDR_isp_sh_dma_cmd_buffer 0x39C4 +#define HIVE_SIZE_isp_sh_dma_cmd_buffer 4 +#define HIVE_MEM_sp_overlay_bg_u scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_bg_u 0xF68 +#define HIVE_SIZE_sp_overlay_bg_u 4 +#define HIVE_MEM_vf_pp_args scalar_processor_dmem +#define HIVE_ADDR_vf_pp_args 0x3B20 +#define HIVE_SIZE_vf_pp_args 76 +#define HIVE_MEM_sp_sync_gen_width scalar_processor_dmem +#define HIVE_ADDR_sp_sync_gen_width 0xF6C +#define HIVE_SIZE_sp_sync_gen_width 4 +#define HIVE_ADDR_vf_pp_dynamic_entry 0x16C7 +#define HIVE_MEM_current_thread scalar_processor_dmem +#define HIVE_ADDR_current_thread 0x39A8 +#define HIVE_SIZE_current_thread 4 +#define HIVE_MEM_sp_dma_output_block_width_b scalar_processor_dmem +#define HIVE_ADDR_sp_dma_output_block_width_b 0x3A08 +#define HIVE_SIZE_sp_dma_output_block_width_b 4 +#define HIVE_ADDR_sp_raw_copy_entry 0x486 +#define HIVE_MEM_sp_tpg_x_delta scalar_processor_dmem +#define HIVE_ADDR_sp_tpg_x_delta 0xF70 +#define HIVE_SIZE_sp_tpg_x_delta 4 +#define HIVE_ADDR_sp_init_dmem_entry 0x77 +#define HIVE_MEM_sp_overlay_v_addr scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_v_addr 0xF74 +#define HIVE_SIZE_sp_overlay_v_addr 4 +#define HIVE_MEM_sp_obarea_length_bq scalar_processor_dmem +#define HIVE_ADDR_sp_obarea_length_bq 0xF78 +#define HIVE_SIZE_sp_obarea_length_bq 4 +#define HIVE_MEM_capture_pp_args scalar_processor_dmem +#define HIVE_ADDR_capture_pp_args 0x3B6C +#define HIVE_SIZE_capture_pp_args 12 +#define HIVE_MEM_vtmp4 scalar_processor_dmem +#define HIVE_ADDR_vtmp4 0xF7C +#define HIVE_SIZE_vtmp4 512 +#define HIVE_MEM_sp_bin_copy_out scalar_processor_dmem +#define HIVE_ADDR_sp_bin_copy_out 0x391C +#define HIVE_SIZE_sp_bin_copy_out 4 +#define HIVE_MEM_sp_dma_crop_block_width_b scalar_processor_dmem +#define HIVE_ADDR_sp_dma_crop_block_width_b 0x3A0C +#define HIVE_SIZE_sp_dma_crop_block_width_b 4 +#define HIVE_MEM_sp_overlay_start_x scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_start_x 0x117C +#define HIVE_SIZE_sp_overlay_start_x 4 +#define HIVE_MEM_sp_output_v_addr scalar_processor_dmem +#define HIVE_ADDR_sp_output_v_addr 0x1180 +#define HIVE_SIZE_sp_output_v_addr 4 +#define HIVE_ADDR_sp_start_isp_entry 0x0 +#define HIVE_MEM_sp_no_dma_proxy scalar_processor_dmem +#define HIVE_ADDR_sp_no_dma_proxy 0x440 +#define HIVE_SIZE_sp_no_dma_proxy 4 +#define HIVE_MEM_sp_raw_copy_padded_width scalar_processor_dmem +#define HIVE_ADDR_sp_raw_copy_padded_width 0x39A0 +#define HIVE_SIZE_sp_raw_copy_padded_width 4 +#define HIVE_MEM_sp_current_isp_program scalar_processor_dmem +#define HIVE_ADDR_sp_current_isp_program 0xF34 +#define HIVE_SIZE_sp_current_isp_program 4 +#define HIVE_MEM_sp_dma_crop_block_width_a scalar_processor_dmem +#define HIVE_ADDR_sp_dma_crop_block_width_a 0x3A10 +#define HIVE_SIZE_sp_dma_crop_block_width_a 4 +#define HIVE_MEM_sp_dma_c_block_width_b scalar_processor_dmem +#define HIVE_ADDR_sp_dma_c_block_width_b 0x3A14 +#define HIVE_SIZE_sp_dma_c_block_width_b 4 +#define HIVE_MEM_isp_vectors_per_line scalar_processor_dmem +#define HIVE_ADDR_isp_vectors_per_line 0x1184 +#define HIVE_SIZE_isp_vectors_per_line 4 +#define HIVE_MEM_sp_ddr_data_addr scalar_processor_dmem +#define HIVE_ADDR_sp_ddr_data_addr 0x1188 +#define HIVE_SIZE_sp_ddr_data_addr 4 +#define HIVE_ADDR_sp_gen_histogram_entry 0x353 +#define HIVE_MEM_sp_group scalar_processor_dmem +#define HIVE_ADDR_sp_group 0x118C +#define HIVE_SIZE_sp_group 1160 +#define HIVE_MEM_isp_uv_internal_width_vecs scalar_processor_dmem +#define HIVE_ADDR_isp_uv_internal_width_vecs 0x1614 +#define HIVE_SIZE_isp_uv_internal_width_vecs 4 +#define HIVE_MEM_sp_input_y_addr scalar_processor_dmem +#define HIVE_ADDR_sp_input_y_addr 0x1618 +#define HIVE_SIZE_sp_input_y_addr 4 +#define HIVE_MEM_sp_dmem_data_addr scalar_processor_dmem +#define HIVE_ADDR_sp_dmem_data_addr 0x161C +#define HIVE_SIZE_sp_dmem_data_addr 4 +#define HIVE_MEM_sp_sw_interrupt_value scalar_processor_dmem +#define HIVE_ADDR_sp_sw_interrupt_value 0x1620 +#define HIVE_SIZE_sp_sw_interrupt_value 4 +#define HIVE_MEM_histogram_args scalar_processor_dmem +#define HIVE_ADDR_histogram_args 0x3920 +#define HIVE_SIZE_histogram_args 4 +#define HIVE_MEM_sp_bss_size scalar_processor_dmem +#define HIVE_ADDR_sp_bss_size 0x1624 +#define HIVE_SIZE_sp_bss_size 4 +#define HIVE_ADDR_capture_pp_dynamic_entry 0x37F7 +#define HIVE_MEM_sp_tpg_y_delta scalar_processor_dmem +#define HIVE_ADDR_sp_tpg_y_delta 0x1628 +#define HIVE_SIZE_sp_tpg_y_delta 4 +#define HIVE_MEM_sp_overlay_width scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_width 0x162C +#define HIVE_SIZE_sp_overlay_width 4 +#define HIVE_MEM_isp_sdis_horiproj_num scalar_processor_dmem +#define HIVE_ADDR_isp_sdis_horiproj_num 0x1630 +#define HIVE_SIZE_isp_sdis_horiproj_num 4 +#define HIVE_MEM_sp_dma_output_block_width_a scalar_processor_dmem +#define HIVE_ADDR_sp_dma_output_block_width_a 0x3A18 +#define HIVE_SIZE_sp_dma_output_block_width_a 4 +#define HIVE_MEM_sp_input_mode scalar_processor_dmem +#define HIVE_ADDR_sp_input_mode 0x1634 +#define HIVE_SIZE_sp_input_mode 4 +#define HIVE_MEM_sp_tpg_xy_mask scalar_processor_dmem +#define HIVE_ADDR_sp_tpg_xy_mask 0x1638 +#define HIVE_SIZE_sp_tpg_xy_mask 4 +#define HIVE_MEM_sp_overlay_start_y scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_start_y 0x163C +#define HIVE_SIZE_sp_overlay_start_y 4 +#define HIVE_MEM_sp_sp_group_addr scalar_processor_dmem +#define HIVE_ADDR_sp_sp_group_addr 0x1640 +#define HIVE_SIZE_sp_sp_group_addr 4 +#define HIVE_MEM_sp_data_size scalar_processor_dmem +#define HIVE_ADDR_sp_data_size 0x1644 +#define HIVE_SIZE_sp_data_size 4 +#define HIVE_MEM_num_sp_threads scalar_processor_dmem +#define HIVE_ADDR_num_sp_threads 0x39AC +#define HIVE_SIZE_num_sp_threads 4 +#define HIVE_MEM_sp_output_y_addr scalar_processor_dmem +#define HIVE_ADDR_sp_output_y_addr 0x1648 +#define HIVE_SIZE_sp_output_y_addr 4 +#define HIVE_MEM_bayer_conf scalar_processor_dmem +#define HIVE_ADDR_bayer_conf 0x18C +#define HIVE_SIZE_bayer_conf 56 +#define HIVE_MEM_sp_proxy_busy_wait scalar_processor_dmem +#define HIVE_ADDR_sp_proxy_busy_wait 0x528 +#define HIVE_SIZE_sp_proxy_busy_wait 4 +#define HIVE_MEM_sp_sync_gen_hblank_cycles scalar_processor_dmem +#define HIVE_ADDR_sp_sync_gen_hblank_cycles 0x164C +#define HIVE_SIZE_sp_sync_gen_hblank_cycles 4 +#define HIVE_MEM_isp_sdis_vertproj_num scalar_processor_dmem +#define HIVE_ADDR_isp_sdis_vertproj_num 0x1650 +#define HIVE_SIZE_isp_sdis_vertproj_num 4 +#define HIVE_MEM_sp_sync_gen_height scalar_processor_dmem +#define HIVE_ADDR_sp_sync_gen_height 0x1654 +#define HIVE_SIZE_sp_sync_gen_height 4 +#define HIVE_MEM_sp_program_input_circuit scalar_processor_dmem +#define HIVE_ADDR_sp_program_input_circuit 0x1658 +#define HIVE_SIZE_sp_program_input_circuit 4 +#define HIVE_MEM_sp_if_b_changed scalar_processor_dmem +#define HIVE_ADDR_sp_if_b_changed 0x3958 +#define HIVE_SIZE_sp_if_b_changed 4 +#define HIVE_MEM_sp_dma_c_block_width_a scalar_processor_dmem +#define HIVE_ADDR_sp_dma_c_block_width_a 0x3A1C +#define HIVE_SIZE_sp_dma_c_block_width_a 4 +#define HIVE_MEM_sp_dma_crop_cropping_a scalar_processor_dmem +#define HIVE_ADDR_sp_dma_crop_cropping_a 0x3A20 +#define HIVE_SIZE_sp_dma_crop_cropping_a 4 +#define HIVE_MEM_sp_dma_output_skip_vecs scalar_processor_dmem +#define HIVE_ADDR_sp_dma_output_skip_vecs 0x3A24 +#define HIVE_SIZE_sp_dma_output_skip_vecs 4 +#define HIVE_MEM_sp_vf_downscale_bits scalar_processor_dmem +#define HIVE_ADDR_sp_vf_downscale_bits 0x165C +#define HIVE_SIZE_sp_vf_downscale_bits 4 +#define HIVE_MEM_isp_sdis_vertcoef_vectors scalar_processor_dmem +#define HIVE_ADDR_isp_sdis_vertcoef_vectors 0x1660 +#define HIVE_SIZE_isp_sdis_vertcoef_vectors 4 +#define HIVE_MEM_sp_overlay_bg_v scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_bg_v 0x1664 +#define HIVE_SIZE_sp_overlay_bg_v 4 +#define HIVE_MEM_sp_output_u_addr scalar_processor_dmem +#define HIVE_ADDR_sp_output_u_addr 0x1668 +#define HIVE_SIZE_sp_output_u_addr 4 +#define HIVE_MEM_output_dma_info_descr scalar_processor_dmem +#define HIVE_ADDR_output_dma_info_descr 0x3AD8 +#define HIVE_SIZE_output_dma_info_descr 72 +#define HIVE_MEM_sp_isp_input_stream_format scalar_processor_dmem +#define HIVE_ADDR_sp_isp_input_stream_format 0x166C +#define HIVE_SIZE_sp_isp_input_stream_format 4 +#define HIVE_MEM_curr_binary_id scalar_processor_dmem +#define HIVE_ADDR_curr_binary_id 0x0 +#define HIVE_SIZE_curr_binary_id 4 +#define HIVE_MEM_sp_dma_c_skip_vecs scalar_processor_dmem +#define HIVE_ADDR_sp_dma_c_skip_vecs 0x3A28 +#define HIVE_SIZE_sp_dma_c_skip_vecs 4 +#define HIVE_MEM_sp_dma_vfout_cropping_a scalar_processor_dmem +#define HIVE_ADDR_sp_dma_vfout_cropping_a 0x3A2C +#define HIVE_SIZE_sp_dma_vfout_cropping_a 4 +#define HIVE_MEM_sp_overlay_bg_y scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_bg_y 0x1670 +#define HIVE_SIZE_sp_overlay_bg_y 4 +#define HIVE_MEM_sp_histo_addr scalar_processor_dmem +#define HIVE_ADDR_sp_histo_addr 0x3924 +#define HIVE_SIZE_sp_histo_addr 4 +#define HIVE_MEM_sp_overlay_u_addr scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_u_addr 0x1674 +#define HIVE_SIZE_sp_overlay_u_addr 4 +#define HIVE_MEM_sp_input_u_addr scalar_processor_dmem +#define HIVE_ADDR_sp_input_u_addr 0x1678 +#define HIVE_SIZE_sp_input_u_addr 4 +#define HIVE_MEM_sp_tpg_y_mask scalar_processor_dmem +#define HIVE_ADDR_sp_tpg_y_mask 0x167C +#define HIVE_SIZE_sp_tpg_y_mask 4 +#define HIVE_MEM_sp_si scalar_processor_dmem +#define HIVE_ADDR_sp_si 0x3A30 +#define HIVE_SIZE_sp_si 68 +#define HIVE_MEM_sp_debug scalar_processor_dmem +#define HIVE_ADDR_sp_debug 0x39C8 +#define HIVE_SIZE_sp_debug 64 +#define HIVE_MEM_sp_raw_copy_raw_bit_depth scalar_processor_dmem +#define HIVE_ADDR_sp_raw_copy_raw_bit_depth 0x39A4 +#define HIVE_SIZE_sp_raw_copy_raw_bit_depth 4 +#define HIVE_MEM_sp_overlay_y_addr scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_y_addr 0x1680 +#define HIVE_SIZE_sp_overlay_y_addr 4 +#define HIVE_MEM_isp_sdis_horicoef_vectors scalar_processor_dmem +#define HIVE_ADDR_isp_sdis_horicoef_vectors 0x1684 +#define HIVE_SIZE_isp_sdis_horicoef_vectors 4 +#define HIVE_MEM_sp_if_b scalar_processor_dmem +#define HIVE_ADDR_sp_if_b 0x395C +#define HIVE_SIZE_sp_if_b 48 +#define HIVE_MEM_sp_dmem_bss_addr scalar_processor_dmem +#define HIVE_ADDR_sp_dmem_bss_addr 0x1688 +#define HIVE_SIZE_sp_dmem_bss_addr 4 +#define HIVE_MEM_sp_data scalar_processor_dmem +#define HIVE_ADDR_sp_data 0x168C +#define HIVE_SIZE_sp_data 8704 +#define HIVE_MEM_sp_overlay_height scalar_processor_dmem +#define HIVE_ADDR_sp_overlay_height 0x388C +#define HIVE_SIZE_sp_overlay_height 4 +#define HIVE_MEM_dma_proxy_kill_req scalar_processor_dmem +#define HIVE_ADDR_dma_proxy_kill_req 0x524 +#define HIVE_SIZE_dma_proxy_kill_req 1 +#define HIVE_MEM_mem_map scalar_processor_dmem +#define HIVE_ADDR_mem_map 0x3A74 +#define HIVE_SIZE_mem_map 100 +#define HIVE_MEM_sp_proxy_running scalar_processor_dmem +#define HIVE_ADDR_sp_proxy_running 0x52C +#define HIVE_SIZE_sp_proxy_running 4 +#define HIVE_MEM_sp_if_a_changed scalar_processor_dmem +#define HIVE_ADDR_sp_if_a_changed 0x398C +#define HIVE_SIZE_sp_if_a_changed 4 +#define HIVE_MEM_vtmp1 scalar_processor_dmem +#define HIVE_ADDR_vtmp1 0x3890 +#define HIVE_SIZE_vtmp1 128 +#define HIVE_MEM_isp_vf_output_width_vecs scalar_processor_dmem +#define HIVE_ADDR_isp_vf_output_width_vecs 0x3910 +#define HIVE_SIZE_isp_vf_output_width_vecs 4 +#define HIVE_ADDR_sp_bin_copy_entry 0x2D8 + +#endif /* _SP_MAP_H_ */ diff --git a/drivers/media/video/atomisp/css/hrt/sp_hrt.h b/drivers/media/video/atomisp/css/hrt/sp_hrt.h new file mode 100644 index 0000000..809e9a3 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/sp_hrt.h @@ -0,0 +1,32 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _sp_hrt_h_ +#define _sp_hrt_h_ + +#define hrt_sp_dmem(cell) HRT_PROC_TYPE_PROP(cell, _dmem) + +#define hrt_sp_dmem_master_port_address(cell) \ + hrt_mem_master_port_address(cell, hrt_sp_dmem(cell)) + +#endif /* _sp_hrt_h_ */ diff --git a/drivers/media/video/atomisp/css/hrt/streaming_to_mipi_defs.h b/drivers/media/video/atomisp/css/hrt/streaming_to_mipi_defs.h new file mode 100644 index 0000000..2826ce8 --- /dev/null +++ b/drivers/media/video/atomisp/css/hrt/streaming_to_mipi_defs.h @@ -0,0 +1,37 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _streaming_to_mipi_defs_h +#define _streaming_to_mipi_defs_h + +#define HIVE_STR_TO_MIPI_VALID_A_BIT 0 +#define HIVE_STR_TO_MIPI_VALID_B_BIT 1 +#define HIVE_STR_TO_MIPI_SOL_BIT 2 +#define HIVE_STR_TO_MIPI_EOL_BIT 3 +#define HIVE_STR_TO_MIPI_SOF_BIT 4 +#define HIVE_STR_TO_MIPI_EOF_BIT 5 +#define HIVE_STR_TO_MIPI_CH_ID_LSB 6 + +#define HIVE_STR_TO_MIPI_DATA_A_LSB (HIVE_STR_TO_MIPI_VALID_B_BIT + 1) + +#endif /* _streaming_to_mipi_defs_h */ diff --git a/drivers/media/video/atomisp/css/sh_css.c b/drivers/media/video/atomisp/css/sh_css.c new file mode 100644 index 0000000..b0b68ff --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css.c @@ -0,0 +1,4699 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css.h" +#include "sh_css_hrt.h" +#include "sh_css_binary.h" +#include "sh_css_internal.h" +#include "sh_css_sp.h" +#include "sh_css_hw.h" +#include "sh_css_rx.h" +#include "sh_css_defs.h" +#include "sh_css_firmware.h" +#include "sh_css_binary_info.h" +#include "sh_css_accelerate.h" + +#define WITH_PC_MONITORING 0 + +#if WITH_PC_MONITORING +#define MULTIPLE_SAMPLES 1 +#define NOF_SAMPLES 60 +#include "linux/kthread.h" +#include "linux/sched.h" +#include "linux/delay.h" +#include "sh_css_metrics.h" + +static int thread_alive; +#endif + +/* Name of the sp program: should not be built-in */ +#define SP_PROG_NAME "sp" + +/* for JPEG, we don't know the length of the image upfront, + * but since we support sensor upto 16MP, we take this as + * upper limit. + */ +#define JPEG_BYTES (16 * 1024 * 1024) + +#define NUM_REF_FRAMES 2 +#define NUM_CONTINUOUS_FRAMES 2 +#define NUM_TNR_FRAMES 2 + +#define IS_ODD(a) ((a) & 0x1) + +#define DEFAULT_FRAME_INFO \ +{ \ + .width = 0, \ + .height = 0, \ + .format = SH_CSS_FRAME_FORMAT_YUV420, \ + .raw_bit_depth = 0, \ + .raw_bayer_order = sh_css_bayer_order_grbg, \ +} + +#define DEFAULT_IF_CONFIG \ +{ \ + .start_line = 0, \ + .start_column = 0, \ + .left_padding = 0, \ + .cropped_height = 0, \ + .cropped_width = 0, \ + .deinterleaving = 0, \ + .buf_vecs = 0, \ + .buf_start_index = 0, \ + .buf_increment = 0, \ + .buf_eol_offset = 0, \ + .yuv420 = false, \ + .block_no_reqs = false, \ +} + +enum sh_css_mode { + sh_css_mode_preview, + sh_css_mode_video, + sh_css_mode_capture +}; + +enum sh_css_state { + sh_css_state_idle, + sh_css_state_executing_isp, + sh_css_state_executing_sp_bin_copy, +}; + +struct sh_css_pipeline_stage { + struct sh_css_binary *binary; /* built-in binary */ + struct sh_css_binary_args args; + const struct sh_css_acc_fw *firmware; /* acceleration binary */ + int mode; + bool out_frame_allocated; + bool vf_frame_allocated; + struct sh_css_pipeline_stage *next; +}; + +struct sh_css_pipeline { + unsigned int length; + struct sh_css_pipeline_stage *stages; + bool reload; + struct sh_css_pipeline_stage *current_stage; +}; + +struct sh_css_preview_settings { + struct sh_css_frame_info output_info; + /* resolution before yuv downscaling */ + struct sh_css_frame_info pp_input_info; + struct sh_css_pipeline pipeline; + struct sh_css_binary copy_binary; + struct sh_css_binary preview_binary; + struct sh_css_binary vf_pp_binary; + struct sh_css_frame *ref_frames[NUM_REF_FRAMES]; + unsigned int prev_ref_frame; + struct sh_css_frame *continuous_frames[NUM_CONTINUOUS_FRAMES]; + unsigned int continuous_frame; + bool online; + struct sh_css_shading_table *shading_table; + bool zoom_changed; +}; + +#define DEFAULT_PREVIEW_SETTINGS \ +{ \ + .output_info = DEFAULT_FRAME_INFO, \ + .pp_input_info = DEFAULT_FRAME_INFO, \ + .online = true, \ +} + +struct sh_css_capture_settings { + enum sh_css_capture_mode mode; + bool xnr; + bool bayer_ds; + struct sh_css_binary copy_binary; + struct sh_css_binary primary_binary; + struct sh_css_binary pre_gdc_binary; + struct sh_css_binary gdc_binary; + struct sh_css_binary post_gdc_binary; + struct sh_css_binary pre_anr_binary; + struct sh_css_binary anr_binary; + struct sh_css_binary post_anr_binary; + struct sh_css_binary capture_pp_binary; + struct sh_css_binary vf_pp_binary; + /* resolution before yuv downscaling */ + struct sh_css_frame_info pp_input_info; + struct sh_css_frame_info output_info; + struct sh_css_frame_info vf_info; + struct sh_css_pipeline pipeline; + struct sh_css_frame *capture_pp_frame; + struct sh_css_frame *output_frame; + bool online; + bool need_pp; + struct sh_css_shading_table *shading_table; + bool zoom_changed; +}; + +#define DEFAULT_CAPTURE_SETTINGS \ +{ \ + .mode = SH_CSS_CAPTURE_MODE_PRIMARY, \ + .xnr = false, \ + .bayer_ds = false, \ + .pp_input_info = DEFAULT_FRAME_INFO, \ + .output_info = DEFAULT_FRAME_INFO, \ + .vf_info = DEFAULT_FRAME_INFO, \ + .online = true, \ + .need_pp = false, \ +} + +#define NUM_VIDEO_REF_FRAMES 2 +#define NUM_VIDEO_TNR_FRAMES 2 + +struct sh_css_video_settings { + struct sh_css_binary video_binary; + struct sh_css_binary vf_pp_binary; + struct sh_css_frame_info output_info; + struct sh_css_frame_info vf_info; + struct sh_css_frame *ref_frames[NUM_VIDEO_REF_FRAMES]; + unsigned int prev_ref_frame; + struct sh_css_frame *tnr_frames[NUM_VIDEO_TNR_FRAMES]; + unsigned int prev_tnr_frame; + int dvs_vector_x; + int dvs_vector_y; + unsigned int dvs_envelope_width; + unsigned int dvs_envelope_height; + struct sh_css_frame *vf_pp_in_frame; + struct sh_css_pipeline pipeline; + struct sh_css_shading_table *shading_table; + bool zoom_changed; +}; + +#define DEFAULT_VIDEO_SETTINGS \ +{ \ + .output_info = DEFAULT_FRAME_INFO, \ + .vf_info = DEFAULT_FRAME_INFO, \ +} + +struct sh_css { + struct sh_css_preview_settings preview_settings; + struct sh_css_capture_settings capture_settings; + struct sh_css_video_settings video_settings; + unsigned int ch_id; + unsigned int input_width; + unsigned int input_height; + struct sh_css_frame_info input_effective_info; + enum sh_css_input_format input_format; + enum sh_css_mode mode; + struct sh_css_mipi_config mipi_config; + bool reconfigure_css_rx; + bool invalidate; + void *(*malloc) (size_t size); + void (*free) (void *ptr); + enum sh_css_state state; + bool two_ppc; + enum sh_css_bayer_order bayer_order; + unsigned int sensor_binning; + bool irq_edge; + const struct sh_css_overlay *vf_overlay; + bool vf_overlay_changed; + struct sh_css_if_config curr_if_a_config; + struct sh_css_if_config curr_if_b_config; + unsigned int curr_fmt_type; + unsigned int curr_ch_id; + enum sh_css_input_mode curr_input_mode; + enum sh_css_input_mode input_mode; + bool check_system_idle; + unsigned int curr_dx; + unsigned int curr_dy; + bool continuous; + bool start_sp_copy; + bool disable_vf_pp; + bool disable_capture_pp; + const struct sh_css_shading_table *shading_table; + void *sp_bin_addr; + struct sh_css_acc_fw *output_stage; /* extra output stage */ + struct sh_css_acc_fw *vf_stage; /* extra vf stage */ + void *page_table_base_address; + bool capture_zoom_update; + bool preview_zoom_update; + bool video_zoom_update; +}; + +#define DEFAULT_MIPI_CONFIG \ +{ \ + .port = SH_CSS_MIPI_PORT_1LANE, \ + .num_lanes = 1, \ + .timeout = 0xffff4, \ + .comp_bpp = 0, \ + .uncomp_bpp = 0, \ + .comp = SH_CSS_MIPI_COMPRESSION_NONE, \ + .two_ppc = false, \ +} + +#define DEFAULT_CSS \ +{ \ + .preview_settings = DEFAULT_PREVIEW_SETTINGS, \ + .capture_settings = DEFAULT_CAPTURE_SETTINGS, \ + .video_settings = DEFAULT_VIDEO_SETTINGS, \ + .ch_id = 0, \ + .input_width = 0, \ + .input_height = 0, \ + .input_effective_info = DEFAULT_FRAME_INFO, \ + .input_format = SH_CSS_INPUT_FORMAT_RAW_10, \ + .mode = -1, \ + .mipi_config = DEFAULT_MIPI_CONFIG, \ + .reconfigure_css_rx = true, \ + .invalidate = false, \ + .malloc = NULL, \ + .free = NULL, \ + .state = sh_css_state_idle, \ + .two_ppc = false, \ + .bayer_order = sh_css_bayer_order_grbg, \ + .sensor_binning = 0, \ + .vf_overlay = NULL, \ + .vf_overlay_changed = false, \ + .curr_if_a_config = DEFAULT_IF_CONFIG, \ + .curr_if_b_config = DEFAULT_IF_CONFIG, \ + .curr_fmt_type = -1, /* trigger first configuration */ \ + .curr_ch_id = 0, \ + .curr_input_mode = SH_CSS_INPUT_MODE_SENSOR, \ + .input_mode = SH_CSS_INPUT_MODE_SENSOR, \ + .check_system_idle = true, \ + .curr_dx = 64, \ + .curr_dy = 64, \ + .continuous = false, \ + .start_sp_copy = false, \ + .disable_vf_pp = false, \ + .disable_capture_pp = false, \ + .shading_table = NULL, \ + .sp_bin_addr = NULL, \ + .page_table_base_address = NULL, \ + .capture_zoom_update = false, \ + .preview_zoom_update = false, \ + .video_zoom_update = false, \ +} + +int (*sh_css_printf) (const char *fmt, ...) = NULL; + +static struct sh_css my_css; +/* static variables, temporarily used in load__binaries. + Declaring these inside the functions increases the size of the + stack frames beyond the acceptable 128 bytes. */ +static struct sh_css_binary_descr preview_descr, + vf_pp_descr, + copy_descr, + prim_descr, + pre_gdc_descr, + gdc_descr, + post_gdc_descr, + pre_anr_descr, + anr_descr, + post_anr_descr, + video_descr, + capture_pp_descr; + +static enum sh_css_err +check_frame_info(struct sh_css_frame_info *info) +{ + if (info->width == 0 || info->height == 0) + return sh_css_err_illegal_resolution; + return sh_css_success; +} + +static enum sh_css_err +check_vf_info(struct sh_css_frame_info *info) +{ + enum sh_css_err err; + err = check_frame_info(info); + if (err != sh_css_success) + return err; + if (info->width > ISP_VF_PP_MAX_OUTPUT_WIDTH*2) + return sh_css_err_viewfinder_resolution_too_wide; + return sh_css_success; +} + +static enum sh_css_err +check_vf_out_info(struct sh_css_frame_info *out_info, + struct sh_css_frame_info *vf_info) +{ + enum sh_css_err err; + err = check_frame_info(out_info); + if (err != sh_css_success) + return err; + err = check_vf_info(vf_info); + if (err != sh_css_success) + return err; + if (vf_info->width > out_info->width || + vf_info->height > out_info->height) + return sh_css_err_viewfinder_resolution_exceeds_output; + return sh_css_success; +} + +static enum sh_css_err +check_res(unsigned int width, unsigned int height) +{ + if (width == 0 || + height == 0 || + IS_ODD(width) || + IS_ODD(height)) { + return sh_css_err_illegal_resolution; + } + return sh_css_success; +} + +static enum sh_css_err +check_null_res(unsigned int width, unsigned int height) +{ + if (IS_ODD(width) || IS_ODD(height)) + return sh_css_err_illegal_resolution; + + return sh_css_success; +} + +static bool +input_format_is_raw(enum sh_css_input_format format) +{ + return format == SH_CSS_INPUT_FORMAT_RAW_6 || + format == SH_CSS_INPUT_FORMAT_RAW_7 || + format == SH_CSS_INPUT_FORMAT_RAW_8 || + format == SH_CSS_INPUT_FORMAT_RAW_10 || + format == SH_CSS_INPUT_FORMAT_RAW_12; + /* raw_14 and raw_16 are not supported as input formats to the ISP. + * They can only be copied to a frame in memory using the + * copy binary. + */ +} + +static bool +input_format_is_yuv(enum sh_css_input_format format) +{ + return format == SH_CSS_INPUT_FORMAT_YUV420_8_LEGACY || + format == SH_CSS_INPUT_FORMAT_YUV420_8 || + format == SH_CSS_INPUT_FORMAT_YUV420_10 || + format == SH_CSS_INPUT_FORMAT_YUV422_8 || + format == SH_CSS_INPUT_FORMAT_YUV422_10; +} + +static enum sh_css_err +check_input(bool must_be_raw) +{ + if (my_css.input_effective_info.width == 0 || + my_css.input_effective_info.height == 0) { + return sh_css_err_effective_input_resolution_not_set; + } + if (must_be_raw && + !input_format_is_raw(my_css.input_format)) { + return sh_css_err_unsupported_input_format; + } + return sh_css_success; +} + +/* we don't compare the height here since the output frame is usually + a couple of lines bigger than the height of the binary info. + For the padded width however, we do check equility because this is + not expected to differ. A difference there would indicate an erroneous + situation. */ +static bool +check_infos_match(struct sh_css_frame_info *frame_info, + struct sh_css_frame_info *binary_info) +{ + if (frame_info->padded_width != binary_info->padded_width || + frame_info->height < binary_info->height || + frame_info->format != binary_info->format) { + return sh_css_err_frames_mismatch; + } + return sh_css_success; +} + +/* Input network configuration functions */ +static void +get_copy_out_frame_format(enum sh_css_frame_format *format) +{ + switch (my_css.input_format) { + case SH_CSS_INPUT_FORMAT_YUV420_8_LEGACY: + case SH_CSS_INPUT_FORMAT_YUV420_8: + *format = SH_CSS_FRAME_FORMAT_YUV420; + break; + case SH_CSS_INPUT_FORMAT_YUV420_10: + *format = SH_CSS_FRAME_FORMAT_YUV420_16; + break; + case SH_CSS_INPUT_FORMAT_YUV422_8: + *format = SH_CSS_FRAME_FORMAT_YUV422; + break; + case SH_CSS_INPUT_FORMAT_YUV422_10: + *format = SH_CSS_FRAME_FORMAT_YUV422_16; + break; + case SH_CSS_INPUT_FORMAT_RGB_444: + case SH_CSS_INPUT_FORMAT_RGB_555: + case SH_CSS_INPUT_FORMAT_RGB_565: + if (*format != SH_CSS_FRAME_FORMAT_RGBA888) + *format = SH_CSS_FRAME_FORMAT_RGB565; + break; + case SH_CSS_INPUT_FORMAT_RGB_666: + case SH_CSS_INPUT_FORMAT_RGB_888: + *format = SH_CSS_FRAME_FORMAT_RGBA888; + break; + case SH_CSS_INPUT_FORMAT_RAW_6: + case SH_CSS_INPUT_FORMAT_RAW_7: + case SH_CSS_INPUT_FORMAT_RAW_8: + case SH_CSS_INPUT_FORMAT_RAW_10: + case SH_CSS_INPUT_FORMAT_RAW_12: + case SH_CSS_INPUT_FORMAT_RAW_14: + case SH_CSS_INPUT_FORMAT_RAW_16: + if (*format != SH_CSS_FRAME_FORMAT_RAW) + *format = SH_CSS_FRAME_FORMAT_RAW; + break; + case SH_CSS_INPUT_FORMAT_BINARY_8: + *format = SH_CSS_FRAME_FORMAT_BINARY_8; + break; + } +} + +unsigned int +sh_css_input_format_bits_per_pixel(enum sh_css_input_format format, + bool two_ppc) +{ + switch (format) { + case SH_CSS_INPUT_FORMAT_YUV420_8_LEGACY: + case SH_CSS_INPUT_FORMAT_YUV420_8: + case SH_CSS_INPUT_FORMAT_YUV422_8: + case SH_CSS_INPUT_FORMAT_RGB_888: + case SH_CSS_INPUT_FORMAT_RAW_8: + case SH_CSS_INPUT_FORMAT_BINARY_8: + return 8; + case SH_CSS_INPUT_FORMAT_YUV420_10: + case SH_CSS_INPUT_FORMAT_YUV422_10: + case SH_CSS_INPUT_FORMAT_RAW_10: + return 10; + case SH_CSS_INPUT_FORMAT_RGB_444: + return 4; + case SH_CSS_INPUT_FORMAT_RGB_555: + return 5; + case SH_CSS_INPUT_FORMAT_RGB_565: + return 565; + case SH_CSS_INPUT_FORMAT_RGB_666: + case SH_CSS_INPUT_FORMAT_RAW_6: + return 6; + case SH_CSS_INPUT_FORMAT_RAW_7: + return 7; + case SH_CSS_INPUT_FORMAT_RAW_12: + return 12; + case SH_CSS_INPUT_FORMAT_RAW_14: + if (two_ppc) + return 14; + else + return 12; + case SH_CSS_INPUT_FORMAT_RAW_16: + if (two_ppc) + return 16; + else + return 12; + } + return 0; +} + +/* compute the log2 of the downscale factor needed to get closest + * to the requested viewfinder resolution on the upper side. The output cannot + * be smaller than the requested viewfinder resolution. + */ +enum sh_css_err +sh_css_vf_downscale_log2(const struct sh_css_frame_info *out_info, + const struct sh_css_frame_info *vf_info, + unsigned int *downscale_log2) +{ + unsigned int ds_log2 = 0, out_width = out_info->padded_width; + + if (out_width == 0) + return 0; + + /* downscale until width smaller than the viewfinder width. We don't + * test for the height since the vmem buffers only put restrictions on + * the width of a line, not on the number of lines in a frame. + */ + while (out_width >= vf_info->width) { + ds_log2++; + out_width /= 2; + } + /* now width is smaller, so we go up one step */ + if ((ds_log2 > 0) && (out_width < ISP_VF_PP_MAX_OUTPUT_WIDTH)) + ds_log2--; + /* TODO: use actual max input resolution of vf_pp binary */ + if ((out_info->width >> ds_log2) >= 2*ISP_VF_PP_MAX_OUTPUT_WIDTH) + return sh_css_err_viewfinder_resolution_too_wide; + *downscale_log2 = ds_log2; + return sh_css_success; +} + +/* ISP expects GRBG bayer order, we skip one line and/or one row + * to correct in case the input bayer order is different. + */ +static unsigned int +lines_needed_for_bayer_order(void) +{ + if (my_css.bayer_order == sh_css_bayer_order_bggr || + my_css.bayer_order == sh_css_bayer_order_gbrg) { + return 1; + } + return 0; +} + +static unsigned int +columns_needed_for_bayer_order(void) +{ + if (my_css.bayer_order == sh_css_bayer_order_rggb || + my_css.bayer_order == sh_css_bayer_order_gbrg) { + return 1; + } + return 0; +} + +static enum sh_css_err +input_start_column(unsigned int bin_in, + unsigned int *start_column) +{ + unsigned int in = my_css.input_width, + for_bayer = columns_needed_for_bayer_order(), start; + + if (bin_in + 2 * for_bayer > in) + return sh_css_err_not_enough_input_columns; + + /* On the hardware, we want to use the middle of the input, so we + * divide the start column by 2. */ + start = (in - bin_in) / 2; + /* in case the number of extra columns is 2 or odd, we round the start + * column down */ + start &= ~0x1; + + /* now we add the one column (if needed) to correct for the bayer + * order). + */ + start += for_bayer; + *start_column = start; + return sh_css_success; +} + +static enum sh_css_err +input_start_line(unsigned int bin_in, unsigned int *start_line) +{ + unsigned int in = my_css.input_height, + for_bayer = lines_needed_for_bayer_order(), start; + + if (bin_in + 2 * for_bayer > in) + return sh_css_err_not_enough_input_lines; + + /* On the hardware, we want to use the middle of the input, so we + * divide the start line by 2. On the simulator, we cannot handle extra + * lines at the end of the frame. + */ + start = (in - bin_in) / 2; + /* in case the number of extra lines is 2 or odd, we round the start + * line down. + */ + start &= ~0x1; + + /* now we add the one line (if needed) to correct for the bayer order*/ + start += for_bayer; + *start_line = start; + return sh_css_success; +} + +static enum sh_css_err +program_input_formatter(struct sh_css_binary *binary) +{ + unsigned int start_line, start_column = 0, + cropped_height = binary->in_frame_info.height, + cropped_width = binary->in_frame_info.width, + left_padding = binary->left_padding, + num_vectors, + buffer_height = 2, + buffer_width = binary->info->max_input_width, + two_ppc = my_css.two_ppc, + vmem_increment = 0, + deinterleaving = 0, + deinterleaving_b = 0, + width_a = 0, + width_b = 0, + bits_per_pixel, + vectors_per_buffer, + vectors_per_line = 0, + buffers_per_line = 0, + buf_offset_b = 0, + line_width = 0, + width_b_factor = 1, + start_column_b; + struct sh_css_if_config if_a_config, if_b_config; + enum sh_css_input_format input_format = binary->input_format; + enum sh_css_err err = sh_css_success; + + /* TODO: check to see if input is RAW and if current mode interprets + * RAW data in any particular bayer order. copy binary with output + * format other than raw should not result in dropping lines and/or + * columns. + */ + err = input_start_line(cropped_height, &start_line); + if (err != sh_css_success) + return err; + + if (left_padding) { + num_vectors = CEIL_DIV(cropped_width + left_padding, + ISP_VEC_NELEMS); + } else { + err = input_start_column(cropped_width, &start_column); + if (err != sh_css_success) + return err; + num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); + num_vectors *= buffer_height; + /* todo: in case of left padding, + num_vectors is vectors per line, + otherwise vectors per line * buffer_height. */ + } + + start_column_b = start_column; + + bits_per_pixel = sh_css_hrt_if_prim_vec_align()*8 / ISP_VEC_NELEMS; + switch (input_format) { + case SH_CSS_INPUT_FORMAT_YUV420_8_LEGACY: + if (two_ppc) { + vmem_increment = 1; + deinterleaving = 1; + deinterleaving_b = 1; + /* half lines */ + width_a = cropped_width * deinterleaving / 2; + width_b_factor = 2; + /* full lines */ + width_b = width_a * width_b_factor; + buffer_width *= deinterleaving * 2; + /* Patch from bayer to yuv */ + num_vectors *= deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + vectors_per_line = num_vectors / buffer_height; + /* Even lines are half size */ + line_width = + vectors_per_line * sh_css_hrt_if_prim_vec_align() / + 2; + start_column /= 2; + } else { + vmem_increment = 1; + deinterleaving = 3; + width_a = cropped_width * deinterleaving / 2; + buffer_width = buffer_width * deinterleaving / 2; + /* Patch from bayer to yuv */ + num_vectors = num_vectors / 2 * deinterleaving; + start_column = start_column * deinterleaving / 2; + } + break; + case SH_CSS_INPUT_FORMAT_YUV420_8: + case SH_CSS_INPUT_FORMAT_YUV420_10: + if (two_ppc) { + vmem_increment = 1; + deinterleaving = 1; + width_a = width_b = cropped_width * deinterleaving / 2; + buffer_width *= deinterleaving * 2; + num_vectors *= deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + vectors_per_line = num_vectors / buffer_height; + /* Even lines are half size */ + line_width = + vectors_per_line * sh_css_hrt_if_prim_vec_align() / + 2; + start_column *= deinterleaving; + start_column /= 2; + start_column_b = start_column; + } else { + vmem_increment = 1; + deinterleaving = 1; + width_a = cropped_width * deinterleaving; + buffer_width *= deinterleaving * 2; + num_vectors *= deinterleaving; + start_column *= deinterleaving; + } + break; + case SH_CSS_INPUT_FORMAT_YUV422_8: + case SH_CSS_INPUT_FORMAT_YUV422_10: + if (two_ppc) { + vmem_increment = 1; + deinterleaving = 1; + width_a = width_b = cropped_width * deinterleaving; + buffer_width *= deinterleaving * 2; + num_vectors *= deinterleaving; + start_column *= deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + start_column_b = start_column; + } else { + vmem_increment = 1; + deinterleaving = 2; + width_a = cropped_width * deinterleaving; + buffer_width *= deinterleaving; + num_vectors *= deinterleaving; + start_column *= deinterleaving; + } + break; + case SH_CSS_INPUT_FORMAT_RGB_444: + case SH_CSS_INPUT_FORMAT_RGB_555: + case SH_CSS_INPUT_FORMAT_RGB_565: + case SH_CSS_INPUT_FORMAT_RGB_666: + case SH_CSS_INPUT_FORMAT_RGB_888: + num_vectors *= 2; + if (two_ppc) { + deinterleaving = 2; /* BR in if_a, G in if_b */ + deinterleaving_b = 1; /* BR in if_a, G in if_b */ + buffers_per_line = 4; + start_column_b = start_column; + start_column *= deinterleaving; + start_column_b *= deinterleaving_b; + } else { + deinterleaving = 3; /* BGR */ + buffers_per_line = 3; + start_column *= deinterleaving; + } + vmem_increment = 1; + width_a = cropped_width * deinterleaving; + width_b = cropped_width * deinterleaving_b; + buffer_width *= buffers_per_line; + /* Patch from bayer to rgb */ + num_vectors = num_vectors / 2 * deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + break; + case SH_CSS_INPUT_FORMAT_RAW_6: + case SH_CSS_INPUT_FORMAT_RAW_7: + case SH_CSS_INPUT_FORMAT_RAW_8: + case SH_CSS_INPUT_FORMAT_RAW_10: + case SH_CSS_INPUT_FORMAT_RAW_12: + if (two_ppc) { + vmem_increment = 2; + deinterleaving = 1; + width_a = width_b = cropped_width / 2; + start_column /= 2; + start_column_b = start_column; + buf_offset_b = 1; + } else { + vmem_increment = 1; + deinterleaving = 2; + if (my_css.continuous && + binary->info->mode == SH_CSS_BINARY_MODE_COPY) { + /* No deinterleaving for sp copy */ + deinterleaving = 1; + } + width_a = cropped_width; + /* Must be multiple of deinterleaving */ + num_vectors = CEIL_MUL(num_vectors, deinterleaving); + } + buffer_height *= 2; + vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); + vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving); + break; + case SH_CSS_INPUT_FORMAT_RAW_14: + case SH_CSS_INPUT_FORMAT_RAW_16: + if (two_ppc) { + num_vectors *= 2; + vmem_increment = 1; + deinterleaving = 2; + width_a = width_b = cropped_width; + /* B buffer is one line further */ + buf_offset_b = buffer_width / ISP_VEC_NELEMS; + bits_per_pixel *= 2; + } else { + vmem_increment = 1; + deinterleaving = 2; + width_a = cropped_width; + start_column /= deinterleaving; + } + buffer_height *= 2; + break; + case SH_CSS_INPUT_FORMAT_BINARY_8: + break; + } + if (width_a == 0) + return sh_css_err_unsupported_input_mode; + + if (two_ppc) + left_padding /= 2; + + /* Default values */ + if (left_padding) + vectors_per_line = num_vectors; + if (!vectors_per_line) { + vectors_per_line = CEIL_MUL(num_vectors / buffer_height, + deinterleaving); + line_width = 0; + } + if (!line_width) + line_width = vectors_per_line * sh_css_hrt_if_prim_vec_align(); + if (!buffers_per_line) + buffers_per_line = deinterleaving; + line_width = CEIL_MUL(line_width, + sh_css_hrt_if_prim_vec_align()*vmem_increment); + + vectors_per_buffer = buffer_height * buffer_width / ISP_VEC_NELEMS; + + if (my_css.input_mode == SH_CSS_INPUT_MODE_TPG && + binary->info->mode == SH_CSS_BINARY_MODE_VIDEO) { + /* workaround for TPG in video mode*/ + start_line = 0; + start_column = 0; + cropped_height -= start_line; + width_a -= start_column; + } + + if_a_config.start_line = start_line; + if_a_config.start_column = start_column; + if_a_config.left_padding = left_padding / deinterleaving; + if_a_config.cropped_height = cropped_height; + if_a_config.cropped_width = width_a; + if_a_config.deinterleaving = deinterleaving; + if_a_config.buf_vecs = vectors_per_buffer; + if_a_config.buf_start_index = 0; + if_a_config.buf_increment = vmem_increment; + if_a_config.buf_eol_offset = + buffer_width * bits_per_pixel/8 - line_width; + if_a_config.yuv420 = input_format == SH_CSS_INPUT_FORMAT_YUV420_8 || + input_format == SH_CSS_INPUT_FORMAT_YUV420_10; + if_a_config.block_no_reqs = + my_css.input_mode != SH_CSS_INPUT_MODE_SENSOR; + + if (two_ppc) { + if (deinterleaving_b) { + deinterleaving = deinterleaving_b; + width_b = cropped_width * deinterleaving; + buffer_width *= deinterleaving; + /* Patch from bayer to rgb */ + num_vectors = + num_vectors / 2 * deinterleaving * width_b_factor; + vectors_per_line = num_vectors / buffer_height; + line_width = + vectors_per_line * sh_css_hrt_if_prim_vec_align(); + } + if_b_config.start_line = start_line; + if_b_config.start_column = start_column_b; + if_b_config.left_padding = left_padding / deinterleaving; + if_b_config.cropped_height = cropped_height; + if_b_config.cropped_width = width_b; + if_b_config.deinterleaving = deinterleaving; + if_b_config.buf_vecs = vectors_per_buffer; + if_b_config.buf_start_index = buf_offset_b; + if_b_config.buf_increment = vmem_increment; + if_b_config.buf_eol_offset = + buffer_width * bits_per_pixel/8 - line_width; + if_b_config.yuv420 = + input_format == SH_CSS_INPUT_FORMAT_YUV420_8 + || input_format == SH_CSS_INPUT_FORMAT_YUV420_10; + if_b_config.block_no_reqs = + my_css.input_mode != SH_CSS_INPUT_MODE_SENSOR; + if (memcmp(&if_a_config, &my_css.curr_if_a_config, + sizeof(if_a_config)) || + memcmp(&if_b_config, &my_css.curr_if_b_config, + sizeof(if_b_config))) { + my_css.curr_if_a_config = if_a_config; + my_css.curr_if_b_config = if_b_config; + sh_css_sp_set_if_configs(&if_a_config, &if_b_config); + } + } else { + if (memcmp(&if_a_config, &my_css.curr_if_a_config, + sizeof(if_a_config))) { + my_css.curr_if_a_config = if_a_config; + sh_css_sp_set_if_configs(&if_a_config, NULL); + } + } + return sh_css_success; +} + +static enum sh_css_err +sh_css_config_input_network(struct sh_css_pipeline *pipeline, + struct sh_css_binary *binary) +{ + unsigned int fmt_type; + enum sh_css_err err = sh_css_success; + + if (pipeline && pipeline->stages) + binary = pipeline->stages->binary; + + err = sh_css_input_format_type(my_css.input_format, + my_css.mipi_config.comp, + &fmt_type); + if (err != sh_css_success) + return err; + if (fmt_type != my_css.curr_fmt_type || + my_css.ch_id != my_css.curr_ch_id || + my_css.input_mode != my_css.curr_input_mode) { + my_css.curr_fmt_type = fmt_type; + my_css.curr_ch_id = my_css.ch_id; + my_css.curr_input_mode = my_css.input_mode; + sh_css_sp_program_input_circuit(fmt_type, + my_css.ch_id, + my_css.input_mode); + } + + if (binary && (binary->online || my_css.continuous)) { + if (my_css.continuous) + my_css.start_sp_copy = true; + err = program_input_formatter(binary); + if (err != sh_css_success) + return err; + } + + if (my_css.input_mode == SH_CSS_INPUT_MODE_TPG || + my_css.input_mode == SH_CSS_INPUT_MODE_PRBS) { + unsigned int hblank_cycles = 100, + vblank_lines = 6, + width, + height, + vblank_cycles; + width = binary->in_frame_info.width; + height = binary->in_frame_info.height; + vblank_cycles = vblank_lines * (width + hblank_cycles); + sh_css_sp_configure_sync_gen(width, height, hblank_cycles, + vblank_cycles); + } + return sh_css_success; +} + +#if WITH_PC_MONITORING +struct task_struct *my_kthread; /* Handle for the monitoring thread */ +int sh_binary_running; /* Enable sampling in the thread */ + +static void print_pc_histo(char *core_name, struct sh_css_pc_histogram *hist) +{ + unsigned i; + unsigned cnt_run = 0; + unsigned cnt_stall = 0; + sh_css_print("%s histogram length = %d\n", core_name, hist->length); + sh_css_print("%s PC\trun\tstall\n", core_name); + + for (i = 0; i < hist->length; i++) { + if ((hist->run[i] == 0) && (hist->run[i] == hist->stall[i])) + continue; + sh_css_print("%s %d\t%d\t%d\n", + core_name, i, hist->run[i], hist->stall[i]); + cnt_run += hist->run[i]; + cnt_stall += hist->stall[i]; + } + + sh_css_print(" Statistics for %s, cnt_run = %d, cnt_stall = %d, " + "hist->length = %d\n", + core_name, cnt_run, cnt_stall, hist->length); +} + +static void print_pc_histogram(void) +{ + struct sh_css_binary_metrics *metrics; + + for (metrics = sh_css_metrics.binary_metrics; + metrics; + metrics = metrics->next) { + if (metrics->mode == SH_CSS_BINARY_ID_PREVIEW_DZ || + metrics->mode == SH_CSS_BINARY_ID_VF_PP) { + sh_css_print("pc_histogram for binary %d is SKIPPED\n", + metrics->mode); + continue; + } + + sh_css_print(" pc_histogram for binary %d\n", metrics->mode); + print_pc_histo(" ISP", &metrics->isp_histogram); + print_pc_histo(" SP", &metrics->sp_histogram); + sh_css_print("print_pc_histogram() done for binay->id = %d, " + "done.\n", metrics->mode); + } + + sh_css_print("PC_MONITORING:print_pc_histogram() -- DONE\n"); +} + +static int pc_monitoring(void *data) +{ + int i = 0; + + while (true) { + if (sh_binary_running) { + sh_css_metrics_sample_pcs(); +#if MULTIPLE_SAMPLES + for (i = 0; i < NOF_SAMPLES; i++) + sh_css_metrics_sample_pcs(); +#endif + } + usleep_range(10, 50); + } + return 0; +} + +static void spying_thread_create(void) +{ + my_kthread = kthread_run(pc_monitoring, NULL, "sh_pc_monitor"); + sh_css_metrics_enable_pc_histogram(1); +} + +static void input_frame_info(struct sh_css_frame_info frame_info) +{ + sh_css_print("SH_CSS:input_frame_info() -- frame->info.width = %d, " + "frame->info.height = %d, format = %d\n", + frame_info.width, frame_info.height, frame_info.format); +} +#endif /* WITH_PC_MONITORING */ + +static enum sh_css_err +start_binary(struct sh_css_binary *binary, + struct sh_css_binary_args *args, + bool preview_mode) +{ + enum sh_css_err err = sh_css_success; + + if (my_css.reconfigure_css_rx) + sh_css_rx_disable(); + + sh_css_metrics_start_binary(&binary->metrics); + +#if WITH_PC_MONITORING + sh_css_print("PC_MONITORING: %s() -- binary id = %d , " + "enable_dvs_envelope = %d\n", + __func__, binary->info->id, + binary->info->enable_dvs_envelope); + input_frame_info(binary->in_frame_info); + + if (binary->info->id == SH_CSS_BINARY_ID_VIDEO_DZ) + sh_binary_running = 1; +#endif + + if (binary->info->mode == SH_CSS_BINARY_MODE_VF_PP && + my_css.vf_overlay_changed) { + sh_css_sp_set_overlay(my_css.vf_overlay); + my_css.vf_overlay_changed = false; + } + + if (my_css.continuous && binary->info->mode == + SH_CSS_BINARY_MODE_PREVIEW) { + sh_css_sp_start_raw_copy(binary, args->cc_frame, + my_css.two_ppc, false); + } + my_css.state = sh_css_state_executing_isp; + err = sh_css_sp_start_isp(binary, args, preview_mode); + if (err != sh_css_success) + return err; + + if (my_css.reconfigure_css_rx) { + my_css.mipi_config.two_ppc = my_css.two_ppc; + sh_css_rx_configure(&my_css.mipi_config); + my_css.reconfigure_css_rx = false; + } + return sh_css_success; +} + +static enum sh_css_err +start_firmware(const struct sh_css_acc_fw *fw, + struct sh_css_binary_args *args) +{ + enum sh_css_err err; + struct sh_css_acc_fw *firmware = (struct sh_css_acc_fw *)fw; + my_css.state = sh_css_state_executing_isp; + err = sh_css_acc_start(firmware, args); + return err; +} + +static void +sh_css_frame_zero(struct sh_css_frame *frame) +{ + unsigned int i, words = frame->data_bytes / sizeof(int); + int *ptr = frame->data; + + for (i = 0; i < words; i++) + hrt_isp_css_mm_store_int(ptr + i, 0); +} + +/* start the copy function on the SP */ +static enum sh_css_err +start_copy_on_sp(struct sh_css_binary *binary, + struct sh_css_frame *out_frame) +{ + my_css.capture_settings.output_frame = out_frame; + + if (my_css.reconfigure_css_rx) + sh_css_rx_disable(); + + sh_css_hrt_irq_enable(hrt_isp_css_irq_sw_0, true, false); + sh_css_hrt_irq_enable(hrt_isp_css_irq_sw_1, true, false); + sh_css_hrt_irq_enable(hrt_isp_css_irq_sw_2, true, false); + if (my_css.input_format == SH_CSS_INPUT_FORMAT_BINARY_8) { + sh_css_sp_start_binary_copy(out_frame, my_css.two_ppc); + } else { + sh_css_sp_start_raw_copy(binary, out_frame, + my_css.two_ppc, true); + } + + if (my_css.reconfigure_css_rx) { + /* do we need to wait for the IF do be ready? */ + my_css.mipi_config.two_ppc = my_css.two_ppc; + sh_css_rx_configure(&my_css.mipi_config); + my_css.reconfigure_css_rx = false; + } + + return sh_css_success; +} + +/* Pipeline: + * To organize the several different binaries for each type of mode, + * we use a pipeline. A pipeline contains a number of stages, each with + * their own binary and frame pointers. + * When stages are added to a pipeline, output frames that are not passed + * from outside are automatically allocated. + * When input frames are not passed from outside, each stage will use the + * output frame of the previous stage as input (the full resolution output, + * not the viewfinder output). + * Pipelines must be cleaned and re-created when settings of the binaries + * change. + */ +static void +sh_css_pipeline_stage_destroy(struct sh_css_pipeline_stage *me) +{ + if (me->out_frame_allocated) + sh_css_frame_free(me->args.out_frame); + if (me->vf_frame_allocated) + sh_css_frame_free(me->args.out_vf_frame); + sh_css_free(me); +} + +static void +sh_css_binary_args_reset(struct sh_css_binary_args *args) +{ + args->in_frame = NULL; + args->out_frame = NULL; + args->in_ref_frame = NULL; + args->out_ref_frame = NULL; + args->in_tnr_frame = NULL; + args->out_tnr_frame = NULL; + args->extra_frame = NULL; + args->out_vf_frame = NULL; + args->dvs_vector_x = 0; + args->dvs_vector_y = 0; + args->enable_xnr = my_css.capture_settings.xnr; + args->two_ppc = my_css.two_ppc; + args->copy_vf = false; + args->copy_output = true; + args->vf_downscale_log2 = 0; +} + +static enum sh_css_err +sh_css_pipeline_stage_create(struct sh_css_pipeline_stage **me, + struct sh_css_binary *binary, + const struct sh_css_acc_fw *firmware, + int mode, + struct sh_css_frame *cc_frame, + struct sh_css_frame *in_frame, + struct sh_css_frame *out_frame, + struct sh_css_frame *vf_frame) +{ + struct sh_css_pipeline_stage *stage = sh_css_malloc(sizeof(*stage)); + if (!stage) + return sh_css_err_cannot_allocate_memory; + stage->binary = firmware ? NULL : binary; + stage->firmware = firmware; + stage->mode = mode; + stage->out_frame_allocated = false; + stage->vf_frame_allocated = false; + stage->next = NULL; + sh_css_binary_args_reset(&stage->args); + + if (!in_frame && !firmware && !binary->online) + return sh_css_err_internal_error; + + if (!out_frame && !firmware) { + enum sh_css_err ret = + sh_css_frame_allocate_from_info(&out_frame, + &binary->out_frame_info); + if (ret != sh_css_success) { + sh_css_free(stage); + return ret; + } + stage->out_frame_allocated = true; + } + /* VF frame is not needed in case of my_css.capture_settings.need_pp + However, the capture binary needs a vf frame to write to. + */ + if (!vf_frame) { + if ((binary && binary->vf_frame_info.width) || + (firmware && firmware->header.sp.out_vf)) { + enum sh_css_err ret = + sh_css_frame_allocate_from_info(&vf_frame, + &binary->vf_frame_info); + if (ret != sh_css_success) { + if (stage->out_frame_allocated) + sh_css_frame_free(out_frame); + sh_css_free(stage); + return ret; + } + stage->vf_frame_allocated = true; + } + } else if (vf_frame && binary && binary->vf_frame_info.width) + stage->vf_frame_allocated = true; + + stage->args.cc_frame = cc_frame; + stage->args.in_frame = in_frame; + stage->args.out_frame = out_frame; + stage->args.out_vf_frame = vf_frame; + *me = stage; + return sh_css_success; +} + +static void +sh_css_pipeline_init(struct sh_css_pipeline *me) +{ + me->length = 0; + me->stages = NULL; + me->reload = true; + me->current_stage = NULL; +} + +static enum sh_css_err +sh_css_pipeline_add_stage(struct sh_css_pipeline *me, + struct sh_css_binary *binary, + const struct sh_css_acc_fw *firmware, + int mode, + struct sh_css_frame *cc_frame, + struct sh_css_frame *in_frame, + struct sh_css_frame *out_frame, + struct sh_css_frame *vf_frame, + struct sh_css_pipeline_stage **stage) +{ + struct sh_css_pipeline_stage *last = me->stages, *new_stage = NULL; + enum sh_css_err err; + + if (!binary && !firmware) + return sh_css_err_internal_error; + + while (last && last->next) + last = last->next; + + /* if in_frame is not set, we use the out_frame from the previous + * stage, if no previous stage, it's an error. + */ + if (!in_frame && !firmware && !binary->online) { + if (last) + in_frame = last->args.out_frame; + if (!in_frame) + return sh_css_err_internal_error; + } + err = sh_css_pipeline_stage_create(&new_stage, binary, firmware, + mode, cc_frame, + in_frame, out_frame, vf_frame); + if (err != sh_css_success) + return err; + if (last) + last->next = new_stage; + else + me->stages = new_stage; + me->length++; + if (stage) + *stage = new_stage; + return sh_css_success; +} + +static enum sh_css_err +sh_css_pipeline_get_stage(struct sh_css_pipeline *me, + int mode, + struct sh_css_pipeline_stage **stage) +{ + struct sh_css_pipeline_stage *s; + for (s = me->stages; s; s = s->next) { + if (s->mode == mode) { + *stage = s; + return sh_css_success; + } + } + return sh_css_err_internal_error; +} + +static enum sh_css_err +sh_css_pipeline_get_output_stage(struct sh_css_pipeline *me, + int mode, + struct sh_css_pipeline_stage **stage) +{ + struct sh_css_pipeline_stage *s; + + *stage = NULL; + /* First find acceleration firmware at end of pipe */ + for (s = me->stages; s; s = s->next) { + if (s->firmware && s->mode == mode && + s->firmware->header.sp.output) + *stage = s; + } + if (*stage) + return sh_css_success; + /* If no firmware, find binary in pipe */ + return sh_css_pipeline_get_stage(me, mode, stage); +} + +static void +sh_css_pipeline_restart(struct sh_css_pipeline *me) +{ + me->current_stage = NULL; +} + +static void +sh_css_pipeline_clean(struct sh_css_pipeline *me) +{ + struct sh_css_pipeline_stage *s = me->stages; + + while (s) { + struct sh_css_pipeline_stage *next = s->next; + sh_css_pipeline_stage_destroy(s); + s = next; + } + sh_css_pipeline_init(me); +} + +static bool +sh_css_pipeline_done(struct sh_css_pipeline *me) +{ + return me->current_stage && !me->current_stage->next; +} + +static struct sh_css_pipeline * +get_current_pipeline(void) +{ + if (my_css.mode == sh_css_mode_preview) + return &my_css.preview_settings.pipeline; + else if (my_css.mode == sh_css_mode_video) + return &my_css.video_settings.pipeline; + else + return &my_css.capture_settings.pipeline; +} + +void +sh_css_terminate_firmware(void) +{ + struct sh_css_pipeline *me = get_current_pipeline(); + struct sh_css_acc_fw *firmware; + + if (!me->current_stage) + return; + firmware = (struct sh_css_acc_fw *)me->current_stage->firmware; + if (!firmware) + return; + + sh_css_acceleration_done(firmware); + /* reload SP firmmware */ + my_css.sp_bin_addr = sh_css_sp_load_program(&sh_css_sp_fw, + SP_PROG_NAME); + /* restore SP state */ + if (my_css.two_ppc) { + sh_css_sp_set_if_configs(&my_css.curr_if_a_config, + &my_css.curr_if_b_config); + } else { + sh_css_sp_set_if_configs(&my_css.curr_if_a_config, NULL); + } +} + +static enum sh_css_err +sh_css_pipeline_start_next_stage(struct sh_css_pipeline *me) +{ + struct sh_css_pipeline_stage *stage; + enum sh_css_err err; + + if (me->current_stage) + stage = me->current_stage->next; + else + stage = me->stages; + if (!stage) + return sh_css_success; + + me->current_stage = stage; + + if (stage->firmware) + err = start_firmware(stage->firmware, &stage->args); + else + err = start_binary(stage->binary, &stage->args, + me == &my_css.preview_settings.pipeline); + return err; +} + +void +sh_css_frame_info_set_width(struct sh_css_frame_info *info, + unsigned int width) +{ + info->width = width; + /* frames with a U and V plane of 8 bits per pixel need to have + all planes aligned, this means double the alignment for the + Y plane if the horizontal decimation is 2. */ + if (info->format == SH_CSS_FRAME_FORMAT_YUV420 || + info->format == SH_CSS_FRAME_FORMAT_YV12) + info->padded_width = CEIL_MUL(width, 2*HIVE_ISP_DDR_WORD_BYTES); + else if (info->format == SH_CSS_FRAME_FORMAT_YUV_LINE) + info->padded_width = CEIL_MUL(width, 2*ISP_VEC_NELEMS); + else + info->padded_width = CEIL_MUL(width, HIVE_ISP_DDR_WORD_BYTES); +} + +static void +sh_css_frame_info_set_format(struct sh_css_frame_info *info, + enum sh_css_frame_format format) +{ + /* yuv_line has 2*NWAY alignment */ + info->format = format; + /* HACK: this resets the padded width incorrectly. + Lex needs to fix this in the vf_veceven module. */ + info->padded_width = CEIL_MUL(info->padded_width, 2*ISP_VEC_NELEMS); +} + +static void +sh_css_frame_info_init(struct sh_css_frame_info *info, + unsigned int width, + unsigned int height, + enum sh_css_frame_format format) +{ + info->height = height; + info->format = format; + sh_css_frame_info_set_width(info, width); +} + +static void +invalidate_video_binaries(void) +{ + my_css.video_settings.pipeline.reload = true; + my_css.video_settings.video_binary.info = NULL; + my_css.video_settings.vf_pp_binary.info = NULL; + if (my_css.video_settings.shading_table) { + sh_css_shading_table_free(my_css.video_settings.shading_table); + my_css.video_settings.shading_table = NULL; + } +} + +void +sh_css_overlay_set_for_viewfinder(const struct sh_css_overlay *overlay) +{ + my_css.vf_overlay = overlay; + my_css.vf_overlay_changed = true; +} + +void +sh_css_set_shading_table(const struct sh_css_shading_table *table) +{ + my_css.shading_table = table; +} + +/* CSS receiver programming */ +enum sh_css_err +sh_css_input_configure_port(enum sh_css_mipi_port port, + unsigned int num_lanes, + unsigned int timeout) +{ + if (port == SH_CSS_MIPI_PORT_1LANE && num_lanes > 1) + return sh_css_err_conflicting_mipi_settings; + if (num_lanes > 4) + return sh_css_err_conflicting_mipi_settings; + my_css.mipi_config.port = port; + my_css.mipi_config.num_lanes = num_lanes; + my_css.mipi_config.timeout = timeout; + my_css.reconfigure_css_rx = true; + + return sh_css_success; +} + +enum sh_css_err +sh_css_input_set_compression(enum sh_css_mipi_compression comp, + unsigned int compressed_bits_per_pixel, + unsigned int uncompressed_bits_per_pixel) +{ + if (comp == SH_CSS_MIPI_COMPRESSION_NONE) { + if (compressed_bits_per_pixel || uncompressed_bits_per_pixel) + return sh_css_err_conflicting_mipi_settings; + } else { + if (compressed_bits_per_pixel < 6 || + compressed_bits_per_pixel > 8) + return sh_css_err_conflicting_mipi_settings; + if (uncompressed_bits_per_pixel != 10 && + uncompressed_bits_per_pixel != 12) + return sh_css_err_conflicting_mipi_settings; + } + my_css.mipi_config.comp = comp; + my_css.mipi_config.comp_bpp = compressed_bits_per_pixel; + my_css.mipi_config.uncomp_bpp = uncompressed_bits_per_pixel; + my_css.reconfigure_css_rx = true; + return sh_css_success; +} + +void +sh_css_tpg_configure(unsigned int x_mask, + int x_delta, + unsigned int y_mask, + int y_delta, + unsigned int xy_mask) +{ + sh_css_sp_configure_tpg(x_mask, y_mask, x_delta, y_delta, xy_mask); +} + +void +sh_css_prbs_set_seed(int seed) +{ + sh_css_sp_configure_prbs(seed); +} + +/* currently, the capture pp binary requires an internal frame. This will + be removed in the future. */ +static enum sh_css_err +alloc_capture_pp_frame(const struct sh_css_binary *binary) +{ + + struct sh_css_frame_info cpp_info; + enum sh_css_err err = sh_css_success; + + cpp_info = binary->internal_frame_info; + cpp_info.format = SH_CSS_FRAME_FORMAT_YUV420; + if (my_css.capture_settings.capture_pp_frame) + sh_css_frame_free(my_css.capture_settings.capture_pp_frame); + err = sh_css_frame_allocate_from_info( + &my_css.capture_settings.capture_pp_frame, &cpp_info); + return err; +} + +static void +invalidate_preview_binaries(void) +{ + my_css.preview_settings.pipeline.reload = true; + my_css.preview_settings.preview_binary.info = NULL; + my_css.preview_settings.vf_pp_binary.info = NULL; + my_css.preview_settings.copy_binary.info = NULL; + if (my_css.preview_settings.shading_table) { + sh_css_shading_table_free( + my_css.preview_settings.shading_table); + my_css.preview_settings.shading_table = NULL; + } +} + +static void +invalidate_capture_binaries(void) +{ + my_css.capture_settings.pipeline.reload = true; + my_css.capture_settings.copy_binary.info = NULL; + my_css.capture_settings.primary_binary.info = NULL; + my_css.capture_settings.pre_gdc_binary.info = NULL; + my_css.capture_settings.gdc_binary.info = NULL; + my_css.capture_settings.post_gdc_binary.info = NULL; + my_css.capture_settings.capture_pp_binary.info = NULL; + my_css.capture_settings.vf_pp_binary.info = NULL; + my_css.capture_settings.need_pp = false; + if (my_css.capture_settings.shading_table) { + sh_css_shading_table_free( + my_css.capture_settings.shading_table); + my_css.capture_settings.shading_table = NULL; + } +} + +static void +enable_interrupts(void) +{ + /* Enable IRQ when SP goes to idle */ + sh_css_hrt_irq_enable_sp(true); + /* Enabling this triggers an interrupt immediately, clear it */ + sh_css_hrt_irq_clear_sp(); + + sh_css_hrt_irq_enable(hrt_isp_css_irq_sp, true, my_css.irq_edge); + sh_css_hrt_irq_clear_all(); + sh_css_rx_enable_all_interrupts(); +} + +enum sh_css_err +sh_css_init(void *(*malloc_func) (size_t size), + void (*free_func) (void *ptr), + enum sh_css_interrupt_setting irq_setting, + const char *fw_data, + unsigned int fw_size) +{ + static struct sh_css default_css = DEFAULT_CSS; + enum sh_css_err err; + + if (malloc_func == NULL || free_func == NULL) + return sh_css_err_invalid_arguments; + + memcpy(&my_css, &default_css, sizeof(my_css)); + + my_css.malloc = malloc_func; + my_css.free = free_func; + my_css.irq_edge = (irq_setting == SH_CSS_INTERRUPT_SETTING_EDGE); + + /* In case this has been programmed already, update internal + data structure */ + my_css.page_table_base_address = + sh_css_mmu_get_page_table_base_address(); + + enable_interrupts(); + + err = sh_css_params_init(); + if (err != sh_css_success) + return err; + err = sh_css_load_firmware(fw_data, fw_size); + if (err != sh_css_success) + return err; + sh_css_init_binary_infos(); + my_css.sp_bin_addr = sh_css_sp_load_program(&sh_css_sp_fw, + SP_PROG_NAME); + if (!my_css.sp_bin_addr) + return sh_css_err_cannot_allocate_memory; + sh_css_pipeline_init(&my_css.preview_settings.pipeline); + sh_css_pipeline_init(&my_css.video_settings.pipeline); + sh_css_pipeline_init(&my_css.capture_settings.pipeline); + +#if WITH_PC_MONITORING + if (!thread_alive) { + thread_alive++; + sh_css_print("PC_MONITORING: %s() -- create thread DISABLED\n", + __func__); + spying_thread_create(); + } + sh_css_printf = printk; +#endif + + return err; +} + +/* Suspend does not need to do anything for now, this may change + in the future though. */ +void +sh_css_suspend(void) +{ +} + +void +sh_css_resume(void) +{ + /* trigger reconfiguration of necessary hardware */ + my_css.reconfigure_css_rx = true; + my_css.curr_if_a_config.cropped_width = 0; + my_css.curr_if_a_config.cropped_height = 0; + my_css.curr_if_b_config.cropped_width = 0; + my_css.curr_if_b_config.cropped_height = 0; + my_css.curr_fmt_type = -1; + /* reload the SP binary. ISP binaries are automatically + reloaded by the ISP upon execution. */ + sh_css_hrt_mmu_set_page_table_base_address( + my_css.page_table_base_address); + sh_css_params_reconfigure_gdc_lut(); + + sh_css_sp_activate_program(&sh_css_sp_fw, my_css.sp_bin_addr, + SP_PROG_NAME); + + enable_interrupts(); +} + +void * +sh_css_malloc(size_t size) +{ + if (size > 0 && my_css.malloc) + return my_css.malloc(size); + return NULL; +} + +void +sh_css_free(void *ptr) +{ + if (ptr && my_css.free) + my_css.free(ptr); +} + +void +sh_css_set_print_function(int (*func) (const char *fmt, ...)) +{ + sh_css_printf = func; +} + +void +sh_css_uninit(void) +{ + int i; + +#if WITH_PC_MONITORING + sh_css_print("PC_MONITORING: %s() -- started\n", __func__); + print_pc_histogram(); +#endif + + /* cleanup generic data */ + sh_css_params_uninit(); + sh_css_binary_uninit(); + if (my_css.sp_bin_addr) { + hrt_isp_css_mm_free(my_css.sp_bin_addr); + my_css.sp_bin_addr = NULL; + } + + /* cleanup preview data */ + invalidate_preview_binaries(); + sh_css_pipeline_clean(&my_css.preview_settings.pipeline); + for (i = 0; i < NUM_REF_FRAMES; i++) { + if (my_css.preview_settings.ref_frames[i]) { + sh_css_frame_free( + my_css.preview_settings.ref_frames[i]); + my_css.preview_settings.ref_frames[i] = NULL; + } + } + for (i = 0; i < NUM_CONTINUOUS_FRAMES; i++) { + if (my_css.preview_settings.continuous_frames[i]) { + sh_css_frame_free( + my_css.preview_settings.continuous_frames[i]); + my_css.preview_settings.continuous_frames[i] = NULL; + } + } + + /* cleanup video data */ + invalidate_video_binaries(); + sh_css_pipeline_clean(&my_css.video_settings.pipeline); + for (i = 0; i < NUM_TNR_FRAMES; i++) { + if (my_css.video_settings.tnr_frames[i]) + sh_css_frame_free(my_css.video_settings.tnr_frames[i]); + my_css.video_settings.tnr_frames[i] = NULL; + } + for (i = 0; i < NUM_REF_FRAMES; i++) { + if (my_css.video_settings.ref_frames[i]) + sh_css_frame_free(my_css.video_settings.ref_frames[i]); + my_css.video_settings.ref_frames[i] = NULL; + } + + /* cleanup capture data */ + invalidate_capture_binaries(); + sh_css_pipeline_clean(&my_css.capture_settings.pipeline); + if (my_css.capture_settings.capture_pp_frame) { + sh_css_frame_free(my_css.capture_settings.capture_pp_frame); + my_css.capture_settings.capture_pp_frame = NULL; + } +} + +enum sh_css_err +sh_css_start_next_stage(void) +{ + struct sh_css_pipeline *pipeline = NULL; + enum sh_css_err err = sh_css_success; + + /* LA: to be removed, now only first binary can run it */ + my_css.start_sp_copy = false; + + if (my_css.state != sh_css_state_idle) + return sh_css_err_system_not_idle; + + if (my_css.check_system_idle && !sh_css_hrt_system_is_idle()) + return sh_css_err_system_not_idle; + + if (my_css.mode == sh_css_mode_preview) + pipeline = &my_css.preview_settings.pipeline; + else if (my_css.mode == sh_css_mode_video) + pipeline = &my_css.video_settings.pipeline; + else + pipeline = &my_css.capture_settings.pipeline; + err = sh_css_pipeline_start_next_stage(pipeline); + return err; +} + +static bool +sh_css_frame_done(void) +{ + bool done = true; + if (my_css.state == sh_css_state_executing_isp) + done = sh_css_pipeline_done(get_current_pipeline()); + else if (my_css.state == sh_css_state_executing_sp_bin_copy) { + my_css.capture_settings.output_frame->planes.binary.size = + sh_css_sp_get_binary_copy_size(); + } + return done; +} + +static bool +sh_css_statistics_ready(void) +{ + struct sh_css_pipeline *pipeline = NULL; + + if (my_css.state != sh_css_state_executing_isp) + return false; + + pipeline = get_current_pipeline(); + if (pipeline->current_stage->binary) + return pipeline->current_stage->binary->info->enable_s3a; + return false; +} + +static bool +acceleration_done(void) +{ + struct sh_css_pipeline *pipeline = get_current_pipeline(); + return pipeline && + pipeline->current_stage && + pipeline->current_stage->firmware; +} + +enum sh_css_err +sh_css_translate_interrupt(unsigned int *irq_infos) +{ + enum hrt_isp_css_irq irq; + enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_more_irqs; + unsigned int infos = 0; + + while (status == hrt_isp_css_irq_status_more_irqs) { + status = sh_css_hrt_irq_get_id(&irq); + if (status == hrt_isp_css_irq_status_error) + return sh_css_err_interrupt_error; + +#if WITH_PC_MONITORING + sh_css_print("PC_MONITORING: %s() irq = %d, " + "sh_binary_running set to 0\n", __func__, irq); + sh_binary_running = 0 ; +#endif + + switch (irq) { + case hrt_isp_css_irq_sp: + sh_css_hrt_irq_clear_sp(); + if (sh_css_frame_done()) + infos |= SH_CSS_IRQ_INFO_FRAME_DONE; + else + infos |= SH_CSS_IRQ_INFO_START_NEXT_STAGE; + if (sh_css_statistics_ready()) + infos |= SH_CSS_IRQ_INFO_STATISTICS_READY; + if (acceleration_done()) + infos |= SH_CSS_IRQ_INFO_FW_ACC_DONE; + my_css.state = sh_css_state_idle; + break; + case hrt_isp_css_irq_isp: + /* nothing */ + break; + case hrt_isp_css_irq_mipi: + /* css rx interrupt, read error bits from css rx */ + infos |= SH_CSS_IRQ_INFO_CSS_RECEIVER_ERROR; + break; + case hrt_isp_css_irq_mipi_fifo_full: + infos |= + SH_CSS_IRQ_INFO_CSS_RECEIVER_FIFO_OVERFLOW; + break; + case hrt_isp_css_irq_mipi_sof: + infos |= SH_CSS_IRQ_INFO_CSS_RECEIVER_SOF; + break; + case hrt_isp_css_irq_mipi_eof: + infos |= SH_CSS_IRQ_INFO_CSS_RECEIVER_EOF; + break; + case hrt_isp_css_irq_mipi_sol: + infos |= SH_CSS_IRQ_INFO_CSS_RECEIVER_SOL; + break; + case hrt_isp_css_irq_mipi_eol: + infos |= SH_CSS_IRQ_INFO_CSS_RECEIVER_EOL; + break; + case hrt_isp_css_irq_sideband_changed: + infos |= + SH_CSS_IRQ_INFO_CSS_RECEIVER_SIDEBAND_CHANGED; + break; + case hrt_isp_css_irq_css_gen_short_0: + infos |= SH_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_0; + break; + case hrt_isp_css_irq_css_gen_short_1: + infos |= SH_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_1; + break; + case hrt_isp_css_irq_ift_prim: + infos |= SH_CSS_IRQ_INFO_IF_PRIM_ERROR; + break; + case hrt_isp_css_irq_ift_prim_b: + infos |= SH_CSS_IRQ_INFO_IF_PRIM_B_ERROR; + break; + case hrt_isp_css_irq_ift_sec: + infos |= SH_CSS_IRQ_INFO_IF_SEC_ERROR; + break; + case hrt_isp_css_irq_ift_mem_cpy: + infos |= SH_CSS_IRQ_INFO_STREAM_TO_MEM_ERROR; + break; + case hrt_isp_css_irq_sw_0: + infos |= SH_CSS_IRQ_INFO_SW_0; + break; + case hrt_isp_css_irq_sw_1: + infos |= SH_CSS_IRQ_INFO_SW_1; + break; + case hrt_isp_css_irq_sw_2: + infos |= SH_CSS_IRQ_INFO_SW_2; + break; + default: + break; + } + } + + if (irq_infos) + *irq_infos = infos; + return sh_css_success; +} + +void +sh_css_mmu_set_page_table_base_address(void *base_address) +{ + my_css.page_table_base_address = base_address; + sh_css_hrt_mmu_set_page_table_base_address(base_address); + sh_css_mmu_invalidate_cache(); +} + +void * +sh_css_mmu_get_page_table_base_address(void) +{ + return sh_css_hrt_mmu_get_page_table_base_address(); +} + +void +sh_css_mmu_invalidate_cache(void) +{ + sh_css_sp_invalidate_mmu(); +} + +enum sh_css_err +sh_css_enable_interrupt(enum sh_css_interrupt_info info, + bool enable) +{ + enum hrt_isp_css_irq irq = -1; + bool edge = my_css.irq_edge; + + switch (info) { + case SH_CSS_IRQ_INFO_CSS_RECEIVER_ERROR: + irq = hrt_isp_css_irq_mipi; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_FIFO_OVERFLOW: + irq = hrt_isp_css_irq_mipi_fifo_full; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_SOF: + irq = hrt_isp_css_irq_mipi_sof; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_EOF: + irq = hrt_isp_css_irq_mipi_eof; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_SOL: + irq = hrt_isp_css_irq_mipi_sol; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_EOL: + irq = hrt_isp_css_irq_mipi_eol; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_SIDEBAND_CHANGED: + irq = hrt_isp_css_irq_sideband_changed; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_0: + irq = hrt_isp_css_irq_css_gen_short_0; + break; + case SH_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_1: + irq = hrt_isp_css_irq_css_gen_short_1; + break; + case SH_CSS_IRQ_INFO_IF_PRIM_ERROR: + irq = hrt_isp_css_irq_ift_prim; + break; + case SH_CSS_IRQ_INFO_IF_PRIM_B_ERROR: + irq = hrt_isp_css_irq_ift_prim_b; + break; + case SH_CSS_IRQ_INFO_IF_SEC_ERROR: + irq = hrt_isp_css_irq_ift_sec; + break; + case SH_CSS_IRQ_INFO_STREAM_TO_MEM_ERROR: + irq = hrt_isp_css_irq_ift_mem_cpy; + break; + case SH_CSS_IRQ_INFO_SW_0: + irq = hrt_isp_css_irq_sw_0; + edge = false; + break; + case SH_CSS_IRQ_INFO_SW_1: + irq = hrt_isp_css_irq_sw_1; + edge = false; + break; + case SH_CSS_IRQ_INFO_SW_2: + irq = hrt_isp_css_irq_sw_2; + edge = false; + break; + default: + return sh_css_err_invalid_arguments; + } + + if (enable) + sh_css_hrt_irq_enable(irq, true, edge); + else + sh_css_hrt_irq_disable(irq); + + return sh_css_success; +} + +unsigned int +sh_css_get_sw_interrupt_value(void) +{ + return sh_css_sp_get_sw_interrupt_value(); +} + +enum sh_css_err +sh_css_wait_for_completion(void) +{ + enum sh_css_err err; + unsigned int irq_infos = 0; + + while (true) { + err = sh_css_hrt_sp_wait(); + if (err != sh_css_success) + return err; + /* just in case we're not using interrupts */ + sh_css_translate_interrupt(&irq_infos); + if (irq_infos & SH_CSS_IRQ_INFO_START_NEXT_STAGE) { + err = sh_css_start_next_stage(); + if (err != sh_css_success) + return err; + } else { + break; + } + } + return sh_css_success; +} + +void +sh_css_uv_offset_is_zero(bool *uv_offset_is_zero) +{ + if (uv_offset_is_zero) + *uv_offset_is_zero = SH_CSS_UV_OFFSET_IS_0; +} + +enum sh_css_err +sh_css_input_set_resolution(unsigned int width, unsigned int height) +{ + enum sh_css_err err = sh_css_success; + err = check_res(width, height); + if (err != sh_css_success) + return err; + my_css.input_width = width; + my_css.input_height = height; + return sh_css_success; +} + +enum sh_css_err +sh_css_input_set_effective_resolution(unsigned int width, unsigned int height) +{ + enum sh_css_err err = sh_css_success; + err = check_res(width, height); + if (err != sh_css_success) + return err; + my_css.input_effective_info.width = width; + my_css.input_effective_info.padded_width = width; + my_css.input_effective_info.height = height; + return sh_css_success; +} + +void +sh_css_input_set_format(enum sh_css_input_format format) +{ + my_css.input_format = format; +} + +void +sh_css_input_set_binning_factor(unsigned int binning_factor) +{ + my_css.sensor_binning = binning_factor; +} + +void +sh_css_input_set_two_pixels_per_clock(bool two_ppc) +{ + if (my_css.two_ppc != two_ppc) { + my_css.two_ppc = two_ppc; + my_css.reconfigure_css_rx = true; + } +} + +void +sh_css_input_set_bayer_order(enum sh_css_bayer_order bayer_order) +{ + my_css.bayer_order = bayer_order; +} + +int +sh_css_get_extra_pixels_count(int *extra_rows, int *extra_cols) +{ + int rows = SH_CSS_MAX_LEFT_CROPPING, + cols = SH_CSS_MAX_LEFT_CROPPING; + + if (lines_needed_for_bayer_order()) + rows += 2; + + if (columns_needed_for_bayer_order()) + cols += 2; + + *extra_rows = rows; + *extra_cols = cols; + + return 0; +} + + +void +sh_css_input_set_channel(unsigned int channel_id) +{ + my_css.ch_id = channel_id; +} + +void +sh_css_input_set_mode(enum sh_css_input_mode mode) +{ + enum sh_css_input_mode prev = my_css.input_mode; + + if (prev != mode) { + if (mode == SH_CSS_INPUT_MODE_MEMORY + || prev == SH_CSS_INPUT_MODE_MEMORY) { + /* if we switch from online to offline, we need to + reload the binary */ + invalidate_video_binaries(); + } + } + my_css.input_mode = mode; +} + +static void +init_copy_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info) +{ + *in_info = *out_info; + + copy_descr.mode = SH_CSS_BINARY_MODE_COPY; + copy_descr.online = true; + copy_descr.stream_format = my_css.input_format; + copy_descr.two_ppc = my_css.two_ppc; + copy_descr.in_info = in_info; + copy_descr.out_info = out_info; + copy_descr.vf_info = NULL; +} + +/* Bilinear interpolation on shading tables: + * For each target point T, we calculate the 4 surrounding source points: + * ul (upper left), ur (upper right), ll (lower left) and lr (lower right). + * We then calculate the distances from the T to the source points: x0, x1, + * y0 and y1. + * We then calculate the value of T: + * dx0*dy0*Slr + dx0*dy1*Sur + dx1*dy0*Sll + dx1*dy1*Sul. + * We choose a grid size of 1x1 which means: + * dx1 = 1-dx0 + * dy1 = 1-dy0 + * + * Sul dx0 dx1 Sur + * .<----->|<------------->. + * ^ + * dy0| + * v T + * - . + * ^ + * | + * dy1| + * v + * . . + * Sll Slr + * + * Padding: + * The area that the ISP operates on can include padding both on the left + * and the right. We need to padd the shading table such that the shading + * values end up on the correct pixel values. This means we must padd the + * shading table to match the ISP padding. + * We can have 5 cases: + * 1. All 4 points fall in the left padding. + * 2. The left 2 points fall in the left padding. + * 3. All 4 points fall in the cropped (target) region. + * 4. The right 2 points fall in the right padding. + * 5. All 4 points fall in the right padding. + * Cases 1 and 5 are easy to handle: we simply use the + * value 1 in the shading table. + * Cases 2 and 4 require interpolation that takes into + * account how far into the padding area the pixels + * fall. We extrapolate the shading table into the + * padded area and then interpolate. + */ +static void +crop_and_interpolate(unsigned int cropped_width, + unsigned int cropped_height, + unsigned int left_padding, + unsigned int right_padding, + struct sh_css_shading_table *out_table, + enum sh_css_sc_color color) +{ + unsigned int i, j, + sensor_width = my_css.shading_table->sensor_width, + sensor_height = my_css.shading_table->sensor_height, + table_width = my_css.shading_table->width, + table_height = my_css.shading_table->height, + out_cell_size, + in_cell_size, + out_start_row, + padded_width; + int out_start_col; /* can be negative to indicate padded space */ + unsigned short *in_ptr = my_css.shading_table->data[color], + *out_ptr = out_table->data[color]; + + padded_width = cropped_width + left_padding + right_padding; + out_cell_size = CEIL_DIV(padded_width, out_table->width - 1); + in_cell_size = CEIL_DIV(sensor_width, table_width - 1); + + out_start_col = (sensor_width - cropped_width)/2 - left_padding; + out_start_row = (sensor_height - cropped_height)/2; + + for (i = 0; i < out_table->height; i++) { + unsigned int ty, src_y0, src_y1, sy0, sy1, dy0, dy1, divy; + + /* calculate target point and make sure it falls within + the table */ + ty = out_start_row + i * out_cell_size; + ty = min(ty, sensor_height); + /* calculate closest source points in shading table and + make sure they fall within the table */ + src_y0 = ty / in_cell_size; + if (in_cell_size < out_cell_size) + src_y1 = (ty + out_cell_size) / in_cell_size; + else + src_y1 = src_y0 + 1; + src_y0 = min(src_y0, table_height-1); + src_y1 = min(src_y1, table_height-1); + /* calculate closest source points for distance computation */ + sy0 = min(src_y0 * in_cell_size, sensor_height-1); + sy1 = min(src_y1 * in_cell_size, sensor_height-1); + /* calculate distance between source and target pixels */ + dy0 = ty - sy0; + dy1 = sy1 - ty; + divy = sy1 - sy0; + if (divy == 0) { + dy0 = 1; + divy = 1; + } + + for (j = 0; j < out_table->width; j++, out_ptr++) { + int tx, src_x0, src_x1; + unsigned int sx0, sx1, dx0, dx1, divx; + unsigned short s_ul, s_ur, s_ll, s_lr; + + /* calculate target point */ + tx = out_start_col + j * out_cell_size; + /* calculate closest source points. */ + src_x0 = tx / (int)in_cell_size; + if (in_cell_size < out_cell_size) { + src_x1 = (tx + out_cell_size) / + (int)in_cell_size; + } else { + src_x1 = src_x0 + 1; + } + /* if src points fall in padding, select closest ones.*/ + src_x0 = clamp(src_x0, 0, (int)table_width-1); + src_x1 = clamp(src_x1, 0, (int)table_width-1); + tx = clamp(tx, 0, (int)sensor_width-1); + /* calculate closest source points for distance + computation */ + sx0 = min(src_x0 * in_cell_size, sensor_width-1); + sx1 = min(src_x1 * in_cell_size, sensor_width-1); + /* calculate distances between source and target + pixels */ + dx0 = tx - sx0; + dx1 = sx1 - tx; + divx = sx1 - sx0; + /* if we're at the edge, we just use the closest + point still in the grid. We make up for the divider + in this case by setting the distance to + out_cell_size, since it's actually 0. */ + if (divx == 0) { + dx0 = 1; + divx = 1; + } + + /* get source pixel values */ + s_ul = in_ptr[(table_width*src_y0)+src_x0]; + s_ur = in_ptr[(table_width*src_y0)+src_x1]; + s_ll = in_ptr[(table_width*src_y1)+src_x0]; + s_lr = in_ptr[(table_width*src_y1)+src_x1]; + + *out_ptr = (dx0*dy0*s_lr + + dx0*dy1*s_ur + + dx1*dy0*s_ll + + dx1*dy1*s_ul) / (divx*divy); + } + } +} + +static void +generate_id_shading_table(struct sh_css_shading_table **target_table, + const struct sh_css_binary *binary) +{ + /* initialize table with ones, shift becomes zero */ + unsigned int i, j, table_width, table_height; + struct sh_css_shading_table *result; + + table_width = binary->sctbl_width_per_color; + table_height = binary->sctbl_height; + result = sh_css_shading_table_alloc(table_width, table_height); + if (result == NULL) { + *target_table = NULL; + return; + } + + for (i = 0; i < SH_CSS_SC_NUM_COLORS; i++) { + for (j = 0; j < table_height * table_width; j++) + result->data[i][j] = 1; + } + result->fraction_bits = 0; + *target_table = result; +} + +static void +prepare_shading_table(struct sh_css_shading_table **target_table, + const struct sh_css_binary *binary) +{ + unsigned int input_width, + input_height, + table_width, + table_height, + left_padding, + right_padding, + i; + struct sh_css_shading_table *result; + + if (!my_css.shading_table) { + generate_id_shading_table(target_table, binary); + return; + } + + left_padding = my_css.curr_if_a_config.left_padding; + if (my_css.two_ppc) + left_padding += my_css.curr_if_a_config.left_padding; + /* We use the ISP input resolution for the shading table because + shading correction is performed in the bayer domain (before bayer + down scaling). */ + input_height = binary->in_frame_info.height; + input_width = binary->in_frame_info.width; + left_padding = binary->left_padding; + right_padding = binary->in_frame_info.padded_width - + (input_width + left_padding); + + /* We take into account the binning done by the sensor. We do this + by cropping the non-binned part of the shading table and then + increasing the size of a grid cell with this same binning factor. */ + input_width <<= my_css.sensor_binning; + input_height <<= my_css.sensor_binning; + /* We also scale the padding by the same binning factor. This will + make it much easier later on to calculate the padding of the + shading table. */ + left_padding <<= my_css.sensor_binning; + right_padding <<= my_css.sensor_binning; + + /* during simulation, the used resolution can exceed the sensor + resolution, so we clip it. */ + input_width = min(input_width, my_css.shading_table->sensor_width); + input_height = min(input_height, my_css.shading_table->sensor_height); + + table_width = binary->sctbl_width_per_color; + table_height = binary->sctbl_height; + + result = sh_css_shading_table_alloc(table_width, table_height); + if (result == NULL) { + *target_table = NULL; + return; + } + result->sensor_width = my_css.shading_table->sensor_width; + result->sensor_height = my_css.shading_table->sensor_height; + result->fraction_bits = my_css.shading_table->fraction_bits; + + /* now we crop the original shading table and then interpolate to the + requested resolution and decimation factor. */ + for (i = 0; i < SH_CSS_SC_NUM_COLORS; i++) { + crop_and_interpolate(input_width, input_height, + left_padding, right_padding, result, i); + } + *target_table = result; +} + +static void +init_offline_descr(struct sh_css_binary_descr *descr, + int mode, + struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info, + struct sh_css_frame_info *vf_info) +{ + descr->mode = mode; + descr->online = false; + descr->stream_format = my_css.input_format; + descr->two_ppc = false; + descr->in_info = in_info; + descr->out_info = out_info; + descr->vf_info = vf_info; +} + +static void +init_vf_pp_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info) +{ + in_info->raw_bit_depth = 0; + init_offline_descr(&vf_pp_descr, SH_CSS_BINARY_MODE_VF_PP, + in_info, out_info, NULL); +} + +static void +init_preview_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info) +{ + int mode = SH_CSS_BINARY_MODE_PREVIEW; + + *in_info = my_css.input_effective_info; + in_info->raw_bit_depth = + sh_css_input_format_bits_per_pixel(my_css.input_format, + my_css.two_ppc); + if (input_format_is_yuv(my_css.input_format)) + mode = SH_CSS_BINARY_MODE_COPY; + else + in_info->format = SH_CSS_FRAME_FORMAT_RAW; + + init_offline_descr(&preview_descr, mode, + in_info, out_info, NULL); + preview_descr.online = my_css.preview_settings.online; + preview_descr.stream_format = my_css.input_format; +} + +/* configure and load the copy binary, the next binary is used to + determine whether the copy binary needs to do left padding. */ +static enum sh_css_err +load_copy_binary(struct sh_css_binary *copy_binary, + struct sh_css_binary *next_binary) +{ + struct sh_css_frame_info copy_out_info, copy_in_info; + unsigned int left_padding; + enum sh_css_err err; + int mode = SH_CSS_BINARY_MODE_COPY; + + if (next_binary) { + copy_out_info = next_binary->in_frame_info; + left_padding = next_binary->left_padding; + } else { + copy_out_info = my_css.capture_settings.output_info; + left_padding = 0; + if (my_css.capture_settings.bayer_ds) + mode = SH_CSS_BINARY_MODE_BAYER_DS; + } + + init_copy_descr(©_in_info, ©_out_info); + copy_descr.mode = mode; + err = sh_css_binary_find(©_descr, copy_binary); + if (err != sh_css_success) + return err; + copy_binary->left_padding = left_padding; + return sh_css_success; +} + +static enum sh_css_err +load_preview_binaries(void) +{ + struct sh_css_frame_info prev_in_info, + prev_out_info, + ref_info; + enum sh_css_err err = sh_css_success; + bool online = my_css.preview_settings.online; + bool continuous = my_css.continuous; + unsigned int i; + + if (my_css.preview_settings.preview_binary.info && + my_css.preview_settings.vf_pp_binary.info) + return sh_css_success; + + err = check_input(false); + if (err != sh_css_success) + return err; + err = check_frame_info(&my_css.preview_settings.output_info); + if (err != sh_css_success) + return err; + + /* Preview */ + if (my_css.preview_settings.pp_input_info.width) + prev_out_info = my_css.preview_settings.pp_input_info; + else + prev_out_info = my_css.preview_settings.output_info; + sh_css_frame_info_set_format(&prev_out_info, + SH_CSS_FRAME_FORMAT_YUV_LINE); + init_preview_descr(&prev_in_info, &prev_out_info); + err = sh_css_binary_find(&preview_descr, + &my_css.preview_settings.preview_binary); + if (err != sh_css_success) + return err; + + /* Viewfinder post-processing */ + init_vf_pp_descr( + &my_css.preview_settings.preview_binary.out_frame_info, + &my_css.preview_settings.output_info); + err = sh_css_binary_find(&vf_pp_descr, + &my_css.preview_settings.vf_pp_binary); + if (err != sh_css_success) + return err; + + /* Copy */ + if (!online && !continuous) { + err = load_copy_binary(&my_css.preview_settings.copy_binary, + &my_css.preview_settings.preview_binary); + if (err != sh_css_success) + return err; + } + + ref_info = my_css.preview_settings.preview_binary.internal_frame_info; + ref_info.format = SH_CSS_FRAME_FORMAT_YUV420; + + for (i = 0; i < NUM_REF_FRAMES; i++) { + if (my_css.preview_settings.ref_frames[i]) { + sh_css_frame_free( + my_css.preview_settings.ref_frames[i]); + } + err = sh_css_frame_allocate_from_info( + &my_css.preview_settings.ref_frames[i], + &ref_info); + if (err != sh_css_success) + return err; + } + + my_css.preview_settings.prev_ref_frame = 0; + if (SH_CSS_PREVENT_UNINIT_READS) + sh_css_frame_zero(my_css.preview_settings.ref_frames[0]); + + if (!continuous) + ref_info = my_css.preview_settings.preview_binary.in_frame_info; + else + ref_info = + my_css.preview_settings.preview_binary.internal_frame_info; + ref_info.format = SH_CSS_FRAME_FORMAT_RAW; + + for (i = 0; i < NUM_CONTINUOUS_FRAMES; i++) { + if (my_css.preview_settings.continuous_frames[i]) + sh_css_frame_free( + my_css.preview_settings.continuous_frames[i]); + err = sh_css_frame_allocate_from_info( + &my_css.preview_settings.continuous_frames[i], + &ref_info); + if (err != sh_css_success) + return err; + } + + my_css.preview_settings.continuous_frame = 0; + if (SH_CSS_PREVENT_UNINIT_READS) + sh_css_frame_zero(my_css.preview_settings.continuous_frames[0]); + + if (my_css.preview_settings.shading_table) { + sh_css_shading_table_free( + my_css.preview_settings.shading_table); + my_css.preview_settings.shading_table = NULL; + } + return sh_css_success; +} + +static const struct sh_css_acc_fw * +last_output_firmware(const struct sh_css_acc_fw *fw) +{ + const struct sh_css_acc_fw *last_fw = NULL; + for (; fw; fw = fw->next) { + if (fw->header.sp.output) + last_fw = fw; + } + return last_fw; +} + +static enum sh_css_err +add_firmwares(struct sh_css_pipeline *me, + struct sh_css_binary *binary, + const struct sh_css_acc_fw *fw, + const struct sh_css_acc_fw *last_fw, + unsigned int binary_mode, + struct sh_css_frame *in_frame, + struct sh_css_frame *out_frame, + struct sh_css_frame *vf_frame, + struct sh_css_pipeline_stage **my_stage, + struct sh_css_pipeline_stage **vf_stage) +{ + enum sh_css_err err = sh_css_success; + struct sh_css_pipeline_stage *extra_stage = NULL; + for (; fw; fw = fw->next) { + struct sh_css_frame *out = NULL; + if (fw == last_fw) + out = out_frame; + err = sh_css_pipeline_add_stage(me, binary, fw, + binary_mode, NULL, + in_frame, out, + vf_frame, &extra_stage); + if (err != sh_css_success) + return err; + if (fw->header.sp.output) + in_frame = extra_stage->args.out_frame; + if (my_stage && !*my_stage && extra_stage) + *my_stage = extra_stage; + if (vf_stage && !*vf_stage && extra_stage && + fw->header.sp.out_vf) + *vf_stage = extra_stage; + } + return err; +} + +static enum sh_css_err +add_vf_pp_stage(struct sh_css_pipeline *me, + struct sh_css_frame *out_frame, + struct sh_css_binary *vf_pp_binary, + struct sh_css_pipeline_stage *post_stage, + struct sh_css_pipeline_stage **vf_pp_stage) +{ + const struct sh_css_acc_fw *last_fw; + enum sh_css_err err = sh_css_success; + struct sh_css_frame *in_frame = post_stage->args.out_vf_frame; + + *vf_pp_stage = NULL; + + if (!in_frame) + in_frame = post_stage->args.out_frame; + + last_fw = last_output_firmware(my_css.vf_stage); + if (!my_css.disable_vf_pp) { + err = sh_css_pipeline_add_stage(me, vf_pp_binary, NULL, + vf_pp_binary->info->mode, NULL, + in_frame, + last_fw ? NULL : out_frame, + NULL, vf_pp_stage); + if (err != sh_css_success) + return err; + in_frame = (*vf_pp_stage)->args.out_frame; + } + err = add_firmwares(me, vf_pp_binary, my_css.vf_stage, last_fw, + SH_CSS_BINARY_MODE_VF_PP, + in_frame, out_frame, NULL, + vf_pp_stage, NULL); + return err; +} + +static enum sh_css_err +add_capture_pp_stage(struct sh_css_pipeline *me, + struct sh_css_frame *out_frame, + struct sh_css_binary *capture_pp_binary, + struct sh_css_pipeline_stage *capture_stage, + struct sh_css_pipeline_stage **pre_vf_pp_stage) +{ + const struct sh_css_acc_fw *last_fw; + enum sh_css_err err = sh_css_success; + struct sh_css_frame *in_frame = capture_stage->args.out_frame; + struct sh_css_frame *vf_frame = NULL; + + *pre_vf_pp_stage = NULL; + + if (!in_frame) + in_frame = capture_stage->args.out_frame; + + last_fw = last_output_firmware(my_css.output_stage); + if (!my_css.disable_capture_pp && my_css.capture_settings.need_pp) { + err = sh_css_frame_allocate_from_info(&vf_frame, + &capture_pp_binary->vf_frame_info); + if (err != sh_css_success) + return err; + err = sh_css_pipeline_add_stage(me, capture_pp_binary, NULL, + capture_pp_binary->info->mode, NULL, + NULL, + last_fw ? NULL : out_frame, + vf_frame, pre_vf_pp_stage); + if (err != sh_css_success) + return err; + in_frame = (*pre_vf_pp_stage)->args.out_frame; + } + err = add_firmwares(me, capture_pp_binary, my_css.output_stage, last_fw, + SH_CSS_BINARY_MODE_CAPTURE_PP, + in_frame, out_frame, vf_frame, + NULL, pre_vf_pp_stage); + /* If a firmware produce vf_pp output, we set that as vf_pp input */ + if (*pre_vf_pp_stage) { + (*pre_vf_pp_stage)->args.extra_frame = + my_css.capture_settings.capture_pp_frame; + (*pre_vf_pp_stage)->args.vf_downscale_log2 = + capture_pp_binary->vf_downscale_log2; + } else { + *pre_vf_pp_stage = capture_stage; + } + return err; +} + + +enum sh_css_err +sh_css_preview_start(struct sh_css_frame *raw_out_frame, + struct sh_css_frame *out_frame) +{ + struct sh_css_pipeline *me = &my_css.preview_settings.pipeline; + struct sh_css_pipeline_stage *preview_stage, *copy_stage; + struct sh_css_pipeline_stage *vf_pp_stage; + struct sh_css_frame *in_frame = NULL, *in_ref_frame, *cc_frame = NULL; + struct sh_css_binary *copy_binary, *preview_binary, *vf_pp_binary; + enum sh_css_err err = sh_css_success; + + if (!out_frame) + return sh_css_err_invalid_arguments; + copy_stage = NULL; + + if (my_css.invalidate || my_css.preview_settings.zoom_changed) { + invalidate_preview_binaries(); + my_css.preview_settings.zoom_changed = false; + my_css.invalidate = false; + } + + err = load_preview_binaries(); + if (err != sh_css_success) + return err; + + err = check_infos_match(&out_frame->info, + &my_css.preview_settings.vf_pp_binary.out_frame_info); + if (err != sh_css_success) + return err; + + copy_binary = &my_css.preview_settings.copy_binary; + preview_binary = &my_css.preview_settings.preview_binary; + vf_pp_binary = &my_css.preview_settings.vf_pp_binary; + + sh_css_metrics_start_frame(); + + if (me->reload) { + struct sh_css_pipeline_stage *post_stage; + sh_css_pipeline_clean(me); + if (my_css.preview_settings.copy_binary.info) { + err = sh_css_pipeline_add_stage(me, copy_binary, NULL, + copy_binary->info->mode, + NULL, NULL, raw_out_frame, NULL, + &post_stage); + if (err != sh_css_success) + return err; + in_frame = me->stages->args.out_frame; + } else { + in_frame = my_css.preview_settings.continuous_frames + [my_css.preview_settings.continuous_frame]; + } + err = sh_css_pipeline_add_stage(me, preview_binary, NULL, + preview_binary->info->mode, + cc_frame, in_frame, NULL, NULL, + &post_stage); + if (err != sh_css_success) + return err; + /* If we use copy iso preview, the input must be yuv iso raw */ + post_stage->args.copy_vf = + preview_binary->info->mode == SH_CSS_BINARY_MODE_COPY; + post_stage->args.copy_output = !post_stage->args.copy_vf; + if (post_stage->args.copy_vf) { + /* in case of copy, use the vf frame as output frame */ + post_stage->args.out_vf_frame = + post_stage->args.out_frame; + } + + err = add_vf_pp_stage(me, out_frame, vf_pp_binary, + post_stage, &vf_pp_stage); + if (err != sh_css_success) + return err; + me->reload = false; + } else { + sh_css_pipeline_restart(me); + } + err = sh_css_config_input_network(me, copy_binary); + if (err != sh_css_success) + return err; + if (!my_css.preview_settings.shading_table) { + prepare_shading_table( + &my_css.preview_settings.shading_table, + preview_binary); + } + sh_css_params_set_shading_table(my_css.preview_settings.shading_table); + + err = sh_css_pipeline_get_output_stage(me, SH_CSS_BINARY_MODE_VF_PP, + &vf_pp_stage); + + if (err != sh_css_success) + return err; + err = sh_css_pipeline_get_stage(me, preview_binary->info->mode, + &preview_stage); + if (err != sh_css_success) + return err; + + vf_pp_stage->args.out_frame = out_frame; + + in_ref_frame = my_css.preview_settings.ref_frames + [my_css.preview_settings.prev_ref_frame]; + + /* switch the reference frame buffers */ + my_css.preview_settings.prev_ref_frame++; + if (my_css.preview_settings.prev_ref_frame == NUM_REF_FRAMES) + my_css.preview_settings.prev_ref_frame = 0; + + if (my_css.continuous) { + in_frame = my_css.preview_settings.continuous_frames + [my_css.preview_settings.continuous_frame]; + my_css.preview_settings.continuous_frame++; + if (my_css.preview_settings.continuous_frame == + NUM_CONTINUOUS_FRAMES) { + my_css.preview_settings.continuous_frame = 0; + } + cc_frame = my_css.preview_settings.continuous_frames + [my_css.preview_settings.continuous_frame]; + preview_stage->args.cc_frame = cc_frame; + preview_stage->args.in_frame = in_frame; + } + /* update the arguments with the latest info */ + preview_stage->args.in_ref_frame = in_ref_frame; + preview_stage->args.out_ref_frame = + my_css.preview_settings.ref_frames + [my_css.preview_settings.prev_ref_frame]; + + my_css.mode = sh_css_mode_preview; + return sh_css_pipeline_start_next_stage(me); +} + +enum sh_css_err +sh_css_preview_get_output_frame_info(struct sh_css_frame_info *info) +{ + enum sh_css_err err; + err = load_preview_binaries(); + if (err == sh_css_success) + *info = my_css.preview_settings.output_info; + return err; +} + +enum sh_css_err +sh_css_preview_configure_pp_input(unsigned int width, unsigned int height) +{ + enum sh_css_err err = sh_css_success; + + err = check_null_res(width, height); + if (err != sh_css_success) + return err; + + if (my_css.preview_settings.pp_input_info.width != width || + my_css.preview_settings.pp_input_info.height != height) { + sh_css_frame_info_init(&my_css.preview_settings.pp_input_info, + width, height, + SH_CSS_FRAME_FORMAT_YUV_LINE); + invalidate_preview_binaries(); + } + return sh_css_success; +} + +enum sh_css_err +sh_css_preview_get_input_resolution(unsigned int *width, + unsigned int *height) +{ + enum sh_css_err err; + err = load_preview_binaries(); + if (err == sh_css_success) { + const struct sh_css_binary *binary; + if (my_css.preview_settings.copy_binary.info) + binary = &my_css.preview_settings.copy_binary; + else + binary = &my_css.preview_settings.preview_binary; + *width = binary->in_frame_info.width + + columns_needed_for_bayer_order(); + *height = binary->in_frame_info.height + + lines_needed_for_bayer_order(); + } + return err; +} + +void +sh_css_preview_enable_online(bool enable) +{ + my_css.preview_settings.online = enable; +} + +void +sh_css_enable_continuous(bool enable) +{ + my_css.continuous = enable; +} + +bool +sh_css_continuous_is_enabled(void) +{ + return my_css.continuous; +} + +bool +sh_css_continuous_start_sp_copy(void) +{ + return my_css.start_sp_copy; +} + +void +sh_css_disable_vf_pp(bool disable) +{ + my_css.disable_vf_pp = disable; +} + +void +sh_css_disable_capture_pp(bool disable) +{ + my_css.disable_capture_pp = disable; +} + +enum sh_css_err +sh_css_preview_configure_output(unsigned int width, + unsigned int height, + enum sh_css_frame_format format) +{ + enum sh_css_err err = sh_css_success; + err = check_res(width, height); + if (err != sh_css_success) + return err; + if (my_css.preview_settings.output_info.width != width || + my_css.preview_settings.output_info.height != height || + my_css.preview_settings.output_info.format != format) { + sh_css_frame_info_init(&my_css.preview_settings.output_info, + width, height, format); + invalidate_preview_binaries(); + } + return sh_css_success; +} + +enum sh_css_err +sh_css_preview_get_grid_info(struct sh_css_grid_info *info) +{ + enum sh_css_err err; + err = load_preview_binaries(); + if (err == sh_css_success) { + err = sh_css_binary_grid_info( + &my_css.preview_settings.preview_binary, + info); + } + return err; +} + +static void +init_video_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *vf_info) +{ + int mode = SH_CSS_BINARY_MODE_VIDEO; + + if (input_format_is_yuv(my_css.input_format)) + mode = SH_CSS_BINARY_MODE_COPY; + *in_info = my_css.input_effective_info; + in_info->format = SH_CSS_FRAME_FORMAT_RAW; + in_info->raw_bit_depth = + sh_css_input_format_bits_per_pixel(my_css.input_format, + my_css.two_ppc); + init_offline_descr(&video_descr, mode, + in_info, &my_css.video_settings.output_info, + vf_info); + video_descr.online = my_css.input_mode != SH_CSS_INPUT_MODE_MEMORY; +} + +static enum sh_css_err +load_video_binaries(void) +{ + struct sh_css_frame_info video_in_info, ref_info, tnr_info, + *video_vf_info; + bool online; + enum sh_css_err err = sh_css_success; + int i; + + /* we only test the video_binary because offline video doesn't need a + * vf_pp binary. Both are always reset together anyway. + */ + if (my_css.video_settings.video_binary.info) + return sh_css_success; + online = my_css.input_mode != SH_CSS_INPUT_MODE_MEMORY; + err = check_input(!online); + if (err != sh_css_success) + return err; + if (online) { + err = check_vf_out_info(&my_css.video_settings.output_info, + &my_css.video_settings.vf_info); + } else { + err = check_frame_info(&my_css.video_settings.output_info); + } + if (err != sh_css_success) + return err; + + /* Video */ + if (online) + video_vf_info = &my_css.video_settings.vf_info; + else + video_vf_info = NULL; + init_video_descr(&video_in_info, video_vf_info); + err = sh_css_binary_find(&video_descr, + &my_css.video_settings.video_binary); + if (err != sh_css_success) + return err; + + /* Viewfinder post-processing */ + if (online) { + init_vf_pp_descr( + &my_css.video_settings.video_binary.vf_frame_info, + &my_css.video_settings.vf_info); + err = sh_css_binary_find(&vf_pp_descr, + &my_css.video_settings.vf_pp_binary); + if (err != sh_css_success) + return err; + } + + /* yuv copy does not use reference frames */ + if (input_format_is_yuv(my_css.input_format)) + return sh_css_success; + + ref_info = my_css.video_settings.video_binary.internal_frame_info; + ref_info.format = SH_CSS_FRAME_FORMAT_YUV420; + + for (i = 0; i < NUM_REF_FRAMES; i++) { + if (my_css.video_settings.ref_frames[i]) + sh_css_frame_free(my_css.video_settings.ref_frames[i]); + err = sh_css_frame_allocate_from_info( + &my_css.video_settings.ref_frames[i], + &ref_info); + if (err != sh_css_success) + return err; + } + my_css.video_settings.prev_ref_frame = 0; + if (SH_CSS_PREVENT_UNINIT_READS) + sh_css_frame_zero(my_css.video_settings.ref_frames[0]); + + tnr_info = my_css.video_settings.video_binary.internal_frame_info; + tnr_info.format = SH_CSS_FRAME_FORMAT_YUV420; + + for (i = 0; i < NUM_TNR_FRAMES; i++) { + if (my_css.video_settings.tnr_frames[i]) + sh_css_frame_free(my_css.video_settings.tnr_frames[i]); + err = sh_css_frame_allocate_from_info( + &my_css.video_settings.tnr_frames[i], + &tnr_info); + if (err != sh_css_success) + return err; + } + my_css.video_settings.prev_tnr_frame = 0; + if (SH_CSS_PREVENT_UNINIT_READS) { + sh_css_frame_zero(my_css.video_settings.tnr_frames[0]); + sh_css_frame_zero(my_css.video_settings.tnr_frames[1]); + } + + return sh_css_success; +} + +enum sh_css_err +sh_css_video_start(struct sh_css_frame *in_frame, + struct sh_css_frame *out_frame, + struct sh_css_frame *vf_frame) +{ + struct sh_css_pipeline *me = &my_css.video_settings.pipeline; + struct sh_css_pipeline_stage *video_stage, *vf_pp_stage; + struct sh_css_frame *in_ref_frame, *in_tnr_frame; + struct sh_css_binary *video_binary, *vf_pp_binary; + enum sh_css_err err = sh_css_success; + + if (!out_frame) + return sh_css_err_invalid_arguments; + if (my_css.invalidate || my_css.video_settings.zoom_changed) { + invalidate_video_binaries(); + my_css.video_settings.zoom_changed = false; + my_css.invalidate = false; + } + + err = load_video_binaries(); + if (err != sh_css_success) + return err; + video_binary = &my_css.video_settings.video_binary; + vf_pp_binary = &my_css.video_settings.vf_pp_binary; + if (in_frame) { + if (vf_frame) + return sh_css_err_mode_does_not_have_viewfinder; + } else { + if (!vf_frame) + return sh_css_err_invalid_arguments; + err = check_infos_match(&vf_frame->info, + &my_css.video_settings.vf_pp_binary.out_frame_info); + if (err != sh_css_success) + return err; + } + err = check_infos_match(&out_frame->info, + &my_css.video_settings.video_binary.out_frame_info); + if (err != sh_css_success) + return err; + + sh_css_metrics_start_frame(); + + if (me->reload) { + sh_css_pipeline_clean(me); + err = sh_css_pipeline_add_stage(me, video_binary, NULL, + video_binary->info->mode, NULL, + in_frame, out_frame, NULL, + &video_stage); + if (err != sh_css_success) + return err; + /* If we use copy iso video, the input must be yuv iso raw */ + video_stage->args.copy_vf = + video_binary->info->mode == SH_CSS_BINARY_MODE_COPY; + video_stage->args.copy_output = video_stage->args.copy_vf; + if (!in_frame) { + err = add_vf_pp_stage(me, vf_frame, vf_pp_binary, + video_stage, &vf_pp_stage); + if (err != sh_css_success) + return err; + } + me->reload = false; + } else { + sh_css_pipeline_restart(me); + } + err = sh_css_config_input_network(me, NULL); + if (err != sh_css_success) + return err; + if (!my_css.video_settings.shading_table) { + prepare_shading_table( + &my_css.video_settings.shading_table, + video_binary); + } + sh_css_params_set_shading_table(my_css.video_settings.shading_table); + + err = sh_css_pipeline_get_stage(me, video_binary->info->mode, + &video_stage); + if (err != sh_css_success) + return err; + if (!in_frame) { + err = sh_css_pipeline_get_output_stage(me, + vf_pp_binary->info->mode, + &vf_pp_stage); + if (err != sh_css_success) + return err; + } + + in_ref_frame = my_css.video_settings.ref_frames + [my_css.video_settings.prev_ref_frame]; + /* switch the reference frame buffers */ + my_css.video_settings.prev_ref_frame++; + if (my_css.video_settings.prev_ref_frame == NUM_VIDEO_REF_FRAMES) + my_css.video_settings.prev_ref_frame = 0; + + in_tnr_frame = my_css.video_settings.tnr_frames + [my_css.video_settings.prev_tnr_frame]; + /* switch the tnr frame buffers */ + my_css.video_settings.prev_tnr_frame++; + if (my_css.video_settings.prev_tnr_frame == NUM_VIDEO_TNR_FRAMES) + my_css.video_settings.prev_tnr_frame = 0; + + /* update the arguments with the latest info */ + video_stage->args.in_ref_frame = in_ref_frame; + video_stage->args.in_tnr_frame = in_tnr_frame; + video_stage->args.out_frame = out_frame; + video_stage->args.out_ref_frame = + my_css.video_settings.ref_frames + [my_css.video_settings.prev_ref_frame]; + video_stage->args.out_tnr_frame = + my_css.video_settings.tnr_frames + [my_css.video_settings.prev_tnr_frame]; + video_stage->args.dvs_vector_x = my_css.video_settings.dvs_vector_x; + video_stage->args.dvs_vector_y = my_css.video_settings.dvs_vector_y; + if (!in_frame) + vf_pp_stage->args.out_frame = vf_frame; + + my_css.mode = sh_css_mode_video; + return sh_css_pipeline_start_next_stage(me); +} + +enum sh_css_err +sh_css_video_get_output_frame_info(struct sh_css_frame_info *info) +{ + enum sh_css_err err; + + err = load_video_binaries(); + if (err == sh_css_success) + *info = my_css.video_settings.output_info; + return err; +} + +enum sh_css_err +sh_css_video_get_viewfinder_frame_info(struct sh_css_frame_info *info) +{ + enum sh_css_err err; + + err = load_video_binaries(); + if (err != sh_css_success) + return err; + /* offline video does not generate viewfinder output */ + if (my_css.input_mode == SH_CSS_INPUT_MODE_MEMORY) + return sh_css_err_mode_does_not_have_viewfinder; + else + *info = my_css.video_settings.vf_info; + return sh_css_success; +} + +enum sh_css_err +sh_css_video_get_grid_info(struct sh_css_grid_info *info) +{ + enum sh_css_err err; + + err = load_video_binaries(); + if (err != sh_css_success) + return err; + err = sh_css_binary_grid_info(&my_css.video_settings.video_binary, + info); + return err; +} + +enum sh_css_err +sh_css_video_get_input_resolution(unsigned int *width, unsigned int *height) +{ + enum sh_css_err err; + + err = load_video_binaries(); + if (err == sh_css_success) { + const struct sh_css_binary *binary; + binary = &my_css.video_settings.video_binary; + *width = binary->in_frame_info.width + + columns_needed_for_bayer_order(); + *height = binary->in_frame_info.height + + lines_needed_for_bayer_order(); + } + + return err; +} + +enum sh_css_err +sh_css_video_configure_output(unsigned int width, + unsigned int height, + enum sh_css_frame_format format) +{ + enum sh_css_err err = sh_css_success; + err = check_res(width, height); + if (err != sh_css_success) + return err; + if (my_css.video_settings.output_info.width != width || + my_css.video_settings.output_info.height != height || + my_css.video_settings.output_info.format != format) { + sh_css_frame_info_init(&my_css.video_settings.output_info, + width, height, format); + invalidate_video_binaries(); + } + return sh_css_success; +} + +enum sh_css_err +sh_css_video_configure_viewfinder(unsigned int width, + unsigned int height, + enum sh_css_frame_format format) +{ + enum sh_css_err err = sh_css_success; + err = check_res(width, height); + if (err != sh_css_success) + return err; + if (my_css.video_settings.vf_info.width != width || + my_css.video_settings.vf_info.height != height || + my_css.video_settings.vf_info.format != format) { + sh_css_frame_info_init(&my_css.video_settings.vf_info, + width, height, format); + invalidate_video_binaries(); + } + return sh_css_success; +} + +void +sh_css_video_set_dis_vector(int x, int y) +{ + my_css.video_settings.dvs_vector_x = x; + my_css.video_settings.dvs_vector_y = y; +} + +/* Specify the envelope to be used for DIS. */ +void +sh_css_video_set_dis_envelope(unsigned int width, unsigned int height) +{ + if (width != my_css.video_settings.dvs_envelope_width || + height != my_css.video_settings.dvs_envelope_height) { + my_css.video_settings.dvs_envelope_width = width; + my_css.video_settings.dvs_envelope_height = height; + invalidate_video_binaries(); + } +} + +void +sh_css_video_get_dis_envelope(unsigned int *width, unsigned int *height) +{ + *width = my_css.video_settings.dvs_envelope_width; + *height = my_css.video_settings.dvs_envelope_height; +} + +void +sh_css_set_zoom_factor(unsigned int dx, unsigned int dy) +{ + bool is_zoomed = (dx < 64) || (dy < 64); + bool was_zoomed = (my_css.curr_dx < 64) || (my_css.curr_dy < 64); + + if (is_zoomed != was_zoomed) { + /* for with/without zoom, we use different binaries */ + my_css.video_settings.zoom_changed = true; + my_css.preview_settings.zoom_changed = true; + my_css.capture_settings.zoom_changed = true; + } + my_css.curr_dx = dx; + my_css.curr_dy = dy; +} + +void +sh_css_get_zoom_factor(unsigned int *dx, unsigned int *dy) +{ + *dx = my_css.curr_dx; + *dy = my_css.curr_dy; +} + +static enum sh_css_err +load_copy_binaries(void) +{ + enum sh_css_err err = sh_css_success; + + if (my_css.capture_settings.copy_binary.info) + return sh_css_success; + + err = check_frame_info(&my_css.capture_settings.output_info); + if (err != sh_css_success) + return err; + + get_copy_out_frame_format(&my_css.capture_settings.output_info.format); + return load_copy_binary(&my_css.capture_settings.copy_binary, NULL); +} + +static bool +need_capture_pp(void) +{ + /* determine whether we need to use the capture_pp binary. + * This is needed for: + * 1. XNR or + * 2. Digital Zoom or + * 3. YUV downscaling + */ + if (my_css.capture_settings.pp_input_info.width && + ((my_css.capture_settings.pp_input_info.width != + my_css.capture_settings.output_info.width) || + (my_css.capture_settings.pp_input_info.height != + my_css.capture_settings.output_info.height))) + return true; + if (my_css.capture_settings.xnr) + return true; + if (my_css.curr_dx < 64 || my_css.curr_dy < 64) + return true; + return false; +} + +static void +init_capture_pp_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *vf_info) +{ + /* the in_info is only used for resolution to enable + bayer down scaling. */ + if (my_css.capture_settings.pp_input_info.width) + *in_info = my_css.capture_settings.pp_input_info; + else + *in_info = my_css.capture_settings.output_info; + in_info->format = SH_CSS_FRAME_FORMAT_YUV420; + in_info->raw_bit_depth = 0; + sh_css_frame_info_set_width(in_info, in_info->width); + init_offline_descr(&capture_pp_descr, SH_CSS_BINARY_MODE_CAPTURE_PP, + in_info, &my_css.capture_settings.output_info, + vf_info); +} + +static void +init_primary_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info, + struct sh_css_frame_info *vf_info) +{ + int mode = SH_CSS_BINARY_MODE_PRIMARY; + + if (input_format_is_yuv(my_css.input_format)) + mode = SH_CSS_BINARY_MODE_COPY; + + *in_info = my_css.input_effective_info; + in_info->format = SH_CSS_FRAME_FORMAT_RAW; + in_info->raw_bit_depth = + sh_css_input_format_bits_per_pixel(my_css.input_format, + my_css.two_ppc); + init_offline_descr(&prim_descr, mode, + in_info, out_info, vf_info); + if (my_css.capture_settings.online) { + prim_descr.online = true; + prim_descr.stream_format = my_css.input_format; + } +} + +static void +init_pre_gdc_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info) +{ + *in_info = *out_info; + in_info->format = SH_CSS_FRAME_FORMAT_RAW; + in_info->raw_bit_depth = + sh_css_input_format_bits_per_pixel(my_css.input_format, + my_css.two_ppc); + init_offline_descr(&pre_gdc_descr, SH_CSS_BINARY_MODE_PRE_GDC, + in_info, out_info, NULL); +} + +static void +init_gdc_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info) +{ + *in_info = *out_info; + in_info->format = SH_CSS_FRAME_FORMAT_QPLANE6; + init_offline_descr(&gdc_descr, SH_CSS_BINARY_MODE_GDC, + in_info, out_info, NULL); +} + +static void +init_post_gdc_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info, + struct sh_css_frame_info *vf_info) +{ + *in_info = *out_info; + in_info->format = SH_CSS_FRAME_FORMAT_YUV420_16; + init_offline_descr(&post_gdc_descr, SH_CSS_BINARY_MODE_POST_GDC, + in_info, out_info, vf_info); +} + +static void +init_pre_anr_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info) +{ + *in_info = *out_info; + in_info->format = SH_CSS_FRAME_FORMAT_RAW; + in_info->raw_bit_depth = + sh_css_input_format_bits_per_pixel(my_css.input_format, + my_css.two_ppc); + init_offline_descr(&pre_anr_descr, SH_CSS_BINARY_MODE_PRE_ANR, + in_info, out_info, NULL); +} + +static void +init_anr_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info) +{ + *in_info = *out_info; + in_info->format = SH_CSS_FRAME_FORMAT_RAW; + in_info->raw_bit_depth = + sh_css_input_format_bits_per_pixel(my_css.input_format, + my_css.two_ppc); + init_offline_descr(&anr_descr, SH_CSS_BINARY_MODE_ANR, + in_info, out_info, NULL); +} + +static void +init_post_anr_descr(struct sh_css_frame_info *in_info, + struct sh_css_frame_info *out_info, + struct sh_css_frame_info *vf_info) +{ + *in_info = *out_info; + in_info->format = SH_CSS_FRAME_FORMAT_RAW; + in_info->raw_bit_depth = + sh_css_input_format_bits_per_pixel(my_css.input_format, + my_css.two_ppc); + init_offline_descr(&post_anr_descr, SH_CSS_BINARY_MODE_POST_ANR, + in_info, out_info, vf_info); +} + +static enum sh_css_err +load_primary_binaries(void) +{ + bool online = my_css.capture_settings.online; + bool continuous = my_css.continuous; + bool need_pp = false; + struct sh_css_frame_info prim_in_info, + prim_out_info, vf_info, + *vf_pp_in_info; + enum sh_css_err err = sh_css_success; + + if (my_css.capture_settings.primary_binary.info) + return sh_css_success; + + err = check_vf_out_info(&my_css.capture_settings.output_info, + &my_css.capture_settings.vf_info); + if (err != sh_css_success) + return err; + need_pp = need_capture_pp(); + + /* we use the vf output info to get the primary/capture_pp binary + configured for vf_veceven. It will select the closest downscaling + factor. */ + vf_info = my_css.capture_settings.vf_info; + sh_css_frame_info_set_format(&vf_info, + SH_CSS_FRAME_FORMAT_YUV_LINE); + + /* we build up the pipeline starting at the end */ + /* Capture post-processing */ + my_css.capture_settings.need_pp = need_pp; + if (need_pp) { + init_capture_pp_descr(&prim_out_info, &vf_info); + err = sh_css_binary_find(&capture_pp_descr, + &my_css.capture_settings.capture_pp_binary); + if (err != sh_css_success) + return err; + } else { + prim_out_info = my_css.capture_settings.output_info; + } + + /* Primary */ + init_primary_descr(&prim_in_info, &prim_out_info, &vf_info); + err = sh_css_binary_find(&prim_descr, + &my_css.capture_settings.primary_binary); + if (err != sh_css_success) + return err; + + /* Viewfinder post-processing */ + if (need_pp) { + vf_pp_in_info = + &my_css.capture_settings.capture_pp_binary.vf_frame_info; + } else { + vf_pp_in_info = + &my_css.capture_settings.primary_binary.vf_frame_info; + } + + init_vf_pp_descr(vf_pp_in_info, &my_css.capture_settings.vf_info); + err = sh_css_binary_find(&vf_pp_descr, + &my_css.capture_settings.vf_pp_binary); + if (err != sh_css_success) + return err; + + /* Copy */ + if (!online && !continuous) { + err = load_copy_binary(&my_css.capture_settings.copy_binary, + &my_css.capture_settings.primary_binary); + if (err != sh_css_success) + return err; + } + + if (need_pp) + return alloc_capture_pp_frame( + &my_css.capture_settings.capture_pp_binary); + else + return sh_css_success; +} + +static enum sh_css_err +load_advanced_binaries(void) +{ + struct sh_css_frame_info pre_in_info, gdc_in_info, + post_in_info, post_out_info, + vf_info, *vf_pp_in_info; + bool need_pp; + enum sh_css_err err = sh_css_success; + + if (my_css.capture_settings.pre_gdc_binary.info) + return sh_css_success; + + err = check_vf_out_info(&my_css.capture_settings.output_info, + &my_css.capture_settings.vf_info); + if (err != sh_css_success) + return err; + need_pp = need_capture_pp(); + + vf_info = my_css.capture_settings.vf_info; + sh_css_frame_info_set_format(&vf_info, + SH_CSS_FRAME_FORMAT_YUV_LINE); + + /* we build up the pipeline starting at the end */ + /* Capture post-processing */ + my_css.capture_settings.need_pp = need_pp; + if (need_pp) { + init_capture_pp_descr(&post_out_info, &vf_info); + err = sh_css_binary_find(&capture_pp_descr, + &my_css.capture_settings.capture_pp_binary); + if (err != sh_css_success) + return err; + } else { + post_out_info = my_css.capture_settings.output_info; + } + + /* Post-gdc */ + init_post_gdc_descr(&post_in_info, &post_out_info, &vf_info); + err = sh_css_binary_find(&post_gdc_descr, + &my_css.capture_settings.post_gdc_binary); + if (err != sh_css_success) + return err; + + /* Gdc */ + init_gdc_descr(&gdc_in_info, + &my_css.capture_settings.post_gdc_binary.in_frame_info); + err = sh_css_binary_find(&gdc_descr, + &my_css.capture_settings.gdc_binary); + if (err != sh_css_success) + return err; + my_css.capture_settings.gdc_binary.left_padding = + my_css.capture_settings.post_gdc_binary.left_padding; + + /* Pre-gdc */ + init_pre_gdc_descr(&pre_in_info, + &my_css.capture_settings.gdc_binary.in_frame_info); + err = sh_css_binary_find(&pre_gdc_descr, + &my_css.capture_settings.pre_gdc_binary); + if (err != sh_css_success) + return err; + my_css.capture_settings.pre_gdc_binary.left_padding = + my_css.capture_settings.gdc_binary.left_padding; + + /* Viewfinder post-processing */ + if (need_pp) { + vf_pp_in_info = + &my_css.capture_settings.capture_pp_binary.vf_frame_info; + } else { + vf_pp_in_info = + &my_css.capture_settings.post_gdc_binary.vf_frame_info; + } + + init_vf_pp_descr(vf_pp_in_info, &my_css.capture_settings.vf_info); + err = sh_css_binary_find(&vf_pp_descr, + &my_css.capture_settings.vf_pp_binary); + if (err != sh_css_success) + return err; + + /* Copy */ + err = load_copy_binary(&my_css.capture_settings.copy_binary, + &my_css.capture_settings.pre_gdc_binary); + if (err != sh_css_success) + return err; + + if (need_pp) + return alloc_capture_pp_frame( + &my_css.capture_settings.capture_pp_binary); + else + return sh_css_success; +} + +static enum sh_css_err +load_low_light_binaries(void) +{ + struct sh_css_frame_info pre_in_info, anr_in_info, + post_in_info, post_out_info, + vf_info, *vf_pp_in_info; + bool need_pp; + enum sh_css_err err = sh_css_success; + + if (my_css.capture_settings.pre_anr_binary.info) + return sh_css_success; + + err = check_vf_out_info(&my_css.capture_settings.output_info, + &my_css.capture_settings.vf_info); + if (err != sh_css_success) + return err; + need_pp = need_capture_pp(); + + vf_info = my_css.capture_settings.vf_info; + sh_css_frame_info_set_format(&vf_info, + SH_CSS_FRAME_FORMAT_YUV_LINE); + + /* we build up the pipeline starting at the end */ + /* Capture post-processing */ + my_css.capture_settings.need_pp = need_pp; + if (need_pp) { + init_capture_pp_descr(&post_out_info, &vf_info); + err = sh_css_binary_find(&capture_pp_descr, + &my_css.capture_settings.capture_pp_binary); + if (err != sh_css_success) + return err; + } else { + post_out_info = my_css.capture_settings.output_info; + } + + /* Post-anr */ + init_post_anr_descr(&post_in_info, &post_out_info, &vf_info); + err = sh_css_binary_find(&post_anr_descr, + &my_css.capture_settings.post_anr_binary); + if (err != sh_css_success) + return err; + + /* Anr */ + init_anr_descr(&anr_in_info, + &my_css.capture_settings.post_anr_binary.in_frame_info); + err = sh_css_binary_find(&anr_descr, + &my_css.capture_settings.anr_binary); + if (err != sh_css_success) + return err; + my_css.capture_settings.anr_binary.left_padding = + my_css.capture_settings.post_anr_binary.left_padding; + + /* Pre-anr */ + init_pre_anr_descr(&pre_in_info, + &my_css.capture_settings.anr_binary.in_frame_info); + err = sh_css_binary_find(&pre_anr_descr, + &my_css.capture_settings.pre_anr_binary); + if (err != sh_css_success) + return err; + my_css.capture_settings.pre_anr_binary.left_padding = + my_css.capture_settings.anr_binary.left_padding; + + /* Viewfinder post-processing */ + if (need_pp) { + vf_pp_in_info = + &my_css.capture_settings.capture_pp_binary.vf_frame_info; + } else { + vf_pp_in_info = + &my_css.capture_settings.post_anr_binary.vf_frame_info; + } + + init_vf_pp_descr(vf_pp_in_info, &my_css.capture_settings.vf_info); + err = sh_css_binary_find(&vf_pp_descr, + &my_css.capture_settings.vf_pp_binary); + if (err != sh_css_success) + return err; + + /* Copy */ + err = load_copy_binary(&my_css.capture_settings.copy_binary, + &my_css.capture_settings.pre_anr_binary); + if (err != sh_css_success) + return err; + + if (need_pp) + return alloc_capture_pp_frame( + &my_css.capture_settings.capture_pp_binary); + else + return sh_css_success; +} + +static bool +copy_on_sp(void) +{ + if (my_css.capture_settings.mode != SH_CSS_CAPTURE_MODE_RAW) + return false; + return my_css.continuous || + my_css.input_format == SH_CSS_INPUT_FORMAT_BINARY_8; +} + +static enum sh_css_err +load_capture_binaries(void) +{ + enum sh_css_err err = sh_css_success; + bool must_be_raw; + + /* in primary, advanced or low light, the input format must be raw */ + must_be_raw = + my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_ADVANCED || + my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_LOW_LIGHT; + err = check_input(must_be_raw); + if (err != sh_css_success) + return err; + if (copy_on_sp()) { + /* this is handled by the SP, no ISP binaries needed. */ + if (my_css.input_format == SH_CSS_INPUT_FORMAT_BINARY_8) { + sh_css_frame_info_init( + &my_css.capture_settings.output_info, + JPEG_BYTES, 1, SH_CSS_FRAME_FORMAT_BINARY_8); + return sh_css_success; + } + } + + switch (my_css.capture_settings.mode) { + case SH_CSS_CAPTURE_MODE_RAW: + return load_copy_binaries(); + case SH_CSS_CAPTURE_MODE_PRIMARY: + return load_primary_binaries(); + case SH_CSS_CAPTURE_MODE_ADVANCED: + return load_advanced_binaries(); + case SH_CSS_CAPTURE_MODE_LOW_LIGHT: + return load_low_light_binaries(); + } + return sh_css_success; +} + +enum sh_css_err +sh_css_capture_start(struct sh_css_frame *raw_out_frame, + struct sh_css_frame *out_frame, + struct sh_css_frame *vf_frame) +{ + bool raw = my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_RAW; + struct sh_css_pipeline *me = &my_css.capture_settings.pipeline; + struct sh_css_pipeline_stage *out_stage, *vf_pp_stage, *copy_stage; + struct sh_css_binary *copy_binary, + *primary_binary, + *vf_pp_binary, + *pre_gdc_binary, + *gdc_binary, + *post_gdc_binary, + *pre_anr_binary, + *anr_binary, + *post_anr_binary, + *capture_pp_binary, + *sc_binary = NULL; + bool need_pp = false; + enum sh_css_err err = sh_css_success; + bool raw_copy = my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_RAW + && copy_on_sp(); + + if (!out_frame) + return sh_css_err_invalid_arguments; + copy_stage = NULL; + + if (my_css.invalidate || my_css.capture_settings.zoom_changed) { + invalidate_capture_binaries(); + my_css.capture_settings.zoom_changed = false; + my_css.invalidate = false; + } + + err = load_capture_binaries(); + if (err != sh_css_success) + return err; + + err = check_infos_match(&out_frame->info, + &my_css.capture_settings.output_info); + if (err != sh_css_success) + return err; + if (my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_RAW && vf_frame) + return sh_css_err_mode_does_not_have_viewfinder; + + if (vf_frame) { + err = check_infos_match(&vf_frame->info, + &my_css.capture_settings.vf_info); + if (err != sh_css_success) + return err; + } + + copy_binary = &my_css.capture_settings.copy_binary; + primary_binary = &my_css.capture_settings.primary_binary; + vf_pp_binary = &my_css.capture_settings.vf_pp_binary; + pre_gdc_binary = &my_css.capture_settings.pre_gdc_binary; + gdc_binary = &my_css.capture_settings.gdc_binary; + post_gdc_binary = &my_css.capture_settings.post_gdc_binary; + pre_anr_binary = &my_css.capture_settings.pre_anr_binary; + anr_binary = &my_css.capture_settings.anr_binary; + post_anr_binary = &my_css.capture_settings.post_anr_binary; + capture_pp_binary = &my_css.capture_settings.capture_pp_binary; + need_pp = my_css.capture_settings.need_pp || my_css.output_stage; + + sh_css_metrics_start_frame(); + + if (me->reload) { + struct sh_css_pipeline_stage *post_stage; + sh_css_pipeline_clean(me); + if (my_css.capture_settings.copy_binary.info && !raw_copy) { + err = sh_css_pipeline_add_stage(me, copy_binary, NULL, + copy_binary->info->mode, NULL, NULL, + raw ? out_frame : raw_out_frame, + NULL, &post_stage); + if (err != sh_css_success) + return err; + } + if (my_css.capture_settings.mode == + SH_CSS_CAPTURE_MODE_PRIMARY) { + err = sh_css_pipeline_add_stage(me, primary_binary, + NULL, primary_binary->info->mode, + NULL, NULL, + need_pp ? NULL : out_frame, + NULL, &post_stage); + if (err != sh_css_success) + return err; + /* If we use copy iso primary, + the input must be yuv iso raw */ + post_stage->args.copy_vf = + primary_binary->info->mode == + SH_CSS_BINARY_MODE_COPY; + post_stage->args.copy_output = post_stage->args.copy_vf; + sc_binary = primary_binary; + } else if (my_css.capture_settings.mode == + SH_CSS_CAPTURE_MODE_ADVANCED) { + err = sh_css_pipeline_add_stage(me, pre_gdc_binary, + NULL, pre_gdc_binary->info->mode, + NULL, NULL, NULL, NULL, NULL); + if (err != sh_css_success) + return err; + err = sh_css_pipeline_add_stage(me, gdc_binary, + NULL, gdc_binary->info->mode, + NULL, NULL, NULL, NULL, NULL); + if (err != sh_css_success) + return err; + err = sh_css_pipeline_add_stage(me, post_gdc_binary, + NULL, post_gdc_binary->info->mode, + NULL, NULL, + need_pp ? NULL : out_frame, + NULL, &post_stage); + if (err != sh_css_success) + return err; + sc_binary = pre_gdc_binary; + } else if (my_css.capture_settings.mode == + SH_CSS_CAPTURE_MODE_LOW_LIGHT) { + err = sh_css_pipeline_add_stage(me, pre_anr_binary, + NULL, pre_anr_binary->info->mode, + NULL, NULL, NULL, NULL, NULL); + if (err != sh_css_success) + return err; + err = sh_css_pipeline_add_stage(me, anr_binary, + NULL, anr_binary->info->mode, + NULL, NULL, NULL, NULL, NULL); + if (err != sh_css_success) + return err; + err = sh_css_pipeline_add_stage(me, post_anr_binary, + NULL, post_anr_binary->info->mode, + NULL, NULL, + need_pp ? NULL : out_frame, + NULL, &post_stage); + if (err != sh_css_success) + return err; + sc_binary = pre_anr_binary; + } + + if (need_pp) { + err = add_capture_pp_stage(me, out_frame, + capture_pp_binary, + post_stage, &post_stage); + if (err != sh_css_success) + return err; + } + if (my_css.capture_settings.mode != SH_CSS_CAPTURE_MODE_RAW) { + err = add_vf_pp_stage(me, vf_frame, vf_pp_binary, + post_stage, &vf_pp_stage); + if (err != sh_css_success) + return err; + } + me->reload = false; + } else { + sh_css_pipeline_restart(me); + } + + err = sh_css_config_input_network(me, copy_binary); + if (err != sh_css_success) + return err; + if (!my_css.capture_settings.shading_table && sc_binary) { + prepare_shading_table( + &my_css.capture_settings.shading_table, + sc_binary); + } + sh_css_params_set_shading_table(my_css.capture_settings.shading_table); + + if (my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_RAW) { + if (copy_on_sp()) { + my_css.mode = sh_css_mode_capture; + my_css.state = sh_css_state_executing_sp_bin_copy; + return start_copy_on_sp(copy_binary, out_frame); + } + } else { + if (!vf_frame) + return sh_css_err_invalid_arguments; + } + if (err != sh_css_success) + return err; + + if (my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_RAW) { + err = sh_css_pipeline_get_stage(me, copy_binary->info->mode, + &out_stage); + if (err != sh_css_success) + return err; + copy_stage = out_stage; + } else { + if (copy_binary->info) { + err = sh_css_pipeline_get_stage(me, + copy_binary->info->mode, + ©_stage); + if (err != sh_css_success) + return err; + } + if (capture_pp_binary->info) { + err = sh_css_pipeline_get_stage(me, + capture_pp_binary->info->mode, + &out_stage); + if (err != sh_css_success) + return err; + } else if (my_css.capture_settings.mode == + SH_CSS_CAPTURE_MODE_PRIMARY) { + err = sh_css_pipeline_get_stage(me, + primary_binary->info->mode, &out_stage); + if (err != sh_css_success) + return err; + } else if (my_css.capture_settings.mode == + SH_CSS_CAPTURE_MODE_LOW_LIGHT) { + err = sh_css_pipeline_get_stage(me, + post_anr_binary->info->mode, + &out_stage); + if (err != sh_css_success) + return err; + } else { + err = sh_css_pipeline_get_stage(me, + post_gdc_binary->info->mode, + &out_stage); + if (err != sh_css_success) + return err; + } + err = sh_css_pipeline_get_output_stage(me, + vf_pp_binary->info->mode, + &vf_pp_stage); + if (err != sh_css_success) + return err; + } + if (my_css.capture_settings.mode != SH_CSS_CAPTURE_MODE_RAW) + vf_pp_stage->args.out_frame = vf_frame; + + if (!my_css.output_stage) + out_stage->args.out_frame = out_frame; + + if (copy_stage && raw_out_frame) + copy_stage->args.out_frame = raw_out_frame; + my_css.mode = sh_css_mode_capture; + return sh_css_pipeline_start_next_stage(me); +} + +enum sh_css_err +sh_css_capture_get_output_frame_info(struct sh_css_frame_info *info) +{ + enum sh_css_err err; + + err = load_capture_binaries(); + if (err != sh_css_success) + return err; + + if (copy_on_sp() && + my_css.input_format == SH_CSS_INPUT_FORMAT_BINARY_8) { + sh_css_frame_info_init(info, JPEG_BYTES, 1, + SH_CSS_FRAME_FORMAT_BINARY_8); + } else { + *info = my_css.capture_settings.output_info; + if (info->format == SH_CSS_FRAME_FORMAT_RAW) + info->raw_bit_depth = + sh_css_input_format_bits_per_pixel( + my_css.input_format, + my_css.two_ppc); + } + return sh_css_success; +} + +enum sh_css_err +sh_css_capture_get_viewfinder_frame_info(struct sh_css_frame_info *info) +{ + enum sh_css_err err; + + if (my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_RAW) + return sh_css_err_mode_does_not_have_viewfinder; + err = load_capture_binaries(); + if (err == sh_css_success) + *info = my_css.capture_settings.vf_info; + return err; +} + +enum sh_css_err +sh_css_capture_get_output_raw_frame_info(struct sh_css_frame_info *info) +{ + enum sh_css_err err; + + if (my_css.capture_settings.online || + copy_on_sp()) { + return sh_css_err_mode_does_not_have_raw_output; + } + err = load_capture_binaries(); + if (err == sh_css_success) + *info = my_css.capture_settings.copy_binary.out_frame_info; + return err; +} + +enum sh_css_err +sh_css_capture_get_grid_info(struct sh_css_grid_info *info) +{ + enum sh_css_err err; + + if (my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_RAW) + return sh_css_err_mode_does_not_have_grid; + err = load_capture_binaries(); + if (err != sh_css_success) + return err; + if (my_css.capture_settings.mode == SH_CSS_CAPTURE_MODE_PRIMARY) { + err = sh_css_binary_grid_info( + &my_css.capture_settings.primary_binary, info); + } else { + err = sh_css_binary_grid_info( + &my_css.capture_settings.pre_gdc_binary, info); + } + return err; +} + +enum sh_css_err +sh_css_capture_get_input_resolution(unsigned int *width, unsigned int *height) +{ + enum sh_css_err err; + + if (copy_on_sp() && + my_css.input_format == SH_CSS_INPUT_FORMAT_BINARY_8) { + *width = JPEG_BYTES; + *height = 1; + return sh_css_success; + } + + err = load_capture_binaries(); + if (err == sh_css_success) { + const struct sh_css_binary *binary; + if (my_css.capture_settings.copy_binary.info) + binary = &my_css.capture_settings.copy_binary; + else + binary = &my_css.capture_settings.primary_binary; + *width = binary->in_frame_info.width + + columns_needed_for_bayer_order(); + *height = binary->in_frame_info.height + + lines_needed_for_bayer_order(); + } + return err; +} + +void +sh_css_capture_set_mode(enum sh_css_capture_mode mode) +{ + if (mode != my_css.capture_settings.mode) { + my_css.capture_settings.mode = mode; + invalidate_capture_binaries(); + } +} + +void +sh_css_capture_enable_xnr(bool enable) +{ + if (my_css.capture_settings.xnr != enable) { + invalidate_capture_binaries(); + my_css.capture_settings.xnr = enable; + } +} + +void +sh_css_capture_enable_bayer_downscaling(bool enable) +{ + if (my_css.capture_settings.bayer_ds != enable) { + invalidate_capture_binaries(); + my_css.capture_settings.bayer_ds = enable; + } +} + +enum sh_css_err +sh_css_capture_configure_output(unsigned int width, + unsigned int height, + enum sh_css_frame_format format) +{ + enum sh_css_err err = sh_css_success; + err = check_res(width, height); + if (err != sh_css_success) + return err; + if (my_css.capture_settings.output_info.width != width || + my_css.capture_settings.output_info.height != height || + my_css.capture_settings.output_info.format != format) { + sh_css_frame_info_init(&my_css.capture_settings.output_info, + width, height, format); + invalidate_capture_binaries(); + } + return sh_css_success; +} + +enum sh_css_err +sh_css_capture_configure_viewfinder(unsigned int width, + unsigned int height, + enum sh_css_frame_format format) +{ + enum sh_css_err err = sh_css_success; + err = check_res(width, height); + if (err != sh_css_success) + return err; + if (my_css.capture_settings.vf_info.width != width || + my_css.capture_settings.vf_info.height != height || + my_css.capture_settings.vf_info.format != format) { + sh_css_frame_info_init(&my_css.capture_settings.vf_info, + width, height, format); + invalidate_capture_binaries(); + } + return sh_css_success; +} + +enum sh_css_err +sh_css_capture_configure_pp_input(unsigned int width, + unsigned int height) +{ + enum sh_css_err err = sh_css_success; + err = check_null_res(width, height); + if (err != sh_css_success) + return err; + if (my_css.capture_settings.pp_input_info.width != width || + my_css.capture_settings.pp_input_info.height != height) { + sh_css_frame_info_init(&my_css.capture_settings.pp_input_info, + width, height, + SH_CSS_FRAME_FORMAT_YUV420); + invalidate_capture_binaries(); + } + return sh_css_success; +} + +void +sh_css_capture_enable_online(bool enable) +{ + my_css.capture_settings.online = enable; +} + +enum sh_css_err +sh_css_histogram_allocate(unsigned int num_elements, + struct sh_css_histogram **histogram) +{ + struct sh_css_histogram *me = sh_css_malloc(sizeof(*me)); + + if (me == NULL) + return sh_css_err_cannot_allocate_memory; + me->num_elements = num_elements; + me->data = hrt_isp_css_mm_alloc(num_elements * sizeof(unsigned int)); + if (me->data == NULL) { + sh_css_free(me); + return sh_css_err_cannot_allocate_memory; + } + *histogram = me; + return sh_css_success; +} + +void +sh_css_histogram_free(struct sh_css_histogram *me) +{ + if (me->data) + hrt_isp_css_mm_free(me->data); + sh_css_free(me); +} + +enum sh_css_err +sh_css_histogram_start(const struct sh_css_frame *input_frame, + struct sh_css_histogram *histogram) +{ + if (my_css.state != sh_css_state_idle) + return sh_css_err_system_not_idle; + if (input_frame->info.padded_width > SH_CSS_SP_MAX_WIDTH) + return sh_css_err_overlay_frames_too_big; + if (input_frame->info.format != SH_CSS_FRAME_FORMAT_YUV420) + return sh_css_err_frames_mismatch; + sh_css_sp_start_histogram(histogram, input_frame); + return sh_css_success; +} + +void +sh_css_send_input_frame(unsigned short *data, + unsigned int width, + unsigned int height) +{ + sh_css_hrt_send_input_frame(data, width, height, my_css.ch_id, + my_css.input_format, + my_css.two_ppc); +} + +static enum sh_css_err +allocate_frame_data(struct sh_css_frame *frame, unsigned int bytes) +{ +#ifndef __KERNEL__ + /* Physically contiguous memory allocation only for FPGA. */ + if (frame->contiguous) + frame->data = hrt_isp_css_mm_alloc_contiguous(bytes); + else +#endif + frame->data = hrt_isp_css_mm_alloc(bytes); + if (frame->data == NULL) + return sh_css_err_cannot_allocate_memory; + frame->data_bytes = bytes; + return sh_css_success; +} + +static void +init_plane(struct sh_css_frame_plane *plane, + unsigned int width, + unsigned int stride, + unsigned int height, + void *data) +{ + plane->height = height; + plane->width = width; + plane->stride = stride; + plane->data = data; +} + +static enum sh_css_err +allocate_single_plane(struct sh_css_frame *frame, + struct sh_css_frame_plane *plane, + unsigned int height, + unsigned int subpixels_per_line, + unsigned int bytes_per_pixel) +{ + enum sh_css_err err; + unsigned int stride; + + stride = subpixels_per_line * bytes_per_pixel; + err = allocate_frame_data(frame, stride * height); + if (err == sh_css_success) { + init_plane(plane, subpixels_per_line, stride, + height, frame->data); + } + return err; +} + +static enum sh_css_err +allocate_nv_planes(struct sh_css_frame *frame, + unsigned int horizontal_decimation, + unsigned int vertical_decimation) +{ + enum sh_css_err err; + unsigned int y_width = frame->info.padded_width, + y_height = frame->info.height, + uv_width = 2 * (y_width / horizontal_decimation), + uv_height = y_height / vertical_decimation, + y_bytes, uv_bytes; + + y_bytes = y_width * y_height; + uv_bytes = uv_width * uv_height; + + err = allocate_frame_data(frame, y_bytes + uv_bytes); + if (err == sh_css_success) { + init_plane(&frame->planes.nv.y, y_width, y_width, + y_height, frame->data); + init_plane(&frame->planes.nv.uv, uv_width, uv_width, + uv_height, frame->data + y_bytes); + } + return err; +} + +static enum sh_css_err +allocate_yuv_planes(struct sh_css_frame *frame, + unsigned int horizontal_decimation, + unsigned int vertical_decimation, + bool swap_uv, + unsigned int bytes_per_element) +{ + enum sh_css_err err; + unsigned int y_width = frame->info.padded_width, + y_height = frame->info.height, + uv_width = y_width / horizontal_decimation, + uv_height = y_height / vertical_decimation, + y_stride, y_bytes, uv_bytes, uv_stride; + + y_stride = y_width * bytes_per_element; + uv_stride = uv_width * bytes_per_element; + y_bytes = y_stride * y_height; + uv_bytes = uv_stride * uv_height; + + err = allocate_frame_data(frame, y_bytes + 2 * uv_bytes); + if (err == sh_css_success) { + init_plane(&frame->planes.yuv.y, y_width, y_stride, y_height, + frame->data); + if (swap_uv) { + init_plane(&frame->planes.yuv.v, uv_width, uv_stride, + uv_height, frame->data + y_bytes); + init_plane(&frame->planes.yuv.u, uv_width, uv_stride, + uv_height, frame->data + y_bytes + uv_bytes); + } else { + init_plane(&frame->planes.yuv.u, uv_width, uv_stride, + uv_height, frame->data + y_bytes); + init_plane(&frame->planes.yuv.v, uv_width, uv_stride, + uv_height, frame->data + y_bytes + uv_bytes); + } + } + return err; +} + +static enum sh_css_err +allocate_rgb_planes(struct sh_css_frame *frame, unsigned int bytes_per_element) +{ + enum sh_css_err err; + unsigned int width = frame->info.width, + height = frame->info.height, stride, bytes; + + stride = width * bytes_per_element; + bytes = stride * height; + err = allocate_frame_data(frame, 3 * bytes); + if (err == sh_css_success) { + init_plane(&frame->planes.planar_rgb.r, width, stride, + height, frame->data); + init_plane(&frame->planes.planar_rgb.g, width, stride, + height, frame->data + 1 * bytes); + init_plane(&frame->planes.planar_rgb.b, width, stride, + height, frame->data + 2 * bytes); + } + return err; +} + +static enum sh_css_err +allocate_qplane6_planes(struct sh_css_frame *frame) +{ + enum sh_css_err err; + unsigned int width = frame->info.padded_width / 2, + height = frame->info.height / 2, + bytes, stride; + + stride = width * 2; + bytes = stride * height; + + err = allocate_frame_data(frame, 6 * bytes); + if (err == sh_css_success) { + init_plane(&frame->planes.plane6.r, width, stride, + height, frame->data + 0 * bytes); + init_plane(&frame->planes.plane6.r_at_b, width, stride, + height, frame->data + 1 * bytes); + init_plane(&frame->planes.plane6.gr, width, stride, + height, frame->data + 2 * bytes); + init_plane(&frame->planes.plane6.gb, width, stride, + height, frame->data + 3 * bytes); + init_plane(&frame->planes.plane6.b, width, stride, + height, frame->data + 4 * bytes); + init_plane(&frame->planes.plane6.b_at_r, width, stride, + height, frame->data + 5 * bytes); + } + return err; +} + +static enum sh_css_err +allocate_frame(struct sh_css_frame **frame, + unsigned int width, + unsigned int height, + enum sh_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth, + bool contiguous) +{ + enum sh_css_err err; + struct sh_css_frame *me = sh_css_malloc(sizeof(*me)); + unsigned int bytes_per_pixel = raw_bit_depth <= 8 ? 1 : 2; + + if (!me) + return sh_css_err_cannot_allocate_memory; + me->info.width = width; + me->info.height = height; + me->info.format = format; + me->info.padded_width = padded_width; + me->info.raw_bit_depth = raw_bit_depth; + me->contiguous = contiguous; + + switch (me->info.format) { + case SH_CSS_FRAME_FORMAT_RAW: + err = allocate_single_plane(me, &me->planes.raw, + me->info.height, + padded_width, + bytes_per_pixel); + break; + case SH_CSS_FRAME_FORMAT_RGB565: + err = allocate_single_plane(me, &me->planes.rgb, + me->info.height, + padded_width, 2); + break; + case SH_CSS_FRAME_FORMAT_RGBA888: + err = allocate_single_plane(me, &me->planes.rgb, + me->info.height, + padded_width * 4, 1); + break; + case SH_CSS_FRAME_FORMAT_PLANAR_RGB888: + err = allocate_rgb_planes(me, 1); + break; + /* yuyv and uyvu have the same frame layout, only the data + * positioning differs. + */ + case SH_CSS_FRAME_FORMAT_YUYV: + case SH_CSS_FRAME_FORMAT_UYVY: + err = allocate_single_plane(me, &me->planes.yuyv, + me->info.height, + padded_width * 2, 1); + break; + case SH_CSS_FRAME_FORMAT_YUV_LINE: + /* Needs 3 extra lines to allow vf_pp prefetching */ + err = allocate_single_plane(me, &me->planes.yuyv, + me->info.height * 3/2 + 3, + padded_width, 1); + break; + case SH_CSS_FRAME_FORMAT_NV11: + err = allocate_nv_planes(me, 4, 1); + break; + /* nv12 and nv21 have the same frame layout, only the data + * positioning differs. + */ + case SH_CSS_FRAME_FORMAT_NV12: + case SH_CSS_FRAME_FORMAT_NV21: + err = allocate_nv_planes(me, 2, 2); + break; + /* nv16 and nv61 have the same frame layout, only the data + * positioning differs. + */ + case SH_CSS_FRAME_FORMAT_NV16: + case SH_CSS_FRAME_FORMAT_NV61: + err = allocate_nv_planes(me, 2, 1); + break; + case SH_CSS_FRAME_FORMAT_YUV420: + err = allocate_yuv_planes(me, 2, 2, false, 1); + break; + case SH_CSS_FRAME_FORMAT_YUV422: + err = allocate_yuv_planes(me, 2, 1, false, 1); + break; + case SH_CSS_FRAME_FORMAT_YUV444: + err = allocate_yuv_planes(me, 1, 1, false, 1); + break; + case SH_CSS_FRAME_FORMAT_YUV420_16: + err = allocate_yuv_planes(me, 2, 2, false, 2); + break; + case SH_CSS_FRAME_FORMAT_YUV422_16: + err = allocate_yuv_planes(me, 2, 1, false, 2); + break; + case SH_CSS_FRAME_FORMAT_YV12: + err = allocate_yuv_planes(me, 2, 2, true, 1); + break; + case SH_CSS_FRAME_FORMAT_YV16: + err = allocate_yuv_planes(me, 2, 1, true, 1); + break; + case SH_CSS_FRAME_FORMAT_QPLANE6: + err = allocate_qplane6_planes(me); + break; + case SH_CSS_FRAME_FORMAT_BINARY_8: + err = allocate_single_plane(me, &me->planes.binary.data, + me->info.height, + padded_width, 1); + me->planes.binary.size = 0; + break; + default: + sh_css_free(me); + return sh_css_err_invalid_frame_format; + } + if (err == sh_css_success) + *frame = me; + return err; +} + +enum sh_css_err +sh_css_frame_allocate(struct sh_css_frame **frame, + unsigned int width, + unsigned int height, + enum sh_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth) +{ + return allocate_frame(frame, width, height, format, + padded_width, raw_bit_depth, false); +} + +enum sh_css_err +sh_css_frame_allocate_from_info(struct sh_css_frame **frame, + const struct sh_css_frame_info *info) +{ + return sh_css_frame_allocate(frame, + info->width, + info->height, + info->format, + info->padded_width, + info->raw_bit_depth); +} + +enum sh_css_err +sh_css_frame_allocate_contiguous(struct sh_css_frame **frame, + unsigned int width, + unsigned int height, + enum sh_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth) +{ + return allocate_frame(frame, width, height, format, padded_width, + raw_bit_depth, true); +} + +enum sh_css_err +sh_css_frame_allocate_contiguous_from_info(struct sh_css_frame **frame, + const struct sh_css_frame_info + *info) +{ + return sh_css_frame_allocate_contiguous(frame, + info->width, + info->height, + info->format, + info->padded_width, + info->raw_bit_depth); +} + +void +sh_css_frame_free(struct sh_css_frame *frame) +{ + if (frame) { + hrt_isp_css_mm_free(frame->data); + sh_css_free(frame); + } +} + +bool +sh_css_frame_info_equal_resolution(const struct sh_css_frame_info *info_a, + const struct sh_css_frame_info *info_b) +{ + if (!info_a || !info_b) + return false; + return (info_a->width == info_b->width) && + (info_a->height == info_b->height); +} + +bool +sh_css_frame_equal_types(const struct sh_css_frame *frame_a, + const struct sh_css_frame *frame_b) +{ + const struct sh_css_frame_info *info_a = &frame_a->info, + *info_b = &frame_b->info; + if (!info_a || !info_b) + return false; + if (info_a->format != info_b->format) + return false; + if (info_a->padded_width != info_b->padded_width) + return false; + return sh_css_frame_info_equal_resolution(info_a, info_b); +} + +static void +append_firmware(struct sh_css_acc_fw **l, struct sh_css_acc_fw *firmware) +{ + while (*l) + l = &(*l)->next; + *l = firmware; + firmware->next = NULL; +} + +static void +remove_firmware(struct sh_css_acc_fw **l, struct sh_css_acc_fw *firmware) +{ + while (*l && *l != firmware) + l = &(*l)->next; + if (!*l) + return; + *l = firmware->next; + firmware->next = NULL; +} + +/* Load firmware for acceleration */ +enum sh_css_err +sh_css_load_acceleration(struct sh_css_acc_fw *firmware) +{ + my_css.invalidate = true; + if (firmware->header.type == SH_CSS_ACC_OUTPUT) + append_firmware(&my_css.output_stage, firmware); + else if (firmware->header.type == SH_CSS_ACC_VIEWFINDER) + append_firmware(&my_css.vf_stage, firmware); + return sh_css_acc_load(firmware); +} + +/* Unload firmware for acceleration */ +void +sh_css_unload_acceleration(struct sh_css_acc_fw *firmware) +{ + my_css.invalidate = true; + if (firmware->header.type == SH_CSS_ACC_OUTPUT) + remove_firmware(&my_css.output_stage, firmware); + else if (firmware->header.type == SH_CSS_ACC_VIEWFINDER) + remove_firmware(&my_css.vf_stage, firmware); + sh_css_acc_unload(firmware); +} + +/* Set argument of size to value */ +enum sh_css_err +sh_css_set_acceleration_argument(struct sh_css_acc_fw *firmware, + unsigned num, void *val, size_t size) +{ + return sh_css_acc_set_argument(firmware, num, val, size); +} + +/* Start acceleration of firmware with sp-args as SP arguments. */ +enum sh_css_err +sh_css_start_acceleration(struct sh_css_acc_fw *firmware) +{ + return sh_css_acc_start(firmware, NULL); +} + +/* To be called when acceleration has terminated. +*/ +void +sh_css_acceleration_done(struct sh_css_acc_fw *firmware) +{ + sh_css_acc_done(firmware); +} + +/* Abort acceleration within microseconds +*/ +void +sh_css_abort_acceleration(struct sh_css_acc_fw *firmware, unsigned deadline) +{ + /* TODO: implement time-out */ + (void)deadline; + sh_css_acc_abort(firmware); +} diff --git a/drivers/media/video/atomisp/css/sh_css.h b/drivers/media/video/atomisp/css/sh_css.h new file mode 100644 index 0000000..f187d68 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css.h @@ -0,0 +1,540 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_H_ +#define _SH_CSS_H_ + +#include "sh_css_types.h" +#include "sh_css_params.h" + +/* ===== GENERIC ===== */ + +/* Initialize the API. This is required before any other function in this + * API can be called. + * Arguments: + * - malloc_func: memory allocation function such as malloc or kalloc. + * - free_func: memory free function such as free or kfree + * - irq_setting: the way interrupts should be used (or not) + */ +enum sh_css_err +sh_css_init(void *(*malloc_func) (size_t size), + void (*free_func) (void *ptr), + enum sh_css_interrupt_setting irq_setting, + const char *fw_data, + unsigned int fw_size); + +/* Uninitialize the API. This cleans up all internal data structures. */ +void +sh_css_uninit(void); + +/* Suspend/resume: use suspend before powering the CSS and use resume + after powering it up again. The resume function will make sure the + CSS is correctly reprogrammed. This assumes that all buffers allocated + in DDR will remain alive during power down. If this is not the case, + use sh_css_unit() followed by sh_css_init() at power up. */ +void +sh_css_suspend(void); + +void +sh_css_resume(void); + +/* Set the print function. This function is used to print debug information + * if debugging is enable. An example of the argument is printf. + */ +void +sh_css_set_print_function(int (*func) (const char *fmt, ...)); + +/* When an interrupt occurs from the ISP_CSS, use this function to get + * information about this interrupt. Since multiple interrupts can occur + * at the same time, this function returns whether there are more interrupts + * pending. This function should be called until this return value becomes + * false. + */ +enum sh_css_err +sh_css_translate_interrupt(unsigned int *irq_infos); + +/* Get all interrupt bits from the CSS receiver. */ +void +sh_css_rx_get_interrupt_info(unsigned int *irq_infos); + +/* Reset all bits in the irq_infos variable. */ +void +sh_css_rx_clear_interrupt_info(unsigned int irq_infos); + +/* To be called on a SH_CSS_IRQ_INFO_FW_ACC_DONE interrupt */ +void +sh_css_terminate_firmware(void); + +enum sh_css_err +sh_css_start_next_stage(void); + +void +sh_css_mmu_set_page_table_base_address(void *base_address); + +void * +sh_css_mmu_get_page_table_base_address(void); + +void +sh_css_mmu_invalidate_cache(void); + +/* Enable or disable certain interrupts. The interrupt info type is used + * here to indicate the interrupt to enable or disable. + */ +enum sh_css_err +sh_css_enable_interrupt(enum sh_css_interrupt_info info, bool enable); + +/* Return the value of a SW interrupt */ +unsigned int +sh_css_get_sw_interrupt_value(void); + +/* Allocate a histogram. */ +enum sh_css_err +sh_css_histogram_allocate(unsigned int num_elements, + struct sh_css_histogram **histogram); + +/* Free a histogram */ +void +sh_css_histogram_free(struct sh_css_histogram *histogram); + +/* Return true if UV values range from 0 to 255 and false if UV values + * range from -127 to 128. + */ +void +sh_css_uv_offset_is_zero(bool *uv_offset_is_zero); + +/* When interrupts are disabled, use this function to wait for a particular + * ISP mode to complete. + */ +enum sh_css_err +sh_css_wait_for_completion(void); + +/* Set the current input resolution. This needs to be called every time the + * sensor resolution changes. + */ +enum sh_css_err +sh_css_input_set_resolution(unsigned int width, unsigned int height); + +/* Set the part of the input resolution that will be the input to the ISP. + * The difference between the input resolution and effective input resolution + * will be cropped off. When the effective input resolution is exceeds the + * output resolution, the ISP will downscale the input to the output resolution + * in the domain. + * Note that the effective input resolution cannot be smaller than the output + * resolution. + */ +enum sh_css_err +sh_css_input_set_effective_resolution(unsigned int width, unsigned int height); + +/* Specify the format of the input data. This format is used for all input + * sources except memory (mipi receiver, prbs, tpg, fifo). + */ +void +sh_css_input_set_format(enum sh_css_input_format format); + +void +sh_css_input_set_binning_factor(unsigned int binning_factor); + +/* Translate an input format and mipi compression pair to the fmt_type. + * This is normally done by the sensor, but when using the input fifo, this + * format type must be sumitted correctly by the application. + */ +enum sh_css_err +sh_css_input_format_type(enum sh_css_input_format input_format, + enum sh_css_mipi_compression compression, + unsigned int *fmt_type); + +/* Specify that the input will be sent as 2 pixels per clock. + * The default is one pixel per clock. + */ +void +sh_css_input_set_two_pixels_per_clock(bool two_pixels_per_clock); + +/* Specify the bayer order of the input. The default is grbg. */ +void +sh_css_input_set_bayer_order(enum sh_css_bayer_order bayer_order); + +/* Get the number of extra rows and columns needed to program the + * sensor driver with the correct resolution. + * This is dependent upon the bayer order which is assumed to have + * been already set using the API sh_css_input_set_bayer_order + */ +int +sh_css_get_extra_pixels_count(int *extra_rows, int *extra_columns); + +/* Specify which channel carries the input for the CSS. */ +void +sh_css_input_set_channel(unsigned int channel_id); + +/* Set the input mode to be used. */ +void +sh_css_input_set_mode(enum sh_css_input_mode mode); + +/* Configure the MIPI receiver: + * - port: select the 1lane or 4lane port + * - num_lanes: this argument is only valid for the 4lane port. it specifies + * how many of these 4 lanes are in use. Valid values are 1, 2, + * 3 or 4. + * - timeout: this specifies the timeout after which a timeout interrupt is + * generated. + * The timeout is specified in terms of . + */ +enum sh_css_err +sh_css_input_configure_port(enum sh_css_mipi_port port, + unsigned int num_lanes, unsigned int timeout); + +/* Specify the number of bits per compressed and uncompressed pixel for a given + * compression mode. + */ +enum sh_css_err +sh_css_input_set_compression(enum sh_css_mipi_compression comp, + unsigned int compressed_bits_per_pixel, + unsigned int uncompressed_bits_per_pixel); + +/* Configure the Test Pattern Generator, the way these values are used to + * generate the pattern can be seen in the HRT extension for the test pattern + * generator: + * devices/test_pat_gen/hrt/include/test_pat_gen.h: hrt_calc_tpg_data(). + */ +void +sh_css_tpg_configure(unsigned int x_mask, int x_delta, + unsigned int y_mask, int y_delta, unsigned int xy_mask); + +/* Seed the for the Pseudo Random Bit Sequence */ +void +sh_css_prbs_set_seed(int seed); + +/* Digital zoom: this feature can be configured with a zoom factor + * which determines the amount of zoom and a zoom center which determines + * the point to zoom in at. + * This feature is currently available only for video, but will become + * available for preview and capture as well. + * Set the digital zoom factor, this is a logarithmic scale. The actual zoom + * factor will be 64/x. + * Setting dx or dy to 0 disables digital zoom for that direction. + */ +void +sh_css_set_zoom_factor(unsigned int dx, unsigned int dy); + +/* Get the current zoom factor. This will return the same values as were set + * during the last video_set_zoom_factor() call. + */ +void +sh_css_get_zoom_factor(unsigned int *dx, unsigned int *dy); + +/* Specify the overlay to be used for each viewfinder frame generated. + * This overlay will remain active until it is reset by passing NULL to + * this same function. + */ +void +sh_css_overlay_set_for_viewfinder(const struct sh_css_overlay *overlay); + +/* Set the shading table for the current sensor module. This table will be + * used for shading correction in each mode that supports this feature. + */ +void +sh_css_set_shading_table(const struct sh_css_shading_table *table); + +/* ===== FRAMES ===== */ + +/* Allocate a frame of a certain resolution and format. */ +enum sh_css_err +sh_css_frame_allocate(struct sh_css_frame **frame, + unsigned int width, + unsigned int height, + enum sh_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth); + +/* Allocate a frame using the resolution and format from a frame info struct. */ +enum sh_css_err +sh_css_frame_allocate_from_info(struct sh_css_frame **frame, + const struct sh_css_frame_info *info); + +/* Free a frame */ +void +sh_css_frame_free(struct sh_css_frame *frame); + +/* ===== FPGA display frames ====== */ +/* Contiguous frame allocation, only for FPGA display driver which needs + physically contiguous memory. */ +enum sh_css_err +sh_css_frame_allocate_contiguous(struct sh_css_frame **frame, + unsigned int width, + unsigned int height, + enum sh_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth); + +enum sh_css_err +sh_css_frame_allocate_contiguous_from_info(struct sh_css_frame **frame, + const struct sh_css_frame_info *info); + +/* ===== PREVIEW ===== */ + +/* Start the ISP in preview mode, this will run the preview ISP on one frame. + * After this has completed, it needs to be started again for the next frame. + */ +enum sh_css_err +sh_css_preview_start(struct sh_css_frame *raw_out_frame, + struct sh_css_frame *out_frame); + +/* Enable or disable online binaries if available. Default is enabled. */ +void +sh_css_preview_enable_online(bool enable); + +/* Enable or disable continuous binaries if available. Default is disabled. */ +void +sh_css_enable_continuous(bool enable); + +/* Return whether continuous binaries are enabled */ +bool +sh_css_continuous_is_enabled(void); + +/* Disable vf_pp: used to replace by dynamic binary */ +void +sh_css_disable_vf_pp(bool disable); + +/* Disable capture_pp: used to replace by dynamic binary */ +void +sh_css_disable_capture_pp(bool disable); + +/* Specify the output resolution to be used by the preview ISP. */ +enum sh_css_err +sh_css_preview_configure_output(unsigned int width, + unsigned int height, + enum sh_css_frame_format format); + +/* Get the information about the output frames, this contains the resolution + * and the stride. To allocate frames, use the information returned here. + */ +enum sh_css_err +sh_css_preview_get_output_frame_info(struct sh_css_frame_info *info); + +enum sh_css_err +sh_css_preview_get_grid_info(struct sh_css_grid_info *info); + +enum sh_css_err +sh_css_preview_get_input_resolution(unsigned int *width, + unsigned int *height); + +/* Set the input resolution for viewfinder post processing. + When this is not set, the input resolution is equal to the input + resolution of the preview pipeline. When this is set, the YUV scaler + in the viewfinder post processing step will be activated. */ +enum sh_css_err +sh_css_preview_configure_pp_input(unsigned int width, unsigned int height); + +/* ===== CAPTURE ===== */ + +/* Start the ISP in capture mode: + * - out_frame: pointer to the output frame + * - vf_frame: pointer to the viewfinder frame + */ +enum sh_css_err +sh_css_capture_start(struct sh_css_frame *raw_out_frame, + struct sh_css_frame *out_frame, + struct sh_css_frame *vf_frame); + +/* Specify the mode used for capturing. */ +void +sh_css_capture_set_mode(enum sh_css_capture_mode mode); + +/* Enable the eXtra Noise Reduction as a post processing step. This will be + * run on both the captured output and the viewfinder output. + */ +void +sh_css_capture_enable_xnr(bool enable); + +/* Specify the output resolution for captured images. */ +enum sh_css_err +sh_css_capture_configure_output(unsigned int width, + unsigned int height, + enum sh_css_frame_format format); + +/* Specify the viewfinder resolution. Note that this resolution currently + * has to be a division of the captured output by a power of 2. The API will + * automatically select the resolution that's closest to the one requested + * here. + */ +enum sh_css_err +sh_css_capture_configure_viewfinder(unsigned int width, + unsigned int height, + enum sh_css_frame_format format); + +/* For non-raw still captures, downscaling in the YUV domain can be done + * during post processing. This function specifies the input resolution + * for the YUV downscaling step. If this resolution is not set, the YUV + * downscaling will not be done. The output resolution of the YUV + * downscaling is taken from the configure_output function above. + */ +enum sh_css_err +sh_css_capture_configure_pp_input(unsigned int width, + unsigned int height); + +/* Enable or disable online binaries if available. Default is enabled. */ +void +sh_css_capture_enable_online(bool enable); + +/* Retrieve the format and resolution of the output frames. Note that this + * can differ from the requested resolution. + */ +enum sh_css_err +sh_css_capture_get_output_frame_info(struct sh_css_frame_info *info); + +/* Retrieve the format and resolution of the viewfinder frames. Note that this + * can differ from the requested resolution. + */ +enum sh_css_err +sh_css_capture_get_viewfinder_frame_info(struct sh_css_frame_info *info); + +/* Retrieve the format and resolution of the RAW frame. This is only available + * when the capture is set to offline or continuous using: + * sh_css_capture_enable_online(false) or + * sh_css_enable_continuous(true). + */ +enum sh_css_err +sh_css_capture_get_output_raw_frame_info(struct sh_css_frame_info *info); + +enum sh_css_err +sh_css_capture_get_grid_info(struct sh_css_grid_info *info); + +enum sh_css_err +sh_css_capture_get_input_resolution(unsigned int *width, + unsigned int *height); +/* ===== VIDEO ===== */ + +/* Start the video ISP for one frame: + * - in_frame: pointer to the input frame, this argument is only used if the + * input_mode is set to sh_css_input_mode_memory. + * - out_frame: pointer to the output frame. + * - vf_frame: pointer to the viewfinder output frame. + */ +enum sh_css_err +sh_css_video_start(struct sh_css_frame *in_frame, + struct sh_css_frame *out_frame, + struct sh_css_frame *vf_frame); + +/* Specify the output resolution for output frames. Note that the actual + * resolution can be different from the requested resolution. + */ +enum sh_css_err +sh_css_video_configure_output(unsigned int width, + unsigned int height, + enum sh_css_frame_format format); + +/* Specify the viewfinder resolution. Note that this resolution currently has + * to be a division of the captured output by a power of 2. The API will + * automatically select the resolution that's closest to the one requested + * here. + */ +enum sh_css_err +sh_css_video_configure_viewfinder(unsigned int width, + unsigned int height, + enum sh_css_frame_format format); + +/* Set the motion vector for Digital Image Stabilization (DIS). + * These positions are normally calculated using the DIS statistics. + */ +void +sh_css_video_set_dis_vector(int x, int y); + +/* Specify the envelope to be used for DIS. */ +void +sh_css_video_set_dis_envelope(unsigned int width, unsigned int height); + +/* Retrieve the envelope to be used for DIS. */ +void +sh_css_video_get_dis_envelope(unsigned int *width, unsigned int *height); + +/* Retrieve the format and resolution of the output frames. Note that this + * can differ from the requested resolution. + */ +enum sh_css_err +sh_css_video_get_output_frame_info(struct sh_css_frame_info *info); + +/* Retrieve the format and resolution of the viewfinder frames. Note that this + * can differ from the requested resolution. + */ +enum sh_css_err +sh_css_video_get_viewfinder_frame_info(struct sh_css_frame_info *info); + +enum sh_css_err +sh_css_video_get_grid_info(struct sh_css_grid_info *info); + +enum sh_css_err +sh_css_video_get_input_resolution(unsigned int *width, + unsigned int *height); + +/* Generate a luminance histogram from a frame. The width of the frame + * cannot exceed 640 pixels and the frame must be a yuv420 frame. + */ +enum sh_css_err +sh_css_histogram_start(const struct sh_css_frame *input_frame, + struct sh_css_histogram *histogram); + +/* Send streaming data into the css input FIFO. This is for testing purposes + * only. This uses the channel ID and input format as set by the user with + * the regular functions for this. + * This function blocks until the entire frame has been written into the + * input FIFO. + */ +void +sh_css_send_input_frame(unsigned short *data, + unsigned int width, + unsigned int height); + +/* Temporary function to poll whether the ISP has been started. Once it has, + * the sensor can also be started. */ +bool +sh_css_isp_has_started(void); + +/* Load firmware for acceleration */ +enum sh_css_err +sh_css_load_acceleration(struct sh_css_acc_fw *firmware); + +/* Unload firmware for acceleration */ +void +sh_css_unload_acceleration(struct sh_css_acc_fw *firmware); + +/* Set argument of size to value */ +enum sh_css_err +sh_css_set_acceleration_argument(struct sh_css_acc_fw *firmware, + unsigned num, void *val, size_t size); + +/* Start acceleration of firmware. + Load the firmware if not yet loaded. +*/ +enum sh_css_err +sh_css_start_acceleration(struct sh_css_acc_fw *firmware); + +/* To be called when acceleration has terminated. +*/ +void +sh_css_acceleration_done(struct sh_css_acc_fw *firmware); + +/* Abort acceleration within microseconds +*/ +void +sh_css_abort_acceleration(struct sh_css_acc_fw *firmware, unsigned deadline); + +#endif /* _SH_CSS_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_accelerate.c b/drivers/media/video/atomisp/css/sh_css_accelerate.c new file mode 100644 index 0000000..ab6fc85 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_accelerate.c @@ -0,0 +1,245 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css_hrt.h" +#include "sh_css_sp_start.h" +#include "sh_css_sp.h" +#include "sh_css_internal.h" +#include "sh_css_accelerate.h" + +#if !defined(C_RUN) && !defined(HRT_UNSCHED) +static void +sh_css_acc_upload_isp_code(const struct sh_css_acc_fw *firmware) +{ + const unsigned char *blob = SH_CSS_ACC_ISP_CODE(firmware); + unsigned size = SH_CSS_ACC_ISP_SIZE(firmware); + const unsigned char *binary = sh_css_load_blob(blob, size); + + sh_css_sp_dmem_store((unsigned int)firmware->header.sp.isp_code, + &binary, sizeof(binary)); +} +#endif + +static void +upload_frame(struct sh_css_frame *sp_address, struct sh_css_frame *frame) +{ + if (!frame || !sp_address) + return; + sh_css_sp_dmem_store((unsigned int)sp_address, frame, sizeof(*frame)); +} + +static void +upload_int(unsigned *sp_address, unsigned *val) +{ + if (!sp_address) + return; + sh_css_sp_dmem_store((unsigned int)sp_address, val, sizeof(*val)); +} + +/* Load the firmware into xmem */ +enum sh_css_err +sh_css_acc_load(const struct sh_css_acc_fw *firmware) +{ + struct sh_css_acc_fw_hdr *header + = (struct sh_css_acc_fw_hdr *)&firmware->header; + header->sp_args = + sh_css_malloc(sizeof(*header->sp_args) * + header->sp.args_cnt); + if (!header->sp_args) + return sh_css_err_cannot_allocate_memory; + header->loaded = true; + return sh_css_success; +} + +void +sh_css_acc_unload(const struct sh_css_acc_fw *firmware) +{ + struct sh_css_acc_fw_hdr *header + = (struct sh_css_acc_fw_hdr *)&firmware->header; + sh_css_free(header->sp_args); + header->sp_args = NULL; + header->loaded = false; +} + +/* Set argument of size to value */ +enum sh_css_err +sh_css_acc_set_argument(struct sh_css_acc_fw *firmware, + unsigned num, void *val, size_t size) +{ + if (!firmware->header.sp_args) + return sh_css_err_invalid_arguments; + if (num >= firmware->header.sp.args_cnt) + return sh_css_err_invalid_arguments; + firmware->header.sp_args[num].type = sh_css_argument_type(firmware, + num); + firmware->header.sp_args[num].value = val; + firmware->header.sp_args[num].size = size; + return sh_css_success; +} + +/* Get type for argument */ +enum sh_css_acc_arg_type +sh_css_argument_type(struct sh_css_acc_fw *firmware, unsigned num) +{ + return SH_CSS_ACC_SP_ARGS(firmware)[num]; +} + +/* Set host private data for argument */ +enum sh_css_err +sh_css_argument_set_host(struct sh_css_acc_fw *firmware, + unsigned num, void *host) +{ + if (!firmware->header.sp_args) + return sh_css_err_invalid_arguments; + if (num >= firmware->header.sp.args_cnt) + return sh_css_err_invalid_arguments; + firmware->header.sp_args[num].host = host; + return sh_css_success; +} + +/* Get host private data for argument */ +void * +sh_css_argument_get_host(struct sh_css_acc_fw *firmware, unsigned num) +{ + if (!firmware->header.sp_args) + return NULL; + if (num >= firmware->header.sp.args_cnt) + return NULL; + return firmware->header.sp_args[num].host; +} + +static void +copy_sp_arguments(struct sh_css_acc_fw *firmware, bool to_sp) +{ + unsigned sp_address = (unsigned)firmware->header.sp.args; + unsigned i; + for (i = 0; i < firmware->header.sp.args_cnt; i++) { + enum sh_css_acc_arg_type type = + firmware->header.sp_args[i].type; + void *value = firmware->header.sp_args[i].value; + unsigned size = firmware->header.sp_args[i].size; + bool copy = to_sp; + switch (type) { + case SH_CSS_ACC_ARG_SCALAR_IN: + break; + case SH_CSS_ACC_ARG_SCALAR_IO: + copy = true; + break; + case SH_CSS_ACC_ARG_SCALAR_OUT: + copy = !to_sp; + break; + case SH_CSS_ACC_ARG_PTR_IN: + case SH_CSS_ACC_ARG_PTR_OUT: + case SH_CSS_ACC_ARG_PTR_IO: + value = &firmware->header.sp_args[i].value; + size = sizeof(void *); + break; + case SH_CSS_ACC_ARG_FRAME: + size = sizeof(struct sh_css_frame); + break; + } + if (copy) { + if (to_sp) + sh_css_sp_dmem_store(sp_address, value, size); + else + sh_css_sp_dmem_load(sp_address, value, size); + } + sp_address += size; + } +} + +/* Start the sp, which will start the isp. +*/ +enum sh_css_err +sh_css_acc_start(struct sh_css_acc_fw *firmware, + struct sh_css_binary_args *args) +{ + struct sh_css_acc_fw_hdr *header + = (struct sh_css_acc_fw_hdr *)&firmware->header; + bool has_extension_args = (args != NULL); + bool is_extension = (header->type != SH_CSS_ACC_STANDALONE); + const struct sh_css_sp_fw *sp_fw = &header->sp.fw; + *(const void **)&sp_fw->text = SH_CSS_ACC_SP_CODE(firmware); + *(const void **)&sp_fw->data = SH_CSS_ACC_SP_DATA(firmware); + + if (!header->loaded) + return sh_css_err_invalid_arguments; + if (has_extension_args != is_extension) + return sh_css_err_invalid_arguments; + + if (!sh_css_sp_load_program(sp_fw, SH_CSS_ACC_PROG_NAME(firmware))) + return sh_css_err_cannot_allocate_memory; +#if !defined(C_RUN) && !defined(HRT_UNSCHED) + sh_css_acc_upload_isp_code(firmware); +#endif + +#ifdef C_RUN + header->sp.init(firmware); +#endif + + if (args) { + upload_frame(header->sp.input, args->in_frame); + upload_frame(header->sp.output, args->out_frame); + upload_frame(header->sp.out_vf, args->out_vf_frame); + upload_frame(header->sp.extra, args->extra_frame); + upload_int (header->sp.vf_downscale_bits, + &args->vf_downscale_log2); + } + copy_sp_arguments(firmware, true); + + /* Start the firmware on the sp, which will start the isp */ +#ifdef C_RUN + sh_css_sp_do_invalidate_mmu(); + csim_processor_set_crun_func(SP, header->sp.entry); + hrt_ctl_run(SP, 1); + hrt_ctl_start(SP); + hrt_sleep(); +#elif defined(HRT_CSIM) + sh_css_sp_do_invalidate_mmu(); + _hrt_cell_start(SP, header->sp.entry); +#else + sh_css_sp_start((unsigned int)header->sp.entry); +#endif + return sh_css_success; +} + +/* To be called when acceleration has terminated. +*/ +void +sh_css_acc_done(struct sh_css_acc_fw *firmware) +{ + copy_sp_arguments(firmware, false); +} + +void +sh_css_acc_wait(void) +{ + sh_css_hrt_sp_wait(); +} + +/* Flag abortion of acceleration */ +void sh_css_acc_abort(struct sh_css_acc_fw *firmware) +{ + unsigned int t = true; + upload_int(firmware->header.sp.css_abort, &t); +} diff --git a/drivers/media/video/atomisp/css/sh_css_accelerate.h b/drivers/media/video/atomisp/css/sh_css_accelerate.h new file mode 100644 index 0000000..ce139b1 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_accelerate.h @@ -0,0 +1,76 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_ACCELERATE_H_ +#define _SH_CSS_ACCELERATE_H_ + +#include "sh_css_types.h" + +/* Load the firmware into xmem */ +enum sh_css_err +sh_css_acc_load(const struct sh_css_acc_fw *firmware); + +/* Unload the firmware*/ +void +sh_css_acc_unload(const struct sh_css_acc_fw *firmware); + +/* Set argument of size to value */ +enum sh_css_err +sh_css_acc_set_argument(struct sh_css_acc_fw *firmware, + unsigned int num, + void *val, + unsigned int size); + +/* Get type for argument */ +enum sh_css_acc_arg_type +sh_css_argument_type(struct sh_css_acc_fw *firmware, unsigned int num); + +/* Set host private data for argument */ +enum sh_css_err +sh_css_argument_set_host(struct sh_css_acc_fw *firmware, + unsigned num, void *host); + +/* Get host private data for argument */ +void * +sh_css_argument_get_host(struct sh_css_acc_fw *firmware, unsigned num); + +/* Start the sp, which will start the isp. + Load the firmware if not yet loaded. +*/ +enum sh_css_err +sh_css_acc_start(struct sh_css_acc_fw *firmware, + struct sh_css_binary_args *args); + +/* To be called when acceleration has terminated. +*/ +void +sh_css_acc_done(struct sh_css_acc_fw *firmware); + +/* Wait for the firmware to terminate */ +void +sh_css_acc_wait(void); + +/* Flag abortion of acceleration */ +void sh_css_acc_abort(struct sh_css_acc_fw *firmware); + +#endif /* _SH_CSS_ACCELERATE_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_binary.c b/drivers/media/video/atomisp/css/sh_css_binary.c new file mode 100644 index 0000000..e451509 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_binary.c @@ -0,0 +1,584 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css_binary.h" +#include "sh_css.h" +#include "sh_css_internal.h" +#include "sh_css_hrt.h" +#include "sh_css_sp.h" +#include "sh_css_firmware.h" +#include "sh_css_defs.h" +#include "sh_css_binary_info.h" + +static struct sh_css_binary_info all_binaries[SH_CSS_BINARY_NUM_IDS]; +static struct sh_css_binary_info *binary_infos[SH_CSS_BINARY_NUM_MODES]; + +enum sh_css_err +sh_css_binary_grid_info(struct sh_css_binary *binary, + struct sh_css_grid_info *info) +{ + /* for DIS, we use a division instead of a ceil_div. If this is smaller + * than the 3a grid size, it indicates that the outer values are not + * valid for DIS. + */ + info->dis_width = binary->dis_ver_proj_num_3a; + info->dis_height = binary->dis_hor_proj_num_3a; + info->dis_bqs_per_grid_cell = 1 << binary->dis_deci_factor_log2; + info->dis_hor_coef_num = binary->dis_hor_coef_num_3a; + info->dis_ver_coef_num = binary->dis_ver_coef_num_3a; + /* 3A statistics grid */ + info->s3a_width = binary->s3atbl_width; + info->s3a_height = binary->s3atbl_height; + info->s3a_bqs_per_grid_cell = (1 << binary->deci_factor_log2); + + return sh_css_success; +} + +static enum sh_css_err +load_binary(struct sh_css_binary_info *binary, bool *binary_found) +{ + const unsigned char *blob = sh_css_blob_info[binary->id].blob; + unsigned size = sh_css_blob_info[binary->id].size; + + *binary_found = blob != NULL; + /* we don't have this binary, skip it */ + if (!size) + return sh_css_success; + + binary->xmem_addr = sh_css_load_blob(blob, size); + if (!binary->xmem_addr) + return sh_css_err_cannot_allocate_memory; + return sh_css_success; +} + +static void init_pc_histogram(struct sh_css_pc_histogram *histo) +{ + histo->length = 0; + histo->run = NULL; + histo->stall = NULL; +} + +static void init_metrics(struct sh_css_binary_metrics *metrics, + unsigned int binary_id) +{ + metrics->mode = binary_id; + metrics->next = NULL; + init_pc_histogram(&metrics->isp_histogram); + init_pc_histogram(&metrics->sp_histogram); +} + +#define _init_binary_info(binary, prefix) { \ + int i; \ + enum sh_css_frame_format out_fmts[] = prefix ## OUTPUT_FORMATS; \ + binary->num_output_formats = sizeof(out_fmts)/sizeof(*out_fmts); \ + for (i = 0; i < binary->num_output_formats; i++) \ + binary->output_formats[i] = out_fmts[i]; \ + for (i = binary->num_output_formats; \ + i < SH_CSS_MAX_NUM_FRAME_FORMATS; \ + i++) \ + binary->output_formats[i] = -1; \ + binary->mode = prefix ## MODE; \ + binary->enable_sc = prefix ## ENABLE_SC; \ + binary->enable_fpnr = prefix ## ENABLE_FPNR; \ + binary->enable_s3a = prefix ## ENABLE_S3A; \ + binary->enable_ds = prefix ## ENABLE_DS; \ + binary->enable_uds = prefix ## ENABLE_UDS; \ + binary->enable_dis = prefix ## ENABLE_SDIS; \ + binary->enable_dvs_envelope = prefix ## ENABLE_DVS_ENVELOPE; \ + binary->left_cropping = prefix ## LEFT_CROPPING; \ + binary->top_cropping = prefix ## TOP_CROPPING; \ + binary->c_subsampling = prefix ## C_SUBSAMPLING; \ + binary->pipelining = prefix ## PIPELINING; \ + binary->fixed_s3a_deci_log = prefix ## FIXED_S3A_DECI_LOG; \ + binary->input = prefix ## INPUT; \ + binary->max_dvs_envelope_width = prefix ## MAX_DVS_ENVELOPE_WIDTH; \ + binary->max_dvs_envelope_height = prefix ## MAX_DVS_ENVELOPE_HEIGHT; \ + binary->min_output_width = prefix ## MIN_OUTPUT_WIDTH; \ + binary->max_output_width = prefix ## MAX_OUTPUT_WIDTH; \ + binary->max_vf_log_downscale = prefix ## MAX_VF_LOG_DOWNSCALE; \ + binary->enable_vf_veceven = prefix ## ENABLE_VF_VECEVEN; \ + binary->output_num_chunks = prefix ## OUTPUT_NUM_CHUNKS; \ +} + +static enum sh_css_err +init_binary_info(struct sh_css_binary_info *info, bool *binary_found) +{ + unsigned int max_internal_width; + + switch (info->id) { + case SH_CSS_BINARY_ID_COPY: + _init_binary_info(info, ISP_COPY_); + break; + case SH_CSS_BINARY_ID_VF_PP: + _init_binary_info(info, ISP_VF_PP_); + break; + case SH_CSS_BINARY_ID_CAPTURE_PP: + _init_binary_info(info, ISP_CAPTURE_PP_); + break; + case SH_CSS_BINARY_ID_PRE_GDC: + _init_binary_info(info, ISP_PRE_GDC_); + break; + case SH_CSS_BINARY_ID_GDC: + _init_binary_info(info, ISP_GDC_); + break; + case SH_CSS_BINARY_ID_POST_GDC: + _init_binary_info(info, ISP_POST_GDC_); + break; + case SH_CSS_BINARY_ID_PRE_ANR: + _init_binary_info(info, ISP_PRE_ANR_); + break; + case SH_CSS_BINARY_ID_ANR: + _init_binary_info(info, ISP_ANR_); + break; + case SH_CSS_BINARY_ID_POST_ANR: + _init_binary_info(info, ISP_POST_ANR_); + break; + case SH_CSS_BINARY_ID_PREVIEW_DZ: + _init_binary_info(info, ISP_PREVIEW_DZ_); + break; + case SH_CSS_BINARY_ID_PREVIEW_DS: + _init_binary_info(info, ISP_PREVIEW_DS_); + break; + case SH_CSS_BINARY_ID_PRIMARY_SMALL: + _init_binary_info(info, ISP_PRIMARY_SMALL_); + break; + case SH_CSS_BINARY_ID_PRIMARY_DS: + _init_binary_info(info, ISP_PRIMARY_DS_); + break; + case SH_CSS_BINARY_ID_BAYER_DS: + _init_binary_info(info, ISP_BAYER_DS_); + break; + case SH_CSS_BINARY_ID_VIDEO_OFFLINE: + _init_binary_info(info, ISP_VIDEO_OFFLINE_); + break; + case SH_CSS_BINARY_ID_PRIMARY_VAR: + _init_binary_info(info, ISP_PRIMARY_VAR_); + break; + case SH_CSS_BINARY_ID_PRIMARY_8MP: + _init_binary_info(info, ISP_PRIMARY_8MP_); + break; + case SH_CSS_BINARY_ID_PRIMARY_14MP: + _init_binary_info(info, ISP_PRIMARY_14MP_); + break; + case SH_CSS_BINARY_ID_PRIMARY_16MP: + _init_binary_info(info, ISP_PRIMARY_16MP_); + break; + case SH_CSS_BINARY_ID_PRIMARY_REF: + _init_binary_info(info, ISP_PRIMARY_REF_); + break; + case SH_CSS_BINARY_ID_VIDEO_DZ: + _init_binary_info(info, ISP_VIDEO_DZ_); + break; + case SH_CSS_BINARY_ID_VIDEO_NODZ: + _init_binary_info(info, ISP_VIDEO_NODZ_); + break; + case SH_CSS_BINARY_ID_VIDEO_DS: + _init_binary_info(info, ISP_VIDEO_DS_); + break; + default: + break; + } + info->s3atbl_use_dmem = _S3ATBL_USE_DMEM(info->min_output_width != + info->max_output_width); + /* The ISP uses the veceven module for output, on the host however + * we don't want to know about it. We treat preview output as regular + * output, not as viewfinder output. */ + if (info->mode == SH_CSS_BINARY_MODE_PREVIEW) + info->enable_vf_veceven = false; + info->variable_vf_veceven = info->mode == SH_CSS_BINARY_MODE_COPY; + max_internal_width = + __ISP_INTERNAL_WIDTH(info->max_output_width, + info->max_dvs_envelope_width, + info->left_cropping, + info->mode, + info->c_subsampling, + info->output_num_chunks, + info->pipelining); + info->max_input_width = _ISP_MAX_INPUT_WIDTH(max_internal_width, + info->enable_ds); + info->xmem_addr = NULL; + info->next = NULL; + return load_binary(info, binary_found); +} + +/* When binaries are put at the beginning, they will only + * be selected if no other primary matches. + */ +enum sh_css_err +sh_css_init_binary_infos(void) +{ + int i; + + for (i = 0; i < SH_CSS_BINARY_NUM_IDS; i++) { + enum sh_css_err ret; + struct sh_css_binary_info *binary = &all_binaries[i]; + bool binary_found; + + binary->id = (enum sh_css_binary_id) i; + ret = init_binary_info(binary, &binary_found); + if (ret != sh_css_success) + return ret; + if (!binary_found) + continue; + /* Prepend new binary information */ + binary->next = binary_infos[binary->mode]; + binary_infos[binary->mode] = binary; + } + return sh_css_success; +} + +enum sh_css_err +sh_css_binary_uninit(void) +{ + unsigned int i; + struct sh_css_binary_info *b; + + for (i = 0; i < SH_CSS_BINARY_NUM_MODES; i++) { + for (b = binary_infos[i]; b; b = b->next) { + if (b->xmem_addr) + hrt_isp_css_mm_free(b->xmem_addr); + b->xmem_addr = NULL; + } + binary_infos[i] = NULL; + } + return sh_css_success; +} + +static bool +supports_output_format(const struct sh_css_binary_info *info, + enum sh_css_frame_format format) +{ + int i; + + for (i = 0; i < info->num_output_formats; i++) { + if (info->output_formats[i] == format) + return true; + } + return false; +} + +static int +sh_css_grid_deci_factor_log2(int width, int height) +{ + int fact, fact1; + fact = 5; + while (ISP_BQ_GRID_WIDTH(width, fact - 1) <= SH_CSS_MAX_BQ_GRID_WIDTH && + ISP_BQ_GRID_HEIGHT(height, fact - 1) <= SH_CSS_MAX_BQ_GRID_HEIGHT + && fact > 3) + fact--; + + /* fact1 satisfies the specification of grid size. fact and fact1 is + not the same for some resolution (fact=4 and fact1=5 for 5mp). */ + if (width >= 2560) + fact1 = 5; + else if (width >= 1280) + fact1 = 4; + else + fact1 = 3; + return max(fact, fact1); +} + +static enum sh_css_err +fill_binary_info(const struct sh_css_binary_info *info, + bool online, + bool two_ppc, + enum sh_css_input_format stream_format, + const struct sh_css_frame_info *in_info, + const struct sh_css_frame_info *out_info, + const struct sh_css_frame_info *vf_info, + struct sh_css_binary *binary) +{ + unsigned int dvs_env_width = 0, + dvs_env_height = 0, + vf_log_ds = 0, + s3a_log_deci = 0, + bits_per_pixel = in_info->raw_bit_depth, + ds_input_width = 0, + ds_input_height = 0, + isp_input_width, + isp_input_height, + isp_internal_width, + isp_internal_height, + isp_output_width = out_info->padded_width, + isp_output_height = out_info->height, + s3a_isp_width; + + if (info->enable_dvs_envelope) { + sh_css_video_get_dis_envelope(&dvs_env_width, &dvs_env_height); + dvs_env_width = MAX(dvs_env_width, SH_CSS_MIN_DVS_ENVELOPE); + dvs_env_height = MAX(dvs_env_height, SH_CSS_MIN_DVS_ENVELOPE); + binary->dvs_envelope_width = dvs_env_width; + binary->dvs_envelope_height = dvs_env_height; + } + if (vf_info) { + enum sh_css_err err; + err = sh_css_vf_downscale_log2(out_info, vf_info, &vf_log_ds); + if (err != sh_css_success) + return err; + vf_log_ds = min(vf_log_ds, info->max_vf_log_downscale); + } + if (online) { + bits_per_pixel = sh_css_input_format_bits_per_pixel( + stream_format, two_ppc); + } + if (info->enable_ds) { + ds_input_width = in_info->padded_width + info->left_cropping; + ds_input_height = in_info->height + info->top_cropping; + } + /* We first calculate the resolutions used by the ISP. After that, + * we use those resolutions to compute sizes for tables etc. */ + isp_internal_width = + __ISP_INTERNAL_WIDTH(isp_output_width, dvs_env_width, + info->left_cropping, info->mode, + info->c_subsampling, + info->output_num_chunks, info->pipelining); + isp_internal_height = + __ISP_INTERNAL_HEIGHT(isp_output_height, info->top_cropping, + dvs_env_height); + isp_input_width = _ISP_INPUT_WIDTH(isp_internal_width, + ds_input_width, info->enable_ds); + isp_input_height = _ISP_INPUT_HEIGHT(isp_internal_height, + ds_input_height, info->enable_ds); + + s3a_isp_width = _ISP_S3A_ISP_WIDTH(isp_input_width, + info->left_cropping); + if (info->fixed_s3a_deci_log) + s3a_log_deci = info->fixed_s3a_deci_log; + else + s3a_log_deci = sh_css_grid_deci_factor_log2(s3a_isp_width, + isp_input_height); + + binary->vf_downscale_log2 = vf_log_ds; + binary->deci_factor_log2 = s3a_log_deci; + binary->input_buf_vectors = + SH_CSS_NUM_INPUT_BUF_LINES * _ISP_VECS(isp_input_width); + binary->online = online; + binary->input_format = stream_format; + /* input info */ + binary->in_frame_info.format = in_info->format; + binary->in_frame_info.width = in_info->width + info->left_cropping + + dvs_env_width; + binary->in_frame_info.padded_width = isp_input_width; + binary->in_frame_info.height = isp_input_height; + binary->in_frame_info.raw_bit_depth = bits_per_pixel; + /* internal frame info */ + binary->internal_frame_info.format = out_info->format; + binary->internal_frame_info.width = isp_internal_width; + binary->internal_frame_info.padded_width = isp_internal_width; + binary->internal_frame_info.height = isp_internal_height; + binary->internal_frame_info.raw_bit_depth = bits_per_pixel; + /* output info */ + binary->out_frame_info.format = out_info->format; + binary->out_frame_info.width = out_info->width; + binary->out_frame_info.padded_width = isp_output_width; + binary->out_frame_info.height = isp_output_height; + binary->out_frame_info.raw_bit_depth = bits_per_pixel; + + /* viewfinder output info */ + binary->vf_frame_info.format = SH_CSS_FRAME_FORMAT_YUV_LINE; + if (vf_info) { + unsigned int vf_out_vecs, vf_out_width, vf_out_height; + vf_out_vecs = __ISP_VF_OUTPUT_WIDTH_VECS(isp_output_width, + vf_log_ds); + vf_out_width = _ISP_VF_OUTPUT_WIDTH(vf_out_vecs); + vf_out_height = _ISP_VF_OUTPUT_HEIGHT(isp_output_height, + vf_log_ds); + /* we also store the raw downscaled width. This is used for + * digital zoom in preview to zoom only on the width that + * we actually want to keep, not on the aligned width. */ + binary->vf_frame_info.width = (out_info->width >> vf_log_ds); + binary->vf_frame_info.padded_width = vf_out_width; + binary->vf_frame_info.height = vf_out_height; + } else { + binary->vf_frame_info.width = 0; + binary->vf_frame_info.padded_width = 0; + binary->vf_frame_info.height = 0; + } + if (info->mode == SH_CSS_BINARY_MODE_GDC) { + binary->morph_tbl_width = + _ISP_MORPH_TABLE_WIDTH(isp_internal_width); + binary->morph_tbl_aligned_width = + _ISP_MORPH_TABLE_ALIGNED_WIDTH(isp_internal_width); + binary->morph_tbl_height = + _ISP_MORPH_TABLE_HEIGHT(isp_internal_height); + } else { + binary->morph_tbl_width = 0; + binary->morph_tbl_aligned_width = 0; + binary->morph_tbl_height = 0; + } + if (info->enable_sc) + binary->sctbl_width_per_color = + SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR; + else + binary->sctbl_width_per_color = 0; + + if (info->enable_s3a) { + binary->s3atbl_width = + _ISP_S3ATBL_WIDTH(binary->in_frame_info.width, + s3a_log_deci); + binary->s3atbl_height = + _ISP_S3ATBL_HEIGHT(isp_input_height, s3a_log_deci); + binary->s3atbl_isp_width = + _ISP_S3ATBL_ISP_WIDTH(isp_input_width, s3a_log_deci, + info->left_cropping); + binary->s3atbl_isp_height = + _ISP_S3ATBL_ISP_HEIGHT(isp_input_height, s3a_log_deci); + } else { + binary->s3atbl_width = 0; + binary->s3atbl_height = 0; + binary->s3atbl_isp_width = 0; + binary->s3atbl_isp_height = 0; + } + + if (info->enable_sc) { + binary->sctbl_width_per_color = + _ISP_SCTBL_WIDTH_PER_COLOR(isp_input_width, + s3a_log_deci); + binary->sctbl_aligned_width_per_color = + SH_CSS_MAX_SCTBL_ALIGNED_WIDTH_PER_COLOR; + binary->sctbl_height = + _ISP_SCTBL_HEIGHT(isp_input_height, s3a_log_deci); + } else { + binary->sctbl_width_per_color = 0; + binary->sctbl_aligned_width_per_color = 0; + binary->sctbl_height = 0; + } + if (info->enable_dis) { + binary->dis_deci_factor_log2 = SH_CSS_DIS_DECI_FACTOR_LOG2; + binary->dis_hor_coef_num_3a = + _ISP_SDIS_HOR_COEF_NUM_3A(binary->in_frame_info.width, + SH_CSS_DIS_DECI_FACTOR_LOG2); + binary->dis_ver_coef_num_3a = + _ISP_SDIS_VER_COEF_NUM_3A(isp_input_height, + SH_CSS_DIS_DECI_FACTOR_LOG2); + binary->dis_hor_coef_num_isp = + _ISP_SDIS_HOR_COEF_NUM_ISP(isp_input_width); + binary->dis_ver_coef_num_isp = + _ISP_SDIS_VER_COEF_NUM_ISP(isp_input_height); + binary->dis_hor_proj_num_3a = + _ISP_SDIS_HOR_PROJ_NUM_3A(isp_input_height, + SH_CSS_DIS_DECI_FACTOR_LOG2); + binary->dis_ver_proj_num_3a = + _ISP_SDIS_VER_PROJ_NUM_3A(binary->in_frame_info.width, + SH_CSS_DIS_DECI_FACTOR_LOG2); + binary->dis_hor_proj_num_isp = + __ISP_SDIS_HOR_PROJ_NUM_ISP(isp_input_height, + SH_CSS_DIS_DECI_FACTOR_LOG2); + binary->dis_ver_proj_num_isp = + __ISP_SDIS_VER_PROJ_NUM_ISP(isp_input_width, + SH_CSS_DIS_DECI_FACTOR_LOG2); + } else { + binary->dis_deci_factor_log2 = 0; + binary->dis_hor_coef_num_3a = 0; + binary->dis_ver_coef_num_3a = 0; + binary->dis_hor_coef_num_isp = 0; + binary->dis_ver_coef_num_isp = 0; + binary->dis_hor_proj_num_3a = 0; + binary->dis_ver_proj_num_3a = 0; + binary->dis_hor_proj_num_isp = 0; + binary->dis_ver_proj_num_isp = 0; + } + if (info->left_cropping) + binary->left_padding = 2 * ISP_VEC_NELEMS - info->left_cropping; + else + binary->left_padding = 0; + + binary->info = info; + return sh_css_success; +} +enum sh_css_err +sh_css_binary_find(struct sh_css_binary_descr *descr, + struct sh_css_binary *binary) +{ + int mode = descr->mode; + bool online = descr->online; + bool two_ppc = descr->two_ppc; + enum sh_css_input_format stream_format = descr->stream_format; + const struct sh_css_frame_info *req_in_info = descr->in_info, + *req_out_info = descr->out_info, + *req_vf_info = descr->vf_info; + struct sh_css_binary_info *candidate; + unsigned int dvs_envelope_width = 0, + dvs_envelope_height = 0; + bool need_ds = false, + need_dz = false, + need_dvs = false; + enum sh_css_err err = sh_css_success; + + if (mode == SH_CSS_BINARY_MODE_VIDEO) { + unsigned int dx, dy; + sh_css_get_zoom_factor(&dx, &dy); + sh_css_video_get_dis_envelope(&dvs_envelope_width, + &dvs_envelope_height); + + /* Video is the only mode that has a nodz variant. */ + need_dz = (dx != 64 || dy != 64); + need_dvs = dvs_envelope_width || dvs_envelope_height; + } + + need_ds = req_in_info->width > req_out_info->width || + req_in_info->height > req_out_info->height; + + for (candidate = binary_infos[mode]; candidate; + candidate = candidate->next) { + if (candidate->enable_vf_veceven && !req_vf_info) + continue; + if (req_vf_info && !(candidate->enable_vf_veceven || + candidate->variable_vf_veceven)) + continue; + if (!candidate->enable_dvs_envelope && need_dvs) + continue; + if (dvs_envelope_width > candidate->max_dvs_envelope_width) + continue; + if (dvs_envelope_height > candidate->max_dvs_envelope_height) + continue; + if (!candidate->enable_ds && need_ds) + continue; + if (!candidate->enable_uds && need_dz) + continue; + if (online && candidate->input == SH_CSS_BINARY_INPUT_MEMORY) + continue; + if (!online && candidate->input == SH_CSS_BINARY_INPUT_SENSOR) + continue; + if (req_out_info->padded_width < candidate->min_output_width || + req_out_info->padded_width > candidate->max_output_width) + continue; + + if (req_in_info->padded_width > candidate->max_input_width) + continue; + + if (!supports_output_format(candidate, req_out_info->format)) + continue; + + /* reconfigure any variable properties of the binary */ + err = fill_binary_info(candidate, online, two_ppc, + stream_format, req_in_info, + req_out_info, req_vf_info, + binary); + if (err) + return err; + init_metrics(&binary->metrics, binary->info->id); + return sh_css_success; + } + return sh_css_err_internal_error; +} diff --git a/drivers/media/video/atomisp/css/sh_css_binary.h b/drivers/media/video/atomisp/css/sh_css_binary.h new file mode 100644 index 0000000..c3e4b67 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_binary.h @@ -0,0 +1,189 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_BINARY_H_ +#define _SH_CSS_BINARY_H_ + +#include "sh_css_types.h" +#include "sh_css_metrics.h" + +/* The binary mode is used in pre-processor expressions so we cannot + * use an enum here. */ +#define SH_CSS_BINARY_MODE_COPY 0 +#define SH_CSS_BINARY_MODE_PREVIEW 1 +#define SH_CSS_BINARY_MODE_PRIMARY 2 +#define SH_CSS_BINARY_MODE_VIDEO 3 +#define SH_CSS_BINARY_MODE_PRE_GDC 4 +#define SH_CSS_BINARY_MODE_GDC 5 +#define SH_CSS_BINARY_MODE_POST_GDC 6 +#define SH_CSS_BINARY_MODE_PRE_ANR 7 +#define SH_CSS_BINARY_MODE_ANR 8 +#define SH_CSS_BINARY_MODE_POST_ANR 9 +#define SH_CSS_BINARY_MODE_CAPTURE_PP 10 +#define SH_CSS_BINARY_MODE_BAYER_DS 11 +#define SH_CSS_BINARY_MODE_VF_PP 12 +#define SH_CSS_BINARY_NUM_MODES 13 +#define SH_CSS_BINARY_MODE_NONE 14 + +/* Indicate where binaries can read input from */ +#define SH_CSS_BINARY_INPUT_SENSOR 0 +#define SH_CSS_BINARY_INPUT_MEMORY 1 +#define SH_CSS_BINARY_INPUT_VARIABLE 2 + +/* ISP binary identifiers. + these determine the order in which the binaries are looked up, do not change + this! + Also, the SP firmware uses this same order (sp_main_funcs in sp.hive.c). + Also, gen_firmware.c uses this order in its firmware_header. +*/ +enum sh_css_binary_id { + SH_CSS_BINARY_ID_COPY, + SH_CSS_BINARY_ID_BAYER_DS, + SH_CSS_BINARY_ID_VF_PP, + SH_CSS_BINARY_ID_CAPTURE_PP, + SH_CSS_BINARY_ID_PRE_GDC, + SH_CSS_BINARY_ID_GDC, + SH_CSS_BINARY_ID_POST_GDC, + SH_CSS_BINARY_ID_PRE_ANR, + SH_CSS_BINARY_ID_ANR, + SH_CSS_BINARY_ID_POST_ANR, + SH_CSS_BINARY_ID_PREVIEW_DS, + SH_CSS_BINARY_ID_PREVIEW_DZ, + SH_CSS_BINARY_ID_PRIMARY_DS, + SH_CSS_BINARY_ID_PRIMARY_VAR, + SH_CSS_BINARY_ID_PRIMARY_8MP, + SH_CSS_BINARY_ID_PRIMARY_14MP, + SH_CSS_BINARY_ID_PRIMARY_16MP, + SH_CSS_BINARY_ID_PRIMARY_SMALL, + SH_CSS_BINARY_ID_PRIMARY_REF, + SH_CSS_BINARY_ID_VIDEO_OFFLINE, + SH_CSS_BINARY_ID_VIDEO_DS, + SH_CSS_BINARY_ID_VIDEO_DZ, + SH_CSS_BINARY_ID_VIDEO_NODZ, + SH_CSS_BINARY_NUM_IDS, +}; + +#define SH_CSS_BINARY_ID(BINARY) SH_CSS_BINARY_##BINARY +/* The maximum number of different frame formats any binary can support */ +#define SH_CSS_MAX_NUM_FRAME_FORMATS 18 + +struct sh_css_binary_descr { + int mode; + bool online; + bool continuous; + bool two_ppc; + enum sh_css_input_format stream_format; + struct sh_css_frame_info *in_info; + struct sh_css_frame_info *out_info; + struct sh_css_frame_info *vf_info; +}; + +struct sh_css_binary; + +struct sh_css_binary_info { + enum sh_css_binary_id id; + int mode; + int num_output_formats; + enum sh_css_frame_format output_formats[SH_CSS_MAX_NUM_FRAME_FORMATS]; + unsigned int max_input_width; + unsigned int min_output_width; + unsigned int max_output_width; + unsigned int max_dvs_envelope_width; + unsigned int max_dvs_envelope_height; + bool variable_vf_veceven; + unsigned int max_vf_log_downscale; + bool enable_vf_veceven; + bool enable_dis; + bool enable_dvs_envelope; + bool enable_uds; + bool enable_ds; + bool enable_s3a; + bool enable_fpnr; + bool enable_sc; + unsigned int top_cropping; + unsigned int left_cropping; + int s3atbl_use_dmem; + int input; + void *xmem_addr; + unsigned int c_subsampling; + unsigned int output_num_chunks; + unsigned int pipelining; + unsigned int fixed_s3a_deci_log; + struct sh_css_binary_info *next; +}; + +struct sh_css_binary { + const struct sh_css_binary_info *info; + enum sh_css_input_format input_format; + struct sh_css_frame_info in_frame_info; + struct sh_css_frame_info internal_frame_info; + struct sh_css_frame_info out_frame_info; + struct sh_css_frame_info vf_frame_info; + int input_buf_vectors; + int deci_factor_log2; + int dis_deci_factor_log2; + int vf_downscale_log2; + int s3atbl_width; + int s3atbl_height; + int s3atbl_isp_width; + int s3atbl_isp_height; + unsigned int morph_tbl_width; + unsigned int morph_tbl_aligned_width; + unsigned int morph_tbl_height; + int sctbl_width_per_color; + int sctbl_aligned_width_per_color; + int sctbl_height; + int dis_hor_coef_num_3a; + int dis_ver_coef_num_3a; + int dis_hor_coef_num_isp; + int dis_ver_coef_num_isp; + int dis_hor_proj_num_3a; + int dis_ver_proj_num_3a; + int dis_hor_proj_num_isp; + int dis_ver_proj_num_isp; + unsigned int dvs_envelope_width; + unsigned int dvs_envelope_height; + bool online; + unsigned int uds_xc; + unsigned int uds_yc; + unsigned int left_padding; + struct sh_css_binary_metrics metrics; +}; + +enum sh_css_err +sh_css_init_binary_infos(void); + +enum sh_css_err +sh_css_binary_uninit(void); + +enum sh_css_err +sh_css_binary_find(struct sh_css_binary_descr *descr, + struct sh_css_binary *binary); + +enum sh_css_err +sh_css_binary_grid_info(struct sh_css_binary *binary, + struct sh_css_grid_info *info); + +void sh_css_binary_init(struct sh_css_binary *binary); + +#endif /* _SH_CSS_BINARY_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_binary_info.h b/drivers/media/video/atomisp/css/sh_css_binary_info.h new file mode 100644 index 0000000..46f486e --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_binary_info.h @@ -0,0 +1,741 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_BINARY_INFO_H_ +#define _SH_CSS_BINARY_INFO_H_ + +#include "sh_css_defs.h" + +/* Bayer DS */ +#define ISP_BAYER_DS_BINARY_ID SH_CSS_BINARY_ID_BAYER_DS +#define ISP_BAYER_DS_BINARY isp_bayer_ds_var +#define ISP_BAYER_DS_MODE SH_CSS_BINARY_MODE_BAYER_DS +#define ISP_BAYER_DS_OUTPUT_FRAME_FORMAT SH_CSS_FRAME_FORMAT_RAW +#define ISP_BAYER_DS_ENABLE_DS 1 +#define ISP_BAYER_DS_ENABLE_FPNR 0 +#define ISP_BAYER_DS_ENABLE_SC 0 +#define ISP_BAYER_DS_ENABLE_S3A 0 +#define ISP_BAYER_DS_ENABLE_SDIS 0 +#define ISP_BAYER_DS_ENABLE_VF_VECEVEN 0 +#define ISP_BAYER_DS_ENABLE_UDS 0 +#define ISP_BAYER_DS_PIPELINING 1 +#define ISP_BAYER_DS_OUTPUT_NUM_CHUNKS 1 +#define ISP_BAYER_DS_DUMMY_BUF_VECTORS 0 +#define ISP_BAYER_DS_LEFT_CROPPING 0 +#define ISP_BAYER_DS_TOP_CROPPING 0 +#define ISP_BAYER_DS_ENABLE_DVS_ENVELOPE 0 +#define ISP_BAYER_DS_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_BAYER_DS_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_BAYER_DS_MAX_OUTPUT_WIDTH SH_CSS_MAX_SENSOR_WIDTH +#define ISP_BAYER_DS_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_BAYER_DS_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_BAYER_DS_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_BAYER_DS_OUTPUT_FORMATS { SH_CSS_FRAME_FORMAT_RAW } +#define ISP_BAYER_DS_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_BAYER_DS_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_BAYER_DS_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_BAYER_DS_FIXED_S3A_DECI_LOG 0 + +/* Capture PP */ +#define ISP_CAPTURE_PP_BINARY_ID SH_CSS_BINARY_ID_CAPTURE_PP +#define ISP_CAPTURE_PP_BINARY isp_capture_pp_var +#define ISP_CAPTURE_PP_MODE SH_CSS_BINARY_MODE_CAPTURE_PP +#define ISP_CAPTURE_PP_ENABLE_UDS 1 +#define ISP_CAPTURE_PP_ENABLE_DS 1 +#define ISP_CAPTURE_PP_ENABLE_VF_VECEVEN 1 +#define ISP_CAPTURE_PP_ENABLE_FPNR 0 +#define ISP_CAPTURE_PP_ENABLE_SC 0 +#define ISP_CAPTURE_PP_ENABLE_S3A 0 +#define ISP_CAPTURE_PP_ENABLE_SDIS 0 +#define ISP_CAPTURE_PP_PIPELINING 1 +#define ISP_CAPTURE_PP_OUTPUT_NUM_CHUNKS 2 +#define ISP_CAPTURE_PP_DUMMY_BUF_VECTORS 0 +#define ISP_CAPTURE_PP_LEFT_CROPPING 0 +#define ISP_CAPTURE_PP_TOP_CROPPING 0 +#define ISP_CAPTURE_PP_ENABLE_DVS_ENVELOPE 0 +#define ISP_CAPTURE_PP_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_CAPTURE_PP_MAX_DVS_ENVELOPE_HEIGHT 0 +/* max width currently limited because of VMEM shortage */ +#define ISP_CAPTURE_PP_MAX_OUTPUT_WIDTH MAX(4480, SH_CSS_MAX_SENSOR_WIDTH) +#define ISP_CAPTURE_PP_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_CAPTURE_PP_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_CAPTURE_PP_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_CAPTURE_PP_OUTPUT_FORMATS SH_CSS_CAPTURE_OUTPUT_FORMATS +#define ISP_CAPTURE_PP_MAX_VF_LOG_DOWNSCALE 1 +#define ISP_CAPTURE_PP_INPUT SH_CSS_BINARY_INPUT_MEMORY +#define ISP_CAPTURE_PP_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_CAPTURE_PP_FIXED_S3A_DECI_LOG 0 + +/* Copy */ +#define ISP_COPY_BINARY_ID SH_CSS_BINARY_ID_COPY +#define ISP_COPY_MODE SH_CSS_BINARY_MODE_COPY +#define ISP_COPY_BINARY isp_copy_var +#define ISP_COPY_ENABLE_DS 0 +#define ISP_COPY_ENABLE_FPNR 0 +#define ISP_COPY_ENABLE_SC 0 +#define ISP_COPY_ENABLE_S3A 0 +#define ISP_COPY_ENABLE_SDIS 0 +#define ISP_COPY_ENABLE_VF_VECEVEN 0 +#define ISP_COPY_ENABLE_UDS 0 +#define ISP_COPY_PIPELINING 1 +#define ISP_COPY_OUTPUT_NUM_CHUNKS 1 +#define ISP_COPY_DUMMY_BUF_VECTORS 0 +#define ISP_COPY_LEFT_CROPPING 0 +#define ISP_COPY_TOP_CROPPING 0 +#define ISP_COPY_ENABLE_DVS_ENVELOPE 0 +#define ISP_COPY_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_COPY_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_COPY_MAX_VF_LOG_DOWNSCALE 2 +#define ISP_COPY_MAX_OUTPUT_WIDTH SH_CSS_MAX_SENSOR_WIDTH +#define ISP_COPY_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_COPY_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_COPY_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_COPY_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_COPY_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_COPY_FIXED_S3A_DECI_LOG 0 +#define ISP_COPY_OUTPUT_FORMATS \ + { \ + SH_CSS_FRAME_FORMAT_NV11, \ + SH_CSS_FRAME_FORMAT_NV12, \ + SH_CSS_FRAME_FORMAT_NV16, \ + SH_CSS_FRAME_FORMAT_NV21, \ + SH_CSS_FRAME_FORMAT_NV61, \ + SH_CSS_FRAME_FORMAT_YV12, \ + SH_CSS_FRAME_FORMAT_YV16, \ + SH_CSS_FRAME_FORMAT_YUV420, \ + SH_CSS_FRAME_FORMAT_YUV420_16, \ + SH_CSS_FRAME_FORMAT_YUV422, \ + SH_CSS_FRAME_FORMAT_YUV422_16, \ + SH_CSS_FRAME_FORMAT_YUV_LINE, \ + SH_CSS_FRAME_FORMAT_RAW, \ + SH_CSS_FRAME_FORMAT_UYVY, \ + SH_CSS_FRAME_FORMAT_YUYV, \ + SH_CSS_FRAME_FORMAT_RGB565, \ + SH_CSS_FRAME_FORMAT_PLANAR_RGB888, \ + SH_CSS_FRAME_FORMAT_RGBA888 \ + } + +/* GDC */ +#define ISP_GDC_BINARY_ID SH_CSS_BINARY_ID_GDC +#define ISP_GDC_BINARY isp_gdc_var +#define ISP_GDC_MODE SH_CSS_BINARY_MODE_GDC +#define ISP_GDC_OUTPUT_NUM_CHUNKS 2 +#define ISP_GDC_ENABLE_DS 0 +#define ISP_GDC_ENABLE_FPNR 0 +#define ISP_GDC_ENABLE_SC 0 +#define ISP_GDC_ENABLE_S3A 0 +#define ISP_GDC_ENABLE_SDIS 0 +#define ISP_GDC_ENABLE_VF_VECEVEN 0 +#define ISP_GDC_ENABLE_UDS 0 +#define ISP_GDC_PIPELINING 1 +#define ISP_GDC_DUMMY_BUF_VECTORS 0 +#define ISP_GDC_LEFT_CROPPING 0 +#define ISP_GDC_TOP_CROPPING 0 +#define ISP_GDC_ENABLE_DVS_ENVELOPE 0 +#define ISP_GDC_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_GDC_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_GDC_MAX_OUTPUT_WIDTH SH_CSS_MAX_SENSOR_WIDTH +#define ISP_GDC_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_GDC_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_GDC_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_GDC_OUTPUT_FORMATS { SH_CSS_FRAME_FORMAT_YUV420_16 } +#define ISP_GDC_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_GDC_INPUT SH_CSS_BINARY_INPUT_MEMORY +#define ISP_GDC_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_GDC_FIXED_S3A_DECI_LOG 0 + +/* Post GDC */ +#define ISP_POST_GDC_BINARY_ID SH_CSS_BINARY_ID_POST_GDC +#define ISP_POST_GDC_BINARY isp_postgdc_var +#define ISP_POST_GDC_MODE SH_CSS_BINARY_MODE_POST_GDC +#define ISP_POST_GDC_PIPELINING 2 +#define ISP_POST_GDC_ENABLE_VF_VECEVEN 1 +#define ISP_POST_GDC_ENABLE_DS 0 +#define ISP_POST_GDC_ENABLE_FPNR 0 +#define ISP_POST_GDC_ENABLE_SC 0 +#define ISP_POST_GDC_ENABLE_S3A 0 +#define ISP_POST_GDC_ENABLE_SDIS 0 +#define ISP_POST_GDC_ENABLE_UDS 0 +#define ISP_POST_GDC_OUTPUT_NUM_CHUNKS 1 +#define ISP_POST_GDC_DUMMY_BUF_VECTORS 0 +#define ISP_POST_GDC_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_POST_GDC_TOP_CROPPING 8 +#define ISP_POST_GDC_ENABLE_DVS_ENVELOPE 0 +#define ISP_POST_GDC_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_POST_GDC_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_POST_GDC_MAX_VF_LOG_DOWNSCALE 2 +/* limited due to VMEM shortage */ +#define ISP_POST_GDC_MAX_OUTPUT_WIDTH 4352 /* was 4416 */ +#define ISP_POST_GDC_MAX_OUTPUT_HEIGHT 3312 +#define ISP_POST_GDC_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_POST_GDC_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_POST_GDC_OUTPUT_FORMATS SH_CSS_CAPTURE_OUTPUT_FORMATS +#define ISP_POST_GDC_INPUT SH_CSS_BINARY_INPUT_MEMORY +#define ISP_POST_GDC_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_POST_GDC_FIXED_S3A_DECI_LOG 0 + +/* Pre GDC */ +#define ISP_PRE_GDC_BINARY_ID SH_CSS_BINARY_ID_PRE_GDC +#define ISP_PRE_GDC_BINARY isp_pregdc_var +#define ISP_PRE_GDC_MODE SH_CSS_BINARY_MODE_PRE_GDC +#define ISP_PRE_GDC_ENABLE_FPNR 1 +#define ISP_PRE_GDC_ENABLE_SC 1 +#define ISP_PRE_GDC_ENABLE_S3A 1 +#define ISP_PRE_GDC_ENABLE_SDIS 1 +#define ISP_PRE_GDC_ENABLE_DS 0 +#define ISP_PRE_GDC_ENABLE_VF_VECEVEN 0 +#define ISP_PRE_GDC_ENABLE_UDS 0 +#define ISP_PRE_GDC_PIPELINING 1 +#define ISP_PRE_GDC_OUTPUT_NUM_CHUNKS 1 +#define ISP_PRE_GDC_DUMMY_BUF_VECTORS 0 +#define ISP_PRE_GDC_LEFT_CROPPING 0 +#define ISP_PRE_GDC_TOP_CROPPING 0 +#define ISP_PRE_GDC_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRE_GDC_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRE_GDC_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRE_GDC_MAX_OUTPUT_WIDTH SH_CSS_MAX_SENSOR_WIDTH +#define ISP_PRE_GDC_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRE_GDC_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PRE_GDC_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PRE_GDC_OUTPUT_FORMATS { SH_CSS_FRAME_FORMAT_QPLANE6 } +#define ISP_PRE_GDC_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_PRE_GDC_INPUT SH_CSS_BINARY_INPUT_VARIABLE +#define ISP_PRE_GDC_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PRE_GDC_FIXED_S3A_DECI_LOG 0 + +/* ANR */ +#define ISP_ANR_BINARY_ID SH_CSS_BINARY_ID_ANR +#define ISP_ANR_BINARY isp_anr_var +#define ISP_ANR_MODE SH_CSS_BINARY_MODE_ANR +#define ISP_ANR_OUTPUT_NUM_CHUNKS 1 +#define ISP_ANR_ENABLE_DS 0 +#define ISP_ANR_ENABLE_FPNR 0 +#define ISP_ANR_ENABLE_SC 0 +#define ISP_ANR_ENABLE_S3A 0 +#define ISP_ANR_ENABLE_SDIS 0 +#define ISP_ANR_ENABLE_VF_VECEVEN 0 +#define ISP_ANR_ENABLE_UDS 0 +#define ISP_ANR_PIPELINING 1 +#define ISP_ANR_DUMMY_BUF_VECTORS 0 +#define ISP_ANR_LEFT_CROPPING 0 +#define ISP_ANR_TOP_CROPPING 0 +#define ISP_ANR_ENABLE_DVS_ENVELOPE 0 +#define ISP_ANR_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_ANR_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_ANR_MAX_OUTPUT_WIDTH 3264 +#define ISP_ANR_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_ANR_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_ANR_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_ANR_OUTPUT_FORMATS { SH_CSS_FRAME_FORMAT_RAW } +#define ISP_ANR_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_ANR_INPUT SH_CSS_BINARY_INPUT_MEMORY +#define ISP_ANR_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_ANR_FIXED_S3A_DECI_LOG 0 + +/* Post ANR */ +#define ISP_POST_ANR_BINARY_ID SH_CSS_BINARY_ID_POST_ANR +#define ISP_POST_ANR_BINARY isp_postanr_var +#define ISP_POST_ANR_MODE SH_CSS_BINARY_MODE_POST_ANR +#define ISP_POST_ANR_PIPELINING 2 +#define ISP_POST_ANR_ENABLE_VF_VECEVEN 1 +#define ISP_POST_ANR_ENABLE_DS 0 +#define ISP_POST_ANR_ENABLE_FPNR 0 +#define ISP_POST_ANR_ENABLE_SC 0 +#define ISP_POST_ANR_ENABLE_S3A 0 +#define ISP_POST_ANR_ENABLE_SDIS 0 +#define ISP_POST_ANR_ENABLE_UDS 0 +#define ISP_POST_ANR_OUTPUT_NUM_CHUNKS 1 +#define ISP_POST_ANR_DUMMY_BUF_VECTORS 0 +#define ISP_POST_ANR_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_POST_ANR_TOP_CROPPING 8 +#define ISP_POST_ANR_ENABLE_DVS_ENVELOPE 0 +#define ISP_POST_ANR_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_POST_ANR_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_POST_ANR_MAX_VF_LOG_DOWNSCALE 2 +/* limited due to VMEM shortage */ +#define ISP_POST_ANR_MAX_OUTPUT_WIDTH 3264 +#define ISP_POST_ANR_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_POST_ANR_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_POST_ANR_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_POST_ANR_OUTPUT_FORMATS SH_CSS_CAPTURE_OUTPUT_FORMATS +#define ISP_POST_ANR_INPUT SH_CSS_BINARY_INPUT_MEMORY +#define ISP_POST_ANR_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_POST_ANR_FIXED_S3A_DECI_LOG 0 + +/* Pre ANR */ +#define ISP_PRE_ANR_BINARY_ID SH_CSS_BINARY_ID_PRE_ANR +#define ISP_PRE_ANR_BINARY isp_preanr_var +#define ISP_PRE_ANR_MODE SH_CSS_BINARY_MODE_PRE_ANR +#define ISP_PRE_ANR_ENABLE_FPNR 1 +#define ISP_PRE_ANR_ENABLE_SC 1 +#define ISP_PRE_ANR_ENABLE_S3A 1 +#define ISP_PRE_ANR_ENABLE_SDIS 1 +#define ISP_PRE_ANR_ENABLE_DS 0 +#define ISP_PRE_ANR_ENABLE_VF_VECEVEN 0 +#define ISP_PRE_ANR_ENABLE_UDS 0 +#define ISP_PRE_ANR_PIPELINING 1 +#define ISP_PRE_ANR_OUTPUT_NUM_CHUNKS 1 +#define ISP_PRE_ANR_DUMMY_BUF_VECTORS 0 +#define ISP_PRE_ANR_LEFT_CROPPING 0 +#define ISP_PRE_ANR_TOP_CROPPING 0 +#define ISP_PRE_ANR_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRE_ANR_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRE_ANR_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRE_ANR_MAX_OUTPUT_WIDTH SH_CSS_MAX_SENSOR_WIDTH +#define ISP_PRE_ANR_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRE_ANR_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PRE_ANR_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PRE_ANR_OUTPUT_FORMATS { SH_CSS_FRAME_FORMAT_RAW } +#define ISP_PRE_ANR_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_PRE_ANR_INPUT SH_CSS_BINARY_INPUT_VARIABLE +#define ISP_PRE_ANR_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PRE_ANR_FIXED_S3A_DECI_LOG 0 + +/* Preview DS */ +#define ISP_PREVIEW_DS_BINARY_ID SH_CSS_BINARY_ID_PREVIEW_DS +#define ISP_PREVIEW_DS_BINARY isp_preview_ds +#define ISP_PREVIEW_DS_MODE SH_CSS_BINARY_MODE_PREVIEW +#define ISP_PREVIEW_DS_OUTPUT_NUM_CHUNKS 2 +#define ISP_PREVIEW_DS_DUMMY_BUF_VECTORS 2 +#define ISP_PREVIEW_DS_PIPELINING 2 +#define ISP_PREVIEW_DS_ENABLE_SC 1 +#define ISP_PREVIEW_DS_ENABLE_S3A 1 +#define ISP_PREVIEW_DS_ENABLE_VF_VECEVEN 1 +#define ISP_PREVIEW_DS_ENABLE_DS 1 +#define ISP_PREVIEW_DS_ENABLE_FPNR 0 +#define ISP_PREVIEW_DS_ENABLE_SDIS 0 +#define ISP_PREVIEW_DS_ENABLE_UDS 0 +#define ISP_PREVIEW_DS_LEFT_CROPPING 0 +#define ISP_PREVIEW_DS_TOP_CROPPING 8 +#define ISP_PREVIEW_DS_ENABLE_DVS_ENVELOPE 0 +#define ISP_PREVIEW_DS_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PREVIEW_DS_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PREVIEW_DS_MAX_OUTPUT_WIDTH \ + __ISP_MAX_VF_OUTPUT_WIDTH(2*SH_CSS_MAX_VF_WIDTH, \ + ISP_PREVIEW_DS_LEFT_CROPPING) +#define ISP_PREVIEW_DS_MAX_OUTPUT_HEIGHT SH_CSS_MAX_VF_HEIGHT +#define ISP_PREVIEW_DS_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PREVIEW_DS_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PREVIEW_DS_OUTPUT_FORMATS { SH_CSS_FRAME_FORMAT_YUV_LINE } +#define ISP_PREVIEW_DS_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_PREVIEW_DS_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_PREVIEW_DS_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PREVIEW_DS_FIXED_S3A_DECI_LOG 0 + +/* Preview DZ */ +#define ISP_PREVIEW_DZ_BINARY_ID SH_CSS_BINARY_ID_PREVIEW_DZ +#define ISP_PREVIEW_DZ_BINARY isp_preview_var +#define ISP_PREVIEW_DZ_MODE SH_CSS_BINARY_MODE_PREVIEW +#define ISP_PREVIEW_DZ_PIPELINING 3 +#define ISP_PREVIEW_DZ_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_PREVIEW_DZ_ENABLE_VF_VECEVEN 1 +#define ISP_PREVIEW_DZ_ENABLE_UDS 0 +#define ISP_PREVIEW_DZ_ENABLE_SC 1 +#define ISP_PREVIEW_DZ_ENABLE_S3A 1 +#define ISP_PREVIEW_DZ_ENABLE_DS 0 +#define ISP_PREVIEW_DZ_ENABLE_FPNR 0 +#define ISP_PREVIEW_DZ_ENABLE_SDIS 0 +#define ISP_PREVIEW_DZ_OUTPUT_NUM_CHUNKS 1 +#define ISP_PREVIEW_DZ_DUMMY_BUF_VECTORS 0 +#define ISP_PREVIEW_DZ_TOP_CROPPING 8 +#define ISP_PREVIEW_DZ_ENABLE_DVS_ENVELOPE 0 +#define ISP_PREVIEW_DZ_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PREVIEW_DZ_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PREVIEW_DZ_MAX_OUTPUT_WIDTH \ + __ISP_MAX_VF_OUTPUT_WIDTH(2*SH_CSS_MAX_VF_WIDTH, \ + ISP_PREVIEW_DZ_LEFT_CROPPING) +#define ISP_PREVIEW_DZ_MAX_OUTPUT_HEIGHT SH_CSS_MAX_VF_HEIGHT +#define ISP_PREVIEW_DZ_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PREVIEW_DZ_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PREVIEW_DZ_OUTPUT_FORMATS { SH_CSS_FRAME_FORMAT_YUV_LINE } +#define ISP_PREVIEW_DZ_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_PREVIEW_DZ_INPUT SH_CSS_BINARY_INPUT_VARIABLE +#define ISP_PREVIEW_DZ_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PREVIEW_DZ_FIXED_S3A_DECI_LOG 0 + +/* Primary 14MP */ +#define ISP_PRIMARY_14MP_BINARY_ID SH_CSS_BINARY_ID_PRIMARY_14MP +#define ISP_PRIMARY_14MP_BINARY isp_primary_14mp +#define ISP_PRIMARY_14MP_MODE SH_CSS_BINARY_MODE_PRIMARY +#define ISP_PRIMARY_14MP_VF_LOG_DOWNSCALE 2 +#define ISP_PRIMARY_14MP_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_PRIMARY_14MP_PIPELINING 4 +#define ISP_PRIMARY_14MP_ENABLE_VF_VECEVEN 1 +#define ISP_PRIMARY_14MP_ENABLE_FPNR 1 +#define ISP_PRIMARY_14MP_ENABLE_SC 1 +#define ISP_PRIMARY_14MP_ENABLE_S3A 1 +#define ISP_PRIMARY_14MP_ENABLE_DS 0 +#define ISP_PRIMARY_14MP_ENABLE_SDIS 0 +#define ISP_PRIMARY_14MP_ENABLE_UDS 0 +#define ISP_PRIMARY_14MP_OUTPUT_NUM_CHUNKS 1 +#define ISP_PRIMARY_14MP_DUMMY_BUF_VECTORS 0 +#define ISP_PRIMARY_14MP_TOP_CROPPING 8 +#define ISP_PRIMARY_14MP_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRIMARY_14MP_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRIMARY_14MP_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRIMARY_14MP_MAX_OUTPUT_WIDTH 4352 +#define ISP_PRIMARY_14MP_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRIMARY_14MP_MIN_OUTPUT_WIDTH ISP_PRIMARY_14MP_MAX_OUTPUT_WIDTH +#define ISP_PRIMARY_14MP_MIN_OUTPUT_HEIGHT ISP_PRIMARY_14MP_MAX_OUTPUT_HEIGHT +#define ISP_PRIMARY_14MP_OUTPUT_FORMATS { SH_CSS_FIXED_PRIMARY_FORMAT } +#define ISP_PRIMARY_14MP_MAX_VF_LOG_DOWNSCALE ISP_PRIMARY_14MP_VF_LOG_DOWNSCALE +#define ISP_PRIMARY_14MP_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_PRIMARY_14MP_C_SUBSAMPLING 1 +#define ISP_PRIMARY_14MP_FIXED_S3A_DECI_LOG 6 + +/* Primary 16MP */ +#define ISP_PRIMARY_16MP_BINARY_ID SH_CSS_BINARY_ID_PRIMARY_16MP +#define ISP_PRIMARY_16MP_BINARY isp_primary_16mp +#define ISP_PRIMARY_16MP_MODE SH_CSS_BINARY_MODE_PRIMARY +#define ISP_PRIMARY_16MP_VF_LOG_DOWNSCALE 2 +#define ISP_PRIMARY_16MP_PIPELINING 4 +#define ISP_PRIMARY_16MP_ENABLE_FPNR 1 +#define ISP_PRIMARY_16MP_ENABLE_SC 1 +#define ISP_PRIMARY_16MP_ENABLE_S3A 1 +#define ISP_PRIMARY_16MP_ENABLE_VF_VECEVEN 1 +#define ISP_PRIMARY_16MP_ENABLE_DS 0 +#define ISP_PRIMARY_16MP_ENABLE_SDIS 0 +#define ISP_PRIMARY_16MP_ENABLE_UDS 0 +#define ISP_PRIMARY_16MP_OUTPUT_NUM_CHUNKS 1 +#define ISP_PRIMARY_16MP_DUMMY_BUF_VECTORS 0 +#define ISP_PRIMARY_16MP_LEFT_CROPPING 0 +#define ISP_PRIMARY_16MP_TOP_CROPPING 8 +#define ISP_PRIMARY_16MP_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRIMARY_16MP_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRIMARY_16MP_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRIMARY_16MP_MAX_OUTPUT_WIDTH 4608 +#define ISP_PRIMARY_16MP_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRIMARY_16MP_MIN_OUTPUT_WIDTH ISP_PRIMARY_16MP_MAX_OUTPUT_WIDTH +#define ISP_PRIMARY_16MP_MIN_OUTPUT_HEIGHT ISP_PRIMARY_16MP_MAX_OUTPUT_HEIGHT +#define ISP_PRIMARY_16MP_OUTPUT_FORMATS { SH_CSS_FIXED_PRIMARY_FORMAT } +#define ISP_PRIMARY_16MP_MAX_VF_LOG_DOWNSCALE ISP_PRIMARY_16MP_VF_LOG_DOWNSCALE +#define ISP_PRIMARY_16MP_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_PRIMARY_16MP_C_SUBSAMPLING 1 +#define ISP_PRIMARY_16MP_FIXED_S3A_DECI_LOG 6 + +/* Primary 8MP */ +#define ISP_PRIMARY_8MP_BINARY_ID SH_CSS_BINARY_ID_PRIMARY_8MP +#define ISP_PRIMARY_8MP_BINARY isp_primary_8mp +#define ISP_PRIMARY_8MP_MODE SH_CSS_BINARY_MODE_PRIMARY +#define ISP_PRIMARY_8MP_VF_LOG_DOWNSCALE 1 +#define ISP_PRIMARY_8MP_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_PRIMARY_8MP_PIPELINING 4 +#define ISP_PRIMARY_8MP_ENABLE_FPNR 1 +#define ISP_PRIMARY_8MP_ENABLE_SC 1 +#define ISP_PRIMARY_8MP_ENABLE_S3A 1 +#define ISP_PRIMARY_8MP_ENABLE_VF_VECEVEN 1 +#define ISP_PRIMARY_8MP_ENABLE_DS 0 +#define ISP_PRIMARY_8MP_ENABLE_SDIS 0 +#define ISP_PRIMARY_8MP_ENABLE_UDS 0 +#define ISP_PRIMARY_8MP_OUTPUT_NUM_CHUNKS 1 +#define ISP_PRIMARY_8MP_DUMMY_BUF_VECTORS 0 +#define ISP_PRIMARY_8MP_TOP_CROPPING 8 +#define ISP_PRIMARY_8MP_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRIMARY_8MP_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRIMARY_8MP_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRIMARY_8MP_MAX_OUTPUT_WIDTH 3264 +#define ISP_PRIMARY_8MP_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRIMARY_8MP_MIN_OUTPUT_WIDTH ISP_PRIMARY_8MP_MAX_OUTPUT_WIDTH +#define ISP_PRIMARY_8MP_MIN_OUTPUT_HEIGHT ISP_PRIMARY_8MP_MAX_OUTPUT_HEIGHT +#define ISP_PRIMARY_8MP_OUTPUT_FORMATS { SH_CSS_FIXED_PRIMARY_FORMAT } +#define ISP_PRIMARY_8MP_MAX_VF_LOG_DOWNSCALE ISP_PRIMARY_8MP_VF_LOG_DOWNSCALE +#define ISP_PRIMARY_8MP_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_PRIMARY_8MP_C_SUBSAMPLING 1 +#define ISP_PRIMARY_8MP_FIXED_S3A_DECI_LOG 6 + +/* Primary DS */ +#define ISP_PRIMARY_DS_BINARY_ID SH_CSS_BINARY_ID_PRIMARY_DS +#define ISP_PRIMARY_DS_BINARY isp_primary_ds +#define ISP_PRIMARY_DS_MODE SH_CSS_BINARY_MODE_PRIMARY +#define ISP_PRIMARY_DS_OUTPUT_NUM_CHUNKS 2 +#define ISP_PRIMARY_DS_DUMMY_BUF_VECTORS 2 +#define ISP_PRIMARY_DS_PIPELINING 2 +#define ISP_PRIMARY_DS_ENABLE_FPNR 1 +#define ISP_PRIMARY_DS_ENABLE_SC 1 +#define ISP_PRIMARY_DS_ENABLE_S3A 1 +#define ISP_PRIMARY_DS_ENABLE_VF_VECEVEN 1 +#define ISP_PRIMARY_DS_ENABLE_DS 1 +#define ISP_PRIMARY_DS_ENABLE_SDIS 0 +#define ISP_PRIMARY_DS_ENABLE_UDS 0 +#define ISP_PRIMARY_DS_LEFT_CROPPING 0 +#define ISP_PRIMARY_DS_TOP_CROPPING 8 +#define ISP_PRIMARY_DS_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRIMARY_DS_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRIMARY_DS_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRIMARY_DS_MAX_OUTPUT_WIDTH 2560 +#define ISP_PRIMARY_DS_MAX_OUTPUT_HEIGHT 1920 +#define ISP_PRIMARY_DS_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PRIMARY_DS_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PRIMARY_DS_OUTPUT_FORMATS SH_CSS_CAPTURE_OUTPUT_FORMATS +#define ISP_PRIMARY_DS_MAX_VF_LOG_DOWNSCALE 1 +#define ISP_PRIMARY_DS_INPUT SH_CSS_BINARY_INPUT_VARIABLE +#define ISP_PRIMARY_DS_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PRIMARY_DS_FIXED_S3A_DECI_LOG 0 + +/* Primary Small */ +#define ISP_PRIMARY_SMALL_BINARY_ID SH_CSS_BINARY_ID_PRIMARY_SMALL +#define ISP_PRIMARY_SMALL_BINARY isp_primary_small +#define ISP_PRIMARY_SMALL_MODE SH_CSS_BINARY_MODE_PRIMARY +#define ISP_PRIMARY_SMALL_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_PRIMARY_SMALL_PIPELINING 2 +#define ISP_PRIMARY_SMALL_ENABLE_FPNR 1 +#define ISP_PRIMARY_SMALL_ENABLE_SC 1 +#define ISP_PRIMARY_SMALL_ENABLE_S3A 1 +#define ISP_PRIMARY_SMALL_ENABLE_VF_VECEVEN 1 +#define ISP_PRIMARY_SMALL_ENABLE_DS 0 +#define ISP_PRIMARY_SMALL_ENABLE_SDIS 0 +#define ISP_PRIMARY_SMALL_ENABLE_UDS 0 +#define ISP_PRIMARY_SMALL_OUTPUT_NUM_CHUNKS 1 +#define ISP_PRIMARY_SMALL_DUMMY_BUF_VECTORS 0 +#define ISP_PRIMARY_SMALL_TOP_CROPPING 8 +#define ISP_PRIMARY_SMALL_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRIMARY_SMALL_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRIMARY_SMALL_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRIMARY_SMALL_MAX_OUTPUT_WIDTH 2560 +#define ISP_PRIMARY_SMALL_MAX_OUTPUT_HEIGHT 1920 +#define ISP_PRIMARY_SMALL_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PRIMARY_SMALL_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PRIMARY_SMALL_OUTPUT_FORMATS SH_CSS_CAPTURE_OUTPUT_FORMATS +#define ISP_PRIMARY_SMALL_MAX_VF_LOG_DOWNSCALE 1 +#define ISP_PRIMARY_SMALL_INPUT SH_CSS_BINARY_INPUT_VARIABLE +#define ISP_PRIMARY_SMALL_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PRIMARY_SMALL_FIXED_S3A_DECI_LOG 0 + +/* Primary Var */ +#define ISP_PRIMARY_VAR_BINARY_ID SH_CSS_BINARY_ID_PRIMARY_VAR +#define ISP_PRIMARY_VAR_BINARY isp_primary_var +#define ISP_PRIMARY_VAR_MODE SH_CSS_BINARY_MODE_PRIMARY +#define ISP_PRIMARY_VAR_OUTPUT_NUM_CHUNKS 4 +#define ISP_PRIMARY_VAR_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_PRIMARY_VAR_PIPELINING 3 +#define ISP_PRIMARY_VAR_ENABLE_FPNR 1 +#define ISP_PRIMARY_VAR_ENABLE_SC 1 +#define ISP_PRIMARY_VAR_ENABLE_S3A 1 +#define ISP_PRIMARY_VAR_ENABLE_VF_VECEVEN 1 +#define ISP_PRIMARY_VAR_ENABLE_DS 0 +#define ISP_PRIMARY_VAR_ENABLE_SDIS 0 +#define ISP_PRIMARY_VAR_ENABLE_UDS 0 +#define ISP_PRIMARY_VAR_DUMMY_BUF_VECTORS 0 +#define ISP_PRIMARY_VAR_TOP_CROPPING 8 +#define ISP_PRIMARY_VAR_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRIMARY_VAR_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRIMARY_VAR_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_PRIMARY_VAR_MAX_VF_LOG_DOWNSCALE 2 +#define ISP_PRIMARY_VAR_MAX_OUTPUT_WIDTH SH_CSS_MAX_SENSOR_WIDTH +#define ISP_PRIMARY_VAR_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRIMARY_VAR_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PRIMARY_VAR_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PRIMARY_VAR_OUTPUT_FORMATS SH_CSS_CAPTURE_OUTPUT_FORMATS +#define ISP_PRIMARY_VAR_INPUT SH_CSS_BINARY_INPUT_VARIABLE +#define ISP_PRIMARY_VAR_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PRIMARY_VAR_FIXED_S3A_DECI_LOG 0 + +/* Primary Ref */ +#define ISP_PRIMARY_REF_BINARY_ID SH_CSS_BINARY_ID_PRIMARY_REF +#define ISP_PRIMARY_REF_BINARY isp_primary_ref +#define ISP_PRIMARY_REF_MODE SH_CSS_BINARY_MODE_PRIMARY +#define ISP_PRIMARY_REF_VF_LOG_DOWNSCALE 1 +#define ISP_PRIMARY_REF_LEFT_CROPPING SH_CSS_MAX_LEFT_CROPPING +#define ISP_PRIMARY_REF_PIPELINING 4 +#define ISP_PRIMARY_REF_ENABLE_FPNR 1 +#define ISP_PRIMARY_REF_ENABLE_SC 1 +#define ISP_PRIMARY_REF_ENABLE_S3A 1 +#define ISP_PRIMARY_REF_ENABLE_VF_VECEVEN 1 +#define ISP_PRIMARY_REF_ENABLE_DS 0 +#define ISP_PRIMARY_REF_ENABLE_SDIS 0 +#define ISP_PRIMARY_REF_ENABLE_UDS 0 +#define ISP_PRIMARY_REF_OUTPUT_NUM_CHUNKS 1 +#define ISP_PRIMARY_REF_DUMMY_BUF_VECTORS 0 +#define ISP_PRIMARY_REF_TOP_CROPPING 8 +#define ISP_PRIMARY_REF_ENABLE_DVS_ENVELOPE 0 +#define ISP_PRIMARY_REF_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_PRIMARY_REF_MAX_DVS_ENVELOPE_HEIGHT 0 +/* +#define ISP_PRIMARY_REF_MAX_OUTPUT_WIDTH SH_CSS_MAX_SENSOR_WIDTH +#define ISP_PRIMARY_REF_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRIMARY_REF_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_PRIMARY_REF_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_PRIMARY_REF_OUTPUT_FORMATS SH_CSS_CAPTURE_OUTPUT_FORMATS +#define ISP_PRIMARY_REF_INPUT SH_CSS_BINARY_INPUT_VARIABLE +#define ISP_PRIMARY_REF_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_PRIMARY_REF_FIXED_S3A_DECI_LOG 0 +*/ +#define ISP_PRIMARY_REF_MAX_OUTPUT_WIDTH 3328 +#define ISP_PRIMARY_REF_MAX_OUTPUT_HEIGHT SH_CSS_MAX_SENSOR_HEIGHT +#define ISP_PRIMARY_REF_MIN_OUTPUT_WIDTH ISP_PRIMARY_REF_MAX_OUTPUT_WIDTH +#define ISP_PRIMARY_REF_MIN_OUTPUT_HEIGHT ISP_PRIMARY_REF_MAX_OUTPUT_HEIGHT +#define ISP_PRIMARY_REF_OUTPUT_FORMATS { SH_CSS_FIXED_PRIMARY_FORMAT } +#define ISP_PRIMARY_REF_MAX_VF_LOG_DOWNSCALE ISP_PRIMARY_REF_VF_LOG_DOWNSCALE +#define ISP_PRIMARY_REF_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_PRIMARY_REF_C_SUBSAMPLING 1 +#define ISP_PRIMARY_REF_FIXED_S3A_DECI_LOG 6 + +/* Video Offline */ +#define ISP_VIDEO_OFFLINE_BINARY_ID SH_CSS_BINARY_ID_VIDEO_OFFLINE +#define ISP_VIDEO_OFFLINE_BINARY isp_video_offline +#define ISP_VIDEO_OFFLINE_MODE SH_CSS_BINARY_MODE_VIDEO +#define ISP_VIDEO_OFFLINE_PIPELINING 3 +/* we use the VF_VECEVEN dma channel for the input frame so + * we cannot generate viewfinder output here. This is also not + * needed for the demo. */ +#define ISP_VIDEO_OFFLINE_ENABLE_VF_VECEVEN 0 +#define ISP_VIDEO_OFFLINE_ENABLE_SC 1 +#define ISP_VIDEO_OFFLINE_ENABLE_S3A 1 +#define ISP_VIDEO_OFFLINE_ENABLE_SDIS 1 +#define ISP_VIDEO_OFFLINE_ENABLE_DVS_ENVELOPE 0 +#define ISP_VIDEO_OFFLINE_ENABLE_UDS 0 +#define ISP_VIDEO_OFFLINE_ENABLE_DS 0 +#define ISP_VIDEO_OFFLINE_ENABLE_FPNR 0 +#define ISP_VIDEO_OFFLINE_OUTPUT_NUM_CHUNKS 1 +#define ISP_VIDEO_OFFLINE_DUMMY_BUF_VECTORS 0 +#define ISP_VIDEO_OFFLINE_LEFT_CROPPING 0 +#define ISP_VIDEO_OFFLINE_TOP_CROPPING 8 +#define ISP_VIDEO_OFFLINE_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_VIDEO_OFFLINE_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_VIDEO_OFFLINE_MAX_OUTPUT_WIDTH 1920 +#define ISP_VIDEO_OFFLINE_MAX_OUTPUT_HEIGHT 1080 +#define ISP_VIDEO_OFFLINE_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_VIDEO_OFFLINE_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_VIDEO_OFFLINE_OUTPUT_FORMATS SH_CSS_VIDEO_OUTPUT_FORMATS +#define ISP_VIDEO_OFFLINE_MAX_VF_LOG_DOWNSCALE 1 +#define ISP_VIDEO_OFFLINE_INPUT SH_CSS_BINARY_INPUT_MEMORY +#define ISP_VIDEO_OFFLINE_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_VIDEO_OFFLINE_FIXED_S3A_DECI_LOG 0 + +/* Video Online DZ */ +#define ISP_VIDEO_DZ_BINARY_ID SH_CSS_BINARY_ID_VIDEO_DZ +#define ISP_VIDEO_DZ_BINARY isp_video_dz +#define ISP_VIDEO_DZ_MODE SH_CSS_BINARY_MODE_VIDEO +#define ISP_VIDEO_DZ_OUTPUT_NUM_CHUNKS 2 +#define ISP_VIDEO_DZ_PIPELINING 3 +#define ISP_VIDEO_DZ_MAX_DVS_ENVELOPE_WIDTH 384 +#define ISP_VIDEO_DZ_MAX_DVS_ENVELOPE_HEIGHT 216 +#define ISP_VIDEO_DZ_ENABLE_SC 1 +#define ISP_VIDEO_DZ_ENABLE_S3A 1 +#define ISP_VIDEO_DZ_ENABLE_SDIS 1 +#define ISP_VIDEO_DZ_ENABLE_DVS_ENVELOPE 1 +#define ISP_VIDEO_DZ_ENABLE_UDS 1 +#define ISP_VIDEO_DZ_ENABLE_VF_VECEVEN 1 +#define ISP_VIDEO_DZ_ENABLE_DS 0 +#define ISP_VIDEO_DZ_ENABLE_FPNR 0 +#define ISP_VIDEO_DZ_DUMMY_BUF_VECTORS 0 +#define ISP_VIDEO_DZ_LEFT_CROPPING 0 +#define ISP_VIDEO_DZ_TOP_CROPPING 0 +#define ISP_VIDEO_DZ_MAX_OUTPUT_WIDTH 1920 +#define ISP_VIDEO_DZ_MAX_OUTPUT_HEIGHT 1080 +#define ISP_VIDEO_DZ_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_VIDEO_DZ_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_VIDEO_DZ_OUTPUT_FORMATS SH_CSS_VIDEO_OUTPUT_FORMATS +#define ISP_VIDEO_DZ_MAX_VF_LOG_DOWNSCALE 1 +#define ISP_VIDEO_DZ_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_VIDEO_DZ_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_VIDEO_DZ_FIXED_S3A_DECI_LOG 0 + +/* Video Online DS */ +#define ISP_VIDEO_DS_BINARY_ID SH_CSS_BINARY_ID_VIDEO_DS +#define ISP_VIDEO_DS_BINARY isp_video_ds +#define ISP_VIDEO_DS_MODE SH_CSS_BINARY_MODE_VIDEO +#define ISP_VIDEO_DS_OUTPUT_NUM_CHUNKS 2 +#define ISP_VIDEO_DS_DUMMY_BUF_VECTORS 2 +#define ISP_VIDEO_DS_PIPELINING 2 +#define ISP_VIDEO_DS_ENABLE_SC 1 +#define ISP_VIDEO_DS_ENABLE_S3A 1 +#define ISP_VIDEO_DS_ENABLE_SDIS 0 +#define ISP_VIDEO_DS_ENABLE_DVS_ENVELOPE 1 +#define ISP_VIDEO_DS_ENABLE_VF_VECEVEN 1 +#define ISP_VIDEO_DS_ENABLE_DS 1 +#define ISP_VIDEO_DS_ENABLE_FPNR 0 +#define ISP_VIDEO_DS_ENABLE_UDS 0 +#define ISP_VIDEO_DS_LEFT_CROPPING 0 +#define ISP_VIDEO_DS_TOP_CROPPING 8 +#define ISP_VIDEO_DS_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_VIDEO_DS_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_VIDEO_DS_MAX_OUTPUT_WIDTH 1920 +#define ISP_VIDEO_DS_MAX_OUTPUT_HEIGHT 1080 +#define ISP_VIDEO_DS_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_VIDEO_DS_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_VIDEO_DS_OUTPUT_FORMATS SH_CSS_VIDEO_OUTPUT_FORMATS +#define ISP_VIDEO_DS_MAX_VF_LOG_DOWNSCALE 1 +#define ISP_VIDEO_DS_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_VIDEO_DS_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_VIDEO_DS_FIXED_S3A_DECI_LOG 0 + +/* Video Online no DZ */ +#define ISP_VIDEO_NODZ_BINARY_ID SH_CSS_BINARY_ID_VIDEO_NODZ +#define ISP_VIDEO_NODZ_BINARY isp_video_nodz +#define ISP_VIDEO_NODZ_MODE SH_CSS_BINARY_MODE_VIDEO +#define ISP_VIDEO_NODZ_PIPELINING 3 +#define ISP_VIDEO_NODZ_MAX_DVS_ENVELOPE_WIDTH 384 +#define ISP_VIDEO_NODZ_MAX_DVS_ENVELOPE_HEIGHT 216 +#define ISP_VIDEO_NODZ_ENABLE_SC 1 +#define ISP_VIDEO_NODZ_ENABLE_S3A 1 +#define ISP_VIDEO_NODZ_ENABLE_SDIS 1 +#define ISP_VIDEO_NODZ_ENABLE_DVS_ENVELOPE 1 +#define ISP_VIDEO_NODZ_ENABLE_VF_VECEVEN 1 +#define ISP_VIDEO_NODZ_ENABLE_DS 0 +#define ISP_VIDEO_NODZ_ENABLE_FPNR 0 +#define ISP_VIDEO_NODZ_ENABLE_UDS 0 +#define ISP_VIDEO_NODZ_OUTPUT_NUM_CHUNKS 2 +#define ISP_VIDEO_NODZ_DUMMY_BUF_VECTORS 0 +#define ISP_VIDEO_NODZ_LEFT_CROPPING 0 +#define ISP_VIDEO_NODZ_TOP_CROPPING 0 +#define ISP_VIDEO_NODZ_MAX_OUTPUT_WIDTH 1920 +#define ISP_VIDEO_NODZ_MAX_OUTPUT_HEIGHT 1080 +#define ISP_VIDEO_NODZ_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_VIDEO_NODZ_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_VIDEO_NODZ_OUTPUT_FORMATS SH_CSS_VIDEO_OUTPUT_FORMATS +#define ISP_VIDEO_NODZ_MAX_VF_LOG_DOWNSCALE 1 +#define ISP_VIDEO_NODZ_INPUT SH_CSS_BINARY_INPUT_SENSOR +#define ISP_VIDEO_NODZ_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_VIDEO_NODZ_FIXED_S3A_DECI_LOG 0 + +/* Viewfinder Post-processing */ +#define ISP_VF_PP_BINARY_ID SH_CSS_BINARY_ID_VF_PP +#define ISP_VF_PP_BINARY isp_vf_pp +#define ISP_VF_PP_MODE SH_CSS_BINARY_MODE_VF_PP +#define ISP_VF_PP_ENABLE_DS 1 +#define ISP_VF_PP_ENABLE_FPNR 0 +#define ISP_VF_PP_ENABLE_SC 0 +#define ISP_VF_PP_ENABLE_S3A 0 +#define ISP_VF_PP_ENABLE_SDIS 0 +#define ISP_VF_PP_ENABLE_VF_VECEVEN 0 +#define ISP_VF_PP_ENABLE_UDS 0 +#define ISP_VF_PP_PIPELINING 1 +#define ISP_VF_PP_OUTPUT_NUM_CHUNKS 1 +#define ISP_VF_PP_DUMMY_BUF_VECTORS 0 +#define ISP_VF_PP_LEFT_CROPPING 0 +#define ISP_VF_PP_TOP_CROPPING 0 +#define ISP_VF_PP_ENABLE_DVS_ENVELOPE 0 +#define ISP_VF_PP_MAX_DVS_ENVELOPE_WIDTH 0 +#define ISP_VF_PP_MAX_DVS_ENVELOPE_HEIGHT 0 +#define ISP_VF_PP_MAX_OUTPUT_WIDTH SH_CSS_MAX_VF_WIDTH +#define ISP_VF_PP_MAX_OUTPUT_HEIGHT SH_CSS_MAX_VF_HEIGHT +#define ISP_VF_PP_MIN_OUTPUT_WIDTH SH_CSS_MIN_SENSOR_WIDTH +#define ISP_VF_PP_MIN_OUTPUT_HEIGHT SH_CSS_MIN_SENSOR_HEIGHT +#define ISP_VF_PP_OUTPUT_FORMATS SH_CSS_VF_OUTPUT_FORMATS +#define ISP_VF_PP_MAX_VF_LOG_DOWNSCALE 0 +#define ISP_VF_PP_INPUT SH_CSS_BINARY_INPUT_MEMORY +#define ISP_VF_PP_C_SUBSAMPLING SH_CSS_DEFAULT_C_SUBSAMPLING +#define ISP_VF_PP_FIXED_S3A_DECI_LOG 0 + +#endif /* _SH_CSS_BINARY_INFO_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_debug.c b/drivers/media/video/atomisp/css/sh_css_debug.c new file mode 100644 index 0000000..05a4023 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_debug.c @@ -0,0 +1,676 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css_debug.h" +#include "sh_css.h" +#include "sh_css_hrt.h" +#include "sh_css_internal.h" +#include "sh_css_rx.h" + +static void +print_cell_state(struct sh_css_cell_state *state, const char *cell) +{ + sh_css_print("%s state:\n", cell); + sh_css_print(" PC: 0x%x\n", state->pc); + sh_css_print(" Status register : 0x%x\n", state->status_register); + sh_css_print(" is broken: %d\n", state->is_broken); + sh_css_print(" is idle: %d\n", state->is_idle); + sh_css_print(" is sleeping: %d\n", state->is_sleeping); + sh_css_print(" is stalling: %d\n", state->is_stalling); +} + +void +sh_css_dump_isp_state(void) +{ + struct sh_css_cell_state state; + struct sh_css_isp_stall_state stall_state; + sh_css_hrt_isp_get_state(&state, &stall_state); + print_cell_state(&state, "ISP"); + if (state.is_stalling) { + sh_css_print(" FIFO 0 stalled: %d\n", stall_state.fifo0); + sh_css_print(" FIFO 1 stalled: %d\n", stall_state.fifo1); + sh_css_print(" FIFO 2 stalled: %d\n", stall_state.fifo2); + sh_css_print(" FIFO 3 stalled: %d\n", stall_state.fifo3); + sh_css_print(" FIFO 4 stalled: %d\n", stall_state.fifo4); + sh_css_print(" FIFO 5 stalled: %d\n", stall_state.fifo5); + sh_css_print(" status & control stalled: %d\n", + stall_state.stat_ctrl); + sh_css_print(" dmem stalled: %d\n", stall_state.dmem); + sh_css_print(" vmem stalled: %d\n", stall_state.vmem); + sh_css_print(" vamem1 stalled: %d\n", stall_state.vamem1); + sh_css_print(" vamem2 stalled: %d\n", stall_state.vamem2); + } +} + +void +sh_css_dump_sp_state(void) +{ + struct sh_css_cell_state state; + struct sh_css_sp_stall_state stall_state; + sh_css_hrt_sp_get_state(&state, &stall_state); + print_cell_state(&state, "SP"); + if (state.is_stalling) { + sh_css_print(" if_prim_FIFO stalled: %d\n", + stall_state.fifo0); + sh_css_print(" if_sec_FIFO stalled: %d\n", + stall_state.fifo1); + sh_css_print(" str_to_mem_FIFO stalled: %d\n", + stall_state.fifo2); + sh_css_print(" dma_FIFO stalled: %d\n", + stall_state.fifo3); + sh_css_print(" gdc_FIFO stalled: %d\n", + stall_state.fifo4); + sh_css_print(" isp_FIFO stalled: %d\n", + stall_state.fifo5); + sh_css_print(" gp_FIFO stalled: %d\n", + stall_state.fifo6); + sh_css_print(" if_prim_b_FIFO stalled: %d\n", + stall_state.fifo7); + sh_css_print(" dmem stalled: %d\n", stall_state.dmem); + sh_css_print(" control master stalled: %d\n", + stall_state.control_master); + sh_css_print(" i-cache master stalled: %d\n", + stall_state.icache_master); + } +} + +static void +print_if_state(struct sh_css_if_state *state) +{ + unsigned int val; + sh_css_print("InputFormatter State:\n"); + sh_css_print(" Configuration:\n"); + sh_css_print(" Software reset: %s\n", + state->reset ? "Active" : "Not active"); + sh_css_print(" Start line: %d\n", state->start_line); + sh_css_print(" Start column: %d\n", + state->start_column); + sh_css_print(" Cropped height: %d\n", + state->cropped_height); + sh_css_print(" Cropped width: %d\n", + state->cropped_width); + sh_css_print(" Vertical decimation: %d\n", + state->ver_decimation); + sh_css_print(" Horizontal decimation: %d\n", + state->hor_decimation); + sh_css_print(" Deinterleaving: %d\n", + state->deinterleaving); + sh_css_print(" Left padding: %d\n", + state->left_padding); + sh_css_print(" End-of-line offset (bytes): %d\n", + state->eol_offset); + sh_css_print(" VMEM start address: 0x%06X\n", + state->vmem_start_address); + sh_css_print(" VMEM end address: 0x%06X\n", + state->vmem_end_address); + sh_css_print(" VMEM increment: 0x%06X\n", + state->vmem_increment); + sh_css_print(" YUV 420 format: %d\n", state->yuv420); + sh_css_print(" Vsync: Active %s\n", + state->vsync_active_low ? "low" : "high"); + sh_css_print(" Hsync: Active %s\n", + state->hsync_active_low ? "low" : "high"); +#if 0 + /* not supported on css_dev */ + sh_css_print(" Sensor stalling: %s\n", + state->allow_fifo_overflow ? "Allowed" : "Not allowed"); +#endif + sh_css_print(" FSM Status\n"); + val = state->fsm_sync_status; + sh_css_print(" FSM Synchronization Status 0x%X: ", val); + if (val > 7) + sh_css_print("ERROR : "); + + switch (val & 0x7) { + case 0: + sh_css_print("idle\n"); + break; + case 1: + sh_css_print("request frame\n"); + break; + case 2: + sh_css_print("request lines\n"); + break; + case 3: + sh_css_print("request vectors\n"); + break; + case 4: + sh_css_print("send acknowledge\n"); + break; + default: + sh_css_print("unknown\n"); + break; + } + sh_css_print(" FSM Synchronization Counter %d\n", + state->fsm_sync_counter); + val = state->fsm_crop_status; + sh_css_print(" FSM Crop Status 0x%X: ", + val); + if (val > 7) + sh_css_print("ERROR : "); + switch (val & 0x7) { + case 0: + sh_css_print("idle\n"); + break; + case 1: + sh_css_print("wait line\n"); + break; + case 2: + sh_css_print("crop line\n"); + break; + case 3: + sh_css_print("crop pixel\n"); + break; + case 4: + sh_css_print("pass pixel\n"); + break; + case 5: + sh_css_print("pass line\n"); + break; + case 6: + sh_css_print("lost line\n"); + break; + default: + sh_css_print("unknown\n"); + break; + } + + sh_css_print(" FSM Crop Line Counter %d\n", + state->fsm_crop_line_counter); + sh_css_print(" FSM Crop Pixel Counter %d\n", + state->fsm_crop_pixel_counter); + sh_css_print(" FSM Deinterleaving idx buffer %d\n", + state->fsm_deinterleaving_index); + sh_css_print(" FSM Decimation H decimation counter %d\n", + state->fsm_dec_h_counter); + sh_css_print(" FSM Decimation V decimation counter %d\n", + state->fsm_dec_v_counter); + sh_css_print(" FSM Decimation block V decimation counter %d\n", + state->fsm_dec_block_v_counter); + + val = state->fsm_padding_status; + sh_css_print(" FSM Padding Status 0x%X: ", val); + if (val > 7) + sh_css_print("ERROR : "); + + switch (val & 0x7) { + case 0: + sh_css_print("idle\n"); + break; + case 1: + sh_css_print("left pad\n"); + break; + case 2: + sh_css_print("write\n"); + break; + case 3: + sh_css_print("right pad\n"); + break; + case 4: + sh_css_print("send end of line\n"); + break; + default: + sh_css_print("unknown\n"); + break; + } + sh_css_print("FSM Padding element index counter %d\n", + state->fsm_padding_elem_counter); + sh_css_print("FSM Vector support error %d\n", + state->fsm_vector_support_error); + sh_css_print("FSM Vector support buf full %d\n", + state->fsm_vector_buffer_full); + sh_css_print("FSM Vector support %d\n", + state->vector_support); + sh_css_print("Fifo sensor data lost %d\n", + state->sensor_data_lost); +} + +void +sh_css_dump_if_state(void) +{ + struct sh_css_if_state state; + sh_css_hrt_if_prim_a_get_state(&state); + print_if_state(&state); + sh_css_dump_pif_isp_fifo_state(); +} + +void +sh_css_dump_dma_state(void) +{ + struct sh_css_dma_state state; + int i, ch_id, num_ports = 3, num_channels = 8; + + sh_css_hrt_dma_get_state(&state); + sh_css_print("DMA dump status:\n\t"); + sh_css_print("FSM Command flag state:\n\t\t"); + if (state.fsm_command_idle) + sh_css_print("IDLE\n\t\t"); + if (state.fsm_command_run) + sh_css_print("RUN\n\t\t"); + if (state.fsm_command_stalling) + sh_css_print("STALL\n\t\t"); + if (state.fsm_command_error) + sh_css_print("ERROR\n\t\t"); + ch_id = state.last_command_channel; + sh_css_print("last command received (0x%x) : ", state.last_command); + if (state.last_command == sh_css_dma_command_read) + sh_css_print(" Read 2D Block with settings from ch:%d", ch_id); + if (state.last_command == sh_css_dma_command_write) + sh_css_print(" Write 2D Block with settings from ch:%d", ch_id); + if (state.last_command == sh_css_dma_command_set_channel) + sh_css_print(" Set Channel:%d", ch_id); + if (state.last_command == sh_css_dma_command_set_param) + sh_css_print(" Set Param:%d on Channel:%d", + state.last_command_param, ch_id); + if (state.last_command == sh_css_dma_command_read_spec) + sh_css_print(" Read Specific 2D Block on ch:%d", ch_id); + if (state.last_command == sh_css_dma_command_write_spec) + sh_css_print(" Write Specific 2D Block on ch:%d", ch_id); + if (state.last_command == sh_css_dma_command_init) + sh_css_print(" Init 2D Block on Device A on ch:%d", ch_id); + if (state.last_command == sh_css_dma_command_init_spec) + sh_css_print(" Init Specific 2D Block on ch:%d", ch_id); + if (state.last_command == sh_css_dma_command_reset) + sh_css_print(" DMA SW Reset"); + sh_css_print("\n\t"); + sh_css_print("DMA registers, connection group 0\n\t"); + sh_css_print("Cmd Fifo Command 0x%x\n\t\t", state.current_command); + sh_css_print("Cmd Fifo Address A 0x%x\n\t\t", state.current_addr_a); + sh_css_print("Cmd Fifo Address B 0x%x\n\t\t", state.current_addr_b); + sh_css_print("FSM Ctrl flag and state:\n\t\t\t"); + if (state.fsm_ctrl_idle) + sh_css_print("IDLE -> "); + if (state.fsm_ctrl_run) + sh_css_print("RUN -> "); + if (state.fsm_ctrl_stalling) + sh_css_print("STALL -> "); + if (state.fsm_ctrl_error) + sh_css_print("ERROR -> "); + if (state.fsm_ctrl_state == sh_css_dma_ctrl_state_idle) + sh_css_print("Idle state\n\t\t"); + if (state.fsm_ctrl_state == sh_css_dma_ctrl_state_req_rcv) + sh_css_print("Req Rcv state\n\t\t"); + if (state.fsm_ctrl_state == sh_css_dma_ctrl_state_rcv) + sh_css_print("Rcv state\n\t\t"); + if (state.fsm_ctrl_state == sh_css_dma_ctrl_state_rcv_req) + sh_css_print("Rcv Req state\n\t\t"); + if (state.fsm_ctrl_state == sh_css_dma_ctrl_state_init) + sh_css_print("Init state\n\t\t"); + sh_css_print("FSM Ctrl source dev : %d\n\t\t", + state.fsm_ctrl_source_dev); + sh_css_print("FSM Ctrl source addr : 0x%x\n\t\t", + state.fsm_ctrl_source_addr); + sh_css_print("FSM Ctrl source stride : 0x%x\n\t\t", + state.fsm_ctrl_source_stride); + sh_css_print("FSM Ctrl source width : %d\n\t\t", + state.fsm_ctrl_source_width); + sh_css_print("FSM Ctrl source height : %d\n\t\t", + state.fsm_ctrl_source_height); + sh_css_print("FSM Ctrl pack source dev : %d\n\t\t", + state.fsm_ctrl_pack_source_dev); + sh_css_print("FSM Ctrl pack dest dev : %d\n\t\t", + state.fsm_ctrl_pack_dest_dev); + sh_css_print("FSM Ctrl dest addr : 0x%x\n\t\t", + state.fsm_ctrl_dest_addr); + sh_css_print("FSM Ctrl dest stride : 0x%x\n\t\t", + state.fsm_ctrl_dest_stride); + sh_css_print("FSM Ctrl pack source width : %d\n\t\t", + state.fsm_ctrl_pack_source_width); + sh_css_print("FSM Ctrl pack dest height : %d\n\t\t", + state.fsm_ctrl_pack_dest_height); + sh_css_print("FSM Ctrl pack dest width : %d\n\t\t", + state.fsm_ctrl_pack_dest_width); + sh_css_print("FSM Ctrl pack source elems : %d\n\t\t", + state.fsm_ctrl_pack_source_elems); + sh_css_print("FSM Ctrl pack dest elems : %d\n\t\t", + state.fsm_ctrl_pack_dest_elems); + sh_css_print("FSM Ctrl pack extension : %d\n\t\t", + state.fsm_ctrl_pack_extension); + sh_css_print("FSM Pack flag state\t\t\t"); + if (state.pack_idle) + sh_css_print("IDLE\t\t"); + if (state.pack_run) + sh_css_print("RUN\t\t"); + if (state.pack_stalling) + sh_css_print("STALL\t\t"); + if (state.pack_error) + sh_css_print("ERROR\t\t"); + sh_css_print("FSM Pack cnt height : %d\n\t\t", + state.pack_cnt_height); + sh_css_print("FSM Pack src cnt width : %d\n\t\t", + state.pack_src_cnt_width); + sh_css_print("FSM Pack dest cnt width : %d\n\t\t", + state.pack_dest_cnt_width); + sh_css_print("FSM Read state\n\t\t"); + if (state.read_state == sh_css_dma_rw_state_idle) + sh_css_print("\tIdle state\n\t\t"); + if (state.read_state == sh_css_dma_rw_state_req) + sh_css_print("\tReq state\n\t\t"); + if (state.read_state == sh_css_dma_rw_state_next_line) + sh_css_print("\tNext line\n\t\t"); + if (state.read_state == sh_css_dma_rw_state_unlock_channel) + sh_css_print("\tUnlock channel\n\t\t"); + sh_css_print("FSM Read cnt height : %d\n\t\t", + state.read_cnt_height); + sh_css_print("FSM Read cnt width : %d\n\t\t", + state.read_cnt_width); + sh_css_print("FSM Write state\n\t\t\t"); + if (state.write_state == sh_css_dma_rw_state_idle) + sh_css_print("\tIdle state\n\t\t"); + if (state.write_state == sh_css_dma_rw_state_req) + sh_css_print("\tReq state\n\t\t"); + if (state.write_state == sh_css_dma_rw_state_next_line) + sh_css_print("\tNext line\n\t\t"); + if (state.write_state == sh_css_dma_rw_state_unlock_channel) + sh_css_print("\tUnlock channel\n\t\t"); + sh_css_print("FSM Write height : %d\n\t\t", + state.write_height); + sh_css_print("FSM Write width : %d\n\t\t", + state.write_width); + sh_css_print("\n\t"); + for (i = 0; i < num_ports; i++) { + sh_css_print("DMA device interface %d\n", i); + sh_css_print("\t\tDMA internal side state\n\t\t\t"); + sh_css_print("CS: %d - We_n: %d - Run: %d - Ack: %d\n", + state.port_states[i].req_cs, + state.port_states[i].req_we_n, + state.port_states[i].req_run, + state.port_states[i].req_ack); + sh_css_print("\t\tMaster Output side state\n\t\t\t"); + sh_css_print("CS: %d - We_n: %d - Run: s%d - Ack: %d\n", + state.port_states[i].send_cs, + state.port_states[i].send_we_n, + state.port_states[i].send_run, + state.port_states[i].send_ack); + sh_css_print("\t\tFifo state\n\t\t\t"); + if (state.port_states[i].fifo_state == + sh_css_dma_fifo_state_will_be_full) { + sh_css_print("FiFo will be full\n"); + } + if (state.port_states[i].fifo_state == + sh_css_dma_fifo_state_full) { + sh_css_print("Fifo Full\n"); + } + if (state.port_states[i].fifo_state == + sh_css_dma_fifo_state_empty) { + sh_css_print("Fifo Empty\n"); + } + sh_css_print("\t\tFifo counter %d\n\t", + state.port_states[i].fifo_counter); + } + sh_css_print("\n\t"); + for (i = 0; i < num_channels; i++) { + struct sh_css_dma_channel_state *ch; + ch = &(state.channel_states[i]); + sh_css_print("DMA channel register %d\n\t\t", i); + sh_css_print("Connection : %d\n\t\t", ch->connection); + sh_css_print("Sign extend: : %d\n\t\t", ch->sign_extend); + sh_css_print("Reverse elems : %d\n\t\t", + ch->reverse_elem_order); + sh_css_print("Stride Dev A : 0x%x\n\t\t", ch->stride_a); + sh_css_print("Elems Dev A : %d\n\t\t", ch->elems_a); + sh_css_print("Cropping Dev A : %d\n\t\t", ch->cropping_a); + sh_css_print("Width Dev A : %d\n\t\t", ch->width_a); + sh_css_print("Stride Dev B : 0x%x\n\t\t", ch->stride_b); + sh_css_print("Elems Dev B : %d\n\t\t", ch->elems_b); + sh_css_print("Cropping Dev B : %d\n\t\t", ch->cropping_b); + sh_css_print("Width Dev B : %d\n\t\t", ch->width_b); + sh_css_print("Height : %d\n\t", ch->height); + } + sh_css_print("\n"); +} + +static void +print_fifo_channel_state(struct sh_css_fifo_channel_state *state, + const char *descr) +{ + sh_css_print("FIFO channel: %s\n", descr); + sh_css_print(" source valid: %d\n", state->src_valid); + sh_css_print(" fifo accept: %d\n", state->fifo_accept); + sh_css_print(" fifo valid: %d\n", state->fifo_valid); + sh_css_print(" sink accept: %d\n", state->sink_accept); +} + +void +sh_css_dump_pif_isp_fifo_state(void) +{ + struct sh_css_fifo_channel_state pif_to_isp, + isp_to_pif; + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_isp_to_if_prim_a, + &isp_to_pif); + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_if_prim_a_to_isp, + &pif_to_isp); + print_fifo_channel_state(&pif_to_isp, "Primary IF A to ISP"); + print_fifo_channel_state(&isp_to_pif, "ISP to Primary IF A)"); +} + +void +sh_css_dump_dma_sp_fifo_state(void) +{ + struct sh_css_fifo_channel_state dma_to_sp, + sp_to_dma; + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_dma_to_sp, + &dma_to_sp); + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_sp_to_dma, + &sp_to_dma); + print_fifo_channel_state(&dma_to_sp, "DMA to SP"); + print_fifo_channel_state(&sp_to_dma, "SP to DMA"); +} + +void +sh_css_dump_dma_isp_fifo_state(void) +{ + struct sh_css_fifo_channel_state dma_to_isp, + isp_to_dma; + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_dma_to_isp, + &dma_to_isp); + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_isp_to_dma, + &isp_to_dma); + print_fifo_channel_state(&dma_to_isp, "DMA to ISP"); + print_fifo_channel_state(&isp_to_dma, "ISP to DMA"); +} + +void +sh_css_dump_isp_sp_fifo_state(void) +{ + struct sh_css_fifo_channel_state sp_to_isp, + isp_to_sp; + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_sp_to_isp, + &sp_to_isp); + sh_css_hrt_fifo_channel_get_state(sh_css_hrt_fifo_isp_to_sp, + &isp_to_sp); + print_fifo_channel_state(&sp_to_isp, "SP to ISP"); + print_fifo_channel_state(&isp_to_sp, "ISP to SP"); +} + +void +sh_css_dump_debug_info(void) +{ + sh_css_dump_rx_state(); + sh_css_dump_if_state(); + /* some of these are commented out because they usually don't offer + anything meaningful. */ + if (0) { + sh_css_dump_isp_state(); + sh_css_dump_isp_sp_fifo_state(); + } + sh_css_dump_sp_state(); + if (0) { + sh_css_dump_dma_isp_fifo_state(); + sh_css_dump_dma_sp_fifo_state(); + sh_css_dump_dma_state(); + } +} + +static void +sh_css_binary_info_print(const struct sh_css_binary_info *info) +{ + sh_css_print("id = %d\n", info->id); + sh_css_print("mode = %d\n", info->mode); + sh_css_print("max_input_width = %d\n", info->max_input_width); + sh_css_print("min_output_width = %d\n", info->min_output_width); + sh_css_print("max_output_width = %d\n", info->max_output_width); + sh_css_print("top_cropping = %d\n", info->top_cropping); + sh_css_print("left_cropping = %d\n", info->left_cropping); + sh_css_print("xmem_addr = %p\n", info->xmem_addr); + sh_css_print("enable_vf_veceven = %d\n", info->enable_vf_veceven); + sh_css_print("enable_dis = %d\n", info->enable_dis); + sh_css_print("enable_uds = %d\n", info->enable_uds); + sh_css_print("enable ds = %d\n", info->enable_ds); + sh_css_print("s3atbl_use_dmem = %d\n", info->s3atbl_use_dmem); +} + +void +sh_css_binary_print(const struct sh_css_binary *bi) +{ + sh_css_binary_info_print(bi->info); + sh_css_print("input: %dx%d, format = %d, padded width = %d\n", + bi->in_frame_info.width, bi->in_frame_info.height, + bi->in_frame_info.format, bi->in_frame_info.padded_width); + sh_css_print("internal :%dx%d, format = %d, padded width = %d\n", + bi->internal_frame_info.width, + bi->internal_frame_info.height, + bi->internal_frame_info.format, + bi->internal_frame_info.padded_width); + sh_css_print("out: %dx%d, format = %d, padded width = %d\n", + bi->out_frame_info.width, bi->out_frame_info.height, + bi->out_frame_info.format, + bi->out_frame_info.padded_width); + sh_css_print("vf out: %dx%d, format = %d, padded width = %d\n", + bi->vf_frame_info.width, bi->vf_frame_info.height, + bi->vf_frame_info.format, bi->vf_frame_info.padded_width); + sh_css_print("online = %d\n", bi->online); + sh_css_print("input_buf_vectors = %d\n", bi->input_buf_vectors); + sh_css_print("deci_factor_log2 = %d\n", bi->deci_factor_log2); + sh_css_print("vf_downscale_log2 = %d\n", bi->vf_downscale_log2); + sh_css_print("dis_deci_factor_log2 = %d\n", bi->dis_deci_factor_log2); + sh_css_print("dis hor coef num = %d\n", bi->dis_hor_coef_num_isp); + sh_css_print("dis ver coef num = %d\n", bi->dis_ver_coef_num_isp); + sh_css_print("dis hor proj num = %d\n", bi->dis_ver_proj_num_isp); + sh_css_print("sctbl_width_per_color = %d\n", bi->sctbl_width_per_color); + sh_css_print("s3atbl_width = %d\n", bi->s3atbl_width); + sh_css_print("s3atbl_height = %d\n", bi->s3atbl_height); +} + +void +sh_css_frame_print(const struct sh_css_frame *frame, const char *descr) +{ + sh_css_print("frame %s (%p):\n", descr, frame); + sh_css_print(" resolution = %dx%d\n", + frame->info.width, frame->info.height); + sh_css_print(" padded width = %d\n", frame->info.padded_width); + sh_css_print(" format = %d\n", frame->info.format); + sh_css_print(" is contiguous = %s\n", + frame->contiguous ? "yes" : "no"); + switch (frame->info.format) { + case SH_CSS_FRAME_FORMAT_NV12: + case SH_CSS_FRAME_FORMAT_NV16: + case SH_CSS_FRAME_FORMAT_NV21: + case SH_CSS_FRAME_FORMAT_NV61: + sh_css_print(" Y = %p\n", frame->planes.nv.y.data); + sh_css_print(" UV = %p\n", frame->planes.nv.uv.data); + break; + case SH_CSS_FRAME_FORMAT_YUYV: + case SH_CSS_FRAME_FORMAT_UYVY: + case SH_CSS_FRAME_FORMAT_YUV_LINE: + sh_css_print(" YUYV = %p\n", frame->planes.yuyv.data); + break; + case SH_CSS_FRAME_FORMAT_YUV420: + case SH_CSS_FRAME_FORMAT_YUV422: + case SH_CSS_FRAME_FORMAT_YUV444: + case SH_CSS_FRAME_FORMAT_YV12: + case SH_CSS_FRAME_FORMAT_YV16: + case SH_CSS_FRAME_FORMAT_YUV420_16: + case SH_CSS_FRAME_FORMAT_YUV422_16: + sh_css_print(" Y = %p\n", frame->planes.yuv.y.data); + sh_css_print(" U = %p\n", frame->planes.yuv.u.data); + sh_css_print(" V = %p\n", frame->planes.yuv.v.data); + break; + case SH_CSS_FRAME_FORMAT_RAW: + sh_css_print(" RAW = %p\n", frame->planes.raw.data); + break; + case SH_CSS_FRAME_FORMAT_RGBA888: + case SH_CSS_FRAME_FORMAT_RGB565: + sh_css_print(" RGB = %p\n", frame->planes.rgb.data); + break; + case SH_CSS_FRAME_FORMAT_QPLANE6: + sh_css_print(" R = %p\n", frame->planes.plane6.r.data); + sh_css_print(" RatB = %p\n", frame->planes.plane6.r_at_b.data); + sh_css_print(" Gr = %p\n", frame->planes.plane6.gr.data); + sh_css_print(" Gb = %p\n", frame->planes.plane6.gb.data); + sh_css_print(" B = %p\n", frame->planes.plane6.b.data); + sh_css_print(" BatR = %p\n", frame->planes.plane6.b_at_r.data); + break; + case SH_CSS_FRAME_FORMAT_BINARY_8: + sh_css_print(" Binary data = %p\n", + frame->planes.binary.data.data); + break; + default: + sh_css_print(" unknown frame type\n"); + break; + } +} + +void +sh_css_print_sp_debug_state(const struct sh_css_sp_debug_state *state) +{ + int i; + + sh_css_print("sp_error = 0x%x\n", state->error); + for (i = 0; i < 16; i++) + sh_css_print("sp_debug[%d] = %d\n", i, state->debug[i]); +} + +void +sh_css_dump_rx_state(void) +{ + unsigned int infos = 0, bits; + bits = sh_css_rx_get_interrupt_reg(); + sh_css_rx_get_interrupt_info(&infos); + + sh_css_print("CSI Receiver errors: (irq reg = 0x%X\n", bits); + if (infos & SH_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) + sh_css_print(" buffer overrun"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_SOT) + sh_css_print(" start-of-transmission error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_SOT_SYNC) + sh_css_print(" start-of-transmission sync error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_CONTROL) + sh_css_print(" control error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) + sh_css_print(" 2 or more ECC errors"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_CRC) + sh_css_print(" CRC mismatch"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) + sh_css_print(" unknown error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) + sh_css_print(" frame sync error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_FRAME_DATA) + sh_css_print(" frame data error"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) + sh_css_print(" data timeout"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) + sh_css_print(" unknown escape command entry"); + if (infos & SH_CSS_RX_IRQ_INFO_ERR_LINE_SYNC) + sh_css_print(" line sync error"); +} diff --git a/drivers/media/video/atomisp/css/sh_css_debug.h b/drivers/media/video/atomisp/css/sh_css_debug.h new file mode 100644 index 0000000..de4bae0 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_debug.h @@ -0,0 +1,42 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_DEBUG_H_ +#define _SH_CSS_DEBUG_H_ + +#include "sh_css_types.h" + +void sh_css_dump_if_state(void); +void sh_css_dump_isp_state(void); +void sh_css_dump_sp_state(void); +void sh_css_dump_dma_state(void); +void sh_css_dump_debug_info(void); +void sh_css_dump_dma_isp_fifo_state(void); +void sh_css_dump_dma_sp_fifo_state(void); +void sh_css_dump_pif_isp_fifo_state(void); +void sh_css_dump_isp_sp_fifo_state(void); +void sh_css_dump_rx_state(void); +void sh_css_frame_print(const struct sh_css_frame *frame, + const char *descr); + +#endif /* _SH_CSS_DEBUG_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_defs.h b/drivers/media/video/atomisp/css/sh_css_defs.h new file mode 100644 index 0000000..e7b99c4 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_defs.h @@ -0,0 +1,330 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_DEFS_H_ +#define _SH_CSS_DEFS_H_ + +/* the max macro from the kernel only works within function context. We use + these macros also as global initializers (for now). for this, we need + the MAX macro. */ +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define CEIL_MUL(a, b) (CEIL_DIV(a, b) * (b)) +#define CEIL_DIV(a, b) ((b) ? ((a)+(b)-1)/(b) : 0) +#define CEIL_SHIFT(a, b) (((a)+(1<<(b))-1)>>(b)) + +/* Digital Image Stabilization */ +#define SH_CSS_DIS_DECI_FACTOR_LOG2 6 + +/* Width of a DDR word in bytes */ +#define HIVE_ISP_DDR_WORD_BYTES (HIVE_ISP_DDR_WORD_BITS/8) + +/* UV offset: 1:uv=-128...127, 0:uv=0...255 */ +#define SH_CSS_UV_OFFSET_IS_0 0 + +/* Bits of bayer is adjusted as 13 in ISP */ +#define SH_CSS_BAYER_BITS 13 +/* Max value of bayer data (unsigned 13bit in ISP) */ +#define SH_CSS_BAYER_MAXVAL ((1U << SH_CSS_BAYER_BITS) - 1) + +#define SH_CSS_DP_GAIN_SHIFT 5 +#define SH_CSS_BNR_GAIN_SHIFT 13 +#define SH_CSS_AE_YCOEF_SHIFT 13 +#define SH_CSS_AF_FIR_SHIFT 13 +#define SH_CSS_YEE_DETAIL_GAIN_SHIFT 8 /* [u5.8] */ +#define SH_CSS_YEE_SCALE_SHIFT 8 +#define SH_CSS_TNR_COEF_SHIFT 13 +#define SH_CSS_MACC_COEF_SHIFT 11 /* [s2.11] */ + +#define SH_CSS_NUM_INPUT_BUF_LINES 4 + +/* Left cropping only applicable for sufficiently large nway */ +#if ISP_VEC_NELEMS == 16 +#define SH_CSS_MAX_LEFT_CROPPING 0 +#else +#define SH_CSS_MAX_LEFT_CROPPING 8 +#endif + +#define SH_CSS_SP_MAX_WIDTH 2560 +#define SH_CSS_SP_MAX_OVERLAY_WIDTH 640 + +/* This is the maximum grid we can handle in the ISP binaries. + * The host code makes sure no bigger grid is ever selected. */ +#define SH_CSS_MAX_BQ_GRID_WIDTH 80 +#define SH_CSS_MAX_BQ_GRID_HEIGHT 60 + +/* The minimum dvs envelope is 8x8 to make sure the invalid rows/columns + that result from filter initialization are skipped. */ +#define SH_CSS_MIN_DVS_ENVELOPE 8 + +/* The FPGA system (vec_nelems == 16) only supports upto 5MP */ +#if ISP_VEC_NELEMS == 16 +#define SH_CSS_MAX_SENSOR_WIDTH 2560 +#define SH_CSS_MAX_SENSOR_HEIGHT 1920 +#else +#define SH_CSS_MAX_SENSOR_WIDTH 4608 +#define SH_CSS_MAX_SENSOR_HEIGHT 3450 +#endif + +#define SH_CSS_MIN_SENSOR_WIDTH 2 +#define SH_CSS_MIN_SENSOR_HEIGHT 2 + +#define SH_CSS_MAX_VF_WIDTH 1280 +#define SH_CSS_MAX_VF_HEIGHT 960 + +#define SH_CSS_DEFAULT_C_SUBSAMPLING 2 + +/* We use 16 bits per coordinate component, including integer + and fractional bits */ +#define SH_CSS_MORPH_TABLE_GRID ISP_VEC_NELEMS +#define SH_CSS_MORPH_TABLE_ELEM_BYTES 2 +#define SH_CSS_MORPH_TABLE_ELEMS_PER_DDR_WORD \ + (HIVE_ISP_DDR_WORD_BYTES/SH_CSS_MORPH_TABLE_ELEM_BYTES) + +#define SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR (SH_CSS_MAX_BQ_GRID_WIDTH + 1) +#define SH_CSS_MAX_SCTBL_ALIGNED_WIDTH_PER_COLOR \ + CEIL_MUL(SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR, ISP_VEC_NELEMS) + +/* Each line of this table is aligned to the maximum line width. */ +#define SH_CSS_MAX_S3ATBL_WIDTH SH_CSS_MAX_BQ_GRID_WIDTH + +/* Rules: these implement logic shared between the host code and ISP firmware. + The ISP firmware needs these rules to be applied at pre-processor time, + that's why these are macros, not functions. */ +#define _ISP_BQS(num) ((num)/2) +#define _ISP_VECS(width) CEIL_DIV(width, ISP_VEC_NELEMS) + +#define ISP_BQ_GRID_WIDTH(elements_per_line, deci_factor_log2) \ + CEIL_SHIFT(elements_per_line/2, deci_factor_log2) +#define ISP_BQ_GRID_HEIGHT(lines_per_frame, deci_factor_log2) \ + CEIL_SHIFT(lines_per_frame/2, deci_factor_log2) +#define ISP_C_VECTORS_PER_LINE(elements_per_line) \ + _ISP_VECS(elements_per_line/2) + +/* The morphing table is similar to the shading table in the sense that we + have 1 more value than we have cells in the grid. */ +#define _ISP_MORPH_TABLE_WIDTH(int_width) \ + (CEIL_DIV(int_width, SH_CSS_MORPH_TABLE_GRID) + 1) +#define _ISP_MORPH_TABLE_HEIGHT(int_height) \ + (CEIL_DIV(int_height, SH_CSS_MORPH_TABLE_GRID) + 1) +#define _ISP_MORPH_TABLE_ALIGNED_WIDTH(width) \ + CEIL_MUL(_ISP_MORPH_TABLE_WIDTH(width), \ + SH_CSS_MORPH_TABLE_ELEMS_PER_DDR_WORD) + +#define _ISP_SCTBL_WIDTH_PER_COLOR(input_width, deci_factor_log2) \ + (ISP_BQ_GRID_WIDTH(input_width, deci_factor_log2) + 1) +#define _ISP_SCTBL_HEIGHT(input_height, deci_factor_log2) \ + (ISP_BQ_GRID_HEIGHT(input_height, deci_factor_log2) + 1) +#define _ISP_SCTBL_ALIGNED_WIDTH_PER_COLOR(input_width, deci_factor_log2) \ + CEIL_MUL(_ISP_SCTBL_WIDTH_PER_COLOR(input_width, deci_factor_log2), \ + ISP_VEC_NELEMS) + +/* As an optimization we use DMEM to store the 3A statistics for fixed + * resolution primary binaries on the ASIC system (not on FPGA). */ +#define _S3ATBL_USE_DMEM(var_res) (ISP_VEC_NELEMS != 64 || !(var_res)) + +/* ******************************************************** + * Statistics for Digital Image Stabilization + * ********************************************************/ +/* Some binaries put the vertical coefficients in DMEM instead + of VMEM to save VMEM. */ +#define _SDIS_VER_COEF_TBL_USE_DMEM(mode, enable_sdis) \ + (mode == SH_CSS_BINARY_MODE_VIDEO && enable_sdis) + +/* SDIS Projections: + * Horizontal projections are calculated for each line. + * Vertical projections are calculated for each column. + * Grid cells that do not fall completely within the image are not + * valid. The host needs to use the bigger one for the stride but + * should only return the valid ones to the 3A. */ +#define __ISP_SDIS_HOR_PROJ_NUM_ISP(in_height, deci_factor_log2) \ + CEIL_SHIFT(_ISP_BQS(in_height), deci_factor_log2) +#define __ISP_SDIS_VER_PROJ_NUM_ISP(in_width, deci_factor_log2) \ + CEIL_SHIFT(_ISP_BQS(in_width), deci_factor_log2) + +#define _ISP_SDIS_HOR_PROJ_NUM_3A(in_height, deci_factor_log2) \ + (_ISP_BQS(in_height) >> deci_factor_log2) +#define _ISP_SDIS_VER_PROJ_NUM_3A(in_width, deci_factor_log2) \ + (_ISP_BQS(in_width) >> deci_factor_log2) + +/* SDIS Coefficients: */ +/* The ISP uses vectors to store the coefficients, so we round + the number of coefficients up to vectors. */ +#define __ISP_SDIS_HOR_COEF_NUM_VECS(in_width) _ISP_VECS(_ISP_BQS(in_width)) +#define __ISP_SDIS_VER_COEF_NUM_VECS(in_height) _ISP_VECS(_ISP_BQS(in_height)) + +/* The number of coefficients produced by the ISP */ +#define _ISP_SDIS_HOR_COEF_NUM_ISP(in_width) \ + (__ISP_SDIS_HOR_COEF_NUM_VECS(in_width) * ISP_VEC_NELEMS) +#define _ISP_SDIS_VER_COEF_NUM_ISP(in_height) \ + (__ISP_SDIS_VER_COEF_NUM_VECS(in_height) * ISP_VEC_NELEMS) + +/* The number of coefficients used by the 3A library. This excludes + coefficients from grid cells that do not fall completely within the image. */ +#define _ISP_SDIS_HOR_COEF_NUM_3A(in_width, deci_factor_log2) \ + ((_ISP_BQS(in_width) >> deci_factor_log2) << deci_factor_log2) +#define _ISP_SDIS_VER_COEF_NUM_3A(in_height, deci_factor_log2) \ + ((_ISP_BQS(in_height) >> deci_factor_log2) << deci_factor_log2) + +/* ***************************************************************** + * Statistics for 3A (Auto Focus, Auto White Balance, Auto Exposure) + * *****************************************************************/ +/* if left cropping is used, 3A statistics are also cropped by 2 vectors. */ +#define _ISP_S3ATBL_WIDTH(in_width, deci_factor_log2) \ + (_ISP_BQS(in_width) >> deci_factor_log2) +#define _ISP_S3ATBL_HEIGHT(in_height, deci_factor_log2) \ + (_ISP_BQS(in_height) >> deci_factor_log2) +#define _ISP_S3A_ISP_WIDTH(in_width, left_crop) \ + ((in_width) - ((left_crop) ? 2*ISP_VEC_NELEMS : 0)) +#define _ISP_S3ATBL_ISP_WIDTH(in_width, deci_log2, left_crop) \ + CEIL_SHIFT(_ISP_BQS(_ISP_S3A_ISP_WIDTH(in_width, left_crop)), deci_log2) +#define _ISP_S3ATBL_ISP_HEIGHT(in_height, deci_factor_log2) \ + CEIL_SHIFT(_ISP_BQS(in_height), deci_factor_log2) +#define ISP_S3ATBL_VECTORS \ + _ISP_VECS(SH_CSS_MAX_S3ATBL_WIDTH * \ + (sizeof(struct sh_css_3a_output)/sizeof(int))) +#define ISP_S3ATBL_HI_LO_STRIDE \ + (ISP_S3ATBL_VECTORS * ISP_VEC_NELEMS) +#define ISP_S3ATBL_HI_LO_STRIDE_BYTES \ + (sizeof(unsigned short) * ISP_S3ATBL_HI_LO_STRIDE) + +/* Viewfinder support */ +#define __ISP_MAX_VF_OUTPUT_WIDTH(width, left_crop) \ + (width - 2*ISP_VEC_NELEMS + ((left_crop) ? 2 * ISP_VEC_NELEMS : 0)) + +/* Number of vectors per vf line is determined by the chroma width, + * the luma width is derived from that. That's why we have the +1. */ +#define __ISP_VF_OUTPUT_WIDTH_VECS(out_width, vf_log_downscale) \ + (_ISP_VECS((out_width) >> ((vf_log_downscale)+1)) * 2) + +#define _ISP_VF_OUTPUT_WIDTH(vf_out_vecs) ((vf_out_vecs) * ISP_VEC_NELEMS) +#define _ISP_VF_OUTPUT_HEIGHT(out_height, vf_log_ds) \ + ((out_height) >> (vf_log_ds)) + +#define _ISP_LOG_VECTOR_STEP(mode) \ + ((mode) == SH_CSS_BINARY_MODE_CAPTURE_PP ? 2 : 1) + +/* Rules for computing the internal width. This is extremely complicated + * and definitely needs to be commented and explained. */ +#define _ISP_LEFT_CROP_EXTRA(left_crop) ((left_crop) > 0 ? 2*ISP_VEC_NELEMS : 0) + +#define __ISP_MIN_INTERNAL_WIDTH(num_chunks, pipelining, mode) \ + ((num_chunks) * (pipelining) * (1<<_ISP_LOG_VECTOR_STEP(mode)) * \ + ISP_VEC_NELEMS) +#define __ISP_PADDED_OUTPUT_WIDTH(out_width, dvs_env_width, left_crop) \ + ((out_width) + MAX(dvs_env_width, _ISP_LEFT_CROP_EXTRA(left_crop))) +#define __ISP_CHUNK_STRIDE_ISP(mode) \ + ((1<<_ISP_LOG_VECTOR_STEP(mode)) * ISP_VEC_NELEMS) +#define __ISP_CHUNK_STRIDE_DDR(c_subsampling, num_chunks) \ + ((c_subsampling) * (num_chunks) * HIVE_ISP_DDR_WORD_BYTES) +#define __ISP_INTERNAL_WIDTH(out_width, \ + dvs_env_width, \ + left_crop, \ + mode, \ + c_subsampling, \ + num_chunks, \ + pipelining) \ + CEIL_MUL(CEIL_MUL(MAX(__ISP_PADDED_OUTPUT_WIDTH(out_width, \ + dvs_env_width, \ + left_crop), \ + __ISP_MIN_INTERNAL_WIDTH(num_chunks, \ + pipelining, \ + mode) \ + ), \ + __ISP_CHUNK_STRIDE_ISP(mode) \ + ), \ + __ISP_CHUNK_STRIDE_DDR(c_subsampling, num_chunks) \ + ) + +#define __ISP_INTERNAL_HEIGHT(out_height, dvs_env_height, top_crop) \ + ((out_height) + (dvs_env_height) + top_crop) + +#define _ISP_MAX_INPUT_WIDTH(max_internal_width, enable_ds) \ + ((enable_ds) ? SH_CSS_MAX_SENSOR_WIDTH : max_internal_width) + +#define _ISP_INPUT_WIDTH(internal_width, ds_input_width, enable_ds) \ + ((enable_ds) ? (ds_input_width) : (internal_width)) + +#define _ISP_INPUT_HEIGHT(internal_height, ds_input_height, enable_ds) \ + ((enable_ds) ? (ds_input_height) : (internal_height)) + +#define SH_CSS_VF_OUTPUT_FORMATS \ + { \ + SH_CSS_FRAME_FORMAT_NV11, \ + SH_CSS_FRAME_FORMAT_NV12, \ + SH_CSS_FRAME_FORMAT_NV16, \ + SH_CSS_FRAME_FORMAT_NV21, \ + SH_CSS_FRAME_FORMAT_NV61, \ + SH_CSS_FRAME_FORMAT_YV12, \ + SH_CSS_FRAME_FORMAT_YV16, \ + SH_CSS_FRAME_FORMAT_YUV420, \ + SH_CSS_FRAME_FORMAT_YUV420_16, \ + SH_CSS_FRAME_FORMAT_YUV422, \ + SH_CSS_FRAME_FORMAT_YUV422_16, \ + SH_CSS_FRAME_FORMAT_UYVY, \ + SH_CSS_FRAME_FORMAT_YUYV, \ + SH_CSS_FRAME_FORMAT_RGB565, \ + SH_CSS_FRAME_FORMAT_PLANAR_RGB888, \ + SH_CSS_FRAME_FORMAT_RGBA888 \ + } + +#define SH_CSS_VIDEO_OUTPUT_FORMATS \ + { \ + SH_CSS_FRAME_FORMAT_NV11, \ + SH_CSS_FRAME_FORMAT_NV12, \ + SH_CSS_FRAME_FORMAT_NV16, \ + SH_CSS_FRAME_FORMAT_NV21, \ + SH_CSS_FRAME_FORMAT_NV61, \ + SH_CSS_FRAME_FORMAT_YV12, \ + SH_CSS_FRAME_FORMAT_YV16, \ + SH_CSS_FRAME_FORMAT_YUV420, \ + SH_CSS_FRAME_FORMAT_YUV420_16, \ + SH_CSS_FRAME_FORMAT_YUV422, \ + SH_CSS_FRAME_FORMAT_YUV422_16, \ + SH_CSS_FRAME_FORMAT_UYVY, \ + SH_CSS_FRAME_FORMAT_YUYV \ + } + +#define SH_CSS_CAPTURE_OUTPUT_FORMATS \ + { \ + SH_CSS_FRAME_FORMAT_NV12, \ + SH_CSS_FRAME_FORMAT_NV16, \ + SH_CSS_FRAME_FORMAT_NV21, \ + SH_CSS_FRAME_FORMAT_NV61, \ + SH_CSS_FRAME_FORMAT_YV12, \ + SH_CSS_FRAME_FORMAT_YV16, \ + SH_CSS_FRAME_FORMAT_YUV420, \ + SH_CSS_FRAME_FORMAT_YUV420_16, \ + SH_CSS_FRAME_FORMAT_YUV422, \ + SH_CSS_FRAME_FORMAT_YUV422_16, \ + SH_CSS_FRAME_FORMAT_UYVY, \ + SH_CSS_FRAME_FORMAT_YUYV, \ + SH_CSS_FRAME_FORMAT_YUV444, \ + SH_CSS_FRAME_FORMAT_RGB565, \ + SH_CSS_FRAME_FORMAT_PLANAR_RGB888, \ + SH_CSS_FRAME_FORMAT_RGBA888 \ + } + +/* Fixed resolution primaries only output this format */ +#define SH_CSS_FIXED_PRIMARY_FORMAT SH_CSS_FRAME_FORMAT_NV12 + +#endif /* _SH_CSS_DEFS_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_firmware.c b/drivers/media/video/atomisp/css/sh_css_firmware.c new file mode 100644 index 0000000..99dcd73 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_firmware.c @@ -0,0 +1,115 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css_hrt.h" +#include "sh_css_defs.h" +#include "sh_css_firmware.h" +#include "sh_css_internal.h" + +/* One extra for the sp binary */ +#define NUM_BINARIES (SH_CSS_BINARY_NUM_IDS+1) + +struct sh_css_sp_fw sh_css_sp_fw; +struct sh_css_blob_info sh_css_blob_info[SH_CSS_BINARY_NUM_IDS]; + +/* + * Split the loaded firmware into blobs + */ + +/* Setup sp binary */ +static void +setup_sp(struct sh_css_fw_bi_h *fw, const char *fw_data) +{ + const char *blob_data; + unsigned int blob_size; + + blob_data = fw_data + fw->offset; + blob_size = fw->size; + + sh_css_sp_fw.text = blob_data + fw->text_source; + sh_css_sp_fw.text_size = fw->text_size; + + sh_css_sp_fw.data = blob_data + fw->data_source; + sh_css_sp_fw.data_target = fw->data_target; + sh_css_sp_fw.data_size = fw->data_size; + + sh_css_sp_fw.bss_target = fw->bss_target; + sh_css_sp_fw.bss_size = fw->bss_size; +} + +enum sh_css_err +sh_css_load_firmware(const char *fw_data, + unsigned int fw_size) +{ + int i, num_binaries; + struct sh_css_fw_bi_h *binaries; + struct sh_css_fw_bi_file_h *file_header; + + file_header = (struct sh_css_fw_bi_file_h *)fw_data; + binaries = (struct sh_css_fw_bi_h *)(&file_header[1]); + + /* some sanity checks */ + if (!fw_data || fw_size < sizeof(struct sh_css_fw_bi_file_h)) + return sh_css_err_internal_error; + + if (file_header->h_size != sizeof(struct sh_css_fw_bi_file_h)) + return sh_css_err_internal_error; + + num_binaries = file_header->binary_nr; + + for (i = 0; i < num_binaries; i++) { + struct sh_css_fw_bi_h *bi = &binaries[i]; + + /* sanity check */ + if (bi->size != bi->text_size + bi->data_size) + return sh_css_err_internal_error; + + if (bi->offset + bi->size > fw_size) + return sh_css_err_internal_error; + + if (bi->id == 0) { + setup_sp(bi, fw_data); + } else if (bi->id > 0) { + const unsigned char *blob = fw_data + bi->offset; + sh_css_blob_info[bi->id-1].blob = blob; + sh_css_blob_info[bi->id-1].size = bi->size; + } + } + return sh_css_success; +} + +void * +sh_css_load_blob(const unsigned char *blob, unsigned size) +{ + void *target_addr = hrt_isp_css_mm_alloc(size); + /* this will allocate memory aligned to a DDR word boundary which + is required for the CSS DMA to read the instructions. */ + hrt_isp_css_mm_store(target_addr, blob, size); + if (SH_CSS_PREVENT_UNINIT_READS) { + unsigned i; + unsigned padded_size = CEIL_MUL(size, HIVE_ISP_DDR_WORD_BYTES); + for (i = 0; i < padded_size - size; i++) + hrt_isp_css_mm_store_char(target_addr + size + i, 0); + } + return target_addr; +} diff --git a/drivers/media/video/atomisp/css/sh_css_firmware.h b/drivers/media/video/atomisp/css/sh_css_firmware.h new file mode 100644 index 0000000..62a4e85 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_firmware.h @@ -0,0 +1,63 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_FIRMWARE_H_ +#define _SH_CSS_FIRMWARE_H_ + +#include "sh_css_binary.h" + +/* This is for the firmware loaded from user space */ +struct sh_css_fw_bi_file_h { + int version; /* Date in the form YYYYMMDD */ + int binary_nr; /* Number of binaries */ + unsigned int h_size; /* sizeof(struct sh_css_fw_bi_file_h) */ +}; + +struct sh_css_fw_bi_h { + int id; /* Binary id */ + unsigned int offset; /* Offset in firmware file */ + unsigned int size; /* Size of blob */ + unsigned int text_source; + unsigned int text_size; + unsigned int data_source; + unsigned int data_target; + unsigned int data_size; + unsigned int bss_target; + unsigned int bss_size; +}; + +struct sh_css_blob_info { + const unsigned char *blob; + unsigned int size; +}; + +extern struct sh_css_sp_fw sh_css_sp_fw; +extern struct sh_css_blob_info sh_css_blob_info[SH_CSS_BINARY_NUM_IDS]; + +enum sh_css_err +sh_css_load_firmware(const char *fw_data, + unsigned int fw_size); + +void *sh_css_load_blob(const unsigned char *blob, unsigned size); + +#endif /* _SH_CSS_FIRMWARE_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_hrt.c b/drivers/media/video/atomisp/css/sh_css_hrt.c new file mode 100644 index 0000000..5a6d415 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_hrt.c @@ -0,0 +1,1922 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css_hrt.h" +#include "sh_css_internal.h" +#define HRT_NO_BLOB_sp +#include "sp.map.h" +#include "sh_css.h" +#include "sh_css_hw.h" +#include "sh_css_debug.h" + +/* The data type is used to send special cases: + * yuv420: odd lines (1, 3 etc) are twice as wide as even + * lines (0, 2, 4 etc). + * rgb: for two pixels per clock, the R and B values are sent + * to output_0 while only G is sent to output_1. This means + * that output_1 only gets half the number of values of output_0. + * WARNING: This type should also be used for Legacy YUV420. + * regular: used for all other data types (RAW, YUV422, etc) + */ +enum sh_css_mipi_data_type { + sh_css_mipi_data_type_regular, + sh_css_mipi_data_type_yuv420, + sh_css_mipi_data_type_yuv420_legacy, + sh_css_mipi_data_type_rgb, +}; + +/* these are unsigned long pointers such that we can simply + * add the register index to get the right address. + */ +static unsigned long *mmu_base_address = MMU_BASE, + *gdc_lut_base_address = GDC_LUT_BASE, + *dma_base_address = DMA_BASE, + *if_prim_a_base_address = IF_PRIM_A_BASE, + *if_prim_b_base_address = IF_PRIM_B_BASE, + *sp_sc_base_address = SP_SC_BASE, + *isp_sc_base_address = ISP_SC_BASE, + *str_monitor_base_address = STR_MON_BASE, + *irq_ctrl_base_address = IRQ_CTRL_BASE, + *gp_fifo_base_address = GP_FIFO_BASE; + +static unsigned int curr_ch_id, curr_fmt_type; + +void +sh_css_sp_ctrl_store(unsigned int reg, unsigned int value) +{ + unsigned int addr = (unsigned int)(sp_sc_base_address + reg); + hrt_master_port_store_32(addr, value); +} + +static unsigned long +sh_css_sp_ctrl_load(unsigned int reg) +{ + unsigned int addr = (unsigned int)(sp_sc_base_address + reg); + return hrt_master_port_uload_32(addr); +} + +static unsigned long +sh_css_isp_ctrl_load(unsigned int reg) +{ + unsigned int addr = (unsigned int)(isp_sc_base_address + reg); + return hrt_master_port_uload_32(addr); +} + +static unsigned int +isp_ctrl_get_bit(unsigned int reg, unsigned int bit) +{ + unsigned long val; + val = sh_css_isp_ctrl_load(reg); + return (val & (1U << bit)) != 0; +} + +void +sh_css_sp_ctrl_set_bits(unsigned int reg, unsigned long bits) +{ + unsigned long val; + val = sh_css_sp_ctrl_load(reg); + val |= bits; + sh_css_sp_ctrl_store(reg, val); +} + +static unsigned int +sp_ctrl_get_bit(unsigned int reg, unsigned int bit) +{ + unsigned long val; + val = sh_css_sp_ctrl_load(reg); + return (val & (1U << bit)) != 0; +} + +static void +sh_css_sp_ctrl_reset_bits(unsigned int reg, unsigned long bits) +{ + unsigned long val; + val = sh_css_sp_ctrl_load(reg); + val &= ~bits; + sh_css_sp_ctrl_store(reg, val); +} + +void +sh_css_hrt_irq_enable_sp(bool enable) +{ + if (enable) + sh_css_sp_ctrl_set_bits(SP_IRQ_READY_REG, + 1UL<pc = sh_css_sp_ctrl_load(SP_PC_REG); + state->status_register = sc; + state->is_broken = (sc & (1U << SP_BROKEN_BIT)) != 0; + state->is_idle = (sc & (1U << SP_IDLE_BIT)) != 0; + state->is_sleeping = (sc & (1U << SP_SLEEPING_BIT)) != 0; + state->is_stalling = (sc & (1U << SP_STALLING_BIT)) != 0; + stall_state->fifo0 = + sp_ctrl_get_bit(SP_FIFO0_SINK_BIT, SP_FIFO0_SINK_REG); + stall_state->fifo1 = + sp_ctrl_get_bit(SP_FIFO1_SINK_BIT, SP_FIFO1_SINK_REG); + stall_state->fifo2 = + sp_ctrl_get_bit(SP_FIFO2_SINK_BIT, SP_FIFO2_SINK_REG); + stall_state->fifo3 = + sp_ctrl_get_bit(SP_FIFO3_SINK_BIT, SP_FIFO3_SINK_REG); + stall_state->fifo4 = + sp_ctrl_get_bit(SP_FIFO4_SINK_BIT, SP_FIFO4_SINK_REG); + stall_state->fifo5 = + sp_ctrl_get_bit(SP_FIFO5_SINK_BIT, SP_FIFO5_SINK_REG); + stall_state->fifo6 = + sp_ctrl_get_bit(SP_FIFO6_SINK_BIT, SP_FIFO6_SINK_REG); + stall_state->fifo7 = + sp_ctrl_get_bit(SP_FIFO7_SINK_BIT, SP_FIFO7_SINK_REG); + stall_state->dmem = + sp_ctrl_get_bit(SP_DMEM_SINK_BIT, SP_DMEM_SINK_REG); + stall_state->control_master = + sp_ctrl_get_bit(SP_CTRL_MT_SINK_BIT, SP_CTRL_MT_SINK_REG); + stall_state->icache_master = + sp_ctrl_get_bit(SP_ICACHE_MT_SINK_BIT, SP_ICACHE_MT_SINK_REG); +} + +void +sh_css_hrt_isp_get_state(struct sh_css_cell_state *state, + struct sh_css_isp_stall_state *stall_state) +{ + unsigned int sc; + sc = sh_css_isp_ctrl_load(ISP_SC_REG); + state->pc = sh_css_isp_ctrl_load(ISP_PC_REG); + state->status_register = sc; + state->is_broken = isp_ctrl_get_bit(ISP_SC_REG, ISP_BROKEN_BIT); + state->is_idle = isp_ctrl_get_bit(ISP_SC_REG, ISP_IDLE_BIT); + state->is_sleeping = isp_ctrl_get_bit(ISP_SC_REG, ISP_SLEEPING_BIT); + state->is_stalling = isp_ctrl_get_bit(ISP_SC_REG, ISP_STALLING_BIT); + stall_state->stat_ctrl = + isp_ctrl_get_bit(ISP_CTRL_SINK_BIT, ISP_CTRL_SINK_REG); + stall_state->dmem = + isp_ctrl_get_bit(ISP_DMEM_SINK_BIT, ISP_DMEM_SINK_REG); + stall_state->vmem = + isp_ctrl_get_bit(ISP_VMEM_SINK_BIT, ISP_VMEM_SINK_REG); + stall_state->fifo0 = + isp_ctrl_get_bit(ISP_FIFO0_SINK_BIT, ISP_FIFO0_SINK_REG); + stall_state->fifo1 = + isp_ctrl_get_bit(ISP_FIFO1_SINK_BIT, ISP_FIFO1_SINK_REG); + stall_state->fifo2 = + isp_ctrl_get_bit(ISP_FIFO2_SINK_BIT, ISP_FIFO2_SINK_REG); + stall_state->fifo3 = + isp_ctrl_get_bit(ISP_FIFO3_SINK_BIT, ISP_FIFO3_SINK_REG); + stall_state->fifo4 = + isp_ctrl_get_bit(ISP_FIFO4_SINK_BIT, ISP_FIFO4_SINK_REG); + stall_state->fifo5 = + isp_ctrl_get_bit(ISP_FIFO5_SINK_BIT, ISP_FIFO5_SINK_REG); + stall_state->vamem1 = + isp_ctrl_get_bit(ISP_VAMEM1_SINK_BIT, ISP_VAMEM1_SINK_REG); + stall_state->vamem2 = + isp_ctrl_get_bit(ISP_VAMEM2_SINK_BIT, ISP_VAMEM2_SINK_REG); +} + +static inline unsigned long +_sh_css_dma_get_register(unsigned int addr) +{ + unsigned char *dma_base = (unsigned char *)dma_base_address; + unsigned int bus_addr = (unsigned int)(dma_base + addr); + return hrt_master_port_load_32(bus_addr); +} + +/* Command FSM state */ +static inline unsigned +sh_css_dma_get_command_fsm_state(void) +{ + return _sh_css_dma_get_register(_hrt_dma_v1_sel_comp(0)); +} + +/* Get channel parameters */ +static inline unsigned +_sh_css_dma_get_channel_parameter(int ch, int param) +{ + return _sh_css_dma_get_register( + hrt_dma_v1_channel_parameter_register_address(ch, param)); +} + +static inline unsigned +sh_css_dma_get_channel_connection(int channel) +{ + return _hrt_dma_v1_get_connection( + _sh_css_dma_get_channel_parameter(channel, 0)); +} + +static inline unsigned +sh_css_dma_get_channel_extension(int channel) +{ + return _hrt_dma_v1_get_extension( + _sh_css_dma_get_channel_parameter(channel, 0)); +} + +static inline unsigned +sh_css_dma_get_channel_element_order(int channel) +{ + return _hrt_dma_v1_get_element_order( + _sh_css_dma_get_channel_parameter(channel, 0)); +} + +static inline unsigned +sh_css_dma_get_channel_stride_A(int channel) +{ + return _sh_css_dma_get_channel_parameter(channel, 1); +} + +static inline unsigned +sh_css_dma_get_channel_elements_A(int channel) +{ + return _hrt_dma_v1_get_elements( + _sh_css_dma_get_channel_parameter(channel, 2)); +} + +static inline unsigned +sh_css_dma_get_channel_cropping_A(int channel) +{ + return _hrt_dma_v1_get_cropping( + _sh_css_dma_get_channel_parameter(channel, 2)); +} + +static inline unsigned +sh_css_dma_get_channel_width_A(int channel) +{ + return _sh_css_dma_get_channel_parameter(channel, 3); +} + +static inline unsigned +sh_css_dma_get_channel_stride_B(int channel) +{ + return _sh_css_dma_get_channel_parameter(channel, 4); +} + +static inline unsigned +sh_css_dma_get_channel_elements_B(int channel) +{ + return _hrt_dma_v1_get_elements( + _sh_css_dma_get_channel_parameter(channel, 5)); +} + +static inline unsigned +sh_css_dma_get_channel_cropping_B(int channel) +{ + return _hrt_dma_v1_get_cropping( + _sh_css_dma_get_channel_parameter(channel, 5)); +} + +static inline unsigned +sh_css_dma_get_channel_width_B(int channel) +{ + return _sh_css_dma_get_channel_parameter(channel, 6); +} + +static inline unsigned +sh_css_dma_get_channel_height(int channel) +{ + return _sh_css_dma_get_channel_parameter(channel, 7); +} + +/* Connection group */ + +static inline unsigned +_sh_css_dma_get_conn_group_info(int info_id, int comp_id, int gr_id) +{ + return _sh_css_dma_get_register( + hrt_dma_v1_conn_group_info_register_address(info_id, + comp_id, gr_id)); +} + +static inline unsigned +sh_css_dma_get_conn_group_command(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(0, 0, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_address_A(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(0, 1, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_address_B(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(0, 2, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_state(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(0, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_request_device(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(1, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_request_address(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(2, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_request_stride(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(3, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_request_width(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(4, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_request_height(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(5, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_request_device(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(6, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_write_device(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(7, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_write_address(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(8, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_write_stride(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(9, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_request_width(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(10, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_write_height(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(11, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_write_width(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(12, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_request_elems(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(13, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_write_elems(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(14, 3, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_control_pack_extension_and_elem_order(int + gr_id) +{ + return _sh_css_dma_get_conn_group_info(15, 3, gr_id); +} + +static inline unsigned sh_css_dma_get_conn_group_fsm_pack_state(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(0, 4, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_pack_counter_height(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(1, 4, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_pack_request_counter_width(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(2, 4, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_pack_write_counter_width(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(3, 4, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_request_state(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(0, 5, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_request_counter_height(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(1, 5, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_request_counter_width(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(2, 5, gr_id); +} + +static inline unsigned +sh_css_dma_get_conn_group_fsm_write_height(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(1, 6, gr_id); +} + +static inline unsigned sh_css_dma_get_conn_group_fsm_write_width(int gr_id) +{ + return _sh_css_dma_get_conn_group_info(2, 6, gr_id); +} + +/* Device Interface */ +static inline unsigned +_sh_css_dma_get_device_interface_info(int info_id, int dev_id) +{ + return _sh_css_dma_get_register( + hrt_dma_v1_device_interface_info_register_address(info_id, + dev_id)); +} + +static inline unsigned +sh_css_dma_get_device_interface_request_side_state(int dev_id) +{ + return _sh_css_dma_get_device_interface_info(0, dev_id); +} + +static inline unsigned +sh_css_dma_get_device_interface_send_side_state(int dev_id) +{ + return _sh_css_dma_get_device_interface_info(1, dev_id); +} + +static inline unsigned +sh_css_dma_get_device_interface_fifo_state(int dev_id) +{ + return _sh_css_dma_get_device_interface_info(2, dev_id); +} + +void +sh_css_hrt_dma_get_state(struct sh_css_dma_state *state) +{ + int tmp, i, num_ports = 3, num_channels = 8; + tmp = sh_css_dma_get_command_fsm_state(); + state->fsm_command_idle = tmp & 0x1; + state->fsm_command_run = tmp & 0x2; + state->fsm_command_stalling = tmp & 0x4; + state->fsm_command_error = tmp & 0x8; + state->last_command_channel = (tmp>>8 & 0xFF); + state->last_command_param = (tmp>>16 & 0xF); + tmp = (tmp>>4) & 0xF; + if (tmp == 0) + state->last_command = sh_css_dma_command_read; + if (tmp == 1) + state->last_command = sh_css_dma_command_write; + if (tmp == 2) + state->last_command = sh_css_dma_command_set_channel; + if (tmp == 3) + state->last_command = sh_css_dma_command_set_param; + if (tmp == 4) + state->last_command = sh_css_dma_command_read_spec; + if (tmp == 5) + state->last_command = sh_css_dma_command_write_spec; + if (tmp == 8) + state->last_command = sh_css_dma_command_init; + if (tmp == 12) + state->last_command = sh_css_dma_command_init_spec; + if (tmp == 15) + state->last_command = sh_css_dma_command_reset; + state->current_command = sh_css_dma_get_conn_group_command(0); + state->current_addr_a = sh_css_dma_get_conn_group_address_A(0); + state->current_addr_b = sh_css_dma_get_conn_group_address_B(0); + tmp = sh_css_dma_get_conn_group_fsm_control_state(0); + state->fsm_ctrl_idle = tmp & 0x1; + state->fsm_ctrl_run = tmp & 0x2; + state->fsm_ctrl_stalling = tmp & 0x4; + state->fsm_ctrl_error = tmp & 0x8; + tmp = tmp >> 4; + if (tmp == 0) + state->fsm_ctrl_state = sh_css_dma_ctrl_state_idle; + if (tmp == 1) + state->fsm_ctrl_state = sh_css_dma_ctrl_state_req_rcv; + if (tmp == 2) + state->fsm_ctrl_state = sh_css_dma_ctrl_state_rcv; + if (tmp == 3) + state->fsm_ctrl_state = sh_css_dma_ctrl_state_rcv_req; + if (tmp == 4) + state->fsm_ctrl_state = sh_css_dma_ctrl_state_init; + state->fsm_ctrl_source_dev = + sh_css_dma_get_conn_group_fsm_control_request_device(0); + state->fsm_ctrl_source_addr = + sh_css_dma_get_conn_group_fsm_control_request_address(0); + state->fsm_ctrl_source_stride = + sh_css_dma_get_conn_group_fsm_control_request_stride(0); + state->fsm_ctrl_source_width = + sh_css_dma_get_conn_group_fsm_control_request_width(0); + state->fsm_ctrl_source_height = + sh_css_dma_get_conn_group_fsm_control_request_height(0); + state->fsm_ctrl_pack_source_dev = + sh_css_dma_get_conn_group_fsm_control_pack_request_device(0); + state->fsm_ctrl_pack_dest_dev = + sh_css_dma_get_conn_group_fsm_control_pack_write_device(0); + state->fsm_ctrl_dest_addr = + sh_css_dma_get_conn_group_fsm_control_write_address(0); + state->fsm_ctrl_dest_stride = + sh_css_dma_get_conn_group_fsm_control_write_stride(0); + state->fsm_ctrl_pack_source_width = + sh_css_dma_get_conn_group_fsm_control_pack_request_width(0); + state->fsm_ctrl_pack_dest_height = + sh_css_dma_get_conn_group_fsm_control_pack_write_height(0); + state->fsm_ctrl_pack_dest_width = + sh_css_dma_get_conn_group_fsm_control_pack_write_width(0); + state->fsm_ctrl_pack_source_elems = + sh_css_dma_get_conn_group_fsm_control_pack_request_elems(0); + state->fsm_ctrl_pack_dest_elems = + sh_css_dma_get_conn_group_fsm_control_pack_write_elems(0); + state->fsm_ctrl_pack_extension = + sh_css_dma_get_conn_group_fsm_control_pack_extension_and_elem_order(0); + tmp = sh_css_dma_get_conn_group_fsm_pack_state(0); + state->pack_idle = tmp & 0x1; + state->pack_run = tmp & 0x2; + state->pack_stalling = tmp & 0x4; + state->pack_error = tmp & 0x8; + state->pack_cnt_height = + sh_css_dma_get_conn_group_fsm_pack_counter_height(0); + state->pack_src_cnt_width = + sh_css_dma_get_conn_group_fsm_pack_request_counter_width(0); + state->pack_dest_cnt_width = + sh_css_dma_get_conn_group_fsm_pack_write_counter_width(0); + tmp = sh_css_dma_get_conn_group_fsm_request_state(0) & 0x3; + if (tmp == 0) + state->read_state = sh_css_dma_rw_state_idle; + if (tmp == 1) + state->read_state = sh_css_dma_rw_state_req; + if (tmp == 2) + state->read_state = sh_css_dma_rw_state_next_line; + if (tmp == 3) + state->read_state = sh_css_dma_rw_state_unlock_channel; + state->read_cnt_height = + sh_css_dma_get_conn_group_fsm_request_counter_height(0); + state->read_cnt_width = + sh_css_dma_get_conn_group_fsm_request_counter_width(0); + tmp = sh_css_dma_get_conn_group_fsm_request_state(0) & 0x3; + if (tmp == 0) + state->write_state = sh_css_dma_rw_state_idle; + if (tmp == 1) + state->write_state = sh_css_dma_rw_state_req; + if (tmp == 2) + state->write_state = sh_css_dma_rw_state_next_line; + if (tmp == 3) + state->write_state = sh_css_dma_rw_state_unlock_channel; + state->write_height = + sh_css_dma_get_conn_group_fsm_write_height(0); + state->write_width = sh_css_dma_get_conn_group_fsm_write_width(0); + for (i = 0; i < num_ports; i++) { + tmp = + sh_css_dma_get_device_interface_request_side_state(i); + state->port_states[i].req_cs = (tmp & 0x1) != 0; + state->port_states[i].req_we_n = (tmp & 0x2) != 0; + state->port_states[i].req_run = (tmp & 0x4) != 0; + state->port_states[i].req_ack = (tmp & 0x8) != 0; + tmp = sh_css_dma_get_device_interface_send_side_state(i); + state->port_states[i].send_cs = (tmp & 0x1) != 0; + state->port_states[i].send_we_n = (tmp & 0x2) != 0; + state->port_states[i].send_run = (tmp & 0x4) != 0; + state->port_states[i].send_ack = (tmp & 0x8) != 0; + tmp = sh_css_dma_get_device_interface_fifo_state(i); + if (tmp & 0x1) { + state->port_states[i].fifo_state = + sh_css_dma_fifo_state_will_be_full; + } + if (tmp & 0x2) { + state->port_states[i].fifo_state = + sh_css_dma_fifo_state_full; + } + if (tmp & 0x4) { + state->port_states[i].fifo_state = + sh_css_dma_fifo_state_empty; + } + state->port_states[i].fifo_counter = tmp >> 3; + } + for (i = 0; i < num_channels; i++) { + state->channel_states[i].connection = + sh_css_dma_get_channel_connection(i); + state->channel_states[i].sign_extend = + sh_css_dma_get_channel_extension(i); + state->channel_states[i].reverse_elem_order = + sh_css_dma_get_channel_element_order(i); + state->channel_states[i].height = + sh_css_dma_get_channel_height(i); + state->channel_states[i].stride_a = + sh_css_dma_get_channel_stride_A(i); + state->channel_states[i].elems_a = + sh_css_dma_get_channel_elements_A(i); + state->channel_states[i].cropping_a = + sh_css_dma_get_channel_cropping_A(i); + state->channel_states[i].width_a = + sh_css_dma_get_channel_width_A(i); + state->channel_states[i].stride_b = + sh_css_dma_get_channel_stride_B(i); + state->channel_states[i].elems_b = + sh_css_dma_get_channel_elements_B(i); + state->channel_states[i].cropping_b = + sh_css_dma_get_channel_cropping_B(i); + state->channel_states[i].width_b = + sh_css_dma_get_channel_width_B(i); + } +} + +static inline void +_sh_css_gdc_set_lut_entry(unsigned int index, unsigned int val) +{ + hrt_master_port_store_32(gdc_lut_base_address + index, val); +} + +void +sh_css_hrt_gdc_set_lut(const int lut[4][HRT_GDC_N]) +{ + unsigned int i, entry_0, entry_1, entry_2, entry_3, + word_0, word_1, lut_offset = HRT_GDC_LUT_IDX; + + for (i = 0; i < HRT_GDC_N; i++) { + entry_0 = lut[0][i] & HRT_GDC_BCI_COEF_MASK; + entry_1 = lut[1][i] & HRT_GDC_BCI_COEF_MASK; + entry_2 = lut[2][i] & HRT_GDC_BCI_COEF_MASK; + entry_3 = lut[3][i] & HRT_GDC_BCI_COEF_MASK; + word_0 = entry_0 | (entry_1 << HRT_GDC_BCI_COEF_BITS); + word_1 = entry_2 | (entry_3 << HRT_GDC_BCI_COEF_BITS); + _sh_css_gdc_set_lut_entry(lut_offset++, word_0); + _sh_css_gdc_set_lut_entry(lut_offset++, word_1); + } +} + +static inline void +_sh_css_mmu_set_register(unsigned int index, unsigned int value) +{ + hrt_master_port_store_32(mmu_base_address + index, value); +} + +static inline unsigned int +_sh_css_mmu_get_register(unsigned int index) +{ + return hrt_master_port_uload_32(mmu_base_address + index); +} + +void +sh_css_hrt_mmu_set_page_table_base_address(void *base_address) +{ + _sh_css_mmu_set_register(_HRT_MMU_PAGE_TABLE_BASE_ADDRESS_REG_IDX, + (unsigned long)base_address); +} + +void * +sh_css_hrt_mmu_get_page_table_base_address(void) +{ + return (void *)_sh_css_mmu_get_register( + _HRT_MMU_PAGE_TABLE_BASE_ADDRESS_REG_IDX); +} + +void +sh_css_hrt_mmu_invalidate_cache(void) +{ + _sh_css_mmu_set_register(_HRT_MMU_INVALIDATE_TLB_REG_IDX, 1); +} + +static inline unsigned long +_sh_css_if_get_register(unsigned long *base, unsigned addr) +{ + /* offsets are in bytes, so we cast the base to char* + to get the right address for each register */ + unsigned char *if_base = (unsigned char *)base; + unsigned int bus_addr = (unsigned int)(if_base + addr); + return hrt_master_port_load_32(bus_addr); +} + +static inline void +_sh_css_if_set_register(unsigned long *base, unsigned addr, unsigned long value) +{ + /* offsets are in bytes, so we cast the base to char* + to get the right address for each register */ + unsigned char *if_base = (unsigned char *)base; + unsigned int bus_addr = (unsigned int)(if_base + addr); + hrt_master_port_store_32(bus_addr, value); + /* hack */ + (void)hrt_master_port_load_32(bus_addr); +} + +static inline unsigned +sh_css_if_get_start_line(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_START_LINE_ADDRESS); +} + +static inline unsigned +sh_css_if_get_start_column(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_START_COLUMN_ADDRESS); +} + +static inline unsigned +sh_css_if_get_cropped_height(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_CROPPED_HEIGHT_ADDRESS); +} + +static inline unsigned +sh_css_if_get_cropped_width(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_CROPPED_WIDTH_ADDRESS); +} + +static inline unsigned +sh_css_if_get_vertical_decimation(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_VERTICAL_DECIMATION_ADDRESS); +} + +static inline unsigned +sh_css_if_get_horizontal_decimation(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_HORIZONTAL_DECIMATION_ADDRESS); +} + +static inline unsigned +sh_css_if_get_v_deinterleaving(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_V_DEINTERLEAVING_ADDRESS); +} + +static inline unsigned +sh_css_if_get_h_deinterleaving(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_H_DEINTERLEAVING_ADDRESS); +} + +static inline unsigned +sh_css_if_get_leftpadding_width(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_LEFTPADDING_WIDTH_ADDRESS); +} + +static inline unsigned +sh_css_if_get_vmem_start_address(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_VMEM_START_ADDRESS_ADDRESS); +} + +static inline unsigned +sh_css_if_get_end_of_line_offset(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_END_OF_LINE_OFFSET_ADDRESS); +} + +static inline unsigned +sh_css_if_get_vmem_end_address(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_VMEM_END_ADDRESS_ADDRESS); +} + +static inline unsigned +sh_css_if_get_allow_fifo_overflow(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_ALLOW_FIFO_OVERFLOW_ADDRESS); +} + +static inline unsigned +sh_css_if_get_vmem_increment(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_VMEM_INCREMENT_ADDRESS); +} + +static inline unsigned +sh_css_if_get_fsm_sync_counter(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, HIVE_IF_FSM_SYNC_COUNTER); +} + +static inline unsigned +sh_css_if_get_fsm_crop_status(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, HIVE_IF_FSM_CROP_STATUS); +} + +static inline unsigned +sh_css_if_get_fsm_crop_line_counter(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_CROP_LINE_COUNTER); +} + +static inline unsigned +sh_css_if_get_fsm_crop_pixel_counter(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_CROP_PIXEL_COUNTER); +} + +static inline unsigned +sh_css_if_get_fsm_deinterleaving_index(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_DEINTERLEAVING_IDX); +} + +static inline unsigned +sh_css_if_get_fsm_dec_h_counter(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_DECIMATION_H_COUNTER); +} + +static inline unsigned +sh_css_if_get_fsm_dec_v_counter(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_DECIMATION_V_COUNTER); +} + +static inline unsigned +sh_css_if_get_fsm_dec_block_v_counter(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_DECIMATION_BLOCK_V_COUNTER); +} + +static inline unsigned +sh_css_if_get_fsm_padding_status(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_PADDING_STATUS); +} + +static inline unsigned +sh_css_if_get_fsm_padding_elem_counter(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_PADDING_ELEMENT_COUNTER); +} + +static inline unsigned +sh_css_if_get_fsm_vector_support_error(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_VECTOR_SUPPORT_ERROR); +} + +static inline unsigned +sh_css_if_get_fsm_vector_buffer_full(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_VECTOR_SUPPORT_BUFF_FULL); +} + +static inline unsigned +sh_css_if_get_vector_support(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FSM_VECTOR_SUPPORT); +} + +static inline unsigned +sh_css_if_get_sensor_data_lost(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_FIFO_SENSOR_DATA_LOST); +} + +static inline unsigned +sh_css_if_get_reset(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, HIVE_IF_RESET_ADDRESS); +} + +static inline unsigned +sh_css_if_get_fsm_sync_status(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, HIVE_IF_FSM_SYNC_STATUS); +} + +static inline unsigned +sh_css_if_get_yuv_420_format(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_YUV_420_FORMAT_ADDRESS); +} + +static inline unsigned +sh_css_if_get_vsynck_active_low(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_VSYNCK_ACTIVE_LOW_ADDRESS); +} + +static inline unsigned +sh_css_if_get_hsynck_active_low(unsigned long *ifbase) +{ + return _sh_css_if_get_register(ifbase, + HIVE_IF_HSYNCK_ACTIVE_LOW_ADDRESS); +} + +static inline void +sh_css_if_set_block_fifo_no_reqs(unsigned long *ifbase, bool enable) +{ + _sh_css_if_set_register(ifbase, + HIVE_IF_BLOCK_FIFO_NO_REQ_ADDRESS, + enable); +} + +static void +sh_css_if_get_state(unsigned long *ifbase, struct sh_css_if_state *state) +{ + state->reset = sh_css_if_get_reset(ifbase); + state->start_line = sh_css_if_get_start_line(ifbase); + state->start_column = sh_css_if_get_start_column(ifbase); + state->cropped_height = sh_css_if_get_cropped_height(ifbase); + state->cropped_width = sh_css_if_get_cropped_width(ifbase); + state->ver_decimation = sh_css_if_get_vertical_decimation(ifbase); + state->hor_decimation = sh_css_if_get_horizontal_decimation(ifbase); + state->deinterleaving = sh_css_if_get_h_deinterleaving(ifbase); + state->left_padding = sh_css_if_get_leftpadding_width(ifbase); + state->eol_offset = sh_css_if_get_end_of_line_offset(ifbase); + state->vmem_start_address = sh_css_if_get_vmem_start_address(ifbase); + state->vmem_end_address = sh_css_if_get_vmem_end_address(ifbase); + state->vmem_increment = sh_css_if_get_vmem_increment(ifbase); + state->yuv420 = sh_css_if_get_yuv_420_format(ifbase); + state->vsync_active_low = sh_css_if_get_vsynck_active_low(ifbase); + state->hsync_active_low = sh_css_if_get_hsynck_active_low(ifbase); + state->allow_fifo_overflow = sh_css_if_get_allow_fifo_overflow(ifbase); + state->fsm_sync_status = sh_css_if_get_fsm_sync_status(ifbase); + state->fsm_sync_counter = sh_css_if_get_fsm_sync_counter(ifbase); + state->fsm_crop_status = sh_css_if_get_fsm_crop_status(ifbase); + state->fsm_crop_line_counter = + sh_css_if_get_fsm_crop_line_counter(ifbase); + state->fsm_crop_pixel_counter = + sh_css_if_get_fsm_crop_pixel_counter(ifbase); + state->fsm_deinterleaving_index = + sh_css_if_get_fsm_deinterleaving_index(ifbase); + state->fsm_dec_h_counter = sh_css_if_get_fsm_dec_h_counter(ifbase); + state->fsm_dec_v_counter = sh_css_if_get_fsm_dec_v_counter(ifbase); + state->fsm_dec_block_v_counter = + sh_css_if_get_fsm_dec_block_v_counter(ifbase); + state->fsm_padding_status = sh_css_if_get_fsm_padding_status(ifbase); + state->fsm_padding_elem_counter = + sh_css_if_get_fsm_padding_elem_counter(ifbase); + state->fsm_vector_support_error = + sh_css_if_get_fsm_vector_support_error(ifbase); + state->fsm_vector_buffer_full = + sh_css_if_get_fsm_vector_buffer_full(ifbase); + state->vector_support = sh_css_if_get_vector_support(ifbase); + state->sensor_data_lost = sh_css_if_get_sensor_data_lost(ifbase); +} + +unsigned int +sh_css_hrt_if_prim_vec_align(void) +{ + return _HRT_IF_VEC_ALIGN(IF_PRIM); +} + +void +sh_css_hrt_if_prim_a_get_state(struct sh_css_if_state *state) +{ + sh_css_if_get_state(if_prim_a_base_address, state); +} + +void +sh_css_hrt_if_prim_b_get_state(struct sh_css_if_state *state) +{ + sh_css_if_get_state(if_prim_b_base_address, state); +} + +void +sh_css_hrt_if_reset(void) +{ + _sh_css_if_set_register(if_prim_a_base_address, + HIVE_IF_RESET_ADDRESS, 1); + _sh_css_if_set_register(if_prim_b_base_address, + HIVE_IF_RESET_ADDRESS, 1); +} + +void +sh_css_hrt_if_set_block_fifo_no_reqs(bool enable_prim, bool enable_prim_b) +{ + sh_css_if_set_block_fifo_no_reqs(if_prim_a_base_address, enable_prim); + sh_css_if_set_block_fifo_no_reqs(if_prim_b_base_address, enable_prim_b); +} + +/* Streaming monitors */ +static inline unsigned long +sh_css_stream_monitor_get_register(unsigned addr) +{ + unsigned int bus_addr = (unsigned int)(str_monitor_base_address + addr); + return hrt_master_port_load_32(bus_addr); +} + +static inline unsigned int +sh_css_sp_stream_monitor_get_status(void) +{ + return sh_css_stream_monitor_get_register(HIVE_GP_REGS_SP_STREAM_STAT); +} + +static inline unsigned int +sh_css_isp_stream_monitor_get_status(void) +{ + return sh_css_stream_monitor_get_register(HIVE_GP_REGS_ISP_STREAM_STAT); +} + +static inline unsigned int +sh_css_mod_stream_monitor_get_status(void) +{ + return sh_css_stream_monitor_get_register(HIVE_GP_REGS_MOD_STREAM_STAT); +} + +/* use the following function if the stream stat word is already available. */ +static inline unsigned int +sh_css_get_stream_stat_valid(unsigned int stream_stat_word, + unsigned int port_id) +{ + return ((stream_stat_word) >> + (((port_id * 2) + _hive_str_mon_valid_offset))) & 0x1; +} + +static inline unsigned int +sh_css_get_stream_stat_accept(unsigned int stream_stat_word, + unsigned int port_id) +{ + return ((stream_stat_word) >> + (((port_id * 2) + _hive_str_mon_accept_offset))) & 0x1; +} + +/* Following functions are intended for single bit lookup. + * If multiple valid/accept bits are required from the same words + * use the hrt_get_*_stream_stat_word in combination with + * hrt_gets_stream_valid/accept functions. + */ +static inline unsigned int +sh_css_get_sp_stream_stat_valid(unsigned int port_id) +{ + unsigned int status; + status = sh_css_sp_stream_monitor_get_status(); + return sh_css_get_stream_stat_valid(status, port_id); +} + +static inline unsigned int +sh_css_get_sp_stream_stat_accept(unsigned int port_id) +{ + unsigned int status; + status = sh_css_sp_stream_monitor_get_status(); + return sh_css_get_stream_stat_accept(status, port_id); +} + +static inline unsigned int +sh_css_get_isp_stream_stat_valid(unsigned int port_id) +{ + unsigned int status; + status = sh_css_isp_stream_monitor_get_status(); + return sh_css_get_stream_stat_valid(status, port_id); +} + +static inline unsigned int +sh_css_get_isp_stream_stat_accept(unsigned int port_id) +{ + unsigned int status; + status = sh_css_isp_stream_monitor_get_status(); + return sh_css_get_stream_stat_accept(status, port_id); +} + +static inline unsigned int +sh_css_get_mod_stream_stat_valid(unsigned int port_id) +{ + unsigned int status; + status = sh_css_mod_stream_monitor_get_status(); + return sh_css_get_stream_stat_valid(status, port_id); +} + +static inline unsigned int +sh_css_get_mod_stream_stat_accept(unsigned int port_id) +{ + unsigned int status; + status = sh_css_mod_stream_monitor_get_status(); + return sh_css_get_stream_stat_accept(status, port_id); +} + +bool +sh_css_hrt_system_is_idle(void) +{ + bool not_idle = false; + + not_idle |= !sh_css_cell_is_ready(isp_sc_base_address + ISP_SC_REG, + ISP_IDLE_BIT); + /* ISP to SP */ + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_SND_SP); + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_RCV_ISP); + /* SP to ISP */ + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_SND_ISP); + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_RCV_SP); + /* IF_PRIM_A to ISP */ + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_SND_PIF_A); + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_RCV_PIF_A); + /* ISP to IF_PRIM_A */ + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_SND_PIF_A); + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_RCV_PIF_A); + /* IF_PRIM_B to ISP */ + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_RCV_PIF_B); + /* ISP to IF_PRIM_B */ + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_SND_PIF_B); + /* DMA to SP */ + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_SND_DMA); + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_RCV_DMA); + /* SP to DMA */ + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_SND_DMA); + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_RCV_DMA); + /* DMA to ISP */ + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_RCV_DMA); + /* ISP to DMA */ + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_SND_DMA); + /* GDC to SP/ISP */ + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_SND_GDC); + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_RCV_GDC); + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_RCV_GDC); + /* SP/ISP to GDC */ + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_SND_GDC); + not_idle |= + sh_css_get_isp_stream_stat_valid(ISP_STR_MON_PORT_SND_GDC); + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_RCV_GDC); + /* Stream2Mem to SP */ + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_SND_MC); + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_RCV_MC); + /* SP to Stream2Mem */ + not_idle |= + sh_css_get_sp_stream_stat_valid(SP_STR_MON_PORT_SND_MC); + not_idle |= + sh_css_get_mod_stream_stat_valid(MOD_STR_MON_PORT_RCV_MC); + return !not_idle; +} + +void +sh_css_hrt_fifo_channel_get_state(enum sh_css_fifo_channel channel, + struct sh_css_fifo_channel_state *state) +{ + switch (channel) { + case sh_css_hrt_fifo_isp_to_sp: + state->src_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_SND_SP); + state->fifo_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_SND_SP); + state->fifo_valid = sh_css_get_sp_stream_stat_valid( + SP_STR_MON_PORT_RCV_ISP); + state->sink_accept = sh_css_get_sp_stream_stat_accept( + SP_STR_MON_PORT_RCV_ISP); + break; + case sh_css_hrt_fifo_sp_to_isp: + state->src_valid = sh_css_get_sp_stream_stat_valid( + SP_STR_MON_PORT_SND_ISP); + state->fifo_accept = sh_css_get_sp_stream_stat_accept( + SP_STR_MON_PORT_SND_ISP); + state->fifo_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_RCV_SP); + state->sink_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_RCV_SP); + break; + case sh_css_hrt_fifo_isp_to_if_prim_a: + state->src_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_SND_PIF_A); + state->fifo_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_SND_PIF_A); + state->fifo_valid = sh_css_get_mod_stream_stat_valid( + MOD_STR_MON_PORT_RCV_PIF_A); + state->sink_accept = sh_css_get_mod_stream_stat_accept( + MOD_STR_MON_PORT_RCV_PIF_A); + break; + case sh_css_hrt_fifo_if_prim_a_to_isp: + state->src_valid = sh_css_get_mod_stream_stat_valid( + MOD_STR_MON_PORT_SND_PIF_A); + state->fifo_accept = sh_css_get_mod_stream_stat_accept( + MOD_STR_MON_PORT_SND_PIF_A); + state->fifo_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_RCV_PIF_A); + state->sink_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_RCV_PIF_A); + break; + case sh_css_hrt_fifo_isp_to_if_prim_b: + state->src_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_SND_PIF_B); + state->fifo_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_SND_PIF_B); + state->fifo_valid = false; /* no monitor connected */ + state->sink_accept = false; /* no monitor connected */ + break; + case sh_css_hrt_fifo_if_prim_b_to_isp: + state->src_valid = false; /* no monitor connected */ + state->fifo_accept = false; /* no monitor connected */ + state->fifo_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_RCV_PIF_B); + state->sink_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_RCV_PIF_B); + break; + case sh_css_hrt_fifo_isp_to_dma: + state->src_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_SND_DMA); + state->fifo_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_SND_DMA); + state->fifo_valid = sh_css_get_mod_stream_stat_valid( + MOD_STR_MON_PORT_RCV_DMA); + state->sink_accept = sh_css_get_mod_stream_stat_accept( + MOD_STR_MON_PORT_RCV_DMA); + break; + case sh_css_hrt_fifo_dma_to_isp: + state->src_valid = sh_css_get_mod_stream_stat_valid( + MOD_STR_MON_PORT_SND_DMA); + state->fifo_accept = sh_css_get_mod_stream_stat_accept( + MOD_STR_MON_PORT_SND_DMA); + state->fifo_valid = sh_css_get_isp_stream_stat_valid( + ISP_STR_MON_PORT_RCV_DMA); + state->sink_accept = sh_css_get_isp_stream_stat_accept( + ISP_STR_MON_PORT_RCV_DMA); + break; + case sh_css_hrt_fifo_sp_to_dma: + state->src_valid = sh_css_get_sp_stream_stat_valid( + SP_STR_MON_PORT_SND_DMA); + state->fifo_accept = sh_css_get_sp_stream_stat_accept( + SP_STR_MON_PORT_SND_DMA); + state->fifo_valid = sh_css_get_mod_stream_stat_valid( + MOD_STR_MON_PORT_RCV_DMA); + state->sink_accept = sh_css_get_mod_stream_stat_accept( + MOD_STR_MON_PORT_RCV_DMA); + break; + case sh_css_hrt_fifo_dma_to_sp: + state->src_valid = sh_css_get_mod_stream_stat_valid( + MOD_STR_MON_PORT_SND_DMA); + state->fifo_accept = sh_css_get_mod_stream_stat_accept( + MOD_STR_MON_PORT_SND_DMA); + state->fifo_valid = sh_css_get_sp_stream_stat_valid( + SP_STR_MON_PORT_RCV_DMA); + state->sink_accept = sh_css_get_sp_stream_stat_accept( + SP_STR_MON_PORT_RCV_DMA); + break; + } +} + +static inline unsigned long +_sh_css_irq_get_reg(unsigned addr) +{ + unsigned int bus_addr = (unsigned int)(irq_ctrl_base_address + addr); + return hrt_master_port_load_32(bus_addr); +} + +static inline void +_sh_css_irq_set_reg(unsigned addr, unsigned long value) +{ + hrt_master_port_store_32(irq_ctrl_base_address + addr, value); + /* workaround: without this read, the write sometimes does not + get propagated into the register. This being investigated by + Jozef. */ +#ifndef HRT_CSIM + /* todo: make this register readable in hss model */ + (void)hrt_master_port_load_32(irq_ctrl_base_address + addr); +#else + /* Lex: write needs to be processed by IRQ controller. + Therefore, we need a context switch to let it do this. + The asic system has a bus with delay, so that will do this + context switch. The fpga system, however, does not have a bus delay. + Jozef to find a clean sync mechanism. + */ + hrt_sleep(); +#endif +} + +/* set register */ +static inline void +sh_css_irq_set_edge_reg(unsigned long val) +{ + _sh_css_irq_set_reg(_HRT_IRQ_CONTROLLER_EDGE_REG_IDX, val); +} + +static inline void +sh_css_irq_set_mask_reg(unsigned long val) +{ + _sh_css_irq_set_reg(_HRT_IRQ_CONTROLLER_MASK_REG_IDX, val); +} + +static inline void +sh_css_irq_clear_status_reg(unsigned long val) +{ + _sh_css_irq_set_reg(_HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, val); +} + +static inline void +sh_css_irq_set_enable_reg(unsigned long val) +{ + _sh_css_irq_set_reg(_HRT_IRQ_CONTROLLER_ENABLE_REG_IDX, val); +} + +static inline void +sh_css_irq_set_edge_not_pulse_reg(unsigned long val) +{ + _sh_css_irq_set_reg(_HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX, val); +} + +static inline unsigned +sh_css_irq_get_edge_reg(void) +{ + return _sh_css_irq_get_reg(_HRT_IRQ_CONTROLLER_EDGE_REG_IDX); +} + +static inline unsigned +sh_css_irq_get_mask_reg(void) +{ + return _sh_css_irq_get_reg(_HRT_IRQ_CONTROLLER_MASK_REG_IDX); +} + +static inline unsigned +sh_css_irq_get_status_reg(void) +{ + return _sh_css_irq_get_reg(_HRT_IRQ_CONTROLLER_STATUS_REG_IDX); +} + +static inline unsigned +sh_css_irq_get_enable_reg(void) +{ + return _sh_css_irq_get_reg(_HRT_IRQ_CONTROLLER_ENABLE_REG_IDX); +} + +static inline unsigned +sh_css_irq_get_edge_not_pulse_reg(void) +{ + return _sh_css_irq_get_reg(_HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX); +} + +void +sh_css_hrt_irq_clear_all(void) +{ + sh_css_irq_clear_status_reg(0xFFFFFFFF); +} + +void +sh_css_hrt_irq_enable(enum hrt_isp_css_irq irq_id, + bool rising_edge_in, + bool edge_not_pulse_out) +{ + unsigned int mask = sh_css_irq_get_mask_reg(); + unsigned int enable = sh_css_irq_get_enable_reg(); + unsigned int edge_in = sh_css_irq_get_edge_reg(); + unsigned int edge_out = sh_css_irq_get_edge_not_pulse_reg(); + unsigned int me = 1u << irq_id; + + mask |= me; + enable |= me; + if (rising_edge_in) + edge_in |= me; + if (edge_not_pulse_out) + edge_out |= me; + + /* to avoid mishaps configuration must follow the following order */ + + /* mask this interrupt */ + sh_css_irq_set_mask_reg(mask & ~me); + /* rising edge at input */ + sh_css_irq_set_edge_reg(edge_in); + /* enable interrupt to output */ + sh_css_irq_set_enable_reg(enable); + /* output is given as edge, not pulse */ + sh_css_irq_set_edge_not_pulse_reg(edge_out); + /* clear current irq only */ + sh_css_irq_clear_status_reg(me); + /* unmask interrupt from input */ + sh_css_irq_set_mask_reg(mask); +} + +void +sh_css_hrt_irq_disable(enum hrt_isp_css_irq irq_id) +{ + unsigned int mask = sh_css_irq_get_mask_reg(); + unsigned int enable = sh_css_irq_get_enable_reg(); + unsigned int me = 1u << irq_id; + + mask &= ~me; + enable &= ~me; + + /* enable interrupt to output */ + sh_css_irq_set_enable_reg(enable); + /* unmask interrupt from input */ + sh_css_irq_set_mask_reg(mask); + /* clear current irq only */ + sh_css_irq_clear_status_reg(me); +} + +enum hrt_isp_css_irq_status +sh_css_hrt_irq_get_id(enum hrt_isp_css_irq *irq_id) +{ + unsigned int irq_status = sh_css_irq_get_status_reg(); + unsigned int irq_mask = sh_css_irq_get_mask_reg(); + unsigned int i; + int irq_idx_found = -1; + enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_success; + + /* find the first irq bit */ + for (i = 0; + (i < hrt_isp_css_irq_num_irqs) && (irq_idx_found == -1); + i++) { + if (irq_status & (1u << i)) + irq_idx_found = i; + } + if (irq_idx_found == -1) + return hrt_isp_css_irq_status_error; + + /* now check whether there are more bits set */ + for (i = irq_idx_found + 1; (i < hrt_isp_css_irq_num_irqs) + && (status == hrt_isp_css_irq_status_success); i++) { + if (irq_status & (1u << i)) + status = hrt_isp_css_irq_status_more_irqs; + } + + /* now we clear the irq status bit, to avoid generating a + * new IRQ, we must set the mask temporarily to zero. + */ + sh_css_irq_set_mask_reg(0); + sh_css_irq_clear_status_reg(1u << irq_idx_found); + sh_css_irq_set_mask_reg(irq_mask); + if (irq_id) + *irq_id = (enum hrt_isp_css_irq) irq_idx_found; + return status; +} + +/* Streaming to MIPI */ +static inline unsigned +_sh_css_wrap_marker(unsigned marker) +{ + return marker | + (curr_ch_id << HIVE_STR_TO_MIPI_CH_ID_LSB) | + (curr_fmt_type << _HIVE_STR_TO_MIPI_FMT_TYPE_LSB); +} + +static inline void +_sh_css_fifo_snd(unsigned token) +{ + hrt_master_port_store_32(gp_fifo_base_address, token); +} + +static inline void +sh_css_streaming_to_mipi_send_data_a(unsigned int data) +{ + unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_A_BIT) | + (data << HIVE_STR_TO_MIPI_DATA_A_LSB); + _sh_css_fifo_snd(token); +} + +static inline void +sh_css_streaming_to_mipi_send_data_b(unsigned int data) +{ + unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) | + (data << _HIVE_STR_TO_MIPI_DATA_B_LSB); + _sh_css_fifo_snd(token); +} + +static inline void +sh_css_streaming_to_mipi_send_data(unsigned int a, unsigned int b) +{ + unsigned int token = ((1 << HIVE_STR_TO_MIPI_VALID_A_BIT) | + (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) | + (a << HIVE_STR_TO_MIPI_DATA_A_LSB) | + (b << _HIVE_STR_TO_MIPI_DATA_B_LSB)); + _sh_css_fifo_snd(token); +} + +static inline void +sh_css_streaming_to_mipi_send_sol(void) +{ + _sh_css_fifo_snd(_sh_css_wrap_marker(1 << HIVE_STR_TO_MIPI_SOL_BIT)); +} + +static inline void +sh_css_streaming_to_mipi_send_eol(void) +{ + _sh_css_fifo_snd(_sh_css_wrap_marker(1 << HIVE_STR_TO_MIPI_EOL_BIT)); +} + +static inline void +sh_css_streaming_to_mipi_send_sof(void) +{ + _sh_css_fifo_snd(_sh_css_wrap_marker(1 << HIVE_STR_TO_MIPI_SOF_BIT)); +} + +static inline void +sh_css_streaming_to_mipi_send_eof(void) +{ + _sh_css_fifo_snd(_sh_css_wrap_marker(1 << HIVE_STR_TO_MIPI_EOF_BIT)); +} + +static inline void +sh_css_streaming_to_mipi_send_ch_id(unsigned int ch_id) +{ + curr_ch_id = ch_id & _HIVE_ISP_CH_ID_MASK; + /* we send an zero marker, this will wrap the ch_id and + * fmt_type automatically. + */ + _sh_css_fifo_snd(_sh_css_wrap_marker(0)); +} + +static inline void +sh_css_streaming_to_mipi_send_fmt_type(unsigned int fmt_type) +{ + curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK; + /* we send an zero marker, this will wrap the ch_id and + * fmt_type automatically. + */ + _sh_css_fifo_snd(_sh_css_wrap_marker(0)); +} + +static inline void +sh_css_streaming_to_mipi_send_ch_id_and_fmt_type(unsigned int ch_id, + unsigned int fmt_type) +{ + curr_ch_id = ch_id & _HIVE_ISP_CH_ID_MASK; + curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK; + /* we send an zero marker, this will wrap the ch_id and + * fmt_type automatically. + */ + _sh_css_fifo_snd(_sh_css_wrap_marker(0)); +} + +static inline void +sh_css_streaming_to_mipi_send_empty_token(void) +{ + _sh_css_fifo_snd(_sh_css_wrap_marker(0)); +} + +static inline void +sh_css_streaming_to_mipi_start_frame(unsigned int ch_id, + unsigned int fmt_type) +{ + sh_css_streaming_to_mipi_send_ch_id_and_fmt_type(ch_id, fmt_type); + sh_css_streaming_to_mipi_send_sof(); +} + +static void +sh_css_streaming_to_mipi_end_frame(unsigned int marker_cycles) +{ + unsigned int i; + for (i = 0; i < marker_cycles; i++) + sh_css_streaming_to_mipi_send_empty_token(); + sh_css_streaming_to_mipi_send_eof(); +} + +static void +sh_css_streaming_to_mipi_send_line(unsigned short *data, + unsigned int width, + unsigned int hblank_cycles, + unsigned int marker_cycles, + unsigned int two_ppc, + enum sh_css_mipi_data_type type) +{ + unsigned int i, is_rgb = 0, is_legacy = 0; + + if (type == sh_css_mipi_data_type_rgb) + is_rgb = 1; + + if (type == sh_css_mipi_data_type_yuv420_legacy) + is_legacy = 1; + + for (i = 0; i < hblank_cycles; i++) + sh_css_streaming_to_mipi_send_empty_token(); + sh_css_streaming_to_mipi_send_sol(); + for (i = 0; i < marker_cycles; i++) + sh_css_streaming_to_mipi_send_empty_token(); + for (i = 0; i < width; i++, data++) { + /* for RGB in two_ppc, we only actually send 2 pixels per + * clock in the even pixels (0, 2 etc). In the other cycles, + * we only send 1 pixel, to data[0]. + */ + unsigned int send_two_pixels = two_ppc; + if ((is_rgb || is_legacy) && (i % 3 == 2)) + send_two_pixels = 0; + if (send_two_pixels) { + if (i + 1 == width) { + /* for jpg (binary) copy, this can occur + * if the file contains an odd number of bytes. + */ + sh_css_streaming_to_mipi_send_data(data[0], + 0); + } else { + sh_css_streaming_to_mipi_send_data(data[0], + data + [1]); + } + data++; + i++; + } else if (two_ppc && is_legacy) { + sh_css_streaming_to_mipi_send_data_b(data[0]); + } else { + sh_css_streaming_to_mipi_send_data_a(data[0]); + } +#if 0 /* Disabled, this is now modeled in the config bus */ + hrt_sleep(); +#endif + } + for (i = 0; i < hblank_cycles; i++) + sh_css_streaming_to_mipi_send_empty_token(); + sh_css_streaming_to_mipi_send_eol(); +} + +/* Send a frame of data into the input network via the GP FIFO. + * Parameters: + * - data: array of 16 bit values that contains all data for the frame. + * - width: width of a line in number of subpixels, for yuv420 it is the + * number of Y components per line. + * - height: height of the frame in number of lines. + * - ch_id: channel ID. + * - fmt_type: format type. + * - hblank_cycles: length of horizontal blanking in cycles. + * - marker_cycles: number of empty cycles after start-of-line and before + * end-of-frame. + * - two_ppc: boolean, describes whether to send one or two pixels per clock + * cycle. In this mode, we sent pixels N and N+1 in the same cycle, + * to IF_PRIM_A and IF_PRIM_B respectively. The caller must make + * sure the input data has been formatted correctly for this. + * For example, for RGB formats this means that unused values + * must be inserted. + * - yuv420: boolean, describes whether (non-legacy) yuv420 data is used. In + * this mode, the odd lines (1,3,5 etc) are half as long as the + * even lines (2,4,6 etc). + * Note that the first line is odd (1) and the second line is even + * (2). + * + * This function does not do any reordering of pixels, the caller must make + * sure the data is in the righ format. Please refer to the CSS receiver + * documentation for details on the data formats. + */ +static void +sh_css_streaming_to_mipi_send_frame(unsigned short *data, + unsigned int width, + unsigned int height, + unsigned int ch_id, + unsigned int fmt_type, + unsigned int hblank_cycles, + unsigned int marker_cycles, + unsigned int two_ppc, + enum sh_css_mipi_data_type type) +{ + unsigned int i; + + sh_css_streaming_to_mipi_start_frame(ch_id, fmt_type); + for (i = 0; i < height; i++) { + if ((type == sh_css_mipi_data_type_yuv420) && + (i & 1) == 1) { + sh_css_streaming_to_mipi_send_line(data, 2 * width, + hblank_cycles, + marker_cycles, + two_ppc, type); + data += 2 * width; + } else { + sh_css_streaming_to_mipi_send_line(data, width, + hblank_cycles, + marker_cycles, + two_ppc, type); + data += width; + } + } + sh_css_streaming_to_mipi_end_frame(marker_cycles); +} + +void +sh_css_hrt_send_input_frame(unsigned short *data, + unsigned int width, + unsigned int height, + unsigned int ch_id, + enum sh_css_input_format input_format, + bool two_ppc) +{ + unsigned int fmt_type, hblank_cycles, marker_cycles; + enum sh_css_mipi_data_type str_to_mipi_type; + + hblank_cycles = 187; + marker_cycles = 6; + sh_css_input_format_type(input_format, + SH_CSS_MIPI_COMPRESSION_NONE, + &fmt_type); + str_to_mipi_type = sh_css_mipi_data_type_regular; + if (input_format == SH_CSS_INPUT_FORMAT_YUV420_8_LEGACY) { + str_to_mipi_type = + sh_css_mipi_data_type_yuv420_legacy; + } else if (input_format == SH_CSS_INPUT_FORMAT_YUV420_8 || + input_format == SH_CSS_INPUT_FORMAT_YUV420_10) { + str_to_mipi_type = + sh_css_mipi_data_type_yuv420; + } else if (input_format >= SH_CSS_INPUT_FORMAT_RGB_444 && + input_format <= SH_CSS_INPUT_FORMAT_RGB_888) { + str_to_mipi_type = + sh_css_mipi_data_type_rgb; + } + sh_css_streaming_to_mipi_send_frame(data, width, height, + ch_id, fmt_type, hblank_cycles, marker_cycles, + two_ppc, str_to_mipi_type); +} diff --git a/drivers/media/video/atomisp/css/sh_css_hrt.h b/drivers/media/video/atomisp/css/sh_css_hrt.h new file mode 100644 index 0000000..93b0bb2 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_hrt.h @@ -0,0 +1,394 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +/* This module provides access to the CSS hardware. This includes access to + local memories, registers and starting processors. */ + +#ifndef _SH_CSS_HRT_H_ +#define _SH_CSS_HRT_H_ + +#include + +/* here we include some system header files that provide constants and such + about the system and the ISP processor. */ +#include +#include +#include +#include +#include + +/* The following files provide access to types and memory related functions + that contain system specific behavior. */ +#include +#include + +#include "sh_css_types.h" +#include "sh_css_rx.h" +#include "sh_css_sp_start.h" + +enum sh_css_fifo_channel { + /* SP <-> ISP */ + sh_css_hrt_fifo_isp_to_sp, + sh_css_hrt_fifo_sp_to_isp, + /* ISP <-> PRIM IF A */ + sh_css_hrt_fifo_isp_to_if_prim_a, + sh_css_hrt_fifo_if_prim_a_to_isp, + /* ISP <-> PRIM IF B (only ISP side) */ + sh_css_hrt_fifo_isp_to_if_prim_b, + sh_css_hrt_fifo_if_prim_b_to_isp, + /* ISP <-> DMA */ + sh_css_hrt_fifo_isp_to_dma, + sh_css_hrt_fifo_dma_to_isp, + /* SP <-> DMA */ + sh_css_hrt_fifo_sp_to_dma, + sh_css_hrt_fifo_dma_to_sp +}; + +enum sh_css_dma_ctrl_state { + sh_css_dma_ctrl_state_idle, + sh_css_dma_ctrl_state_req_rcv, + sh_css_dma_ctrl_state_rcv, + sh_css_dma_ctrl_state_rcv_req, + sh_css_dma_ctrl_state_init +}; + +enum sh_css_dma_command { + sh_css_dma_command_read, + sh_css_dma_command_write, + sh_css_dma_command_set_channel, + sh_css_dma_command_set_param, + sh_css_dma_command_read_spec, + sh_css_dma_command_write_spec, + sh_css_dma_command_init, + sh_css_dma_command_init_spec, + sh_css_dma_command_reset +}; + +enum sh_css_dma_rw_state { + sh_css_dma_rw_state_idle, + sh_css_dma_rw_state_req, + sh_css_dma_rw_state_next_line, + sh_css_dma_rw_state_unlock_channel +}; + +enum sh_css_dma_fifo_state { + sh_css_dma_fifo_state_will_be_full, + sh_css_dma_fifo_state_full, + sh_css_dma_fifo_state_empty +}; + +struct sh_css_dma_port_state { + bool req_cs; + bool req_we_n; + bool req_run; + bool req_ack; + bool send_cs; + bool send_we_n; + bool send_run; + bool send_ack; + enum sh_css_dma_fifo_state fifo_state; + int fifo_counter; +}; + +struct sh_css_dma_channel_state { + int connection; + bool sign_extend; + bool reverse_elem_order; + int height; + int stride_a; + int elems_a; + int cropping_a; + int width_a; + int stride_b; + int elems_b; + int cropping_b; + int width_b; +}; + +struct sh_css_dma_state { + bool fsm_command_idle; + bool fsm_command_run; + bool fsm_command_stalling; + bool fsm_command_error; + enum sh_css_dma_command last_command; + int last_command_channel; + int last_command_param; + enum sh_css_dma_command current_command; + int current_addr_a; + int current_addr_b; + bool fsm_ctrl_idle; + bool fsm_ctrl_run; + bool fsm_ctrl_stalling; + bool fsm_ctrl_error; + enum sh_css_dma_ctrl_state fsm_ctrl_state; + int fsm_ctrl_source_dev; + int fsm_ctrl_source_addr; + int fsm_ctrl_source_stride; + int fsm_ctrl_source_width; + int fsm_ctrl_source_height; + int fsm_ctrl_pack_source_dev; + int fsm_ctrl_pack_dest_dev; + int fsm_ctrl_dest_addr; + int fsm_ctrl_dest_stride; + int fsm_ctrl_pack_source_width; + int fsm_ctrl_pack_dest_height; + int fsm_ctrl_pack_dest_width; + int fsm_ctrl_pack_source_elems; + int fsm_ctrl_pack_dest_elems; + int fsm_ctrl_pack_extension; + int pack_idle; + int pack_run; + int pack_stalling; + int pack_error; + int pack_cnt_height; + int pack_src_cnt_width; + int pack_dest_cnt_width; + enum sh_css_dma_rw_state read_state; + int read_cnt_height; + int read_cnt_width; + enum sh_css_dma_rw_state write_state; + int write_height; + int write_width; + struct sh_css_dma_port_state port_states[3]; + struct sh_css_dma_channel_state channel_states[8]; +}; + +struct sh_css_if_state { + int reset, + start_line, + start_column, + cropped_height, + cropped_width, + ver_decimation, + hor_decimation, + deinterleaving, + left_padding, + eol_offset, + vmem_start_address, + vmem_end_address, + vmem_increment, + yuv420, + vsync_active_low, + hsync_active_low, + allow_fifo_overflow, + fsm_sync_status, + fsm_sync_counter, + fsm_crop_status, + fsm_crop_line_counter, + fsm_crop_pixel_counter, + fsm_deinterleaving_index, + fsm_dec_h_counter, + fsm_dec_v_counter, + fsm_dec_block_v_counter, + fsm_padding_status, + fsm_padding_elem_counter, + fsm_vector_support_error, + fsm_vector_buffer_full, + vector_support, + sensor_data_lost; +}; + +struct sh_css_cell_state { + int pc; + int status_register; + bool is_broken; + bool is_idle; + bool is_sleeping; + bool is_stalling; +}; + +struct sh_css_sp_stall_state { + bool fifo0; + bool fifo1; + bool fifo2; + bool fifo3; + bool fifo4; + bool fifo5; + bool fifo6; + bool fifo7; + bool dmem; + bool control_master; + bool icache_master; +}; + +struct sh_css_isp_stall_state { + bool fifo0; + bool fifo1; + bool fifo2; + bool fifo3; + bool fifo4; + bool fifo5; + bool stat_ctrl; + bool dmem; + bool vmem; + bool vamem1; + bool vamem2; +}; + +struct sh_css_fifo_channel_state { + bool src_valid; + bool fifo_accept; + bool fifo_valid; + bool sink_accept; +}; + +void +sh_css_sp_ctrl_store(unsigned int reg, unsigned int value); + +void +sh_css_sp_ctrl_set_bits(unsigned int reg, unsigned long bits); + +/* SP access */ +void +sh_css_hrt_sp_start_si(void); + +void +sh_css_hrt_sp_start_init_dmem(void); + +void +sh_css_hrt_sp_start_histogram(void); + +void +sh_css_hrt_sp_start_copy_frame(void); + +void +sh_css_hrt_sp_start_copy_binary_data(void); + +void +sh_css_hrt_sp_start_copy_raw_data(void); + +void +sh_css_hrt_sp_start_isp(void); + +enum sh_css_err +sh_css_hrt_sp_wait(void); + +bool +sh_css_hrt_sp_is_idle(void); + +bool +sh_css_hrt_sp_is_stalling(void); + +unsigned int +sh_css_hrt_sp_current_pc(void); + +unsigned int +sh_css_hrt_sp_current_msink(void); + +void +sh_css_hrt_sp_get_state(struct sh_css_cell_state *state, + struct sh_css_sp_stall_state *stall_state); + +/* ISP access */ +bool +sh_css_hrt_isp_is_idle(void); + +bool +sh_css_hrt_isp_is_stalling(void); + +void +sh_css_hrt_isp_get_state(struct sh_css_cell_state *state, + struct sh_css_isp_stall_state *stall_state); + +void +sh_css_hrt_fifo_channel_get_state(enum sh_css_fifo_channel, + struct sh_css_fifo_channel_state *state); + +unsigned int +sh_css_hrt_isp_current_pc(void); + +void +sh_css_isp_ctrl_store(unsigned int reg, unsigned int value); + +unsigned int +sh_css_hrt_isp_current_msink(void); + +unsigned int +sh_css_hrt_isp_current_sc(void); + +/* Input formatters */ +unsigned int +sh_css_hrt_if_prim_vec_align(void); + +void +sh_css_hrt_if_prim_a_get_state(struct sh_css_if_state *state); + +void +sh_css_hrt_if_prim_b_get_state(struct sh_css_if_state *state); + +void +sh_css_hrt_if_reset(void); + +void +sh_css_hrt_if_set_block_fifo_no_reqs(bool enable_prim, bool enable_prim_b); + +bool +sh_css_hrt_system_is_idle(void); + +void +sh_css_hrt_dma_get_state(struct sh_css_dma_state *state); + +/* Interrupts */ +void +sh_css_hrt_irq_enable(enum hrt_isp_css_irq irq, + bool rising_edge_in, + bool edge_not_pulse_out); + +void +sh_css_hrt_irq_enable_sp(bool enable); + +void +sh_css_hrt_irq_disable(enum hrt_isp_css_irq irq); + +void +sh_css_hrt_irq_clear_all(void); + +enum hrt_isp_css_irq_status +sh_css_hrt_irq_get_id(enum hrt_isp_css_irq *irq); + +void +sh_css_hrt_irq_clear_sp(void); + +/* GDC */ +void +sh_css_hrt_gdc_set_lut(const int data[4][HRT_GDC_N]); + +/* MMU */ +void +sh_css_hrt_mmu_set_page_table_base_address(void *base_address); + +void * +sh_css_hrt_mmu_get_page_table_base_address(void); + +void +sh_css_hrt_mmu_invalidate_cache(void); + +void +sh_css_hrt_send_input_frame(unsigned short *data, + unsigned int width, + unsigned int height, + unsigned int ch_id, + enum sh_css_input_format input_format, + bool two_ppc); + +#endif /* _SH_CSS_HRT_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_hw.h b/drivers/media/video/atomisp/css/sh_css_hw.h new file mode 100644 index 0000000..5b11667 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_hw.h @@ -0,0 +1,139 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_HW_H_ +#define _SH_CSS_HW_H_ + +#ifdef HRT_ISP_CSS_CUSTOM_HOST +#ifndef HRT_USE_VIR_ADDRS +#define HRT_USE_VIR_ADDRS +#endif +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MMU_BASE ((void *)0x10250000) +#define GDC_LUT_BASE ((void *)0x10180000) +#define DMA_BASE ((void *)0x10240000) +#define IF_PRIM_A_BASE ((void *)0x10210000) +#define IF_PRIM_B_BASE ((void *)0x10270000) +#define SP_DMEM_BASE ((void *)0x10100000) +#define SP_SC_BASE ((void *)0x10104000) +#define ISP_SC_BASE ((void *)0x10020000) +#define STR_MON_BASE ((void *)0x10200000) +#define IRQ_CTRL_BASE ((void *)0x10200500) +#define GP_FIFO_BASE ((void *)0x10200304) +#define CSS_RX_BASE ((void *)0x10260000) + +/* SP Registers */ +#define SP_PC_REG 0x9 +#define SP_SC_REG 0x0 +#define SP_START_ADDR_REG 0x1 +#define SP_ICACHE_ADDR_REG 0x5 +#define SP_IRQ_READY_REG 0x0 +#define SP_IRQ_CLEAR_REG 0x0 +#define SP_ICACHE_INV_REG 0x0 +#define SP_CTRL_SINK_REG 0xA + +/* SP Register bits */ +#define SP_START_BIT 0x1 +#define SP_RUN_BIT 0x3 +#define SP_BROKEN_BIT 0x4 +#define SP_IDLE_BIT 0x5 +#define SP_STALLING_BIT 0x7 +#define SP_IRQ_CLEAR_BIT 0x8 +#define SP_IRQ_READY_BIT 0xA +#define SP_SLEEPING_BIT 0xB +#define SP_ICACHE_INV_BIT 0xC + +/* ISP Registers */ +#define ISP_PC_REG 0x5 +#define ISP_SC_REG 0x0 +#define ISP_BROKEN_BIT 0x4 +#define ISP_IDLE_BIT 0x5 +#define ISP_STALLING_BIT 0x7 +#define ISP_SLEEPING_BIT 0xB + +/* ISP Register bits */ +#define ISP_CTRL_SINK_BIT 0x0 +#define ISP_DMEM_SINK_BIT 0x1 +#define ISP_VMEM_SINK_BIT 0x2 +#define ISP_FIFO0_SINK_BIT 0x3 +#define ISP_FIFO1_SINK_BIT 0x4 +#define ISP_FIFO2_SINK_BIT 0x5 +#define ISP_FIFO3_SINK_BIT 0x6 +#define ISP_FIFO4_SINK_BIT 0x7 +#define ISP_FIFO5_SINK_BIT 0x8 +#define ISP_VAMEM1_SINK_BIT 0x9 +#define ISP_VAMEM2_SINK_BIT 0xA + +#define ISP_CTRL_SINK_REG 0x6 +#define ISP_DMEM_SINK_REG 0x6 +#define ISP_VMEM_SINK_REG 0x6 +#define ISP_FIFO0_SINK_REG 0x6 +#define ISP_FIFO1_SINK_REG 0x6 +#define ISP_FIFO2_SINK_REG 0x6 +#define ISP_FIFO3_SINK_REG 0x6 +#define ISP_FIFO4_SINK_REG 0x6 +#define ISP_FIFO5_SINK_REG 0x6 +#define ISP_VAMEM1_SINK_REG 0x6 +#define ISP_VAMEM2_SINK_REG 0x6 + +#define SP_FIFO0_SINK_BIT 0x0 +#define SP_FIFO1_SINK_BIT 0x1 +#define SP_FIFO2_SINK_BIT 0x2 +#define SP_FIFO3_SINK_BIT 0x3 +#define SP_FIFO4_SINK_BIT 0x4 +#define SP_FIFO5_SINK_BIT 0x5 +#define SP_FIFO6_SINK_BIT 0x6 +#define SP_FIFO7_SINK_BIT 0x7 +#define SP_DMEM_SINK_BIT 0x8 +#define SP_CTRL_MT_SINK_BIT 0x9 +#define SP_ICACHE_MT_SINK_BIT 0xA + +#define SP_FIFO0_SINK_REG 0xA +#define SP_FIFO1_SINK_REG 0xA +#define SP_FIFO2_SINK_REG 0xA +#define SP_FIFO3_SINK_REG 0xA +#define SP_FIFO4_SINK_REG 0xA +#define SP_FIFO5_SINK_REG 0xA +#define SP_FIFO6_SINK_REG 0xA +#define SP_FIFO7_SINK_REG 0xA +#define SP_DMEM_SINK_REG 0xA +#define SP_CTRL_MT_SINK_REG 0xA +#define SP_ICACHE_MT_SINK_REG 0xA + +#endif /* _SH_CSS_HW_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_internal.h b/drivers/media/video/atomisp/css/sh_css_internal.h new file mode 100644 index 0000000..086591e --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_internal.h @@ -0,0 +1,290 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_INTERNAL_H_ +#define _SH_CSS_INTERNAL_H_ + +#include "sh_css_types.h" +#include "sh_css_binary.h" +#include "sh_css_sp.h" + +#define sh_css_print(fmt, s...) \ + do { \ + if (sh_css_printf) { \ + sh_css_printf(fmt, ## s); \ + } \ + } while (0) + +/* Data structures shared with ISP */ +struct sh_css_isp_params { + /* FPNR (Fixed Pattern Noise Reduction) */ + int fpn_shift; + int fpn_enabled; + + /* OB (Optical Black) */ + int ob_blacklevel_gr; + int ob_blacklevel_r; + int ob_blacklevel_b; + int ob_blacklevel_gb; + int obarea_start_bq; + int obarea_length_bq; + int obarea_length_bq_inverse; + + /* SC (Shading Corrction) */ + int sc_gain_shift; + + /* WB (White Balance) */ + int wb_gain_shift; + int wb_gain_gr; + int wb_gain_r; + int wb_gain_b; + int wb_gain_gb; + + /* DP (Defect Pixel Correction) */ + int dp_threshold_single_when_2adjacent_on; + int dp_threshold_2adjacent_when_2adjacent_on; + int dp_threshold_single_when_2adjacent_off; + int dp_threshold_2adjacent_when_2adjacent_off; + int dp_gain; + + /* BNR (Bayer Noise Reduction) */ + int bnr_gain_all; + int bnr_gain_dir; + int bnr_threshold_low; + int bnr_threshold_width_log2; + int bnr_threshold_width; + int bnr_clip; + + /* S3A (3A Support): coefficients to calculate Y */ + int ae_y_coef_r; + int ae_y_coef_g; + int ae_y_coef_b; + + /* S3A (3A Support): af fir coefficients */ + int af_fir1[7]; + int af_fir2[7]; + + /* DE (Demosaic) */ + int de_pixelnoise; + int de_c1_coring_threshold; + int de_c2_coring_threshold; + + /* YNR (Y Noise Reduction), YEE (Y Edge Enhancement) */ + int ynr_threshold; + int ynr_gain_all; + int ynr_gain_dir; + int ynryee_dirthreshold_s; + int ynryee_dirthreshold_g; + int ynryee_dirthreshold_width_log2; + int ynryee_dirthreshold_width; + int yee_detailgain; + int yee_coring_s; + int yee_coring_g; + int yee_scale_plus_s; + int yee_scale_plus_g; + int yee_scale_minus_s; + int yee_scale_minus_g; + int yee_clip_plus_s; + int yee_clip_plus_g; + int yee_clip_minus_s; + int yee_clip_minus_g; + int ynryee_Yclip; + + /* CSC (Color Space Conversion) */ + /* YC1C2->YCbCr */ + int csc_coef_shift; + int yc1c2_to_ycbcr_00; + int yc1c2_to_ycbcr_01; + int yc1c2_to_ycbcr_02; + int yc1c2_to_ycbcr_10; + int yc1c2_to_ycbcr_11; + int yc1c2_to_ycbcr_12; + int yc1c2_to_ycbcr_20; + int yc1c2_to_ycbcr_21; + int yc1c2_to_ycbcr_22; + + /* GC (Gamma Correction) */ + int gamma_gain_k1; + int gamma_gain_k2; + + /* TNR (Temporal Noise Reduction) */ + int tnr_coef; + int tnr_threshold_Y; + int tnr_threshold_C; + + /* ANR (Advance Noise Reduction) */ + int anr_threshold; +}; + +/* xmem address map allocation */ +struct sh_css_ddr_address_map { + void *isp_param; + void *ctc_tbl; + void *gamma_tbl; + void *macc_tbl; + void *fpn_tbl; + void *sc_tbl; + void *s3a_tbl; + void *s3a_tbl_hi; + void *s3a_tbl_lo; + void *sdis_hor_coef; + void *sdis_ver_coef; + void *sdis_hor_proj; + void *sdis_ver_proj; + void *tetra_r_x; + void *tetra_r_y; + void *tetra_gr_x; + void *tetra_gr_y; + void *tetra_gb_x; + void *tetra_gb_y; + void *tetra_b_x; + void *tetra_b_y; + void *tetra_ratb_x; + void *tetra_ratb_y; + void *tetra_batr_x; + void *tetra_batr_y; +}; + +/* Group all host initialized SP variables into this struct. */ +struct sh_css_sp_group { + int sp_isp_binary_id; + int sp_enable_xnr; + unsigned int sp_uds_curr_dx; + unsigned int sp_uds_curr_dy; + unsigned int sp_uds_xc; + unsigned int sp_uds_yc; + int sp_input_stream_format; + unsigned int isp_dvs_envelope_width; + unsigned int isp_dvs_envelope_height; + unsigned int isp_deci_log_factor; + unsigned int isp_vf_downscale_bits; + unsigned int isp_online; + unsigned int isp_copy_vf; + unsigned int isp_copy_output; + unsigned int isp_2ppc; + unsigned int sp_out_crop_pos_x; + unsigned int sp_out_crop_pos_y; + unsigned int sp_run_copy; + void *xmem_bin_addr; + void *xmem_map_addr; + struct sh_css_frame sp_in_frame; + struct sh_css_frame sp_out_frame; + struct sh_css_frame sp_ref_in_frame; + struct sh_css_frame sp_tnr_in_frame; + struct sh_css_frame sp_out_vf_frame; + struct sh_css_frame sp_extra_frame; + struct sh_css_frame sp_ref_out_frame; + struct sh_css_frame sp_tnr_out_frame; + struct sh_css_frame_info sp_internal_frame_info; +} ; + +extern struct sh_css_sp_group sp_group; +extern struct sh_css_frame sp_in_frame; +extern struct sh_css_frame sp_out_frame; + +extern int (*sh_css_printf) (const char *fmt, ...); + +void * +sh_css_params_ddr_address_map(void); + +enum sh_css_err +sh_css_params_write_to_ddr(const struct sh_css_binary *binary_info); + +void +sh_css_params_set_current_binary(const struct sh_css_binary *binary); + +enum sh_css_err +sh_css_params_init(void); + +void +sh_css_params_uninit(void); + +void +sh_css_params_reconfigure_gdc_lut(void); + +void * +sh_css_malloc(size_t size); + +void +sh_css_free(void *ptr); + +/* Check two frames for equality (format, resolution, bits per element) */ +bool +sh_css_frame_equal_types(const struct sh_css_frame *frame_a, + const struct sh_css_frame *frame_b); + +bool +sh_css_frame_info_equal_resolution(const struct sh_css_frame_info *info_a, + const struct sh_css_frame_info *info_b); + +unsigned int +sh_css_input_format_bits_per_pixel(enum sh_css_input_format format, + bool two_ppc); + +enum sh_css_err +sh_css_vf_downscale_log2(const struct sh_css_frame_info *out_info, + const struct sh_css_frame_info *vf_info, + unsigned int *downscale_log2); + +void +sh_css_capture_enable_bayer_downscaling(bool enable); + +void +sh_css_binary_print(const struct sh_css_binary *binary); + +void +sh_css_print_sp_debug_state(const struct sh_css_sp_debug_state *state); + +void +sh_css_frame_info_set_width(struct sh_css_frame_info *info, + unsigned int width); + +/* Return whether the sp copy process should be started */ +bool +sh_css_continuous_start_sp_copy(void); + +/* The following functions are used for testing purposes only */ +const struct sh_css_fpn_table * +sh_css_get_fpn_table(void); + +const struct sh_css_shading_table * +sh_css_get_shading_table(void); + +const struct sh_css_isp_params * +sh_css_get_isp_params(void); + +const struct sh_css_binary * +sh_css_get_3a_binary(void); + +void +sh_css_get_isp_dis_coefficients(short *horizontal_coefficients, + short *vertical_coefficients); + +void +sh_css_get_isp_dis_projections(int *horizontal_projections, + int *vertical_projections); + +void * +sh_css_store_sp_group_to_ddr(void); + +#endif /* _SH_CSS_INTERNAL_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_metrics.c b/drivers/media/video/atomisp/css/sh_css_metrics.c new file mode 100644 index 0000000..24034ec --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_metrics.c @@ -0,0 +1,179 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include "sh_css_hw.h" +#include "sh_css_hrt.h" +#include "sh_css_internal.h" +#include "sh_css_metrics.h" + +#define ISP_RUN_BIT 0x3 +#define MULTIPLE_PCS 0 +#define SUSPEND 0 +#define NOF_PCS 1 +#define RESUME_MASK 0x8 +#define STOP_MASK 0x0 + +static bool pc_histogram_enabled; +static struct sh_css_pc_histogram *isp_histogram; +static struct sh_css_pc_histogram *sp_histogram; + +struct sh_css_metrics sh_css_metrics; + +void +sh_css_metrics_start_frame(void) +{ + sh_css_metrics.frame_metrics.num_frames++; +} + +static void +clear_histogram(struct sh_css_pc_histogram *histogram) +{ + unsigned i; + for (i = 0; i < histogram->length; i++) { + histogram->run[i] = 0; + histogram->stall[i] = 0; + histogram->msink[i] = 0xFFFF; + } +} + +void +sh_css_metrics_enable_pc_histogram(bool enable) +{ + pc_histogram_enabled = enable; +} + +static void +make_histogram(struct sh_css_pc_histogram *histogram, unsigned length) +{ + if (histogram->length) + return; + if (histogram->run) + return; + histogram->run = sh_css_malloc(length * sizeof(*histogram->run)); + if (!histogram->run) + return; + histogram->stall = sh_css_malloc(length * sizeof(*histogram->stall)); + if (!histogram->stall) + return; + histogram->msink = sh_css_malloc(length * sizeof(*histogram->msink)); + if (!histogram->msink) + return; + + histogram->length = length; + clear_histogram(histogram); +} + +static void +insert_binary_metrics(struct sh_css_binary_metrics **l, + struct sh_css_binary_metrics *metrics) +{ + for (; *l; l = &(*l)->next) + if (*l == metrics) + return; + + *l = metrics; + metrics->next = NULL; +} + +void +sh_css_metrics_start_binary(struct sh_css_binary_metrics *metrics) +{ + if (!pc_histogram_enabled) + return; + + isp_histogram = &metrics->isp_histogram; + sp_histogram = &metrics->sp_histogram; + make_histogram(isp_histogram, ISP_PMEM_DEPTH); + make_histogram(sp_histogram, SP_PMEM_DEPTH); + insert_binary_metrics(&sh_css_metrics.binary_metrics, metrics); +} + +void +sh_css_metrics_sample_pcs(void) +{ + bool stall; + unsigned int pc; + unsigned int msink; + +#if SUSPEND + unsigned int sc = 0; + unsigned int stopped_sc = 0; + unsigned int resume_sc = 0; +#endif + + +#if MULTIPLE_PCS + int i; + unsigned int pc_tab[NOF_PCS] ; + + for (i = 0; i < NOF_PCS; i++) + pc_tab[i] = 0; +#endif + + if (!pc_histogram_enabled) + return; + + if (isp_histogram) { +#if SUSPEND + /* STOP the ISP */ + sh_css_isp_ctrl_store(ISP_SC_REG, STOP_MASK); +#endif + msink = sh_css_hrt_isp_current_msink(); +#if MULTIPLE_PCS + for (i = 0; i < NOF_PCS; i++) + pc_tab[i] = sh_css_hrt_isp_current_pc(); +#else + pc = sh_css_hrt_isp_current_pc(); +#endif + +#if SUSPEND + /* RESUME the ISP */ + sh_css_isp_ctrl_store(ISP_SC_REG, RESUME_MASK); +#endif + isp_histogram->msink[pc] &= msink; + stall = (msink != 0x7FF); + + if (stall) + isp_histogram->stall[pc]++; + else + isp_histogram->run[pc]++; + +#if MULTIPLE_PCS + printk(KERN_INFO "msink = 0%X\n", msink); + for (i = 0; i < NOF_PCS; i++) + printk(KERN_INFO "PC = %d ", pc_tab[i]); + printk(KERN_INFO "\n"); +#endif + } + + if (sp_histogram && 0) { + msink = sh_css_hrt_sp_current_msink(); + pc = sh_css_hrt_sp_current_pc(); + sp_histogram->msink[pc] &= msink; + stall = (msink != 0x7FF); + if (stall) + sp_histogram->stall[pc]++; + else + sp_histogram->run[pc]++; + } +} diff --git a/drivers/media/video/atomisp/css/sh_css_metrics.h b/drivers/media/video/atomisp/css/sh_css_metrics.h new file mode 100644 index 0000000..1406d0c --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_metrics.h @@ -0,0 +1,60 @@ +/* + * Support for Medfield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef _SH_CSS_METRICS_H_ +#define _SH_CSS_METRICS_H_ + +#include "sh_css_types.h" + +struct sh_css_pc_histogram { + unsigned length; + unsigned *run; + unsigned *stall; + unsigned *msink; +}; + +struct sh_css_binary_metrics { + unsigned mode; + struct sh_css_pc_histogram isp_histogram; + struct sh_css_pc_histogram sp_histogram; + struct sh_css_binary_metrics *next; +}; + +struct sh_css_frame_metrics { + unsigned num_frames; +}; + +struct sh_css_metrics { + struct sh_css_binary_metrics *binary_metrics; + struct sh_css_frame_metrics frame_metrics; +}; + +extern struct sh_css_metrics sh_css_metrics; + +/* Sample ISP and SP pc and add to histogram */ +void sh_css_metrics_enable_pc_histogram(bool enable); +void sh_css_metrics_start_frame(void); +void sh_css_metrics_start_binary(struct sh_css_binary_metrics *metrics); +void sh_css_metrics_sample_pcs(void); + +#endif /* _SH_CSS_METRICS_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_params.c b/drivers/media/video/atomisp/css/sh_css_params.c new file mode 100644 index 0000000..25c3c93 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_params.c @@ -0,0 +1,2119 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include + +#include "sh_css.h" +#include "sh_css_params.h" +#include "sh_css_internal.h" +#include "sh_css_hrt.h" +#include "sh_css_defs.h" + +#define sISP_REG_BIT ISP_VEC_ELEMBITS +#define uISP_REG_BIT (sISP_REG_BIT-1) +#define sSHIFT (16-sISP_REG_BIT) +#define uSHIFT (16-uISP_REG_BIT) +#define sFRACTION_BITS_FITTING(a) (a-sSHIFT) +#define uFRACTION_BITS_FITTING(a) (a-uSHIFT) +/* a:fraction bits for 16bit precision, b:fraction bits for ISP precision */ +#define sDIGIT_FITTING(v, a, b) \ + (((v)>>sSHIFT) >> (sFRACTION_BITS_FITTING(a)-(b))) +#define uDIGIT_FITTING(v, a, b) \ + (((v)>>uSHIFT) >> (uFRACTION_BITS_FITTING(a)-(b))) + +#define FPNTBL_BYTES(binary) \ + (sizeof(char) * (binary)->in_frame_info.height * \ + (binary)->in_frame_info.padded_width) +#define SCTBL_BYTES(binary) \ + (sizeof(unsigned short) * (binary)->sctbl_height * \ + (binary)->sctbl_aligned_width_per_color * SH_CSS_SC_NUM_COLORS) +#define S3ATBL_BYTES(binary) \ + (sizeof(struct sh_css_3a_output) * (binary)->s3atbl_isp_width * \ + (binary)->s3atbl_isp_height) +/* TODO: check if the stride is always the same max value or whether + * it varies per resolution. */ +#define S3ATBL_HI_LO_BYTES(binary) \ + (ISP_S3ATBL_HI_LO_STRIDE_BYTES * (binary)->s3atbl_isp_height) +/* SDIS */ +#define SDIS_VER_COEF_TBL__IN_DMEM(b) \ + _SDIS_VER_COEF_TBL_USE_DMEM(b->info->mode, b->info->enable_dis) + +#define SH_CSS_DIS_VER_NUM_COEF_TYPES(b) \ + (SDIS_VER_COEF_TBL__IN_DMEM(b) ? \ + SH_CSS_DIS_COEF_TYPES_ON_DMEM : \ + SH_CSS_DIS_NUM_COEF_TYPES) + +#define SDIS_HOR_COEF_TBL_BYTES(b) \ + (sizeof(short) * SH_CSS_DIS_NUM_COEF_TYPES * (b)->dis_hor_coef_num_isp) +#define SDIS_VER_COEF_TBL_BYTES(b) \ + (sizeof(short) * SH_CSS_DIS_VER_NUM_COEF_TYPES(b) * \ + (b)->dis_ver_coef_num_isp) +#define SDIS_HOR_PROJ_TBL_BYTES(b) \ + (sizeof(int) * SH_CSS_DIS_NUM_COEF_TYPES * (b)->dis_hor_proj_num_isp) +#define SDIS_VER_PROJ_TBL_BYTES(b) \ + (sizeof(int) * SH_CSS_DIS_NUM_COEF_TYPES * (b)->dis_ver_proj_num_isp) +#define MORPH_PLANE_BYTES(binary) \ + (SH_CSS_MORPH_TABLE_ELEM_BYTES * (binary)->morph_tbl_aligned_width * \ + (binary)->morph_tbl_height) + +static struct sh_css_isp_params isp_parameters; +static struct sh_css_fpn_table fpn_table; +static const struct sh_css_morph_table *morph_table; +static const struct sh_css_shading_table *sc_table; +static const struct sh_css_macc_table *macc_table; +static const struct sh_css_gamma_table *gamma_table; +static const struct sh_css_ctc_table *ctc_table; +static const struct sh_css_3a_config *s3a_config; +static const struct sh_css_wb_config *wb_config; +static const struct sh_css_cc_config *cc_config; +static const struct sh_css_tnr_config *tnr_config; +static const struct sh_css_ob_config *ob_config; +static const struct sh_css_dp_config *dp_config; +static const struct sh_css_nr_config *nr_config; +static const struct sh_css_ee_config *ee_config; +static const struct sh_css_de_config *de_config; +static const struct sh_css_gc_config *gc_config; +static const struct sh_css_anr_config *anr_config; +static bool isp_params_changed, + fpn_table_changed, + dis_coef_table_changed, + morph_table_changed, + sc_table_changed, + macc_table_changed, + gamma_table_changed, + ctc_table_changed, + s3a_config_changed, + wb_config_changed, + cc_config_changed, + tnr_config_changed, + ob_config_changed, + dp_config_changed, + nr_config_changed, + ee_config_changed, + de_config_changed, + gc_config_changed, + anr_config_changed; + +static size_t fpn_tbl_size, + sc_tbl_size, + s3a_tbl_size, + s3a_tbl_hi_size, + s3a_tbl_lo_size, + sdis_hor_coef_size, + sdis_ver_coef_size, + sdis_hor_proj_size, + sdis_ver_proj_size, + tetra_r_x_size, + tetra_r_y_size, + tetra_gr_x_size, + tetra_gr_y_size, + tetra_gb_x_size, + tetra_gb_y_size, + tetra_b_x_size, + tetra_b_y_size, + tetra_batr_x_size, + tetra_batr_y_size, + tetra_ratb_x_size, + tetra_ratb_y_size; + +/* local buffers, used to re-order the 3a statistics in vmem-format */ +static unsigned short s3a_tbl_hi_buf[ISP_S3ATBL_HI_LO_STRIDE * + SH_CSS_MAX_BQ_GRID_HEIGHT], + s3a_tbl_lo_buf[ISP_S3ATBL_HI_LO_STRIDE * + SH_CSS_MAX_BQ_GRID_HEIGHT]; +static struct sh_css_macc_table converted_macc_table; +static const short *dis_hor_coef_tbl, + *dis_ver_coef_tbl; +static const struct sh_css_binary *current_3a_binary; +/* for csim and fpga, we need to keep a copy of all data in DDR. + On the chip this is not necessary through. + TODO: remove this for the chip */ +static struct sh_css_ddr_address_map ddr_ptrs; +/* We keep a second copy of the ptr struct for the SP to access. + Again, this would not be necessary on the chip. */ +static void *sp_ddr_ptrs; + +/* sp group address on DDR */ +static void *xmem_sp_group_ptrs; + +/* Default Parameters */ +static const struct sh_css_gamma_table default_gamma_table = { + .data = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 16, + 17, 18, 19, 20, 21, 23, 24, 25, + 27, 28, 29, 31, 32, 33, 35, 36, + 38, 39, 41, 42, 44, 45, 47, 48, + 49, 51, 52, 54, 55, 57, 58, 60, + 61, 62, 64, 65, 66, 68, 69, 70, + 71, 72, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 93, 94, + 95, 96, 97, 98, 98, 99, 100, 101, + 102, 102, 103, 104, 105, 105, 106, 107, + 108, 108, 109, 110, 110, 111, 112, 112, + 113, 114, 114, 115, 116, 116, 117, 118, + 118, 119, 120, 120, 121, 121, 122, 123, + 123, 124, 125, 125, 126, 126, 127, 127, /* 128 */ + 128, 129, 129, 130, 130, 131, 131, 132, + 132, 133, 134, 134, 135, 135, 136, 136, + 137, 137, 138, 138, 139, 139, 140, 140, + 141, 141, 142, 142, 143, 143, 144, 144, + 145, 145, 145, 146, 146, 147, 147, 148, + 148, 149, 149, 150, 150, 150, 151, 151, + 152, 152, 152, 153, 153, 154, 154, 155, + 155, 155, 156, 156, 156, 157, 157, 158, + 158, 158, 159, 159, 160, 160, 160, 161, + 161, 161, 162, 162, 162, 163, 163, 163, + 164, 164, 164, 165, 165, 165, 166, 166, + 166, 167, 167, 167, 168, 168, 168, 169, + 169, 169, 170, 170, 170, 170, 171, 171, + 171, 172, 172, 172, 172, 173, 173, 173, + 174, 174, 174, 174, 175, 175, 175, 176, + 176, 176, 176, 177, 177, 177, 177, 178, /* 256 */ + 178, 178, 178, 179, 179, 179, 179, 180, + 180, 180, 180, 181, 181, 181, 181, 182, + 182, 182, 182, 182, 183, 183, 183, 183, + 184, 184, 184, 184, 184, 185, 185, 185, + 185, 186, 186, 186, 186, 186, 187, 187, + 187, 187, 187, 188, 188, 188, 188, 188, + 189, 189, 189, 189, 189, 190, 190, 190, + 190, 190, 191, 191, 191, 191, 191, 192, + 192, 192, 192, 192, 192, 193, 193, 193, + 193, 193, 194, 194, 194, 194, 194, 194, + 195, 195, 195, 195, 195, 195, 196, 196, + 196, 196, 196, 196, 197, 197, 197, 197, + 197, 197, 198, 198, 198, 198, 198, 198, + 198, 199, 199, 199, 199, 199, 199, 200, + 200, 200, 200, 200, 200, 200, 201, 201, + 201, 201, 201, 201, 201, 202, 202, 202, /* 384 */ + 202, 202, 202, 202, 203, 203, 203, 203, + 203, 203, 203, 204, 204, 204, 204, 204, + 204, 204, 204, 205, 205, 205, 205, 205, + 205, 205, 205, 206, 206, 206, 206, 206, + 206, 206, 206, 207, 207, 207, 207, 207, + 207, 207, 207, 208, 208, 208, 208, 208, + 208, 208, 208, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 211, 211, 211, + 211, 211, 211, 211, 211, 211, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 216, 216, 216, 216, 216, + 216, 216, 216, 216, 216, 217, 217, 217, /* 512 */ + 217, 217, 217, 217, 217, 217, 217, 218, + 218, 218, 218, 218, 218, 218, 218, 218, + 218, 219, 219, 219, 219, 219, 219, 219, + 219, 219, 219, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, + 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 223, 223, 223, 223, 223, 223, + 223, 223, 223, 223, 223, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, + 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 226, 226, 226, 226, 226, + 226, 226, 226, 226, 226, 226, 226, 227, + 227, 227, 227, 227, 227, 227, 227, 227, + 227, 227, 228, 228, 228, 228, 228, 228, + 228, 228, 228, 228, 228, 228, 229, 229, + 229, 229, 229, 229, 229, 229, 229, 229, + 229, 229, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 231, + 231, 231, 231, 232, 232, 232, 232, 232, + 232, 232, 232, 232, 232, 232, 232, 233, + 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 234, 234, 234, 234, + 234, 234, 234, 234, 234, 234, 234, 234, + 234, 235, 235, 235, 235, 235, 235, 235, + 235, 235, 235, 235, 235, 235, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, + 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 241, 241, 241, 241, + 241, 241, 241, 241, 241, 241, 241, 241, + 241, 241, 241, 242, 242, 242, 242, 242, + 242, 242, 242, 242, 242, 242, 242, 242, + 242, 242, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, + 243, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, + 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 246, + 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 247, + 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 248, + 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 249, + 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 250, + 250, 250, 250, 250, 250, 250, 250, 250, + 250, 250, 250, 250, 250, 250, 250, 251, + 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 252, + 252, 252, 252, 252, 252, 252, 252, 252, + 252, 252, 252, 252, 252, 252, 252, 253, + 253, 253, 253, 253, 253, 253, 253, 253, + 253, 253, 253, 253, 253, 253, 253, 253, + 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, + 255, 255, 255, 255, 255, 255, 255, 255 + } +}; + +static const struct sh_css_ctc_table default_ctc_table = { + .data = { + 0, 0, 256, 384, 384, 497, 765, 806, + 837, 851, 888, 901, 957, 981, 993, 1001, + 1011, 1029, 1028, 1039, 1062, 1059, 1073, 1080, + 1083, 1085, 1085, 1098, 1080, 1084, 1085, 1093, + 1078, 1073, 1070, 1069, 1077, 1066, 1072, 1063, + 1053, 1044, 1046, 1053, 1039, 1028, 1025, 1024, + 1012, 1013, 1016, 996, 992, 990, 990, 980, + 969, 968, 961, 955, 951, 949, 933, 930, + 929, 925, 921, 916, 906, 901, 895, 893, + 886, 877, 872, 869, 866, 861, 857, 849, + 845, 838, 836, 832, 823, 821, 815, 813, + 809, 805, 796, 793, 790, 785, 784, 778, + 772, 768, 766, 763, 758, 752, 749, 745, + 741, 740, 736, 730, 726, 724, 723, 718, + 711, 709, 706, 704, 701, 698, 691, 689, + 688, 683, 683, 678, 675, 673, 671, 669, + 666, 663, 661, 660, 656, 656, 653, 650, + 648, 647, 646, 643, 639, 638, 637, 635, + 633, 632, 629, 627, 626, 625, 622, 621, + 618, 618, 614, 614, 612, 609, 606, 606, + 603, 600, 600, 597, 594, 591, 590, 586, + 582, 581, 578, 575, 572, 569, 563, 560, + 557, 554, 551, 548, 545, 539, 536, 533, + 529, 527, 524, 519, 516, 513, 510, 507, + 504, 501, 498, 493, 491, 488, 485, 484, + 480, 476, 474, 471, 467, 466, 464, 460, + 459, 455, 453, 449, 447, 446, 443, 441, + 438, 435, 432, 432, 429, 427, 426, 422, + 419, 418, 416, 414, 412, 410, 408, 406, + 404, 402, 401, 398, 397, 395, 393, 390, + 389, 388, 387, 384, 382, 380, 378, 377, + 376, 375, 372, 370, 368, 368, 366, 364, + 363, 361, 360, 358, 357, 355, 354, 352, + 351, 350, 349, 346, 345, 344, 344, 342, + 340, 339, 337, 337, 336, 335, 333, 331, + 330, 329, 328, 326, 326, 324, 324, 322, + 321, 320, 318, 318, 318, 317, 315, 313, + 312, 311, 311, 310, 308, 307, 306, 306, + 304, 304, 302, 301, 300, 300, 299, 297, + 297, 296, 296, 294, 294, 292, 291, 291, + 291, 290, 288, 287, 286, 286, 287, 285, + 284, 283, 282, 282, 281, 281, 279, 278, + 278, 278, 276, 276, 275, 274, 274, 273, + 271, 270, 269, 268, 268, 267, 265, 262, + 261, 260, 260, 259, 257, 254, 252, 252, + 251, 251, 249, 246, 245, 244, 243, 242, + 240, 239, 239, 237, 235, 235, 233, 231, + 232, 230, 229, 226, 225, 224, 225, 224, + 223, 220, 219, 219, 218, 217, 217, 214, + 213, 213, 212, 211, 209, 209, 209, 208, + 206, 205, 204, 203, 204, 203, 201, 200, + 199, 197, 198, 198, 197, 195, 194, 194, + 193, 192, 192, 191, 189, 190, 189, 188, + 186, 187, 186, 185, 185, 184, 183, 181, + 183, 182, 181, 180, 179, 178, 178, 178, + 177, 176, 175, 176, 175, 174, 174, 173, + 172, 173, 172, 171, 170, 170, 169, 169, + 169, 168, 167, 166, 167, 167, 166, 165, + 164, 164, 164, 163, 164, 163, 162, 163, + 162, 161, 160, 161, 160, 160, 160, 159, + 158, 157, 158, 158, 157, 157, 156, 156, + 156, 156, 155, 155, 154, 154, 154, 154, + 154, 153, 152, 153, 152, 152, 151, 152, + 151, 152, 151, 150, 150, 149, 149, 150, + 149, 149, 148, 148, 148, 149, 148, 147, + 146, 146, 147, 146, 147, 146, 145, 146, + 146, 145, 144, 145, 144, 145, 144, 144, + 143, 143, 143, 144, 143, 142, 142, 142, + 142, 142, 142, 141, 141, 141, 141, 140, + 140, 141, 140, 140, 141, 140, 139, 139, + 139, 140, 139, 139, 138, 138, 137, 139, + 138, 138, 138, 137, 138, 137, 137, 137, + 137, 136, 137, 136, 136, 136, 136, 135, + 136, 135, 135, 135, 135, 136, 135, 135, + 134, 134, 133, 135, 134, 134, 134, 133, + 134, 133, 134, 133, 133, 132, 133, 133, + 132, 133, 132, 132, 132, 132, 131, 131, + 131, 132, 131, 131, 130, 131, 130, 132, + 131, 130, 130, 129, 130, 129, 130, 129, + 129, 129, 130, 129, 128, 128, 128, 128, + 129, 128, 128, 127, 127, 128, 128, 127, + 127, 126, 126, 127, 127, 126, 126, 126, + 127, 126, 126, 126, 125, 125, 126, 125, + 125, 124, 124, 124, 125, 125, 124, 124, + 123, 124, 124, 123, 123, 122, 122, 122, + 122, 122, 121, 120, 120, 119, 118, 118, + 118, 117, 117, 116, 115, 115, 115, 114, + 114, 113, 113, 112, 111, 111, 111, 110, + 110, 109, 109, 108, 108, 108, 107, 107, + 106, 106, 105, 105, 105, 104, 104, 103, + 103, 102, 102, 102, 102, 101, 101, 100, + 100, 99, 99, 99, 99, 99, 99, 98, + 97, 98, 97, 97, 97, 96, 96, 95, + 96, 95, 96, 95, 95, 94, 94, 95, + 94, 94, 94, 93, 93, 92, 93, 93, + 93, 93, 92, 92, 91, 92, 92, 92, + 91, 91, 90, 90, 91, 91, 91, 90, + 90, 90, 90, 91, 90, 90, 90, 89, + 89, 89, 90, 89, 89, 89, 89, 89, + 88, 89, 89, 88, 88, 88, 88, 87, + 89, 88, 88, 88, 88, 88, 87, 88, + 88, 88, 87, 87, 87, 87, 87, 88, + 87, 87, 87, 87, 87, 87, 88, 87, + 87, 87, 87, 86, 86, 87, 87, 87, + 87, 86, 86, 86, 87, 87, 86, 87, + 86, 86, 86, 87, 87, 86, 86, 86, + 86, 86, 87, 87, 86, 85, 85, 85, + 84, 85, 85, 84, 84, 83, 83, 82, + 82, 82, 81, 81, 80, 79, 79, 79, + 78, 77, 77, 76, 76, 76, 75, 74, + 74, 74, 73, 73, 72, 71, 71, 71, + 70, 70, 69, 69, 68, 68, 67, 67, + 67, 66, 66, 65, 65, 64, 64, 63, + 62, 62, 62, 61, 60, 60, 59, 59, + 58, 58, 57, 57, 56, 56, 56, 55, + 55, 54, 55, 55, 54, 53, 53, 52, + 53, 53, 52, 51, 51, 50, 51, 50, + 49, 49, 50, 49, 49, 48, 48, 47, + 47, 48, 46, 45, 45, 45, 46, 45, + 45, 44, 45, 45, 45, 43, 42, 42, + 41, 43, 41, 40, 40, 39, 40, 41, + 39, 39, 39, 39, 39, 38, 35, 35, + 34, 37, 36, 34, 33, 33, 33, 35, + 34, 32, 32, 31, 32, 30, 29, 26, + 25, 25, 27, 26, 23, 23, 23, 25, + 24, 24, 22, 21, 20, 19, 16, 14, + 13, 13, 13, 10, 9, 7, 7, 7, + 12, 12, 12, 7, 0, 0, 0, 0 + } +}; + +/* multiple axis color correction table, + * 64values = 2x2matrix for 16area, [s2.11]. + */ +static const struct sh_css_macc_table default_macc_table = { + .data = { + 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192 + } +}; + +/* Digital Zoom lookup table. See documentation for more details about the + * contents of this table. + */ +static const int zoom_table[4][HRT_GDC_N] = { + {0, 0, 0, 0, 0, 0, -1, -1, + -1, -2, -2, -3, -3, -4, -4, -5, + -6, -6, -7, -7, -8, -9, -9, -10, + -11, -11, -12, -13, -13, -14, -14, -15, + -16, -16, -16, -17, -17, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, + -18, -17, -17, -16, -15, -15, -14, -13, + -12, -11, -9, -8, -7, -5, -3, -1}, + {0, 2, 4, 7, 9, 12, 16, 19, + 23, 27, 31, 35, 39, 43, 48, 53, + 58, 62, 67, 73, 78, 83, 88, 94, + 99, 105, 110, 116, 121, 127, 132, 138, + 144, 149, 154, 160, 165, 170, 176, 181, + 186, 191, 195, 200, 205, 209, 213, 218, + 222, 225, 229, 232, 236, 239, 241, 244, + 246, 248, 250, 252, 253, 254, 255, 255}, + {256, 255, 255, 254, 253, 252, 250, 248, + 246, 244, 241, 239, 236, 232, 229, 225, + 222, 218, 213, 209, 205, 200, 195, 191, + 186, 181, 176, 170, 165, 160, 154, 149, + 144, 138, 132, 127, 121, 116, 110, 105, + 99, 94, 88, 83, 78, 73, 67, 62, + 58, 53, 48, 43, 39, 35, 31, 27, + 23, 19, 16, 12, 9, 7, 4, 2}, + {0, -1, -3, -5, -6, -8, -9, -10, + -12, -13, -14, -15, -16, -15, -17, -17, + -18, -18, -17, -19, -19, -18, -18, -19, + -18, -19, -18, -17, -17, -17, -16, -16, + -16, -15, -14, -14, -13, -12, -12, -12, + -11, -11, -9, -9, -9, -8, -6, -6, + -6, -5, -4, -3, -4, -3, -2, -2, + -1, 0, -1, 0, 1, 0, 0, 0} +}; + +static const struct sh_css_3a_config default_3a_config = { + .ae_y_coef_r = 25559, + .ae_y_coef_g = 32768, + .ae_y_coef_b = 7209, + .af_fir1_coef = {-3344, -6104, -19143, 19143, 6104, 3344, 0}, + .af_fir2_coef = {1027, 0, -9219, 16384, -9219, 1027, 0} +}; + +static const struct sh_css_3a_config disabled_3a_config = { + .ae_y_coef_r = 25559, + .ae_y_coef_g = 32768, + .ae_y_coef_b = 7209, + .af_fir1_coef = {-6689, -12207, -32768, 32767, 12207, 6689, 0}, + .af_fir2_coef = {2053, 0, -18437, 32767, -18437, 2053, 0} +}; + +static const struct sh_css_wb_config default_wb_config = { + .integer_bits = 1, + .gr = 32768, + .r = 32768, + .b = 32768, + .gb = 32768 +}; + +static const struct sh_css_wb_config disabled_wb_config = { + .integer_bits = 1, + .gr = 32768, + .r = 32768, + .b = 32768, + .gb = 32768 +}; + +static const struct sh_css_cc_config default_cc_config = { + .fraction_bits = 8, + .matrix = {255, 29, 120, 0, -374, -342, 0, -672, 301}, +}; + +static const struct sh_css_cc_config disabled_cc_config = { + .fraction_bits = 8, + .matrix = {256, 44, 47, 0, -169, -171, 0, -214, 148}, +}; + +static const struct sh_css_tnr_config default_tnr_config = { + .gain = 32768, + .threshold_y = 32, + .threshold_uv = 32, +}; + +static const struct sh_css_tnr_config disabled_tnr_config = { + .gain = 0, + .threshold_y = 65535, + .threshold_uv = 65535, +}; + +static const struct sh_css_ob_config default_ob_config = { + .mode = sh_css_ob_mode_none, + .level_gr = 0, + .level_r = 0, + .level_b = 0, + .level_gb = 0, + .start_position = 0, + .end_position = 0 +}; + +static const struct sh_css_ob_config disabled_ob_config = { + .mode = sh_css_ob_mode_none, + .level_gr = 0, + .level_r = 0, + .level_b = 0, + .level_gb = 0, + .start_position = 0, + .end_position = 0 +}; + +static const struct sh_css_dp_config default_dp_config = { + .threshold = 8192, + .gain = 2048 +}; + +static const struct sh_css_dp_config disabled_dp_config = { + .threshold = 65535, + .gain = 65535 +}; + +static const struct sh_css_nr_config default_nr_config = { + .gain = 16384, + .direction = 1280, + .threshold_cb = 0, + .threshold_cr = 0 +}; + +static const struct sh_css_nr_config disabled_nr_config = { + .gain = 0, + .direction = 0, + .threshold_cb = 0, + .threshold_cr = 0 +}; + +static const struct sh_css_ee_config default_ee_config = { + .gain = 8192, + .threshold = 128, + .detail_gain = 2048 +}; + +static const struct sh_css_ee_config disabled_ee_config = { + .gain = 0, + .threshold = 0, + .detail_gain = 0 +}; + +static const struct sh_css_de_config default_de_config = { + .pixelnoise = 0, + .c1_coring_threshold = 0, + .c2_coring_threshold = 0 +}; + +static const struct sh_css_de_config disabled_de_config = { + .pixelnoise = 65535, + .c1_coring_threshold = 0, + .c2_coring_threshold = 0 +}; + +static const struct sh_css_gc_config default_gc_config = { + .gain_k1 = 2457, /* (1<<13) * 0.3 */ + .gain_k2 = 2457 /* idem */ +}; + +static const struct sh_css_gc_config disabled_gc_config = { + .gain_k1 = 2457, /* (1<<13) * 0.3 */ + .gain_k2 = 2457 /* idem */ +}; + +static const struct sh_css_anr_config default_anr_config = { + .threshold = 5, +}; + +int +sh_css_get_gdc_coord_one(void) +{ + return HRT_GDC_COORD_ONE; +} + +void +sh_css_set_dis_coefficients(const short *horizontal_coefficients, + const short *vertical_coefficients) +{ + dis_hor_coef_tbl = horizontal_coefficients; + dis_ver_coef_tbl = vertical_coefficients; + dis_coef_table_changed = true; +} + +void +sh_css_get_dis_projections(int *horizontal_projections, + int *vertical_projections) +{ + unsigned int hor_num_isp, ver_num_isp, + hor_num_3a, ver_num_3a, i; + int *hor_ptr_3a = horizontal_projections, + *ver_ptr_3a = vertical_projections, + *hor_ptr_isp = ddr_ptrs.sdis_hor_proj, + *ver_ptr_isp = ddr_ptrs.sdis_ver_proj; + + if (current_3a_binary == NULL) + return; + + hor_num_isp = current_3a_binary->dis_hor_proj_num_isp; + ver_num_isp = current_3a_binary->dis_ver_proj_num_isp; + hor_num_3a = current_3a_binary->dis_hor_proj_num_3a; + ver_num_3a = current_3a_binary->dis_ver_proj_num_3a; + + for (i = 0; i < SH_CSS_DIS_NUM_COEF_TYPES; i++) { + hrt_isp_css_mm_load(hor_ptr_isp, hor_ptr_3a, + hor_num_3a * sizeof(int)); + hor_ptr_isp += hor_num_isp; + hor_ptr_3a += hor_num_3a; + + hrt_isp_css_mm_load(ver_ptr_isp, ver_ptr_3a, + ver_num_3a * sizeof(int)); + ver_ptr_isp += ver_num_isp; + ver_ptr_3a += ver_num_3a; + } +} + +static void +get_3a_stats_from_dmem(struct sh_css_3a_output *output) +{ + int ddr_width = current_3a_binary->s3atbl_isp_width, + out_width = current_3a_binary->s3atbl_width, + out_height = current_3a_binary->s3atbl_height, + i; + struct sh_css_3a_output + *ddr_ptr = ddr_ptrs.s3a_tbl, + *out_ptr = output; + + for (i = 0; i < out_height; i++) { + hrt_isp_css_mm_load(ddr_ptr, out_ptr, + out_width * sizeof(*output)); + ddr_ptr += ddr_width; + out_ptr += out_width; + } +} + +static inline int +merge_hi14bit_lo14bit(unsigned short hi, unsigned short lo) +{ + int val = (int) ((((unsigned int) hi << 14) & 0xfffc000) | + ((unsigned int) lo & 0x3fff)); + return val; +} + +static void +get_3a_stats_from_vmem(struct sh_css_3a_output *output) +{ + int out_width = current_3a_binary->s3atbl_width, + out_height = current_3a_binary->s3atbl_height; + unsigned short *hi, *lo; + int chunk, rest, kmax, y, x, k, elm_start, elm, ofs, bytes; + + hi = s3a_tbl_hi_buf; + lo = s3a_tbl_lo_buf; + + chunk = (ISP_VEC_NELEMS >> current_3a_binary->deci_factor_log2); + chunk = max(chunk, 1); + bytes = ISP_S3ATBL_HI_LO_STRIDE_BYTES * out_height; + + hrt_isp_css_mm_load(ddr_ptrs.s3a_tbl_hi, hi, bytes); + hrt_isp_css_mm_load(ddr_ptrs.s3a_tbl_lo, lo, bytes); + + for (y = 0; y < out_height; y++) { + elm_start = y * ISP_S3ATBL_HI_LO_STRIDE; + rest = out_width; + x = 0; + while (x < out_width) { + kmax = (rest > chunk) ? chunk : rest; + ofs = y * out_width + x; + elm = elm_start + x * sizeof(*output) / sizeof(int); + for (k = 0; k < kmax; k++, elm++) { + output[ofs + k].ae_y = + merge_hi14bit_lo14bit + (hi[elm], lo[elm]); + output[ofs + k].awb_cnt = + merge_hi14bit_lo14bit + (hi[elm + chunk], lo[elm + chunk]); + output[ofs + k].awb_gr = + merge_hi14bit_lo14bit + (hi[elm + chunk * 2], + lo[elm + chunk * 2]); + output[ofs + k].awb_r = + merge_hi14bit_lo14bit + (hi[elm + chunk * 3], + lo[elm + chunk * 3]); + output[ofs + k].awb_b = + merge_hi14bit_lo14bit + (hi[elm + chunk * 4], + lo[elm + chunk * 4]); + output[ofs + k].awb_gb = + merge_hi14bit_lo14bit + (hi[elm + chunk * 5], + lo[elm + chunk * 5]); + output[ofs + k].af_hpf1 = + merge_hi14bit_lo14bit + (hi[elm + chunk * 6], + lo[elm + chunk * 6]); + output[ofs + k].af_hpf2 = + merge_hi14bit_lo14bit + (hi[elm + chunk * 7], + lo[elm + chunk * 7]); + } + x += chunk; + rest -= chunk; + } + } +} + +static void +sh_css_process_3a(void) +{ + unsigned int i; + /* coefficients to calculate Y */ + isp_parameters.ae_y_coef_r = + uDIGIT_FITTING(s3a_config->ae_y_coef_r, 16, SH_CSS_AE_YCOEF_SHIFT); + isp_parameters.ae_y_coef_g = + uDIGIT_FITTING(s3a_config->ae_y_coef_g, 16, SH_CSS_AE_YCOEF_SHIFT); + isp_parameters.ae_y_coef_b = + uDIGIT_FITTING(s3a_config->ae_y_coef_b, 16, SH_CSS_AE_YCOEF_SHIFT); + + /* af fir coefficients */ + for (i = 0; i < 7; ++i) { + isp_parameters.af_fir1[i] = + sDIGIT_FITTING(s3a_config->af_fir1_coef[i], 15, + SH_CSS_AF_FIR_SHIFT); + isp_parameters.af_fir2[i] = + sDIGIT_FITTING(s3a_config->af_fir2_coef[i], 15, + SH_CSS_AF_FIR_SHIFT); + } + isp_params_changed = true; + s3a_config_changed = false; +} + +void * +sh_css_params_ddr_address_map(void) +{ + return sp_ddr_ptrs; +} + +/* **************************************************** + * Each coefficient is stored as 7bits to fit 2 of them into one + * ISP vector element, so we will store 4 coefficents on every + * memory word (32bits) + * + * 0: Coefficient 0 used bits + * 1: Coefficient 1 used bits + * 2: Coefficient 2 used bits + * 3: Coefficient 3 used bit3 + * x: not used + * + * xx33333332222222 | xx11111110000000 + * + * *************************************************** + */ +static void +store_fpntbl(void *ptr) +{ + unsigned int i, j; + short *data_ptr = fpn_table.data; + + for (i = 0; i < fpn_table.height; i++) { + for (j = 0; + j < fpn_table.width; + j += 4, ptr += 4, data_ptr += 4) { + int data = data_ptr[0] << 0 | + data_ptr[1] << 7 | + data_ptr[2] << 16 | + data_ptr[3] << 23; + hrt_isp_css_mm_store_int(ptr, data); + } + } +} + +static void +convert_raw_to_fpn(void) +{ + short maxval = 0; + unsigned int i; + + /* Find the maximum value in the table */ + for (i = 0; i < fpn_table.height * fpn_table.width; i++) { + short val = fpn_table.data[i]; + /* Make sure FPN value can be represented in 13-bit unsigned + * number (ISP precision - 1), but note that actual input range + * depends on precision of input frame data. + */ + if (val < 0) + val = 0; + if (val >= (1 << 13)) + val = (1 << 13) - 1; + maxval = max(maxval, val); + } + /* Find the lowest shift value to remap the values in the range + * 0..maxval to 0..2^shiftval*63. + */ + fpn_table.shift = 0; + while (maxval > 63) { + maxval /= 2; + fpn_table.shift++; + } + /* Adjust the values in the table for the shift value */ + for (i = 0; i < fpn_table.height * fpn_table.width; i++) + ((unsigned short *) fpn_table.data)[i] >>= fpn_table.shift; +} + +enum sh_css_err +sh_css_set_black_frame(const struct sh_css_frame *raw_black_frame) +{ + /* this function desperately needs to be moved to the ISP or SP such + * that it can use the DMA. + */ + unsigned int height = raw_black_frame->info.height, + width = raw_black_frame->info.padded_width, + y, x, k, data; + void *ptr = raw_black_frame->planes.raw.data; + + if (fpn_table.data && + (fpn_table.width != width || fpn_table.height != height)) { + sh_css_free(fpn_table.data); + fpn_table.data = NULL; + } + if (fpn_table.data == NULL) { + fpn_table.data = sh_css_malloc(height * width * sizeof(short)); + if (!fpn_table.data) + return sh_css_err_cannot_allocate_memory; + fpn_table.width = width; + fpn_table.height = height; + fpn_table.shift = 0; + } + + /* store raw to fpntbl */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x += (ISP_VEC_NELEMS * 2)) { + int ofs = y * width + x; + for (k = 0; k < ISP_VEC_NELEMS; k += 2) { + hrt_isp_css_mm_load(ptr, &data, sizeof(int)); + fpn_table.data[ofs + 2 * k] = + (short) (data & 0xFFFF); + fpn_table.data[ofs + 2 * k + 2] = + (short) ((data >> 16) & 0xFFFF); + ptr += 4; /* byte system address */ + } + for (k = 0; k < ISP_VEC_NELEMS; k += 2) { + hrt_isp_css_mm_load(ptr, &data, sizeof(int)); + fpn_table.data[ofs + 2 * k + 1] = + (short) (data & 0xFFFF); + fpn_table.data[ofs + 2 * k + 3] = + (short) ((data >> 16) & 0xFFFF); + ptr += 4; /* byte system address */ + } + } + } + + /* raw -> fpn */ + convert_raw_to_fpn(); + + /* overwrite isp parameter */ + isp_parameters.fpn_shift = fpn_table.shift; + isp_parameters.fpn_enabled = 1; + fpn_table_changed = true; + isp_params_changed = true; + return sh_css_success; +} + +struct sh_css_shading_table * +sh_css_shading_table_alloc(unsigned int width, + unsigned int height) +{ + unsigned int i; + struct sh_css_shading_table *me = sh_css_malloc(sizeof(*me)); + + if (me == NULL) + return NULL; + me->width = width; + me->height = height; + me->sensor_width = 0; + me->sensor_height = 0; + me->fraction_bits = 0; + for (i = 0; i < SH_CSS_SC_NUM_COLORS; i++) { + me->data[i] = + sh_css_malloc(width * height * sizeof(*me->data[0])); + if (me->data[i] == NULL) { + unsigned int j; + for (j = 0; j < i; j++) + sh_css_free(me->data[j]); + sh_css_free(me); + return NULL; + } + } + return me; +} + +void +sh_css_shading_table_free(struct sh_css_shading_table *table) +{ + unsigned int i; + + if (table == NULL) + return; + for (i = 0; i < SH_CSS_SC_NUM_COLORS; i++) { + if (table->data[i]) + sh_css_free(table->data[i]); + } + sh_css_free(table); +} + +void +sh_css_params_set_shading_table(const struct sh_css_shading_table *table) +{ + if (table != sc_table) { + sc_table = table; + sc_table_changed = true; + } +} + +static void +store_sctbl(const struct sh_css_binary *binary, + void *ddr_addr) +{ + unsigned int i, j, aligned_width, row_padding; + + if (!sc_table) + return; + + aligned_width = binary->sctbl_aligned_width_per_color; + isp_parameters.sc_gain_shift = sc_table->fraction_bits; + row_padding = aligned_width - sc_table->width; + + for (i = 0; i < sc_table->height; i++) { + for (j = 0; j < SH_CSS_SC_NUM_COLORS; j++) { + hrt_isp_css_mm_store(ddr_addr, + &sc_table->data[j][i*sc_table->width], + sc_table->width * sizeof(short)); + ddr_addr += sc_table->width * sizeof(short); + hrt_isp_css_mm_set(ddr_addr, 0, + row_padding * sizeof(short)); + ddr_addr += row_padding * sizeof(short); + } + } + isp_params_changed = true; +} + +static void +sh_css_process_wb(void) +{ + isp_parameters.wb_gain_shift = + uISP_REG_BIT - wb_config->integer_bits; + isp_parameters.wb_gain_gr = + uDIGIT_FITTING(wb_config->gr, 16 - wb_config->integer_bits, + isp_parameters.wb_gain_shift); + isp_parameters.wb_gain_r = + uDIGIT_FITTING(wb_config->r, 16 - wb_config->integer_bits, + isp_parameters.wb_gain_shift); + isp_parameters.wb_gain_b = + uDIGIT_FITTING(wb_config->b, 16 - wb_config->integer_bits, + isp_parameters.wb_gain_shift); + isp_parameters.wb_gain_gb = + uDIGIT_FITTING(wb_config->gb, 16 - wb_config->integer_bits, + isp_parameters.wb_gain_shift); + isp_params_changed = true; + wb_config_changed = false; +} + +static void +sh_css_process_cc(void) +{ + isp_parameters.csc_coef_shift = (int) cc_config->fraction_bits; + isp_parameters.yc1c2_to_ycbcr_00 = (int) cc_config->matrix[0]; + isp_parameters.yc1c2_to_ycbcr_01 = (int) cc_config->matrix[1]; + isp_parameters.yc1c2_to_ycbcr_02 = (int) cc_config->matrix[2]; + isp_parameters.yc1c2_to_ycbcr_10 = (int) cc_config->matrix[3]; + isp_parameters.yc1c2_to_ycbcr_11 = (int) cc_config->matrix[4]; + isp_parameters.yc1c2_to_ycbcr_12 = (int) cc_config->matrix[5]; + isp_parameters.yc1c2_to_ycbcr_20 = (int) cc_config->matrix[6]; + isp_parameters.yc1c2_to_ycbcr_21 = (int) cc_config->matrix[7]; + isp_parameters.yc1c2_to_ycbcr_22 = (int) cc_config->matrix[8]; + isp_params_changed = true; + cc_config_changed = false; +} + +static void +sh_css_process_tnr(void) +{ + isp_parameters.tnr_coef = + uDIGIT_FITTING(tnr_config->gain, 16, SH_CSS_TNR_COEF_SHIFT); + isp_parameters.tnr_threshold_Y = + uDIGIT_FITTING(tnr_config->threshold_y, 16, SH_CSS_BAYER_BITS); + isp_parameters.tnr_threshold_C = + uDIGIT_FITTING(tnr_config->threshold_uv, 16, SH_CSS_BAYER_BITS); + isp_params_changed = true; + tnr_config_changed = false; +} + +static void +sh_css_process_ob(void) +{ + unsigned int raw_bit_depth = 16; + switch (ob_config->mode) { + case sh_css_ob_mode_fixed: + if (current_3a_binary) + raw_bit_depth + = current_3a_binary->in_frame_info.raw_bit_depth; + isp_parameters.ob_blacklevel_gr + = ob_config->level_gr >> (16 - raw_bit_depth); + isp_parameters.ob_blacklevel_r + = ob_config->level_r >> (16 - raw_bit_depth); + isp_parameters.ob_blacklevel_b + = ob_config->level_b >> (16 - raw_bit_depth); + isp_parameters.ob_blacklevel_gb + = ob_config->level_gb >> (16 - raw_bit_depth); + isp_parameters.obarea_start_bq = 0; + isp_parameters.obarea_length_bq = 0; + isp_parameters.obarea_length_bq_inverse = 0; + break; + case sh_css_ob_mode_raster: + isp_parameters.ob_blacklevel_gr = 0; + isp_parameters.ob_blacklevel_r = 0; + isp_parameters.ob_blacklevel_b = 0; + isp_parameters.ob_blacklevel_gb = 0; + isp_parameters.obarea_start_bq = + ob_config->start_position; + isp_parameters.obarea_length_bq = + ((ob_config->end_position - ob_config->start_position) + 1); + isp_parameters.obarea_length_bq_inverse = + (1 << 12) / isp_parameters.obarea_length_bq; + break; + default: + isp_parameters.ob_blacklevel_gr = 0; + isp_parameters.ob_blacklevel_r = 0; + isp_parameters.ob_blacklevel_b = 0; + isp_parameters.ob_blacklevel_gb = 0; + isp_parameters.obarea_start_bq = 0; + isp_parameters.obarea_length_bq = 0; + isp_parameters.obarea_length_bq_inverse = 0; + break; + } + isp_params_changed = true; + ob_config_changed = false; +} + +static void +sh_css_process_dp(void) +{ + isp_parameters.dp_threshold_single_when_2adjacent_on = + SH_CSS_BAYER_MAXVAL; + isp_parameters.dp_threshold_2adjacent_when_2adjacent_on = + uDIGIT_FITTING(dp_config->threshold, 16, SH_CSS_BAYER_BITS); + isp_parameters.dp_threshold_single_when_2adjacent_off = + uDIGIT_FITTING(dp_config->threshold, 16, SH_CSS_BAYER_BITS); + isp_parameters.dp_threshold_2adjacent_when_2adjacent_off = + SH_CSS_BAYER_MAXVAL; + isp_parameters.dp_gain = + uDIGIT_FITTING(dp_config->gain, 8, SH_CSS_DP_GAIN_SHIFT); + isp_params_changed = true; + dp_config_changed = false; +} + +static void +sh_css_process_nr_ee(void) +{ + int asiWk1, asiWk2, asiWk3; + + /* BNR (Bayer Noise Reduction) */ + isp_parameters.bnr_threshold_low = + uDIGIT_FITTING(nr_config->direction, 16, SH_CSS_BAYER_BITS); + isp_parameters.bnr_threshold_width_log2 = uFRACTION_BITS_FITTING(8); + isp_parameters.bnr_threshold_width = + 1 << isp_parameters.bnr_threshold_width_log2; + isp_parameters.bnr_gain_all = + uDIGIT_FITTING(nr_config->gain, 16, SH_CSS_BNR_GAIN_SHIFT); + isp_parameters.bnr_gain_dir = + uDIGIT_FITTING(nr_config->gain, 16, SH_CSS_BNR_GAIN_SHIFT); + isp_parameters.bnr_clip = uDIGIT_FITTING(16384, 16, SH_CSS_BAYER_BITS); + + /* YNR (Y Noise Reduction), YEE (Y Edge Enhancement) */ + asiWk1 = (int) ee_config->gain; + asiWk2 = asiWk1 / 8; + asiWk3 = asiWk1 / 4; + isp_parameters.ynr_threshold = + uDIGIT_FITTING(8192, 16, SH_CSS_BAYER_BITS); + isp_parameters.ynr_gain_dir = isp_parameters.bnr_gain_dir / 2; + isp_parameters.ynr_gain_all = isp_parameters.bnr_gain_all / 2; + isp_parameters.ynryee_dirthreshold_s = + min((uDIGIT_FITTING(nr_config->direction, 16, SH_CSS_BAYER_BITS) + << 1), + SH_CSS_BAYER_MAXVAL); + isp_parameters.ynryee_dirthreshold_g = + min((uDIGIT_FITTING(nr_config->direction, 16, SH_CSS_BAYER_BITS) + << 4), + SH_CSS_BAYER_MAXVAL); + isp_parameters.ynryee_dirthreshold_width_log2 = + uFRACTION_BITS_FITTING(8); + isp_parameters.ynryee_dirthreshold_width = + 1 << isp_parameters.ynryee_dirthreshold_width_log2; + isp_parameters.yee_detailgain = + uDIGIT_FITTING(ee_config->detail_gain, 11, + SH_CSS_YEE_DETAIL_GAIN_SHIFT); + isp_parameters.yee_coring_s = + (uDIGIT_FITTING(56, 16, SH_CSS_BAYER_BITS) * + ee_config->threshold) >> 8; + isp_parameters.yee_coring_g = + (uDIGIT_FITTING(224, 16, SH_CSS_BAYER_BITS) * + ee_config->threshold) >> 8; + /* 8; // *1.125 ->[s4.8] */ + isp_parameters.yee_scale_plus_s = + (asiWk1 + asiWk2) >> (11 - SH_CSS_YEE_SCALE_SHIFT); + /* 8; // ( * -.25)->[s4.8] */ + isp_parameters.yee_scale_plus_g = + (0 - asiWk3) >> (11 - SH_CSS_YEE_SCALE_SHIFT); + /* 8; // *0.875 ->[s4.8] */ + isp_parameters.yee_scale_minus_s = + (asiWk1 - asiWk2) >> (11 - SH_CSS_YEE_SCALE_SHIFT); + /* 8; // ( *.25 ) ->[s4.8] */ + isp_parameters.yee_scale_minus_g = + (asiWk3) >> (11 - SH_CSS_YEE_SCALE_SHIFT); + isp_parameters.yee_clip_plus_s = + uDIGIT_FITTING(32760, 16, SH_CSS_BAYER_BITS); + isp_parameters.yee_clip_plus_g = 0; + isp_parameters.yee_clip_minus_s = + uDIGIT_FITTING(504, 16, SH_CSS_BAYER_BITS); + isp_parameters.yee_clip_minus_g = + uDIGIT_FITTING(32256, 16, SH_CSS_BAYER_BITS); + isp_parameters.ynryee_Yclip = SH_CSS_BAYER_MAXVAL; + isp_params_changed = true; + nr_config_changed = false; + ee_config_changed = false; +} + +static void +sh_css_process_de(void) +{ + isp_parameters.de_pixelnoise = + uDIGIT_FITTING(de_config->pixelnoise, 16, SH_CSS_BAYER_BITS); + isp_parameters.de_c1_coring_threshold = + uDIGIT_FITTING(de_config->c1_coring_threshold, 16, + SH_CSS_BAYER_BITS); + isp_parameters.de_c2_coring_threshold = + uDIGIT_FITTING(de_config->c2_coring_threshold, 16, + SH_CSS_BAYER_BITS); + isp_params_changed = true; + de_config_changed = false; +} + +static void +sh_css_process_gc(void) +{ + isp_parameters.gamma_gain_k1 = gc_config->gain_k1; + isp_parameters.gamma_gain_k2 = gc_config->gain_k2; + isp_params_changed = true; + gc_config_changed = false; +} + +static void +sh_css_process_anr(void) +{ + isp_parameters.anr_threshold = anr_config->threshold; + isp_params_changed = true; + anr_config_changed = false; +} + +void +sh_css_set_gamma_table(const struct sh_css_gamma_table *table) +{ + gamma_table = table; + gamma_table_changed = true; +} + +void +sh_css_get_gamma_table(const struct sh_css_gamma_table **table) +{ + *table = gamma_table; +} + +void +sh_css_set_ctc_table(const struct sh_css_ctc_table *table) +{ + ctc_table = table; + ctc_table_changed = true; +} + +void +sh_css_get_ctc_table(const struct sh_css_ctc_table **table) +{ + *table = ctc_table; +} + +void +sh_css_set_macc_table(const struct sh_css_macc_table *table) +{ + macc_table = table; + macc_table_changed = true; +} + +void +sh_css_get_macc_table(const struct sh_css_macc_table **table) +{ + *table = macc_table; +} + +void +sh_css_morph_table_free(struct sh_css_morph_table *me) +{ + unsigned int i; + + if (me == NULL) + return; + + for (i = 0; i < SH_CSS_MORPH_TABLE_NUM_PLANES; i++) { + if (me->coordinates_x[i]) + sh_css_free(me->coordinates_x[i]); + if (me->coordinates_y[i]) + sh_css_free(me->coordinates_y[i]); + } + sh_css_free(me); +} + +struct sh_css_morph_table * +sh_css_morph_table_allocate(unsigned int width, unsigned int height) +{ + unsigned int i; + struct sh_css_morph_table *me = sh_css_malloc(sizeof(*me)); + + if (!me) + return NULL; + + for (i = 0; i < SH_CSS_MORPH_TABLE_NUM_PLANES; i++) { + me->coordinates_x[i] = NULL; + me->coordinates_y[i] = NULL; + } + + for (i = 0; i < SH_CSS_MORPH_TABLE_NUM_PLANES; i++) { + me->coordinates_x[i] = + sh_css_malloc(height * width * + sizeof(*me->coordinates_x[i])); + me->coordinates_y[i] = + sh_css_malloc(height * width * + sizeof(*me->coordinates_y[i])); + if (!me->coordinates_x[i] || !me->coordinates_y[i]) { + sh_css_morph_table_free(me); + return NULL; + } + } + me->width = width; + me->height = height; + return me; +} + +static enum sh_css_err +sh_css_params_default_morph_table(struct sh_css_morph_table **table, + const struct sh_css_binary *binary) +{ + unsigned int i, j, k, + step = (ISP_VEC_NELEMS / 16) * 128, + width = binary->morph_tbl_width, + height = binary->morph_tbl_height; + short start_x[SH_CSS_MORPH_TABLE_NUM_PLANES] = { -8, 0, -8, 0, 0, -8 }, + start_y[SH_CSS_MORPH_TABLE_NUM_PLANES] = { 0, 0, -8, -8, -8, 0 }; + struct sh_css_morph_table *tab; + + tab = sh_css_morph_table_allocate(width, height); + if (!tab) + return sh_css_err_cannot_allocate_memory; + + for (i = 0; i < SH_CSS_MORPH_TABLE_NUM_PLANES; i++) { + short val_y = start_y[i]; + for (j = 0; j < height; j++) { + short val_x = start_x[i]; + unsigned short *x_ptr, *y_ptr; + + x_ptr = &tab->coordinates_x[i][j * width]; + y_ptr = &tab->coordinates_y[i][j * width]; + for (k = 0; k < width; + k++, x_ptr++, y_ptr++, val_x += step) { + if (k == 0) + *x_ptr = 0; + else if (k == width - 1) + *x_ptr = val_x + 2 * start_x[i]; + else + *x_ptr = val_x; + if (j == 0) + *y_ptr = 0; + else + *y_ptr = val_y; + } + val_y += step; + } + } + *table = tab; + + return sh_css_success; +} + +void +sh_css_set_morph_table(const struct sh_css_morph_table *table) +{ + morph_table = table; + morph_table_changed = true; +} + +void +sh_css_get_morph_table(const struct sh_css_morph_table **table) +{ + *table = morph_table; +} + +enum sh_css_err +sh_css_get_3a_statistics(struct sh_css_3a_output *output) +{ + if (!current_3a_binary) + return sh_css_err_internal_error; + + if (current_3a_binary->info->s3atbl_use_dmem) + get_3a_stats_from_dmem(output); + else + get_3a_stats_from_vmem(output); + return sh_css_success; +} + +void +sh_css_set_3a_config(const struct sh_css_3a_config *config) +{ + if (config) + s3a_config = config; + else + s3a_config = &disabled_3a_config; + s3a_config_changed = true; +} + +void +sh_css_get_3a_config(const struct sh_css_3a_config **config) +{ + *config = s3a_config; +} + +void +sh_css_set_wb_config(const struct sh_css_wb_config *config) +{ + if (config) + wb_config = config; + else + wb_config = &disabled_wb_config; + wb_config_changed = true; +} + +void +sh_css_get_wb_config(const struct sh_css_wb_config **config) +{ + *config = wb_config; +} + +void +sh_css_set_cc_config(const struct sh_css_cc_config *config) +{ + if (config) + cc_config = config; + else + cc_config = &disabled_cc_config; + cc_config_changed = true; +} + +void +sh_css_get_cc_config(const struct sh_css_cc_config **config) +{ + *config = cc_config; +} + +void +sh_css_set_tnr_config(const struct sh_css_tnr_config *config) +{ + if (config) + tnr_config = config; + else + tnr_config = &disabled_tnr_config; + tnr_config_changed = true; +} + +void +sh_css_get_tnr_config(const struct sh_css_tnr_config **config) +{ + *config = tnr_config; +} + +void +sh_css_set_ob_config(const struct sh_css_ob_config *config) +{ + if (config) + ob_config = config; + else + ob_config = &disabled_ob_config; + ob_config_changed = true; +} + +void +sh_css_get_ob_config(const struct sh_css_ob_config **config) +{ + *config = ob_config; +} + +void +sh_css_set_dp_config(const struct sh_css_dp_config *config) +{ + if (config) + dp_config = config; + else + dp_config = &disabled_dp_config; + dp_config_changed = true; +} + +void +sh_css_get_dp_config(const struct sh_css_dp_config **config) +{ + *config = dp_config; +} + +void +sh_css_set_nr_config(const struct sh_css_nr_config *config) +{ + if (config) + nr_config = config; + else + nr_config = &disabled_nr_config; + nr_config_changed = true; +} + +void +sh_css_get_nr_config(const struct sh_css_nr_config **config) +{ + *config = nr_config; +} + +void +sh_css_set_ee_config(const struct sh_css_ee_config *config) +{ + if (config) + ee_config = config; + else + ee_config = &disabled_ee_config; + ee_config_changed = true; +} + +void +sh_css_get_ee_config(const struct sh_css_ee_config **config) +{ + *config = ee_config; +} + +void +sh_css_set_de_config(const struct sh_css_de_config *config) +{ + if (config) + de_config = config; + else + de_config = &disabled_de_config; + de_config_changed = true; +} + +void +sh_css_get_de_config(const struct sh_css_de_config **config) +{ + *config = de_config; +} + +void +sh_css_set_gc_config(const struct sh_css_gc_config *config) +{ + if (config) + gc_config = config; + else + gc_config = &disabled_gc_config; + gc_config_changed = true; +} + +void +sh_css_get_gc_config(const struct sh_css_gc_config **config) +{ + *config = gc_config; +} + +void +sh_css_set_anr_config(const struct sh_css_anr_config *config) +{ + if (config) + anr_config = config; + else + anr_config = &default_anr_config; + anr_config_changed = true; +} + +void +sh_css_get_anr_config(const struct sh_css_anr_config **config) +{ + *config = anr_config; +} + +void +sh_css_set_anr_threshold(int threshold) +{ + struct sh_css_anr_config + **config = sh_css_malloc(sizeof(struct sh_css_anr_config *)); + sh_css_get_anr_config((const struct sh_css_anr_config **)config); + (*config)->threshold = threshold; + sh_css_set_anr_config(*config); + if (config) + sh_css_free(config); +} + +static bool +alloc(void **ptr, unsigned int bytes) +{ + void *p = hrt_isp_css_mm_alloc(bytes); + if (p == NULL) + return false; + *ptr = p; + return true; +} + +static inline bool +realloc_buf(void **curr_buf, size_t *curr_size, + size_t needed_size, enum sh_css_err *err, + bool cached) +{ + /* Possible optimization: add a function hrt_isp_css_mm_realloc() + * and implement on top of hmm. */ + if (*curr_size >= needed_size) + return false; + if (*curr_buf) + hrt_isp_css_mm_free(*curr_buf); + if (cached) + *curr_buf = hrt_isp_css_mm_alloc_cached(needed_size); + else + *curr_buf = hrt_isp_css_mm_alloc(needed_size); + if (!*curr_buf) { + *err = sh_css_err_cannot_allocate_memory; + *curr_size = 0; + } else { + *curr_size = needed_size; + } + return true; +} + +static inline bool +reallocate_buffer(void **curr_buf, size_t *curr_size, + size_t needed_size, enum sh_css_err *err) +{ + return realloc_buf(curr_buf, curr_size, needed_size, err, false); +} + +static inline bool +reallocate_cached_buffer(void **curr_buf, size_t *curr_size, + size_t needed_size, enum sh_css_err *err) +{ + return realloc_buf(curr_buf, curr_size, needed_size, err, true); +} + +static enum sh_css_err +reallocate_buffers(const struct sh_css_binary *binary) +{ + bool changed = false; + enum sh_css_err err = sh_css_success; + + if (binary->info->enable_fpnr) { + changed |= reallocate_buffer(&ddr_ptrs.fpn_tbl, &fpn_tbl_size, + FPNTBL_BYTES(binary), &err); + } + if (binary->info->enable_sc) { + changed |= reallocate_buffer(&ddr_ptrs.sc_tbl, &sc_tbl_size, + SCTBL_BYTES(binary), &err); + } + if (binary->info->enable_s3a && binary->info->s3atbl_use_dmem) { + changed |= reallocate_cached_buffer(&ddr_ptrs.s3a_tbl, + &s3a_tbl_size, + S3ATBL_BYTES(binary), &err); + } + if (binary->info->enable_s3a && !binary->info->s3atbl_use_dmem) { + changed |= reallocate_cached_buffer(&ddr_ptrs.s3a_tbl_hi, + &s3a_tbl_hi_size, + S3ATBL_HI_LO_BYTES(binary), + &err); + changed |= reallocate_cached_buffer(&ddr_ptrs.s3a_tbl_lo, + &s3a_tbl_lo_size, + S3ATBL_HI_LO_BYTES(binary), + &err); + } + if (binary->info->enable_dis) { + changed |= reallocate_buffer(&ddr_ptrs.sdis_hor_coef, + &sdis_hor_coef_size, + SDIS_HOR_COEF_TBL_BYTES(binary), + &err); + changed |= reallocate_buffer(&ddr_ptrs.sdis_ver_coef, + &sdis_ver_coef_size, + SDIS_VER_COEF_TBL_BYTES(binary), + &err); + changed |= reallocate_buffer(&ddr_ptrs.sdis_hor_proj, + &sdis_hor_proj_size, + SDIS_HOR_PROJ_TBL_BYTES(binary), + &err); + changed |= reallocate_buffer(&ddr_ptrs.sdis_ver_proj, + &sdis_ver_proj_size, + SDIS_VER_PROJ_TBL_BYTES(binary), + &err); + } + if (binary->info->mode == SH_CSS_BINARY_MODE_GDC) { + changed |= reallocate_buffer(&ddr_ptrs.tetra_r_x, + &tetra_r_x_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_r_y, + &tetra_r_y_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_gr_x, + &tetra_gr_x_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_gr_y, + &tetra_gr_y_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_gb_x, + &tetra_gb_x_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_gb_y, + &tetra_gb_y_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_b_x, + &tetra_b_x_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_b_y, + &tetra_b_y_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_ratb_x, + &tetra_ratb_x_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_ratb_y, + &tetra_ratb_y_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_batr_x, + &tetra_batr_x_size, + MORPH_PLANE_BYTES(binary), &err); + changed |= reallocate_buffer(&ddr_ptrs.tetra_batr_y, + &tetra_batr_y_size, + MORPH_PLANE_BYTES(binary), &err); + } + if (changed) + hrt_isp_css_mm_store(sp_ddr_ptrs, &ddr_ptrs, sizeof(ddr_ptrs)); + return err; +} + +enum sh_css_err +sh_css_params_init(void) +{ + bool succ = true; + + memset(&ddr_ptrs, 0, sizeof(ddr_ptrs)); + succ &= alloc(&ddr_ptrs.isp_param, sizeof(struct sh_css_isp_params)); + succ &= alloc(&ddr_ptrs.ctc_tbl, sizeof(struct sh_css_ctc_table)); + succ &= alloc(&ddr_ptrs.gamma_tbl, sizeof(struct sh_css_gamma_table)); + succ &= alloc(&ddr_ptrs.macc_tbl, sizeof(struct sh_css_macc_table)); + fpn_tbl_size = 0; + sc_tbl_size = 0; + s3a_tbl_size = 0; + s3a_tbl_hi_size = 0; + s3a_tbl_lo_size = 0; + sdis_hor_coef_size = 0; + sdis_ver_coef_size = 0; + sdis_hor_proj_size = 0; + sdis_ver_proj_size = 0; + tetra_r_x_size = 0; + tetra_r_y_size = 0; + tetra_gr_x_size = 0; + tetra_gr_y_size = 0; + tetra_gb_x_size = 0; + tetra_gb_y_size = 0; + tetra_b_x_size = 0; + tetra_b_y_size = 0; + tetra_batr_x_size = 0; + tetra_batr_y_size = 0; + tetra_ratb_x_size = 0; + tetra_ratb_y_size = 0; + + sp_ddr_ptrs = hrt_isp_css_mm_calloc(CEIL_MUL(sizeof(ddr_ptrs), + HIVE_ISP_DDR_WORD_BYTES)); + xmem_sp_group_ptrs = hrt_isp_css_mm_calloc + (sizeof(struct sh_css_sp_group)); + if (!succ || !sp_ddr_ptrs || !xmem_sp_group_ptrs) { + sh_css_uninit(); + return sh_css_err_cannot_allocate_memory; + } + /* Copy XMEM address map to XMEM for SP access */ + hrt_isp_css_mm_store(sp_ddr_ptrs, &ddr_ptrs, sizeof(ddr_ptrs)); + sh_css_set_3a_config(&default_3a_config); + sh_css_set_wb_config(&default_wb_config); + sh_css_set_cc_config(&default_cc_config); + sh_css_set_tnr_config(&default_tnr_config); + sh_css_set_ob_config(&default_ob_config); + sh_css_set_dp_config(&default_dp_config); + sh_css_set_nr_config(&default_nr_config); + sh_css_set_ee_config(&default_ee_config); + sh_css_set_de_config(&default_de_config); + sh_css_set_gc_config(&default_gc_config); + sh_css_set_macc_table(&default_macc_table); + sh_css_set_gamma_table(&default_gamma_table); + sh_css_set_ctc_table(&default_ctc_table); + sh_css_hrt_gdc_set_lut(zoom_table); + fpn_table_changed = true; + isp_parameters.fpn_enabled = 0; + morph_table = NULL; + morph_table_changed = true; + sc_table = NULL; + sc_table_changed = false; + return sh_css_success; +} + +void +sh_css_params_reconfigure_gdc_lut(void) +{ + sh_css_hrt_gdc_set_lut(zoom_table); +} + +static void +safe_free(void *ptr) +{ + if (ptr) + hrt_isp_css_mm_free(ptr); +} + +void +sh_css_params_uninit(void) +{ + safe_free(ddr_ptrs.isp_param); + safe_free(ddr_ptrs.ctc_tbl); + safe_free(ddr_ptrs.gamma_tbl); + safe_free(ddr_ptrs.macc_tbl); + safe_free(ddr_ptrs.fpn_tbl); + safe_free(ddr_ptrs.sc_tbl); + safe_free(ddr_ptrs.s3a_tbl); + safe_free(ddr_ptrs.s3a_tbl_hi); + safe_free(ddr_ptrs.s3a_tbl_lo); + safe_free(ddr_ptrs.sdis_hor_coef); + safe_free(ddr_ptrs.sdis_ver_coef); + safe_free(ddr_ptrs.sdis_hor_proj); + safe_free(ddr_ptrs.sdis_ver_proj); + safe_free(ddr_ptrs.tetra_r_x); + safe_free(ddr_ptrs.tetra_r_y); + safe_free(ddr_ptrs.tetra_gr_x); + safe_free(ddr_ptrs.tetra_gr_y); + safe_free(ddr_ptrs.tetra_gb_x); + safe_free(ddr_ptrs.tetra_gb_y); + safe_free(ddr_ptrs.tetra_b_x); + safe_free(ddr_ptrs.tetra_b_y); + safe_free(ddr_ptrs.tetra_ratb_x); + safe_free(ddr_ptrs.tetra_ratb_y); + safe_free(ddr_ptrs.tetra_batr_x); + safe_free(ddr_ptrs.tetra_batr_y); + safe_free(sp_ddr_ptrs); + safe_free(xmem_sp_group_ptrs); + if (fpn_table.data) + sh_css_free(fpn_table.data); +} + +static void write_morph_plane(unsigned short *data, + unsigned int width, + unsigned int height, + void *dest, + unsigned int aligned_width) +{ + unsigned int i, padding, w; + + /* currently we don't have morph table interpolation yet, + * so we allow a wider table to be used. This will be removed + * in the future. */ + if (width > aligned_width) { + padding = 0; + w = aligned_width; + } else { + padding = aligned_width - width; + w = width; + } + + for (i = 0; i < height; i++) { + hrt_isp_css_mm_store(dest, data, w * sizeof(short)); + dest += w * sizeof(short); + hrt_isp_css_mm_set(dest, 0, padding * sizeof(short)); + dest += padding * sizeof(short); + data += width; + } +} + +/* Store the DIS coefficients from the 3A library to DDR where the ISP + will read them from. The ISP works on a grid that can be larger than + that of the 3a library. If that is the case, we padd the difference + with zeroes. */ +static void +store_dis_coefficients(const struct sh_css_binary *binary) +{ + unsigned int hor_num_isp = binary->dis_hor_coef_num_isp, + ver_num_isp = binary->dis_ver_coef_num_isp, + hor_num_3a = binary->dis_hor_coef_num_3a, + ver_num_3a = binary->dis_ver_coef_num_3a, + hor_padding = hor_num_isp - hor_num_3a, + ver_padding = ver_num_isp - ver_num_3a, + i; + const short *hor_ptr_3a = dis_hor_coef_tbl, + *ver_ptr_3a = dis_ver_coef_tbl; + short *hor_ptr_isp = ddr_ptrs.sdis_hor_coef, + *ver_ptr_isp = ddr_ptrs.sdis_ver_coef; + + for (i = 0; i < SH_CSS_DIS_NUM_COEF_TYPES; i++) { + hrt_isp_css_mm_store(hor_ptr_isp, hor_ptr_3a, + hor_num_3a * sizeof(*hor_ptr_3a)); + hor_ptr_3a += hor_num_3a; + hor_ptr_isp += hor_num_3a; + hrt_isp_css_mm_set(hor_ptr_isp, 0, + hor_padding * sizeof(short)); + hor_ptr_isp += hor_padding; + } + for (i = 0; i < SH_CSS_DIS_VER_NUM_COEF_TYPES(binary); i++) { + hrt_isp_css_mm_store(ver_ptr_isp, ver_ptr_3a, + ver_num_3a * sizeof(*ver_ptr_3a)); + ver_ptr_3a += ver_num_3a; + ver_ptr_isp += ver_num_3a; + hrt_isp_css_mm_set(ver_ptr_isp, 0, + ver_padding * sizeof(short)); + ver_ptr_isp += ver_padding; + } + dis_coef_table_changed = false; +} + +enum sh_css_err +sh_css_params_write_to_ddr(const struct sh_css_binary *binary) +{ + enum sh_css_err err; + + err = reallocate_buffers(binary); + if (err != sh_css_success) + return err; + + if (fpn_table_changed && binary->info->enable_fpnr) { + if (isp_parameters.fpn_enabled) { + store_fpntbl(ddr_ptrs.fpn_tbl); + } else if (SH_CSS_PREVENT_UNINIT_READS) { + int *ptr = ddr_ptrs.fpn_tbl; + /* prevent warnings when reading fpn table in csim. + Actual values are not used when fpn is disabled. */ + hrt_isp_css_mm_set(ptr, 0, fpn_tbl_size); + } + fpn_table_changed = false; + } + if (sc_table_changed && binary->info->enable_sc) { + store_sctbl(binary, ddr_ptrs.sc_tbl); + sc_table_changed = false; + } + + if (s3a_config && s3a_config_changed) + sh_css_process_3a(); + if (wb_config && wb_config_changed) + sh_css_process_wb(); + if (cc_config && cc_config_changed) + sh_css_process_cc(); + if (tnr_config && tnr_config_changed) + sh_css_process_tnr(); + if (ob_config && ob_config_changed) + sh_css_process_ob(); + if (dp_config && dp_config_changed) + sh_css_process_dp(); + if (nr_config && ee_config && (nr_config_changed || ee_config_changed)) + sh_css_process_nr_ee(); + if (de_config && de_config_changed) + sh_css_process_de(); + if (gc_config && gc_config_changed) + sh_css_process_gc(); + if (anr_config && anr_config_changed) + sh_css_process_anr(); + + if (isp_params_changed) { + if (SH_CSS_PREVENT_UNINIT_READS) { + /* ispparm struct is read with DMA which reads + * multiples of the DDR word with (32 bytes): + * So we pad with zeroes to prevent warnings in csim. + */ + unsigned int aligned_width, padding_bytes; + char *pad_ptr; + + aligned_width = CEIL_MUL( + sizeof(struct sh_css_isp_params), + HIVE_ISP_DDR_WORD_BYTES); + padding_bytes = aligned_width - + sizeof(struct sh_css_isp_params); + pad_ptr = ddr_ptrs.isp_param + + sizeof(struct sh_css_isp_params); + hrt_isp_css_mm_set(pad_ptr, 0, padding_bytes); + } + hrt_isp_css_mm_store(ddr_ptrs.isp_param, + &isp_parameters, + sizeof(struct sh_css_isp_params)); + isp_params_changed = false; + } + + if (ctc_table && ctc_table_changed) { + hrt_isp_css_mm_store(ddr_ptrs.ctc_tbl, + ctc_table->data, + sizeof(ctc_table->data)); + ctc_table_changed = false; + } + if (gamma_table && gamma_table_changed) { + hrt_isp_css_mm_store(ddr_ptrs.gamma_tbl, + gamma_table->data, + sizeof(gamma_table->data)); + gamma_table_changed = false; + } + if (macc_table && macc_table_changed) { + unsigned int i; + for (i = 0; + i < SH_CSS_MACC_NUM_AXES * SH_CSS_MACC_NUM_COEFS; + i++) { + converted_macc_table.data[i] = + sDIGIT_FITTING(macc_table->data[i], 13, + SH_CSS_MACC_COEF_SHIFT); + } + hrt_isp_css_mm_store(ddr_ptrs.macc_tbl, + converted_macc_table.data, + sizeof(converted_macc_table.data)); + macc_table_changed = false; + } + + if (dis_coef_table_changed && binary->info->enable_dis) { + store_dis_coefficients(binary); + dis_coef_table_changed = false; + } + + if (binary->info->mode == SH_CSS_BINARY_MODE_GDC && + morph_table_changed) { + unsigned int i; + void *virt_addr_tetra_x[SH_CSS_MORPH_TABLE_NUM_PLANES] = { + ddr_ptrs.tetra_r_x, + ddr_ptrs.tetra_gr_x, + ddr_ptrs.tetra_gb_x, + ddr_ptrs.tetra_b_x, + ddr_ptrs.tetra_ratb_x, + ddr_ptrs.tetra_batr_x + }; + void *virt_addr_tetra_y[SH_CSS_MORPH_TABLE_NUM_PLANES] = { + ddr_ptrs.tetra_r_y, + ddr_ptrs.tetra_gr_y, + ddr_ptrs.tetra_gb_y, + ddr_ptrs.tetra_b_y, + ddr_ptrs.tetra_ratb_y, + ddr_ptrs.tetra_batr_y + }; + const struct sh_css_morph_table *table = morph_table; + struct sh_css_morph_table *id_table = NULL; + if (table && + (table->width < binary->morph_tbl_width || + table->height < binary->morph_tbl_height)) { + table = NULL; + } + if (!table) { + sh_css_params_default_morph_table(&id_table, binary); + table = id_table; + } + + for (i = 0; i < SH_CSS_MORPH_TABLE_NUM_PLANES; i++) { + write_morph_plane(table->coordinates_x[i], + table->width, + table->height, + virt_addr_tetra_x[i], + binary->morph_tbl_aligned_width); + write_morph_plane(table->coordinates_y[i], + table->width, + table->height, + virt_addr_tetra_y[i], + binary->morph_tbl_aligned_width); + } + if (id_table) + sh_css_morph_table_free(id_table); + morph_table_changed = false; + } + return sh_css_success; +} + +void +sh_css_params_set_current_binary(const struct sh_css_binary *binary) +{ + if (binary->info->enable_s3a) + current_3a_binary = binary; +} + +const struct sh_css_fpn_table * +sh_css_get_fpn_table(void) +{ + return &fpn_table; +} + +const struct sh_css_shading_table * +sh_css_get_shading_table(void) +{ + return sc_table; +} + +const struct sh_css_isp_params * +sh_css_get_isp_params(void) +{ + return &isp_parameters; +} + +const struct sh_css_binary * +sh_css_get_3a_binary(void) +{ + return current_3a_binary; +} + +void +sh_css_get_isp_dis_coefficients(short *horizontal_coefficients, + short *vertical_coefficients) +{ + unsigned int hor_num_isp, ver_num_isp, i; + short *hor_ptr = horizontal_coefficients, + *ver_ptr = vertical_coefficients, + *hor_ptr_isp = ddr_ptrs.sdis_hor_coef, + *ver_ptr_isp = ddr_ptrs.sdis_ver_coef; + + if (current_3a_binary == NULL) + return; + + hor_num_isp = current_3a_binary->dis_hor_coef_num_isp; + ver_num_isp = current_3a_binary->dis_ver_coef_num_isp; + + for (i = 0; i < SH_CSS_DIS_NUM_COEF_TYPES; i++) { + hrt_isp_css_mm_load(hor_ptr_isp, hor_ptr, + hor_num_isp * sizeof(short)); + hor_ptr_isp += hor_num_isp; + hor_ptr += hor_num_isp; + } + for (i = 0; i < SH_CSS_DIS_VER_NUM_COEF_TYPES(current_3a_binary); i++) { + hrt_isp_css_mm_load(ver_ptr_isp, ver_ptr, + ver_num_isp * sizeof(short)); + ver_ptr_isp += ver_num_isp; + ver_ptr += ver_num_isp; + } +} + +void +sh_css_get_isp_dis_projections(int *horizontal_projections, + int *vertical_projections) +{ + unsigned int hor_num_isp, ver_num_isp, i; + int *hor_ptr = horizontal_projections, + *ver_ptr = vertical_projections, + *hor_ptr_isp = ddr_ptrs.sdis_hor_proj, + *ver_ptr_isp = ddr_ptrs.sdis_ver_proj; + + if (current_3a_binary == NULL) + return; + + hor_num_isp = current_3a_binary->dis_hor_proj_num_isp; + ver_num_isp = current_3a_binary->dis_ver_proj_num_isp; + + for (i = 0; i < SH_CSS_DIS_NUM_COEF_TYPES; i++) { + hrt_isp_css_mm_load(hor_ptr_isp, hor_ptr, + hor_num_isp * sizeof(int)); + hor_ptr_isp += hor_num_isp; + hor_ptr += hor_num_isp; + + hrt_isp_css_mm_load(ver_ptr_isp, ver_ptr, + ver_num_isp * sizeof(int)); + ver_ptr_isp += ver_num_isp; + ver_ptr += ver_num_isp; + } +} + +void * +sh_css_store_sp_group_to_ddr(void) +{ + hrt_isp_css_mm_store(xmem_sp_group_ptrs, + &sh_css_sp_group, + sizeof(struct sh_css_sp_group)); + return xmem_sp_group_ptrs; +} diff --git a/drivers/media/video/atomisp/css/sh_css_params.h b/drivers/media/video/atomisp/css/sh_css_params.h new file mode 100644 index 0000000..e99441b --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_params.h @@ -0,0 +1,174 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_PARAMS_H_ +#define _SH_CSS_PARAMS_H_ + +#include "sh_css_types.h" + +int sh_css_get_gdc_coord_one(void); + +/* DIS */ +/* get the pointers to the dis coefficient tables. + * These tables will then be written by the caller and the + * values will be sent to the ISP upon the next start of frame. + */ +void +sh_css_set_dis_coefficients(const short *horizontal_coefs, + const short *vertical_coefs); + +void +sh_css_get_dis_projections(int *horizontal_projections, + int *vertical_projections); + +/* 3A */ +enum sh_css_err +sh_css_get_3a_statistics(struct sh_css_3a_output *output); + +void +sh_css_set_3a_config(const struct sh_css_3a_config *config); + +void +sh_css_get_3a_config(const struct sh_css_3a_config **config); + +/* FPN */ +enum sh_css_err +sh_css_set_black_frame(const struct sh_css_frame *raw_black_frame); + +/* Morph Table for GDC & CAC */ +void +sh_css_set_morph_table(const struct sh_css_morph_table *table); + +void +sh_css_get_morph_table(const struct sh_css_morph_table **table); + +struct sh_css_morph_table * +sh_css_morph_table_allocate(unsigned int width, unsigned int height); + +void +sh_css_morph_table_free(struct sh_css_morph_table *me); + +/* White Balance */ +void +sh_css_set_wb_config(const struct sh_css_wb_config *wb_config); + +void +sh_css_get_wb_config(const struct sh_css_wb_config **wb_config); + +/* Color Correction */ +void +sh_css_set_cc_config(const struct sh_css_cc_config *cc_config); + +void +sh_css_get_cc_config(const struct sh_css_cc_config **cc_config); + +/* TNR */ +void +sh_css_set_tnr_config(const struct sh_css_tnr_config *tnr_config); + +void +sh_css_get_tnr_config(const struct sh_css_tnr_config **tnr_config); + +/* ANR */ +void +sh_css_set_anr_threshold(int threshold); + +void +sh_css_set_anr_config(const struct sh_css_anr_config *anr_config); + +void +sh_css_get_anr_config(const struct sh_css_anr_config **anr_config); + +/* Objective Black */ +void +sh_css_set_ob_config(const struct sh_css_ob_config *ob_config); + +void +sh_css_get_ob_config(const struct sh_css_ob_config **ob_config); + +/* Dead Pixel */ +void +sh_css_set_dp_config(const struct sh_css_dp_config *dp_config); + +void +sh_css_get_dp_config(const struct sh_css_dp_config **dp_config); + +/* Noise Reduction */ +void +sh_css_set_nr_config(const struct sh_css_nr_config *nr_config); + +void +sh_css_get_nr_config(const struct sh_css_nr_config **nr_config); + +/* Edge Enhancement */ +void +sh_css_set_ee_config(const struct sh_css_ee_config *ee_config); + +void +sh_css_get_ee_config(const struct sh_css_ee_config **ee_config); + +/* Demosaic */ +void +sh_css_set_de_config(const struct sh_css_de_config *de_config); + +void +sh_css_get_de_config(const struct sh_css_de_config **de_config); + +/* Gamma Correction */ +void +sh_css_set_gc_config(const struct sh_css_gc_config *gc_config); + +void +sh_css_get_gc_config(const struct sh_css_gc_config **gc_config); + +void +sh_css_set_gamma_table(const struct sh_css_gamma_table *table); + +void +sh_css_get_gamma_table(const struct sh_css_gamma_table **table); + +void +sh_css_set_ctc_table(const struct sh_css_ctc_table *table); + +void +sh_css_get_ctc_table(const struct sh_css_ctc_table **table); + +/* Multi-Access Color Correction */ +void +sh_css_set_macc_table(const struct sh_css_macc_table *table); + +void +sh_css_get_macc_table(const struct sh_css_macc_table **table); + +/* Shading Correction */ +void +sh_css_params_set_shading_table(const struct sh_css_shading_table *table); + +void +sh_css_shading_table_free(struct sh_css_shading_table *table); + +struct sh_css_shading_table * +sh_css_shading_table_alloc(unsigned int width, + unsigned int height); + +#endif /* _SH_CSS_PARAMS_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_rx.c b/drivers/media/video/atomisp/css/sh_css_rx.c new file mode 100644 index 0000000..d70b38a --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_rx.c @@ -0,0 +1,388 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css.h" +#include "sh_css_hw.h" +#include "sh_css_rx.h" +#include "sh_css_internal.h" + +static unsigned long *css_rx_base_address = CSS_RX_BASE; + +static unsigned long +_sh_css_rx_get_register(enum sh_css_mipi_port port, unsigned int reg) +{ + unsigned int bus_addr = (unsigned int)(css_rx_base_address + reg); + if (port == SH_CSS_MIPI_PORT_1LANE) + bus_addr += hrt_css_receiver_ahb_1_lane_port_offset; + else + bus_addr += hrt_css_receiver_ahb_4_lane_port_offset; + return hrt_master_port_load_32(bus_addr); +} + +static void +_sh_css_rx_set_register(enum sh_css_mipi_port port, + unsigned int reg, + unsigned long val) +{ + unsigned int bus_addr = (unsigned int)(css_rx_base_address + reg); + if (port == SH_CSS_MIPI_PORT_1LANE) + bus_addr += hrt_css_receiver_ahb_1_lane_port_offset; + else + bus_addr += hrt_css_receiver_ahb_4_lane_port_offset; + hrt_master_port_store_32(bus_addr, val); +} + +static void +_sh_css_rx_set_bits(enum sh_css_mipi_port port, + unsigned int reg, + unsigned long bits) +{ + unsigned long val; + val = _sh_css_rx_get_register(port, reg); + val |= bits; + _sh_css_rx_set_register(port, reg, val); +} + +void +sh_css_rx_enable_all_interrupts(void) +{ + unsigned long bits; + + bits = _HRT_CSS_RECEIVER_AHB_IRQ_OVERRUN_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_SLEEP_MODE_ENTRY_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_SLEEP_MODE_EXIT_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_SOT_HS_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_SOT_SYNC_HS_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_CONTROL_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ECC_DOUBLE_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ECC_CORRECTED_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ECC_NO_CORRECTION_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_CRC_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ID_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_FRAME_SYNC_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_FRAME_DATA_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_DATA_TIMEOUT_BIT | + _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ESCAPE_BIT; + + _sh_css_rx_set_bits(SH_CSS_MIPI_PORT_1LANE, + _HRT_CSS_RECEIVER_AHB_IRQ_ENABLE_REG_IDX, + bits); +} + +unsigned int +sh_css_rx_get_interrupt_reg(void) +{ + return _sh_css_rx_get_register(SH_CSS_MIPI_PORT_1LANE, + _HRT_CSS_RECEIVER_AHB_IRQ_STATUS_REG_IDX); +} + +void +sh_css_rx_get_interrupt_info(unsigned int *irq_infos) +{ + unsigned long bits, infos = 0; + + bits = _sh_css_rx_get_register(SH_CSS_MIPI_PORT_1LANE, + _HRT_CSS_RECEIVER_AHB_IRQ_STATUS_REG_IDX); + + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_OVERRUN_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_BUFFER_OVERRUN; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_SLEEP_MODE_ENTRY_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ENTER_SLEEP_MODE; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_SLEEP_MODE_EXIT_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_EXIT_SLEEP_MODE; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ECC_CORRECTED_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ECC_CORRECTED; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_SOT_HS_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_SOT; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_SOT_SYNC_HS_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_SOT_SYNC; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_CONTROL_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_CONTROL; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ECC_DOUBLE_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_CRC_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_CRC; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ID_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_FRAME_SYNC_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_FRAME_DATA_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_FRAME_DATA; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_DATA_TIMEOUT_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ESCAPE_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC; + if (bits & (1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_LINE_SYNC_BIT)) + infos |= SH_CSS_RX_IRQ_INFO_ERR_LINE_SYNC; + + *irq_infos = infos; +} + +void +sh_css_rx_clear_interrupt_info(unsigned int irq_infos) +{ + unsigned int bits = 0; + + if (irq_infos & SH_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_OVERRUN_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ENTER_SLEEP_MODE) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_SLEEP_MODE_ENTRY_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_EXIT_SLEEP_MODE) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_SLEEP_MODE_EXIT_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ECC_CORRECTED) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ECC_CORRECTED_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_SOT) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_SOT_HS_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_SOT_SYNC) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_SOT_SYNC_HS_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_CONTROL) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_CONTROL_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ECC_DOUBLE_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_CRC) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_CRC_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ID_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_FRAME_SYNC_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_FRAME_DATA) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_FRAME_DATA_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_DATA_TIMEOUT_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_ESCAPE_BIT; + if (irq_infos & SH_CSS_RX_IRQ_INFO_ERR_LINE_SYNC) + bits |= 1 << _HRT_CSS_RECEIVER_AHB_IRQ_ERR_LINE_SYNC_BIT; + + _sh_css_rx_set_bits(SH_CSS_MIPI_PORT_1LANE, + _HRT_CSS_RECEIVER_AHB_IRQ_ENABLE_REG_IDX, + bits); +} + +enum sh_css_err +sh_css_input_format_type(enum sh_css_input_format input_format, + enum sh_css_mipi_compression compression, + unsigned int *fmt_type) +{ + if (compression != SH_CSS_MIPI_COMPRESSION_NONE) { + switch (input_format) { + case SH_CSS_INPUT_FORMAT_RAW_6: + *fmt_type = 6; + break; + case SH_CSS_INPUT_FORMAT_RAW_7: + *fmt_type = 7; + break; + case SH_CSS_INPUT_FORMAT_RAW_8: + *fmt_type = 8; + break; + case SH_CSS_INPUT_FORMAT_RAW_10: + *fmt_type = 10; + break; + case SH_CSS_INPUT_FORMAT_RAW_12: + *fmt_type = 12; + break; + case SH_CSS_INPUT_FORMAT_RAW_14: + *fmt_type = 14; + break; + case SH_CSS_INPUT_FORMAT_RAW_16: + *fmt_type = 16; + break; + default: + return sh_css_err_internal_error; + } + return sh_css_success; + } + /* This mapping comes from the Arasan CSS function spec + * (CSS_func_spec1.08_ahb_sep29_08.pdf). + */ + switch (input_format) { + case SH_CSS_INPUT_FORMAT_RGB_888: + *fmt_type = 0; + break; + case SH_CSS_INPUT_FORMAT_RGB_555: + *fmt_type = 1; + break; + case SH_CSS_INPUT_FORMAT_RGB_444: + *fmt_type = 2; + break; + case SH_CSS_INPUT_FORMAT_RGB_565: + *fmt_type = 3; + break; + case SH_CSS_INPUT_FORMAT_RGB_666: + *fmt_type = 4; + break; + case SH_CSS_INPUT_FORMAT_RAW_8: + *fmt_type = 5; + break; + case SH_CSS_INPUT_FORMAT_RAW_10: + *fmt_type = 6; + break; + case SH_CSS_INPUT_FORMAT_RAW_6: + *fmt_type = 7; + break; + case SH_CSS_INPUT_FORMAT_RAW_7: + *fmt_type = 8; + break; + case SH_CSS_INPUT_FORMAT_RAW_12: + *fmt_type = 9; + break; + case SH_CSS_INPUT_FORMAT_RAW_14: + *fmt_type = 10; + break; + case SH_CSS_INPUT_FORMAT_YUV420_8: + *fmt_type = 11; + break; + case SH_CSS_INPUT_FORMAT_YUV420_10: + *fmt_type = 12; + break; + case SH_CSS_INPUT_FORMAT_YUV422_8: + *fmt_type = 13; + break; + case SH_CSS_INPUT_FORMAT_YUV422_10: + *fmt_type = 14; + break; + case SH_CSS_INPUT_FORMAT_BINARY_8: + *fmt_type = 15; + break; + case SH_CSS_INPUT_FORMAT_YUV420_8_LEGACY: + *fmt_type = 16; + break; + case SH_CSS_INPUT_FORMAT_RAW_16: + /* This is not specified by Arasan, so we use + * 17 for now. + */ + *fmt_type = 17; + break; + default: + return sh_css_err_internal_error; + } + return sh_css_success; +} + +static void +sh_css_rx_set_bits(enum sh_css_mipi_port port, unsigned int reg, + unsigned int lsb, unsigned int bits, unsigned int val) +{ + /* prevent writing out of range */ + val &= (1U << bits)-1; + /* shift into place */ + val <<= lsb; + _sh_css_rx_set_bits(port, reg, val); +} + +static void +sh_css_rx_set_num_lanes(enum sh_css_mipi_port port, unsigned int lanes) +{ + sh_css_rx_set_bits(port, + _HRT_CSS_RECEIVER_AHB_CSI2_FUNC_PROG_REG_IDX, + _HRT_CSS_RECEIVER_AHB_CSI2_NUM_DATA_LANES_IDX, + _HRT_CSS_RECEIVER_AHB_CSI2_NUM_DATA_LANES_BITS, + lanes); +} + +static void +sh_css_rx_port_enable(enum sh_css_mipi_port port, bool enable) +{ + _sh_css_rx_set_register(port, + _HRT_CSS_RECEIVER_AHB_DEVICE_READY_REG_IDX, + enable); +} + +static void +sh_css_rx_set_timeout(enum sh_css_mipi_port port, unsigned int timeout) +{ + sh_css_rx_set_bits(port, + _HRT_CSS_RECEIVER_AHB_CSI2_FUNC_PROG_REG_IDX, + _HRT_CSS_RECEIVER_AHB_CSI2_DATA_TIMEOUT_IDX, + _HRT_CSS_RECEIVER_AHB_CSI2_DATA_TIMEOUT_BITS, + timeout); +} + +static void +sh_css_rx_set_compression(enum sh_css_mipi_port port, + enum sh_css_mipi_compression comp) +{ + unsigned int reg = _HRT_CSS_RECEIVER_AHB_COMP_PREDICT_REG_IDX, + comp_val = _HRT_CSS_RECEIVER_AHB_PREDICT_NO_COMP; + + if (comp == SH_CSS_MIPI_COMPRESSION_1) + comp_val = _HRT_CSS_RECEIVER_AHB_PREDICT_1; + if (comp == SH_CSS_MIPI_COMPRESSION_2) + comp_val = _HRT_CSS_RECEIVER_AHB_PREDICT_2; + + _sh_css_rx_set_register(port, reg, comp_val); +} + +static void +sh_css_rx_set_uncomp_size(enum sh_css_mipi_port port, unsigned int size) +{ + sh_css_rx_set_bits(port, + _HRT_CSS_RECEIVER_AHB_COMP_FORMAT_REG_IDX, + _HRT_CSS_RECEIVER_AHB_COMP_NUM_BITS_IDX, + _HRT_CSS_RECEIVER_AHB_COMP_NUM_BITS_BITS, + size); +} + +static void +sh_css_rx_set_comp_size(enum sh_css_mipi_port port, unsigned int size) +{ + sh_css_rx_set_bits(port, + _HRT_CSS_RECEIVER_AHB_COMP_FORMAT_REG_IDX, + _HRT_CSS_RECEIVER_AHB_COMP_RAW_BITS_IDX, + _HRT_CSS_RECEIVER_AHB_COMP_RAW_BITS_BITS, + size); +} + +static void +sh_css_rx_set_two_ppc(enum sh_css_mipi_port port, bool enable) +{ + _sh_css_rx_set_register(port, + _HRT_CSS_RECEIVER_AHB_TWO_PIXEL_EN_REG_IDX, + enable); +} + +void +sh_css_rx_configure(const struct sh_css_mipi_config *config) +{ + /* turn off both ports just in case */ + sh_css_rx_disable(); + + /* configure the selected port */ + sh_css_rx_set_num_lanes(config->port, config->num_lanes); + sh_css_rx_set_timeout(config->port, config->timeout); + sh_css_rx_set_compression(config->port, config->comp); + sh_css_rx_set_uncomp_size(config->port, config->uncomp_bpp); + sh_css_rx_set_comp_size(config->port, config->comp_bpp); + sh_css_rx_set_two_ppc(config->port, config->two_ppc); + + /* enable the selected port */ + sh_css_rx_port_enable(config->port, true); +} + +void +sh_css_rx_disable(void) +{ + sh_css_rx_port_enable(SH_CSS_MIPI_PORT_1LANE, false); + sh_css_rx_port_enable(SH_CSS_MIPI_PORT_4LANE, false); +} + diff --git a/drivers/media/video/atomisp/css/sh_css_rx.h b/drivers/media/video/atomisp/css/sh_css_rx.h new file mode 100644 index 0000000..67a38d5 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_rx.h @@ -0,0 +1,53 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_RX_H_ +#define _SH_CSS_RX_H_ + +#include "sh_css_types.h" + +/* CSS Receiver */ + +struct sh_css_mipi_config { + enum sh_css_mipi_port port; + unsigned int num_lanes; + unsigned int timeout; + unsigned int comp_bpp; + unsigned int uncomp_bpp; + enum sh_css_mipi_compression comp; + bool two_ppc; +}; + +void +sh_css_rx_configure(const struct sh_css_mipi_config *config); + +void +sh_css_rx_disable(void); + +void +sh_css_rx_enable_all_interrupts(void); + +unsigned int +sh_css_rx_get_interrupt_reg(void); + +#endif /* _SH_CSS_RX_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_sp.c b/drivers/media/video/atomisp/css/sh_css_sp.c new file mode 100644 index 0000000..409e570 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_sp.c @@ -0,0 +1,584 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css.h" +#include "sh_css_binary.h" +#include "sh_css_sp.h" +#include "sh_css_sp_start.h" +#include "sh_css_hrt.h" +#include "sh_css_defs.h" +#include "sh_css_internal.h" +#define HRT_NO_BLOB_sp +#include "sp.map.h" + +/* Convenience macro to force a value to a lower even value. + * We do not want to (re)use the kernel macro round_down here + * because the same code base is used internally by Silicon Hive + * simulation environment, where the kernel macro is not available + */ +#define EVEN_FLOOR(x) (x & ~1) + +struct sh_css_sp_group sh_css_sp_group; + +void +sh_css_store_sp_group_pointer_to_sp(void) +{ + void *sp_group_on_ddr = sh_css_store_sp_group_to_ddr(); + + store_sp_ptr(sp_sp_group_addr, sp_group_on_ddr); + /* set flag (should read sp group from DDR) */ + store_sp_int(sp_read_sp_group_from_ddr, 1); +} + +/* Initialize the entire contents of the DMEM at once -- does not need to + * do this from the host + */ +void +sh_css_sp_start_init_dmem(struct sh_css_sp_init_dmem_cfg *init_dmem_cfg) +{ + store_sp_ptr(sp_ddr_data_addr , init_dmem_cfg->ddr_data_addr); + store_sp_ptr(sp_dmem_data_addr, init_dmem_cfg->dmem_data_addr); + store_sp_int(sp_data_size , init_dmem_cfg->data_size); + store_sp_ptr(sp_dmem_bss_addr , init_dmem_cfg->dmem_bss_addr); + store_sp_int(sp_bss_size , init_dmem_cfg->bss_size); + + sh_css_hrt_sp_start_init_dmem(); + sh_css_hrt_sp_wait(); +} + +void +sh_css_sp_start_histogram(struct sh_css_histogram *histogram, + const struct sh_css_frame *frame) +{ + store_sp_ptr(sp_histo_addr, histogram->data); + sh_css_sp_group.sp_in_frame = *frame; + sh_css_store_sp_group_pointer_to_sp(); + sh_css_hrt_sp_start_histogram(); +} + +void +sh_css_sp_get_debug_state(struct sh_css_sp_debug_state *state) +{ + int i; + + state->error = load_sp_uint(sp_error); + + for (i = 0; i < 16; i++) + state->debug[i] = load_sp_array_uint(sp_debug, i); +} + +void +sh_css_sp_start_binary_copy(struct sh_css_frame *out_frame, + unsigned two_ppc) +{ + store_sp_ptr(sp_bin_copy_out, out_frame->planes.binary.data.data); + store_sp_int(sp_bin_copy_bytes_available, out_frame->data_bytes); + sh_css_sp_group.isp_2ppc = two_ppc; + sh_css_store_sp_group_pointer_to_sp(); + sh_css_hrt_sp_start_copy_binary_data(); +} + +void +sh_css_sp_start_raw_copy(struct sh_css_binary *binary, + struct sh_css_frame *out_frame, + unsigned two_ppc, + bool start) +{ + store_sp_ptr(sp_raw_copy_out, out_frame->planes.raw.data); + store_sp_ptr(sp_raw_copy_height, out_frame->info.height); + store_sp_ptr(sp_raw_copy_width, out_frame->info.width); + store_sp_ptr(sp_raw_copy_padded_width, out_frame->info.padded_width); + store_sp_ptr(sp_raw_copy_raw_bit_depth, out_frame->info.raw_bit_depth); + store_sp_ptr(sp_raw_copy_max_input_width, + binary->info->max_input_width); + store_sp_ptr(sp_proxy_busy_wait, true); + sh_css_sp_group.isp_2ppc = two_ppc; + sh_css_sp_group.xmem_bin_addr = binary->info->xmem_addr; + sh_css_store_sp_group_pointer_to_sp(); + if (start) + sh_css_hrt_sp_start_copy_raw_data(); +} + +unsigned int +sh_css_sp_get_binary_copy_size(void) +{ + return load_sp_uint(sp_bin_copy_bytes_copied); +} + +unsigned int +sh_css_sp_get_sw_interrupt_value(void) +{ + return load_sp_uint(sp_sw_interrupt_value); +} + +static enum sh_css_err +set_input_frame_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + switch (frame->info.format) { + case SH_CSS_FRAME_FORMAT_QPLANE6: + case SH_CSS_FRAME_FORMAT_YUV420_16: + case SH_CSS_FRAME_FORMAT_RAW: + case SH_CSS_FRAME_FORMAT_YUV420: + case SH_CSS_FRAME_FORMAT_YUV_LINE: + break; + default: + return sh_css_err_unsupported_frame_format; + } + sh_css_sp_group.sp_in_frame = *frame; + return sh_css_success; +} + +static enum sh_css_err +set_output_frame_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + switch (frame->info.format) { + case SH_CSS_FRAME_FORMAT_YUV420: + case SH_CSS_FRAME_FORMAT_YUV422: + case SH_CSS_FRAME_FORMAT_YUV444: + case SH_CSS_FRAME_FORMAT_YV12: + case SH_CSS_FRAME_FORMAT_YV16: + case SH_CSS_FRAME_FORMAT_YUV420_16: + case SH_CSS_FRAME_FORMAT_YUV422_16: + case SH_CSS_FRAME_FORMAT_NV11: + case SH_CSS_FRAME_FORMAT_NV12: + case SH_CSS_FRAME_FORMAT_NV16: + case SH_CSS_FRAME_FORMAT_NV21: + case SH_CSS_FRAME_FORMAT_NV61: + case SH_CSS_FRAME_FORMAT_YUYV: + case SH_CSS_FRAME_FORMAT_UYVY: + case SH_CSS_FRAME_FORMAT_YUV_LINE: + case SH_CSS_FRAME_FORMAT_RGB565: + case SH_CSS_FRAME_FORMAT_RGBA888: + case SH_CSS_FRAME_FORMAT_PLANAR_RGB888: + case SH_CSS_FRAME_FORMAT_RAW: + case SH_CSS_FRAME_FORMAT_QPLANE6: + break; + default: + return sh_css_err_unsupported_frame_format; + } + sh_css_sp_group.sp_out_frame = *frame; + return sh_css_success; +} + +static enum sh_css_err +set_ref_in_frame_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + if (frame->info.format != SH_CSS_FRAME_FORMAT_YUV420) + return sh_css_err_unsupported_frame_format; + sh_css_sp_group.sp_ref_in_frame = *frame; + return sh_css_success; +} + +static enum sh_css_err +set_ref_out_frame_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + if (frame->info.format != SH_CSS_FRAME_FORMAT_YUV420) + return sh_css_err_unsupported_frame_format; + sh_css_sp_group.sp_ref_out_frame = *frame; + return sh_css_success; +} + +static enum sh_css_err +set_tnr_in_frame_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + if (frame->info.format != SH_CSS_FRAME_FORMAT_YUV420) + return sh_css_err_unsupported_frame_format; + sh_css_sp_group.sp_tnr_in_frame = *frame; + return sh_css_success; +} + +static enum sh_css_err +set_tnr_out_frame_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + if (frame->info.format != SH_CSS_FRAME_FORMAT_YUV420) + return sh_css_err_unsupported_frame_format; + sh_css_sp_group.sp_tnr_out_frame = *frame; + return sh_css_success; +} + +static enum sh_css_err +set_capture_pp_frame_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + switch (frame->info.format != SH_CSS_FRAME_FORMAT_YUV420) + return sh_css_err_unsupported_frame_format; + sh_css_sp_group.sp_extra_frame = *frame; + return sh_css_success; +} + +static enum sh_css_err +set_view_finder_buffer(const struct sh_css_frame *frame) +{ + if (frame == NULL) + return sh_css_err_invalid_arguments; + + if (frame->info.format != SH_CSS_FRAME_FORMAT_YUV_LINE) + return sh_css_err_unsupported_frame_format; + sh_css_sp_group.sp_out_vf_frame = *frame; + return sh_css_success; +} + +static void +sh_css_sp_configure_cropping(const struct sh_css_binary *binary) +{ + sh_css_sp_group.sp_uds_xc = binary->in_frame_info.width / 2; + sh_css_sp_group.sp_uds_yc = binary->in_frame_info.height / 2; + sh_css_sp_group.sp_out_crop_pos_x = binary->info->left_cropping; + sh_css_sp_group.sp_out_crop_pos_y = binary->info->top_cropping; +} + +static void +sh_css_sp_configure_dvs(const struct sh_css_binary *binary, + const struct sh_css_binary_args *args) +{ + unsigned int crop_x = 0, + crop_y = 0, + uds_xc = 0, + uds_yc = 0, + env_width, env_height; + int half_env_x, half_env_y, + motion_x = args->dvs_vector_x, + motion_y = args->dvs_vector_y; + + if (binary->info->enable_uds) { + /* we calculate with the envelope that we can actually use, + the min dvs envelope is for the filter initialization. */ + env_width = binary->dvs_envelope_width - + SH_CSS_MIN_DVS_ENVELOPE; + env_height = binary->dvs_envelope_height - + SH_CSS_MIN_DVS_ENVELOPE; + half_env_x = env_width / 2; + half_env_y = env_height / 2; + /* for digital zoom, we use the dvs envelope and make sure + that we don't include the 8 leftmost pixels or 8 topmost + rows. */ + uds_xc = (binary->out_frame_info.width + env_width) / 2 + + SH_CSS_MIN_DVS_ENVELOPE; + uds_yc = (binary->out_frame_info.height + env_height) / 2 + + SH_CSS_MIN_DVS_ENVELOPE; + /* clip the motion vector to +/- half the envelope */ + motion_x = clamp(motion_x, -half_env_x, half_env_x); + motion_y = clamp(motion_y, -half_env_y, half_env_y); + uds_xc += motion_x; + uds_yc += motion_y; + } else if (binary->info->enable_ds) { + env_width = binary->dvs_envelope_width; + env_height = binary->dvs_envelope_height; + half_env_x = env_width / 2; + half_env_y = env_height / 2; + /* clip the motion vector to +/- half the envelope */ + motion_x = clamp(motion_x, -half_env_x, half_env_x); + motion_y = clamp(motion_y, -half_env_y, half_env_y); + /* for video with downscaling, the envelope is included in + the input resolution. */ + uds_xc = binary->in_frame_info.width/2 + motion_x; + uds_yc = binary->in_frame_info.height/2 + motion_y; + crop_x = binary->info->left_cropping; + crop_y = binary->info->top_cropping; + } else { + /* video nodz: here we can only crop. We make sure we crop at + least the first 8x8 pixels away. */ + env_width = binary->dvs_envelope_width - + SH_CSS_MIN_DVS_ENVELOPE; + env_height = binary->dvs_envelope_height - + SH_CSS_MIN_DVS_ENVELOPE; + half_env_x = env_width / 2; + half_env_y = env_height / 2; + motion_x = clamp(motion_x, -half_env_x, half_env_x); + motion_y = clamp(motion_y, -half_env_y, half_env_y); + crop_x = SH_CSS_MIN_DVS_ENVELOPE + half_env_x + motion_x; + crop_y = SH_CSS_MIN_DVS_ENVELOPE + half_env_y + motion_y; + } + + /* Must enforce that the crop position is even */ + crop_x = EVEN_FLOOR(crop_x); + crop_y = EVEN_FLOOR(crop_y); + uds_xc = EVEN_FLOOR(uds_xc); + uds_yc = EVEN_FLOOR(uds_yc); + + sh_css_sp_group.sp_uds_xc = uds_xc; + sh_css_sp_group.sp_uds_yc = uds_yc; + sh_css_sp_group.sp_out_crop_pos_x = crop_x; + sh_css_sp_group.sp_out_crop_pos_y = crop_y; +} + +static void +sh_css_sp_set_vf_zoom_position(const struct sh_css_binary *binary, bool zoom) +{ + /* for down scaling, we always use the center of the image */ + unsigned uds_xc = 0; + unsigned uds_yc = 0; + if (zoom) { + uds_xc = (binary->in_frame_info.width) / 2; + uds_yc = (binary->in_frame_info.height) / 2; + } + sh_css_sp_group.sp_uds_xc = uds_xc; + sh_css_sp_group.sp_uds_yc = uds_yc; + sh_css_sp_group.sp_out_crop_pos_x = binary->info->left_cropping; + sh_css_sp_group.sp_out_crop_pos_y = binary->info->top_cropping; +} + +void +sh_css_sp_set_if_configs(const struct sh_css_if_config *config_a, + const struct sh_css_if_config *config_b) +{ + bool block_a = config_a->block_no_reqs, + block_b = false; + if (config_b) + block_b = config_b->block_no_reqs; + sh_css_hrt_if_reset(); + sh_css_hrt_if_set_block_fifo_no_reqs(block_a, block_b); + store_sp_int(sp_if_a_changed, 1); + store_sp_var(sp_if_a, (void *)config_a, sizeof(*config_a)); + + if (config_b) { + store_sp_int(sp_if_b_changed, 1); + store_sp_var(sp_if_b, (void *)config_b, sizeof(*config_b)); + } +} + +void +sh_css_sp_program_input_circuit(int fmt_type, + int ch_id, + enum sh_css_input_mode input_mode) +{ + store_sp_int(sp_no_side_band, 0); + store_sp_int(sp_fmt_type, fmt_type); + store_sp_int(sp_ch_id, ch_id); + store_sp_int(sp_input_mode, input_mode); + store_sp_int(sp_program_input_circuit, 1); +} + +void +sh_css_sp_configure_sync_gen(int width, int height, + int hblank_cycles, + int vblank_cycles) +{ + store_sp_int(sp_sync_gen_width, width); + store_sp_int(sp_sync_gen_height, height); + store_sp_int(sp_sync_gen_hblank_cycles, hblank_cycles); + store_sp_int(sp_sync_gen_vblank_cycles, vblank_cycles); +} + +void +sh_css_sp_configure_tpg(int x_mask, + int y_mask, + int x_delta, + int y_delta, + int xy_mask) +{ + store_sp_int(sp_tpg_x_mask, x_mask); + store_sp_int(sp_tpg_y_mask, y_mask); + store_sp_int(sp_tpg_x_delta, x_delta); + store_sp_int(sp_tpg_y_delta, y_delta); + store_sp_int(sp_tpg_xy_mask, xy_mask); +} + +void +sh_css_sp_configure_prbs(int seed) +{ + store_sp_int(sp_prbs_seed, seed); +} + +static enum sh_css_err +sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) +{ + enum sh_css_err err = sh_css_success; + if (args->in_frame) + err = set_input_frame_buffer(args->in_frame); + if (err == sh_css_success && args->in_ref_frame) + err = set_ref_in_frame_buffer(args->in_ref_frame); + if (err == sh_css_success && args->in_tnr_frame) + err = set_tnr_in_frame_buffer(args->in_tnr_frame); + if (err == sh_css_success && args->out_vf_frame) + err = set_view_finder_buffer(args->out_vf_frame); + if (err == sh_css_success && args->extra_frame) + err = set_capture_pp_frame_buffer(args->extra_frame); + if (err == sh_css_success && args->out_ref_frame) + err = set_ref_out_frame_buffer(args->out_ref_frame); + if (err == sh_css_success && args->out_tnr_frame) + err = set_tnr_out_frame_buffer(args->out_tnr_frame); + if (err == sh_css_success && args->out_frame) + err = set_output_frame_buffer(args->out_frame); + return err; +} + +static void +sh_css_sp_compute_overlay(const struct sh_css_overlay *overlay, + struct sh_css_sp_overlay *sp_overlay) +{ + if (overlay == NULL) { + sp_overlay->overlay_width = 0; + sp_overlay->overlay_height = 0; + } else { + int blend_shift, + ratio100, + blend_input_y, + blend_input_u, + blend_input_v, + blend_overlay_y, blend_overlay_u, blend_overlay_v; + + blend_shift = 12; + ratio100 = 1 << blend_shift; + blend_input_y = + (ratio100 * overlay->blend_input_perc_y + 50) / 100; + blend_input_u = + (ratio100 * overlay->blend_input_perc_u + 50) / 100; + blend_input_v = + (ratio100 * overlay->blend_input_perc_v + 50) / 100; + blend_overlay_y = + (ratio100 * overlay->blend_overlay_perc_y + 50) / 100; + blend_overlay_u = + (ratio100 * overlay->blend_overlay_perc_u + 50) / 100; + blend_overlay_v = + (ratio100 * overlay->blend_overlay_perc_v + 50) / 100; + sp_overlay->bg_y = (int) overlay->bg_y; + sp_overlay->bg_u = (int) overlay->bg_u; + sp_overlay->bg_v = (int) overlay->bg_v; + sp_overlay->blend_shift = blend_shift; + sp_overlay->blend_input_y = blend_input_y; + sp_overlay->blend_input_u = blend_input_u; + sp_overlay->blend_input_v = blend_input_v; + sp_overlay->blend_overlay_y = blend_overlay_y; + sp_overlay->blend_overlay_u = blend_overlay_u; + sp_overlay->blend_overlay_v = blend_overlay_v; + sp_overlay->overlay_width = + (int) overlay->frame->info.width; + sp_overlay->overlay_height = + (int) overlay->frame->info.height; + sp_overlay->overlay_start_x = + (int) overlay->overlay_start_x; + sp_overlay->overlay_start_y = + (int) overlay->overlay_start_y; + sp_overlay->frame_ptr_overlay_y = + overlay->frame->planes.yuv.y.data; + sp_overlay->frame_ptr_overlay_u = + overlay->frame->planes.yuv.u.data; + sp_overlay->frame_ptr_overlay_v = + overlay->frame->planes.yuv.v.data; + } +} + +void +sh_css_sp_set_overlay(const struct sh_css_overlay *overlay) +{ + struct sh_css_sp_overlay sp_overlay; + sh_css_sp_compute_overlay(overlay, &sp_overlay); + store_sp_var(sp_si, &sp_overlay, sizeof(sp_overlay)); +} + +enum sh_css_err +sh_css_sp_start_isp(struct sh_css_binary *binary, + const struct sh_css_binary_args *args, + bool preview_mode) +{ + unsigned int dx, dy; + enum sh_css_err err = sh_css_success; + bool start_copy = sh_css_continuous_start_sp_copy(); + + if (binary->info->mode == SH_CSS_BINARY_MODE_VF_PP) { + bool zoom = false; + if (preview_mode) { + sh_css_get_zoom_factor(&dx, &dy); + zoom = dx != 64 || dy != 64; + } else { + /* in non-preview modes, VF_PP does not do + the zooming, capture_pp or video do. */ + dx = 64; + dy = 64; + } + sh_css_sp_set_vf_zoom_position(binary, zoom); + } else { + sh_css_get_zoom_factor(&dx, &dy); + } + + /* Copy the frame infos first, to be overwritten by the frames, + if these are present. + */ + sh_css_sp_group.sp_in_frame.info = binary->in_frame_info; + sh_css_sp_group.sp_out_frame.info = binary->out_frame_info; + sh_css_sp_group.sp_internal_frame_info = binary->internal_frame_info; + + sh_css_sp_group.sp_isp_binary_id = binary->info->id; + sh_css_sp_group.sp_enable_xnr = args->enable_xnr; + sh_css_sp_group.sp_uds_curr_dx = dx; + sh_css_sp_group.sp_uds_curr_dy = dy; + sh_css_sp_group.sp_input_stream_format = binary->input_format; + sh_css_sp_group.isp_dvs_envelope_width = binary->dvs_envelope_width; + sh_css_sp_group.isp_dvs_envelope_height = binary->dvs_envelope_height; + sh_css_sp_group.isp_deci_log_factor = binary->deci_factor_log2; + sh_css_sp_group.isp_vf_downscale_bits = binary->vf_downscale_log2; + sh_css_sp_group.isp_online = binary->online; + sh_css_sp_group.isp_copy_vf = args->copy_vf; + sh_css_sp_group.isp_copy_output = args->copy_output; + sh_css_sp_group.isp_2ppc = args->two_ppc; + sh_css_sp_group.sp_run_copy = start_copy; + sh_css_sp_group.xmem_bin_addr = binary->info->xmem_addr; + sh_css_sp_group.xmem_map_addr = + sh_css_params_ddr_address_map(); + + store_sp_int(sp_isp_started, 0); + + if (binary->info->enable_dvs_envelope) + sh_css_sp_configure_dvs(binary, args); + else if (binary->info->mode != SH_CSS_BINARY_MODE_VF_PP) + sh_css_sp_configure_cropping(binary); + sh_css_params_set_current_binary(binary); + err = sh_css_params_write_to_ddr(binary); + if (err != sh_css_success) + return err; + err = sh_css_sp_write_frame_pointers(args); + if (err != sh_css_success) + return err; + + sh_css_store_sp_group_pointer_to_sp(); + + sh_css_hrt_sp_start_isp(); + return err; +} + +bool +sh_css_isp_has_started(void) +{ + return load_sp_uint(sp_isp_started); +} diff --git a/drivers/media/video/atomisp/css/sh_css_sp.h b/drivers/media/video/atomisp/css/sh_css_sp.h new file mode 100644 index 0000000..7acd6d1 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_sp.h @@ -0,0 +1,127 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_SP_H_ +#define _SH_CSS_SP_H_ + +#include "sh_css_binary.h" + +struct sh_css_sp_debug_state { + unsigned int error; + unsigned int debug[16]; +}; + +struct sh_css_if_config { + unsigned int start_line; + unsigned int start_column; + unsigned int left_padding; + unsigned int cropped_height; + unsigned int cropped_width; + unsigned int deinterleaving; + unsigned int buf_vecs; + unsigned int buf_start_index; + unsigned int buf_increment; + unsigned int buf_eol_offset; + unsigned int yuv420; + unsigned int block_no_reqs; +}; + +/* Structure to encapsulate required arguments for + * initialization of SP DMEM using the SP itself + */ +struct sh_css_sp_init_dmem_cfg { + void *ddr_data_addr; /* data segment address in ddr */ + void *dmem_data_addr; /* data segment address in dmem */ + unsigned int data_size; /* data segment size */ + void *dmem_bss_addr; /* bss segment address in dmem */ + unsigned int bss_size; /* bss segment size */ +}; + +/* Function to initialize the bss section of the binary */ +void +sh_css_sp_start_init_dmem(struct sh_css_sp_init_dmem_cfg *init_dmem_cfg); + +void +sh_css_sp_start_histogram(struct sh_css_histogram *histogram, + const struct sh_css_frame *frame); + +/* Start binary (jpeg) copy on the SP */ +void +sh_css_sp_start_binary_copy(struct sh_css_frame *out_frame, + unsigned two_ppc); + +/* Start raw copy on the SP */ +void +sh_css_sp_start_raw_copy(struct sh_css_binary *binary, + struct sh_css_frame *out_frame, + unsigned two_ppc, + bool start); + +unsigned int +sh_css_sp_get_binary_copy_size(void); + +/* Return the value of a SW interrupt */ +unsigned int +sh_css_sp_get_sw_interrupt_value(void); + +enum sh_css_err +sh_css_sp_start_isp(struct sh_css_binary *binary, + const struct sh_css_binary_args *args, + bool preview_mode); + +void +sh_css_sp_get_debug_state(struct sh_css_sp_debug_state *state); + +void +sh_css_sp_set_overlay(const struct sh_css_overlay *overlay); + +void +sh_css_sp_set_if_configs(const struct sh_css_if_config *config_a, + const struct sh_css_if_config *config_b); + +void +sh_css_sp_program_input_circuit(int fmt_type, + int ch_id, + enum sh_css_input_mode input_mode); + +void +sh_css_sp_configure_sync_gen(int width, + int height, + int hblank_cycles, + int vblank_cycles); + +void +sh_css_sp_configure_tpg(int x_mask, + int y_mask, + int x_delta, + int y_delta, + int xy_mask); + +void +sh_css_sp_configure_prbs(int seed); + +void +sh_css_store_sp_group_pointer_to_sp(void); + +extern struct sh_css_sp_group sh_css_sp_group; +#endif /* _SH_CSS_SP_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_sp_start.c b/drivers/media/video/atomisp/css/sh_css_sp_start.c new file mode 100644 index 0000000..1ec6624 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_sp_start.c @@ -0,0 +1,129 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#include "sh_css_sp_start.h" +#include "sh_css_sp.h" +#include "sh_css_hw.h" +#include "sh_css_hrt.h" +#include "sp.map.h" +#include "sh_css_firmware.h" + +static unsigned char *sp_dmem_base_address = SP_DMEM_BASE; +static bool invalidate_mmu; + +void +sh_css_sp_invalidate_mmu(void) +{ + invalidate_mmu = true; +} + +void +sh_css_sp_start(unsigned int start_address) +{ + if (invalidate_mmu) { + sh_css_hrt_mmu_invalidate_cache(); + invalidate_mmu = false; + } + /* set the start address */ + sh_css_sp_ctrl_store(SP_START_ADDR_REG, start_address); + /* set the run bit and the start bit with a read-modify-write */ + sh_css_sp_ctrl_set_bits(SP_SC_REG, + 1UL<text_size); + hrt_isp_css_mm_store(code_addr, fw->text, fw->text_size); + + /* Set the correct start address for the SP program */ + sh_css_sp_activate_program(fw, code_addr, sp_prog); + + return code_addr; +} + + void +sh_css_sp_activate_program(const struct sh_css_sp_fw *fw, + void *code_addr, + const char *sp_prog) +{ + struct sh_css_sp_init_dmem_cfg init_dmem_cfg; + void *data_addr; + (void)sp_prog; /* not used on hardware, only for simulation */ + + /* now we program the base address into the icache and + * invalidate the cache. + */ + sh_css_sp_ctrl_store(SP_ICACHE_ADDR_REG, (unsigned long)code_addr); + sh_css_sp_ctrl_set_bits(SP_ICACHE_INV_REG, 1UL<data_size); + hrt_isp_css_mm_store(data_addr, fw->data, fw->data_size); + + /* Configure the data structure to initialize dmem */ + init_dmem_cfg.ddr_data_addr = data_addr; + init_dmem_cfg.dmem_data_addr = (void *) fw->data_target; + init_dmem_cfg.data_size = fw->data_size; + init_dmem_cfg.dmem_bss_addr = (void *) fw->bss_target; + init_dmem_cfg.bss_size = fw->bss_size; + + /* Start function on the SP to initialize the SP DMEM */ + sh_css_sp_start_init_dmem(&init_dmem_cfg); + + hrt_isp_css_mm_free(data_addr); +} + + +unsigned int +sh_css_sp_dmem_load_32(unsigned int address) +{ + unsigned long addr = (unsigned long)(sp_dmem_base_address + address); + return hrt_master_port_uload_32(addr); +} + +void +sh_css_sp_dmem_store_32(unsigned int address, unsigned int value) +{ + unsigned long addr = (unsigned long)(sp_dmem_base_address + address); + hrt_master_port_store_32(addr, value); +} + +void +sh_css_sp_dmem_load(unsigned int address, void *data, unsigned int bytes) +{ + unsigned long addr = (unsigned long)(sp_dmem_base_address + address); + hrt_master_port_load(addr, data, bytes); +} + +void +sh_css_sp_dmem_store(unsigned int address, const void *data, unsigned int bytes) +{ + unsigned long addr = (unsigned long)(sp_dmem_base_address + address); + hrt_master_port_store(addr, data, bytes); +} diff --git a/drivers/media/video/atomisp/css/sh_css_sp_start.h b/drivers/media/video/atomisp/css/sh_css_sp_start.h new file mode 100644 index 0000000..0b79963 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_sp_start.h @@ -0,0 +1,87 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_SP_START_H_ +#define _SH_CSS_SP_START_H_ + +#include "sh_css_firmware.h" + +#define sh_css_sp_start_function(func) \ + sh_css_sp_start(HIVE_ADDR_ ## func ## _entry) + +/* int on SP is 4 bytes */ +#define SP_INT_BYTES 4 + +#define store_sp_int(var, value) \ + sh_css_sp_dmem_store_32((unsigned) HIVE_ADDR_ ## var, \ + (unsigned int)(value)) + +#define store_sp_ptr(var, value) \ + sh_css_sp_dmem_store_32((unsigned) HIVE_ADDR_ ## var, \ + (unsigned int)(value)) + +#define load_sp_uint(var) \ + sh_css_sp_dmem_load_32((unsigned) HIVE_ADDR_ ## var) + +#define load_sp_array_uint(array, index) \ + sh_css_sp_dmem_load_32((unsigned) HIVE_ADDR_ ## array + \ + (index)*SP_INT_BYTES) + +#define store_sp_array_uint(array, index, value) \ + sh_css_sp_dmem_store_32((unsigned) HIVE_ADDR_ ## array + \ + (index)*SP_INT_BYTES, value) + +#define store_sp_var(var, data, bytes) \ + sh_css_sp_dmem_store((unsigned) HIVE_ADDR_ ## var, data, bytes) + +#define SH_CSS_PREVENT_UNINIT_READS 0 + +unsigned int +sh_css_sp_dmem_load_32(unsigned int address); + +void +sh_css_sp_dmem_store_32(unsigned int address, unsigned int value); + +void +sh_css_sp_dmem_load(unsigned int address, void *data, + unsigned int bytes); + +void +sh_css_sp_dmem_store(unsigned int address, const void *data, + unsigned int bytes); + +void +sh_css_sp_start(unsigned int start_address); + +void * +sh_css_sp_load_program(const struct sh_css_sp_fw *fw, const char *sp_prog); + +void +sh_css_sp_activate_program(const struct sh_css_sp_fw *fw, + void *code_addr, + const char *sp_prog); + +void +sh_css_sp_invalidate_mmu(void); + +#endif /* _SH_CSS_SP_START_H_ */ diff --git a/drivers/media/video/atomisp/css/sh_css_types.h b/drivers/media/video/atomisp/css/sh_css_types.h new file mode 100644 index 0000000..2ffa1a6 --- /dev/null +++ b/drivers/media/video/atomisp/css/sh_css_types.h @@ -0,0 +1,778 @@ +/* +* Support for Medfield PNW Camera Imaging ISP subsystem. +* +* Copyright (c) 2010 Intel Corporation. All Rights Reserved. +* +* Copyright (c) 2010 Silicon Hive www.siliconhive.com. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version +* 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA. +* +*/ + +#ifndef _SH_CSS_TYPES_H_ +#define _SH_CSS_TYPES_H_ + +/* This code is also used by Silicon Hive in a simulation environment + * Therefore, the following macro is used to differentiate when this + * code is being included from within the Linux kernel source + */ +#ifdef __KERNEL__ +#include +#include /* for memcpy */ +#else +#include /* for the print function */ +#include /* for size_t */ +#include /* for memcpy */ +#include "sh_css_min_max.h" +#ifdef STDC99 +#include +#else +#include "sh_css_bool.h" +#endif /* STDC99 */ +#endif + +#define SH_CSS_MAJOR 0 +#define SH_CSS_MINOR 2 +#define SH_CSS_REVISION 5 + +#define SH_CSS_MACC_NUM_AXES 16 +#define SH_CSS_MACC_NUM_COEFS 4 +#define SH_CSS_MORPH_TABLE_NUM_PLANES 6 +#define SH_CSS_SC_NUM_COLORS 4 +#define SH_CSS_CTC_TABLE_SIZE 1024 +#define SH_CSS_GAMMA_TABLE_SIZE 1024 +#define SH_CSS_DIS_NUM_COEF_TYPES 6 +#define SH_CSS_DIS_COEF_TYPES_ON_DMEM 2 +#define SH_CSS_CTC_COEF_SHIFT 13 +#define SH_CSS_GAMMA_GAIN_K_SHIFT 13 + +/* Fixed point types. + * NOTE: the 16 bit fixed point types actually occupy 32 bits + * to save on extension operations in the ISP code. + */ +#define u0_16 unsigned int /* unsigned 0.16 fixed point type */ +#define u2_14 unsigned int /* unsigned 2.14 fixed point type */ +#define u5_11 unsigned int /* unsigned 5.11 fixed point type */ +#define u8_8 unsigned int /* unsigned 8.8 fixed point type */ +#define s0_15 signed int /* signed 0.15 fixed point type */ + +/* Errors, these values are used as the return value for most + functions in this API. These can be translated into a human readable + string (see below). */ +enum sh_css_err { + sh_css_success, + sh_css_err_internal_error, + sh_css_err_conflicting_mipi_settings, + sh_css_err_unsupported_configuration, + sh_css_err_mode_does_not_have_viewfinder, + sh_css_err_input_resolution_not_set, + sh_css_err_unsupported_input_mode, + sh_css_err_cannot_allocate_memory, + sh_css_err_invalid_arguments, + sh_css_err_too_may_colors, + sh_css_err_overlay_frame_missing, + sh_css_err_overlay_frames_too_big, + sh_css_err_unsupported_frame_format, + sh_css_err_frames_mismatch, + sh_css_err_overlay_not_set, + sh_css_err_not_implemented, + sh_css_err_invalid_frame_format, + sh_css_err_unsupported_resolution, + sh_css_err_scaling_factor_out_of_range, + sh_css_err_cannot_obtain_shading_table, + sh_css_err_interrupt_error, + sh_css_err_unexpected_interrupt, + sh_css_err_interrupts_not_enabled, + sh_css_err_system_not_idle, + sh_css_err_unsupported_input_format, + sh_css_err_not_enough_input_lines, + sh_css_err_not_enough_input_columns, + sh_css_err_illegal_resolution, + sh_css_err_effective_input_resolution_not_set, + sh_css_err_viewfinder_resolution_too_wide, + sh_css_err_viewfinder_resolution_exceeds_output, + sh_css_err_mode_does_not_have_grid, + sh_css_err_mode_does_not_have_raw_output +}; + +/* Input modes, these enumerate all supported input modes: + * - Sensor: data from a sensor coming into the MIPI interface + * - FIFO: data from the host coming into the GP FIFO + * - TPG: data coming from the test pattern generator + * - PRBS: data coming from the Pseudo Random Bit Sequence + * - Memory: data coming from DDR + */ +enum sh_css_input_mode { + SH_CSS_INPUT_MODE_SENSOR, + SH_CSS_INPUT_MODE_FIFO, + SH_CSS_INPUT_MODE_TPG, + SH_CSS_INPUT_MODE_PRBS, + SH_CSS_INPUT_MODE_MEMORY +}; + +/* The MIPI interface can be used in two modes, one with one + * lane and one with 4 lanes. + */ +enum sh_css_mipi_port { + SH_CSS_MIPI_PORT_1LANE, + SH_CSS_MIPI_PORT_4LANE +}; + +/* The MIPI interface supports 2 types of compression or can + * be run without compression. + */ +enum sh_css_mipi_compression { + SH_CSS_MIPI_COMPRESSION_NONE, + SH_CSS_MIPI_COMPRESSION_1, + SH_CSS_MIPI_COMPRESSION_2 +}; + +/* The ISP streaming input interface supports the following formats. + * These match the corresponding MIPI formats. + */ +enum sh_css_input_format { + SH_CSS_INPUT_FORMAT_YUV420_8_LEGACY, /* 8 bits per subpixel */ + SH_CSS_INPUT_FORMAT_YUV420_8, /* 8 bits per subpixel */ + SH_CSS_INPUT_FORMAT_YUV420_10, /* 10 bits per subpixel */ + SH_CSS_INPUT_FORMAT_YUV422_8, /* UYVY..UVYV, 8 bits per subpixel */ + SH_CSS_INPUT_FORMAT_YUV422_10, /* UYVY..UVYV, 10 bits per subpixel */ + SH_CSS_INPUT_FORMAT_RGB_444, /* BGR..BGR, 4 bits per subpixel */ + SH_CSS_INPUT_FORMAT_RGB_555, /* BGR..BGR, 5 bits per subpixel */ + SH_CSS_INPUT_FORMAT_RGB_565, /* BGR..BGR, 5 bits B and $, 6 bits G */ + SH_CSS_INPUT_FORMAT_RGB_666, /* BGR..BGR, 6 bits per subpixel */ + SH_CSS_INPUT_FORMAT_RGB_888, /* BGR..BGR, 8 bits per subpixel */ + SH_CSS_INPUT_FORMAT_RAW_6, /* RAW data, 6 bits per pixel */ + SH_CSS_INPUT_FORMAT_RAW_7, /* RAW data, 7 bits per pixel */ + SH_CSS_INPUT_FORMAT_RAW_8, /* RAW data, 8 bits per pixel */ + SH_CSS_INPUT_FORMAT_RAW_10, /* RAW data, 10 bits per pixel */ + SH_CSS_INPUT_FORMAT_RAW_12, /* RAW data, 12 bits per pixel */ + SH_CSS_INPUT_FORMAT_RAW_14, /* RAW data, 14 bits per pixel */ + SH_CSS_INPUT_FORMAT_RAW_16, /* RAW data, 16 bits per pixel */ + SH_CSS_INPUT_FORMAT_BINARY_8, /* Binary byte stream. */ +}; + +/* Specify the capture mode, this can be RAW (simply copy sensor input to DDR), + * Primary ISP or the Advanced ISP. + */ +enum sh_css_capture_mode { + SH_CSS_CAPTURE_MODE_RAW, /* no processing, only copy input to + output, no viewfinder output */ + SH_CSS_CAPTURE_MODE_PRIMARY, /* primary ISP */ + SH_CSS_CAPTURE_MODE_ADVANCED, /* advanced ISP */ + SH_CSS_CAPTURE_MODE_LOW_LIGHT, /* low light ISP */ +}; + +/* Interrupt info enumeration. + * This lists all possible interrupts for use by the appliation layer. + * Note that the sh_css API uses some internal interrupts, these are not listed + * here. + */ +enum sh_css_interrupt_info { + /* the current frame is done and a new one can be started */ + SH_CSS_IRQ_INFO_FRAME_DONE = 1 << 0, + /* another stage (ISP binary) needs to be started. */ + SH_CSS_IRQ_INFO_START_NEXT_STAGE = 1 << 1, + /* 3A + DIS statistics are ready. */ + SH_CSS_IRQ_INFO_STATISTICS_READY = 1 << 2, + /* the css receiver has encountered an error */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_ERROR = 1 << 3, + /* the FIFO in the csi receiver has overflown */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_FIFO_OVERFLOW = 1 << 4, + /* the css receiver received the start of frame */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_SOF = 1 << 5, + /* the css receiver received the end of frame */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_EOF = 1 << 6, + /* the css receiver received the start of line */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_SOL = 1 << 7, + /* the css receiver received the end of line */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_EOL = 1 << 8, + /* the css receiver received a change in side band signals */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_SIDEBAND_CHANGED = 1 << 9, + /* generic short packets (0) */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_0 = 1 << 10, + /* generic short packets (1) */ + SH_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_1 = 1 << 11, + /* the primary input formatter (A) has encountered an error */ + SH_CSS_IRQ_INFO_IF_PRIM_ERROR = 1 << 12, + /* the primary input formatter (B) has encountered an error */ + SH_CSS_IRQ_INFO_IF_PRIM_B_ERROR = 1 << 13, + /* the secondary input formatter has encountered an error */ + SH_CSS_IRQ_INFO_IF_SEC_ERROR = 1 << 14, + /* the stream-to-memory device has encountered an error */ + SH_CSS_IRQ_INFO_STREAM_TO_MEM_ERROR = 1 << 15, + /* A firmware accelerator has terminated */ + SH_CSS_IRQ_INFO_FW_ACC_DONE = 1 << 16, + /* software interrupts */ + SH_CSS_IRQ_INFO_SW_0 = 1 << 17, + SH_CSS_IRQ_INFO_SW_1 = 1 << 18, + SH_CSS_IRQ_INFO_SW_2 = 1 << 19, +}; + +enum sh_css_rx_irq_info { + SH_CSS_RX_IRQ_INFO_BUFFER_OVERRUN = 1 << 0, + SH_CSS_RX_IRQ_INFO_ENTER_SLEEP_MODE = 1 << 1, + SH_CSS_RX_IRQ_INFO_EXIT_SLEEP_MODE = 1 << 2, + SH_CSS_RX_IRQ_INFO_ECC_CORRECTED = 1 << 3, + SH_CSS_RX_IRQ_INFO_ERR_SOT = 1 << 4, + SH_CSS_RX_IRQ_INFO_ERR_SOT_SYNC = 1 << 5, + SH_CSS_RX_IRQ_INFO_ERR_CONTROL = 1 << 6, + SH_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE = 1 << 7, + SH_CSS_RX_IRQ_INFO_ERR_CRC = 1 << 8, + SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID = 1 << 9, + SH_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC = 1 << 10, + SH_CSS_RX_IRQ_INFO_ERR_FRAME_DATA = 1 << 11, + SH_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT = 1 << 12, + SH_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC = 1 << 13, + SH_CSS_RX_IRQ_INFO_ERR_LINE_SYNC = 1 << 14, +}; + +/* Enumeration used to select whether interrupts should be used, and if so, + * whether they are edge or pulse triggered. + * If interrupts are not used, the blocking function + * sh_css_wait_for_completion() must be used. + */ +enum sh_css_interrupt_setting { + SH_CSS_INTERRUPT_SETTING_EDGE, + SH_CSS_INTERRUPT_SETTING_PULSE +}; + +/* Frame formats, some of these come from fourcc.org, others are + better explained by video4linux2. The NV11 seems to be described only + on MSDN pages, but even those seem to be gone now. + Frames can come in many forms, the main categories are RAW, RGB and YUV + (or YCbCr). The YUV frames come in 4 flavors, determined by how the U and V + values are subsampled: + 1. YUV420: hor = 2, ver = 2 + 2. YUV411: hor = 4, ver = 1 + 3. YUV422: hor = 2, ver = 1 + 4. YUV444: hor = 1, ver = 1 + */ +enum sh_css_frame_format { + SH_CSS_FRAME_FORMAT_NV11, /* 12 bit YUV 411, Y, UV plane */ + SH_CSS_FRAME_FORMAT_NV12, /* 12 bit YUV 420, Y, UV plane */ + SH_CSS_FRAME_FORMAT_NV16, /* 16 bit YUV 422, Y, UV plane */ + SH_CSS_FRAME_FORMAT_NV21, /* 12 bit YUV 420, Y, VU plane */ + SH_CSS_FRAME_FORMAT_NV61, /* 16 bit YUV 422, Y, VU plane */ + SH_CSS_FRAME_FORMAT_YV12, /* 12 bit YUV 420, Y, V, U plane */ + SH_CSS_FRAME_FORMAT_YV16, /* 16 bit YUV 422, Y, V, U plane */ + SH_CSS_FRAME_FORMAT_YUV420, /* 12 bit YUV 420, Y, U, V plane */ + SH_CSS_FRAME_FORMAT_YUV420_16, /* yuv420, 16 bits per subpixel */ + SH_CSS_FRAME_FORMAT_YUV422, /* 16 bit YUV 422, Y, U, V plane */ + SH_CSS_FRAME_FORMAT_YUV422_16, /* yuv422, 16 bits per subpixel */ + SH_CSS_FRAME_FORMAT_UYVY, /* 16 bit YUV 422, UYVY interleaved */ + SH_CSS_FRAME_FORMAT_YUYV, /* 16 bit YUV 422, YUYV interleaved */ + SH_CSS_FRAME_FORMAT_YUV444, /* 24 bit YUV 444, Y, U, V plane */ + SH_CSS_FRAME_FORMAT_YUV_LINE, /* Internal format, e.g. for VBF frame. + 2 y lines followed by a uv + interleaved line */ + SH_CSS_FRAME_FORMAT_RAW, /* RAW, 1 plane */ + SH_CSS_FRAME_FORMAT_RGB565, /* 16 bit RGB, 1 plane. Each 3 sub + pixels are packed into one 16 bit + value, 5 bits for R, 6 bits for G + and 5 bits for B. */ + SH_CSS_FRAME_FORMAT_PLANAR_RGB888, /* 24 bit RGB, 3 planes */ + SH_CSS_FRAME_FORMAT_RGBA888, /* 32 bit RGBA, 1 plane, A=Alpha unused + */ + SH_CSS_FRAME_FORMAT_QPLANE6, /* Internal, for advanced ISP */ + SH_CSS_FRAME_FORMAT_BINARY_8, /* byte stream, used for jpeg. For + frames of this type, we set the + height to 1 and the width to the + number of allocated bytes. */ +}; + +struct sh_css_frame_plane { + unsigned int height; /* height of a plane in lines */ + unsigned int width; /* width of a line, in DMA elements, note that + for RGB565 the three subpixels are stored in + one element. For all other formats this is + the number of subpixels per line. */ + unsigned int stride; /* stride of a line in bytes */ + void *data; /* pointer that points into frame data */ +}; + +struct sh_css_frame_binary_plane { + unsigned int size; + struct sh_css_frame_plane data; +}; + +struct sh_css_frame_yuv_planes { + struct sh_css_frame_plane y; + struct sh_css_frame_plane u; + struct sh_css_frame_plane v; +}; + +struct sh_css_frame_nv_planes { + struct sh_css_frame_plane y; + struct sh_css_frame_plane uv; +}; + +struct sh_css_frame_rgb_planes { + struct sh_css_frame_plane r; + struct sh_css_frame_plane g; + struct sh_css_frame_plane b; +}; + +struct sh_css_frame_plane6_planes { + struct sh_css_frame_plane r; + struct sh_css_frame_plane r_at_b; + struct sh_css_frame_plane gr; + struct sh_css_frame_plane gb; + struct sh_css_frame_plane b; + struct sh_css_frame_plane b_at_r; +}; + +/* For RAW input, the bayer order needs to be specified separately. There + are 4 possible orders. The name is constructed by taking the first two + colors on the first line and the first two colors from the second line. +grbg: GRGRGRGR + BGBGBGBG +rgbg: RGRGRGRG + GBGBGBGB +bggr: BGBGBGBG + GRGRGRGR +gbrg: GBGBGBGB + RGRGRGRG + */ +enum sh_css_bayer_order { + sh_css_bayer_order_grbg, + sh_css_bayer_order_rggb, + sh_css_bayer_order_bggr, + sh_css_bayer_order_gbrg +}; + +/* Frame info struct: + This structure describes a frame. It contains the resolution and strides. + */ +struct sh_css_frame_info { + /* width in valid data in pixels (not subpixels) */ + unsigned int width; + /* height in lines of valid image data */ + unsigned int height; + /* width of a line in memory, in pixels */ + unsigned int padded_width; + /* format of the data in this frame */ + enum sh_css_frame_format format; + /* number of valid bits per pixel, only valid for raw frames. */ + unsigned int raw_bit_depth; + /* bayer order of raw data, only valid for raw frames. */ + enum sh_css_bayer_order raw_bayer_order; +}; + +struct sh_css_frame { + struct sh_css_frame_info info; + /* pointer to start of image data in memory */ + void *data; + /* size of data pointer in bytes */ + unsigned int data_bytes; + /* indicate whether memory is allocated physically contiguously */ + bool contiguous; + union { + struct sh_css_frame_plane raw; + struct sh_css_frame_plane rgb; + struct sh_css_frame_rgb_planes planar_rgb; + struct sh_css_frame_plane yuyv; + struct sh_css_frame_yuv_planes yuv; + struct sh_css_frame_nv_planes nv; + struct sh_css_frame_plane6_planes plane6; + struct sh_css_frame_binary_plane binary; + } planes; +}; + +/* Histogram. This contains num_elements values of type unsigned int. + * The data pointer is a DDR pointer (virtual address). + */ +struct sh_css_histogram { + unsigned int num_elements; + void *data; +}; + +/* Overlay: + * this is the structure describing the entire overlay. + * An overlay consists of a frame (of type sh_css_frame_format_yuv420), + * the background color (yuv) and the blending ratios for the subpixels + * of the input data and the overlay data. + * All pixels in the overlay that are not equal to the background are + * overlaid, taking their blending ratio into account. The blending ratio + * should be specified between 0 and 100. + */ +struct sh_css_overlay { + /* the frame containing the overlay data The overlay frame width should + * be the multiples of 2*ISP_VEC_NELEMS. The overlay frame height + * should be the multiples of 2. + */ + struct sh_css_frame *frame; + /* Y value of overlay background */ + unsigned char bg_y; + /* U value of overlay background */ + char bg_u; + /* V value of overlay background */ + char bg_v; + /* the blending percent of input data for Y subpixels */ + unsigned char blend_input_perc_y; + /* the blending percent of input data for U subpixels */ + unsigned char blend_input_perc_u; + /* the blending percent of input data for V subpixels */ + unsigned char blend_input_perc_v; + /* the blending percent of overlay data for Y subpixels */ + unsigned char blend_overlay_perc_y; + /* the blending percent of overlay data for U subpixels */ + unsigned char blend_overlay_perc_u; + /* the blending percent of overlay data for V subpixels */ + unsigned char blend_overlay_perc_v; + /* the overlay start x pixel position on output frame It should be the + multiples of 2*ISP_VEC_NELEMS. */ + unsigned int overlay_start_x; + /* the overlay start y pixel position on output frame It should be the + multiples of 2. */ + unsigned int overlay_start_y; +}; + +/* SP struct describing overlay properties */ +struct sh_css_sp_overlay { + int bg_y; + int bg_u; + int bg_v; + int blend_shift; + int blend_input_y; + int blend_input_u; + int blend_input_v; + int blend_overlay_y; + int blend_overlay_u; + int blend_overlay_v; + int overlay_width; + int overlay_height; + int overlay_start_x; + int overlay_start_y; + const char *frame_ptr_overlay_y; + const char *frame_ptr_overlay_u; + const char *frame_ptr_overlay_v; +}; + +/* structure that describes the 3A and DIS grids */ +struct sh_css_grid_info { + /* 3A statistics grid: */ + unsigned int s3a_width; + unsigned int s3a_height; + unsigned int s3a_bqs_per_grid_cell; + /* DIS grid: */ + unsigned int dis_width; /* also used for vertical projections */ + unsigned int dis_height; /* also used for horizontal projections */ + unsigned int dis_bqs_per_grid_cell; + unsigned int dis_hor_coef_num; + unsigned int dis_ver_coef_num; +}; + +enum sh_css_ob_mode { + sh_css_ob_mode_none, + sh_css_ob_mode_fixed, + sh_css_ob_mode_raster +}; + +/* Shading correction */ +enum sh_css_sc_color { + SH_CSS_SC_COLOR_GR, + SH_CSS_SC_COLOR_R, + SH_CSS_SC_COLOR_B, + SH_CSS_SC_COLOR_GB +}; + +/* White Balance (Gain Adjust) */ +struct sh_css_wb_config { + unsigned int integer_bits; + unsigned int gr; /* unsigned .<16-integer_bits> */ + unsigned int r; /* unsigned .<16-integer_bits> */ + unsigned int b; /* unsigned .<16-integer_bits> */ + unsigned int gb; /* unsigned .<16-integer_bits> */ +}; + +/* Color Space Conversion settings */ +struct sh_css_cc_config { + unsigned int fraction_bits; + int matrix[3 * 3]; /* RGB2YUV Color matrix, signed + <13-fraction_bits>. */ +}; + +/* Morphing table for advanced ISP. + * Each line of width elements takes up COORD_TABLE_EXT_WIDTH elements + * in memory. + */ +struct sh_css_morph_table { + unsigned int height; + unsigned int width; /* number of valid elements per line */ + unsigned short *coordinates_x[SH_CSS_MORPH_TABLE_NUM_PLANES]; + unsigned short *coordinates_y[SH_CSS_MORPH_TABLE_NUM_PLANES]; +}; + +struct sh_css_fpn_table { + short *data; + unsigned int width; + unsigned int height; + unsigned int shift; +}; + +struct sh_css_shading_table { + /* native sensor resolution */ + unsigned int sensor_width; + unsigned int sensor_height; + /* number of data points per line per color (bayer quads) */ + unsigned int width; + /* number of lines of data points per color (bayer quads) */ + unsigned int height; + /* bits of fraction part for shading table values */ + unsigned int fraction_bits; + /* one table for each color (use sh_css_sc_color to index) */ + unsigned short *data[SH_CSS_SC_NUM_COLORS]; +}; + +struct sh_css_gamma_table { + unsigned short data[SH_CSS_GAMMA_TABLE_SIZE]; +}; + +struct sh_css_ctc_table { + unsigned short data[SH_CSS_CTC_TABLE_SIZE]; +}; + +struct sh_css_macc_table { + short data[SH_CSS_MACC_NUM_COEFS * SH_CSS_MACC_NUM_AXES]; +}; + +/* Temporal noise reduction configuration */ +struct sh_css_tnr_config { + u0_16 gain; /* [gain] Strength of NR */ + u0_16 threshold_y; /* [intensity] Motion sensitivity for Y */ + u0_16 threshold_uv; /* [intensity] Motion sensitivity for U/V */ +}; + +/* Optical black level configuration */ +struct sh_css_ob_config { + /* Obtical black level mode (Fixed / Raster) */ + enum sh_css_ob_mode mode; + /* [intensity] optical black level for GR (relevant for fixed mode) */ + u0_16 level_gr; + /* [intensity] optical black level for R (relevant for fixed mode) */ + u0_16 level_r; + /* [intensity] optical black level for B (relevant for fixed mode) */ + u0_16 level_b; + /* [intensity] optical black level for GB (relevant for fixed mode) */ + u0_16 level_gb; + /* [BQ] 0..63 start position of OB area (relevant for raster mode) */ + unsigned short start_position; + /* [BQ] start..63 end position of OB area (relevant for raster mode) */ + unsigned short end_position; +}; + +/* Defect pixel correction configuration */ +struct sh_css_dp_config { + /* [intensity] The threshold of defect Pixel Correction, representing + * the permissible difference of intensity between one pixel and its + * surrounding pixels. Smaller values result in more frequent pixel + * corrections. + */ + u0_16 threshold; + /* [gain] The sensitivity of mis-correction. ISP will miss a lot of + * defects if the value is set too large. + */ + u8_8 gain; +}; + +/* Configuration used by Bayer noise reduction and YCC noise reduction */ +struct sh_css_nr_config { + /* [gain] Strength of noise reduction for both Bayer NR & YCC NR (Used + * by Bayer NR and YCC NR). + */ + u0_16 gain; + /* [intensity] Sensitivity of Edge (Used by Bayer NR) */ + u0_16 direction; + /* [intensity] coring threshold for Cb (Used by YCC NR) */ + u0_16 threshold_cb; + /* [intensity] coring threshold for Cr (Used by YCC NR) */ + u0_16 threshold_cr; +}; + +/* Edge enhancement (sharpen) configuration */ +struct sh_css_ee_config { + /* [gain] The strength of sharpness. */ + u5_11 gain; + /* [intensity] The threshold that divides noises from edge. */ + u8_8 threshold; + /* [gain] The strength of sharpness in pell-mell area. */ + u5_11 detail_gain; +}; + +struct sh_css_de_config { + u0_16 pixelnoise; + u0_16 c1_coring_threshold; + u0_16 c2_coring_threshold; +}; + +struct sh_css_gc_config { + int gain_k1; + int gain_k2; +}; + +struct sh_css_anr_config { + int threshold; +}; + +struct sh_css_3a_config { + u0_16 ae_y_coef_r; /* [gain] Weight of R for Y */ + u0_16 ae_y_coef_g; /* [gain] Weight of G for Y */ + u0_16 ae_y_coef_b; /* [gain] Weight of B for Y */ + s0_15 af_fir1_coef[7]; /* [factor] AF FIR coefficients of fir1 */ + s0_15 af_fir2_coef[7]; /* [factor] AF FIR coefficients of fir2 */ +}; + +/* Workaround: hivecc complains about "tag "sh_css_3a_output" already declared" + without this extra decl. */ +struct sh_css_3a_output; + +struct sh_css_3a_output { + int ae_y; + int awb_cnt; + int awb_gr; + int awb_r; + int awb_b; + int awb_gb; + int af_hpf1; + int af_hpf2; +}; + +/* Descriptor of sp firmware blob */ +struct sh_css_sp_fw { + const void *text; /* Sp text section */ + unsigned int text_source; /* Position of text in blob */ + unsigned int text_size; /* Size of text section */ + const void *data; /* Sp data section */ + unsigned int data_source; /* Position of data in blob */ + unsigned int data_target; /* Start position of data in SP dmem */ + unsigned int data_size; /* Size of text section */ + unsigned int bss_target; /* Start position of bss in SP dmem */ + unsigned int bss_size; /* Size of bss section */ +}; + +/* this struct contains all arguments that can be passed to + a binary. It depends on the binary which ones are used. */ +struct sh_css_binary_args { + struct sh_css_frame *cc_frame; /* continuous capture frame */ + struct sh_css_frame *in_frame; /* input frame */ + struct sh_css_frame *in_ref_frame; /* reference input frame */ + struct sh_css_frame *in_tnr_frame; /* tnr input frame */ + struct sh_css_frame *out_frame; /* output frame */ + struct sh_css_frame *out_ref_frame; /* reference output frame */ + struct sh_css_frame *out_tnr_frame; /* tnr output frame */ + struct sh_css_frame *extra_frame; /* intermediate frame */ + struct sh_css_frame *out_vf_frame; /* viewfinder output frame */ + int dvs_vector_x; + int dvs_vector_y; + bool enable_xnr; + bool two_ppc; + bool copy_vf; + bool copy_output; + unsigned vf_downscale_log2; +}; + +/* Type of acceleration */ +enum sh_css_acc_type { + SH_CSS_ACC_STANDALONE, /* Stand-alone acceleration */ + SH_CSS_ACC_OUTPUT, /* Accelerator stage on output frame */ + SH_CSS_ACC_VIEWFINDER /* Accelerator stage on viewfinder frame */ +}; + +/* Type of acceleration argument */ +enum sh_css_acc_arg_type { + SH_CSS_ACC_ARG_SCALAR_IN, /* Scalar input argument */ + SH_CSS_ACC_ARG_SCALAR_OUT, /* Scalar output argument */ + SH_CSS_ACC_ARG_SCALAR_IO, /* Scalar in/output argument */ + SH_CSS_ACC_ARG_PTR_IN, /* Pointer input argument */ + SH_CSS_ACC_ARG_PTR_OUT, /* Pointer output argument */ + SH_CSS_ACC_ARG_PTR_IO, /* Pointer in/output argument */ + SH_CSS_ACC_ARG_FRAME /* Frame argument */ +}; + +/* Descriptor for an SP argument */ +struct sh_css_sp_arg { + enum sh_css_acc_arg_type type; /* Type of SP argument */ + void *value; /* Value of SP argument */ + unsigned int size; /* Size of SP argument */ + void *host; /* Private data used by host */ +}; + +struct sh_css_acc_fw; + +/* Firmware descriptor */ +struct sh_css_acc_fw_hdr { + enum sh_css_acc_type type; /* Type of accelerator */ + bool loaded; /* Firmware has been loaded */ + struct sh_css_sp_arg *sp_args; /* Current SP argument */ + unsigned prog_name_offset; /* offset wrt hdr in bytes */ + unsigned arg_types_offset; /* offset wrt hdr in bytes */ + unsigned sp_blob_offset; /* offset wrt hdr in bytes */ + unsigned isp_blob_offset; /* offset wrt hdr in bytes */ + struct { + unsigned int size; /* Size of sp blob */ + void (*init) (struct sh_css_acc_fw *); /* init for crun */ + void *entry; /* Address of sp entry point */ + unsigned int *args; /* Address of sp_args */ + unsigned int args_cnt; /* Number of sp_args */ + unsigned int args_size; /* Size of sp_args */ + unsigned int *css_abort; /* SP dmem abort flag */ + struct sh_css_frame *input; /* SP dmem input frame */ + struct sh_css_frame *output; /* SP dmem output frame */ + struct sh_css_frame *out_vf; /* SP dmem vf frame */ + struct sh_css_frame *extra; /* SP dmem extra frame */ + unsigned int *vf_downscale_bits; + void *isp_code; /* SP dmem address holding xmem + address of isp code */ + struct sh_css_sp_fw fw; /* SP fw descriptor */ + } sp; + struct { + unsigned int size; /* Size of isp blob */ + } isp; +}; + +/* Firmware. Containing header and actual blobs */ +struct sh_css_acc_fw { + /* firmware header */ + struct sh_css_acc_fw_hdr header; + /* To create a sequence of accelerators */ + struct sh_css_acc_fw *next; + /* Firmware handle between user space and kernel */ + unsigned int handle; + /* followed by prog_name, sp arg types, sp blob and isp blob */ +#ifdef __HIVECC + unsigned char data[1]; /* Not C89 */ +#else + unsigned char data[]; +#endif +}; + +/* Access macros for firmware */ +#define SH_CSS_ACC_OFFSET(t, f, n) ((t)((unsigned char *)(f)+(f->header.n))) +#define SH_CSS_ACC_PROG_NAME(f) SH_CSS_ACC_OFFSET(const char *, f, \ + prog_name_offset) +#define SH_CSS_ACC_SP_ARGS(f) SH_CSS_ACC_OFFSET(enum sh_css_acc_arg_type*,\ + f, arg_types_offset) +#define SH_CSS_ACC_SP_CODE(f) SH_CSS_ACC_OFFSET(unsigned char *, f, \ + sp_blob_offset) +#define SH_CSS_ACC_SP_SIZE(f) ((f)->header.sp.size) +#define SH_CSS_ACC_SP_DATA(f) (SH_CSS_ACC_SP_CODE(f) + \ + (f)->header.sp.fw.data_source) +#define SH_CSS_ACC_ISP_CODE(f) SH_CSS_ACC_OFFSET(unsigned char*, f,\ + isp_blob_offset) +#define SH_CSS_ACC_ISP_SIZE(f) ((f)->header.isp.size) +#define SH_CSS_ACC_SIZE(f) ((f)->header.isp_blob_offset + \ + SH_CSS_ACC_ISP_SIZE(f)) + +#endif /* _SH_CSS_TYPES_H_ */ diff --git a/drivers/media/video/atomisp/hmm/hmm.c b/drivers/media/video/atomisp/hmm/hmm.c new file mode 100644 index 0000000..f4fa7fa --- /dev/null +++ b/drivers/media/video/atomisp/hmm/hmm.c @@ -0,0 +1,388 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +/* + * This file contains entry functions for memory management of ISP driver + */ +#include +#include +#include +#include /* for kmap */ +#include /* for page_to_phys */ + +#include "hmm/hmm.h" +#include "hmm/hmm_bo.h" +#include "hmm/hmm_bo_dev.h" + +#include "mmu/isp_mmu.h" +#include "mmu/sh_mmu.h" +#include "atomisp_internal.h" +#include "asm/cacheflush.h" + +#ifdef USE_SSSE3 +#include +#endif + +static struct hmm_bo_device bo_device; +static void *dummy_ptr; + +int hmm_init() +{ + int ret; + + ret = hmm_bo_device_init(&bo_device, &sh_mmu_driver, + ISP_VM_START, ISP_VM_SIZE); + if (ret) + v4l2_err(&atomisp_dev, + "hmm_bo_device_init failed.\n"); + + /* + * As hmm use NULL to indicate invalid ISP virtual address, + * and ISP_VM_START is defined to 0 too, so we allocate + * one piece of dummy memory, which should return value 0, + * at the beginning, to avoid hmm_alloc return 0 in the + * further allocation. + */ + dummy_ptr = hmm_alloc(1, HMM_BO_PRIVATE, 0, 0, HMM_UNCACHED); + return ret; +} + +void hmm_cleanup() +{ + /* + * free dummy memory first + */ + hmm_free(dummy_ptr); + dummy_ptr = NULL; + + hmm_bo_device_exit(&bo_device); +} + +void *hmm_alloc(size_t bytes, enum hmm_bo_type type, + int from_highmem, unsigned int userptr, bool cached) +{ + unsigned int pgnr; + struct hmm_buffer_object *bo; + int ret; + + /*Get page number from size*/ + pgnr = size_to_pgnr_ceil(bytes); + + /*Buffer object structure init*/ + bo = hmm_bo_create(&bo_device, pgnr); + if (!bo) { + v4l2_err(&atomisp_dev, "hmm_bo_create failed.\n"); + goto create_bo_err; + } + + /*Allocate virtual address in ISP virtual space*/ + ret = hmm_bo_alloc_vm(bo); + if (ret) { + v4l2_err(&atomisp_dev, + "hmm_bo_alloc_vm failed.\n"); + goto alloc_vm_err; + } + + /*Allocate pages for memory*/ + ret = hmm_bo_alloc_pages(bo, type, from_highmem, userptr, cached); + if (ret) { + v4l2_err(&atomisp_dev, + "hmm_bo_alloc_pages failed.\n"); + goto alloc_page_err; + } + + /*Combind the virtual address and pages togather*/ + ret = hmm_bo_bind(bo); + if (ret) { + v4l2_err(&atomisp_dev, "hmm_bo_bind failed.\n"); + goto bind_err; + } + + return (void *)bo->vm_node->start; + +bind_err: + hmm_bo_free_pages(bo); +alloc_page_err: + hmm_bo_free_vm(bo); +alloc_vm_err: + hmm_bo_unref(bo); +create_bo_err: + return NULL; +} + +void hmm_free(void *virt) +{ + struct hmm_buffer_object *bo; + + bo = hmm_bo_device_search_start(&bo_device, (unsigned int)virt); + + if (!bo) { + v4l2_err(&atomisp_dev, + "can not find buffer object start with " + "address 0x%x\n", (unsigned int)virt); + return; + } + + hmm_bo_unbind(bo); + + hmm_bo_free_pages(bo); + + hmm_bo_free_vm(bo); + + hmm_bo_unref(bo); +} + +static inline int hmm_check_bo(struct hmm_buffer_object *bo, unsigned int ptr) +{ + if (!bo) { + v4l2_err(&atomisp_dev, + "can not find buffer object contains " + "address 0x%x\n", ptr); + return -EINVAL; + } + + if (!hmm_bo_page_allocated(bo)) { + v4l2_err(&atomisp_dev, + "buffer object has no page allocated.\n"); + return -EINVAL; + } + + if (!hmm_bo_vm_allocated(bo)) { + v4l2_err(&atomisp_dev, + "buffer object has no virtual address" + " space allocated.\n"); + return -EINVAL; + } + + return 0; +} + +/*Read function in ISP memory management*/ +int hmm_load(void *virt, void *data, unsigned int bytes) +{ + unsigned int ptr; + struct hmm_buffer_object *bo; + unsigned int idx, offset, len; + char *src, *des; + int ret; + + ptr = (unsigned int)virt; + + bo = hmm_bo_device_search_in_range(&bo_device, ptr); + ret = hmm_check_bo(bo, ptr); + if (ret) + return ret; + + des = (char *)data; + while (bytes) { + idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT; + offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT); + + src = (char *)kmap(bo->pages[idx]); + if (!src) { + v4l2_err(&atomisp_dev, + "kmap buffer object page failed: " + "pg_idx = %d\n", idx); + return -EINVAL; + } + + src += offset; + + if ((bytes + offset) >= PAGE_SIZE) { + len = PAGE_SIZE - offset; + bytes -= len; + } else { + len = bytes; + bytes = 0; + } + + ptr += len; /* update ptr for next loop */ + +#ifdef USE_SSSE3 + _ssse3_memcpy(des, src, len); +#else + memcpy(des, src, len); +#endif + + des += len; + clflush_cache_range(src, len); + + kunmap(bo->pages[idx]); + } + + return 0; +} + +/*Write function in ISP memory management*/ +int hmm_store(void *virt, const void *data, unsigned int bytes) +{ + unsigned int ptr; + struct hmm_buffer_object *bo; + unsigned int idx, offset, len; + char *src, *des; + int ret; + + ptr = (unsigned int)virt; + + bo = hmm_bo_device_search_in_range(&bo_device, ptr); + ret = hmm_check_bo(bo, ptr); + if (ret) + return ret; + + src = (char *)data; + while (bytes) { + idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT; + offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT); + + des = (char *)kmap(bo->pages[idx]); + if (!des) { + v4l2_err(&atomisp_dev, + "kmap buffer object page failed: " + "pg_idx = %d\n", idx); + return -EINVAL; + } + + des += offset; + + if ((bytes + offset) >= PAGE_SIZE) { + len = PAGE_SIZE - offset; + bytes -= len; + } else { + len = bytes; + bytes = 0; + } + + ptr += len; + +#ifdef USE_SSSE3 + _ssse3_memcpy(des, src, len); +#else + memcpy(des, src, len); +#endif + src += len; + + kunmap(bo->pages[idx]); + } + + return 0; +} + +/*memset function in ISP memory management*/ +int hmm_set(void *virt, int c, unsigned int bytes) +{ + unsigned int ptr; + struct hmm_buffer_object *bo; + unsigned int idx, offset, len; + char *des; + int ret; + + ptr = (unsigned int)virt; + + bo = hmm_bo_device_search_in_range(&bo_device, ptr); + ret = hmm_check_bo(bo, ptr); + if (ret) + return ret; + + while (bytes) { + idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT; + offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT); + + des = (char *)kmap(bo->pages[idx]); + if (!des) { + v4l2_err(&atomisp_dev, + "kmap buffer object page failed: " + "pg_idx = %d\n", idx); + return -EINVAL; + } + des += offset; + + if ((bytes + offset) >= PAGE_SIZE) { + len = PAGE_SIZE - offset; + bytes -= len; + } else { + len = bytes; + bytes = 0; + } + + ptr += len; + + memset(des, c, len); + + kunmap(bo->pages[idx]); + } + + return 0; +} + +/*Virtual address to physical address convert*/ +unsigned int hmm_virt_to_phys(void *virt) +{ + unsigned int ptr = (unsigned int)virt; + unsigned int idx, offset; + struct hmm_buffer_object *bo; + + bo = hmm_bo_device_search_in_range(&bo_device, ptr); + if (!bo) { + v4l2_err(&atomisp_dev, + "can not find buffer object contains " + "address 0x%x\n", ptr); + return -1; + } + + idx = (ptr - bo->vm_node->start) >> PAGE_SHIFT; + offset = (ptr - bo->vm_node->start) - (idx << PAGE_SHIFT); + + return page_to_phys(bo->pages[idx]) + offset; +} + +int hmm_mmap(struct vm_area_struct *vma, void *virt) +{ + unsigned int ptr = (unsigned int)virt; + struct hmm_buffer_object *bo; + + bo = hmm_bo_device_search_start(&bo_device, ptr); + if (!bo) { + v4l2_err(&atomisp_dev, + "can not find buffer object start with " + "address 0x%x\n", (unsigned int)virt); + return -EINVAL; + } + + return hmm_bo_mmap(vma, bo); +} + +/*Map ISP virtual address into IA virtual address*/ +void *hmm_vmap(void *virt) +{ + unsigned int ptr = (unsigned int)virt; + struct hmm_buffer_object *bo; + + bo = hmm_bo_device_search_start(&bo_device, ptr); + if (!bo) { + v4l2_err(&atomisp_dev, + "can not find buffer object start with " + "address 0x%x\n", (unsigned int)virt); + return NULL; + } + + return hmm_bo_vmap(bo); +} diff --git a/drivers/media/video/atomisp/hmm/hmm_bo.c b/drivers/media/video/atomisp/hmm/hmm_bo.c new file mode 100644 index 0000000..7957667 --- /dev/null +++ b/drivers/media/video/atomisp/hmm/hmm_bo.c @@ -0,0 +1,1077 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +/* + * This file contains functions for buffer object structure management + */ +#include +#include +#include /* for GFP_ATOMIC */ +#include +#include +#include +#include +#include /* for kmalloc */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hmm/hmm_vm.h" +#include "hmm/hmm_bo.h" +#include "hmm/hmm_bo_dev.h" +#include "hmm/hmm_common.h" +#include "atomisp_internal.h" + +static inline unsigned int order_to_nr(unsigned int order) +{ + return 1U << order; +} + +static inline unsigned int nr_to_order_ceil(unsigned int nr) +{ + unsigned int order = 0; + + for (; nr / 2; nr = nr / 2 + nr % 2) + order++; + + return order; +} + +static inline unsigned int nr_to_order_bottom(unsigned int nr) +{ + unsigned int order = 0; + + while (nr /= 2) + order++; + + return order; +} + +static void free_bo_internal(struct hmm_buffer_object *bo) +{ + kfree(bo); +} + +/* + * use these functions to dynamically alloc hmm_buffer_object. + * hmm_bo_init will called for that allocated buffer object, and + * the release callback is set to kfree. + */ +struct hmm_buffer_object *hmm_bo_create(struct hmm_bo_device *bdev, int pgnr) +{ + struct hmm_buffer_object *bo; + int ret; + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); + if (!bo) { + v4l2_err(&atomisp_dev, "out of memory for bo\n"); + return NULL; + } + + ret = hmm_bo_init(bdev, bo, pgnr, free_bo_internal); + if (ret) { + v4l2_err(&atomisp_dev, "hmm_bo_init failed\n"); + kfree(bo); + return NULL; + } + + return bo; +} + +/* + * use this function to initialize pre-allocated hmm_buffer_object. + * as hmm_buffer_object may be used as an embedded object in an upper + * level object, a release callback must be provided. if it is + * embedded in upper level object, set release call back to release + * function of that object. if no upper level object, set release + * callback to NULL. + * + * bo->kref is inited to 1. + */ +int hmm_bo_init(struct hmm_bo_device *bdev, + struct hmm_buffer_object *bo, + unsigned int pgnr, void (*release) (struct hmm_buffer_object *)) +{ + if (bdev == NULL) { + v4l2_warn(&atomisp_dev, + "NULL hmm_bo_device.\n"); + return -EINVAL; + } + + /* hmm_bo_device must be already inited */ + var_equal_return(hmm_bo_device_inited(bdev), 0, -EINVAL, + "hmm_bo_device not inited yet.\n"); + + /* prevent zero size buffer object */ + if (pgnr == 0) { + v4l2_err(&atomisp_dev, + "0 size buffer is not allowed.\n"); + return -EINVAL; + } + + memset(bo, 0, sizeof(*bo)); + + kref_init(&bo->kref); + + mutex_init(&bo->mutex); + + INIT_LIST_HEAD(&bo->list); + + bo->pgnr = pgnr; + bo->bdev = bdev; + + INIT_LIST_HEAD(&bo->pgblocks); + + bo->release = release; + + if (!bo->release) + v4l2_warn(&atomisp_dev, + "no release callback specified.\n"); + + /* + * add to active_bo_list + */ + mutex_lock(&bdev->ablist_mutex); + list_add_tail(&bo->list, &bdev->active_bo_list); + bo->status |= HMM_BO_ACTIVE; + mutex_unlock(&bdev->ablist_mutex); + + return 0; +} + +static void hmm_bo_release(struct hmm_buffer_object *bo) +{ + struct hmm_bo_device *bdev; + + check_bo_null_return(bo, (void)0); + + bdev = bo->bdev; + + /* + * FIX ME: + * + * how to destroy the bo when it is stilled MMAPED? + * + * ideally, this will not happened as hmm_bo_release + * will only be called when kref reaches 0, and in mmap + * operation the hmm_bo_ref will eventually be called. + * so, if this happened, something goes wrong. + */ + if (bo->status & HMM_BO_MMAPED) { + v4l2_err(&atomisp_dev, + "destroy bo which is MMAPED, do nothing\n"); + goto err; + } + + if (bo->status & HMM_BO_BINDED) { + v4l2_warn(&atomisp_dev, + "the bo is still binded, unbind it first...\n"); + hmm_bo_unbind(bo); + } + if (bo->status & HMM_BO_PAGE_ALLOCED) { + v4l2_warn(&atomisp_dev, + "the pages is not freed, free pages first\n"); + hmm_bo_free_pages(bo); + } + if (bo->status & HMM_BO_VM_ALLOCED) { + v4l2_warn(&atomisp_dev, + "the vm is still not freed, free vm first...\n"); + hmm_bo_free_vm(bo); + } + + /* + * remove it from buffer device's buffer object list. + */ + if (hmm_bo_activated(bo)) { + mutex_lock(&bdev->ablist_mutex); + list_del(&bo->list); + mutex_unlock(&bdev->ablist_mutex); + } else { + mutex_lock(&bdev->fblist_mutex); + list_del(&bo->list); + mutex_unlock(&bdev->fblist_mutex); + } + + if (bo->release) + bo->release(bo); +err: + return; +} + +int hmm_bo_activated(struct hmm_buffer_object *bo) +{ + check_bo_null_return(bo, 0); + + return bo->status & HMM_BO_ACTIVE; +} + +void hmm_bo_unactivate(struct hmm_buffer_object *bo) +{ + struct hmm_bo_device *bdev; + + check_bo_null_return(bo, (void)0); + + check_bo_status_no_goto(bo, HMM_BO_ACTIVE, status_err); + + bdev = bo->bdev; + + mutex_lock(&bdev->ablist_mutex); + list_del(&bo->list); + mutex_unlock(&bdev->ablist_mutex); + + mutex_lock(&bdev->fblist_mutex); + list_add_tail(&bo->list, &bdev->free_bo_list); + bo->status &= (~HMM_BO_ACTIVE); + mutex_unlock(&bdev->fblist_mutex); + + return; + +status_err: + v4l2_err(&atomisp_dev, + "buffer object already unactivated.\n"); + return; +} + +int hmm_bo_alloc_vm(struct hmm_buffer_object *bo) +{ + struct hmm_bo_device *bdev; + + check_bo_null_return(bo, -EINVAL); + + mutex_lock(&bo->mutex); + + check_bo_status_no_goto(bo, HMM_BO_VM_ALLOCED, status_err); + + bdev = bo->bdev; + + bo->vm_node = hmm_vm_alloc_node(&bdev->vaddr_space, bo->pgnr); + if (unlikely(!bo->vm_node)) { + v4l2_err(&atomisp_dev, + "hmm_vm_alloc_node err.\n"); + goto null_vm; + } + + bo->status |= HMM_BO_VM_ALLOCED; + + mutex_unlock(&bo->mutex); + + return 0; +null_vm: + mutex_unlock(&bo->mutex); + return -ENOMEM; + +status_err: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, + "buffer object already has vm allocated.\n"); + return -EINVAL; +} + +void hmm_bo_free_vm(struct hmm_buffer_object *bo) +{ + struct hmm_bo_device *bdev; + + check_bo_null_return(bo, (void)0); + + mutex_lock(&bo->mutex); + + check_bo_status_yes_goto(bo, HMM_BO_VM_ALLOCED, status_err); + + bdev = bo->bdev; + + hmm_vm_free_node(bo->vm_node); + bo->vm_node = NULL; + bo->status &= (~HMM_BO_VM_ALLOCED); + mutex_unlock(&bo->mutex); + + return; + +status_err: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, + "buffer object has no vm allocated.\n"); +} + +int hmm_bo_vm_allocated(struct hmm_buffer_object *bo) +{ + int ret; + + check_bo_null_return(bo, 0); + + mutex_lock(&bo->mutex); + + ret = (bo->status & HMM_BO_VM_ALLOCED); + + mutex_unlock(&bo->mutex); + + return ret; +} + +/*Allocate pages which will be used only by ISP*/ +static int alloc_private_pages(struct hmm_buffer_object *bo, int from_highmem, + bool cached) +{ + int ret; + unsigned int pgnr, order, blk_pgnr; + struct page *pages; + struct page_block *pgblk; + gfp_t gfp; + int i, j; + + gfp = GFP_KERNEL; + if (from_highmem) + gfp |= __GFP_HIGHMEM; + + pgnr = bo->pgnr; + + bo->pages = kzalloc(sizeof(struct page *) * pgnr, GFP_KERNEL); + if (unlikely(!bo->pages)) { + v4l2_err(&atomisp_dev, "out of memory for bo->pages\n"); + goto out_of_mem; + } + + i = 0; + while (pgnr) { + order = nr_to_order_bottom(pgnr); + if (order > HMM_MAX_ORDER) + order = HMM_MAX_ORDER; +retry: + pages = alloc_pages(gfp, order); + if (unlikely(!pages)) { + /* + * in low memory case, if allocation page fails, + * we turn to try if order=0 allocation could + * succeed. if order=0 fails too, that means there is + * no memory left. + */ + if (order == HMM_MIN_ORDER) { + v4l2_err(&atomisp_dev, + "out of memory in alloc_pages\n"); + goto out_of_mem; + } + v4l2_warn(&atomisp_dev, + "allocate order=%d pages failed." + "reduing page order to %d.\n", + order, HMM_MIN_ORDER); + order = HMM_MIN_ORDER; + goto retry; + } else { + blk_pgnr = order_to_nr(order); + + pgblk = kzalloc(sizeof(*pgblk), GFP_KERNEL); + if (unlikely(!pgblk)) { + v4l2_err(&atomisp_dev, + "out of memory for pgblk\n"); + goto out_of_mem; + } + + INIT_LIST_HEAD(&pgblk->list); + pgblk->pages = pages; + pgblk->order = order; + + list_add_tail(&pgblk->list, &bo->pgblocks); + + for (j = 0; j < blk_pgnr; j++) + bo->pages[i++] = pages + j; + + pgnr -= blk_pgnr; + + if (!cached) { + /* + * set memory to uncacheable -- UC_MINUS + */ + ret = set_pages_uc(pages, blk_pgnr); + if (ret) { + v4l2_err(&atomisp_dev, + "set page uncacheable" + "failed.\n"); + goto set_uc_mem_fail; + } + } + } + } + + return 0; +set_uc_mem_fail: + /* FIX ME: select one better */ + ret = -ENOMEM; + goto cleanup; +out_of_mem: + ret = -ENOMEM; + goto cleanup; +cleanup: + while (!list_empty(&bo->pgblocks)) { + pgblk = list_first_entry(&bo->pgblocks, + struct page_block, list); + + list_del(&pgblk->list); + + ret = set_pages_wb(pgblk->pages, order_to_nr(pgblk->order)); + if (ret) + v4l2_err(&atomisp_dev, + "set page to WB err...\n"); + + __free_pages(pgblk->pages, pgblk->order); + kfree(pgblk); + } + + return ret; +} + +static void free_private_pages(struct hmm_buffer_object *bo) +{ + struct page_block *pgblk; + int ret; + + while (!list_empty(&bo->pgblocks)) { + pgblk = list_first_entry(&bo->pgblocks, + struct page_block, list); + + list_del(&pgblk->list); + + ret = set_pages_wb(pgblk->pages, order_to_nr(pgblk->order)); + if (ret) + v4l2_err(&atomisp_dev, + "set page to WB err...\n"); + + __free_pages(pgblk->pages, pgblk->order); + kfree(pgblk); + } + + kfree(bo->pages); +} + +/* + * Hacked from kernel function __get_user_pages in mm/memory.c + * + * Handle buffers allocated by other kernel space driver and mmaped into user + * space, function Ignore the VM_PFNMAP and VM_IO flag in VMA structure + * + * Get physical pages from user space virtual address and update into page list + */ +static int __get_pfnmap_pages(struct task_struct *tsk, struct mm_struct *mm, + unsigned long start, int nr_pages, + unsigned int gup_flags, struct page **pages, + struct vm_area_struct **vmas) +{ + int i, ret; + unsigned long vm_flags; + + if (nr_pages <= 0) + return 0; + + VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET)); + + /* + * Require read or write permissions. + * If FOLL_FORCE is set, we only require the "MAY" flags. + */ + vm_flags = (gup_flags & FOLL_WRITE) ? + (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD); + vm_flags &= (gup_flags & FOLL_FORCE) ? + (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE); + i = 0; + + do { + struct vm_area_struct *vma; + + vma = find_vma(mm, start); + if (!vma) { + v4l2_err(&atomisp_dev, "find_vma failed\n"); + return i ? : -EFAULT; + } + + if (is_vm_hugetlb_page(vma)) { + /* + i = follow_hugetlb_page(mm, vma, pages, vmas, + &start, &nr_pages, i, gup_flags); + */ + continue; + } + + do { + struct page *page; + unsigned long pfn; + + /* + * If we have a pending SIGKILL, don't keep faulting + * pages and potentially allocating memory. + */ + if (unlikely(fatal_signal_pending(current))) { + v4l2_err(&atomisp_dev, + "fatal_signal_pending in %s\n", + __func__); + return i ? i : -ERESTARTSYS; + } + + ret = follow_pfn(vma, start, &pfn); + if (ret) { + v4l2_err(&atomisp_dev, + "follow_pfn() failed\n"); + return i ? : -EFAULT; + } + + page = pfn_to_page(pfn); + if (IS_ERR(page)) + return i ? i : PTR_ERR(page); + if (pages) { + pages[i] = page; + + flush_anon_page(vma, page, start); + flush_dcache_page(page); + } + if (vmas) + vmas[i] = vma; + i++; + start += PAGE_SIZE; + nr_pages--; + } while (nr_pages && start < vma->vm_end); + } while (nr_pages); + return i; +} + +static int get_pfnmap_pages(struct task_struct *tsk, struct mm_struct *mm, + unsigned long start, int nr_pages, int write, int force, + struct page **pages, struct vm_area_struct **vmas) +{ + int flags = FOLL_TOUCH; + + if (pages) + flags |= FOLL_GET; + if (write) + flags |= FOLL_WRITE; + if (force) + flags |= FOLL_FORCE; + + return __get_pfnmap_pages(tsk, mm, start, nr_pages, flags, pages, vmas); +} + +/* + * Convert user space virtual address into pages list + */ +static int alloc_user_pages(struct hmm_buffer_object *bo, + unsigned int userptr, bool cached) +{ + unsigned int page_nr; + unsigned int i; + struct page_block *pgblk; + struct vm_area_struct *vma; + int ret; + + bo->pages = kzalloc(sizeof(struct page *) * bo->pgnr, GFP_KERNEL); + if (unlikely(!bo->pages)) { + v4l2_err(&atomisp_dev, "out of memory for bo->pages...\n"); + return -ENOMEM; + } + + mutex_unlock(&bo->mutex); + down_read(¤t->mm->mmap_sem); + vma = find_vma(current->mm, userptr); + up_read(¤t->mm->mmap_sem); + if (vma == NULL) { + v4l2_err(&atomisp_dev, "find_vma failed\n"); + return -EFAULT; + } + mutex_lock(&bo->mutex); + /* + * Handle frame buffer allocated in other kerenl space driver + * and map to user space + */ + if (vma->vm_flags & (VM_IO | VM_PFNMAP)) { + page_nr = get_pfnmap_pages(current, current->mm, + (unsigned long)userptr, + (int)(bo->pgnr), 1, 0, + bo->pages, NULL); + bo->mem_type = HMM_BO_MEM_TYPE_PFN; + } else { + /*Handle frame buffer allocated in user space*/ + mutex_unlock(&bo->mutex); + down_read(¤t->mm->mmap_sem); + page_nr = get_user_pages(current, current->mm, + (unsigned long)userptr, + (int)(bo->pgnr), 1, 0, bo->pages, + NULL); + up_read(¤t->mm->mmap_sem); + mutex_lock(&bo->mutex); + bo->mem_type = HMM_BO_MEM_TYPE_USER; + } + + /* can be written by caller, not forced */ + if (page_nr != bo->pgnr) { + v4l2_err(&atomisp_dev, + "get_user_pages err: bo->pgnr = %d, " + "pgnr actually pinned = %d.\n", + bo->pgnr, page_nr); + return -ENOMEM; + } + + pgblk = kzalloc(sizeof(*pgblk) * bo->pgnr, GFP_KERNEL); + if (unlikely(!pgblk)) { + v4l2_err(&atomisp_dev, "out of memory for pgblk\n"); + goto out_of_mem; + } + + for (i = 0; i < bo->pgnr; i++) { + INIT_LIST_HEAD(&pgblk->list); + pgblk->pages = bo->pages[i]; + pgblk->order = 0; + + list_add_tail(&pgblk->list, &bo->pgblocks); + pgblk++; + } + return 0; + +out_of_mem: + ret = -ENOMEM; + while (!list_empty(&bo->pgblocks)) { + pgblk = list_first_entry(&bo->pgblocks, + struct page_block, list); + + list_del(&pgblk->list); + + kfree(pgblk); + } + + return ret; +} + +static void free_user_pages(struct hmm_buffer_object *bo) +{ + struct page_block *pgblk, *head; + head = list_first_entry(&bo->pgblocks, + struct page_block, list); + + while (!list_empty(&bo->pgblocks)) { + pgblk = list_first_entry(&bo->pgblocks, + struct page_block, list); + if (bo->mem_type == HMM_BO_MEM_TYPE_USER) + put_page(pgblk->pages); + + list_del(&pgblk->list); + } + + kfree(head); + kfree(bo->pages); +} + +/* + * allocate/free physical pages for the bo. + * + * type indicate where are the pages from. currently we have 3 types + * of memory: HMM_BO_PRIVATE, HMM_BO_USER, HMM_BO_SHARE. + * + * from_highmem is only valid when type is HMM_BO_PRIVATE, it will + * try to alloc memory from highmem if from_highmem is set. + * + * userptr is only valid when type is HMM_BO_USER, it indicates + * the start address from user space task. + * + * from_highmem and userptr will both be ignored when type is + * HMM_BO_SHARE. + */ +int hmm_bo_alloc_pages(struct hmm_buffer_object *bo, + enum hmm_bo_type type, int from_highmem, + unsigned int userptr, bool cached) +{ + int ret; + + check_bo_null_return(bo, -EINVAL); + + mutex_lock(&bo->mutex); + + check_bo_status_no_goto(bo, HMM_BO_PAGE_ALLOCED, status_err); + + /* + * TO DO: + * add HMM_BO_USER type + */ + if (type == HMM_BO_PRIVATE) + ret = alloc_private_pages(bo, from_highmem, cached); + else if (type == HMM_BO_USER) + ret = alloc_user_pages(bo, userptr, cached); + else { + v4l2_err(&atomisp_dev, "invalid buffer type.\n"); + ret = -EINVAL; + } + + if (ret) + goto alloc_err; + + bo->type = type; + + bo->status |= HMM_BO_PAGE_ALLOCED; + + mutex_unlock(&bo->mutex); + + return 0; + +alloc_err: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, "alloc pages err...\n"); + return ret; +status_err: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, + "buffer object has already page allocated.\n"); + return -EINVAL; +} + +/* + * free physical pages of the bo. + */ +void hmm_bo_free_pages(struct hmm_buffer_object *bo) +{ + check_bo_null_return(bo, (void)0); + + mutex_lock(&bo->mutex); + + check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err2); + + if (bo->type == HMM_BO_PRIVATE) + free_private_pages(bo); + else if (bo->type == HMM_BO_USER) + free_user_pages(bo); + else + v4l2_err(&atomisp_dev, "invalid buffer type.\n"); + /* clear the flag anyway. */ + bo->status &= (~HMM_BO_PAGE_ALLOCED); + + mutex_unlock(&bo->mutex); + + return; + +status_err2: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, + "buffer object not page allocated yet.\n"); + +} + +int hmm_bo_page_allocated(struct hmm_buffer_object *bo) +{ + int ret; + + check_bo_null_return(bo, 0); + + mutex_lock(&bo->mutex); + + ret = bo->status & HMM_BO_PAGE_ALLOCED; + + mutex_unlock(&bo->mutex); + + return ret; +} + +/* + * get physical page info of the bo. + */ +int hmm_bo_get_page_info(struct hmm_buffer_object *bo, + struct page ***pages, int *pgnr) +{ + check_bo_null_return(bo, -EINVAL); + + mutex_lock(&bo->mutex); + + check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err); + + *pages = bo->pages; + *pgnr = bo->pgnr; + + mutex_unlock(&bo->mutex); + + return 0; + +status_err: + v4l2_err(&atomisp_dev, + "buffer object not page allocated yet.\n"); + mutex_unlock(&bo->mutex); + return -EINVAL; +} + +/* + * bind the physical pages to a virtual address space. + */ +int hmm_bo_bind(struct hmm_buffer_object *bo) +{ + int ret; + unsigned int virt; + struct hmm_bo_device *bdev; + unsigned int i; + + check_bo_null_return(bo, -EINVAL); + + mutex_lock(&bo->mutex); + + check_bo_status_yes_goto(bo, + HMM_BO_PAGE_ALLOCED | HMM_BO_VM_ALLOCED, + status_err1); + + check_bo_status_no_goto(bo, HMM_BO_BINDED, status_err2); + + bdev = bo->bdev; + + virt = bo->vm_node->start; + + for (i = 0; i < bo->pgnr; i++) { + ret = + isp_mmu_map(&bdev->mmu, virt, page_to_phys(bo->pages[i]), + 1); + if (ret) + goto map_err; + virt += (1 << PAGE_SHIFT); + } + + /* + * flush TBL here. + * + * theoretically, we donot need to flush TLB as we didnot change + * any existed address mappings, but for Silicon Hive's MMU, its + * really a bug here. I guess when fetching PTEs (page table entity) + * to TLB, its MMU will fetch additional INVALID PTEs automatically + * for performance issue. EX, we only set up 1 page address mapping, + * meaning updating 1 PTE, but the MMU fetches 4 PTE at one time, + * so the additional 3 PTEs are invalid. + */ + isp_mmu_flush_tlb_range(&bdev->mmu, bo->vm_node->start, + (bo->pgnr << PAGE_SHIFT)); + + bo->status |= HMM_BO_BINDED; + + mutex_unlock(&bo->mutex); + + return 0; + +map_err: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, + "setup MMU address mapping failed.\n"); + return ret; + +status_err2: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, "buffer object already binded.\n"); + return -EINVAL; +status_err1: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, + "buffer object vm_node or page not allocated.\n"); + return -EINVAL; +} + +/* + * unbind the physical pages with related virtual address space. + */ +void hmm_bo_unbind(struct hmm_buffer_object *bo) +{ + unsigned int virt; + struct hmm_bo_device *bdev; + unsigned int i; + + check_bo_null_return(bo, (void)0); + + mutex_lock(&bo->mutex); + + check_bo_status_yes_goto(bo, + HMM_BO_PAGE_ALLOCED | + HMM_BO_VM_ALLOCED | + HMM_BO_BINDED, status_err); + + bdev = bo->bdev; + + virt = bo->vm_node->start; + + for (i = 0; i < bo->pgnr; i++) { + isp_mmu_unmap(&bdev->mmu, virt, 1); + virt += pgnr_to_size(1); + } + + /* + * flush TLB as the address mapping has been removed and + * related TLBs should be invalidated. + */ + isp_mmu_flush_tlb_range(&bdev->mmu, bo->vm_node->start, + (bo->pgnr << PAGE_SHIFT)); + + bo->status &= (~HMM_BO_BINDED); + + mutex_unlock(&bo->mutex); + + return; + +status_err: + mutex_unlock(&bo->mutex); + v4l2_err(&atomisp_dev, + "buffer vm or page not allocated or not binded yet.\n"); +} + +int hmm_bo_binded(struct hmm_buffer_object *bo) +{ + int ret; + + check_bo_null_return(bo, 0); + + mutex_lock(&bo->mutex); + + ret = bo->status & HMM_BO_BINDED; + + mutex_unlock(&bo->mutex); + + return ret; +} + +void *hmm_bo_vmap(struct hmm_buffer_object *bo) +{ + check_bo_null_return(bo, NULL); + + return vmap(bo->pages, bo->pgnr, VM_MAP, PAGE_KERNEL_NOCACHE); +} + +void hmm_bo_ref(struct hmm_buffer_object *bo) +{ + check_bo_null_return(bo, (void)0); + + kref_get(&bo->kref); +} + +static void kref_hmm_bo_release(struct kref *kref) +{ + if (!kref) + return; + + hmm_bo_release(kref_to_hmm_bo(kref)); +} + +void hmm_bo_unref(struct hmm_buffer_object *bo) +{ + check_bo_null_return(bo, (void)0); + + kref_put(&bo->kref, kref_hmm_bo_release); +} + +static void hmm_bo_vm_open(struct vm_area_struct *vma) +{ + struct hmm_buffer_object *bo = + (struct hmm_buffer_object *)vma->vm_private_data; + + check_bo_null_return(bo, (void)0); + + hmm_bo_ref(bo); + + mutex_lock(&bo->mutex); + + bo->status |= HMM_BO_MMAPED; + + bo->mmap_count++; + + mutex_unlock(&bo->mutex); +} + +static void hmm_bo_vm_close(struct vm_area_struct *vma) +{ + struct hmm_buffer_object *bo = + (struct hmm_buffer_object *)vma->vm_private_data; + + check_bo_null_return(bo, (void)0); + + hmm_bo_unref(bo); + + mutex_lock(&bo->mutex); + + bo->mmap_count--; + + if (!bo->mmap_count) { + bo->status &= (~HMM_BO_MMAPED); + vma->vm_private_data = NULL; + } + + mutex_unlock(&bo->mutex); +} + +static const struct vm_operations_struct hmm_bo_vm_ops = { + .open = hmm_bo_vm_open, + .close = hmm_bo_vm_close, +}; + +/* + * mmap the bo to user space. + */ +int hmm_bo_mmap(struct vm_area_struct *vma, struct hmm_buffer_object *bo) +{ + unsigned int start, end; + unsigned int virt; + unsigned int pgnr, i; + unsigned int pfn; + + check_bo_null_return(bo, -EINVAL); + + check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err); + + pgnr = bo->pgnr; + start = vma->vm_start; + end = vma->vm_end; + + /* + * check vma's virtual address space size and buffer object's size. + * must be the same. + */ + if ((start + pgnr_to_size(pgnr)) != end) { + v4l2_warn(&atomisp_dev, + "vma's address space size not equal" + " to buffer object's size"); + return -EINVAL; + } + + virt = vma->vm_start; + for (i = 0; i < pgnr; i++) { + pfn = page_to_pfn(bo->pages[i]); + if (remap_pfn_range(vma, virt, pfn, PAGE_SIZE, PAGE_SHARED)) { + v4l2_warn(&atomisp_dev, + "remap_pfn_range failed:" + " virt = 0x%x, pfn = 0x%x," + " mapped_pgnr = %d\n", virt, pfn, 1); + return -EINVAL; + } + virt += PAGE_SIZE; + } + + vma->vm_private_data = bo; + + vma->vm_ops = &hmm_bo_vm_ops; + vma->vm_flags |= (VM_RESERVED | VM_IO); + + /* + * call hmm_bo_vm_open explictly. + */ + hmm_bo_vm_open(vma); + + return 0; + +status_err: + v4l2_err(&atomisp_dev, + "buffer page not allocated yet.\n"); + return -EINVAL; +} diff --git a/drivers/media/video/atomisp/hmm/hmm_bo_dev.c b/drivers/media/video/atomisp/hmm/hmm_bo_dev.c new file mode 100644 index 0000000..d3e5ddf --- /dev/null +++ b/drivers/media/video/atomisp/hmm/hmm_bo_dev.c @@ -0,0 +1,279 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#include +#include +#include +#include /* for GFP_ATOMIC */ +#include /* for kmalloc */ +#include +#include +#include +#include +#include + +#include "hmm/hmm_common.h" +#include "hmm/hmm_bo_dev.h" +#include "hmm/hmm_bo.h" +#include "atomisp_internal.h" + +/* + * hmm_bo_device functions. + */ +int hmm_bo_device_init(struct hmm_bo_device *bdev, + struct isp_mmu_driver *mmu_driver, + unsigned int vaddr_start, unsigned int size) +{ + int ret; + + check_bodev_null_return(bdev, -EINVAL); + + ret = isp_mmu_init(&bdev->mmu, mmu_driver); + if (ret) { + v4l2_err(&atomisp_dev, "isp_mmu_init failed.\n"); + goto isp_mmu_init_err; + } + + ret = hmm_vm_init(&bdev->vaddr_space, vaddr_start, size); + if (ret) { + v4l2_err(&atomisp_dev, "hmm_vm_init falied. " + "vaddr_start = 0x%x, size = %d\n", vaddr_start, + size); + goto vm_init_err; + } + + INIT_LIST_HEAD(&bdev->free_bo_list); + INIT_LIST_HEAD(&bdev->active_bo_list); + + mutex_init(&bdev->fblist_mutex); + mutex_init(&bdev->ablist_mutex); + + bdev->flag = HMM_BO_DEVICE_INITED; + + return 0; + +vm_init_err: + isp_mmu_exit(&bdev->mmu); +isp_mmu_init_err: + return ret; +} + +void hmm_bo_device_exit(struct hmm_bo_device *bdev) +{ + check_bodev_null_return(bdev, (void)0); + + /* + * destroy all bos in the bo list, even they are in use. + */ + if (!list_empty(&bdev->active_bo_list)) + v4l2_warn(&atomisp_dev, + "there're still activated bo in use. " + "force to free them.\n"); + + while (!list_empty(&bdev->active_bo_list)) + hmm_bo_unref(list_to_hmm_bo(bdev->active_bo_list.next)); + + if (!list_empty(&bdev->free_bo_list)) + v4l2_warn(&atomisp_dev, + "there're still bo in free_bo_list. " + "force to free them.\n"); + + while (!list_empty(&bdev->free_bo_list)) + hmm_bo_unref(list_to_hmm_bo(bdev->free_bo_list.next)); + + isp_mmu_exit(&bdev->mmu); + hmm_vm_clean(&bdev->vaddr_space); +} + +int hmm_bo_device_inited(struct hmm_bo_device *bdev) +{ + check_bodev_null_return(bdev, -EINVAL); + + return bdev->flag == HMM_BO_DEVICE_INITED; +} + +/* + * find the buffer object with virtual address vaddr. + * return NULL if no such buffer object found. + */ +struct hmm_buffer_object *hmm_bo_device_search_start(struct hmm_bo_device *bdev, + unsigned int vaddr) +{ + struct list_head *pos; + struct hmm_buffer_object *bo; + + check_bodev_null_return(bdev, NULL); + + mutex_lock(&bdev->ablist_mutex); + list_for_each(pos, &bdev->active_bo_list) { + bo = list_to_hmm_bo(pos); + /* pass bo which has no vm_node allocated */ + if (!hmm_bo_vm_allocated(bo)) + continue; + if (bo->vm_node->start == vaddr) + goto found; + } + mutex_unlock(&bdev->ablist_mutex); + return NULL; +found: + mutex_unlock(&bdev->ablist_mutex); + return bo; +} + +static int in_range(unsigned int start, unsigned int size, unsigned int addr) +{ + return (start <= addr) && (start + size > addr); +} + +struct hmm_buffer_object *hmm_bo_device_search_in_range(struct hmm_bo_device + *bdev, + unsigned int vaddr) +{ + struct list_head *pos; + struct hmm_buffer_object *bo; + + check_bodev_null_return(bdev, NULL); + + mutex_lock(&bdev->fblist_mutex); + list_for_each(pos, &bdev->active_bo_list) { + bo = list_to_hmm_bo(pos); + /* pass bo which has no vm_node allocated */ + if (!hmm_bo_vm_allocated(bo)) + continue; + if (in_range(bo->vm_node->start, bo->vm_node->size, vaddr)) + goto found; + } + mutex_unlock(&bdev->fblist_mutex); + return NULL; +found: + mutex_unlock(&bdev->fblist_mutex); + return bo; +} + +/* + * find a buffer object with pgnr pages from free_bo_list and + * activate it (remove from free_bo_list and add to + * active_bo_list) + * + * return NULL if no such buffer object found. + */ +struct hmm_buffer_object *hmm_bo_device_get_bo(struct hmm_bo_device *bdev, + unsigned int pgnr) +{ + struct list_head *pos; + struct hmm_buffer_object *bo; + + check_bodev_null_return(bdev, NULL); + + mutex_lock(&bdev->fblist_mutex); + list_for_each(pos, &bdev->free_bo_list) { + bo = list_to_hmm_bo(pos); + if (bo->pgnr == pgnr) + goto found; + } + mutex_unlock(&bdev->fblist_mutex); + return NULL; +found: + list_del(&bo->list); + mutex_unlock(&bdev->fblist_mutex); + + mutex_lock(&bdev->ablist_mutex); + list_add(&bo->list, &bdev->active_bo_list); + mutex_unlock(&bdev->ablist_mutex); + + return bo; +} + +/* + * destroy all buffer objects in the free_bo_list. + */ +void hmm_bo_device_destroy_free_bo_list(struct hmm_bo_device *bdev) +{ + struct hmm_buffer_object *bo; + + check_bodev_null_return(bdev, (void)0); + + mutex_lock(&bdev->fblist_mutex); + while (!list_empty(&bdev->free_bo_list)) { + bo = list_first_entry(&bdev->free_bo_list, + struct hmm_buffer_object, list); + + list_del(&bo->list); + hmm_bo_unref(bo); + } + mutex_unlock(&bdev->fblist_mutex); +} + +/* + * destroy buffer object with start virtual address vaddr. + */ +void hmm_bo_device_destroy_free_bo_addr(struct hmm_bo_device *bdev, + unsigned int vaddr) +{ + struct list_head *pos; + struct hmm_buffer_object *bo; + + check_bodev_null_return(bdev, (void)0); + + mutex_lock(&bdev->fblist_mutex); + list_for_each(pos, &bdev->free_bo_list) { + bo = list_to_hmm_bo(pos); + /* pass bo which has no vm_node allocated */ + if (!hmm_bo_vm_allocated(bo)) + continue; + if (bo->vm_node->start == vaddr) + goto found; + } + mutex_unlock(&bdev->fblist_mutex); + return; +found: + list_del(&bo->list); + mutex_unlock(&bdev->fblist_mutex); + hmm_bo_unref(bo); +} + +/* + * destroy all buffer objects with pgnr pages. + */ +void hmm_bo_device_destroy_free_bo_size(struct hmm_bo_device *bdev, + unsigned int pgnr) +{ + struct list_head *pos; + struct hmm_buffer_object *bo; + + check_bodev_null_return(bdev, (void)0); + +retry: + mutex_lock(&bdev->fblist_mutex); + list_for_each(pos, &bdev->free_bo_list) { + bo = list_to_hmm_bo(pos); + if (bo->pgnr == pgnr) + goto found; + } + mutex_unlock(&bdev->fblist_mutex); + return; +found: + list_del(&bo->list); + mutex_unlock(&bdev->fblist_mutex); + hmm_bo_unref(bo); + goto retry; +} diff --git a/drivers/media/video/atomisp/hmm/hmm_vm.c b/drivers/media/video/atomisp/hmm/hmm_vm.c new file mode 100644 index 0000000..5bac810 --- /dev/null +++ b/drivers/media/video/atomisp/hmm/hmm_vm.c @@ -0,0 +1,210 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +/* + * This file contains function for ISP virtual address management in ISP driver + */ +#include +#include +#include +#include +#include + +#include "mmu/isp_mmu.h" +#include "hmm/hmm_vm.h" +#include "hmm/hmm_common.h" +#include "atomisp_internal.h" + +static unsigned int vm_node_end(unsigned int start, unsigned int pgnr) +{ + return start + pgnr_to_size(pgnr); +} + +static int addr_in_vm_node(unsigned int addr, + struct hmm_vm_node *node) +{ + return (addr >= node->start) && (addr < (node->start + node->size)); +} + +int hmm_vm_init(struct hmm_vm *vm, unsigned int start, + unsigned int size) +{ + if (!vm) + return -1; + + vm->start = start; + vm->pgnr = size_to_pgnr_ceil(size); + vm->size = pgnr_to_size(vm->pgnr); + + INIT_LIST_HEAD(&vm->vm_node_list); + spin_lock_init(&vm->lock); + + return 0; +} + +void hmm_vm_clean(struct hmm_vm *vm) +{ + if (!vm) + return; + + while (!list_empty(&vm->vm_node_list)) + hmm_vm_free_node(hmm_vm_node(vm->vm_node_list.next)); +} + +static struct hmm_vm_node *alloc_hmm_vm_node(unsigned int start, + unsigned int pgnr, + struct hmm_vm *vm) +{ + struct hmm_vm_node *node; + + node = kzalloc(sizeof(struct hmm_vm_node), GFP_KERNEL); + if (!node) { + v4l2_err(&atomisp_dev, "out of memory.\n"); + return NULL; + } + + INIT_LIST_HEAD(&node->list); + node->start = start; + node->pgnr = pgnr; + node->size = pgnr_to_size(pgnr); + node->vm = vm; + + return node; +} + +struct hmm_vm_node *hmm_vm_alloc_node(struct hmm_vm *vm, unsigned int pgnr) +{ + struct list_head *head, *p, *pos; + struct hmm_vm_node *node, *cur, *next; + unsigned int vm_start, vm_end; + unsigned int addr; + unsigned int size; + + if (!vm) + return NULL; + + vm_start = vm->start; + vm_end = vm_node_end(vm->start, vm->pgnr); + size = pgnr_to_size(pgnr); + + addr = vm_start; + pos = head = &vm->vm_node_list; + + spin_lock(&vm->lock); + + /* + * if list is empty, the loop code will not be executed. + */ + list_for_each(p, head) { + pos = p; + cur = hmm_vm_node(pos); + addr = vm_node_end(cur->start, cur->pgnr); + if (pos->next != head) { + next = hmm_vm_node(pos->next); + if ((next->start - addr) >= size) + goto found; + } + } + + if (addr + size > vm_end) { + v4l2_info(&atomisp_dev, + "no enough virtual address space.\n"); + goto failed; + } + +found: + + spin_unlock(&vm->lock); + node = alloc_hmm_vm_node(addr, pgnr, vm); + if (!node) + goto failed; + + spin_lock(&vm->lock); + list_add(&node->list, pos); + + spin_unlock(&vm->lock); + + return node; +failed: + v4l2_err(&atomisp_dev, "failed...\n"); + spin_unlock(&vm->lock); + + return NULL; +} + +void hmm_vm_free_node(struct hmm_vm_node *node) +{ + if (node) { + struct hmm_vm *vm = node->vm; + spin_lock(&vm->lock); + list_del(&node->list); + spin_unlock(&vm->lock); + kfree(node); + } +} + +struct hmm_vm_node *hmm_vm_find_node_start(struct hmm_vm *vm, unsigned int addr) +{ + struct list_head *pos; + struct hmm_vm_node *node; + + if (!vm) + return NULL; + + spin_lock(&vm->lock); + + list_for_each(pos, &vm->vm_node_list) { + node = hmm_vm_node(pos); + if (node->start == addr) + goto found; + } + + spin_unlock(&vm->lock); + return NULL; +found: + spin_unlock(&vm->lock); + return node; +} + +struct hmm_vm_node *hmm_vm_find_node_in_range(struct hmm_vm *vm, + unsigned int addr) +{ + struct list_head *pos; + struct hmm_vm_node *node; + + if (!vm) + return NULL; + + spin_lock(&vm->lock); + + list_for_each(pos, &vm->vm_node_list) { + node = hmm_vm_node(pos); + if (addr_in_vm_node(addr, node)) + goto found; + } + + spin_unlock(&vm->lock); + return NULL; +found: + spin_unlock(&vm->lock); + return node; +} diff --git a/drivers/media/video/atomisp/hrt/hive_isp_css_custom_host_hrt.h b/drivers/media/video/atomisp/hrt/hive_isp_css_custom_host_hrt.h new file mode 100644 index 0000000..c47ff26 --- /dev/null +++ b/drivers/media/video/atomisp/hrt/hive_isp_css_custom_host_hrt.h @@ -0,0 +1,102 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#ifndef _hive_isp_css_custom_host_hrt_h_ +#define _hive_isp_css_custom_host_hrt_h_ + +#include "atomisp_cmd.h" + + +#define _hrt_master_port_store_8(a, d) \ + (*((__iomem s8 *)atomisp_get_io_virt_addr((unsigned int)(a))) = (d)) + +#define _hrt_master_port_store_16(a, d) \ + (*((__iomem s16 *)atomisp_get_io_virt_addr((unsigned int)(a))) = (d)) + +#define _hrt_master_port_store_32(a, d) \ + (*((__iomem s32 *)atomisp_get_io_virt_addr((unsigned int)(a))) = (d)) + +#define _hrt_master_port_load_8(a) \ + (*(__iomem s8 *)atomisp_get_io_virt_addr((unsigned int)(a))) + +#define _hrt_master_port_load_16(a) \ + (*(__iomem s16 *)atomisp_get_io_virt_addr((unsigned int)(a))) + +#define _hrt_master_port_load_32(a) \ + (*(__iomem s32 *)atomisp_get_io_virt_addr((unsigned int)(a))) + +#define _hrt_master_port_uload_8(a) \ + (*(__iomem u8 *)atomisp_get_io_virt_addr((unsigned int)(a))) + +#define _hrt_master_port_uload_16(a) \ + (*(__iomem u16 *)atomisp_get_io_virt_addr((unsigned int)(a))) + +#define _hrt_master_port_uload_32(a) \ + (*(__iomem u32 *)atomisp_get_io_virt_addr((unsigned int)(a))) + +#define _hrt_master_port_store_8_volatile(a, d) _hrt_master_port_store_8(a, d) +#define _hrt_master_port_store_16_volatile(a, d) _hrt_master_port_store_16(a, d) +#define _hrt_master_port_store_32_volatile(a, d) _hrt_master_port_store_32(a, d) + +#define _hrt_master_port_load_8_volatile(a) _hrt_master_port_load_8(a) +#define _hrt_master_port_load_16_volatile(a) _hrt_master_port_load_16(a) +#define _hrt_master_port_load_32_volatile(a) _hrt_master_port_load_32(a) + +#define _hrt_master_port_uload_8_volatile(a) _hrt_master_port_uload_8(a) +#define _hrt_master_port_uload_16_volatile(a) _hrt_master_port_uload_16(a) +#define _hrt_master_port_uload_32_volatile(a) _hrt_master_port_uload_32(a) + +static inline void hrt_sleep(void) +{ + udelay(1); +} + +static inline void *_hrt_mem_store(void *to, const void *from, size_t n) +{ + unsigned i; + unsigned int _to = (unsigned int)to; + const char *_from = (const char *)from; + for (i = 0; i < n; i++, _to++, _from++) + _hrt_master_port_store_8(_to, *_from); + return (void *)_to; +} + +static inline void *_hrt_mem_load(const void *from, void *to, size_t n) +{ + unsigned i; + char *_to = (char *)to; + unsigned int _from = (unsigned int)from; + for (i = 0; i < n; i++, _to++, _from++) + *_to = _hrt_master_port_load_8(_from); + return _to; +} + +static inline void *_hrt_mem_set(void *to, int c, size_t n) +{ + unsigned i; + unsigned int _to = (unsigned int)to; + for (i = 0; i < n; i++, _to++) + _hrt_master_port_store_8(_to, c); + return (void *)_to; +} + +#endif /* _hive_isp_css_custom_host_hrt_h_ */ diff --git a/drivers/media/video/atomisp/hrt/hive_isp_css_mm_hrt.c b/drivers/media/video/atomisp/hrt/hive_isp_css_mm_hrt.c new file mode 100644 index 0000000..daa076d --- /dev/null +++ b/drivers/media/video/atomisp/hrt/hive_isp_css_mm_hrt.c @@ -0,0 +1,179 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#include + +/* not sure if we need these two for page related macros, + * need to double check */ + +#include +#include +#include "atomisp_internal.h" + +#define __page_align(size) (((size) + (PAGE_SIZE-1)) & (~(PAGE_SIZE-1))) + +static unsigned init_done; +void hrt_isp_css_mm_init(void) +{ + hmm_init(); + init_done = 1; +} + +int hrt_isp_css_mm_set(void *virt_addr, int c, size_t bytes) +{ + if (virt_addr) + return hmm_set(virt_addr, c, bytes); + + return -EINVAL; +} + +int hrt_isp_css_mm_load(void *virt_addr, void *data, size_t bytes) +{ + if (virt_addr) + return hmm_load(virt_addr, data, bytes); + return -EINVAL; +} + +int hrt_isp_css_mm_store(void *virt_addr, const void *data, size_t bytes) +{ + if (virt_addr) + return hmm_store(virt_addr, data, bytes); + return -EINVAL; +} + +void hrt_isp_css_mm_free(void *virt_addr) +{ + if (virt_addr) + hmm_free(virt_addr); +} + +void hrt_isp_css_mm_clear(void) +{ + if (init_done) { + hmm_cleanup(); + init_done = 0; + } +} + +static unsigned int my_userptr, my_num_pages; +void hrt_isp_css_mm_set_user_ptr(unsigned int userptr, unsigned int num_pages) +{ + my_userptr = userptr; + my_num_pages = num_pages; +} + +void *hrt_isp_css_mm_alloc(size_t bytes) +{ + if (!init_done) + hrt_isp_css_mm_init(); + + if (my_userptr == 0) + return (void *)hmm_alloc(bytes, HMM_BO_PRIVATE, 0, 0, + HMM_UNCACHED); + else { + if (my_num_pages < ((__page_align(bytes)) >> PAGE_SHIFT)) + v4l2_err(&atomisp_dev, + "user space memory size is less" + " than the expected size..\n"); + else if (my_num_pages > ((__page_align(bytes)) >> PAGE_SHIFT)) + v4l2_err(&atomisp_dev, + "user space memory size is" + " large than the expected size..\n"); + + return (void *)hmm_alloc(bytes, HMM_BO_USER, 0, + my_userptr, HMM_UNCACHED); + } +} + +void *hrt_isp_css_mm_alloc_cached(size_t bytes) +{ + if (!init_done) + hrt_isp_css_mm_init(); + + if (my_userptr == 0) + return (void *)hmm_alloc(bytes, HMM_BO_PRIVATE, 0, 0, + HMM_CACHED); + else { + if (my_num_pages < ((__page_align(bytes)) >> PAGE_SHIFT)) + v4l2_err(&atomisp_dev, + "user space memory size is less" + " than the expected size..\n"); + else if (my_num_pages > ((__page_align(bytes)) >> PAGE_SHIFT)) + v4l2_err(&atomisp_dev, + "user space memory size is" + " large than the expected size..\n"); + + return (void *)hmm_alloc(bytes, HMM_BO_USER, 0, + my_userptr, HMM_CACHED); + } +} + +void *hrt_isp_css_mm_calloc(size_t bytes) +{ + void *ptr = hrt_isp_css_mm_alloc(bytes); + if (!ptr) + hmm_set(ptr, 0, bytes); + return ptr; +} + +void *hrt_isp_css_mm_calloc_cached(size_t bytes) +{ + void *ptr = hrt_isp_css_mm_alloc_cached(bytes); + if (!ptr) + hmm_set(ptr, 0, bytes); + return ptr; +} + +int hrt_isp_css_mm_load_int(void *virt_addr, int *data) +{ + return hrt_isp_css_mm_load(virt_addr, data, sizeof(*data)); +} + +int hrt_isp_css_mm_load_short(void *virt_addr, short *data) +{ + return hrt_isp_css_mm_load(virt_addr, data, sizeof(*data)); +} + +int hrt_isp_css_mm_load_char(void *virt_addr, char *data) +{ + return hrt_isp_css_mm_load(virt_addr, data, sizeof(*data)); +} + +int hrt_isp_css_mm_store_char(void *virt_addr, char data) +{ + return hrt_isp_css_mm_store(virt_addr, &data, sizeof(data)); +} + +int hrt_isp_css_mm_store_short(void *virt_addr, short data) +{ + return hrt_isp_css_mm_store(virt_addr, &data, sizeof(data)); +} + +int hrt_isp_css_mm_store_int(void *virt_addr, int data) +{ + return hrt_isp_css_mm_store(virt_addr, &data, sizeof(data)); +} + +void *hrt_isp_css_virt_to_phys(void *virt_addr) +{ + return (void *)hmm_virt_to_phys(virt_addr); +} diff --git a/drivers/media/video/atomisp/include/atomisp/atomisp_internal.h b/drivers/media/video/atomisp/include/atomisp/atomisp_internal.h new file mode 100644 index 0000000..e0b5286 --- /dev/null +++ b/drivers/media/video/atomisp/include/atomisp/atomisp_internal.h @@ -0,0 +1,284 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#ifndef ATOMISP_INTERNAL_H_ +#define ATOMISP_INTERNAL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "atomisp_subdev.h" +#include "atomisp_csi2.h" +#include "atomisp_tpg.h" +#include "atomisp_file.h" + +#define MAGIC_NUMBER 0x73c5cc4 + +#define ATOMISP_MAJOR 0 +#define ATOMISP_MINOR 5 +#define ATOMISP_PATCHLEVEL 1 + +#define DRIVER_VERSION_STR __stringify(ATOMISP_MAJOR) \ + "." __stringify(ATOMISP_MINOR) "." __stringify(ATOMISP_PATCHLEVEL) +#define DRIVER_VERSION KERNEL_VERSION(ATOMISP_MAJOR, \ + ATOMISP_MINOR, ATOMISP_PATCHLEVEL) + +#define ATOM_ISP_STEP_WIDTH 4 +#define ATOM_ISP_STEP_HEIGHT 4 + +#define ATOM_ISP_MIN_WIDTH 4 +#define ATOM_ISP_MIN_HEIGHT 4 +#define ATOM_ISP_MAX_WIDTH 4352 +#define ATOM_ISP_MAX_HEIGHT 3264 + +#define ATOM_ISP_MAX_WIDTH_TMP 1280 +#define ATOM_ISP_MAX_HEIGHT_TMP 720 + +#define ATOM_ISP_I2C_BUS_1 4 +#define ATOM_ISP_I2C_BUS_2 5 + +#define ATOM_ISP_POWER_DOWN 0 +#define ATOM_ISP_POWER_UP 1 + +#define ATOM_ISP_MAX_INPUTS 4 +#define ATOMISP_ACC_FW_MAX 8 + +int atomisp_video_init(struct atomisp_video_pipe *video, const char *name); +void atomisp_video_unregister(struct atomisp_video_pipe *video); +int atomisp_video_register(struct atomisp_video_pipe *video, + struct v4l2_device *vdev); + +struct atomisp_input_subdev { + unsigned int type; + enum atomisp_camera_port port; + struct v4l2_subdev *camera; + struct v4l2_subdev *motor; + struct sh_css_morph_table *morph_table; + struct sh_css_shading_table *shading_table; +}; + +struct atomisp_hw_contex { + /*OSPM related */ + unsigned int apm_reg; + unsigned short apm_base; + unsigned int ospm_base; + + unsigned int pcicmdsts; + unsigned int ispmmadr; + unsigned int msicap; + unsigned int msi_addr; + unsigned int msi_data; + unsigned int intr; + unsigned int interrupt_control; + unsigned int pmcs; + unsigned int cg_dis; + unsigned int i_control; + unsigned int csi_rcomp_config; + unsigned int csi_afe_dly; + unsigned int csi_control; + u16 pci_cmd; + struct pci_dev *pci_dev; + + void *mmu_l1_base; +}; + +struct atomisp_sw_contex { + bool init; + bool probed; + + bool work_queued; + bool sensor_streaming; + bool isp_streaming; + + bool error; + bool bypass; + bool updating_uptr; + bool file_input; + bool grid_info_updated; + + int power_state; + int run_mode; + int output_mode; +}; + +struct atomisp_css_params { + int online_process; + int yuv_ds_en; + unsigned int color_effect; + bool gdc_cac_en; + bool macc_en; + bool bad_pixel_en; + bool video_dis_en; + bool sc_en; + bool fpn_en; + bool xnr_en; + int false_color; + unsigned int histogram_elenum; + + /* default configurations */ + const struct sh_css_dp_config *default_dp_config; + const struct sh_css_wb_config *default_wb_config; + const struct sh_css_cc_config *default_cc_config; + const struct sh_css_nr_config *default_nr_config; + const struct sh_css_ee_config *default_ee_config; + const struct sh_css_ob_config *default_ob_config; + const struct sh_css_de_config *default_de_config; + const struct sh_css_gc_config *default_gc_config; + const struct sh_css_tnr_config *default_tnr_config; + const struct sh_css_3a_config *default_3a_config; + const struct sh_css_macc_table *default_macc_table; + const struct sh_css_ctc_table *default_ctc_table; + const struct sh_css_gamma_table *default_gamma_table; + + /* current configurations */ + struct sh_css_dp_config dp_config; + struct sh_css_wb_config wb_config; + struct sh_css_cc_config cc_config; + struct sh_css_nr_config nr_config; + struct sh_css_ee_config ee_config; + struct sh_css_ob_config ob_config; + struct sh_css_de_config de_config; + struct sh_css_gc_config gc_config; + struct sh_css_tnr_config tnr_config; + struct sh_css_3a_config s3a_config; + struct sh_css_gamma_table gamma_table; + struct sh_css_ctc_table ctc_table; + struct sh_css_macc_table macc_table; + struct sh_css_overlay *vf_overlay; + /* Current grid info */ + struct sh_css_grid_info curr_grid_info; + + /* DIS coefficients, must remain alive during execution */ + int dis_x; + int dis_y; + + /* Intermediate buffers used to communicate data between + CSS and user space. These are needed to perform the + copy_to_user. */ + struct sh_css_3a_output *s3a_output_buf; + int s3a_output_bytes; + /* DIS Coefficients */ + short *dis_hor_coef_buf; + int dis_hor_coef_bytes; + short *dis_ver_coef_buf; + int dis_ver_coef_bytes; + /* DIS projections */ + int *dis_ver_proj_buf; + int dis_ver_proj_bytes; + int *dis_hor_proj_buf; + int dis_hor_proj_bytes; + + /* Flash */ + int num_flash_frames; +}; + +struct atomisp_video_pipe_format { + struct v4l2_pix_format out; + struct v4l2_pix_format in; + unsigned int out_sh_fmt; +}; + +/* + * ci device struct + */ +struct atomisp_device { + struct pci_dev *pdev; + struct device *dev; + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct atomisp_platform_data *pdata; + const struct firmware *firmware; + + struct sh_css_acc_fw *acc_fw[ATOMISP_ACC_FW_MAX]; + unsigned int acc_fw_handle; + int acc_fw_count; + struct sh_css_acc_fw *marked_fw_for_unload; + + /* ISP modules */ + struct atomisp_sub_device isp_subdev; + struct atomisp_mipi_csi2_device csi2_4p; + struct atomisp_mipi_csi2_device csi2_1p; + struct atomisp_tpg_device tpg; + struct atomisp_file_device file_dev; + + struct workqueue_struct *work_queue; + struct work_struct work; + struct completion wq_frame_complete; + struct completion dis_state_complete; + struct completion acc_fw_complete; + struct completion acc_unload_fw_complete; + + spinlock_t irq_lock; + uint32_t irq_infos; + struct mutex input_lock; + struct mutex isp_lock; + struct mutex isp3a_lock; + struct atomisp_tvnorm *tvnorm; + bool isp3a_stat_ready; + + struct atomisp_video_pipe_format *main_format; + struct atomisp_video_pipe_format *vf_format; + struct atomisp_video_pipe_format *input_format; + struct sh_css_frame *vf_frame; + struct sh_css_frame *regular_output_frame; + struct sh_css_frame *raw_output_frame; + enum atomisp_frame_status frame_status[VIDEO_MAX_FRAME]; + + int input_cnt; + int input_curr; + struct atomisp_input_subdev inputs[ATOM_ISP_MAX_INPUTS]; + struct v4l2_subdev *flash; + struct v4l2_subdev *motor; + + struct atomisp_hw_contex hw_contex; + struct atomisp_sw_contex sw_contex; + struct atomisp_css_params params; + + __u32 snr_max_width; + __u32 snr_max_height; + __u32 snr_pixelformat; +}; + +#define v4l2_dev_to_atomisp_device(dev) \ + container_of(dev, struct atomisp_device, v4l2_dev) + +extern struct v4l2_device atomisp_dev; + +extern void hrt_isp_css_mm_set_user_ptr(unsigned int userptr, + unsigned int num_pages); + +#define FW_PATH "shisp.bin" + +#endif /* ATOMISP_INTERNAL_H_ */ diff --git a/drivers/media/video/atomisp/include/atomisp/atomisp_tables.h b/drivers/media/video/atomisp/include/atomisp/atomisp_tables.h new file mode 100644 index 0000000..ddf6b75 --- /dev/null +++ b/drivers/media/video/atomisp/include/atomisp/atomisp_tables.h @@ -0,0 +1,265 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#ifndef __ATOMISP_TABLES_H__ +#define __ATOMISP_TABLES_H__ + +#include "sh_css_params.h" + +/*Sepia image effect table*/ +const struct sh_css_cc_config sepia_cc_config = { + .fraction_bits = 8, + .matrix = {141, 18, 68, -40, -5, -19, 35, 4, 16}, +}; + +/*Negative image effect table*/ +const struct sh_css_cc_config nega_cc_config = { + .fraction_bits = 8, + .matrix = {255, 29, 120, 0, 374, 342, 0, 672, -301}, +}; + +/*Mono image effect table*/ +const struct sh_css_cc_config mono_cc_config = { + .fraction_bits = 8, + .matrix = {255, 29, 120, 0, 0, 0, 0, 0, 0}, +}; + +/*Skin whiten image effect table*/ +struct sh_css_macc_table skin_low_macc_table = { + .data = { + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 7129, 0, 0, 7129, + 6684, 0, 0, 6684, + 6684, 0, 0, 6684, + 7129, 0, 0, 7129, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912 + } +}; + +struct sh_css_macc_table skin_medium_macc_table = { + .data = { + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 5792, 0, 0, 5792, + 4456, 0, 0, 4456, + 4456, 0, 0, 4456, + 5792, 0, 0, 5792, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912 + } +}; + +struct sh_css_macc_table skin_high_macc_table = { + .data = { + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 4456, 0, 0, 4456, + 2228, 0, 0, 2228, + 2228, 0, 0, 2228, + 4456, 0, 0, 4456, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912, + 8912, 0, 0, 8912 + } +}; + +/*Blue enhencement image effect table*/ +struct sh_css_macc_table blue_macc_table = { + .data = { + 14336, -7168, 0, 10240, 13312, -5120, 2048, 6144, 8192, 0, 0, + 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, + 0, 0, 8192, 8192, 0, 0, 8192, 14336, 0, 0, 14336, 18432, 8192, + -4096, 6144, 8192, 0, 0, 8192, 12288, 2048, -4096, 6144, 8192, + 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192 + } +}; + +/*Green enhencement image effect table*/ +struct sh_css_macc_table green_macc_table = { + .data = { + 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, + 8192, 10240, 4096, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, + 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, + 4096, 10240, 8192, 0, 0, 8192, 10240, 5120, 0, 12288, 9216, + 7168, -4096, 20480, 12288, 0, 5120, 10240, 20480, -4096, 7168, 9216 + } +}; + +/*Color enhancement image effect table*/ +struct sh_css_ctc_table vivid_ctc_table = { + .data = { + 876, 872, 869, 865, 861, 858, 854, 850, + 847, 843, 839, 835, 832, 828, 824, 821, + 817, 813, 810, 806, 802, 799, 795, 791, + 788, 784, 780, 777, 773, 769, 766, 762, + 758, 754, 751, 747, 743, 740, 736, 732, + 729, 725, 721, 718, 714, 710, 707, 703, + 699, 696, 692, 688, 685, 681, 677, 673, + 670, 666, 662, 659, 655, 651, 648, 644, + 640, 637, 633, 629, 626, 622, 618, 615, + 611, 607, 604, 600, 596, 592, 589, 585, + 581, 578, 574, 570, 567, 563, 559, 556, + 552, 548, 545, 541, 539, 537, 536, 534, + 533, 531, 530, 528, 527, 525, 524, 522, + 521, 519, 518, 516, 515, 514, 512, 511, + 509, 508, 506, 505, 503, 502, 500, 499, + 497, 496, 494, 493, 491, 490, 488, 487, + 485, 484, 482, 481, 479, 478, 476, 475, + 473, 472, 470, 469, 467, 466, 464, 463, + 461, 460, 458, 457, 455, 454, 452, 451, + 449, 448, 446, 445, 443, 442, 440, 439, + 437, 436, 434, 433, 431, 430, 428, 427, + 425, 424, 422, 421, 419, 418, 417, 415, + 414, 412, 411, 409, 408, 406, 405, 403, + 402, 400, 399, 397, 396, 394, 393, 392, + 392, 391, 391, 390, 389, 389, 388, 388, + 387, 387, 386, 385, 385, 384, 384, 383, + 383, 382, 381, 381, 380, 380, 379, 379, + 378, 377, 377, 376, 376, 375, 375, 374, + 374, 373, 372, 372, 371, 371, 370, 370, + 369, 368, 368, 367, 367, 366, 366, 365, + 364, 364, 363, 363, 362, 362, 361, 360, + 360, 359, 359, 358, 358, 357, 356, 356, + 355, 355, 354, 354, 353, 352, 352, 351, + 351, 350, 350, 349, 348, 348, 347, 347, + 346, 346, 345, 344, 344, 343, 343, 342, + 342, 341, 340, 340, 339, 339, 338, 338, + 337, 336, 336, 335, 335, 334, 334, 333, + 333, 332, 331, 331, 330, 330, 329, 329, + 328, 327, 327, 326, 326, 325, 325, 324, + 323, 323, 322, 322, 321, 321, 320, 319, + 319, 318, 318, 317, 317, 316, 315, 315, + 314, 314, 313, 313, 312, 311, 311, 310, + 310, 309, 309, 308, 307, 307, 306, 306, + 305, 305, 304, 303, 303, 302, 302, 301, + 301, 300, 299, 299, 298, 298, 297, 297, + 296, 296, 295, 294, 294, 293, 293, 292, + 292, 291, 290, 290, 289, 289, 288, 288, + 287, 286, 286, 285, 285, 284, 284, 283, + 282, 282, 281, 281, 280, 280, 279, 278, + 278, 277, 277, 276, 276, 275, 274, 274, + 273, 273, 272, 272, 271, 270, 270, 269, + 269, 268, 268, 267, 266, 266, 265, 265, + 264, 264, 263, 262, 262, 261, 261, 260, + 260, 259, 259, 258, 257, 257, 256, 256, + 255, 255, 254, 253, 253, 252, 252, 251, + 251, 250, 249, 249, 248, 248, 247, 247, + 246, 245, 245, 244, 244, 243, 243, 242, + 241, 241, 240, 240, 239, 239, 238, 237, + 237, 236, 236, 235, 235, 234, 233, 233, + 232, 232, 231, 231, 230, 229, 229, 228, + 228, 227, 227, 226, 225, 225, 224, 224, + 223, 223, 222, 221, 221, 220, 220, 219, + 219, 218, 218, 217, 216, 216, 215, 215, + 214, 214, 213, 212, 212, 211, 211, 210, + 210, 209, 208, 208, 207, 207, 206, 206, + 205, 204, 204, 203, 203, 202, 202, 201, + 200, 200, 199, 199, 198, 198, 197, 196, + 196, 195, 195, 194, 194, 193, 192, 192, + 191, 191, 190, 190, 189, 188, 188, 187, + 187, 186, 186, 185, 184, 184, 183, 183, + 182, 182, 181, 181, 180, 179, 179, 178, + 178, 177, 177, 176, 175, 175, 174, 174, + 173, 173, 172, 171, 171, 170, 170, 169, + 169, 168, 167, 167, 166, 166, 165, 165, + 164, 163, 163, 163, 162, 162, 161, 161, + 161, 160, 160, 159, 159, 159, 158, 158, + 158, 157, 157, 156, 156, 156, 155, 155, + 155, 154, 154, 153, 153, 153, 152, 152, + 152, 151, 151, 150, 150, 150, 149, 149, + 149, 148, 148, 147, 147, 147, 146, 146, + 145, 145, 145, 144, 144, 144, 143, 143, + 142, 142, 142, 141, 141, 141, 140, 140, + 139, 139, 139, 138, 138, 138, 137, 137, + 136, 136, 136, 135, 135, 134, 134, 134, + 133, 133, 133, 132, 132, 131, 131, 131, + 130, 130, 130, 129, 129, 128, 128, 128, + 127, 127, 127, 126, 126, 125, 125, 125, + 124, 124, 123, 123, 123, 122, 122, 122, + 121, 121, 120, 120, 120, 119, 119, 119, + 118, 118, 117, 117, 117, 116, 116, 116, + 115, 115, 114, 114, 114, 113, 113, 112, + 112, 112, 111, 111, 111, 110, 110, 109, + 109, 109, 108, 108, 108, 107, 107, 106, + 106, 106, 105, 105, 105, 104, 104, 103, + 103, 103, 102, 102, 101, 101, 101, 100, + 100, 100, 99, 99, 98, 98, 98, 97, + 97, 97, 96, 96, 95, 95, 95, 94, + 94, 94, 93, 93, 92, 92, 92, 91, + 91, 91, 90, 90, 89, 89, 89, 88, + 88, 87, 87, 87, 86, 86, 86, 85, + 85, 84, 84, 84, 83, 83, 83, 82, + 82, 81, 81, 81, 80, 80, 80, 79, + 79, 78, 78, 78, 77, 77, 76, 76, + 76, 75, 75, 75, 74, 74, 73, 73, + 73, 72, 72, 72, 71, 71, 70, 70, + 70, 69, 69, 69, 68, 68, 67, 67, + 67, 66, 66, 65, 65, 65, 64, 64, + 64, 63, 63, 61, 61, 61, 61, 61, + 61, 60, 60, 58, 58, 58, 58, 58, + 58, 57, 57, 56, 56, 56, 55, 55, + 54, 54, 54, 53, 53, 53, 51, 51, + 51, 51, 51, 50, 50, 50, 48, 48, + 48, 48, 48, 47, 47, 47, 45, 45, + 45, 45, 45, 44, 44, 42, 42, 42, + 42, 42, 42, 41, 41, 40, 40, 40, + 39, 39, 39, 38, 38, 37, 37, 37, + 35, 35, 35, 35, 35, 34, 34, 34, + 32, 32, 32, 32, 32, 31, 31, 31, + 29, 29, 29, 29, 29, 28, 28, 28, + 26, 26, 25, 25, 25, 25, 25, 25, + 24, 24, 22, 22, 22, 22, 22, 22, + 21, 21, 19, 19, 19, 19, 19, 18, + 18, 18, 16, 16, 16, 16, 16, 15, + 15, 15, 13, 13, 13, 12, 12, 12, + 12, 12, 10, 10, 10, 9, 9, 9, + 9, 9, 8, 8, 6, 6, 6, 6, + 6, 6, 5, 5, 3, 3, 3, 3, + 3, 3, 2, 2, 0, 0, 0, 0, + } +}; +#endif diff --git a/drivers/media/video/atomisp/include/atomisp/atomisp_v4l2.h b/drivers/media/video/atomisp/include/atomisp/atomisp_v4l2.h new file mode 100644 index 0000000..9ab5c8d --- /dev/null +++ b/drivers/media/video/atomisp/include/atomisp/atomisp_v4l2.h @@ -0,0 +1,58 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef ATOMISP_V4L2_H_ +#define ATOMISP_V4L2_H_ + +#include + +/* SH header files */ +#include + +#define ATOMISP_MAJOR 0 +#define ATOMISP_MINOR 5 +#define ATOMISP_PATCHLEVEL 1 + +#define DRIVER_VERSION_STR __stringify(ATOMISP_MAJOR) \ + "." __stringify(ATOMISP_MINOR) "." __stringify(ATOMISP_PATCHLEVEL) +#define DRIVER_VERSION KERNEL_VERSION(ATOMISP_MAJOR, \ + ATOMISP_MINOR, ATOMISP_PATCHLEVEL) + +/*ISP binary running mode*/ +#define CI_MODE_PREVIEW 0x8000 +#define CI_MODE_VIDEO 0x4000 +#define CI_MODE_STILL_CAPTURE 0x2000 +#define CI_MODE_NONE 0x0000 + +#define ATOM_ISP_STEP_WIDTH 2 +#define ATOM_ISP_STEP_HEIGHT 2 + +#define ATOM_ISP_MIN_WIDTH 256 +#define ATOM_ISP_MIN_HEIGHT 2 +#define ATOM_ISP_MAX_WIDTH 4352 +#define ATOM_ISP_MAX_HEIGHT 3264 + +#define ATOM_ISP_MAX_WIDTH_TMP 1280 +#define ATOM_ISP_MAX_HEIGHT_TMP 720 + +#endif /* ATOMISP_V4L2_H_ */ diff --git a/drivers/media/video/atomisp/include/hmm/hmm.h b/drivers/media/video/atomisp/include/hmm/hmm.h new file mode 100644 index 0000000..51c29cd --- /dev/null +++ b/drivers/media/video/atomisp/include/hmm/hmm.h @@ -0,0 +1,74 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __HMM_H__ +#define __HMM_H__ + +#include +#include +#include +#include + +#include "hmm/hmm_bo.h" + +#define HMM_CACHED true +#define HMM_UNCACHED false + +int hmm_init(void); +void hmm_cleanup(void); + +void *hmm_alloc(size_t bytes, enum hmm_bo_type type, + int from_highmem, unsigned int userptr, bool cached); +void hmm_free(void *ptr); +int hmm_load(void *virt, void *data, unsigned int bytes); +int hmm_store(void *virt, const void *data, unsigned int bytes); +int hmm_set(void *virt, int c, unsigned int bytes); + +/* + * get kernel memory physical address from ISP virtual address. + */ +unsigned int hmm_virt_to_phys(void *virt); + +/* + * map ISP memory starts with virt to kernel virtual address + * by using vmap. return NULL if failed. + * + * !! user needs to use vunmap to unmap it manually before calling + * hmm_free to free the memory. + * + * virt must be the start address of ISP memory (return by hmm_alloc), + * do not pass any other address. + */ +void *hmm_vmap(void *virt); + +/* + * map ISP memory starts with virt to specific vma. + * + * used for mmap operation. + * + * virt must be the start address of ISP memory (return by hmm_alloc), + * do not pass any other address. + */ +int hmm_mmap(struct vm_area_struct *vma, void *virt); + +#endif diff --git a/drivers/media/video/atomisp/include/hmm/hmm_bo.h b/drivers/media/video/atomisp/include/hmm/hmm_bo.h new file mode 100644 index 0000000..951b0a8 --- /dev/null +++ b/drivers/media/video/atomisp/include/hmm/hmm_bo.h @@ -0,0 +1,291 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __HMM_BO_H__ +#define __HMM_BO_H__ + +#include +#include +#include +#include +#include +#include +#include "hmm_common.h" +#include "hmm/hmm_vm.h" + +#define check_bo_status_yes_goto(bo, _status, label) \ + var_not_equal_goto((bo->status & (_status)), (_status), \ + label, \ + "HMM buffer status not contain %s.\n", \ + #_status) + +#define check_bo_status_no_goto(bo, _status, label) \ + var_equal_goto((bo->status & (_status)), (_status), \ + label, \ + "HMM buffer status contains %s.\n", \ + #_status) +#define list_to_hmm_bo(list_ptr) \ + list_entry((list_ptr), struct hmm_buffer_object, list) + +#define kref_to_hmm_bo(kref_ptr) \ + list_entry((kref_ptr), struct hmm_buffer_object, kref) + +#define check_bo_null_return(bo, exp) \ + check_null_return(bo, exp, "NULL hmm buffer object.\n") + +#define HMM_MAX_ORDER 3 +#define HMM_MIN_ORDER 0 + +struct hmm_bo_device; + +/* + * buffer object type. + * + * HMM_BO_PRIVATE: + * pages are allocated by driver itself. + * HMM_BO_SHARE: + * pages are allocated by other component. currently: video driver. + * HMM_BO_USER: + * pages are allocated in user space process. + * + */ +enum hmm_bo_type { + HMM_BO_PRIVATE, + HMM_BO_SHARE, + HMM_BO_USER, +}; + +#define HMM_BO_VM_ALLOCED 0x1 +#define HMM_BO_PAGE_ALLOCED 0x2 +#define HMM_BO_BINDED 0x4 +#define HMM_BO_MMAPED 0x8 +#define HMM_BO_ACTIVE 0x1000 +#define HMM_BO_MEM_TYPE_USER 0x1 +#define HMM_BO_MEM_TYPE_PFN 0x2 + +struct page_block { + struct list_head list; + struct page *pages; + int order; +}; + +struct hmm_buffer_object { + struct hmm_bo_device *bdev; + struct list_head list; + struct kref kref; + + /* mutex protecting this BO */ + struct mutex mutex; + enum hmm_bo_type type; + struct list_head pgblocks; + struct page **pages; /* physical pages */ + unsigned int pgnr; /* page number */ + int from_highmem; + int mmap_count; + struct hmm_vm_node *vm_node; + int status; + int mem_type; + + /* + * release callback for releasing buffer object. + * + * usually set to the release function to release the + * upper level buffer object which has hmm_buffer_object + * embedded in. if the hmm_buffer_object is dynamically + * created by hmm_bo_create, release will set to kfree. + * + */ + void (*release)(struct hmm_buffer_object *bo); +}; + +/* + * use this function to initialize pre-allocated hmm_buffer_object. + * + * the hmm_buffer_object use reference count to manage its life cycle. + * + * bo->kref is inited to 1. + * + * use hmm_bo_ref/hmm_bo_unref increase/decrease the reference count, + * and hmm_bo_unref will free resource of buffer object (but not the + * buffer object itself as it can be both pre-allocated or dynamically + * allocated) when reference reaches 0. + * + * see detailed description of hmm_bo_ref/hmm_bo_unref below. + * + * as hmm_buffer_object may be used as an embedded object in an upper + * level object, a release callback must be provided. if it is + * embedded in upper level object, set release call back to release + * function of that object. if no upper level object, set release + * callback to NULL. + * + * ex: + * struct hmm_buffer_object bo; + * hmm_bo_init(bdev, &bo, pgnr, NULL); + * + * or + * struct my_buffer_object { + * struct hmm_buffer_object bo; + * ... + * }; + * + * void my_buffer_release(struct hmm_buffer_object *bo) + * { + * struct my_buffer_object *my_bo = + * container_of(bo, struct my_buffer_object, bo); + * + * ... // release resource in my_buffer_object + * + * kfree(my_bo); + * } + * + * struct my_buffer_object *my_bo = + * kmalloc(sizeof(*my_bo), GFP_KERNEL); + * + * hmm_bo_init(bdev, &my_bo->bo, pgnr, my_buffer_release); + * ... + * + * hmm_bo_unref(&my_bo->bo); + */ +int hmm_bo_init(struct hmm_bo_device *bdev, + struct hmm_buffer_object *bo, + unsigned int pgnr, + void (*release)(struct hmm_buffer_object *)); + +/* + * use these functions to dynamically alloc hmm_buffer_object. + * + * hmm_bo_init will called for that allocated buffer object, and + * the release callback is set to kfree. + * + * ex: + * hmm_buffer_object *bo = hmm_bo_create(bdev, pgnr); + * ... + * hmm_bo_unref(bo); + */ +struct hmm_buffer_object *hmm_bo_create(struct hmm_bo_device *bdev, + int pgnr); + +/* + * increse buffer object reference. + */ +void hmm_bo_ref(struct hmm_buffer_object *bo); + +/* + * decrese buffer object reference. if reference reaches 0, + * release function of the buffer object will be called. + * + * this call is also used to release hmm_buffer_object or its + * upper level object with it embedded in. you need to call + * this function when it is no longer used. + * + * Note: + * + * user dont need to care about internal resource release of + * the buffer object in the release callback, it will be + * handled internally. + * + * this call will only release internal resource of the buffer + * object but will not free the buffer object itself, as the + * buffer object can be both pre-allocated statically or + * dynamically allocated. so user need to deal with the release + * of the buffer object itself manually. below example shows + * the normal case of using the buffer object. + * + * struct hmm_buffer_object *bo = hmm_bo_create(bdev, pgnr); + * ...... + * hmm_bo_unref(bo); + * + * or: + * + * struct hmm_buffer_object bo; + * + * hmm_bo_init(bdev, &bo, pgnr, NULL); + * ... + * hmm_bo_unref(&bo); + */ +void hmm_bo_unref(struct hmm_buffer_object *bo); + + +/* + * put buffer object to unactivated status, meaning put it into + * bo->bdev->free_bo_list, but not destroy it. + * + * this can be used to instead of hmm_bo_destroy if there are + * lots of petential hmm_bo_init/hmm_bo_destroy operations with + * the same buffer object size. using this with hmm_bo_device_get_bo + * can improve performace as lots of memory allocation/free are + * avoided.. + */ +void hmm_bo_unactivate(struct hmm_buffer_object *bo); +int hmm_bo_activated(struct hmm_buffer_object *bo); + +/* + * allocate/free virtual address space for the bo. + */ +int hmm_bo_alloc_vm(struct hmm_buffer_object *bo); +void hmm_bo_free_vm(struct hmm_buffer_object *bo); +int hmm_bo_vm_allocated(struct hmm_buffer_object *bo); + +/* + * allocate/free physical pages for the bo. will try to alloc mem + * from highmem if from_highmem is set, and type indicate that the + * pages will be allocated by using video driver (for share buffer) + * or by ISP driver itself. + */ +int hmm_bo_alloc_pages(struct hmm_buffer_object *bo, + enum hmm_bo_type type, int from_highmem, + unsigned int userptr, bool cached); +void hmm_bo_free_pages(struct hmm_buffer_object *bo); +int hmm_bo_page_allocated(struct hmm_buffer_object *bo); + +/* + * get physical page info of the bo. + */ +int hmm_bo_get_page_info(struct hmm_buffer_object *bo, + struct page ***pages, int *pgnr); + +/* + * bind/unbind the physical pages to a virtual address space. + */ +int hmm_bo_bind(struct hmm_buffer_object *bo); +void hmm_bo_unbind(struct hmm_buffer_object *bo); +int hmm_bo_binded(struct hmm_buffer_object *bo); + +/* + * vmap buffer object's pages to contiguous kernel virtual address. + * user needs to call vunmap manually to unmap it. + */ +void *hmm_bo_vmap(struct hmm_buffer_object *bo); + +/* + * mmap the bo's physical pages to specific vma. + * + * vma's address space size must be the same as bo's size, + * otherwise it will return -EINVAL. + * + * vma->vm_flags will be set to (VM_RESERVED | VM_IO). + */ +int hmm_bo_mmap(struct vm_area_struct *vma, + struct hmm_buffer_object *bo); + +#endif diff --git a/drivers/media/video/atomisp/include/hmm/hmm_bo_dev.h b/drivers/media/video/atomisp/include/hmm/hmm_bo_dev.h new file mode 100644 index 0000000..0020d09 --- /dev/null +++ b/drivers/media/video/atomisp/include/hmm/hmm_bo_dev.h @@ -0,0 +1,112 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __HMM_BO_DEV_H__ +#define __HMM_BO_DEV_H__ + +#include +#include +#include +#include +#include +#include "mmu/isp_mmu.h" +#include "hmm/hmm_common.h" +#include "hmm/hmm_vm.h" + +#define check_bodev_null_return(bdev, exp) \ + check_null_return(bdev, exp, \ + "NULL hmm_bo_device.\n") + +#define HMM_BO_DEVICE_INITED 0x1 + +struct hmm_buffer_object; + +struct hmm_bo_device { + /* isp_mmu provides lock itself */ + struct isp_mmu mmu; + + /* hmm_vm provides lock itself */ + struct hmm_vm vaddr_space; + + struct list_head free_bo_list; + struct mutex fblist_mutex; + struct list_head active_bo_list; + struct mutex ablist_mutex; + + int flag; +}; + +int hmm_bo_device_init(struct hmm_bo_device *bdev, + struct isp_mmu_driver *mmu_driver, + unsigned int vaddr_start, unsigned int size); + +/* + * clean up all hmm_bo_device related things. + */ +void hmm_bo_device_exit(struct hmm_bo_device *bdev); + +/* + * whether the bo device is inited or not. + */ +int hmm_bo_device_inited(struct hmm_bo_device *bdev); + +/* + * find the buffer object with virtual address vaddr. + * return NULL if no such buffer object found. + */ +struct hmm_buffer_object *hmm_bo_device_search_start( + struct hmm_bo_device *bdev, unsigned int vaddr); + +/* + * find the buffer object with virtual address vaddr. + * return NULL if no such buffer object found. + */ +struct hmm_buffer_object *hmm_bo_device_search_in_range( + struct hmm_bo_device *bdev, unsigned int vaddr); + +/* + * find a buffer object with pgnr pages from free_bo_list and + * activate it (remove from free_bo_list and add to + * active_bo_list) + * + * return NULL if no such buffer object found. + */ +struct hmm_buffer_object *hmm_bo_device_get_bo( + struct hmm_bo_device *bdev, unsigned int pgnr); + +/* + * destroy all buffer objects in the free_bo_list. + */ +void hmm_bo_device_destroy_free_bo_list(struct hmm_bo_device *bdev); +/* + * destroy buffer object with start virtual address vaddr. + */ +void hmm_bo_device_destroy_free_bo_addr(struct hmm_bo_device *bdev, + unsigned int vaddr); +/* + * destroy all buffer objects with pgnr pages. + */ +void hmm_bo_device_destroy_free_bo_size(struct hmm_bo_device *bdev, + unsigned int pgnr); + +#endif diff --git a/drivers/media/video/atomisp/include/hmm/hmm_common.h b/drivers/media/video/atomisp/include/hmm/hmm_common.h new file mode 100644 index 0000000..4b9b296d --- /dev/null +++ b/drivers/media/video/atomisp/include/hmm/hmm_common.h @@ -0,0 +1,67 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __HMM_BO_COMMON_H__ +#define __HMM_BO_COMMON_H__ + +#include +#include +#include +#include + +#define HMM_BO_NAME "HMM" + +/* + * some common use micros + */ +#define var_equal_return(var1, var2, exp, fmt, arg ...) \ + do { \ + if ((var1) == (var2)) { \ + v4l2_err(&atomisp_dev, \ + fmt, ## arg); \ + return exp;\ + } \ + } while (0) + +#define var_equal_goto(var1, var2, label, fmt, arg ...) \ + do { \ + if ((var1) == (var2)) { \ + v4l2_err(&atomisp_dev, \ + fmt, ## arg); \ + goto label;\ + } \ + } while (0) + +#define var_not_equal_goto(var1, var2, label, fmt, arg ...) \ + do { \ + if ((var1) != (var2)) { \ + v4l2_err(&atomisp_dev, \ + fmt, ## arg); \ + goto label;\ + } \ + } while (0) + +#define check_null_return(ptr, exp, fmt, arg ...) \ + var_equal_return(ptr, NULL, exp, fmt, ## arg) + +#endif diff --git a/drivers/media/video/atomisp/include/hmm/hmm_vm.h b/drivers/media/video/atomisp/include/hmm/hmm_vm.h new file mode 100644 index 0000000..260cb90 --- /dev/null +++ b/drivers/media/video/atomisp/include/hmm/hmm_vm.h @@ -0,0 +1,67 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __HMM_VM_H__ +#define __HMM_VM_H__ + +#include +#include +#include +#include + +struct hmm_vm { + unsigned int start; + unsigned int pgnr; + unsigned int size; + struct list_head vm_node_list; + spinlock_t lock; +}; + +struct hmm_vm_node { + struct list_head list; + unsigned int start; + unsigned int pgnr; + unsigned int size; + struct hmm_vm *vm; +}; + +#define hmm_vm_node(list_ptr) \ + list_entry((list_ptr), struct hmm_vm_node, list) + +int hmm_vm_init(struct hmm_vm *vm, unsigned int start, + unsigned int size); + +void hmm_vm_clean(struct hmm_vm *vm); + +struct hmm_vm_node *hmm_vm_alloc_node(struct hmm_vm *vm, + unsigned int pgnr); + +void hmm_vm_free_node(struct hmm_vm_node *node); + +struct hmm_vm_node *hmm_vm_find_node_start(struct hmm_vm *vm, + unsigned int addr); + +struct hmm_vm_node *hmm_vm_find_node_in_range(struct hmm_vm *vm, + unsigned int addr); + +#endif diff --git a/drivers/media/video/atomisp/include/mmu/isp_mmu.h b/drivers/media/video/atomisp/include/mmu/isp_mmu.h new file mode 100644 index 0000000..a01c19b --- /dev/null +++ b/drivers/media/video/atomisp/include/mmu/isp_mmu.h @@ -0,0 +1,168 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +/* + * ISP MMU driver for classic two-level page tables + */ +#ifndef __ISP_MMU_H__ +#define __ISP_MMU_H__ + +#include + +/* + * do not change these values, the page size for ISP must be the + * same as kernel's page size. + */ +#define ISP_PAGE_OFFSET 12 +#define ISP_PAGE_SIZE (1U << ISP_PAGE_OFFSET) +#define ISP_PAGE_MASK (~(ISP_PAGE_SIZE - 1)) + +#define ISP_L1PT_OFFSET 22 +#define ISP_L1PT_MASK (~((1U << ISP_L1PT_OFFSET) - 1)) + +#define ISP_L2PT_OFFSET 12 +#define ISP_L2PT_MASK (~(ISP_L1PT_MASK|(~(ISP_PAGE_MASK)))) + +#define ISP_L1PT_PTES 1024 +#define ISP_L2PT_PTES 1024 + +#define ISP_PTR_TO_L1_IDX(x) ((((x) & ISP_L1PT_MASK)) \ + >> ISP_L1PT_OFFSET) + +#define ISP_PTR_TO_L2_IDX(x) ((((x) & ISP_L2PT_MASK)) \ + >> ISP_L2PT_OFFSET) + +#define ISP_PAGE_ALIGN(x) (((x) + (ISP_PAGE_SIZE-1)) \ + & ISP_PAGE_MASK) + +#define ISP_PT_TO_VIRT(l1_idx, l2_idx, offset) do {\ + ((l1_idx) << ISP_L1PT_OFFSET) | \ + ((l2_idx) << ISP_L2PT_OFFSET) | \ + (offset)\ +} while (0) + +#define pgnr_to_size(pgnr) ((pgnr) << ISP_PAGE_OFFSET) +#define size_to_pgnr_ceil(size) (((size) + (1 << ISP_PAGE_OFFSET) - 1)\ + >> ISP_PAGE_OFFSET) +#define size_to_pgnr_bottom(size) ((size) >> ISP_PAGE_OFFSET) + +struct isp_mmu; + +struct isp_mmu_driver { + /* + * const value + * + * @name: + * driver name + * @pte_valid_mask: + * should be 1 bit valid data, meaning the value should + * be power of 2. + */ + char *name; + unsigned int pte_valid_mask; + + /* + * set page directory base address (physical address). + * + * must be provided. + */ + int (*set_pd_base) (struct isp_mmu *mmu, + unsigned int pd_base); + /* + * callback to flush tlb. + * + * tlb_flush_range will at least flush TLBs containing + * address mapping from addr to addr + size. + * + * tlb_flush_all will flush all TLBs. + * + * tlb_flush_all is must be provided. if tlb_flush_range is + * not valid, it will set to tlb_flush_all by default. + */ + void (*tlb_flush_range) (struct isp_mmu *mmu, + unsigned int addr, unsigned int size); + void (*tlb_flush_all) (struct isp_mmu *mmu); + +}; + +struct isp_mmu { + struct isp_mmu_driver *driver; + unsigned int l1_pte; + + struct mutex pt_mutex; +}; + +/* flags for PDE and PTE */ +#define ISP_PTE_VALID_MASK(mmu) \ + ((mmu)->driver->pte_valid_mask) + +#define ISP_PTE_VALID(mmu, pte) \ + ((pte) & ISP_PTE_VALID_MASK(mmu)) + +#define UNVALID_PHYS 0xffffffff + +#define NULL_PAGE (UNVALID_PHYS & ISP_PAGE_MASK) +#define NULL_PTE NULL_PAGE + +#define PAGE_VALID(page) ((page) != NULL_PAGE) + +/* + * init mmu with specific mmu driver. + */ +int isp_mmu_init(struct isp_mmu *mmu, struct isp_mmu_driver *driver); +/* + * cleanup all mmu related things. + */ +void isp_mmu_exit(struct isp_mmu *mmu); + +/* + * setup/remove address mapping for pgnr continous physical pages + * and isp_virt. + * + * map/unmap is mutex lock protected, and caller does not have + * to do lock/unlock operation. + * + * map/unmap will not flush tlb, and caller needs to deal with + * this itself. + */ +int isp_mmu_map(struct isp_mmu *mmu, unsigned int isp_virt, + unsigned int phys, unsigned int pgnr); + +void isp_mmu_unmap(struct isp_mmu *mmu, unsigned int isp_virt, + unsigned int pgnr); + +static inline void isp_mmu_flush_tlb_all(struct isp_mmu *mmu) +{ + if (mmu->driver && mmu->driver->tlb_flush_all) + mmu->driver->tlb_flush_all(mmu); +} + +#define isp_mmu_flush_tlb isp_mmu_flush_tlb_all + +static inline void isp_mmu_flush_tlb_range(struct isp_mmu *mmu, + unsigned int start, unsigned int size) +{ + if (mmu->driver && mmu->driver->tlb_flush_range) + mmu->driver->tlb_flush_range(mmu, start, size); +} + +#endif /* ISP_MMU_H_ */ diff --git a/drivers/media/video/atomisp/include/mmu/sh_mmu.h b/drivers/media/video/atomisp/include/mmu/sh_mmu.h new file mode 100644 index 0000000..d05aa3b --- /dev/null +++ b/drivers/media/video/atomisp/include/mmu/sh_mmu.h @@ -0,0 +1,74 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#ifndef SH_MMU_H_ +#define SH_MMU_H_ + +#include +#include "mmu/isp_mmu.h" + + +/* + * include SH header file here + */ + +/* + * set page directory base address (physical address). + * + * must be provided. + */ +static int sh_set_pd_base(struct isp_mmu *mmu, + unsigned int phys) +{ + sh_css_mmu_set_page_table_base_address((void *)phys); + return 0; +} + +/* + * callback to flush tlb. + * + * tlb_flush_range will at least flush TLBs containing + * address mapping from addr to addr + size. + * + * tlb_flush_all will flush all TLBs. + * + * tlb_flush_all is must be provided. if tlb_flush_range is + * not valid, it will set to tlb_flush_all by default. + */ +static void sh_tlb_flush(struct isp_mmu *mmu) +{ + sh_css_mmu_invalidate_cache(); +} + +static struct isp_mmu_driver sh_mmu_driver = { + .name = "Silicon Hive ISP3000 MMU", + .pte_valid_mask = 0x1, + .set_pd_base = sh_set_pd_base, + .tlb_flush_all = sh_tlb_flush, +}; + +#define ISP_VM_START 0x0 +#define ISP_VM_SIZE (1 << 30) /* 1G address space */ +#define ISP_PTR_NULL NULL + +#endif /* SH_MMU_H_ */ + diff --git a/drivers/media/video/atomisp/mmu/isp_mmu.c b/drivers/media/video/atomisp/mmu/isp_mmu.c new file mode 100644 index 0000000..05ef59d --- /dev/null +++ b/drivers/media/video/atomisp/mmu/isp_mmu.c @@ -0,0 +1,512 @@ +/* + * Support for Medifield PNW Camera Imaging ISP subsystem. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +/* + * ISP MMU management wrap code + */ +#include +#include +#include +#include /* for GFP_ATOMIC */ +#include /* for kmalloc */ +#include +#include +#include +#include +#include +#include +#include + +#include "mmu/isp_mmu.h" +#include "atomisp_internal.h" + +static unsigned int atomisp_get_pte(unsigned int pt, unsigned int idx) +{ + unsigned int pt_virt = (unsigned int)phys_to_virt(pt); + return *(((unsigned int *) pt_virt) + idx); +} + +static void atomisp_set_pte(unsigned int pt, + unsigned int idx, unsigned int pte) +{ + unsigned int pt_virt = (unsigned int)phys_to_virt(pt); + (*(((unsigned int *) pt_virt) + idx)) = pte; +} + +static void *isp_pt_phys_to_virt(unsigned int phys) +{ + return phys_to_virt(phys); +} + +static unsigned int isp_pte_to_pgaddr(unsigned int pte) +{ + return (unsigned int)(pte & ISP_PAGE_MASK); +} + +static unsigned int isp_pgaddr_to_pte_valid(struct isp_mmu *mmu, + unsigned int phys) +{ + return (unsigned int) (phys | ISP_PTE_VALID_MASK(mmu)); +} + +/* + * allocate a uncacheable page table. + * return physical address. + */ +static unsigned int alloc_page_table(void) +{ + int i; + unsigned int page; + + void *virt = (void *)__get_free_page(GFP_KERNEL); + if (!virt) + return NULL_PAGE; + + /* + * we need a uncacheable page table. + */ +#ifdef CONFIG_X86 + set_memory_uc((unsigned int)virt, 1); +#endif + + page = virt_to_phys(virt); + + for (i = 0; i < 1024; i++) { + /* NEED CHECK */ + atomisp_set_pte(page, i, NULL_PAGE); + } + + return page; +} + +static void free_page_table(unsigned int page) +{ + unsigned int virt; + page &= ISP_PAGE_MASK; + /* + * reset the page to write back before free + */ +#ifdef CONFIG_X86 + virt = (unsigned int)phys_to_virt(page); + set_memory_wb(virt, 1); +#endif + free_page((unsigned long)phys_to_virt(page)); +} + +static void mmu_remap_error(struct isp_mmu *mmu, + unsigned int l1_pt, unsigned int l1_idx, + unsigned int l2_pt, unsigned int l2_idx, + unsigned int isp_virt, unsigned int old_phys, + unsigned int new_phys) +{ + v4l2_err(&atomisp_dev, "address remap:\n\n" + "\tL1 PT: virt = 0x%x, phys = 0x%x, " + "idx = %d\n" + "\tL2 PT: virt = 0x%x, phys = 0x%x, " + "idx = %d\n" + "\told: isp_virt = 0x%x, phys = 0x%x\n" + "\tnew: isp_virt = 0x%x, phys = 0x%x\n", + (unsigned int)isp_pt_phys_to_virt(l1_pt), + (unsigned int)(l1_pt), l1_idx, + (unsigned int)isp_pt_phys_to_virt(l2_pt), + (unsigned int)(l2_pt), l2_idx, (unsigned int)isp_virt, + (unsigned int)old_phys, (unsigned int)isp_virt, + (unsigned int)new_phys); +} + +static void mmu_unmap_l2_pte_error(struct isp_mmu *mmu, + unsigned int l1_pt, unsigned int l1_idx, + unsigned int l2_pt, unsigned int l2_idx, + unsigned int isp_virt, unsigned int pte) +{ + v4l2_err(&atomisp_dev, "unmap unvalid L2 pte:\n\n" + "\tL1 PT: virt = 0x%x, phys = 0x%x, " + "idx = %d\n" + "\tL2 PT: virt = 0x%x, phys = 0x%x, " + "idx = %d\n" + "\tisp_virt = 0x%x, pte(page phys) = 0x%x\n", + (unsigned int)isp_pt_phys_to_virt(l1_pt), + (unsigned int)(l1_pt), l1_idx, + (unsigned int)isp_pt_phys_to_virt(l2_pt), + (unsigned int)(l2_pt), l2_idx, (unsigned int)isp_virt, + (unsigned int)pte); +} + +static void mmu_unmap_l1_pte_error(struct isp_mmu *mmu, + unsigned int l1_pt, unsigned int l1_idx, + unsigned int isp_virt, unsigned int pte) +{ + v4l2_err(&atomisp_dev, "unmap unvalid L1 pte (L2 PT):\n\n" + "\tL1 PT: virt = 0x%x, phys = 0x%x, " + "idx = %d\n" + "\tisp_virt = 0x%x, l1_pte(L2 PT) = 0x%x\n", + (unsigned int)isp_pt_phys_to_virt(l1_pt), + (unsigned int)(l1_pt), l1_idx, (unsigned int)isp_virt, + (unsigned int)pte); +} + +static void mmu_unmap_l1_pt_error(struct isp_mmu *mmu, unsigned int pte) +{ + v4l2_err(&atomisp_dev, "unmap unvalid L1PT:\n\n" + "L1PT = 0x%x\n", (unsigned int)pte); +} + +/* + * Update L2 page table according to isp virtual address and page physical + * address + */ +static int mmu_l2_map(struct isp_mmu *mmu, unsigned int l1_pt, + unsigned int l1_idx, unsigned int l2_pt, + unsigned int start, unsigned int end, unsigned int phys) +{ + unsigned int ptr; + unsigned int idx; + unsigned int pte; + + l2_pt &= ISP_PAGE_MASK; + + start = start & ISP_PAGE_MASK; + end = ISP_PAGE_ALIGN(end); + phys &= ISP_PAGE_MASK; + + ptr = start; + do { + idx = ISP_PTR_TO_L2_IDX(ptr); + + pte = atomisp_get_pte(l2_pt, idx); + + if (ISP_PTE_VALID(mmu, pte)) + mmu_remap_error(mmu, l1_pt, l1_idx, + l2_pt, idx, ptr, pte, phys); + + pte = isp_pgaddr_to_pte_valid(mmu, phys); + + atomisp_set_pte(l2_pt, idx, pte); + ptr += (1U << ISP_L2PT_OFFSET); + phys += (1U << ISP_L2PT_OFFSET); + } while (ptr < end && idx < ISP_L2PT_PTES - 1); + + return 0; +} + +/* + * Update L1 page table according to isp virtual address and page physical + * address + */ +static int mmu_l1_map(struct isp_mmu *mmu, unsigned int l1_pt, + unsigned int start, unsigned int end, unsigned int phys) +{ + unsigned int l2_pt, ptr, l1_aligned; + unsigned int idx; + unsigned int l2_pte; + int ret; + + l1_pt &= ISP_PAGE_MASK; + + start = start & ISP_PAGE_MASK; + end = ISP_PAGE_ALIGN(end); + phys &= ISP_PAGE_MASK; + + ptr = start; + do { + idx = ISP_PTR_TO_L1_IDX(ptr); + + l2_pte = atomisp_get_pte(l1_pt, idx); + + if (!ISP_PTE_VALID(mmu, l2_pte)) { + l2_pt = alloc_page_table(); + if (l2_pt == NULL_PAGE) { + v4l2_err(&atomisp_dev, + "alloc page table fail.\n"); + return -ENOMEM; + } + + l2_pte = isp_pgaddr_to_pte_valid(mmu, l2_pt); + + atomisp_set_pte(l1_pt, idx, l2_pte); + } + + l2_pt = isp_pte_to_pgaddr(l2_pte); + + l1_aligned = (ptr & ISP_PAGE_MASK) + (1U << ISP_L1PT_OFFSET); + + if (l1_aligned < end) { + ret = mmu_l2_map(mmu, l1_pt, idx, + l2_pt, ptr, l1_aligned, phys); + phys += (l1_aligned - ptr); + ptr = l1_aligned; + } else { + ret = mmu_l2_map(mmu, l1_pt, idx, + l2_pt, ptr, end, phys); + phys += (end - ptr); + ptr = end; + } + + if (ret) { + v4l2_err(&atomisp_dev, + "setup mapping in L2PT fail.\n"); + return ret; + } + } while (ptr < end && idx < ISP_L1PT_PTES - 1); + + return 0; +} + +/* + * Update page table according to isp virtual address and page physical + * address + */ +static int mmu_map(struct isp_mmu *mmu, unsigned int isp_virt, + unsigned int phys, unsigned int pgnr) +{ + unsigned int start, end; + unsigned int l1_pt; + int ret; + + if (!ISP_PTE_VALID(mmu, mmu->l1_pte)) { + /* + * allocate 1 new page for L1 page table + */ + l1_pt = alloc_page_table(); + if (l1_pt == NULL_PAGE) { + v4l2_err(&atomisp_dev, + "alloc page table fail.\n"); + return -ENOMEM; + } + + /* + * setup L1 page table physical addr to MMU + */ + ret = mmu->driver->set_pd_base(mmu, l1_pt); + if (ret) { + v4l2_err(&atomisp_dev, + "set page directory base address " + "fail.\n"); + return ret; + } + mmu->l1_pte = isp_pgaddr_to_pte_valid(mmu, l1_pt); + } + + l1_pt = isp_pte_to_pgaddr(mmu->l1_pte); + + start = (isp_virt) & ISP_PAGE_MASK; + end = start + (pgnr << ISP_PAGE_OFFSET); + phys &= ISP_PAGE_MASK; + + ret = mmu_l1_map(mmu, l1_pt, start, end, phys); + + if (ret) + v4l2_err(&atomisp_dev, + "setup mapping in L1PT fail.\n"); + + return ret; +} + +/* + * Free L2 page table according to isp virtual address and page physical + * address + */ +static void mmu_l2_unmap(struct isp_mmu *mmu, unsigned int l1_pt, + unsigned int l1_idx, unsigned int l2_pt, + unsigned int start, unsigned int end) +{ + + unsigned int ptr; + unsigned int idx; + unsigned int pte; + + l2_pt &= ISP_PAGE_MASK; + + start = start & ISP_PAGE_MASK; + end = ISP_PAGE_ALIGN(end); + + ptr = start; + do { + idx = ISP_PTR_TO_L2_IDX(ptr); + + pte = atomisp_get_pte(l2_pt, idx); + + if (!ISP_PTE_VALID(mmu, pte)) + mmu_unmap_l2_pte_error(mmu, l1_pt, l1_idx, + l2_pt, idx, ptr, pte); + + atomisp_set_pte(l2_pt, idx, NULL_PTE); + + ptr += (1U << ISP_L2PT_OFFSET); + } while (ptr < end && idx < ISP_L2PT_PTES - 1); +} + +/* + * Free L1 page table according to isp virtual address and page physical + * address + */ +static void mmu_l1_unmap(struct isp_mmu *mmu, unsigned int l1_pt, + unsigned int start, unsigned int end) +{ + unsigned int l2_pt, ptr, l1_aligned; + unsigned int idx; + unsigned int l2_pte; + + l1_pt &= ISP_PAGE_MASK; + + start = start & ISP_PAGE_MASK; + end = ISP_PAGE_ALIGN(end); + + ptr = start; + do { + idx = ISP_PTR_TO_L1_IDX(ptr); + + l2_pte = atomisp_get_pte(l1_pt, idx); + + if (!ISP_PTE_VALID(mmu, l2_pte)) { + mmu_unmap_l1_pte_error(mmu, l1_pt, idx, ptr, l2_pte); + continue; + } + + l2_pt = isp_pte_to_pgaddr(l2_pte); + + l1_aligned = (ptr & ISP_PAGE_MASK) + (1U << ISP_L1PT_OFFSET); + + if (l1_aligned < end) { + mmu_l2_unmap(mmu, l1_pt, idx, l2_pt, ptr, l1_aligned); + ptr = l1_aligned; + } else { + mmu_l2_unmap(mmu, l1_pt, idx, l2_pt, ptr, end); + ptr = end; + } + /* + * use the same L2 page next time, so we dont + * need to invalidate and free this PT. + */ + /* atomisp_set_pte(l1_pt, idx, NULL_PTE); */ + } while (ptr < end && idx < ISP_L1PT_PTES - 1); +} + +/* + * Free page table according to isp virtual address and page physical + * address + */ +static void mmu_unmap(struct isp_mmu *mmu, unsigned int isp_virt, + unsigned int pgnr) +{ + unsigned int start, end; + unsigned int l1_pt; + + if (!ISP_PTE_VALID(mmu, mmu->l1_pte)) { + mmu_unmap_l1_pt_error(mmu, mmu->l1_pte); + return; + } + + l1_pt = isp_pte_to_pgaddr(mmu->l1_pte); + + start = (isp_virt) & ISP_PAGE_MASK; + end = start + (pgnr << ISP_PAGE_OFFSET); + + mmu_l1_unmap(mmu, l1_pt, start, end); +} + +int isp_mmu_map(struct isp_mmu *mmu, unsigned int isp_virt, + unsigned int phys, unsigned int pgnr) +{ + return mmu_map(mmu, isp_virt, phys, pgnr); +} + +void isp_mmu_unmap(struct isp_mmu *mmu, unsigned int isp_virt, + unsigned int pgnr) +{ + mmu_unmap(mmu, isp_virt, pgnr); +} + +static void isp_mmu_flush_tlb_range_default(struct isp_mmu *mmu, + unsigned int start, + unsigned int size) +{ + isp_mmu_flush_tlb(mmu); +} + +/*MMU init for internal structure*/ +int isp_mmu_init(struct isp_mmu *mmu, struct isp_mmu_driver *driver) +{ + if (!mmu) /* error */ + return -EINVAL; + if (!driver) /* error */ + return -EINVAL; + + if (!driver->name) + v4l2_warn(&atomisp_dev, + "NULL name for MMU driver...\n"); + + mmu->driver = driver; + + if (!driver->set_pd_base || !driver->tlb_flush_all) { + v4l2_err(&atomisp_dev, + "set_pd_base or tlb_flush_all operation " + "not provided.\n"); + return -EINVAL; + } + + if (!driver->tlb_flush_range) + driver->tlb_flush_range = isp_mmu_flush_tlb_range_default; + + if (!driver->pte_valid_mask) + driver->pte_valid_mask = 0x1; + + mmu->l1_pte = NULL_PTE; + + mutex_init(&mmu->pt_mutex); + + isp_mmu_flush_tlb(mmu); + + return 0; +} + +/*Free L1 and L2 page table*/ +void isp_mmu_exit(struct isp_mmu *mmu) +{ + unsigned int idx; + unsigned int pte; + unsigned int l1_pt, l2_pt; + + if (!mmu) + return; + + if (!ISP_PTE_VALID(mmu, mmu->l1_pte)) { + v4l2_warn(&atomisp_dev, + "invalid L1PT: pte = 0x%x\n", + (unsigned int)mmu->l1_pte); + return; + } + + l1_pt = isp_pte_to_pgaddr(mmu->l1_pte); + + for (idx = 0; idx < ISP_L1PT_PTES; idx++) { + pte = atomisp_get_pte(l1_pt, idx); + + if (ISP_PTE_VALID(mmu, pte)) { + l2_pt = isp_pte_to_pgaddr(pte); + + free_page_table(l2_pt); + } + } + + free_page_table(l1_pt); +} -- 2.7.4