MTK camera启动流程

目录

一、Camera 框架介绍:

二、Camera 启动流程

三、kernel 启动流程

1、set clock 设置时钟

2、set driver

3、上电相关

四、总结

1、ID读取不到,I2C不通

2、Camera 启动时间过长

3、preview 阶段耗时

4、低电流、功耗相关问题


一、Camera 框架介绍:

Camera的框架分为Kernel部分和hal部分,其中kernel部分主要有两块:

  • image sensor driver,负责具体型号的sensorid检测,上电,以及在previewcapture初始化3A等等功能设定时的寄存器配置;

  • isp driver,通过DMAsensor数据流上传;

HAL层部分主要有三部分组成:

  • imageio,主要负责数据buffer上传的pipe

  • drv,包含imgsensorisphal层控制;

  • feature io,包含各种3A等性能配置;

这篇内容主要介绍开机过程中search sensor以及上电流程等内容。

二、Camera 启动流程

1、CameraService是在开机时启动的,启动后进行searchSensor的操作,会search系统有多少camera,开机时的search操作,只进行camera支持数量的遍历,以及sensor ID的读取操作,如下是hal部分的ASTAH绘制调用流程图,对应的接口的文件路径:

  • HalSensorList:
    vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.enumList.cpp
    vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.cpp

  • SeninfDrv:
    vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/mt6765/seninf_drv.cpp

  • SensorDrv:
    vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/imgsensor_drv.cpp

(1) 这里先看enumerateSensor_Locked完成的工作,直接看代码:

MUINT HalSensorList::searchSensors()

{

    Mutex::Autolock _l(mEnumSensorMutex);

    MY_LOGD("searchSensors");

    return enumerateSensor_Locked();

}

MUINT HalSensorList::enumerateSensor_Locked()

{

    SensorDrv *const pSensorDrv = SensorDrv::get();

    SeninfDrv *const pSeninfDrv = SeninfDrv::createInstance();

    //初始化seninf,配置ISP相关内容

    pSeninfDrv->init();

    //将所有的clk全部打开

    pSeninfDrv->setAllMclkOnOff(ISP_DRIVING_8MA, TRUE);

    pSensorDrv->init();

    for (MUINT i = IMGSENSOR_SENSOR_IDX_MIN_NUM; i <= max_index_of_camera; i++) {

        if((ret = pSensorDrv->searchSensor((IMGSENSOR_SENSOR_IDX)i)) == SENSOR_NO_ERROR){

            //query sensorinfo

            querySensorDrvInfo((IMGSENSOR_SENSOR_IDX)i);

            //fill in metadata

            buildSensorMetadata((IMGSENSOR_SENSOR_IDX)i);

            pSensorInfo = pSensorDrv->getSensorInfo((IMGSENSOR_SENSOR_IDX)i);

            addAndInitSensorEnumInfo_Locked(

                (IMGSENSOR_SENSOR_IDX)i,

                mapToSensorType(pSensorInfo->GetType()),

            pSensorInfo->getDrvMacroName());

        }

    }

}

(2) 下面主要看下searchSensor的流程,这里有去获取sensorList的内容:

MINT32 ImgSensorDrv::searchSensor(IMGSENSOR_SENSOR_IDX sensorIdx)

{

    GetSensorInitFuncList(&pSensorInitFunc);

    featureControl(sensorIdx, SENSOR_FEATURE_SET_DRIVER, (MUINT8 *)&idx, &featureParaLen);

    NSFeature::SensorInfoBase* pSensorInfo = pSensorInitFunc[idx].pSensorInfo;

}

GetSensorInitFuncList是获取到配置的sensorList的内容,此sensorList需要与kernel层配置的一致,不一致的话在打开camera时会出现异常:
文件位置:
vendor/mediatek/proprietary/custom/mt6765/hal/imgsensor_src/sensorlist.cpp

MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] =

