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