/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * */ #include #include #include #include #include #include #include #include "msm_vfe8x_proc.h" #include #include 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; }; 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_cmds_camif_epoch vfeCamifEpoch1Local; 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; struct msm_vfe_callback *resp; struct vfe_frame_extra extdata; struct isr_queue_cmd irqs[5]; spinlock_t irqs_lock; int irq_get; int irq_put; int vfeirq; void __iomem *vfebase; void *syncdata; struct msm_camera_sensor_info *s_info; }; static struct msm_vfe8x_ctrl *ctrl; static void vfe_prog_hw(uint8_t *hwreg, uint32_t *inptr, uint32_t regcnt) { /* unsigned long flags; */ uint32_t i; uint32_t *p; p = (uint32_t *) (hwreg); for (i = 0; i < (regcnt >> 2); i++) writel(*inptr++, p++); /* *p++ = *inptr++; */ } 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; memset(&cmd, 0, sizeof(cmd)); /* 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; memset(&cmd, 0, sizeof(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 = *pDeltaR | (*pDeltaGr << 16); pDeltaR++; pDeltaGr++; writel(data, ctrl->vfebase + VFE_DMI_DATA_LO); data = *pDeltaB | (*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_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_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 uint32_t vfe_read_axi_status(void) { return readl(ctrl->vfebase + VFE_AXI_STATUS); } 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 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, int *elen) { switch (type) { #ifndef CONFIG_720P_CAMERA case VFE_MSG_OUTPUT1:{ pinfo->y_phy = ((struct vfe_message *)data)->_u.msgOutput1.yBuffer; pinfo->cbcr_phy = ((struct vfe_message *)data)->_u.msgOutput1. cbcrBuffer; ctrl->extdata.bpcInfo = ((struct vfe_message *)data)->_u.msgOutput1.bpcInfo; ctrl->extdata.asfInfo = ((struct vfe_message *)data)->_u.msgOutput1.asfInfo; ctrl->extdata.frameCounter = ((struct vfe_message *)data)->_u.msgOutput1. frameCounter; ctrl->extdata.pmData = ((struct vfe_message *)data)->_u.msgOutput1.pmData; *ext = &ctrl->extdata; *elen = sizeof(ctrl->extdata); } 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); ctrl->extdata.bpcInfo = ((struct vfe_message *)data)->_u.msgOutput2.bpcInfo; ctrl->extdata.asfInfo = ((struct vfe_message *)data)->_u.msgOutput2.asfInfo; ctrl->extdata.frameCounter = ((struct vfe_message *)data)->_u.msgOutput2. frameCounter; ctrl->extdata.pmData = ((struct vfe_message *)data)->_u.msgOutput2.pmData; *ext = &ctrl->extdata; *elen = sizeof(ctrl->extdata); } break; #else case VFE_MSG_OUTPUT_P: case VFE_MSG_OUTPUT_V:{ 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); /*pinfo->output_id = OUTPUT_TYPE_P;*/ ctrl->extdata.bpcInfo = ((struct vfe_message *)data)->_u.msgOutput2.bpcInfo; ctrl->extdata.asfInfo = ((struct vfe_message *)data)->_u.msgOutput2.asfInfo; ctrl->extdata.frameCounter = ((struct vfe_message *)data)->_u.msgOutput2. frameCounter; ctrl->extdata.pmData = ((struct vfe_message *)data)->_u.msgOutput2.pmData; *ext = &ctrl->extdata; *elen = sizeof(ctrl->extdata); } break; #endif 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 boolean vfe_send_preview_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); static boolean vfe_send_video_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); #ifdef CONFIG_720P_CAMERA static boolean vfe_send_mainimage_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); static boolean vfe_send_thumbnail_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); #endif static boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); static boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); static boolean invalid(struct msm_vfe_resp *rp, struct vfe_message *_m, void *_d) { BUG_ON(1); /* this function should not be called. */ return FALSE; } static struct { boolean (*fn)(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data); enum vfe_resp_msg rt; /* reponse type */ } vfe_funcs[] = { [VFE_MSG_ID_RESET_ACK] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_START_ACK] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_STOP_ACK] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_UPDATE_ACK] = { NULL, VFE_MSG_GENERAL }, #ifndef CONFIG_720P_CAMERA [VFE_MSG_ID_OUTPUT1] = { vfe_send_preview_msg, VFE_MSG_OUTPUT1 }, [VFE_MSG_ID_OUTPUT2] = { vfe_send_video_msg, VFE_MSG_OUTPUT2 }, #else [VFE_MSG_ID_OUTPUT_P] = { vfe_send_preview_msg, VFE_MSG_OUTPUT_P }, [VFE_MSG_ID_OUTPUT_V] = { vfe_send_video_msg, VFE_MSG_OUTPUT_V }, [VFE_MSG_ID_OUTPUT_S] = { vfe_send_mainimage_msg, VFE_MSG_OUTPUT_S }, [VFE_MSG_ID_OUTPUT_T] = { vfe_send_thumbnail_msg, VFE_MSG_OUTPUT_T }, #endif [VFE_MSG_ID_SNAPSHOT_DONE] = { NULL, VFE_MSG_SNAPSHOT }, [VFE_MSG_ID_STATS_AUTOFOCUS] = { vfe_send_af_stats_msg, VFE_MSG_STATS_AF }, [VFE_MSG_ID_STATS_WB_EXP] = { vfe_send_awb_stats_msg, VFE_MSG_STATS_WE }, [VFE_MSG_ID_EPOCH1] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_EPOCH2] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_SYNC_TIMER0_DONE] = { invalid }, [VFE_MSG_ID_SYNC_TIMER1_DONE] = { invalid }, [VFE_MSG_ID_SYNC_TIMER2_DONE] = { invalid }, [VFE_MSG_ID_ASYNC_TIMER0_DONE] = { invalid }, [VFE_MSG_ID_ASYNC_TIMER1_DONE] = { invalid }, [VFE_MSG_ID_ASYNC_TIMER2_DONE] = { invalid }, [VFE_MSG_ID_ASYNC_TIMER3_DONE] = { invalid }, [VFE_MSG_ID_AF_OVERFLOW] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_AWB_OVERFLOW] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_AXI_ERROR] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_CAMIF_OVERFLOW] = { NULL, VFE_MSG_GENERAL }, [VFE_MSG_ID_VIOLATION] = { invalid }, [VFE_MSG_ID_CAMIF_ERROR] = { vfe_send_camif_error_msg, VFE_MSG_GENERAL }, [VFE_MSG_ID_BUS_OVERFLOW] = { vfe_send_bus_overflow_msg, VFE_MSG_GENERAL }, }; static void vfe_proc_ops(enum VFE_MESSAGE_ID id, void *data) { struct msm_vfe_resp *rp; struct vfe_message *msg; struct msm_sync *sync = (struct msm_sync *)ctrl->syncdata; CDBG("ctrl->vfeOperationMode = %d, msgId = %d\n", ctrl->vfeOperationMode, id); if (id >= ARRAY_SIZE(vfe_funcs) || vfe_funcs[id].fn == invalid) { pr_err("%s: invalid VFE message id %d\n", __func__, id); return; } /* In 8k, OUTPUT1 & OUTPUT2 messages arrive before SNAPSHOT_DONE. * We don't send such messages to the user. Note that we can do * this in the vfe_func[] callback, but that would cause us to * allocate and then immediately free the msm_vfe_resp structure, * which is wasteful. */ #ifndef CONFIG_720P_CAMERA if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) && (id == VFE_MSG_ID_OUTPUT1 || id == VFE_MSG_ID_OUTPUT2)) return; #else if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) && (id == VFE_MSG_ID_OUTPUT_T || id == VFE_MSG_ID_OUTPUT_S)) return; #endif rp = ctrl->resp->vfe_alloc(sizeof(*rp) + (vfe_funcs[id].fn ? sizeof(*msg) : 0), ctrl->syncdata, GFP_ATOMIC); if (!rp) { pr_err("%s: out of memory\n", __func__); return; } rp->type = vfe_funcs[id].rt; rp->evt_msg.type = MSM_CAMERA_MSG; rp->evt_msg.msg_id = id; rp->evt_msg.exttype = 0; if (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) { rp->evt_msg.exttype = VFE_MSG_SNAPSHOT; #if 0 /* google flashlight */ /* Turn off the flash if epoch1 is enabled and snapshot is done. */ if (ctrl->vfeCamifEpoch1Local.enable && ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT && id == VFE_MSG_ID_SNAPSHOT_DONE) { ctrl->resp->flash_ctrl(sync, MSM_CAMERA_LED_OFF); ctrl->vfeCamifEpoch1Local.enable = 0; #endif } if (!vfe_funcs[id].fn) { rp->evt_msg.len = 0; rp->evt_msg.data = 0; } else { /* populate the message accordingly */ if (vfe_funcs[id].fn) rp->evt_msg.data = msg = (struct vfe_message *)(rp + 1); else rp->evt_msg.data = msg = 0; rp->evt_msg.len = sizeof(*msg); if (msg == NULL) { pr_err("%s dsp send msg with NULL pointer\n", __func__); return ; } msg->_d = id; if (vfe_funcs[id].fn(rp, msg, data) == FALSE) { pr_info("%s: freeing memory: handler for %d " "returned false\n", __func__, id); ctrl->resp->vfe_free(rp); return; } } ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, ctrl->syncdata, GFP_ATOMIC); } static boolean vfe_send_bus_overflow_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { struct isr_queue_cmd *qcmd = data; memcpy(&(msg->_u.msgBusOverflow), &qcmd->vfePmData, sizeof(qcmd->vfePmData)); return TRUE; } static boolean vfe_send_camif_error_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { struct isr_queue_cmd *qcmd = data; memcpy(&(msg->_u.msgCamifError), &qcmd->vfeCamifStatusLocal, sizeof(qcmd->vfeCamifStatusLocal)); return TRUE; } static void vfe_process_error_irq(struct isr_queue_cmd *qcmd) { struct vfe_interrupt_status *irqstatus = &qcmd->vfeInterruptStatus; /* all possible error irq. Note error irqs are not enabled, it is * checked only when other interrupts are present. */ if (irqstatus->afOverflowIrq) vfe_proc_ops(VFE_MSG_ID_AF_OVERFLOW, qcmd); if (irqstatus->awbOverflowIrq) vfe_proc_ops(VFE_MSG_ID_AWB_OVERFLOW, qcmd); if (irqstatus->axiErrorIrq) vfe_proc_ops(VFE_MSG_ID_AXI_ERROR, qcmd); if (irqstatus->busOverflowIrq) vfe_proc_ops(VFE_MSG_ID_BUS_OVERFLOW, qcmd); if (irqstatus->camifErrorIrq) vfe_proc_ops(VFE_MSG_ID_CAMIF_ERROR, qcmd); if (irqstatus->camifOverflowIrq) vfe_proc_ops(VFE_MSG_ID_CAMIF_OVERFLOW, qcmd); if (irqstatus->violationIrq) pr_err("%s: violation irq\n", __func__); } /* We use epoch1 interrupt to control flash timing. The purpose is to reduce the * flash duration as much as possible. Userspace driver has no way to control * the exactly timing like VFE. Currently we skip a frame during snapshot. * We want to fire the flash in the middle of the first frame. Epoch1 interrupt * allows us to set a line index and we will get an interrupt when VFE reaches * the line. Userspace driver sets the line index in camif configuration. VFE * will fire the flash in high mode when it gets the epoch1 interrupt. Flash * will be turned off after snapshot is done. */ static void vfe_process_camif_epoch1_irq(void) { /* Turn on the flash. */ struct msm_sync *sync = (struct msm_sync *)ctrl->syncdata; /*remove google flashlight*/ /*ctrl->resp->flash_ctrl(sync, MSM_CAMERA_LED_HIGH);*/ /* Disable the epoch1 interrupt. */ ctrl->vfeImaskLocal.camifEpoch1Irq = FALSE; ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); vfe_program_irq_mask(ctrl->vfeImaskPacked); } 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 boolean vfe_get_af_pingpong_status(void) { uint32_t busPingPongStatus = readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); return !!(busPingPongStatus & VFE_AF_PINGPONG_STATUS_BIT); } 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 boolean vfe_send_af_stats_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { uint32_t afBufAddress = (uint32_t)data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; msg->_u.msgStatsAf.afBuffer = afBufAddress; msg->_u.msgStatsAf.frameCounter = ctrl->vfeFrameId; ctrl->afStatsControl.ackPending = TRUE; vfe_addr_convert(&(rp->phy), rp->type, msg, NULL, NULL); return TRUE; } 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_proc_ops(VFE_MSG_ID_STATS_AUTOFOCUS, (void *)ctrl->afStatsControl.bufToRender); } else ctrl->afStatsControl.droppedStatsFrameCount++; } static boolean vfe_get_awb_pingpong_status(void) { uint32_t busPingPongStatus = readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS); return !!(busPingPongStatus & VFE_AWB_PINGPONG_STATUS_BIT); } 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 boolean vfe_send_awb_stats_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { uint32_t awbBufAddress = (uint32_t)data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; msg->_u.msgStatsWbExp.awbBuffer = awbBufAddress; msg->_u.msgStatsWbExp.frameCounter = ctrl->vfeFrameId; ctrl->awbStatsControl.ackPending = TRUE; vfe_addr_convert(&(rp->phy), rp->type, msg, NULL, NULL); return TRUE; } 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_proc_ops(VFE_MSG_ID_STATS_WB_EXP, (void *)ctrl->awbStatsControl.bufToRender); } else ctrl->awbStatsControl.droppedStatsFrameCount++; } 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); #if 0 /*this for YUV performance tuning */ writel(0x7, ctrl->vfebase + CAMIF_COMMAND); writel(0x3, ctrl->vfebase + CAMIF_COMMAND); CDBG("camifStatus = 0x%x\n", out->camifStatus); #endif /* 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 void vfe_parse_interrupt_status(struct vfe_interrupt_status *ret, uint32_t irqStatusIn) { struct vfe_irqenable hwstat; 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->awbOverflowIrq || ret->awbPingpongIrq || ret->afPingpongIrq || 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; } static void vfe_get_asf_frame_info(struct vfe_frame_asf_info *rc, struct vfe_irq_thread_msg *in) { struct vfe_asf_info asfInfoTemp; 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; } static void vfe_get_demosaic_frame_info(struct vfe_frame_bpc_info *rc, struct vfe_irq_thread_msg *in) { struct vfe_bps_info bpcInfoTemp; 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; } static void vfe_get_camif_status(struct vfe_msg_camif_status *rc, struct vfe_irq_thread_msg *in) { struct vfe_camif_stats camifStatusTemp; 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; } static void vfe_get_performance_monitor_data(struct vfe_bus_performance_monitor *rc, struct vfe_irq_thread_msg *in) { 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; } 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_proc_ops(VFE_MSG_ID_START_ACK, NULL); ctrl->vfeStartAckPendingFlag = FALSE; } else vfe_proc_ops(VFE_MSG_ID_UPDATE_ACK, NULL); } static void vfe_process_reset_irq(void) { /* unsigned long flags; */ ctrl->vstate = VFE_STATE_IDLE; if (ctrl->vfeStopAckPending == TRUE) { ctrl->vfeStopAckPending = FALSE; /* disable all irqs when got stop ack from VFE */ vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS); vfe_proc_ops(VFE_MSG_ID_STOP_ACK, NULL); } else { vfe_set_default_reg_values(); vfe_proc_ops(VFE_MSG_ID_RESET_ACK, NULL); } } 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 boolean vfe_send_video_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { #ifdef CONFIG_720P_CAMERA struct vfe_msg_output *pPayload = data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); rp->phy.output_id = OUTPUT_TYPE_V; CDBG("vfe_send_video_msg rp->type= %d\n",rp->type); vfe_addr_convert(&(rp->phy), rp->type, msg, &(rp->extdata), &(rp->extlen)); return TRUE; #else struct vfe_msg_output *pPayload = data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; memcpy(&(msg->_u.msgOutput2), (void *)pPayload, sizeof(struct vfe_msg_output)); ctrl->encPath.ackPending = TRUE; if (!(ctrl->vfeRequestedSnapShotCount <= 3) && (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT)) ctrl->encPath.ackPending = TRUE; vfe_addr_convert(&(rp->phy), rp->type, msg, &(rp->extdata), &(rp->extlen)); return TRUE; #endif } static boolean vfe_send_preview_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { #ifdef CONFIG_720P_CAMERA struct vfe_msg_output *pPayload = data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); rp->phy.output_id = OUTPUT_TYPE_P; CDBG("vfe_send_preview_msg rp->type= %d\n",rp->type); vfe_addr_convert(&(rp->phy), rp->type, msg, &(rp->extdata), &(rp->extlen)); return TRUE; #else struct vfe_msg_output *pPayload = data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); ctrl->viewPath.ackPending = TRUE; if (!(ctrl->vfeRequestedSnapShotCount <= 3) && (ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT)) ctrl->viewPath.ackPending = TRUE; vfe_addr_convert(&(rp->phy), rp->type, msg, &(rp->extdata), &(rp->extlen)); return TRUE; #endif } #ifdef CONFIG_720P_CAMERA static boolean vfe_send_thumbnail_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { struct vfe_msg_output *pPayload = data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); rp->phy.output_id = OUTPUT_TYPE_T; CDBG("vfe_send_thumbnail_msg rp->type= %d\n",rp->type); if (ctrl->viewPath.snapshotPendingCount <= 1) ctrl->viewPath.ackPending = FALSE; vfe_addr_convert(&(rp->phy), rp->type, msg, &(rp->extdata), &(rp->extlen)); return TRUE; } static boolean vfe_send_mainimage_msg(struct msm_vfe_resp *rp, struct vfe_message *msg, void *data) { struct vfe_msg_output *pPayload = data; if (ctrl->vstate != VFE_STATE_ACTIVE) return FALSE; memcpy(&(msg->_u), (void *)pPayload, sizeof(struct vfe_msg_output)); rp->phy.output_id = OUTPUT_TYPE_S; CDBG("vfe_send_mainimage_msg rp->type= %d\n",rp->type); if (ctrl->encPath.snapshotPendingCount <=1 ) { ctrl->encPath.ackPending = FALSE; } vfe_addr_convert(&(rp->phy), rp->type, msg, &(rp->extdata), &(rp->extlen)); return TRUE; } #endif 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; #ifndef CONFIG_720P_CAMERA if (whichOutputPath) { /* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */ vfe_proc_ops(VFE_MSG_ID_OUTPUT2, &msgPayload); } else { /* msgPayload.pmData = ctrl->vfePmData.viewPathPmInfo; */ vfe_proc_ops(VFE_MSG_ID_OUTPUT1, &msgPayload); } #else if (whichOutputPath) {/* vfe output2 physical path */ /* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */ ctrl->encPath.ackPending = TRUE; if (ctrl->vfeOperationMode == 0) { if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_Output1AndOutput2) { /* video mode */ vfe_proc_ops(VFE_MSG_ID_OUTPUT_V, &msgPayload); } else { /* preview mode */ vfe_proc_ops(VFE_MSG_ID_OUTPUT_P, &msgPayload); } } else { vfe_proc_ops(VFE_MSG_ID_OUTPUT_S, &msgPayload); } } else { /* physical output1 path from vfe */ ctrl->viewPath.ackPending = TRUE; if (ctrl->vfeOperationMode == 0) { vfe_proc_ops(VFE_MSG_ID_OUTPUT_P, &msgPayload); CDBG(" ==== check output ==== video mode display output.\n"); } else { vfe_proc_ops(VFE_MSG_ID_OUTPUT_T, &msgPayload); CDBG(" ==== check output ==== snapshot mode thumbnail output.\n"); } } #endif } 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]; 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 { CDBG("horng irqstatus->encIrq = %x\n", irqstatus->encIrq); if (irqstatus->encIrq) vfe_process_frame_done_irq_no_frag(&ctrl-> encPath); } } if (ctrl->vfeOperationMode) { if ((ctrl->encPath.snapshotPendingCount == 0) && (ctrl->viewPath.snapshotPendingCount == 0)) { ctrl->vstate = VFE_STATE_IDLE; vfe_proc_ops(VFE_MSG_ID_SNAPSHOT_DONE, NULL); vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP); vfe_pm_stop(); } } } static void __vfe_do_tasklet(struct isr_queue_cmd *qcmd) { if (qcmd->vfeInterruptStatus.regUpdateIrq) { CDBG("irq regUpdateIrq\n"); vfe_process_reg_update_irq(); } if (qcmd->vfeInterruptStatus.resetAckIrq) { CDBG("%s: process resetAckIrq\n", __func__); vfe_process_reset_irq(); } if (ctrl->vstate != VFE_STATE_ACTIVE) return; if (qcmd->vfeInterruptStatus.camifEpoch1Irq) { vfe_process_camif_epoch1_irq(); } #if 0 if (qcmd->vfeInterruptStatus.camifEpoch2Irq) vfe_proc_ops(VFE_MSG_ID_EPOCH2); #endif /* 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); #if 0 if (qcmd->vfeInterruptStatus.anySyncTimerIrqs) vfe_process_sync_timer_irq(); if (qcmd->vfeInterruptStatus.anyAsyncTimerIrqs) vfe_process_async_timer_irq(); #endif if (qcmd->vfeInterruptStatus.camifSofIrq) { CDBG("irq: camifSofIrq\n"); vfe_process_camif_sof_irq(); } } static struct isr_queue_cmd *get_irq_cmd_nosync(void) { int old_get = ctrl->irq_get++; ctrl->irq_get = ctrl->irq_get % ARRAY_SIZE(ctrl->irqs); if (ctrl->irq_get == ctrl->irq_put) { pr_err("%s: out of irq command packets\n", __func__); ctrl->irq_get = old_get; return NULL; } return ctrl->irqs + old_get; } static struct isr_queue_cmd *next_irq_cmd(void) { unsigned long flags; struct isr_queue_cmd *cmd; spin_lock_irqsave(&ctrl->irqs_lock, flags); if (ctrl->irq_get == ctrl->irq_put) { spin_unlock_irqrestore(&ctrl->irqs_lock, flags); return NULL; /* already empty */ } cmd = ctrl->irqs + ctrl->irq_put; spin_unlock_irqrestore(&ctrl->irqs_lock, flags); return cmd; } static void put_irq_cmd(void) { unsigned long flags; spin_lock_irqsave(&ctrl->irqs_lock, flags); if (ctrl->irq_get == ctrl->irq_put) { spin_unlock_irqrestore(&ctrl->irqs_lock, flags); return; /* already empty */ } ctrl->irq_put++; ctrl->irq_put %= ARRAY_SIZE(ctrl->irqs); spin_unlock_irqrestore(&ctrl->irqs_lock, flags); } static void vfe_do_tasklet(unsigned long data) { int cnt = 0; struct isr_queue_cmd *qcmd = NULL; if (!ctrl) return; CDBG("%s\n", __func__); while ((qcmd = next_irq_cmd())) { __vfe_do_tasklet(qcmd); put_irq_cmd(); cnt++; } if (cnt > 1) pr_info("%s: serviced %d vfe interrupts\n", __func__, cnt); } 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; } if (ctrl->vfeStopAckPending) irqStatusLocal = (VFE_IMASK_WHILE_STOPPING & irq.vfeIrqStatus); else irqStatusLocal = ((ctrl->vfeImaskPacked | VFE_IMASK_ERROR_ONLY) & irq.vfeIrqStatus); spin_lock_irqsave(&ctrl->irqs_lock, flags); qcmd = get_irq_cmd_nosync(); if (!qcmd) { spin_unlock_irqrestore(&ctrl->irqs_lock, flags); goto done; } /* parse the interrupt status to local data structures. */ vfe_parse_interrupt_status(&qcmd->vfeInterruptStatus, irqStatusLocal); vfe_get_asf_frame_info(&qcmd->vfeAsfFrameInfo, &irq); vfe_get_demosaic_frame_info(&qcmd->vfeBpcFrameInfo, &irq); vfe_get_camif_status(&qcmd->vfeCamifStatusLocal, &irq); vfe_get_performance_monitor_data(&qcmd->vfePmData, &irq); spin_unlock_irqrestore(&ctrl->irqs_lock, flags); tasklet_schedule(&vfe_tasklet); done: /* 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; struct msm_camera_sensor_info *s_info; s_info = pdev->dev.platform_data; pdev->resource = s_info->resource; pdev->num_resources = s_info->num_resources; vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!vfemem) { pr_err("%s: no mem resource\n", __func__); return -ENODEV; } vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!vfeirq) { pr_err("%s: no irq resource\n", __func__); return -ENODEV; } vfeio = request_mem_region(vfemem->start, resource_size(vfemem), pdev->name); if (!vfeio) { pr_err("%s: VFE region already claimed\n", __func__); return -EBUSY; } ctrl = kzalloc(sizeof(struct msm_vfe8x_ctrl), GFP_KERNEL); if (!ctrl) { pr_err("%s: out of memory\n", __func__); rc = -ENOMEM; goto cmd_init_failed1; } spin_lock_init(&ctrl->irqs_lock); ctrl->vfeirq = vfeirq->start; ctrl->vfebase = ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1); if (!ctrl->vfebase) { pr_err("%s: ioremap failed\n", __func__); rc = -ENOMEM; goto cmd_init_failed2; } rc = request_irq(ctrl->vfeirq, vfe_parse_irq, IRQF_TRIGGER_RISING, "vfe", 0); if (rc < 0) { pr_err("%s: request_irq(%d) failed\n", __func__, ctrl->vfeirq); goto cmd_init_failed2; } if (presp && presp->vfe_resp) ctrl->resp = presp; else { pr_err("%s: no vfe_resp function\n", __func__); rc = -EIO; goto cmd_init_failed3; } ctrl->syncdata = sdata; ctrl->s_info = s_info; 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); if (mem == NULL) { pr_err("%s : platform get resource is NULL pointer\n", __func__); } else release_mem_region(mem->start, (mem->end - mem->start) + 1); kfree(ctrl); ctrl = 0; } void vfe_stats_af_stop(void) { ctrl->vfeStatsCmdLocal.autoFocusEnable = FALSE; ctrl->vfeImaskLocal.afPingpongIrq = FALSE; } void vfe_stop(void) { int spin_cnt = 0; 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); do { vfeAxiStauts = vfe_read_axi_status(); spin_cnt++; } while (!(vfeAxiStauts & AXI_STATUS_BUSY_MASK)); if (spin_cnt > 1) pr_warning("%s: spin_cnt %d\n", __func__, spin_cnt); 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: pr_err("%s: invalid gamma channel %d\n", __func__, in->channelSelect); 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: pr_err("%s: invalid gamma channel %d\n", __func__, in->channelSelect); 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; } #ifndef CONFIG_720P_CAMERA 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; } #else void vfe_output_v_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]); CDBG("video_frame_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_output_p_ack(struct vfe_cmd_output_ack *in) { const uint32_t *psrc; uint32_t *pdest; uint8_t i; if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_Output1AndOutput2 ) { /* video mode, preview comes from output1 path */ 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; } else { /* preview mode, preview comes from output2 path. */ pdest = ctrl->encPath.nextFrameAddrBuf; 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; } } #endif void vfe_start(struct vfe_cmd_start *in) { 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_proc_ops(VFE_MSG_ID_START_ACK, NULL); ctrl->vfeStartAckPendingFlag = FALSE; } ctrl->vstate = VFE_STATE_ACTIVE; } 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.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)); } 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_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_epoch1_config(struct vfe_cmds_camif_epoch *in) { struct vfe_epoch1cfg cmd; memset(&cmd, 0, sizeof(cmd)); /* determine if epoch interrupt needs to be enabled. */ if (in->enable == TRUE) { cmd.epoch1Line = in->lineindex; vfe_prog_hw(ctrl->vfebase + CAMIF_EPOCH_IRQ, (uint32_t *)&cmd, sizeof(cmd)); } /* Set the epoch1 interrupt mask. */ ctrl->vfeImaskLocal.camifEpoch1Irq = in->enable; ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal); vfe_program_irq_mask(ctrl->vfeImaskPacked); /* Store the epoch1 data. */ ctrl->vfeCamifEpoch1Local.enable = in->enable; ctrl->vfeCamifEpoch1Local.lineindex = in->lineindex; } 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) { /* 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; ctrl->vstate = VFE_STATE_IDLE; 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); }