{

    #if defined(IMX486_MIPI_RAW)

        RAW_INFO(IMX486_SENSOR_ID, SENSOR_DRVNAME_IMX486_MIPI_RAW, CAM_CALGetCalData),

    #endif

//.....

}

UINT32 GetSensorInitFuncList(MSDK_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)

{

    if (NULL == ppSensorList) {

        ALOGE("ERROR: NULL pSensorList\n");

        return MHAL_UNKNOWN_ERROR;

    }

    *ppSensorList = &SensorList[0];

    return MHAL_NO_ERROR;

}

对应的MSDK_SENSOR_INIT_FUNCTION_STRUCT的结构体如下:

typedef struct

{

    MUINT32 sensorType;

    MUINT32 SensorId;

    MUINT8 drvname[32];

    NSFeature::SensorInfoBase* pSensorInfo;

    MUINT32 (*getCameraIndexMgr)(CAMERA_DATA_TYPE_ENUM CameraDataType, MVOID *pDataBuf,                 MUINT32 size);

    MUINT32 (*getCameraCalData)(UINT32* pGetSensorCalData);

} MSDK_SENSOR_INIT_FUNCTION_STRUCT, *PMSDK_SENSOR_INIT_FUNCTION_STRUCT;

(3) featureControlsetDriver流程:
文件位置:
vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/imgsensor_drv.cpp

MINT32 ImgSensorDrv::featureControl(

    IMGSENSOR_SENSOR_IDX sensorIdx,

    ACDK_SENSOR_FEATURE_ENUM FeatureId,

    MUINT8 *pFeaturePara,

    MUINT32 *pFeatureParaLen

)

{

    //结构ACDK_SENSOR_FEATURECONTROL_STRUCT和kernel中一致

    featureCtrl.InvokeCamera = sensorIdx;

    featureCtrl.FeatureId = FeatureId;//SENSOR_FEATURE_SET_DRIVER

    featureCtrl.pFeaturePara = pFeaturePara;

    featureCtrl.pFeatureParaLen = pFeatureParaLen;

    if (ioctl(m_fdSensor, KDIMGSENSORIOC_X_FEATURECONCTROL , &featureCtrl) < 0) {

        LOG_ERR("[featureControl] Err-ctrlCode (%s)", strerror(errno));

        return -errno;

    }

    return SENSOR_NO_ERROR;

}

三、kernel 启动流程

先来看整体的框架图如下:

  

1、set clock 设置时钟

static long imgsensor_ioctl(

    struct file *a_pstFile,

    unsigned int a_u4Command,

    unsigned long a_u4Param)

{

    case KDIMGSENSORIOC_X_SET_MCLK_PLL:

        i4RetValue = imgsensor_clk_set(

            &pgimgsensor->clk,

            (struct ACDK_SENSOR_MCLK_STRUCT *)pBuff);

        break;

    //......

}

int imgsensor_clk_set(

struct IMGSENSOR_CLK *pclk, struct ACDK_SENSOR_MCLK_STRUCT *pmclk)

{

    if (pmclk->on) {

        clk_prepare_enable(pclk->imgsensor_ccf[mclk_index])

        ret = clk_set_parent(

        pclk->imgsensor_ccf[pmclk->TG],

        pclk->imgsensor_ccf[mclk_index]);

    } else {

        clk_disable_unprepare(pclk->imgsensor_ccf[mclk_index]);

    }

}

2、set driver

static long imgsensor_ioctl(

    struct file *a_pstFile,

    unsigned int a_u4Command,

    unsigned long a_u4Param)

{

    case KDIMGSENSORIOC_X_FEATURECONCTROL:

    i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);

    break;

    //......

}

static inline int adopt_CAMERA_HW_FeatureControl(void *pBuf)

{

    /* copy from user */

    switch (pFeatureCtrl->FeatureId) {

        case SENSOR_FEATURE_SET_DRIVER:

        {

            MINT32 drv_idx;

            psensor->inst.sensor_idx = pFeatureCtrl->InvokeCamera;

            drv_idx = imgsensor_set_driver(psensor);

            memcpy(pFeaturePara, &drv_idx, FeatureParaLen);

            break;

        }

    }

}

