aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/dream/camera/msm_vfe8x_proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/dream/camera/msm_vfe8x_proc.c')
-rw-r--r--drivers/staging/dream/camera/msm_vfe8x_proc.c4003
1 files changed, 4003 insertions, 0 deletions
diff --git a/drivers/staging/dream/camera/msm_vfe8x_proc.c b/drivers/staging/dream/camera/msm_vfe8x_proc.c
new file mode 100644
index 000000000000..10aef0e59bab
--- /dev/null
+++ b/drivers/staging/dream/camera/msm_vfe8x_proc.c
@@ -0,0 +1,4003 @@
+/*
+* Copyright (C) 2008-2009 QUALCOMM Incorporated.
+*/
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include "msm_vfe8x_proc.h"
+#include <media/msm_camera.h>
+
+struct msm_vfe8x_ctrl {
+ /* bit 1:0 ENC_IRQ_MASK = 0x11:
+ * generate IRQ when both y and cbcr frame is ready. */
+
+ /* bit 1:0 VIEW_IRQ_MASK= 0x11:
+ * generate IRQ when both y and cbcr frame is ready. */
+ struct vfe_irq_composite_mask_config vfeIrqCompositeMaskLocal;
+ struct vfe_module_enable vfeModuleEnableLocal;
+ struct vfe_camif_cfg_data vfeCamifConfigLocal;
+ struct vfe_interrupt_mask vfeImaskLocal;
+ struct vfe_stats_cmd_data vfeStatsCmdLocal;
+ struct vfe_bus_cfg_data vfeBusConfigLocal;
+ struct vfe_cmd_bus_pm_start vfeBusPmConfigLocal;
+ struct vfe_bus_cmd_data vfeBusCmdLocal;
+ enum vfe_interrupt_name vfeInterruptNameLocal;
+ uint32_t vfeLaBankSel;
+ struct vfe_gamma_lut_sel vfeGammaLutSel;
+
+ boolean vfeStartAckPendingFlag;
+ boolean vfeStopAckPending;
+ boolean vfeResetAckPending;
+ boolean vfeUpdateAckPending;
+
+ enum VFE_AXI_OUTPUT_MODE axiOutputMode;
+ enum VFE_START_OPERATION_MODE vfeOperationMode;
+
+ uint32_t vfeSnapShotCount;
+ uint32_t vfeRequestedSnapShotCount;
+ boolean vfeStatsPingPongReloadFlag;
+ uint32_t vfeFrameId;
+
+ struct vfe_cmd_frame_skip_config vfeFrameSkip;
+ uint32_t vfeFrameSkipPattern;
+ uint8_t vfeFrameSkipCount;
+ uint8_t vfeFrameSkipPeriod;
+
+ boolean vfeTestGenStartFlag;
+ uint32_t vfeImaskPacked;
+ uint32_t vfeImaskCompositePacked;
+ enum VFE_RAW_PIXEL_DATA_SIZE axiInputDataSize;
+ struct vfe_irq_thread_msg vfeIrqThreadMsgLocal;
+
+ struct vfe_output_path_combo viewPath;
+ struct vfe_output_path_combo encPath;
+ struct vfe_frame_skip_counts vfeDroppedFrameCounts;
+ struct vfe_stats_control afStatsControl;
+ struct vfe_stats_control awbStatsControl;
+
+ enum VFE_STATE vstate;
+
+ spinlock_t ack_lock;
+ spinlock_t state_lock;
+ spinlock_t io_lock;
+
+ struct msm_vfe_callback *resp;
+ uint32_t extlen;
+ void *extdata;
+
+ spinlock_t tasklet_lock;
+ struct list_head tasklet_q;
+
+ int vfeirq;
+ void __iomem *vfebase;
+
+ void *syncdata;
+};
+static struct msm_vfe8x_ctrl *ctrl;
+static irqreturn_t vfe_parse_irq(int irq_num, void *data);
+
+struct isr_queue_cmd {
+ struct list_head list;
+ struct vfe_interrupt_status vfeInterruptStatus;
+ struct vfe_frame_asf_info vfeAsfFrameInfo;
+ struct vfe_frame_bpc_info vfeBpcFrameInfo;
+ struct vfe_msg_camif_status vfeCamifStatusLocal;
+ struct vfe_bus_performance_monitor vfePmData;
+};
+
+static void vfe_prog_hw(uint8_t *hwreg,
+ uint32_t *inptr, uint32_t regcnt)
+{
+ /* unsigned long flags; */
+ uint32_t i;
+ uint32_t *p;
+
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->io_lock, flags); */
+
+ p = (uint32_t *)(hwreg);
+ for (i = 0; i < (regcnt >> 2); i++)
+ writel(*inptr++, p++);
+ /* *p++ = *inptr++; */
+
+ /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */
+}
+
+static void vfe_read_reg_values(uint8_t *hwreg,
+ uint32_t *dest, uint32_t count)
+{
+ /* unsigned long flags; */
+ uint32_t *temp;
+ uint32_t i;
+
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->io_lock, flags); */
+
+ temp = (uint32_t *)(hwreg);
+ for (i = 0; i < count; i++)
+ *dest++ = *temp++;
+
+ /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */
+}
+
+static struct vfe_irqenable vfe_read_irq_mask(void)
+{
+ /* unsigned long flags; */
+ uint32_t *temp;
+ struct vfe_irqenable rc;
+
+ memset(&rc, 0, sizeof(rc));
+
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->io_lock, flags); */
+ temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_MASK);
+
+ rc = *((struct vfe_irqenable *)temp);
+ /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */
+
+ return rc;
+}
+
+static void
+vfe_set_bus_pipo_addr(struct vfe_output_path_combo *vpath,
+ struct vfe_output_path_combo *epath)
+{
+ vpath->yPath.hwRegPingAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PING_ADDR);
+ vpath->yPath.hwRegPongAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PONG_ADDR);
+ vpath->cbcrPath.hwRegPingAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PING_ADDR);
+ vpath->cbcrPath.hwRegPongAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PONG_ADDR);
+
+ epath->yPath.hwRegPingAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR);
+ epath->yPath.hwRegPongAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PONG_ADDR);
+ epath->cbcrPath.hwRegPingAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PING_ADDR);
+ epath->cbcrPath.hwRegPongAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PONG_ADDR);
+}
+
+static void vfe_axi_output(struct vfe_cmd_axi_output_config *in,
+ struct vfe_output_path_combo *out1,
+ struct vfe_output_path_combo *out2, uint16_t out)
+{
+ struct vfe_axi_out_cfg cmd;
+
+ uint16_t temp;
+ uint32_t burstLength;
+
+ /* force it to burst length 4, hardware does not support it. */
+ burstLength = 1;
+
+ /* AXI Output 2 Y Configuration*/
+ /* VFE_BUS_ENC_Y_WR_PING_ADDR */
+ cmd.out2YPingAddr = out2->yPath.addressBuffer[0];
+
+ /* VFE_BUS_ENC_Y_WR_PONG_ADDR */
+ cmd.out2YPongAddr = out2->yPath.addressBuffer[1];
+
+ /* VFE_BUS_ENC_Y_WR_IMAGE_SIZE */
+ cmd.out2YImageHeight = in->output2.outputY.imageHeight;
+ /* convert the image width and row increment to be in
+ * unit of 64bit (8 bytes) */
+ temp = (in->output2.outputY.imageWidth + (out - 1)) /
+ out;
+ cmd.out2YImageWidthin64bit = temp;
+
+ /* VFE_BUS_ENC_Y_WR_BUFFER_CFG */
+ cmd.out2YBurstLength = burstLength;
+ cmd.out2YNumRows = in->output2.outputY.outRowCount;
+ temp = (in->output2.outputY.outRowIncrement + (out - 1)) /
+ out;
+ cmd.out2YRowIncrementIn64bit = temp;
+
+ /* AXI Output 2 Cbcr Configuration*/
+ /* VFE_BUS_ENC_Cbcr_WR_PING_ADDR */
+ cmd.out2CbcrPingAddr = out2->cbcrPath.addressBuffer[0];
+
+ /* VFE_BUS_ENC_Cbcr_WR_PONG_ADDR */
+ cmd.out2CbcrPongAddr = out2->cbcrPath.addressBuffer[1];
+
+ /* VFE_BUS_ENC_Cbcr_WR_IMAGE_SIZE */
+ cmd.out2CbcrImageHeight = in->output2.outputCbcr.imageHeight;
+ temp = (in->output2.outputCbcr.imageWidth + (out - 1)) /
+ out;
+ cmd.out2CbcrImageWidthIn64bit = temp;
+
+ /* VFE_BUS_ENC_Cbcr_WR_BUFFER_CFG */
+ cmd.out2CbcrBurstLength = burstLength;
+ cmd.out2CbcrNumRows = in->output2.outputCbcr.outRowCount;
+ temp = (in->output2.outputCbcr.outRowIncrement + (out - 1)) /
+ out;
+ cmd.out2CbcrRowIncrementIn64bit = temp;
+
+ /* AXI Output 1 Y Configuration */
+ /* VFE_BUS_VIEW_Y_WR_PING_ADDR */
+ cmd.out1YPingAddr = out1->yPath.addressBuffer[0];
+
+ /* VFE_BUS_VIEW_Y_WR_PONG_ADDR */
+ cmd.out1YPongAddr = out1->yPath.addressBuffer[1];
+
+ /* VFE_BUS_VIEW_Y_WR_IMAGE_SIZE */
+ cmd.out1YImageHeight = in->output1.outputY.imageHeight;
+ temp = (in->output1.outputY.imageWidth + (out - 1)) /
+ out;
+ cmd.out1YImageWidthin64bit = temp;
+
+ /* VFE_BUS_VIEW_Y_WR_BUFFER_CFG */
+ cmd.out1YBurstLength = burstLength;
+ cmd.out1YNumRows = in->output1.outputY.outRowCount;
+
+ temp =
+ (in->output1.outputY.outRowIncrement +
+ (out - 1)) / out;
+ cmd.out1YRowIncrementIn64bit = temp;
+
+ /* AXI Output 1 Cbcr Configuration*/
+ cmd.out1CbcrPingAddr = out1->cbcrPath.addressBuffer[0];
+
+ /* VFE_BUS_VIEW_Cbcr_WR_PONG_ADDR */
+ cmd.out1CbcrPongAddr =
+ out1->cbcrPath.addressBuffer[1];
+
+ /* VFE_BUS_VIEW_Cbcr_WR_IMAGE_SIZE */
+ cmd.out1CbcrImageHeight = in->output1.outputCbcr.imageHeight;
+ temp = (in->output1.outputCbcr.imageWidth +
+ (out - 1)) / out;
+ cmd.out1CbcrImageWidthIn64bit = temp;
+
+ cmd.out1CbcrBurstLength = burstLength;
+ cmd.out1CbcrNumRows = in->output1.outputCbcr.outRowCount;
+ temp =
+ (in->output1.outputCbcr.outRowIncrement +
+ (out - 1)) / out;
+
+ cmd.out1CbcrRowIncrementIn64bit = temp;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_reg_bus_cfg(struct vfe_bus_cfg_data *in)
+{
+ struct vfe_axi_bus_cfg cmd;
+
+ cmd.stripeRdPathEn = in->stripeRdPathEn;
+ cmd.encYWrPathEn = in->encYWrPathEn;
+ cmd.encCbcrWrPathEn = in->encCbcrWrPathEn;
+ cmd.viewYWrPathEn = in->viewYWrPathEn;
+ cmd.viewCbcrWrPathEn = in->viewCbcrWrPathEn;
+ cmd.rawPixelDataSize = (uint32_t)in->rawPixelDataSize;
+ cmd.rawWritePathSelect = (uint32_t)in->rawWritePathSelect;
+
+ /* program vfe_bus_cfg */
+ writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CFG);
+}
+
+static void vfe_reg_camif_config(struct vfe_camif_cfg_data *in)
+{
+ struct VFE_CAMIFConfigType cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+
+ cfg.VSyncEdge =
+ in->camifCfgFromCmd.vSyncEdge;
+
+ cfg.HSyncEdge =
+ in->camifCfgFromCmd.hSyncEdge;
+
+ cfg.syncMode =
+ in->camifCfgFromCmd.syncMode;
+
+ cfg.vfeSubsampleEnable =
+ in->camifCfgFromCmd.vfeSubSampleEnable;
+
+ cfg.busSubsampleEnable =
+ in->camifCfgFromCmd.busSubSampleEnable;
+
+ cfg.camif2vfeEnable =
+ in->camif2OutputEnable;
+
+ cfg.camif2busEnable =
+ in->camif2BusEnable;
+
+ cfg.irqSubsampleEnable =
+ in->camifCfgFromCmd.irqSubSampleEnable;
+
+ cfg.binningEnable =
+ in->camifCfgFromCmd.binningEnable;
+
+ cfg.misrEnable =
+ in->camifCfgFromCmd.misrEnable;
+
+ /* program camif_config */
+ writel(*((uint32_t *)&cfg), ctrl->vfebase + CAMIF_CONFIG);
+}
+
+static void vfe_reg_bus_cmd(struct vfe_bus_cmd_data *in)
+{
+ struct vfe_buscmd cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.stripeReload = in->stripeReload;
+ cmd.busPingpongReload = in->busPingpongReload;
+ cmd.statsPingpongReload = in->statsPingpongReload;
+
+ writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CMD);
+
+ CDBG("bus command = 0x%x\n", (*((uint32_t *)&cmd)));
+
+ /* this is needed, as the control bits are pulse based.
+ * Don't want to reload bus pingpong again. */
+ in->busPingpongReload = 0;
+ in->statsPingpongReload = 0;
+ in->stripeReload = 0;
+}
+
+static void vfe_reg_module_cfg(struct vfe_module_enable *in)
+{
+ struct vfe_mod_enable ena;
+
+ memset(&ena, 0, sizeof(ena));
+
+ ena.blackLevelCorrectionEnable = in->blackLevelCorrectionEnable;
+ ena.lensRollOffEnable = in->lensRollOffEnable;
+ ena.demuxEnable = in->demuxEnable;
+ ena.chromaUpsampleEnable = in->chromaUpsampleEnable;
+ ena.demosaicEnable = in->demosaicEnable;
+ ena.statsEnable = in->statsEnable;
+ ena.cropEnable = in->cropEnable;
+ ena.mainScalerEnable = in->mainScalerEnable;
+ ena.whiteBalanceEnable = in->whiteBalanceEnable;
+ ena.colorCorrectionEnable = in->colorCorrectionEnable;
+ ena.yHistEnable = in->yHistEnable;
+ ena.skinToneEnable = in->skinToneEnable;
+ ena.lumaAdaptationEnable = in->lumaAdaptationEnable;
+ ena.rgbLUTEnable = in->rgbLUTEnable;
+ ena.chromaEnhanEnable = in->chromaEnhanEnable;
+ ena.asfEnable = in->asfEnable;
+ ena.chromaSuppressionEnable = in->chromaSuppressionEnable;
+ ena.chromaSubsampleEnable = in->chromaSubsampleEnable;
+ ena.scaler2YEnable = in->scaler2YEnable;
+ ena.scaler2CbcrEnable = in->scaler2CbcrEnable;
+
+ writel(*((uint32_t *)&ena), ctrl->vfebase + VFE_MODULE_CFG);
+}
+
+static void vfe_program_dmi_cfg(enum VFE_DMI_RAM_SEL bankSel)
+{
+ /* set bit 8 for auto increment. */
+ uint32_t value = (uint32_t) ctrl->vfebase + VFE_DMI_CFG_DEFAULT;
+
+ value += (uint32_t)bankSel;
+ /* CDBG("dmi cfg input bank is 0x%x\n", bankSel); */
+
+ writel(value, ctrl->vfebase + VFE_DMI_CFG);
+ writel(0, ctrl->vfebase + VFE_DMI_ADDR);
+}
+
+static void vfe_write_lens_roll_off_table(
+ struct vfe_cmd_roll_off_config *in)
+{
+ uint16_t i;
+ uint32_t data;
+
+ uint16_t *initGr = in->initTableGr;
+ uint16_t *initGb = in->initTableGb;
+ uint16_t *initB = in->initTableB;
+ uint16_t *initR = in->initTableR;
+
+ int16_t *pDeltaGr = in->deltaTableGr;
+ int16_t *pDeltaGb = in->deltaTableGb;
+ int16_t *pDeltaB = in->deltaTableB;
+ int16_t *pDeltaR = in->deltaTableR;
+
+ vfe_program_dmi_cfg(ROLLOFF_RAM);
+
+ /* first pack and write init table */
+ for (i = 0; i < VFE_ROLL_OFF_INIT_TABLE_SIZE; i++) {
+ data = (((uint32_t)(*initR)) & 0x0000FFFF) |
+ (((uint32_t)(*initGr)) << 16);
+ initR++;
+ initGr++;
+
+ writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+ data = (((uint32_t)(*initB)) & 0x0000FFFF) |
+ (((uint32_t)(*initGr))<<16);
+ initB++;
+ initGb++;
+
+ writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+
+ /* there are gaps between the init table and delta table,
+ * set the offset for delta table. */
+ writel(LENS_ROLL_OFF_DELTA_TABLE_OFFSET,
+ ctrl->vfebase + VFE_DMI_ADDR);
+
+ /* pack and write delta table */
+ for (i = 0; i < VFE_ROLL_OFF_DELTA_TABLE_SIZE; i++) {
+ data = (((int32_t)(*pDeltaR)) & 0x0000FFFF) |
+ (((int32_t)(*pDeltaGr))<<16);
+ pDeltaR++;
+ pDeltaGr++;
+
+ writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+ data = (((int32_t)(*pDeltaB)) & 0x0000FFFF) |
+ (((int32_t)(*pDeltaGb))<<16);
+ pDeltaB++;
+ pDeltaGb++;
+
+ writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+
+ /* After DMI transfer, to make it safe, need to set the
+ * DMI_CFG to unselect any SRAM
+ */
+ /* unselect the SRAM Bank. */
+ writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_set_default_reg_values(void)
+{
+ writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_0);
+ writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_1);
+ writel(0xFFFFF, ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+ /* default frame drop period and pattern */
+ writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+ writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+ writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+ writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+ writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_CFG);
+ writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_CFG);
+ writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+ writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+ writel(0, ctrl->vfebase + VFE_CLAMP_MIN_CFG);
+ writel(0xFFFFFF, ctrl->vfebase + VFE_CLAMP_MAX_CFG);
+}
+
+static void vfe_config_demux(uint32_t period, uint32_t even, uint32_t odd)
+{
+ writel(period, ctrl->vfebase + VFE_DEMUX_CFG);
+ writel(even, ctrl->vfebase + VFE_DEMUX_EVEN_CFG);
+ writel(odd, ctrl->vfebase + VFE_DEMUX_ODD_CFG);
+}
+
+static void vfe_pm_stop(void)
+{
+ writel(VFE_PERFORMANCE_MONITOR_STOP, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static void vfe_program_bus_rd_irq_en(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN);
+}
+
+static void vfe_camif_go(void)
+{
+ writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND);
+}
+
+static void vfe_camif_stop_immediately(void)
+{
+ writel(CAMIF_COMMAND_STOP_IMMEDIATELY, ctrl->vfebase + CAMIF_COMMAND);
+ writel(0, ctrl->vfebase + VFE_CGC_OVERRIDE);
+}
+
+static void vfe_program_reg_update_cmd(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static void vfe_program_bus_cmd(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_BUS_CMD);
+}
+
+static void vfe_program_global_reset_cmd(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}
+
+static void vfe_program_axi_cmd(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_AXI_CMD);
+}
+
+static void vfe_program_irq_composite_mask(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+}
+
+static inline void vfe_program_irq_mask(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_IRQ_MASK);
+}
+
+static void vfe_program_chroma_upsample_cfg(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG);
+}
+
+static uint32_t vfe_read_axi_status(void)
+{
+ return readl(ctrl->vfebase + VFE_AXI_STATUS);
+}
+
+static uint32_t vfe_read_pm_status_in_raw_capture(void)
+{
+ return readl(ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PM_STATS_1);
+}
+
+static void
+vfe_set_stats_pingpong_address(struct vfe_stats_control *afControl,
+ struct vfe_stats_control *awbControl)
+{
+ afControl->hwRegPingAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ afControl->hwRegPongAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+ awbControl->hwRegPingAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ awbControl->hwRegPongAddress = (uint8_t *)
+ (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static uint32_t vfe_read_camif_status(void)
+{
+ return readl(ctrl->vfebase + CAMIF_STATUS);
+}
+
+static void vfe_program_lut_bank_sel(struct vfe_gamma_lut_sel *in)
+{
+ struct VFE_GammaLutSelect_ConfigCmdType cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.ch0BankSelect = in->ch0BankSelect;
+ cmd.ch1BankSelect = in->ch1BankSelect;
+ cmd.ch2BankSelect = in->ch2BankSelect;
+ CDBG("VFE gamma lut bank selection is 0x%x\n", *((uint32_t *)&cmd));
+ vfe_prog_hw(ctrl->vfebase + VFE_LUT_BANK_SEL,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_program_stats_cmd(struct vfe_stats_cmd_data *in)
+{
+ struct VFE_StatsCmdType stats;
+ memset(&stats, 0, sizeof(stats));
+
+ stats.autoFocusEnable = in->autoFocusEnable;
+ stats.axwEnable = in->axwEnable;
+ stats.histEnable = in->histEnable;
+ stats.clearHistEnable = in->clearHistEnable;
+ stats.histAutoClearEnable = in->histAutoClearEnable;
+ stats.colorConversionEnable = in->colorConversionEnable;
+
+ writel(*((uint32_t *)&stats), ctrl->vfebase + VFE_STATS_CMD);
+}
+
+static void vfe_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+ struct VFE_Bus_Pm_ConfigCmdType cmd;
+ memset(&cmd, 0, sizeof(struct VFE_Bus_Pm_ConfigCmdType));
+
+ cmd.output2YWrPmEnable = in->output2YWrPmEnable;
+ cmd.output2CbcrWrPmEnable = in->output2CbcrWrPmEnable;
+ cmd.output1YWrPmEnable = in->output1YWrPmEnable;
+ cmd.output1CbcrWrPmEnable = in->output1CbcrWrPmEnable;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_BUS_PM_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_8k_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+ in->output1CbcrWrPmEnable = ctrl->vfeBusConfigLocal.viewCbcrWrPathEn;
+ in->output1YWrPmEnable = ctrl->vfeBusConfigLocal.viewYWrPathEn;
+ in->output2CbcrWrPmEnable = ctrl->vfeBusConfigLocal.encCbcrWrPathEn;
+ in->output2YWrPmEnable = ctrl->vfeBusConfigLocal.encYWrPathEn;
+
+ if (in->output1CbcrWrPmEnable || in->output1YWrPmEnable)
+ ctrl->viewPath.pmEnabled = TRUE;
+
+ if (in->output2CbcrWrPmEnable || in->output2YWrPmEnable)
+ ctrl->encPath.pmEnabled = TRUE;
+
+ vfe_pm_start(in);
+
+ writel(VFE_PERFORMANCE_MONITOR_GO, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static uint32_t vfe_irq_pack(struct vfe_interrupt_mask data)
+{
+ struct vfe_irqenable packedData;
+
+ memset(&packedData, 0, sizeof(packedData));
+
+ packedData.camifErrorIrq = data.camifErrorIrq;
+ packedData.camifSofIrq = data.camifSofIrq;
+ packedData.camifEolIrq = data.camifEolIrq;
+ packedData.camifEofIrq = data.camifEofIrq;
+ packedData.camifEpoch1Irq = data.camifEpoch1Irq;
+ packedData.camifEpoch2Irq = data.camifEpoch2Irq;
+ packedData.camifOverflowIrq = data.camifOverflowIrq;
+ packedData.ceIrq = data.ceIrq;
+ packedData.regUpdateIrq = data.regUpdateIrq;
+ packedData.resetAckIrq = data.resetAckIrq;
+ packedData.encYPingpongIrq = data.encYPingpongIrq;
+ packedData.encCbcrPingpongIrq = data.encCbcrPingpongIrq;
+ packedData.viewYPingpongIrq = data.viewYPingpongIrq;
+ packedData.viewCbcrPingpongIrq = data.viewCbcrPingpongIrq;
+ packedData.rdPingpongIrq = data.rdPingpongIrq;
+ packedData.afPingpongIrq = data.afPingpongIrq;
+ packedData.awbPingpongIrq = data.awbPingpongIrq;
+ packedData.histPingpongIrq = data.histPingpongIrq;
+ packedData.encIrq = data.encIrq;
+ packedData.viewIrq = data.viewIrq;
+ packedData.busOverflowIrq = data.busOverflowIrq;
+ packedData.afOverflowIrq = data.afOverflowIrq;
+ packedData.awbOverflowIrq = data.awbOverflowIrq;
+ packedData.syncTimer0Irq = data.syncTimer0Irq;
+ packedData.syncTimer1Irq = data.syncTimer1Irq;
+ packedData.syncTimer2Irq = data.syncTimer2Irq;
+ packedData.asyncTimer0Irq = data.asyncTimer0Irq;
+ packedData.asyncTimer1Irq = data.asyncTimer1Irq;
+ packedData.asyncTimer2Irq = data.asyncTimer2Irq;
+ packedData.asyncTimer3Irq = data.asyncTimer3Irq;
+ packedData.axiErrorIrq = data.axiErrorIrq;
+ packedData.violationIrq = data.violationIrq;
+
+ return *((uint32_t *)&packedData);
+}
+
+static uint32_t
+vfe_irq_composite_pack(struct vfe_irq_composite_mask_config data)
+{
+ struct VFE_Irq_Composite_MaskType packedData;
+
+ memset(&packedData, 0, sizeof(packedData));
+
+ packedData.encIrqComMaskBits = data.encIrqComMask;
+ packedData.viewIrqComMaskBits = data.viewIrqComMask;
+ packedData.ceDoneSelBits = data.ceDoneSel;
+
+ return *((uint32_t *)&packedData);
+}
+
+static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo,
+ enum vfe_resp_msg type, void *data, void **ext, int32_t *elen)
+{
+ switch (type) {
+ case VFE_MSG_OUTPUT1: {
+ pinfo->y_phy =
+ ((struct vfe_message *)data)->_u.msgOutput1.yBuffer;
+ pinfo->cbcr_phy =
+ ((struct vfe_message *)data)->_u.msgOutput1.cbcrBuffer;
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->bpcInfo =
+ ((struct vfe_message *)data)->_u.msgOutput1.bpcInfo;
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->asfInfo =
+ ((struct vfe_message *)data)->_u.msgOutput1.asfInfo;
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->frameCounter =
+ ((struct vfe_message *)data)->_u.msgOutput1.frameCounter;
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->pmData =
+ ((struct vfe_message *)data)->_u.msgOutput1.pmData;
+
+ *ext = ctrl->extdata;
+ *elen = ctrl->extlen;
+ }
+ break;
+
+ case VFE_MSG_OUTPUT2: {
+ pinfo->y_phy =
+ ((struct vfe_message *)data)->_u.msgOutput2.yBuffer;
+ pinfo->cbcr_phy =
+ ((struct vfe_message *)data)->_u.msgOutput2.cbcrBuffer;
+
+ CDBG("vfe_addr_convert, pinfo->y_phy = 0x%x\n", pinfo->y_phy);
+ CDBG("vfe_addr_convert, pinfo->cbcr_phy = 0x%x\n",
+ pinfo->cbcr_phy);
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->bpcInfo =
+ ((struct vfe_message *)data)->_u.msgOutput2.bpcInfo;
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->asfInfo =
+ ((struct vfe_message *)data)->_u.msgOutput2.asfInfo;
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->frameCounter =
+ ((struct vfe_message *)data)->_u.msgOutput2.frameCounter;
+
+ ((struct vfe_frame_extra *)ctrl->extdata)->pmData =
+ ((struct vfe_message *)data)->_u.msgOutput2.pmData;
+
+ *ext = ctrl->extdata;
+ *elen = ctrl->extlen;
+ }
+ break;
+
+ case VFE_MSG_STATS_AF:
+ pinfo->sbuf_phy =
+ ((struct vfe_message *)data)->_u.msgStatsAf.afBuffer;
+ break;
+
+ case VFE_MSG_STATS_WE:
+ pinfo->sbuf_phy =
+ ((struct vfe_message *)data)->_u.msgStatsWbExp.awbBuffer;
+ break;
+
+ default:
+ break;
+ } /* switch */
+}
+
+static void
+vfe_proc_ops(enum VFE_MESSAGE_ID id, void *msg, size_t len)
+{
+ struct msm_vfe_resp *rp;
+
+ /* In 8k, OUTPUT1 & OUTPUT2 messages arrive before
+ * SNAPSHOT_DONE. We don't send such messages to user */
+
+ CDBG("ctrl->vfeOperationMode = %d, msgId = %d\n",
+ ctrl->vfeOperationMode, id);
+
+ if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) &&
+ (id == VFE_MSG_ID_OUTPUT1 || id == VFE_MSG_ID_OUTPUT2)) {
+ return;
+ }
+
+ rp = ctrl->resp->vfe_alloc(sizeof(struct msm_vfe_resp), ctrl->syncdata);
+ if (!rp) {
+ CDBG("rp: cannot allocate buffer\n");
+ return;
+ }
+
+ CDBG("vfe_proc_ops, msgId = %d\n", id);
+
+ rp->evt_msg.type = MSM_CAMERA_MSG;
+ rp->evt_msg.msg_id = id;
+ rp->evt_msg.len = len;
+ rp->evt_msg.data = msg;
+
+ switch (rp->evt_msg.msg_id) {
+ case VFE_MSG_ID_SNAPSHOT_DONE:
+ rp->type = VFE_MSG_SNAPSHOT;
+ break;
+
+ case VFE_MSG_ID_OUTPUT1:
+ rp->type = VFE_MSG_OUTPUT1;
+ vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT1,
+ rp->evt_msg.data, &(rp->extdata),
+ &(rp->extlen));
+ break;
+
+ case VFE_MSG_ID_OUTPUT2:
+ rp->type = VFE_MSG_OUTPUT2;
+ vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT2,
+ rp->evt_msg.data, &(rp->extdata),
+ &(rp->extlen));
+ break;
+
+ case VFE_MSG_ID_STATS_AUTOFOCUS:
+ rp->type = VFE_MSG_STATS_AF;
+ vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_AF,
+ rp->evt_msg.data, NULL, NULL);
+ break;
+
+ case VFE_MSG_ID_STATS_WB_EXP:
+ rp->type = VFE_MSG_STATS_WE;
+ vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_WE,
+ rp->evt_msg.data, NULL, NULL);
+ break;
+
+ default:
+ rp->type = VFE_MSG_GENERAL;
+ break;
+ }
+
+ ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, ctrl->syncdata);
+}
+
+static void vfe_send_msg_no_payload(enum VFE_MESSAGE_ID id)
+{
+ struct vfe_message *msg;
+
+ msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ msg->_d = id;
+ vfe_proc_ops(id, msg, 0);
+}
+
+static void vfe_send_bus_overflow_msg(void)
+{
+ struct vfe_message *msg;
+ msg =
+ kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ msg->_d = VFE_MSG_ID_BUS_OVERFLOW;
+#if 0
+ memcpy(&(msg->_u.msgBusOverflow),
+ &ctrl->vfePmData, sizeof(ctrl->vfePmData));
+#endif
+
+ vfe_proc_ops(VFE_MSG_ID_BUS_OVERFLOW,
+ msg, sizeof(struct vfe_message));
+}
+
+static void vfe_send_camif_error_msg(void)
+{
+#if 0
+ struct vfe_message *msg;
+ msg =
+ kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ msg->_d = VFE_MSG_ID_CAMIF_ERROR;
+ memcpy(&(msg->_u.msgCamifError),
+ &ctrl->vfeCamifStatusLocal, sizeof(ctrl->vfeCamifStatusLocal));
+
+ vfe_proc_ops(VFE_MSG_ID_CAMIF_ERROR,
+ msg, sizeof(struct vfe_message));
+#endif
+}
+
+static void vfe_process_error_irq(
+ struct vfe_interrupt_status *irqstatus)
+{
+ /* all possible error irq. Note error irqs are not enabled, it is
+ * checked only when other interrupts are present. */
+ if (irqstatus->afOverflowIrq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_AF_OVERFLOW);
+
+ if (irqstatus->awbOverflowIrq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_AWB_OVERFLOW);
+
+ if (irqstatus->axiErrorIrq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_AXI_ERROR);
+
+ if (irqstatus->busOverflowIrq)
+ vfe_send_bus_overflow_msg();
+
+ if (irqstatus->camifErrorIrq)
+ vfe_send_camif_error_msg();
+
+ if (irqstatus->camifOverflowIrq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_CAMIF_OVERFLOW);
+
+ if (irqstatus->violationIrq)
+ ;
+}
+
+static void vfe_process_camif_sof_irq(void)
+{
+ /* increment the frame id number. */
+ ctrl->vfeFrameId++;
+
+ CDBG("camif_sof_irq, frameId = %d\n",
+ ctrl->vfeFrameId);
+
+ /* In snapshot mode, if frame skip is programmed,
+ * need to check it accordingly to stop camif at
+ * correct frame boundary. For the dropped frames,
+ * there won't be any output path irqs, but there is
+ * still SOF irq, which can help us determine when
+ * to stop the camif.
+ */
+ if (ctrl->vfeOperationMode) {
+ if ((1 << ctrl->vfeFrameSkipCount) &
+ ctrl->vfeFrameSkipPattern) {
+
+ ctrl->vfeSnapShotCount--;
+ if (ctrl->vfeSnapShotCount == 0)
+ /* terminate vfe pipeline at frame boundary. */
+ writel(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ ctrl->vfebase + CAMIF_COMMAND);
+ }
+
+ /* update frame skip counter for bit checking. */
+ ctrl->vfeFrameSkipCount++;
+ if (ctrl->vfeFrameSkipCount ==
+ (ctrl->vfeFrameSkipPeriod + 1))
+ ctrl->vfeFrameSkipCount = 0;
+ }
+}
+
+static int vfe_get_af_pingpong_status(void)
+{
+ uint32_t busPingPongStatus;
+ int rc = 0;
+
+ busPingPongStatus =
+ readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+ if ((busPingPongStatus & VFE_AF_PINGPONG_STATUS_BIT) == 0)
+ return -EFAULT;
+
+ return rc;
+}
+
+static uint32_t vfe_read_af_buf_addr(boolean pipo)
+{
+ if (pipo == FALSE)
+ return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ else
+ return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static void
+vfe_update_af_buf_addr(boolean pipo, uint32_t addr)
+{
+ if (pipo == FALSE)
+ writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ else
+ writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static void
+vfe_send_af_stats_msg(uint32_t afBufAddress)
+{
+ /* unsigned long flags; */
+ struct vfe_message *msg;
+ msg =
+ kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ /* fill message with right content. */
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ if (ctrl->vstate != VFE_STATE_ACTIVE) {
+ kfree(msg);
+ goto af_stats_done;
+ }
+
+ msg->_d = VFE_MSG_ID_STATS_AUTOFOCUS;
+ msg->_u.msgStatsAf.afBuffer = afBufAddress;
+ msg->_u.msgStatsAf.frameCounter = ctrl->vfeFrameId;
+
+ vfe_proc_ops(VFE_MSG_ID_STATS_AUTOFOCUS,
+ msg, sizeof(struct vfe_message));
+
+ ctrl->afStatsControl.ackPending = TRUE;
+
+af_stats_done:
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+ return;
+}
+
+static void vfe_process_stats_af_irq(void)
+{
+ boolean bufferAvailable;
+
+ if (!(ctrl->afStatsControl.ackPending)) {
+
+ /* read hardware status. */
+ ctrl->afStatsControl.pingPongStatus =
+ vfe_get_af_pingpong_status();
+
+ bufferAvailable =
+ (ctrl->afStatsControl.pingPongStatus) ^ 1;
+
+ ctrl->afStatsControl.bufToRender =
+ vfe_read_af_buf_addr(bufferAvailable);
+
+ /* update the same buffer address (ping or pong) */
+ vfe_update_af_buf_addr(bufferAvailable,
+ ctrl->afStatsControl.nextFrameAddrBuf);
+
+ vfe_send_af_stats_msg(ctrl->afStatsControl.bufToRender);
+ } else
+ ctrl->afStatsControl.droppedStatsFrameCount++;
+}
+
+static boolean vfe_get_awb_pingpong_status(void)
+{
+ uint32_t busPingPongStatus;
+
+ busPingPongStatus =
+ readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+ if ((busPingPongStatus & VFE_AWB_PINGPONG_STATUS_BIT) == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static uint32_t
+vfe_read_awb_buf_addr(boolean pingpong)
+{
+ if (pingpong == FALSE)
+ return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ else
+ return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_update_awb_buf_addr(
+ boolean pingpong, uint32_t addr)
+{
+ if (pingpong == FALSE)
+ writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ else
+ writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_send_awb_stats_msg(uint32_t awbBufAddress)
+{
+ /* unsigned long flags; */
+ struct vfe_message *msg;
+
+ msg =
+ kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ /* fill message with right content. */
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ if (ctrl->vstate != VFE_STATE_ACTIVE) {
+ kfree(msg);
+ goto awb_stats_done;
+ }
+
+ msg->_d = VFE_MSG_ID_STATS_WB_EXP;
+ msg->_u.msgStatsWbExp.awbBuffer = awbBufAddress;
+ msg->_u.msgStatsWbExp.frameCounter = ctrl->vfeFrameId;
+
+ vfe_proc_ops(VFE_MSG_ID_STATS_WB_EXP,
+ msg, sizeof(struct vfe_message));
+
+ ctrl->awbStatsControl.ackPending = TRUE;
+
+awb_stats_done:
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+ return;
+}
+
+static void vfe_process_stats_awb_irq(void)
+{
+ boolean bufferAvailable;
+
+ if (!(ctrl->awbStatsControl.ackPending)) {
+
+ ctrl->awbStatsControl.pingPongStatus =
+ vfe_get_awb_pingpong_status();
+
+ bufferAvailable = (ctrl->awbStatsControl.pingPongStatus) ^ 1;
+
+ ctrl->awbStatsControl.bufToRender =
+ vfe_read_awb_buf_addr(bufferAvailable);
+
+ vfe_update_awb_buf_addr(bufferAvailable,
+ ctrl->awbStatsControl.nextFrameAddrBuf);
+
+ vfe_send_awb_stats_msg(ctrl->awbStatsControl.bufToRender);
+
+ } else
+ ctrl->awbStatsControl.droppedStatsFrameCount++;
+}
+
+static void vfe_process_sync_timer_irq(
+ struct vfe_interrupt_status *irqstatus)
+{
+ if (irqstatus->syncTimer0Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER0_DONE);
+
+ if (irqstatus->syncTimer1Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER1_DONE);
+
+ if (irqstatus->syncTimer2Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER2_DONE);
+}
+
+static void vfe_process_async_timer_irq(
+ struct vfe_interrupt_status *irqstatus)
+{
+
+ if (irqstatus->asyncTimer0Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER0_DONE);
+
+ if (irqstatus->asyncTimer1Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER1_DONE);
+
+ if (irqstatus->asyncTimer2Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER2_DONE);
+
+ if (irqstatus->asyncTimer3Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER3_DONE);
+}
+
+static void vfe_send_violation_msg(void)
+{
+ vfe_send_msg_no_payload(VFE_MSG_ID_VIOLATION);
+}
+
+static void vfe_send_async_timer_msg(void)
+{
+ vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER0_DONE);
+}
+
+static void vfe_write_gamma_table(uint8_t channel,
+ boolean bank, int16_t *pTable)
+{
+ uint16_t i;
+
+ enum VFE_DMI_RAM_SEL dmiRamSel = NO_MEM_SELECTED;
+
+ switch (channel) {
+ case 0:
+ if (bank == 0)
+ dmiRamSel = RGBLUT_RAM_CH0_BANK0;
+ else
+ dmiRamSel = RGBLUT_RAM_CH0_BANK1;
+ break;
+
+ case 1:
+ if (bank == 0)
+ dmiRamSel = RGBLUT_RAM_CH1_BANK0;
+ else
+ dmiRamSel = RGBLUT_RAM_CH1_BANK1;
+ break;
+
+ case 2:
+ if (bank == 0)
+ dmiRamSel = RGBLUT_RAM_CH2_BANK0;
+ else
+ dmiRamSel = RGBLUT_RAM_CH2_BANK1;
+ break;
+
+ default:
+ break;
+ }
+
+ vfe_program_dmi_cfg(dmiRamSel);
+
+ for (i = 0; i < VFE_GAMMA_TABLE_LENGTH; i++) {
+ writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+ pTable++;
+ }
+
+ /* After DMI transfer, need to set the DMI_CFG to unselect any SRAM
+ unselect the SRAM Bank. */
+ writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_prog_hw_testgen_cmd(uint32_t value)
+{
+ writel(value, ctrl->vfebase + VFE_HW_TESTGEN_CMD);
+}
+
+static inline void vfe_read_irq_status(struct vfe_irq_thread_msg *out)
+{
+ uint32_t *temp;
+
+ memset(out, 0, sizeof(struct vfe_irq_thread_msg));
+
+ temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_STATUS);
+ out->vfeIrqStatus = readl(temp);
+
+ temp = (uint32_t *)(ctrl->vfebase + CAMIF_STATUS);
+ out->camifStatus = readl(temp);
+ writel(0x7, ctrl->vfebase + CAMIF_COMMAND);
+ writel(0x3, ctrl->vfebase + CAMIF_COMMAND);
+ CDBG("camifStatus = 0x%x\n", out->camifStatus);
+
+/*
+ temp = (uint32_t *)(ctrl->vfebase + VFE_DEMOSAIC_STATUS);
+ out->demosaicStatus = readl(temp);
+
+ temp = (uint32_t *)(ctrl->vfebase + VFE_ASF_MAX_EDGE);
+ out->asfMaxEdge = readl(temp);
+
+ temp = (uint32_t *)(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PM_STATS_0);
+*/
+
+#if 0
+ out->pmInfo.encPathPmInfo.yWrPmStats0 = readl(temp++);
+ out->pmInfo.encPathPmInfo.yWrPmStats1 = readl(temp++);
+ out->pmInfo.encPathPmInfo.cbcrWrPmStats0 = readl(temp++);
+ out->pmInfo.encPathPmInfo.cbcrWrPmStats1 = readl(temp++);
+ out->pmInfo.viewPathPmInfo.yWrPmStats0 = readl(temp++);
+ out->pmInfo.viewPathPmInfo.yWrPmStats1 = readl(temp++);
+ out->pmInfo.viewPathPmInfo.cbcrWrPmStats0 = readl(temp++);
+ out->pmInfo.viewPathPmInfo.cbcrWrPmStats1 = readl(temp);
+#endif /* if 0 Jeff */
+}
+
+static struct vfe_interrupt_status
+vfe_parse_interrupt_status(uint32_t irqStatusIn)
+{
+ struct vfe_irqenable hwstat;
+ struct vfe_interrupt_status ret;
+ boolean temp;
+
+ memset(&hwstat, 0, sizeof(hwstat));
+ memset(&ret, 0, sizeof(ret));
+
+ hwstat = *((struct vfe_irqenable *)(&irqStatusIn));
+
+ ret.camifErrorIrq = hwstat.camifErrorIrq;
+ ret.camifSofIrq = hwstat.camifSofIrq;
+ ret.camifEolIrq = hwstat.camifEolIrq;
+ ret.camifEofIrq = hwstat.camifEofIrq;
+ ret.camifEpoch1Irq = hwstat.camifEpoch1Irq;
+ ret.camifEpoch2Irq = hwstat.camifEpoch2Irq;
+ ret.camifOverflowIrq = hwstat.camifOverflowIrq;
+ ret.ceIrq = hwstat.ceIrq;
+ ret.regUpdateIrq = hwstat.regUpdateIrq;
+ ret.resetAckIrq = hwstat.resetAckIrq;
+ ret.encYPingpongIrq = hwstat.encYPingpongIrq;
+ ret.encCbcrPingpongIrq = hwstat.encCbcrPingpongIrq;
+ ret.viewYPingpongIrq = hwstat.viewYPingpongIrq;
+ ret.viewCbcrPingpongIrq = hwstat.viewCbcrPingpongIrq;
+ ret.rdPingpongIrq = hwstat.rdPingpongIrq;
+ ret.afPingpongIrq = hwstat.afPingpongIrq;
+ ret.awbPingpongIrq = hwstat.awbPingpongIrq;
+ ret.histPingpongIrq = hwstat.histPingpongIrq;
+ ret.encIrq = hwstat.encIrq;
+ ret.viewIrq = hwstat.viewIrq;
+ ret.busOverflowIrq = hwstat.busOverflowIrq;
+ ret.afOverflowIrq = hwstat.afOverflowIrq;
+ ret.awbOverflowIrq = hwstat.awbOverflowIrq;
+ ret.syncTimer0Irq = hwstat.syncTimer0Irq;
+ ret.syncTimer1Irq = hwstat.syncTimer1Irq;
+ ret.syncTimer2Irq = hwstat.syncTimer2Irq;
+ ret.asyncTimer0Irq = hwstat.asyncTimer0Irq;
+ ret.asyncTimer1Irq = hwstat.asyncTimer1Irq;
+ ret.asyncTimer2Irq = hwstat.asyncTimer2Irq;
+ ret.asyncTimer3Irq = hwstat.asyncTimer3Irq;
+ ret.axiErrorIrq = hwstat.axiErrorIrq;
+ ret.violationIrq = hwstat.violationIrq;
+
+ /* logic OR of any error bits
+ * although each irq corresponds to a bit, the data type here is a
+ * boolean already. hence use logic operation.
+ */
+ temp =
+ ret.camifErrorIrq ||
+ ret.camifOverflowIrq ||
+ ret.afOverflowIrq ||
+ ret.awbPingpongIrq ||
+ ret.busOverflowIrq ||
+ ret.axiErrorIrq ||
+ ret.violationIrq;
+
+ ret.anyErrorIrqs = temp;
+
+ /* logic OR of any output path bits*/
+ temp =
+ ret.encYPingpongIrq ||
+ ret.encCbcrPingpongIrq ||
+ ret.encIrq;
+
+ ret.anyOutput2PathIrqs = temp;
+
+ temp =
+ ret.viewYPingpongIrq ||
+ ret.viewCbcrPingpongIrq ||
+ ret.viewIrq;
+
+ ret.anyOutput1PathIrqs = temp;
+
+ ret.anyOutputPathIrqs =
+ ret.anyOutput1PathIrqs ||
+ ret.anyOutput2PathIrqs;
+
+ /* logic OR of any sync timer bits*/
+ temp =
+ ret.syncTimer0Irq ||
+ ret.syncTimer1Irq ||
+ ret.syncTimer2Irq;
+
+ ret.anySyncTimerIrqs = temp;
+
+ /* logic OR of any async timer bits*/
+ temp =
+ ret.asyncTimer0Irq ||
+ ret.asyncTimer1Irq ||
+ ret.asyncTimer2Irq ||
+ ret.asyncTimer3Irq;
+
+ ret.anyAsyncTimerIrqs = temp;
+
+ /* bool for all interrupts that are not allowed in idle state */
+ temp =
+ ret.anyErrorIrqs ||
+ ret.anyOutputPathIrqs ||
+ ret.anySyncTimerIrqs ||
+ ret.regUpdateIrq ||
+ ret.awbPingpongIrq ||
+ ret.afPingpongIrq ||
+ ret.camifSofIrq ||
+ ret.camifEpoch2Irq ||
+ ret.camifEpoch1Irq;
+
+ ret.anyIrqForActiveStatesOnly =
+ temp;
+
+ return ret;
+}
+
+static struct vfe_frame_asf_info
+vfe_get_asf_frame_info(struct vfe_irq_thread_msg *in)
+{
+ struct vfe_asf_info asfInfoTemp;
+ struct vfe_frame_asf_info rc;
+
+ memset(&rc, 0, sizeof(rc));
+ memset(&asfInfoTemp, 0, sizeof(asfInfoTemp));
+
+ asfInfoTemp =
+ *((struct vfe_asf_info *)(&(in->asfMaxEdge)));
+
+ rc.asfHbiCount = asfInfoTemp.HBICount;
+ rc.asfMaxEdge = asfInfoTemp.maxEdge;
+
+ return rc;
+}
+
+static struct vfe_frame_bpc_info
+vfe_get_demosaic_frame_info(struct vfe_irq_thread_msg *in)
+{
+ struct vfe_bps_info bpcInfoTemp;
+ struct vfe_frame_bpc_info rc;
+
+ memset(&rc, 0, sizeof(rc));
+ memset(&bpcInfoTemp, 0, sizeof(bpcInfoTemp));
+
+ bpcInfoTemp =
+ *((struct vfe_bps_info *)(&(in->demosaicStatus)));
+
+ rc.greenDefectPixelCount =
+ bpcInfoTemp.greenBadPixelCount;
+
+ rc.redBlueDefectPixelCount =
+ bpcInfoTemp.RedBlueBadPixelCount;
+
+ return rc;
+}
+
+static struct vfe_msg_camif_status
+vfe_get_camif_status(struct vfe_irq_thread_msg *in)
+{
+ struct vfe_camif_stats camifStatusTemp;
+ struct vfe_msg_camif_status rc;
+
+ memset(&rc, 0, sizeof(rc));
+ memset(&camifStatusTemp, 0, sizeof(camifStatusTemp));
+
+ camifStatusTemp =
+ *((struct vfe_camif_stats *)(&(in->camifStatus)));
+
+ rc.camifState = (boolean)camifStatusTemp.camifHalt;
+ rc.lineCount = camifStatusTemp.lineCount;
+ rc.pixelCount = camifStatusTemp.pixelCount;
+
+ return rc;
+}
+
+static struct vfe_bus_performance_monitor
+vfe_get_performance_monitor_data(struct vfe_irq_thread_msg *in)
+{
+ struct vfe_bus_performance_monitor rc;
+ memset(&rc, 0, sizeof(rc));
+
+ rc.encPathPmInfo.yWrPmStats0 =
+ in->pmInfo.encPathPmInfo.yWrPmStats0;
+ rc.encPathPmInfo.yWrPmStats1 =
+ in->pmInfo.encPathPmInfo.yWrPmStats1;
+ rc.encPathPmInfo.cbcrWrPmStats0 =
+ in->pmInfo.encPathPmInfo.cbcrWrPmStats0;
+ rc.encPathPmInfo.cbcrWrPmStats1 =
+ in->pmInfo.encPathPmInfo.cbcrWrPmStats1;
+ rc.viewPathPmInfo.yWrPmStats0 =
+ in->pmInfo.viewPathPmInfo.yWrPmStats0;
+ rc.viewPathPmInfo.yWrPmStats1 =
+ in->pmInfo.viewPathPmInfo.yWrPmStats1;
+ rc.viewPathPmInfo.cbcrWrPmStats0 =
+ in->pmInfo.viewPathPmInfo.cbcrWrPmStats0;
+ rc.viewPathPmInfo.cbcrWrPmStats1 =
+ in->pmInfo.viewPathPmInfo.cbcrWrPmStats1;
+
+ return rc;
+}
+
+static void vfe_process_reg_update_irq(void)
+{
+ CDBG("vfe_process_reg_update_irq: ackPendingFlag is %d\n",
+ ctrl->vfeStartAckPendingFlag);
+ if (ctrl->vfeStartAckPendingFlag == TRUE) {
+ vfe_send_msg_no_payload(VFE_MSG_ID_START_ACK);
+ ctrl->vfeStartAckPendingFlag = FALSE;
+ } else
+ vfe_send_msg_no_payload(VFE_MSG_ID_UPDATE_ACK);
+}
+
+static void vfe_process_reset_irq(void)
+{
+ /* unsigned long flags; */
+
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ ctrl->vstate = VFE_STATE_IDLE;
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+
+ if (ctrl->vfeStopAckPending == TRUE) {
+ ctrl->vfeStopAckPending = FALSE;
+ vfe_send_msg_no_payload(VFE_MSG_ID_STOP_ACK);
+ } else {
+ vfe_set_default_reg_values();
+ vfe_send_msg_no_payload(VFE_MSG_ID_RESET_ACK);
+ }
+}
+
+static void vfe_process_pingpong_irq(struct vfe_output_path *in,
+ uint8_t fragmentCount)
+{
+ uint16_t circularIndex;
+ uint32_t nextFragmentAddr;
+
+ /* get next fragment address from circular buffer */
+ circularIndex = (in->fragIndex) % (2 * fragmentCount);
+ nextFragmentAddr = in->addressBuffer[circularIndex];
+
+ in->fragIndex = circularIndex + 1;
+
+ /* use next fragment to program hardware ping/pong address. */
+ if (in->hwCurrentFlag == ping) {
+ writel(nextFragmentAddr, in->hwRegPingAddress);
+ in->hwCurrentFlag = pong;
+
+ } else {
+ writel(nextFragmentAddr, in->hwRegPongAddress);
+ in->hwCurrentFlag = ping;
+ }
+}
+
+static void vfe_send_output2_msg(
+ struct vfe_msg_output *pPayload)
+{
+ /* unsigned long flags; */
+ struct vfe_message *msg;
+
+ msg = kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ /* fill message with right content. */
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ if (ctrl->vstate != VFE_STATE_ACTIVE) {
+ kfree(msg);
+ goto output2_msg_done;
+ }
+
+ msg->_d = VFE_MSG_ID_OUTPUT2;
+
+ memcpy(&(msg->_u.msgOutput2),
+ (void *)pPayload, sizeof(struct vfe_msg_output));
+
+ vfe_proc_ops(VFE_MSG_ID_OUTPUT2,
+ msg, sizeof(struct vfe_message));
+
+ ctrl->encPath.ackPending = TRUE;
+
+ if (!(ctrl->vfeRequestedSnapShotCount <= 3) &&
+ (ctrl->vfeOperationMode ==
+ VFE_START_OPERATION_MODE_SNAPSHOT))
+ ctrl->encPath.ackPending = TRUE;
+
+output2_msg_done:
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+ return;
+}
+
+static void vfe_send_output1_msg(
+ struct vfe_msg_output *pPayload)
+{
+ /* unsigned long flags; */
+ struct vfe_message *msg;
+
+ msg = kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ if (ctrl->vstate != VFE_STATE_ACTIVE) {
+ kfree(msg);
+ goto output1_msg_done;
+ }
+
+ msg->_d = VFE_MSG_ID_OUTPUT1;
+ memmove(&(msg->_u),
+ (void *)pPayload, sizeof(struct vfe_msg_output));
+
+ vfe_proc_ops(VFE_MSG_ID_OUTPUT1,
+ msg, sizeof(struct vfe_message));
+
+ ctrl->viewPath.ackPending = TRUE;
+
+ if (!(ctrl->vfeRequestedSnapShotCount <= 3) &&
+ (ctrl->vfeOperationMode ==
+ VFE_START_OPERATION_MODE_SNAPSHOT))
+ ctrl->viewPath.ackPending = TRUE;
+
+output1_msg_done:
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+ return;
+}
+
+static void vfe_send_output_msg(boolean whichOutputPath,
+ uint32_t yPathAddr, uint32_t cbcrPathAddr)
+{
+ struct vfe_msg_output msgPayload;
+
+ msgPayload.yBuffer = yPathAddr;
+ msgPayload.cbcrBuffer = cbcrPathAddr;
+
+ /* asf info is common for both output1 and output2 */
+#if 0
+ msgPayload.asfInfo.asfHbiCount = ctrl->vfeAsfFrameInfo.asfHbiCount;
+ msgPayload.asfInfo.asfMaxEdge = ctrl->vfeAsfFrameInfo.asfMaxEdge;
+
+ /* demosaic info is common for both output1 and output2 */
+ msgPayload.bpcInfo.greenDefectPixelCount =
+ ctrl->vfeBpcFrameInfo.greenDefectPixelCount;
+ msgPayload.bpcInfo.redBlueDefectPixelCount =
+ ctrl->vfeBpcFrameInfo.redBlueDefectPixelCount;
+#endif /* if 0 */
+
+ /* frame ID is common for both paths. */
+ msgPayload.frameCounter = ctrl->vfeFrameId;
+
+ if (whichOutputPath) {
+ /* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */
+ vfe_send_output2_msg(&msgPayload);
+ } else {
+ /* msgPayload.pmData = ctrl->vfePmData.viewPathPmInfo; */
+ vfe_send_output1_msg(&msgPayload);
+ }
+}
+
+static void vfe_process_frame_done_irq_multi_frag(
+ struct vfe_output_path_combo *in)
+{
+ uint32_t yAddress, cbcrAddress;
+ uint16_t idx;
+ uint32_t *ptrY;
+ uint32_t *ptrCbcr;
+ const uint32_t *ptrSrc;
+ uint8_t i;
+
+ if (!in->ackPending) {
+
+ idx = (in->currentFrame) * (in->fragCount);
+
+ /* Send output message. */
+ yAddress = in->yPath.addressBuffer[idx];
+ cbcrAddress = in->cbcrPath.addressBuffer[idx];
+
+ /* copy next frame to current frame. */
+ ptrSrc = in->nextFrameAddrBuf;
+ ptrY = (uint32_t *)&(in->yPath.addressBuffer[idx]);
+ ptrCbcr = (uint32_t *)&(in->cbcrPath.addressBuffer[idx]);
+
+ /* Copy Y address */
+ for (i = 0; i < in->fragCount; i++)
+ *ptrY++ = *ptrSrc++;
+
+ /* Copy Cbcr address */
+ for (i = 0; i < in->fragCount; i++)
+ *ptrCbcr++ = *ptrSrc++;
+
+ vfe_send_output_msg(in->whichOutputPath, yAddress, cbcrAddress);
+
+ } else {
+ if (in->whichOutputPath == 0)
+ ctrl->vfeDroppedFrameCounts.output1Count++;
+
+ if (in->whichOutputPath == 1)
+ ctrl->vfeDroppedFrameCounts.output2Count++;
+ }
+
+ /* toggle current frame. */
+ in->currentFrame = in->currentFrame^1;
+
+ if (ctrl->vfeOperationMode)
+ in->snapshotPendingCount--;
+}
+
+static void vfe_process_frame_done_irq_no_frag_io(
+ struct vfe_output_path_combo *in, uint32_t *pNextAddr,
+ uint32_t *pdestRenderAddr)
+{
+ uint32_t busPingPongStatus;
+ uint32_t tempAddress;
+
+ /* 1. read hw status register. */
+ busPingPongStatus =
+ readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+ CDBG("hardware status is 0x%x\n", busPingPongStatus);
+
+ /* 2. determine ping or pong */
+ /* use cbcr status */
+ busPingPongStatus = busPingPongStatus & (1<<(in->cbcrStatusBit));
+
+ /* 3. read out address and update address */
+ if (busPingPongStatus == 0) {
+ /* hw is working on ping, render pong buffer */
+ /* a. read out pong address */
+ /* read out y address. */
+ tempAddress = readl(in->yPath.hwRegPongAddress);
+
+ CDBG("pong 1 addr = 0x%x\n", tempAddress);
+ *pdestRenderAddr++ = tempAddress;
+ /* read out cbcr address. */
+ tempAddress = readl(in->cbcrPath.hwRegPongAddress);
+
+ CDBG("pong 2 addr = 0x%x\n", tempAddress);
+ *pdestRenderAddr = tempAddress;
+
+ /* b. update pong address */
+ writel(*pNextAddr++, in->yPath.hwRegPongAddress);
+ writel(*pNextAddr, in->cbcrPath.hwRegPongAddress);
+ } else {
+ /* hw is working on pong, render ping buffer */
+
+ /* a. read out ping address */
+ tempAddress = readl(in->yPath.hwRegPingAddress);
+ CDBG("ping 1 addr = 0x%x\n", tempAddress);
+ *pdestRenderAddr++ = tempAddress;
+ tempAddress = readl(in->cbcrPath.hwRegPingAddress);
+
+ CDBG("ping 2 addr = 0x%x\n", tempAddress);
+ *pdestRenderAddr = tempAddress;
+
+ /* b. update ping address */
+ writel(*pNextAddr++, in->yPath.hwRegPingAddress);
+ CDBG("NextAddress = 0x%x\n", *pNextAddr);
+ writel(*pNextAddr, in->cbcrPath.hwRegPingAddress);
+ }
+}
+
+static void vfe_process_frame_done_irq_no_frag(
+ struct vfe_output_path_combo *in)
+{
+ uint32_t addressToRender[2];
+ static uint32_t fcnt;
+
+ if (fcnt++ < 3)
+ return;
+
+ if (!in->ackPending) {
+ vfe_process_frame_done_irq_no_frag_io(in,
+ in->nextFrameAddrBuf, addressToRender);
+
+ /* use addressToRender to send out message. */
+ vfe_send_output_msg(in->whichOutputPath,
+ addressToRender[0], addressToRender[1]);
+
+ } else {
+ /* ackPending is still there, accumulate dropped frame count.
+ * These count can be read through ioctrl command. */
+ CDBG("waiting frame ACK\n");
+
+ if (in->whichOutputPath == 0)
+ ctrl->vfeDroppedFrameCounts.output1Count++;
+
+ if (in->whichOutputPath == 1)
+ ctrl->vfeDroppedFrameCounts.output2Count++;
+ }
+
+ /* in case of multishot when upper layer did not ack, there will still
+ * be a snapshot done msg sent out, even though the number of frames
+ * sent out may be less than the desired number of frames. snapshot
+ * done msg would be helpful to indicate that vfe pipeline has stop,
+ * and in good known state.
+ */
+ if (ctrl->vfeOperationMode)
+ in->snapshotPendingCount--;
+}
+
+static void vfe_process_output_path_irq(
+ struct vfe_interrupt_status *irqstatus)
+{
+ /* unsigned long flags; */
+
+ /* process the view path interrupts */
+ if (irqstatus->anyOutput1PathIrqs) {
+ if (ctrl->viewPath.multiFrag) {
+
+ if (irqstatus->viewCbcrPingpongIrq)
+ vfe_process_pingpong_irq(
+ &(ctrl->viewPath.cbcrPath),
+ ctrl->viewPath.fragCount);
+
+ if (irqstatus->viewYPingpongIrq)
+ vfe_process_pingpong_irq(
+ &(ctrl->viewPath.yPath),
+ ctrl->viewPath.fragCount);
+
+ if (irqstatus->viewIrq)
+ vfe_process_frame_done_irq_multi_frag(
+ &ctrl->viewPath);
+
+ } else {
+ /* typical case for no fragment,
+ only frame done irq is enabled. */
+ if (irqstatus->viewIrq)
+ vfe_process_frame_done_irq_no_frag(
+ &ctrl->viewPath);
+ }
+ }
+
+ /* process the encoder path interrupts */
+ if (irqstatus->anyOutput2PathIrqs) {
+ if (ctrl->encPath.multiFrag) {
+ if (irqstatus->encCbcrPingpongIrq)
+ vfe_process_pingpong_irq(
+ &(ctrl->encPath.cbcrPath),
+ ctrl->encPath.fragCount);
+
+ if (irqstatus->encYPingpongIrq)
+ vfe_process_pingpong_irq(&(ctrl->encPath.yPath),
+ ctrl->encPath.fragCount);
+
+ if (irqstatus->encIrq)
+ vfe_process_frame_done_irq_multi_frag(
+ &ctrl->encPath);
+
+ } else {
+ if (irqstatus->encIrq)
+ vfe_process_frame_done_irq_no_frag(
+ &ctrl->encPath);
+ }
+ }
+
+ if (ctrl->vfeOperationMode) {
+ if ((ctrl->encPath.snapshotPendingCount == 0) &&
+ (ctrl->viewPath.snapshotPendingCount == 0)) {
+
+ /* @todo This is causing issues, further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ ctrl->vstate = VFE_STATE_IDLE;
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+
+ vfe_send_msg_no_payload(VFE_MSG_ID_SNAPSHOT_DONE);
+ vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+ vfe_pm_stop();
+ }
+ }
+}
+
+static void vfe_do_tasklet(unsigned long data)
+{
+ unsigned long flags;
+
+ struct isr_queue_cmd *qcmd = NULL;
+
+ CDBG("=== vfe_do_tasklet start === \n");
+
+ spin_lock_irqsave(&ctrl->tasklet_lock, flags);
+ qcmd = list_first_entry(&ctrl->tasklet_q,
+ struct isr_queue_cmd, list);
+
+ if (!qcmd) {
+ spin_unlock_irqrestore(&ctrl->tasklet_lock, flags);
+ return;
+ }
+
+ list_del(&qcmd->list);
+ spin_unlock_irqrestore(&ctrl->tasklet_lock, flags);
+
+ if (qcmd->vfeInterruptStatus.regUpdateIrq) {
+ CDBG("irq regUpdateIrq\n");
+ vfe_process_reg_update_irq();
+ }
+
+ if (qcmd->vfeInterruptStatus.resetAckIrq) {
+ CDBG("irq resetAckIrq\n");
+ vfe_process_reset_irq();
+ }
+
+ spin_lock_irqsave(&ctrl->state_lock, flags);
+ if (ctrl->vstate != VFE_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&ctrl->state_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&ctrl->state_lock, flags);
+
+#if 0
+ if (qcmd->vfeInterruptStatus.camifEpoch1Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_EPOCH1);
+
+ if (qcmd->vfeInterruptStatus.camifEpoch2Irq)
+ vfe_send_msg_no_payload(VFE_MSG_ID_EPOCH2);
+#endif /* Jeff */
+
+ /* next, check output path related interrupts. */
+ if (qcmd->vfeInterruptStatus.anyOutputPathIrqs) {
+ CDBG("irq anyOutputPathIrqs\n");
+ vfe_process_output_path_irq(&qcmd->vfeInterruptStatus);
+ }
+
+ if (qcmd->vfeInterruptStatus.afPingpongIrq)
+ vfe_process_stats_af_irq();
+
+ if (qcmd->vfeInterruptStatus.awbPingpongIrq)
+ vfe_process_stats_awb_irq();
+
+ /* any error irqs*/
+ if (qcmd->vfeInterruptStatus.anyErrorIrqs)
+ vfe_process_error_irq(&qcmd->vfeInterruptStatus);
+
+#if 0
+ if (qcmd->vfeInterruptStatus.anySyncTimerIrqs)
+ vfe_process_sync_timer_irq();
+
+ if (qcmd->vfeInterruptStatus.anyAsyncTimerIrqs)
+ vfe_process_async_timer_irq();
+#endif /* Jeff */
+
+ if (qcmd->vfeInterruptStatus.camifSofIrq) {
+ CDBG("irq camifSofIrq\n");
+ vfe_process_camif_sof_irq();
+ }
+
+ kfree(qcmd);
+ CDBG("=== vfe_do_tasklet end === \n");
+}
+
+DECLARE_TASKLET(vfe_tasklet, vfe_do_tasklet, 0);
+
+static irqreturn_t vfe_parse_irq(int irq_num, void *data)
+{
+ unsigned long flags;
+ uint32_t irqStatusLocal;
+ struct vfe_irq_thread_msg irq;
+ struct isr_queue_cmd *qcmd;
+
+ CDBG("vfe_parse_irq\n");
+
+ vfe_read_irq_status(&irq);
+
+ if (irq.vfeIrqStatus == 0) {
+ CDBG("vfe_parse_irq: irq.vfeIrqStatus is 0\n");
+ return IRQ_HANDLED;
+ }
+
+ qcmd = kzalloc(sizeof(struct isr_queue_cmd),
+ GFP_ATOMIC);
+ if (!qcmd) {
+ CDBG("vfe_parse_irq: qcmd malloc failed!\n");
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&ctrl->ack_lock, flags);
+
+ if (ctrl->vfeStopAckPending)
+ irqStatusLocal =
+ (VFE_IMASK_WHILE_STOPPING & irq.vfeIrqStatus);
+ else
+ irqStatusLocal =
+ ((ctrl->vfeImaskPacked | VFE_IMASK_ERROR_ONLY) &
+ irq.vfeIrqStatus);
+
+ spin_unlock_irqrestore(&ctrl->ack_lock, flags);
+
+ /* first parse the interrupt status to local data structures. */
+ qcmd->vfeInterruptStatus = vfe_parse_interrupt_status(irqStatusLocal);
+ qcmd->vfeAsfFrameInfo = vfe_get_asf_frame_info(&irq);
+ qcmd->vfeBpcFrameInfo = vfe_get_demosaic_frame_info(&irq);
+ qcmd->vfeCamifStatusLocal = vfe_get_camif_status(&irq);
+ qcmd->vfePmData = vfe_get_performance_monitor_data(&irq);
+
+ spin_lock_irqsave(&ctrl->tasklet_lock, flags);
+ list_add_tail(&qcmd->list, &ctrl->tasklet_q);
+ spin_unlock_irqrestore(&ctrl->tasklet_lock, flags);
+ tasklet_schedule(&vfe_tasklet);
+
+ /* clear the pending interrupt of the same kind.*/
+ writel(irq.vfeIrqStatus, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+ return IRQ_HANDLED;
+}
+
+int vfe_cmd_init(struct msm_vfe_callback *presp,
+ struct platform_device *pdev, void *sdata)
+{
+ struct resource *vfemem, *vfeirq, *vfeio;
+ int rc;
+
+ vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!vfemem) {
+ CDBG("no mem resource?\n");
+ return -ENODEV;
+ }
+
+ vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!vfeirq) {
+ CDBG("no irq resource?\n");
+ return -ENODEV;
+ }
+
+ vfeio = request_mem_region(vfemem->start,
+ resource_size(vfemem), pdev->name);
+ if (!vfeio) {
+ CDBG("VFE region already claimed\n");
+ return -EBUSY;
+ }
+
+ ctrl =
+ kzalloc(sizeof(struct msm_vfe8x_ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ rc = -ENOMEM;
+ goto cmd_init_failed1;
+ }
+
+ ctrl->vfeirq = vfeirq->start;
+
+ ctrl->vfebase =
+ ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
+ if (!ctrl->vfebase) {
+ rc = -ENOMEM;
+ goto cmd_init_failed2;
+ }
+
+ rc = request_irq(ctrl->vfeirq, vfe_parse_irq,
+ IRQF_TRIGGER_RISING, "vfe", 0);
+ if (rc < 0)
+ goto cmd_init_failed2;
+
+ if (presp && presp->vfe_resp)
+ ctrl->resp = presp;
+ else {
+ rc = -EINVAL;
+ goto cmd_init_failed3;
+ }
+
+ ctrl->extdata =
+ kmalloc(sizeof(struct vfe_frame_extra), GFP_KERNEL);
+ if (!ctrl->extdata) {
+ rc = -ENOMEM;
+ goto cmd_init_failed3;
+ }
+
+ spin_lock_init(&ctrl->ack_lock);
+ spin_lock_init(&ctrl->state_lock);
+ spin_lock_init(&ctrl->io_lock);
+
+ ctrl->extlen = sizeof(struct vfe_frame_extra);
+
+ spin_lock_init(&ctrl->tasklet_lock);
+ INIT_LIST_HEAD(&ctrl->tasklet_q);
+
+ ctrl->syncdata = sdata;
+ return 0;
+
+cmd_init_failed3:
+ disable_irq(ctrl->vfeirq);
+ free_irq(ctrl->vfeirq, 0);
+ iounmap(ctrl->vfebase);
+cmd_init_failed2:
+ kfree(ctrl);
+cmd_init_failed1:
+ release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+ return rc;
+}
+
+void vfe_cmd_release(struct platform_device *dev)
+{
+ struct resource *mem;
+
+ disable_irq(ctrl->vfeirq);
+ free_irq(ctrl->vfeirq, 0);
+
+ iounmap(ctrl->vfebase);
+ mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ ctrl->extlen = 0;
+
+ kfree(ctrl->extdata);
+ kfree(ctrl);
+}
+
+void vfe_stats_af_stop(void)
+{
+ ctrl->vfeStatsCmdLocal.autoFocusEnable = FALSE;
+ ctrl->vfeImaskLocal.afPingpongIrq = FALSE;
+}
+
+void vfe_stop(void)
+{
+ boolean vfeAxiBusy;
+ uint32_t vfeAxiStauts;
+
+ /* for reset hw modules, and send msg when reset_irq comes.*/
+ ctrl->vfeStopAckPending = TRUE;
+
+ ctrl->vfeStatsPingPongReloadFlag = FALSE;
+ vfe_pm_stop();
+
+ /* disable all interrupts. */
+ vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS);
+
+ /* in either continuous or snapshot mode, stop command can be issued
+ * at any time.
+ */
+ vfe_camif_stop_immediately();
+ vfe_program_axi_cmd(AXI_HALT);
+ vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+
+ vfeAxiBusy = TRUE;
+
+ while (vfeAxiBusy) {
+ vfeAxiStauts = vfe_read_axi_status();
+ if ((vfeAxiStauts & AXI_STATUS_BUSY_MASK) != 0)
+ vfeAxiBusy = FALSE;
+ }
+
+ vfe_program_axi_cmd(AXI_HALT_CLEAR);
+
+ /* clear all pending interrupts */
+ writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+ /* enable reset_ack and async timer interrupt only while stopping
+ * the pipeline.
+ */
+ vfe_program_irq_mask(VFE_IMASK_WHILE_STOPPING);
+
+ vfe_program_global_reset_cmd(VFE_RESET_UPON_STOP_CMD);
+}
+
+void vfe_update(void)
+{
+ ctrl->vfeModuleEnableLocal.statsEnable =
+ ctrl->vfeStatsCmdLocal.autoFocusEnable |
+ ctrl->vfeStatsCmdLocal.axwEnable;
+
+ vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+ vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+ ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+ vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+ if ((ctrl->vfeModuleEnableLocal.statsEnable == TRUE) &&
+ (ctrl->vfeStatsPingPongReloadFlag == FALSE)) {
+ ctrl->vfeStatsPingPongReloadFlag = TRUE;
+
+ ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+ vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+ }
+
+ vfe_program_reg_update_cmd(VFE_REG_UPDATE_TRIGGER);
+}
+
+int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *in)
+{
+ int rc = 0;
+
+ ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+ switch (in->channelSelect) {
+ case RGB_GAMMA_CH0_SELECTED:
+ ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+ vfe_write_gamma_table(0,
+ ctrl->vfeGammaLutSel.ch0BankSelect, in->table);
+ break;
+
+ case RGB_GAMMA_CH1_SELECTED:
+ ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+ vfe_write_gamma_table(1,
+ ctrl->vfeGammaLutSel.ch1BankSelect, in->table);
+ break;
+
+ case RGB_GAMMA_CH2_SELECTED:
+ ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+ vfe_write_gamma_table(2,
+ ctrl->vfeGammaLutSel.ch2BankSelect, in->table);
+ break;
+
+ case RGB_GAMMA_CH0_CH1_SELECTED:
+ ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+ ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+ vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+ in->table);
+ vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+ in->table);
+ break;
+
+ case RGB_GAMMA_CH0_CH2_SELECTED:
+ ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+ ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+ vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+ in->table);
+ vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+ in->table);
+ break;
+
+ case RGB_GAMMA_CH1_CH2_SELECTED:
+ ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+ ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+ vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+ in->table);
+ vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+ in->table);
+ break;
+
+ case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+ ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+ ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+ ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+ vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+ in->table);
+ vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+ in->table);
+ vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+ in->table);
+ break;
+
+ default:
+ return -EINVAL;
+ } /* switch */
+
+ /* update the gammaLutSel register. */
+ vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+ return rc;
+}
+
+int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *in)
+{
+ int rc = 0;
+
+ ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+ switch (in->channelSelect) {
+ case RGB_GAMMA_CH0_SELECTED:
+vfe_write_gamma_table(0, 0, in->table);
+break;
+
+ case RGB_GAMMA_CH1_SELECTED:
+ vfe_write_gamma_table(1, 0, in->table);
+ break;
+
+ case RGB_GAMMA_CH2_SELECTED:
+ vfe_write_gamma_table(2, 0, in->table);
+ break;
+
+ case RGB_GAMMA_CH0_CH1_SELECTED:
+ vfe_write_gamma_table(0, 0, in->table);
+ vfe_write_gamma_table(1, 0, in->table);
+ break;
+
+ case RGB_GAMMA_CH0_CH2_SELECTED:
+ vfe_write_gamma_table(0, 0, in->table);
+ vfe_write_gamma_table(2, 0, in->table);
+ break;
+
+ case RGB_GAMMA_CH1_CH2_SELECTED:
+ vfe_write_gamma_table(1, 0, in->table);
+ vfe_write_gamma_table(2, 0, in->table);
+ break;
+
+ case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+ vfe_write_gamma_table(0, 0, in->table);
+ vfe_write_gamma_table(1, 0, in->table);
+ vfe_write_gamma_table(2, 0, in->table);
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ } /* switch */
+
+ return rc;
+}
+
+void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *in)
+{
+ ctrl->afStatsControl.nextFrameAddrBuf = in->nextAFOutputBufferAddr;
+ ctrl->afStatsControl.ackPending = FALSE;
+}
+
+void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *in)
+{
+ ctrl->awbStatsControl.nextFrameAddrBuf = in->nextWbExpOutputBufferAddr;
+ ctrl->awbStatsControl.ackPending = FALSE;
+}
+
+void vfe_output2_ack(struct vfe_cmd_output_ack *in)
+{
+ const uint32_t *psrc;
+ uint32_t *pdest;
+ uint8_t i;
+
+ pdest = ctrl->encPath.nextFrameAddrBuf;
+
+ CDBG("output2_ack: ack addr = 0x%x\n", in->ybufaddr[0]);
+
+ psrc = in->ybufaddr;
+ for (i = 0; i < ctrl->encPath.fragCount; i++)
+ *pdest++ = *psrc++;
+
+ psrc = in->chromabufaddr;
+ for (i = 0; i < ctrl->encPath.fragCount; i++)
+ *pdest++ = *psrc++;
+
+ ctrl->encPath.ackPending = FALSE;
+}
+
+void vfe_output1_ack(struct vfe_cmd_output_ack *in)
+{
+ const uint32_t *psrc;
+ uint32_t *pdest;
+ uint8_t i;
+
+ pdest = ctrl->viewPath.nextFrameAddrBuf;
+
+ psrc = in->ybufaddr;
+ for (i = 0; i < ctrl->viewPath.fragCount; i++)
+ *pdest++ = *psrc++;
+
+ psrc = in->chromabufaddr;
+ for (i = 0; i < ctrl->viewPath.fragCount; i++)
+ *pdest++ = *psrc++;
+
+ ctrl->viewPath.ackPending = FALSE;
+}
+
+void vfe_start(struct vfe_cmd_start *in)
+{
+ unsigned long flags;
+ uint32_t pmstatus = 0;
+ boolean rawmode;
+ uint32_t demperiod = 0;
+ uint32_t demeven = 0;
+ uint32_t demodd = 0;
+
+ /* derived from other commands. (camif config, axi output config,
+ * etc)
+ */
+ struct vfe_cfg hwcfg;
+ struct vfe_upsample_cfg chromupcfg;
+
+ CDBG("vfe_start operationMode = %d\n", in->operationMode);
+
+ memset(&hwcfg, 0, sizeof(hwcfg));
+ memset(&chromupcfg, 0, sizeof(chromupcfg));
+
+ switch (in->pixel) {
+ case VFE_BAYER_RGRGRG:
+ demperiod = 1;
+ demeven = 0xC9;
+ demodd = 0xAC;
+ break;
+
+ case VFE_BAYER_GRGRGR:
+ demperiod = 1;
+ demeven = 0x9C;
+ demodd = 0xCA;
+ break;
+
+ case VFE_BAYER_BGBGBG:
+ demperiod = 1;
+ demeven = 0xCA;
+ demodd = 0x9C;
+ break;
+
+ case VFE_BAYER_GBGBGB:
+ demperiod = 1;
+ demeven = 0xAC;
+ demodd = 0xC9;
+ break;
+
+ case VFE_YUV_YCbYCr:
+ demperiod = 3;
+ demeven = 0x9CAC;
+ demodd = 0x9CAC;
+ break;
+
+ case VFE_YUV_YCrYCb:
+ demperiod = 3;
+ demeven = 0xAC9C;
+ demodd = 0xAC9C;
+ break;
+
+ case VFE_YUV_CbYCrY:
+ demperiod = 3;
+ demeven = 0xC9CA;
+ demodd = 0xC9CA;
+ break;
+
+ case VFE_YUV_CrYCbY:
+ demperiod = 3;
+ demeven = 0xCAC9;
+ demodd = 0xCAC9;
+ break;
+
+ default:
+ return;
+ }
+
+ vfe_config_demux(demperiod, demeven, demodd);
+
+ vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+ /* save variables to local. */
+ ctrl->vfeOperationMode = in->operationMode;
+ if (ctrl->vfeOperationMode ==
+ VFE_START_OPERATION_MODE_SNAPSHOT) {
+ /* in snapshot mode, initialize snapshot count*/
+ ctrl->vfeSnapShotCount = in->snapshotCount;
+
+ /* save the requested count, this is temporarily done, to
+ help with HJR / multishot. */
+ ctrl->vfeRequestedSnapShotCount = ctrl->vfeSnapShotCount;
+
+ CDBG("requested snapshot count = %d\n", ctrl->vfeSnapShotCount);
+
+ /* Assumption is to have the same pattern and period for both
+ paths, if both paths are used. */
+ if (ctrl->viewPath.pathEnabled) {
+ ctrl->viewPath.snapshotPendingCount =
+ in->snapshotCount;
+
+ ctrl->vfeFrameSkipPattern =
+ ctrl->vfeFrameSkip.output1Pattern;
+ ctrl->vfeFrameSkipPeriod =
+ ctrl->vfeFrameSkip.output1Period;
+ }
+
+ if (ctrl->encPath.pathEnabled) {
+ ctrl->encPath.snapshotPendingCount =
+ in->snapshotCount;
+
+ ctrl->vfeFrameSkipPattern =
+ ctrl->vfeFrameSkip.output2Pattern;
+ ctrl->vfeFrameSkipPeriod =
+ ctrl->vfeFrameSkip.output2Period;
+ }
+ }
+
+ /* enable color conversion for bayer sensor
+ if stats enabled, need to do color conversion. */
+ if (in->pixel <= VFE_BAYER_GBGBGB)
+ ctrl->vfeStatsCmdLocal.colorConversionEnable = TRUE;
+
+ vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+ if (in->pixel >= VFE_YUV_YCbYCr)
+ ctrl->vfeModuleEnableLocal.chromaUpsampleEnable = TRUE;
+
+ ctrl->vfeModuleEnableLocal.demuxEnable = TRUE;
+
+ /* if any stats module is enabled, the main bit is enabled. */
+ ctrl->vfeModuleEnableLocal.statsEnable =
+ ctrl->vfeStatsCmdLocal.autoFocusEnable |
+ ctrl->vfeStatsCmdLocal.axwEnable;
+
+ vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+ /* in case of offline processing, do not need to config camif. Having
+ * bus output enabled in camif_config register might confuse the
+ * hardware?
+ */
+ if (in->inputSource != VFE_START_INPUT_SOURCE_AXI) {
+ vfe_reg_camif_config(&ctrl->vfeCamifConfigLocal);
+ } else {
+ /* offline processing, enable axi read */
+ ctrl->vfeBusConfigLocal.stripeRdPathEn = TRUE;
+ ctrl->vfeBusCmdLocal.stripeReload = TRUE;
+ ctrl->vfeBusConfigLocal.rawPixelDataSize =
+ ctrl->axiInputDataSize;
+ }
+
+ vfe_reg_bus_cfg(&ctrl->vfeBusConfigLocal);
+
+ /* directly from start command */
+ hwcfg.pixelPattern = in->pixel;
+ hwcfg.inputSource = in->inputSource;
+ writel(*(uint32_t *)&hwcfg, ctrl->vfebase + VFE_CFG);
+
+ /* regardless module enabled or not, it does not hurt
+ * to program the cositing mode. */
+ chromupcfg.chromaCositingForYCbCrInputs =
+ in->yuvInputCositingMode;
+
+ writel(*(uint32_t *)&(chromupcfg),
+ ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG);
+
+ /* MISR to monitor the axi read. */
+ writel(0xd8, ctrl->vfebase + VFE_BUS_MISR_MAST_CFG_0);
+
+ /* clear all pending interrupts. */
+ writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+ /* define how composite interrupt work. */
+ ctrl->vfeImaskCompositePacked =
+ vfe_irq_composite_pack(ctrl->vfeIrqCompositeMaskLocal);
+
+ vfe_program_irq_composite_mask(ctrl->vfeImaskCompositePacked);
+
+ /* enable all necessary interrupts. */
+ ctrl->vfeImaskLocal.camifSofIrq = TRUE;
+ ctrl->vfeImaskLocal.regUpdateIrq = TRUE;
+ ctrl->vfeImaskLocal.resetAckIrq = TRUE;
+
+ ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+ vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+ /* enable bus performance monitor */
+ vfe_8k_pm_start(&ctrl->vfeBusPmConfigLocal);
+
+ /* trigger vfe reg update */
+ ctrl->vfeStartAckPendingFlag = TRUE;
+
+ /* write bus command to trigger reload of ping pong buffer. */
+ ctrl->vfeBusCmdLocal.busPingpongReload = TRUE;
+
+ if (ctrl->vfeModuleEnableLocal.statsEnable == TRUE) {
+ ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+ ctrl->vfeStatsPingPongReloadFlag = TRUE;
+ }
+
+ writel(VFE_REG_UPDATE_TRIGGER,
+ ctrl->vfebase + VFE_REG_UPDATE_CMD);
+
+ /* program later than the reg update. */
+ vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+
+ if ((in->inputSource ==
+ VFE_START_INPUT_SOURCE_CAMIF) ||
+ (in->inputSource ==
+ VFE_START_INPUT_SOURCE_TESTGEN))
+ writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND);
+
+ /* start test gen if it is enabled */
+ if (ctrl->vfeTestGenStartFlag == TRUE) {
+ ctrl->vfeTestGenStartFlag = FALSE;
+ vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_GO);
+ }
+
+ CDBG("ctrl->axiOutputMode = %d\n", ctrl->axiOutputMode);
+ if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2) {
+ /* raw dump mode */
+ rawmode = TRUE;
+
+ while (rawmode) {
+ pmstatus =
+ readl(ctrl->vfebase +
+ VFE_BUS_ENC_CBCR_WR_PM_STATS_1);
+
+ if ((pmstatus & VFE_PM_BUF_MAX_CNT_MASK) != 0)
+ rawmode = FALSE;
+ }
+
+ vfe_send_msg_no_payload(VFE_MSG_ID_START_ACK);
+ ctrl->vfeStartAckPendingFlag = FALSE;
+ }
+
+ spin_lock_irqsave(&ctrl->state_lock, flags);
+ ctrl->vstate = VFE_STATE_ACTIVE;
+ spin_unlock_irqrestore(&ctrl->state_lock, flags);
+}
+
+void vfe_la_update(struct vfe_cmd_la_config *in)
+{
+ int16_t *pTable;
+ enum VFE_DMI_RAM_SEL dmiRamSel;
+ int i;
+
+ pTable = in->table;
+ ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+ /* toggle the bank to be used. */
+ ctrl->vfeLaBankSel ^= 1;
+
+ if (ctrl->vfeLaBankSel == 0)
+ dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+ else
+ dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+ /* configure the DMI_CFG to select right sram */
+ vfe_program_dmi_cfg(dmiRamSel);
+
+ for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+ writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+ pTable++;
+ }
+
+ /* After DMI transfer, to make it safe, need to set
+ * the DMI_CFG to unselect any SRAM */
+ writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+ writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+}
+
+void vfe_la_config(struct vfe_cmd_la_config *in)
+{
+ uint16_t i;
+ int16_t *pTable;
+ enum VFE_DMI_RAM_SEL dmiRamSel;
+
+ pTable = in->table;
+ ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+ if (ctrl->vfeLaBankSel == 0)
+ dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+ else
+ dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+ /* configure the DMI_CFG to select right sram */
+ vfe_program_dmi_cfg(dmiRamSel);
+
+ for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+ writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+ pTable++;
+ }
+
+ /* After DMI transfer, to make it safe, need to set the
+ * DMI_CFG to unselect any SRAM */
+ writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+
+ /* can only be bank 0 or bank 1 for now. */
+ writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+ CDBG("VFE Luma adaptation bank selection is 0x%x\n",
+ *(uint32_t *)&ctrl->vfeLaBankSel);
+}
+
+void vfe_test_gen_start(struct vfe_cmd_test_gen_start *in)
+{
+ struct VFE_TestGen_ConfigCmdType cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.numFrame = in->numFrame;
+ cmd.pixelDataSelect = in->pixelDataSelect;
+ cmd.systematicDataSelect = in->systematicDataSelect;
+ cmd.pixelDataSize = (uint32_t)in->pixelDataSize;
+ cmd.hsyncEdge = (uint32_t)in->hsyncEdge;
+ cmd.vsyncEdge = (uint32_t)in->vsyncEdge;
+ cmd.imageWidth = in->imageWidth;
+ cmd.imageHeight = in->imageHeight;
+ cmd.sofOffset = in->startOfFrameOffset;
+ cmd.eofNOffset = in->endOfFrameNOffset;
+ cmd.solOffset = in->startOfLineOffset;
+ cmd.eolNOffset = in->endOfLineNOffset;
+ cmd.hBlankInterval = in->hbi;
+ cmd.vBlankInterval = in->vbl;
+ cmd.vBlankIntervalEnable = in->vblEnable;
+ cmd.sofDummy = in->startOfFrameDummyLine;
+ cmd.eofDummy = in->endOfFrameDummyLine;
+ cmd.unicolorBarSelect = in->unicolorBarSelect;
+ cmd.unicolorBarEnable = in->unicolorBarEnable;
+ cmd.splitEnable = in->colorBarsSplitEnable;
+ cmd.pixelPattern = (uint32_t)in->colorBarsPixelPattern;
+ cmd.rotatePeriod = in->colorBarsRotatePeriod;
+ cmd.randomSeed = in->testGenRandomSeed;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_HW_TESTGEN_CFG,
+ (uint32_t *) &cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *in)
+{
+ struct VFE_FRAME_SKIP_UpdateCmdType cmd;
+
+ cmd.yPattern = in->output1Pattern;
+ cmd.cbcrPattern = in->output1Pattern;
+ vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmd.yPattern = in->output2Pattern;
+ cmd.cbcrPattern = in->output2Pattern;
+ vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *in)
+{
+ struct vfe_frame_skip_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeFrameSkip = *in;
+
+ cmd.output2YPeriod = in->output2Period;
+ cmd.output2CbCrPeriod = in->output2Period;
+ cmd.output2YPattern = in->output2Pattern;
+ cmd.output2CbCrPattern = in->output2Pattern;
+ cmd.output1YPeriod = in->output1Period;
+ cmd.output1CbCrPeriod = in->output1Period;
+ cmd.output1YPattern = in->output1Pattern;
+ cmd.output1CbCrPattern = in->output1Pattern;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *in)
+{
+ struct vfe_output_clamp_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.yChanMax = in->maxCh0;
+ cmd.cbChanMax = in->maxCh1;
+ cmd.crChanMax = in->maxCh2;
+
+ cmd.yChanMin = in->minCh0;
+ cmd.cbChanMin = in->minCh1;
+ cmd.crChanMin = in->minCh2;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_CLAMP_MAX_CFG, (uint32_t *)&cmd,
+ sizeof(cmd));
+}
+
+void vfe_camif_frame_update(struct vfe_cmds_camif_frame *in)
+{
+ struct vfe_camifframe_update cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.pixelsPerLine = in->pixelsPerLine;
+ cmd.linesPerFrame = in->linesPerFrame;
+
+ vfe_prog_hw(ctrl->vfebase + CAMIF_FRAME_CONFIG, (uint32_t *)&cmd,
+ sizeof(cmd));
+}
+
+void vfe_color_correction_config(
+ struct vfe_cmd_color_correction_config *in)
+{
+ struct vfe_color_correction_cfg cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ctrl->vfeModuleEnableLocal.colorCorrectionEnable = in->enable;
+
+ cmd.c0 = in->C0;
+ cmd.c1 = in->C1;
+ cmd.c2 = in->C2;
+ cmd.c3 = in->C3;
+ cmd.c4 = in->C4;
+ cmd.c5 = in->C5;
+ cmd.c6 = in->C6;
+ cmd.c7 = in->C7;
+ cmd.c8 = in->C8;
+
+ cmd.k0 = in->K0;
+ cmd.k1 = in->K1;
+ cmd.k2 = in->K2;
+
+ cmd.coefQFactor = in->coefQFactor;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CORRECT_COEFF_0,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *in)
+{
+struct vfe_demosaic_cfg cmd;
+ struct vfe_demosaic_abf_cfg cmdabf;
+ uint32_t temp;
+
+ memset(&cmd, 0, sizeof(cmd));
+ temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+ cmd = *((struct vfe_demosaic_cfg *)(&temp));
+ cmd.abfEnable = in->abfUpdate.enable;
+ cmd.forceAbfOn = in->abfUpdate.forceOn;
+ cmd.abfShift = in->abfUpdate.shift;
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmdabf.lpThreshold = in->abfUpdate.lpThreshold;
+ cmdabf.ratio = in->abfUpdate.ratio;
+ cmdabf.minValue = in->abfUpdate.min;
+ cmdabf.maxValue = in->abfUpdate.max;
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+ (uint32_t *)&cmdabf, sizeof(cmdabf));
+}
+
+void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *in)
+{
+ struct vfe_demosaic_cfg cmd;
+ struct vfe_demosaic_bpc_cfg cmdbpc;
+ uint32_t temp;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+ cmd = *((struct vfe_demosaic_cfg *)(&temp));
+ cmd.badPixelCorrEnable = in->bpcUpdate.enable;
+ cmd.fminThreshold = in->bpcUpdate.fminThreshold;
+ cmd.fmaxThreshold = in->bpcUpdate.fmaxThreshold;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmdbpc.blueDiffThreshold = in->bpcUpdate.blueDiffThreshold;
+ cmdbpc.redDiffThreshold = in->bpcUpdate.redDiffThreshold;
+ cmdbpc.greenDiffThreshold = in->bpcUpdate.greenDiffThreshold;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+ (uint32_t *)&cmdbpc, sizeof(cmdbpc));
+}
+
+void vfe_demosaic_config(struct vfe_cmd_demosaic_config *in)
+{
+ struct vfe_demosaic_cfg cmd;
+ struct vfe_demosaic_bpc_cfg cmd_bpc;
+ struct vfe_demosaic_abf_cfg cmd_abf;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&cmd_bpc, 0, sizeof(cmd_bpc));
+ memset(&cmd_abf, 0, sizeof(cmd_abf));
+
+ ctrl->vfeModuleEnableLocal.demosaicEnable = in->enable;
+
+ cmd.abfEnable = in->abfConfig.enable;
+ cmd.badPixelCorrEnable = in->bpcConfig.enable;
+ cmd.forceAbfOn = in->abfConfig.forceOn;
+ cmd.abfShift = in->abfConfig.shift;
+ cmd.fminThreshold = in->bpcConfig.fminThreshold;
+ cmd.fmaxThreshold = in->bpcConfig.fmaxThreshold;
+ cmd.slopeShift = in->slopeShift;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmd_abf.lpThreshold = in->abfConfig.lpThreshold;
+ cmd_abf.ratio = in->abfConfig.ratio;
+ cmd_abf.minValue = in->abfConfig.min;
+ cmd_abf.maxValue = in->abfConfig.max;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+ (uint32_t *)&cmd_abf, sizeof(cmd_abf));
+
+ cmd_bpc.blueDiffThreshold = in->bpcConfig.blueDiffThreshold;
+ cmd_bpc.redDiffThreshold = in->bpcConfig.redDiffThreshold;
+ cmd_bpc.greenDiffThreshold = in->bpcConfig.greenDiffThreshold;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+ (uint32_t *)&cmd_bpc, sizeof(cmd_bpc));
+}
+
+void vfe_demux_channel_gain_update(
+ struct vfe_cmd_demux_channel_gain_config *in)
+{
+ struct vfe_demux_cfg cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.ch0EvenGain = in->ch0EvenGain;
+ cmd.ch0OddGain = in->ch0OddGain;
+ cmd.ch1Gain = in->ch1Gain;
+ cmd.ch2Gain = in->ch2Gain;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demux_channel_gain_config(
+ struct vfe_cmd_demux_channel_gain_config *in)
+{
+ struct vfe_demux_cfg cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.ch0EvenGain = in->ch0EvenGain;
+ cmd.ch0OddGain = in->ch0OddGain;
+ cmd.ch1Gain = in->ch1Gain;
+ cmd.ch2Gain = in->ch2Gain;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_update(struct vfe_cmd_black_level_config *in)
+{
+ struct vfe_blacklevel_cfg cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+ cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+ cmd.evenOddAdjustment = in->evenOddAdjustment;
+ cmd.oddEvenAdjustment = in->oddEvenAdjustment;
+ cmd.oddOddAdjustment = in->oddOddAdjustment;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_config(struct vfe_cmd_black_level_config *in)
+{
+ struct vfe_blacklevel_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+ cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+ cmd.evenOddAdjustment = in->evenOddAdjustment;
+ cmd.oddEvenAdjustment = in->oddEvenAdjustment;
+ cmd.oddOddAdjustment = in->oddOddAdjustment;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_update(struct vfe_cmd_asf_update *in)
+{
+ struct vfe_asf_update cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+ cmd.smoothEnable = in->smoothFilterEnabled;
+ cmd.sharpMode = in->sharpMode;
+ cmd.smoothCoeff1 = in->smoothCoefCenter;
+ cmd.smoothCoeff0 = in->smoothCoefSurr;
+ cmd.cropEnable = in->cropEnable;
+ cmd.sharpThresholdE1 = in->sharpThreshE1;
+ cmd.sharpDegreeK1 = in->sharpK1;
+ cmd.sharpDegreeK2 = in->sharpK2;
+ cmd.normalizeFactor = in->normalizeFactor;
+ cmd.sharpThresholdE2 = in->sharpThreshE2;
+ cmd.sharpThresholdE3 = in->sharpThreshE3;
+ cmd.sharpThresholdE4 = in->sharpThreshE4;
+ cmd.sharpThresholdE5 = in->sharpThreshE5;
+ cmd.F1Coeff0 = in->filter1Coefficients[0];
+ cmd.F1Coeff1 = in->filter1Coefficients[1];
+ cmd.F1Coeff2 = in->filter1Coefficients[2];
+ cmd.F1Coeff3 = in->filter1Coefficients[3];
+ cmd.F1Coeff4 = in->filter1Coefficients[4];
+ cmd.F1Coeff5 = in->filter1Coefficients[5];
+ cmd.F1Coeff6 = in->filter1Coefficients[6];
+ cmd.F1Coeff7 = in->filter1Coefficients[7];
+ cmd.F1Coeff8 = in->filter1Coefficients[8];
+ cmd.F2Coeff0 = in->filter2Coefficients[0];
+ cmd.F2Coeff1 = in->filter2Coefficients[1];
+ cmd.F2Coeff2 = in->filter2Coefficients[2];
+ cmd.F2Coeff3 = in->filter2Coefficients[3];
+ cmd.F2Coeff4 = in->filter2Coefficients[4];
+ cmd.F2Coeff5 = in->filter2Coefficients[5];
+ cmd.F2Coeff6 = in->filter2Coefficients[6];
+ cmd.F2Coeff7 = in->filter2Coefficients[7];
+ cmd.F2Coeff8 = in->filter2Coefficients[8];
+
+ vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_config(struct vfe_cmd_asf_config *in)
+{
+ struct vfe_asf_update cmd;
+ struct vfe_asfcrop_cfg cmd2;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&cmd2, 0, sizeof(cmd2));
+
+ ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+ cmd.smoothEnable = in->smoothFilterEnabled;
+ cmd.sharpMode = in->sharpMode;
+ cmd.smoothCoeff0 = in->smoothCoefCenter;
+ cmd.smoothCoeff1 = in->smoothCoefSurr;
+ cmd.cropEnable = in->cropEnable;
+ cmd.sharpThresholdE1 = in->sharpThreshE1;
+ cmd.sharpDegreeK1 = in->sharpK1;
+ cmd.sharpDegreeK2 = in->sharpK2;
+ cmd.normalizeFactor = in->normalizeFactor;
+ cmd.sharpThresholdE2 = in->sharpThreshE2;
+ cmd.sharpThresholdE3 = in->sharpThreshE3;
+ cmd.sharpThresholdE4 = in->sharpThreshE4;
+ cmd.sharpThresholdE5 = in->sharpThreshE5;
+ cmd.F1Coeff0 = in->filter1Coefficients[0];
+ cmd.F1Coeff1 = in->filter1Coefficients[1];
+ cmd.F1Coeff2 = in->filter1Coefficients[2];
+ cmd.F1Coeff3 = in->filter1Coefficients[3];
+ cmd.F1Coeff4 = in->filter1Coefficients[4];
+ cmd.F1Coeff5 = in->filter1Coefficients[5];
+ cmd.F1Coeff6 = in->filter1Coefficients[6];
+ cmd.F1Coeff7 = in->filter1Coefficients[7];
+ cmd.F1Coeff8 = in->filter1Coefficients[8];
+ cmd.F2Coeff0 = in->filter2Coefficients[0];
+ cmd.F2Coeff1 = in->filter2Coefficients[1];
+ cmd.F2Coeff2 = in->filter2Coefficients[2];
+ cmd.F2Coeff3 = in->filter2Coefficients[3];
+ cmd.F2Coeff4 = in->filter2Coefficients[4];
+ cmd.F2Coeff5 = in->filter2Coefficients[5];
+ cmd.F2Coeff6 = in->filter2Coefficients[6];
+ cmd.F2Coeff7 = in->filter2Coefficients[7];
+ cmd.F2Coeff8 = in->filter2Coefficients[8];
+
+ vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmd2.firstLine = in->cropFirstLine;
+ cmd2.lastLine = in->cropLastLine;
+ cmd2.firstPixel = in->cropFirstPixel;
+ cmd2.lastPixel = in->cropLastPixel;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_ASF_CROP_WIDTH_CFG,
+ (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_white_balance_config(struct vfe_cmd_white_balance_config *in)
+{
+ struct vfe_wb_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.whiteBalanceEnable =
+ in->enable;
+
+ cmd.ch0Gain = in->ch0Gain;
+ cmd.ch1Gain = in->ch1Gain;
+ cmd.ch2Gain = in->ch2Gain;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_WB_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *in)
+{
+ struct vfe_chroma_suppress_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.chromaSuppressionEnable = in->enable;
+
+ cmd.m1 = in->m1;
+ cmd.m3 = in->m3;
+ cmd.n1 = in->n1;
+ cmd.n3 = in->n3;
+ cmd.mm1 = in->mm1;
+ cmd.nn1 = in->nn1;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUPPRESS_CFG_0,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_roll_off_config(struct vfe_cmd_roll_off_config *in)
+{
+ struct vfe_rolloff_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.lensRollOffEnable = in->enable;
+
+ cmd.gridWidth = in->gridWidth;
+ cmd.gridHeight = in->gridHeight;
+ cmd.yDelta = in->yDelta;
+ cmd.gridX = in->gridXIndex;
+ cmd.gridY = in->gridYIndex;
+ cmd.pixelX = in->gridPixelXIndex;
+ cmd.pixelY = in->gridPixelYIndex;
+ cmd.yDeltaAccum = in->yDeltaAccum;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_ROLLOFF_CFG_0,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ vfe_write_lens_roll_off_table(in);
+}
+
+void vfe_chroma_subsample_config(
+ struct vfe_cmd_chroma_subsample_config *in)
+{
+ struct vfe_chromasubsample_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.chromaSubsampleEnable = in->enable;
+
+ cmd.hCositedPhase = in->hCositedPhase;
+ cmd.vCositedPhase = in->vCositedPhase;
+ cmd.hCosited = in->hCosited;
+ cmd.vCosited = in->vCosited;
+ cmd.hsubSampleEnable = in->hsubSampleEnable;
+ cmd.vsubSampleEnable = in->vsubSampleEnable;
+ cmd.cropEnable = in->cropEnable;
+ cmd.cropWidthLastPixel = in->cropWidthLastPixel;
+ cmd.cropWidthFirstPixel = in->cropWidthFirstPixel;
+ cmd.cropHeightLastLine = in->cropHeightLastLine;
+ cmd.cropHeightFirstLine = in->cropHeightFirstLine;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUBSAMPLE_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *in)
+{
+ struct vfe_chroma_enhance_cfg cmd;
+ struct vfe_color_convert_cfg cmd2;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&cmd2, 0, sizeof(cmd2));
+
+ ctrl->vfeModuleEnableLocal.chromaEnhanEnable = in->enable;
+
+ cmd.ap = in->ap;
+ cmd.am = in->am;
+ cmd.bp = in->bp;
+ cmd.bm = in->bm;
+ cmd.cp = in->cp;
+ cmd.cm = in->cm;
+ cmd.dp = in->dp;
+ cmd.dm = in->dm;
+ cmd.kcb = in->kcb;
+ cmd.kcr = in->kcr;
+
+ cmd2.v0 = in->RGBtoYConversionV0;
+ cmd2.v1 = in->RGBtoYConversionV1;
+ cmd2.v2 = in->RGBtoYConversionV2;
+ cmd2.ConvertOffset = in->RGBtoYConversionOffset;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_ENHAN_A,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CONVERT_COEFF_0,
+ (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *in)
+{
+ struct vfe_scaler2_cfg cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.scaler2CbcrEnable = in->enable;
+
+ cmd.hEnable = in->hconfig.enable;
+ cmd.vEnable = in->vconfig.enable;
+ cmd.inWidth = in->hconfig.inputSize;
+ cmd.outWidth = in->hconfig.outputSize;
+ cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor;
+ cmd.horizInterResolution = in->hconfig.interpolationResolution;
+ cmd.inHeight = in->vconfig.inputSize;
+ cmd.outHeight = in->vconfig.outputSize;
+ cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor;
+ cmd.vertInterResolution = in->vconfig.interpolationResolution;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CBCR_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *in)
+{
+ struct vfe_scaler2_cfg cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.scaler2YEnable = in->enable;
+
+ cmd.hEnable = in->hconfig.enable;
+ cmd.vEnable = in->vconfig.enable;
+ cmd.inWidth = in->hconfig.inputSize;
+ cmd.outWidth = in->hconfig.outputSize;
+ cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor;
+ cmd.horizInterResolution = in->hconfig.interpolationResolution;
+ cmd.inHeight = in->vconfig.inputSize;
+ cmd.outHeight = in->vconfig.outputSize;
+ cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor;
+ cmd.vertInterResolution = in->vconfig.interpolationResolution;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_SCALE_Y_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *in)
+{
+ struct vfe_main_scaler_cfg cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.mainScalerEnable = in->enable;
+
+ cmd.hEnable = in->hconfig.enable;
+ cmd.vEnable = in->vconfig.enable;
+ cmd.inWidth = in->hconfig.inputSize;
+ cmd.outWidth = in->hconfig.outputSize;
+ cmd.horizPhaseMult = in->hconfig.phaseMultiplicationFactor;
+ cmd.horizInterResolution = in->hconfig.interpolationResolution;
+ cmd.horizMNInit = in->MNInitH.MNCounterInit;
+ cmd.horizPhaseInit = in->MNInitH.phaseInit;
+ cmd.inHeight = in->vconfig.inputSize;
+ cmd.outHeight = in->vconfig.outputSize;
+ cmd.vertPhaseMult = in->vconfig.phaseMultiplicationFactor;
+ cmd.vertInterResolution = in->vconfig.interpolationResolution;
+ cmd.vertMNInit = in->MNInitV.MNCounterInit;
+ cmd.vertPhaseInit = in->MNInitV.phaseInit;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_wb_exp_stop(void)
+{
+ ctrl->vfeStatsCmdLocal.axwEnable = FALSE;
+ ctrl->vfeImaskLocal.awbPingpongIrq = FALSE;
+}
+
+void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *in)
+{
+ struct vfe_statsawb_update cmd;
+ struct vfe_statsawbae_update cmd2;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&cmd2, 0, sizeof(cmd2));
+
+ cmd.m1 = in->awbMCFG[0];
+ cmd.m2 = in->awbMCFG[1];
+ cmd.m3 = in->awbMCFG[2];
+ cmd.m4 = in->awbMCFG[3];
+ cmd.c1 = in->awbCCFG[0];
+ cmd.c2 = in->awbCCFG[1];
+ cmd.c3 = in->awbCCFG[2];
+ cmd.c4 = in->awbCCFG[3];
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmd2.aeRegionCfg = in->wbExpRegions;
+ cmd2.aeSubregionCfg = in->wbExpSubRegion;
+ cmd2.awbYMin = in->awbYMin;
+ cmd2.awbYMax = in->awbYMax;
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+ (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_update_af(struct vfe_cmd_stats_af_update *in)
+{
+ struct vfe_statsaf_update cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.windowVOffset = in->windowVOffset;
+ cmd.windowHOffset = in->windowHOffset;
+ cmd.windowMode = in->windowMode;
+ cmd.windowHeight = in->windowHeight;
+ cmd.windowWidth = in->windowWidth;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *in)
+{
+ struct vfe_statsawb_update cmd;
+ struct vfe_statsawbae_update cmd2;
+ struct vfe_statsaxw_hdr_cfg cmd3;
+
+ ctrl->vfeStatsCmdLocal.axwEnable = in->enable;
+ ctrl->vfeImaskLocal.awbPingpongIrq = TRUE;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&cmd2, 0, sizeof(cmd2));
+ memset(&cmd3, 0, sizeof(cmd3));
+
+ cmd.m1 = in->awbMCFG[0];
+ cmd.m2 = in->awbMCFG[1];
+ cmd.m3 = in->awbMCFG[2];
+ cmd.m4 = in->awbMCFG[3];
+ cmd.c1 = in->awbCCFG[0];
+ cmd.c2 = in->awbCCFG[1];
+ cmd.c3 = in->awbCCFG[2];
+ cmd.c4 = in->awbCCFG[3];
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmd2.aeRegionCfg = in->wbExpRegions;
+ cmd2.aeSubregionCfg = in->wbExpSubRegion;
+ cmd2.awbYMin = in->awbYMin;
+ cmd2.awbYMax = in->awbYMax;
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+ (uint32_t *)&cmd2, sizeof(cmd2));
+
+ cmd3.axwHeader = in->axwHeader;
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AXW_HEADER,
+ (uint32_t *)&cmd3, sizeof(cmd3));
+}
+
+void vfe_stats_start_af(struct vfe_cmd_stats_af_start *in)
+{
+ struct vfe_statsaf_update cmd;
+ struct vfe_statsaf_cfg cmd2;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&cmd2, 0, sizeof(cmd2));
+
+ctrl->vfeStatsCmdLocal.autoFocusEnable = in->enable;
+ctrl->vfeImaskLocal.afPingpongIrq = TRUE;
+
+ cmd.windowVOffset = in->windowVOffset;
+ cmd.windowHOffset = in->windowHOffset;
+ cmd.windowMode = in->windowMode;
+ cmd.windowHeight = in->windowHeight;
+ cmd.windowWidth = in->windowWidth;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ cmd2.a00 = in->highPassCoef[0];
+ cmd2.a04 = in->highPassCoef[1];
+ cmd2.a20 = in->highPassCoef[2];
+ cmd2.a21 = in->highPassCoef[3];
+ cmd2.a22 = in->highPassCoef[4];
+ cmd2.a23 = in->highPassCoef[5];
+ cmd2.a24 = in->highPassCoef[6];
+ cmd2.fvMax = in->metricMax;
+ cmd2.fvMetric = in->metricSelection;
+ cmd2.afHeader = in->bufferHeader;
+ cmd2.entry00 = in->gridForMultiWindows[0];
+ cmd2.entry01 = in->gridForMultiWindows[1];
+ cmd2.entry02 = in->gridForMultiWindows[2];
+ cmd2.entry03 = in->gridForMultiWindows[3];
+ cmd2.entry10 = in->gridForMultiWindows[4];
+ cmd2.entry11 = in->gridForMultiWindows[5];
+ cmd2.entry12 = in->gridForMultiWindows[6];
+ cmd2.entry13 = in->gridForMultiWindows[7];
+ cmd2.entry20 = in->gridForMultiWindows[8];
+ cmd2.entry21 = in->gridForMultiWindows[9];
+ cmd2.entry22 = in->gridForMultiWindows[10];
+ cmd2.entry23 = in->gridForMultiWindows[11];
+ cmd2.entry30 = in->gridForMultiWindows[12];
+ cmd2.entry31 = in->gridForMultiWindows[13];
+ cmd2.entry32 = in->gridForMultiWindows[14];
+ cmd2.entry33 = in->gridForMultiWindows[15];
+
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_GRID_0,
+ (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_setting(struct vfe_cmd_stats_setting *in)
+{
+ struct vfe_statsframe cmd1;
+ struct vfe_busstats_wrprio cmd2;
+
+ memset(&cmd1, 0, sizeof(cmd1));
+ memset(&cmd2, 0, sizeof(cmd2));
+
+ ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0];
+ ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1];
+ ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2];
+
+ ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0];
+ ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1];
+ ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2];
+
+ cmd1.lastPixel = in->frameHDimension;
+ cmd1.lastLine = in->frameVDimension;
+ vfe_prog_hw(ctrl->vfebase + VFE_STATS_FRAME_SIZE,
+ (uint32_t *)&cmd1, sizeof(cmd1));
+
+ cmd2.afBusPriority = in->afBusPriority;
+ cmd2.awbBusPriority = in->awbBusPriority;
+ cmd2.histBusPriority = in->histBusPriority;
+ cmd2.afBusPriorityEn = in->afBusPrioritySelection;
+ cmd2.awbBusPriorityEn = in->awbBusPrioritySelection;
+ cmd2.histBusPriorityEn = in->histBusPrioritySelection;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_BUS_STATS_WR_PRIORITY,
+ (uint32_t *)&cmd2, sizeof(cmd2));
+
+ /* Program the bus ping pong address for statistics modules. */
+ writel(in->afBuffer[0], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ writel(in->afBuffer[1], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+ writel(in->awbBuffer[0],
+ ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ writel(in->awbBuffer[1],
+ ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+ writel(in->histBuffer[0],
+ ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+ writel(in->histBuffer[1],
+ ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+}
+
+void vfe_axi_input_config(struct vfe_cmd_axi_input_config *in)
+{
+ struct VFE_AxiInputCmdType cmd;
+ uint32_t xSizeWord, axiRdUnpackPattern;
+ uint8_t axiInputPpw;
+ uint32_t busPingpongRdIrqEnable;
+
+ ctrl->vfeImaskLocal.rdPingpongIrq = TRUE;
+
+ switch (in->pixelSize) {
+ case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+ ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_10BIT;
+ break;
+
+ case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+ ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_12BIT;
+ break;
+
+ case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+ default:
+ ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_8BIT;
+ break;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ switch (in->pixelSize) {
+ case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+ axiInputPpw = 6;
+ axiRdUnpackPattern = 0xD43210;
+ break;
+
+ case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+ axiInputPpw = 5;
+ axiRdUnpackPattern = 0xC3210;
+ break;
+
+ case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+ default:
+ axiInputPpw = 8;
+ axiRdUnpackPattern = 0xF6543210;
+ break;
+ }
+
+ xSizeWord =
+ ((((in->xOffset % axiInputPpw) + in->xSize) +
+ (axiInputPpw-1)) / axiInputPpw) - 1;
+
+ cmd.stripeStartAddr0 = in->fragAddr[0];
+ cmd.stripeStartAddr1 = in->fragAddr[1];
+ cmd.stripeStartAddr2 = in->fragAddr[2];
+ cmd.stripeStartAddr3 = in->fragAddr[3];
+ cmd.ySize = in->ySize;
+ cmd.yOffsetDelta = 0;
+ cmd.xSizeWord = xSizeWord;
+ cmd.burstLength = 1;
+ cmd.NumOfRows = in->numOfRows;
+ cmd.RowIncrement =
+ (in->rowIncrement + (axiInputPpw-1))/axiInputPpw;
+ cmd.mainUnpackHeight = in->ySize;
+ cmd.mainUnpackWidth = in->xSize - 1;
+ cmd.mainUnpackHbiSel = (uint32_t)in->unpackHbi;
+ cmd.mainUnpackPhase = in->unpackPhase;
+ cmd.unpackPattern = axiRdUnpackPattern;
+ cmd.padLeft = in->padRepeatCountLeft;
+ cmd.padRight = in->padRepeatCountRight;
+ cmd.padTop = in->padRepeatCountTop;
+ cmd.padBottom = in->padRepeatCountBottom;
+ cmd.leftUnpackPattern0 = in->padLeftComponentSelectCycle0;
+ cmd.leftUnpackPattern1 = in->padLeftComponentSelectCycle1;
+ cmd.leftUnpackPattern2 = in->padLeftComponentSelectCycle2;
+ cmd.leftUnpackPattern3 = in->padLeftComponentSelectCycle3;
+ cmd.leftUnpackStop0 = in->padLeftStopCycle0;
+ cmd.leftUnpackStop1 = in->padLeftStopCycle1;
+ cmd.leftUnpackStop2 = in->padLeftStopCycle2;
+ cmd.leftUnpackStop3 = in->padLeftStopCycle3;
+ cmd.rightUnpackPattern0 = in->padRightComponentSelectCycle0;
+ cmd.rightUnpackPattern1 = in->padRightComponentSelectCycle1;
+ cmd.rightUnpackPattern2 = in->padRightComponentSelectCycle2;
+ cmd.rightUnpackPattern3 = in->padRightComponentSelectCycle3;
+ cmd.rightUnpackStop0 = in->padRightStopCycle0;
+ cmd.rightUnpackStop1 = in->padRightStopCycle1;
+ cmd.rightUnpackStop2 = in->padRightStopCycle2;
+ cmd.rightUnpackStop3 = in->padRightStopCycle3;
+ cmd.topUnapckPattern = in->padTopLineCount;
+ cmd.bottomUnapckPattern = in->padBottomLineCount;
+
+ /* program vfe_bus_cfg */
+ vfe_prog_hw(ctrl->vfebase + VFE_BUS_STRIPE_RD_ADDR_0,
+ (uint32_t *)&cmd, sizeof(cmd));
+
+ /* hacking code, put it to default value */
+ busPingpongRdIrqEnable = 0xf;
+
+ writel(busPingpongRdIrqEnable,
+ ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN);
+}
+
+void vfe_stats_config(struct vfe_cmd_stats_setting *in)
+{
+ ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0];
+ ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1];
+ ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2];
+
+ ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0];
+ ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1];
+ ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2];
+
+ vfe_stats_setting(in);
+}
+
+void vfe_axi_output_config(
+ struct vfe_cmd_axi_output_config *in)
+{
+ /* local variable */
+ uint32_t *pcircle;
+ uint32_t *pdest;
+ uint32_t *psrc;
+ uint8_t i;
+ uint8_t fcnt;
+ uint16_t axioutpw = 8;
+
+ /* parameters check, condition and usage mode check */
+ ctrl->encPath.fragCount = in->output2.fragmentCount;
+ if (ctrl->encPath.fragCount > 1)
+ ctrl->encPath.multiFrag = TRUE;
+
+ ctrl->viewPath.fragCount = in->output1.fragmentCount;
+ if (ctrl->viewPath.fragCount > 1)
+ ctrl->viewPath.multiFrag = TRUE;
+
+ /* VFE_BUS_CFG. raw data size */
+ ctrl->vfeBusConfigLocal.rawPixelDataSize = in->outputDataSize;
+
+ switch (in->outputDataSize) {
+ case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+ axioutpw = 8;
+ break;
+
+ case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+ axioutpw = 6;
+ break;
+
+ case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+ axioutpw = 5;
+ break;
+ }
+
+ ctrl->axiOutputMode = in->outputMode;
+
+ CDBG("axiOutputMode = %d\n", ctrl->axiOutputMode);
+
+ switch (ctrl->axiOutputMode) {
+ case VFE_AXI_OUTPUT_MODE_Output1: {
+ ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE;
+ ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+ ctrl->vfeBusConfigLocal.rawWritePathSelect =
+ VFE_RAW_OUTPUT_DISABLED;
+
+ ctrl->encPath.pathEnabled = FALSE;
+ ctrl->vfeImaskLocal.encIrq = FALSE;
+ ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE;
+ ctrl->vfeBusConfigLocal.encCbcrWrPathEn = FALSE;
+ ctrl->viewPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.viewIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE;
+ ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+ } /* VFE_AXI_OUTPUT_MODE_Output1 */
+ break;
+
+ case VFE_AXI_OUTPUT_MODE_Output2: {
+ ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE;
+ ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+ ctrl->vfeBusConfigLocal.rawWritePathSelect =
+ VFE_RAW_OUTPUT_DISABLED;
+
+ ctrl->encPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.encIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE;
+ ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+ ctrl->viewPath.pathEnabled = FALSE;
+ ctrl->vfeImaskLocal.viewIrq = FALSE;
+ ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE;
+ ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE;
+
+ if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+ } /* VFE_AXI_OUTPUT_MODE_Output2 */
+ break;
+
+ case VFE_AXI_OUTPUT_MODE_Output1AndOutput2: {
+ ctrl->vfeCamifConfigLocal.camif2BusEnable = FALSE;
+ ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+ ctrl->vfeBusConfigLocal.rawWritePathSelect =
+ VFE_RAW_OUTPUT_DISABLED;
+
+ ctrl->encPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.encIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE;
+ ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+ ctrl->viewPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.viewIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE;
+ ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+ } /* VFE_AXI_OUTPUT_MODE_Output1AndOutput2 */
+ break;
+
+ case VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2: {
+ /* For raw snapshot, we need both ping and pong buffer
+ * initialized to the same address. Otherwise, if we
+ * leave the pong buffer to NULL, there will be axi_error.
+ * Note that ideally we should deal with this at upper layer,
+ * which is in msm_vfe8x.c */
+ if (!in->output2.outputCbcr.outFragments[1][0]) {
+ in->output2.outputCbcr.outFragments[1][0] =
+ in->output2.outputCbcr.outFragments[0][0];
+ }
+
+ ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE;
+ ctrl->vfeCamifConfigLocal.camif2OutputEnable = FALSE;
+ ctrl->vfeBusConfigLocal.rawWritePathSelect =
+ VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+ ctrl->encPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.encIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+ VFE_COMP_IRQ_CBCR_ONLY;
+
+ ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE;
+ ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+ ctrl->viewPath.pathEnabled = FALSE;
+ ctrl->vfeImaskLocal.viewIrq = FALSE;
+ ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE;
+ ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = FALSE;
+
+ if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+ } /* VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2 */
+ break;
+
+ case VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1: {
+ ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE;
+ ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+ ctrl->vfeBusConfigLocal.rawWritePathSelect =
+ VFE_RAW_OUTPUT_VIEW_CBCR_PATH;
+
+ ctrl->encPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.encIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.encYWrPathEn = TRUE;
+ ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+ ctrl->viewPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.viewIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+ VFE_COMP_IRQ_CBCR_ONLY;
+
+ ctrl->vfeBusConfigLocal.viewYWrPathEn = FALSE;
+ ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+ } /* VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1 */
+ break;
+
+ case VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2: {
+ ctrl->vfeCamifConfigLocal.camif2BusEnable = TRUE;
+ ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+ ctrl->vfeBusConfigLocal.rawWritePathSelect =
+ VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+ ctrl->encPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.encIrq = TRUE;
+ ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+ VFE_COMP_IRQ_CBCR_ONLY;
+
+ ctrl->vfeBusConfigLocal.encYWrPathEn = FALSE;
+ ctrl->vfeBusConfigLocal.encCbcrWrPathEn = TRUE;
+
+ ctrl->viewPath.pathEnabled = TRUE;
+ ctrl->vfeImaskLocal.viewIrq = TRUE;
+
+ ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ ctrl->vfeBusConfigLocal.viewYWrPathEn = TRUE;
+ ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+ ctrl->encPath.multiFrag)
+ ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewYPingpongIrq = TRUE;
+
+ if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+ ctrl->viewPath.multiFrag)
+ ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+ } /* VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2 */
+ break;
+
+ case VFE_AXI_LAST_OUTPUT_MODE_ENUM:
+ break;
+ } /* switch */
+
+ /* Save the addresses for each path. */
+ /* output2 path */
+ fcnt = ctrl->encPath.fragCount;
+
+ pcircle = ctrl->encPath.yPath.addressBuffer;
+ pdest = ctrl->encPath.nextFrameAddrBuf;
+
+ psrc = &(in->output2.outputY.outFragments[0][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output2.outputY.outFragments[1][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output2.outputY.outFragments[2][0]);
+ for (i = 0; i < fcnt; i++)
+ *pdest++ = *psrc++;
+
+ pcircle = ctrl->encPath.cbcrPath.addressBuffer;
+
+ psrc = &(in->output2.outputCbcr.outFragments[0][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output2.outputCbcr.outFragments[1][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output2.outputCbcr.outFragments[2][0]);
+ for (i = 0; i < fcnt; i++)
+ *pdest++ = *psrc++;
+
+ vfe_set_bus_pipo_addr(&ctrl->viewPath, &ctrl->encPath);
+
+ ctrl->encPath.ackPending = FALSE;
+ ctrl->encPath.currentFrame = ping;
+ ctrl->encPath.whichOutputPath = 1;
+ ctrl->encPath.yPath.fragIndex = 2;
+ ctrl->encPath.cbcrPath.fragIndex = 2;
+ ctrl->encPath.yPath.hwCurrentFlag = ping;
+ ctrl->encPath.cbcrPath.hwCurrentFlag = ping;
+
+ /* output1 path */
+ pcircle = ctrl->viewPath.yPath.addressBuffer;
+ pdest = ctrl->viewPath.nextFrameAddrBuf;
+ fcnt = ctrl->viewPath.fragCount;
+
+ psrc = &(in->output1.outputY.outFragments[0][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output1.outputY.outFragments[1][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output1.outputY.outFragments[2][0]);
+ for (i = 0; i < fcnt; i++)
+ *pdest++ = *psrc++;
+
+ pcircle = ctrl->viewPath.cbcrPath.addressBuffer;
+
+ psrc = &(in->output1.outputCbcr.outFragments[0][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output1.outputCbcr.outFragments[1][0]);
+ for (i = 0; i < fcnt; i++)
+ *pcircle++ = *psrc++;
+
+ psrc = &(in->output1.outputCbcr.outFragments[2][0]);
+ for (i = 0; i < fcnt; i++)
+ *pdest++ = *psrc++;
+
+ ctrl->viewPath.ackPending = FALSE;
+ ctrl->viewPath.currentFrame = ping;
+ ctrl->viewPath.whichOutputPath = 0;
+ ctrl->viewPath.yPath.fragIndex = 2;
+ ctrl->viewPath.cbcrPath.fragIndex = 2;
+ ctrl->viewPath.yPath.hwCurrentFlag = ping;
+ ctrl->viewPath.cbcrPath.hwCurrentFlag = ping;
+
+ /* call to program the registers. */
+ vfe_axi_output(in, &ctrl->viewPath, &ctrl->encPath, axioutpw);
+}
+
+void vfe_camif_config(struct vfe_cmd_camif_config *in)
+{
+ struct vfe_camifcfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ CDBG("camif.frame pixelsPerLine = %d\n", in->frame.pixelsPerLine);
+ CDBG("camif.frame linesPerFrame = %d\n", in->frame.linesPerFrame);
+ CDBG("camif.window firstpixel = %d\n", in->window.firstpixel);
+ CDBG("camif.window lastpixel = %d\n", in->window.lastpixel);
+ CDBG("camif.window firstline = %d\n", in->window.firstline);
+ CDBG("camif.window lastline = %d\n", in->window.lastline);
+
+ /* determine if epoch interrupt needs to be enabled. */
+ if ((in->epoch1.enable == TRUE) &&
+ (in->epoch1.lineindex <=
+ in->frame.linesPerFrame))
+ ctrl->vfeImaskLocal.camifEpoch1Irq = 1;
+
+ if ((in->epoch2.enable == TRUE) &&
+ (in->epoch2.lineindex <=
+ in->frame.linesPerFrame)) {
+ ctrl->vfeImaskLocal.camifEpoch2Irq = 1;
+ }
+
+ /* save the content to program CAMIF_CONFIG seperately. */
+ ctrl->vfeCamifConfigLocal.camifCfgFromCmd = in->camifConfig;
+
+ /* EFS_Config */
+ cmd.efsEndOfLine = in->EFS.efsendofline;
+ cmd.efsStartOfLine = in->EFS.efsstartofline;
+ cmd.efsEndOfFrame = in->EFS.efsendofframe;
+ cmd.efsStartOfFrame = in->EFS.efsstartofframe;
+
+ /* Frame Config */
+ cmd.frameConfigPixelsPerLine = in->frame.pixelsPerLine;
+ cmd.frameConfigLinesPerFrame = in->frame.linesPerFrame;
+
+ /* Window Width Config */
+ cmd.windowWidthCfgLastPixel = in->window.lastpixel;
+ cmd.windowWidthCfgFirstPixel = in->window.firstpixel;
+
+ /* Window Height Config */
+ cmd.windowHeightCfglastLine = in->window.lastline;
+ cmd.windowHeightCfgfirstLine = in->window.firstline;
+
+ /* Subsample 1 Config */
+ cmd.subsample1CfgPixelSkip = in->subsample.pixelskipmask;
+ cmd.subsample1CfgLineSkip = in->subsample.lineskipmask;
+
+ /* Subsample 2 Config */
+ cmd.subsample2CfgFrameSkip = in->subsample.frameskip;
+ cmd.subsample2CfgFrameSkipMode = in->subsample.frameskipmode;
+ cmd.subsample2CfgPixelSkipWrap = in->subsample.pixelskipwrap;
+
+ /* Epoch Interrupt */
+ cmd.epoch1Line = in->epoch1.lineindex;
+ cmd.epoch2Line = in->epoch2.lineindex;
+
+ vfe_prog_hw(ctrl->vfebase + CAMIF_EFS_CONFIG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *in)
+{
+ struct vfe_fov_crop_cfg cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ ctrl->vfeModuleEnableLocal.cropEnable = in->enable;
+
+ /* FOV Corp, Part 1 */
+ cmd.lastPixel = in->lastPixel;
+ cmd.firstPixel = in->firstPixel;
+
+ /* FOV Corp, Part 2 */
+ cmd.lastLine = in->lastLine;
+ cmd.firstLine = in->firstLine;
+
+ vfe_prog_hw(ctrl->vfebase + VFE_CROP_WIDTH_CFG,
+ (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_get_hw_version(struct vfe_cmd_hw_version *out)
+{
+ uint32_t vfeHwVersionPacked;
+ struct vfe_hw_ver ver;
+
+ vfeHwVersionPacked = readl(ctrl->vfebase + VFE_HW_VERSION);
+
+ ver = *((struct vfe_hw_ver *)&vfeHwVersionPacked);
+
+ out->coreVersion = ver.coreVersion;
+ out->minorVersion = ver.minorVersion;
+ out->majorVersion = ver.majorVersion;
+}
+
+static void vfe_reset_internal_variables(void)
+{
+ unsigned long flags;
+
+ /* local variables to program the hardware. */
+ ctrl->vfeImaskPacked = 0;
+ ctrl->vfeImaskCompositePacked = 0;
+
+ /* FALSE = disable, 1 = enable. */
+ memset(&ctrl->vfeModuleEnableLocal, 0,
+ sizeof(ctrl->vfeModuleEnableLocal));
+
+ /* 0 = disable, 1 = enable */
+ memset(&ctrl->vfeCamifConfigLocal, 0,
+ sizeof(ctrl->vfeCamifConfigLocal));
+ /* 0 = disable, 1 = enable */
+ memset(&ctrl->vfeImaskLocal, 0, sizeof(ctrl->vfeImaskLocal));
+ memset(&ctrl->vfeStatsCmdLocal, 0, sizeof(ctrl->vfeStatsCmdLocal));
+ memset(&ctrl->vfeBusConfigLocal, 0, sizeof(ctrl->vfeBusConfigLocal));
+ memset(&ctrl->vfeBusPmConfigLocal, 0,
+ sizeof(ctrl->vfeBusPmConfigLocal));
+ memset(&ctrl->vfeBusCmdLocal, 0, sizeof(ctrl->vfeBusCmdLocal));
+ memset(&ctrl->vfeInterruptNameLocal, 0,
+ sizeof(ctrl->vfeInterruptNameLocal));
+ memset(&ctrl->vfeDroppedFrameCounts, 0,
+ sizeof(ctrl->vfeDroppedFrameCounts));
+ memset(&ctrl->vfeIrqThreadMsgLocal, 0,
+ sizeof(ctrl->vfeIrqThreadMsgLocal));
+
+ /* state control variables */
+ ctrl->vfeStartAckPendingFlag = FALSE;
+ ctrl->vfeStopAckPending = FALSE;
+ ctrl->vfeIrqCompositeMaskLocal.ceDoneSel = 0;
+ ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+ ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+ VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+ spin_lock_irqsave(&ctrl->state_lock, flags);
+ ctrl->vstate = VFE_STATE_IDLE;
+ spin_unlock_irqrestore(&ctrl->state_lock, flags);
+
+ ctrl->axiOutputMode = VFE_AXI_LAST_OUTPUT_MODE_ENUM;
+ /* 0 for continuous mode, 1 for snapshot mode */
+ ctrl->vfeOperationMode = VFE_START_OPERATION_MODE_CONTINUOUS;
+ ctrl->vfeSnapShotCount = 0;
+ ctrl->vfeStatsPingPongReloadFlag = FALSE;
+ /* this is unsigned 32 bit integer. */
+ ctrl->vfeFrameId = 0;
+ ctrl->vfeFrameSkip.output1Pattern = 0xffffffff;
+ ctrl->vfeFrameSkip.output1Period = 31;
+ ctrl->vfeFrameSkip.output2Pattern = 0xffffffff;
+ ctrl->vfeFrameSkip.output2Period = 31;
+ ctrl->vfeFrameSkipPattern = 0xffffffff;
+ ctrl->vfeFrameSkipCount = 0;
+ ctrl->vfeFrameSkipPeriod = 31;
+
+ memset((void *)&ctrl->encPath, 0, sizeof(ctrl->encPath));
+ memset((void *)&ctrl->viewPath, 0, sizeof(ctrl->viewPath));
+
+ ctrl->encPath.whichOutputPath = 1;
+ ctrl->encPath.cbcrStatusBit = 5;
+ ctrl->viewPath.whichOutputPath = 0;
+ ctrl->viewPath.cbcrStatusBit = 7;
+
+ ctrl->vfeTestGenStartFlag = FALSE;
+
+ /* default to bank 0. */
+ ctrl->vfeLaBankSel = 0;
+
+ /* default to bank 0 for all channels. */
+ memset(&ctrl->vfeGammaLutSel, 0, sizeof(ctrl->vfeGammaLutSel));
+
+ /* Stats control variables. */
+ memset(&ctrl->afStatsControl, 0, sizeof(ctrl->afStatsControl));
+ memset(&ctrl->awbStatsControl, 0, sizeof(ctrl->awbStatsControl));
+ vfe_set_stats_pingpong_address(&ctrl->afStatsControl,
+ &ctrl->awbStatsControl);
+}
+
+void vfe_reset(void)
+{
+ vfe_reset_internal_variables();
+
+ ctrl->vfeImaskLocal.resetAckIrq = TRUE;
+ ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+
+ /* disable all interrupts. */
+ writel(VFE_DISABLE_ALL_IRQS,
+ ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+
+ /* clear all pending interrupts*/
+ writel(VFE_CLEAR_ALL_IRQS,
+ ctrl->vfebase + VFE_IRQ_CLEAR);
+
+ /* enable reset_ack interrupt. */
+ writel(ctrl->vfeImaskPacked,
+ ctrl->vfebase + VFE_IRQ_MASK);
+
+ writel(VFE_RESET_UPON_RESET_CMD,
+ ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}