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