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