838 lines
18 KiB
C
838 lines
18 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/uaccess.h>
|
|
#include <linux/interrupt.h>
|
|
#include <mach/irqs.h>
|
|
#include <linux/clk.h>
|
|
#include "msm_vfe8x_proc.h"
|
|
#include <mach/camera.h>
|
|
|
|
#define ON 1
|
|
#define OFF 0
|
|
|
|
static void *vfe_syncdata;
|
|
static struct clk *ebi1_clk;
|
|
static const char *const clk_name = "ebi1_clk";
|
|
|
|
static int vfe_enable(struct camera_enable_cmd *enable)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int vfe_disable(struct camera_enable_cmd *enable,
|
|
struct platform_device *dev)
|
|
{
|
|
vfe_stop();
|
|
msm_camio_disable(dev);
|
|
return 0;
|
|
}
|
|
|
|
static int vfe_init(struct msm_vfe_callback *presp, struct platform_device *dev)
|
|
{
|
|
int rc = 0;
|
|
|
|
ebi1_clk = clk_get(NULL, clk_name);
|
|
if (!ebi1_clk) {
|
|
pr_err("%s: could not get %s\n", __func__, clk_name);
|
|
return -EIO;
|
|
}
|
|
|
|
rc = clk_set_rate(ebi1_clk, 128000000);
|
|
if (rc < 0) {
|
|
pr_err("%s: clk_set_rate(%s) failed: %d\n", __func__,
|
|
clk_name, rc);
|
|
return rc;
|
|
}
|
|
|
|
rc = vfe_cmd_init(presp, dev, vfe_syncdata);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
/* Bring up all the required GPIOs and Clocks */
|
|
return msm_camio_enable(dev);
|
|
}
|
|
|
|
static void vfe_release(struct platform_device *dev)
|
|
{
|
|
struct msm_sensor_ctrl *sctrl =
|
|
&((struct msm_sync *)vfe_syncdata)->sctrl;
|
|
|
|
if (ebi1_clk) {
|
|
clk_set_rate(ebi1_clk, 0);
|
|
clk_put(ebi1_clk);
|
|
ebi1_clk = 0;
|
|
}
|
|
|
|
if (sctrl)
|
|
sctrl->s_release();
|
|
|
|
msm_camio_disable(dev);
|
|
vfe_cmd_release(dev);
|
|
vfe_syncdata = NULL;
|
|
}
|
|
|
|
static void vfe_config_axi(int mode,
|
|
struct axidata *ad,
|
|
struct vfe_cmd_axi_output_config *ao)
|
|
{
|
|
struct msm_pmem_region *regptr, *regptr1;
|
|
int i, j;
|
|
uint32_t *p1, *p2;
|
|
regptr1 = NULL;
|
|
|
|
if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
|
|
regptr = ad->region;
|
|
for (i = 0; i < ad->bufnum1; i++) {
|
|
|
|
p1 = &(ao->output1.outputY.outFragments[i][0]);
|
|
p2 = &(ao->output1.outputCbcr.outFragments[i][0]);
|
|
|
|
for (j = 0; j < ao->output1.fragmentCount; j++) {
|
|
|
|
*p1 = regptr->paddr + regptr->info.y_off;
|
|
p1++;
|
|
|
|
*p2 = regptr->paddr + regptr->info.cbcr_off;
|
|
p2++;
|
|
}
|
|
regptr++;
|
|
}
|
|
}
|
|
/* if OUTPUT1 or Both */
|
|
if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
|
|
|
|
regptr = &(ad->region[ad->bufnum1]);
|
|
CDBG("bufnum2 = %d\n", ad->bufnum2);
|
|
|
|
for (i = 0; i < ad->bufnum2; i++) {
|
|
|
|
p1 = &(ao->output2.outputY.outFragments[i][0]);
|
|
p2 = &(ao->output2.outputCbcr.outFragments[i][0]);
|
|
|
|
CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\
|
|
"cbcr_off = %d\n", regptr->paddr,
|
|
regptr->info.y_off, regptr->info.cbcr_off);
|
|
|
|
for (j = 0; j < ao->output2.fragmentCount; j++) {
|
|
|
|
*p1 = regptr->paddr + regptr->info.y_off;
|
|
CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
|
|
p1++;
|
|
|
|
*p2 = regptr->paddr + regptr->info.cbcr_off;
|
|
CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
|
|
p2++;
|
|
}
|
|
regptr++;
|
|
}
|
|
}
|
|
#ifdef CONFIG_720P_CAMERA
|
|
/* For video configuration */
|
|
if (mode == OUTPUT_1_AND_3) {
|
|
/* this is preview buffer. */
|
|
regptr = &(ad->region[0]);
|
|
/* this is video buffer. */
|
|
regptr1 = &(ad->region[ad->bufnum1]);
|
|
CDBG("bufnum1 = %d\n", ad->bufnum1);
|
|
CDBG("bufnum2 = %d\n", ad->bufnum2);
|
|
|
|
for (i = 0; i < ad->bufnum1; i++) {
|
|
p1 = &(ao->output1.outputY.outFragments[i][0]);
|
|
p2 = &(ao->output1.outputCbcr.outFragments[i][0]);
|
|
|
|
CDBG("config_axi: O1, phy = 0x%lx, y_off = %d, "\
|
|
"cbcr_off = %d\n", regptr->paddr,
|
|
regptr->info.y_off, regptr->info.cbcr_off);
|
|
|
|
for (j = 0; j < ao->output1.fragmentCount; j++) {
|
|
|
|
*p1 = regptr->paddr + regptr->info.y_off;
|
|
CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
|
|
p1++;
|
|
|
|
*p2 = regptr->paddr + regptr->info.cbcr_off;
|
|
CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
|
|
p2++;
|
|
}
|
|
regptr++;
|
|
}
|
|
for (i = 0; i < ad->bufnum2; i++) {
|
|
p1 = &(ao->output2.outputY.outFragments[i][0]);
|
|
p2 = &(ao->output2.outputCbcr.outFragments[i][0]);
|
|
|
|
CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, "\
|
|
"cbcr_off = %d\n", regptr1->paddr,
|
|
regptr1->info.y_off, regptr1->info.cbcr_off);
|
|
|
|
for (j = 0; j < ao->output2.fragmentCount; j++) {
|
|
|
|
*p1 = regptr1->paddr + regptr1->info.y_off;
|
|
CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
|
|
p1++;
|
|
|
|
*p2 = regptr1->paddr + regptr1->info.cbcr_off;
|
|
CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
|
|
p2++;
|
|
}
|
|
regptr1++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
#define ERR_COPY_FROM_USER() \
|
|
pr_err("%s(%d): copy from user\n", __func__, __LINE__)
|
|
|
|
#define CHECKED_COPY_FROM_USER(in) { \
|
|
if (cmd->length != sizeof(*(in))) { \
|
|
pr_err("msm_camera: %s:%d cmd %d: user data size %d " \
|
|
"!= kernel data size %d\n", \
|
|
__func__, __LINE__, \
|
|
cmd->id, cmd->length, sizeof(*(in))); \
|
|
rc = -EIO; \
|
|
break; \
|
|
} \
|
|
if (copy_from_user((in), (void __user *)cmd->value, \
|
|
sizeof(*(in)))) { \
|
|
ERR_COPY_FROM_USER(); \
|
|
rc = -EFAULT; \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
static int vfe_proc_general(struct msm_vfe_command_8k *cmd)
|
|
{
|
|
int rc = 0;
|
|
|
|
CDBG("%s: cmdID = %d\n", __func__, cmd->id);
|
|
|
|
switch (cmd->id) {
|
|
case VFE_CMD_ID_RESET:
|
|
msm_camio_vfe_blk_reset();
|
|
msm_camio_camif_pad_reg_reset_2();
|
|
vfe_reset();
|
|
break;
|
|
|
|
case VFE_CMD_ID_START:{
|
|
struct vfe_cmd_start start;
|
|
CHECKED_COPY_FROM_USER(&start);
|
|
|
|
/* msm_camio_camif_pad_reg_reset_2(); */
|
|
msm_camio_camif_pad_reg_reset();
|
|
vfe_start(&start);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_CAMIF_CONFIG:{
|
|
struct vfe_cmd_camif_config camif;
|
|
CHECKED_COPY_FROM_USER(&camif);
|
|
|
|
vfe_camif_config(&camif);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_BLACK_LEVEL_CONFIG:{
|
|
struct vfe_cmd_black_level_config bl;
|
|
CHECKED_COPY_FROM_USER(&bl);
|
|
|
|
vfe_black_level_config(&bl);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_ROLL_OFF_CONFIG:{
|
|
/* rolloff is too big to be on the stack */
|
|
struct vfe_cmd_roll_off_config *rolloff =
|
|
kmalloc(sizeof(struct vfe_cmd_roll_off_config),
|
|
GFP_KERNEL);
|
|
if (!rolloff) {
|
|
pr_err("%s: out of memory\n", __func__);
|
|
rc = -ENOMEM;
|
|
break;
|
|
}
|
|
/* Wrap CHECKED_COPY_FROM_USER() in a do-while(0) loop
|
|
* to make sure we free rolloff when copy_from_user()
|
|
* fails.
|
|
*/
|
|
do {
|
|
CHECKED_COPY_FROM_USER(rolloff);
|
|
vfe_roll_off_config(rolloff);
|
|
} while (0);
|
|
kfree(rolloff);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG:{
|
|
struct vfe_cmd_demux_channel_gain_config demuxc;
|
|
CHECKED_COPY_FROM_USER(&demuxc);
|
|
|
|
/* demux is always enabled. */
|
|
vfe_demux_channel_gain_config(&demuxc);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_DEMOSAIC_CONFIG:{
|
|
struct vfe_cmd_demosaic_config demosaic;
|
|
CHECKED_COPY_FROM_USER(&demosaic);
|
|
|
|
vfe_demosaic_config(&demosaic);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_FOV_CROP_CONFIG:
|
|
case VFE_CMD_ID_FOV_CROP_UPDATE:{
|
|
struct vfe_cmd_fov_crop_config fov;
|
|
CHECKED_COPY_FROM_USER(&fov);
|
|
|
|
vfe_fov_crop_config(&fov);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_MAIN_SCALER_CONFIG:
|
|
case VFE_CMD_ID_MAIN_SCALER_UPDATE:{
|
|
struct vfe_cmd_main_scaler_config mainds;
|
|
CHECKED_COPY_FROM_USER(&mainds);
|
|
|
|
vfe_main_scaler_config(&mainds);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_WHITE_BALANCE_CONFIG:
|
|
case VFE_CMD_ID_WHITE_BALANCE_UPDATE:{
|
|
struct vfe_cmd_white_balance_config wb;
|
|
CHECKED_COPY_FROM_USER(&wb);
|
|
|
|
vfe_white_balance_config(&wb);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_COLOR_CORRECTION_CONFIG:
|
|
case VFE_CMD_ID_COLOR_CORRECTION_UPDATE:{
|
|
struct vfe_cmd_color_correction_config cc;
|
|
CHECKED_COPY_FROM_USER(&cc);
|
|
|
|
vfe_color_correction_config(&cc);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_LA_CONFIG:{
|
|
struct vfe_cmd_la_config la;
|
|
CHECKED_COPY_FROM_USER(&la);
|
|
|
|
vfe_la_config(&la);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_RGB_GAMMA_CONFIG:{
|
|
struct vfe_cmd_rgb_gamma_config rgb;
|
|
CHECKED_COPY_FROM_USER(&rgb);
|
|
|
|
rc = vfe_rgb_gamma_config(&rgb);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_CHROMA_ENHAN_CONFIG:
|
|
case VFE_CMD_ID_CHROMA_ENHAN_UPDATE:{
|
|
struct vfe_cmd_chroma_enhan_config chrom;
|
|
CHECKED_COPY_FROM_USER(&chrom);
|
|
|
|
vfe_chroma_enhan_config(&chrom);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG:
|
|
case VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE:{
|
|
struct vfe_cmd_chroma_suppression_config chromsup;
|
|
CHECKED_COPY_FROM_USER(&chromsup);
|
|
|
|
vfe_chroma_sup_config(&chromsup);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_ASF_CONFIG:{
|
|
struct vfe_cmd_asf_config asf;
|
|
CHECKED_COPY_FROM_USER(&asf);
|
|
|
|
vfe_asf_config(&asf);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_SCALER2Y_CONFIG:
|
|
case VFE_CMD_ID_SCALER2Y_UPDATE:{
|
|
struct vfe_cmd_scaler2_config ds2y;
|
|
CHECKED_COPY_FROM_USER(&ds2y);
|
|
|
|
vfe_scaler2y_config(&ds2y);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_SCALER2CbCr_CONFIG:
|
|
case VFE_CMD_ID_SCALER2CbCr_UPDATE:{
|
|
struct vfe_cmd_scaler2_config ds2cbcr;
|
|
CHECKED_COPY_FROM_USER(&ds2cbcr);
|
|
|
|
vfe_scaler2cbcr_config(&ds2cbcr);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG:{
|
|
struct vfe_cmd_chroma_subsample_config sub;
|
|
CHECKED_COPY_FROM_USER(&sub);
|
|
|
|
vfe_chroma_subsample_config(&sub);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_FRAME_SKIP_CONFIG:{
|
|
struct vfe_cmd_frame_skip_config fskip;
|
|
CHECKED_COPY_FROM_USER(&fskip);
|
|
|
|
vfe_frame_skip_config(&fskip);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_OUTPUT_CLAMP_CONFIG:{
|
|
struct vfe_cmd_output_clamp_config clamp;
|
|
CHECKED_COPY_FROM_USER(&clamp);
|
|
|
|
vfe_output_clamp_config(&clamp);
|
|
}
|
|
break;
|
|
|
|
/* module update commands */
|
|
case VFE_CMD_ID_BLACK_LEVEL_UPDATE:{
|
|
struct vfe_cmd_black_level_config blk;
|
|
CHECKED_COPY_FROM_USER(&blk);
|
|
|
|
vfe_black_level_update(&blk);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE:{
|
|
struct vfe_cmd_demux_channel_gain_config dmu;
|
|
CHECKED_COPY_FROM_USER(&dmu);
|
|
|
|
vfe_demux_channel_gain_update(&dmu);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_DEMOSAIC_BPC_UPDATE:{
|
|
struct vfe_cmd_demosaic_bpc_update demo_bpc;
|
|
CHECKED_COPY_FROM_USER(&demo_bpc);
|
|
|
|
vfe_demosaic_bpc_update(&demo_bpc);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_DEMOSAIC_ABF_UPDATE:{
|
|
struct vfe_cmd_demosaic_abf_update demo_abf;
|
|
CHECKED_COPY_FROM_USER(&demo_abf);
|
|
|
|
vfe_demosaic_abf_update(&demo_abf);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_LA_UPDATE:{
|
|
struct vfe_cmd_la_config la;
|
|
CHECKED_COPY_FROM_USER(&la);
|
|
|
|
vfe_la_update(&la);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_RGB_GAMMA_UPDATE:{
|
|
struct vfe_cmd_rgb_gamma_config rgb;
|
|
CHECKED_COPY_FROM_USER(&rgb);
|
|
|
|
rc = vfe_rgb_gamma_update(&rgb);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_ASF_UPDATE:{
|
|
struct vfe_cmd_asf_update asf;
|
|
CHECKED_COPY_FROM_USER(&asf);
|
|
|
|
vfe_asf_update(&asf);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_FRAME_SKIP_UPDATE:{
|
|
struct vfe_cmd_frame_skip_update fskip;
|
|
CHECKED_COPY_FROM_USER(&fskip);
|
|
|
|
vfe_frame_skip_update(&fskip);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_CAMIF_FRAME_UPDATE:{
|
|
struct vfe_cmds_camif_frame fup;
|
|
CHECKED_COPY_FROM_USER(&fup);
|
|
|
|
vfe_camif_frame_update(&fup);
|
|
}
|
|
break;
|
|
|
|
/* stats update commands */
|
|
case VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE:{
|
|
struct vfe_cmd_stats_af_update afup;
|
|
CHECKED_COPY_FROM_USER(&afup);
|
|
|
|
vfe_stats_update_af(&afup);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_STATS_WB_EXP_UPDATE:{
|
|
struct vfe_cmd_stats_wb_exp_update wbexp;
|
|
CHECKED_COPY_FROM_USER(&wbexp);
|
|
|
|
vfe_stats_update_wb_exp(&wbexp);
|
|
}
|
|
break;
|
|
|
|
/* control of start, stop, update, etc... */
|
|
case VFE_CMD_ID_STOP:
|
|
vfe_stop();
|
|
break;
|
|
|
|
case VFE_CMD_ID_GET_HW_VERSION:
|
|
break;
|
|
|
|
/* stats */
|
|
case VFE_CMD_ID_STATS_SETTING:{
|
|
struct vfe_cmd_stats_setting stats;
|
|
CHECKED_COPY_FROM_USER(&stats);
|
|
|
|
vfe_stats_setting(&stats);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_STATS_AUTOFOCUS_START:{
|
|
struct vfe_cmd_stats_af_start af;
|
|
CHECKED_COPY_FROM_USER(&af);
|
|
|
|
vfe_stats_start_af(&af);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_STATS_AUTOFOCUS_STOP:
|
|
vfe_stats_af_stop();
|
|
break;
|
|
|
|
case VFE_CMD_ID_STATS_WB_EXP_START:{
|
|
struct vfe_cmd_stats_wb_exp_start awexp;
|
|
CHECKED_COPY_FROM_USER(&awexp);
|
|
|
|
vfe_stats_start_wb_exp(&awexp);
|
|
}
|
|
break;
|
|
|
|
case VFE_CMD_ID_STATS_WB_EXP_STOP:
|
|
vfe_stats_wb_exp_stop();
|
|
break;
|
|
|
|
case VFE_CMD_ID_ASYNC_TIMER_SETTING:
|
|
break;
|
|
|
|
case VFE_CMD_ID_UPDATE:
|
|
vfe_update();
|
|
break;
|
|
|
|
/* test gen */
|
|
case VFE_CMD_ID_TEST_GEN_START:
|
|
break;
|
|
|
|
/*
|
|
acknowledge from upper layer
|
|
these are not in general command.
|
|
|
|
case VFE_CMD_ID_OUTPUT1_ACK:
|
|
break;
|
|
case VFE_CMD_ID_OUTPUT2_ACK:
|
|
break;
|
|
case VFE_CMD_ID_EPOCH1_ACK:
|
|
break;
|
|
case VFE_CMD_ID_EPOCH2_ACK:
|
|
break;
|
|
case VFE_CMD_ID_STATS_AUTOFOCUS_ACK:
|
|
break;
|
|
case VFE_CMD_ID_STATS_WB_EXP_ACK:
|
|
break;
|
|
*/
|
|
|
|
default:
|
|
pr_err("%s: invalid cmd id %d\n", __func__, cmd->id);
|
|
rc = -EINVAL;
|
|
break;
|
|
} /* switch */
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data)
|
|
{
|
|
struct msm_pmem_region *regptr;
|
|
struct msm_vfe_command_8k vfecmd;
|
|
struct vfe_cmd_axi_output_config axio;
|
|
struct axidata *axid = data;
|
|
|
|
int rc = 0;
|
|
|
|
if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
|
|
cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
|
|
cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
|
|
if (copy_from_user(&vfecmd,
|
|
(void __user *)(cmd->value), sizeof(vfecmd))) {
|
|
ERR_COPY_FROM_USER();
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
|
|
|
|
switch (cmd->cmd_type) {
|
|
case CMD_GENERAL:
|
|
rc = vfe_proc_general(&vfecmd);
|
|
break;
|
|
|
|
case CMD_STATS_ENABLE:
|
|
case CMD_STATS_AXI_CFG: {
|
|
int i;
|
|
struct vfe_cmd_stats_setting scfg;
|
|
|
|
BUG_ON(!axid);
|
|
|
|
if (vfecmd.length != sizeof(scfg)) {
|
|
pr_err
|
|
("msm_camera: %s: cmd %d: user-space "\
|
|
"data size %d != kernel data size %d\n",
|
|
__func__,
|
|
cmd->cmd_type, vfecmd.length,
|
|
sizeof(scfg));
|
|
return -EIO;
|
|
}
|
|
|
|
if (copy_from_user(&scfg,
|
|
(void __user *)(vfecmd.value),
|
|
sizeof(scfg))) {
|
|
ERR_COPY_FROM_USER();
|
|
return -EFAULT;
|
|
}
|
|
|
|
regptr = axid->region;
|
|
if (axid->bufnum1 > 0) {
|
|
for (i = 0; i < axid->bufnum1; i++) {
|
|
scfg.awbBuffer[i] =
|
|
(uint32_t) (regptr->paddr);
|
|
regptr++;
|
|
}
|
|
}
|
|
|
|
if (axid->bufnum2 > 0) {
|
|
for (i = 0; i < axid->bufnum2; i++) {
|
|
scfg.afBuffer[i] =
|
|
(uint32_t) (regptr->paddr);
|
|
regptr++;
|
|
}
|
|
}
|
|
|
|
vfe_stats_setting(&scfg);
|
|
}
|
|
break;
|
|
|
|
case CMD_STATS_AF_AXI_CFG:
|
|
break;
|
|
|
|
case CMD_FRAME_BUF_RELEASE: {
|
|
/* preview buffer release */
|
|
struct msm_frame *b;
|
|
unsigned long p;
|
|
struct vfe_cmd_output_ack fack;
|
|
|
|
BUG_ON(!data);
|
|
|
|
b = (struct msm_frame *)(cmd->value);
|
|
p = *(unsigned long *)data;
|
|
|
|
#ifndef CONFIG_720P_CAMERA
|
|
b->path = MSM_FRAME_ENC;
|
|
|
|
fack.ybufaddr[0] = (uint32_t) (p + b->y_off);
|
|
|
|
fack.chromabufaddr[0] = (uint32_t) (p + b->cbcr_off);
|
|
|
|
if (b->path == MSM_FRAME_PREV_1)
|
|
vfe_output1_ack(&fack);
|
|
|
|
if (b->path == MSM_FRAME_ENC ||
|
|
b->path == MSM_FRAME_PREV_2)
|
|
vfe_output2_ack(&fack);
|
|
#else
|
|
|
|
fack.ybufaddr[0] = (uint32_t) (p + b->y_off);
|
|
|
|
fack.chromabufaddr[0] = (uint32_t) (p + b->cbcr_off);
|
|
|
|
if (b->path == OUTPUT_TYPE_P)
|
|
vfe_output_p_ack(&fack);
|
|
|
|
if ((b->path == OUTPUT_TYPE_V)
|
|
|| (b->path == OUTPUT_TYPE_S))
|
|
vfe_output_v_ack(&fack);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case CMD_SNAP_BUF_RELEASE:
|
|
break;
|
|
|
|
case CMD_STATS_BUF_RELEASE: {
|
|
struct vfe_cmd_stats_wb_exp_ack sack;
|
|
|
|
BUG_ON(!data);
|
|
|
|
sack.nextWbExpOutputBufferAddr = *(uint32_t *) data;
|
|
vfe_stats_wb_exp_ack(&sack);
|
|
}
|
|
break;
|
|
|
|
case CMD_STATS_AF_BUF_RELEASE: {
|
|
struct vfe_cmd_stats_af_ack ack;
|
|
|
|
BUG_ON(!data);
|
|
|
|
ack.nextAFOutputBufferAddr = *(uint32_t *) data;
|
|
vfe_stats_af_ack(&ack);
|
|
}
|
|
break;
|
|
#ifndef CONFIG_720P_CAMERA
|
|
case CMD_AXI_CFG_OUT1: {
|
|
|
|
BUG_ON(!axid);
|
|
|
|
if (copy_from_user(&axio, (void __user *)(vfecmd.value),
|
|
sizeof(axio))) {
|
|
ERR_COPY_FROM_USER();
|
|
return -EFAULT;
|
|
}
|
|
|
|
vfe_config_axi(OUTPUT_1, axid, &axio);
|
|
vfe_axi_output_config(&axio);
|
|
}
|
|
break;
|
|
|
|
case CMD_AXI_CFG_OUT2:
|
|
case CMD_RAW_PICT_AXI_CFG: {
|
|
|
|
BUG_ON(!axid);
|
|
|
|
if (copy_from_user(&axio, (void __user *)(vfecmd.value),
|
|
sizeof(axio))) {
|
|
ERR_COPY_FROM_USER();
|
|
return -EFAULT;
|
|
}
|
|
|
|
vfe_config_axi(OUTPUT_2, axid, &axio);
|
|
|
|
axio.outputDataSize = 0;
|
|
vfe_axi_output_config(&axio);
|
|
}
|
|
break;
|
|
|
|
case CMD_AXI_CFG_SNAP_O1_AND_O2:{
|
|
|
|
BUG_ON(!axid);
|
|
|
|
if (copy_from_user(&axio, (void __user *)(vfecmd.value),
|
|
sizeof(axio))) {
|
|
ERR_COPY_FROM_USER();
|
|
return -EFAULT;
|
|
}
|
|
|
|
vfe_config_axi(OUTPUT_1_AND_2, axid, &axio);
|
|
vfe_axi_output_config(&axio);
|
|
}
|
|
break;
|
|
#else
|
|
case CMD_AXI_CFG_PREVIEW:
|
|
case CMD_RAW_PICT_AXI_CFG: {
|
|
|
|
BUG_ON(!axid);
|
|
|
|
if (copy_from_user(&axio, (void __user *)(vfecmd.value),
|
|
sizeof(axio))) {
|
|
pr_err("%s %d: copy_from_user failed\n",
|
|
__func__, __LINE__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
vfe_config_axi(OUTPUT_2, axid, &axio);
|
|
|
|
axio.outputDataSize = 0;
|
|
vfe_axi_output_config(&axio);
|
|
}
|
|
break;
|
|
|
|
case CMD_AXI_CFG_SNAP: {
|
|
|
|
BUG_ON(!axid);
|
|
|
|
if (copy_from_user(&axio, (void __user *)(vfecmd.value),
|
|
sizeof(axio))) {
|
|
pr_err("%s %d: copy_from_user failed\n",
|
|
__func__, __LINE__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
vfe_config_axi(OUTPUT_1_AND_2, axid, &axio);
|
|
vfe_axi_output_config(&axio);
|
|
}
|
|
break;
|
|
|
|
case CMD_AXI_CFG_VIDEO: {
|
|
BUG_ON(!axid);
|
|
|
|
if (copy_from_user(&axio, (void __user *)(vfecmd.value),
|
|
sizeof(axio))) {
|
|
pr_err("%s %d: copy_from_user failed\n",
|
|
__func__, __LINE__);
|
|
return -EFAULT;
|
|
}
|
|
vfe_config_axi(OUTPUT_1_AND_3, axid, &axio);
|
|
axio.outputDataSize = 0;
|
|
vfe_axi_output_config(&axio);
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
} /* switch */
|
|
|
|
return rc;
|
|
}
|
|
|
|
void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
|
|
{
|
|
fptr->vfe_init = vfe_init;
|
|
fptr->vfe_enable = vfe_enable;
|
|
fptr->vfe_config = vfe_config;
|
|
fptr->vfe_disable = vfe_disable;
|
|
fptr->vfe_release = vfe_release;
|
|
vfe_syncdata = data;
|
|
}
|