遍历CONFIG_CUSTOM_KERNEL_IMGSENSOR的内容,然后看sensorList是否对应,并获取对应的下标,调用imgsensor_check_is_alive进行上下电并读取ID 的操作:

struct IMGSENSOR_INIT_FUNC_LIST kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR] = {

    #if defined(XXXXXX_MIPI_RAW)

        {XXXXXX_SENSOR_ID,

            SENSOR_DRVNAME_XXXXXX_MIPI_RAW,

            XXXXXX_MIPI_RAW_SensorInit},

    #endif

//......

}

int imgsensor_set_driver(struct IMGSENSOR_SENSOR *psensor)

{

    struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst;

    struct IMGSENSOR_INIT_FUNC_LIST *pSensorList = kdSensorList;

    //获取config的size

    char *sensor_configs = STRINGIZE(CONFIG_CUSTOM_KERNEL_IMGSENSOR);

    imgsensor_i2c_init(&psensor_inst->i2c_cfg,

    imgsensor_custom_config[psensor->inst.sensor_idx].i2c_dev);

    memcpy(psensor_list_config, sensor_configs+1, strlen(sensor_configs)-2);

    //对应config字符串进行按空格进行拆解

    driver_name = strsep(&psensor_list_config, " \0");

    while (driver_name != NULL) {

        for (j = 0; j < MAX_NUM_OF_SUPPORT_SENSOR; j++) {

            //判断对应的init函数是否存在

            if (pSensorList[j].init == NULL)

                break;

            else if (!strcmp(driver_name, pSensorList[j].name)) {

                //如果在config中和sensorlist中同时有定义进行赋值

                orderedSearchList[i++] = j;

                break;

            }

        }

        driver_name = strsep(&psensor_list_config, " \0");

    }

    for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {

        //上面获取到的sensorlist的下标

        drv_idx = orderedSearchList[i];

        if (pSensorList[drv_idx].init) {

            //调用对应驱动的init函数

            pSensorList[drv_idx].init(&psensor->pfunc);

            if (psensor->pfunc) {

                psensor_inst->psensor_name =

                    (char *)pSensorList[drv_idx].name;

                //到这里是重点,进行上电读取ID的操作

                if (!imgsensor_check_is_alive(psensor)) {

                    ret = drv_idx;

                }

            }

        }

    }

}

下面看对应的上下电以及读取ID的操作:

static inline int imgsensor_check_is_alive(struct IMGSENSOR_SENSOR *psensor)

{

    struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst;

    //上电

    err = imgsensor_hw_power(&pgimgsensor->hw,

        psensor,

        psensor_inst->psensor_name,

        IMGSENSOR_HW_POWER_STATUS_ON);

    //读取ID

    imgsensor_sensor_feature_control(

        psensor,

        SENSOR_FEATURE_CHECK_SENSOR_ID,

        (MUINT8 *)&sensorID,

        &retLen);

    if (sensorID == 0 || sensorID == 0xFFFFFFFF) {

        pr_info("Fail to get sensor ID %x\n", sensorID);
    
        err = ERROR_SENSOR_CONNECT_FAIL;

    } else {

        pr_info(" Sensor found ID = 0x%x\n", sensorID);

        err = ERROR_NONE;

    }

    //下电

    imgsensor_hw_power(&pgimgsensor->hw,

        psensor,

        psensor_inst->psensor_name,

        IMGSENSOR_HW_POWER_STATUS_OFF);

    return err ? -EIO:err;

}

3、上电相关

上电时序配置:

struct IMGSENSOR_HW_POWER_INFO {

    enum IMGSENSOR_HW_PIN pin;

    enum IMGSENSOR_HW_PIN_STATE pin_state_on;

    u32 pin_on_delay;

    enum IMGSENSOR_HW_PIN_STATE pin_state_off;

    u32 pin_off_delay;

};

struct IMGSENSOR_HW_POWER_SEQ sensor_power_sequence[] = {

    //……

    #if defined(XXXXXX_MIPI_RAW)

    {

        SENSOR_DRVNAME_XXXXXX_MIPI_RAW,

        {

            {RST, Vol_Low, 0},

            {DVDD, Vol_1100, 1},

            {AVDD, Vol_2800, 1},

            {DOVDD, Vol_1800, 1},

            {RST, Vol_High, 1},

            {SensorMCLK, Vol_High, 0},

        },

    },

    #endif

}

对应的控制的流程如下:

static enum IMGSENSOR_RETURN imgsensor_hw_power_sequence(

    struct IMGSENSOR_HW *phw,

    enum IMGSENSOR_SENSOR_IDX sensor_idx,

    enum IMGSENSOR_HW_POWER_STATUS pwr_status,

    struct IMGSENSOR_HW_POWER_SEQ *ppower_sequence,

    char *pcurr_idx)

{

    ppwr_info = ppwr_seq->pwr_info;

    // 上电

    while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE &&

        ppwr_info < ppwr_seq->pwr_info + IMGSENSOR_HW_POWER_INFO_MAX) {

            if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON &&

                ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) {

                pdev = phw->pdev[psensor_pwr->id[ppwr_info->pin]];

                if (pdev->set != NULL)

                    //调用GPIO或者regulator的set 电压操作,这里的pdev在imgsensor_probe中已经设置

                    pdev->set(

                        pdev->pinstance,

                        sensor_idx,

                        ppwr_info->pin,

                        ppwr_info->pin_state_on);

                        mdelay(ppwr_info->pin_on_delay);

            }

            // 从上到下依次上电

            ppwr_info++;

            pin_cnt++;

    }

    // 下电操作

    if (pwr_status == IMGSENSOR_HW_POWER_STATUS_OFF) {

        while (pin_cnt) {

            //从下到上依次下电

            ppwr_info--;

            pin_cnt--;

            if (ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) {

                pdev =

                    phw->pdev[psensor_pwr->id[ppwr_info->pin]];

                mdelay(ppwr_info->pin_on_delay);

                if (pdev->set != NULL)

                pdev->set(

                    pdev->pinstance,

                    sensor_idx,

                    ppwr_info->pin,

                    ppwr_info->pin_state_off);

            }

        }

    }

    /* wait for power stable */

    if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON)

    mdelay(5);

    return IMGSENSOR_RETURN_SUCCESS;

}

四、总结

通过上面的代码流程,可以知道上开机时,camera模块先会将所有的MCLK打开,然后对依次对对应的sensor进行上电,读取ID(判断I2C是否正常通讯)。这部分调试过程中遇到的问题总结如下:

1、ID读取不到,I2C不通

  • 检查上电时序,3项电压(AVDD/DVDD/IOVDD)是否正确;

  • I2C地址及通道设置是否正确;

  • 检查cfg_setting_imgsensor.cppMCLKHW链接配置是否正确;

2、Camera 启动时间过长

  • 检查Sensor上电时序要求的延时,是否有偏长的情况;

  • 去掉多余的I2C地址,因为大部分驱动会多添加一些地址;

  • OTP的加载调整到每次开机时第一次打开加载,之后不加载;

  • sensorInit如果时间过长,可以调节I2C speed(400->1000)

3、preview 阶段耗时

  • 检查streamOn/Off的耗时;

  • preview_init是否有较长时间的耗时

  • 以及延时操作使用mdelay代替msleep

  • pre_delay_frame/cap_delay_frame丢帧操作是否合适;

4、低电流、功耗相关问题

  • 检查电压是否都有下电成功,防止漏电;

  • 对于共pinsensor,在操作时是否有做好workaround

  • I2C寄存器单个读写,调整为连续读写的方式也有一定优化;

  • sensorPIN是否有被其他模块占用,异常操作的行为;

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值