SA8450 camera 源码分析

目录

代码路径:/apps/qnx_ap/AMSS/multimedia/camera_safe/qcd

Initialize the IFE and CSI Phy devices

 初始化IFE 

初始化 IFE CSID VFE 的结构体

获取IFE CSID base addr 的vaddr

VFEDriver_Init

RegisterISTCallback

HwMgr_CSIPHYOpen


代码路径:/apps/qnx_ap/AMSS/multimedia/camera_safe/qcd

Initialize the IFE and CSI Phy devices

 Initialization function for the Camera HW. During initialization, the HW Topology Manager will
 * query information about the current configuration through the Camera Config Handler to be used
 * for initializing its internal context. It will also open each of the CSI Phy and IFE devices
 * used the system through the HW Manager block.
 *
 * @return
 * Error code defined in QCDStatus_e
 **************************************************************************************************/
QCDStatus_e HTM_Init (
    void)
{
    QCDStatus_e status = QCD_ERROR_GENERAL_FAILURE;
    CameraConfigGetInfo_t configInfo = {0};
    CameraConfigGetInfo_t mappingInfo = {0};

    QCD_LOG(LOG_HTM,
            LOG_LEVEL_HIGH,
            "HTM Init Starting");

    configInfo.infoType = CAMERA_CONFIG_INFO_ALL;
    mappingInfo.infoType = CAMERA_CONFIG_INFO_INPUT_MAPPINGS;

    if (TRUE == g_htmInitialized)
    {
        QCD_LOG(LOG_HTM,
                LOG_LEVEL_ERROR,
                "HTM already initialized");

        status = QCD_ERROR_INVALID_STATE;
    }
    else if((QCD_SUCCESS != CC_GetInfo(&configInfo))
            || (NULL == configInfo.info.pConfigInfo))
    {
        QCD_LOG(LOG_HTM,
                LOG_LEVEL_FATAL,
                "Unable to get config from CC");

        status = QCD_ERROR_NOT_FOUND;
    }
    else if((QCD_SUCCESS != CC_GetInfo(&mappingInfo))
            || (NULL == mappingInfo.info.pInpuMappings))
    {
        QCD_LOG(LOG_HTM,
                LOG_LEVEL_FATAL,
                "Unable to get mappings from CC");

        status = QCD_ERROR_NOT_FOUND;
    }
    /*
     * 1. Initialize the IFE and CSI Phy devices
     */
    else
    {
        uint32_t csiIdx = 0;
        QCDStatus_e hwInitStatus = QCD_SUCCESS;

        g_pBoardInfo = &configInfo.info.pConfigInfo->boardConfig;
        g_pCsiDevicesList = &configInfo.info.pConfigInfo->csiDevices;
        g_pInputMappingList = mappingInfo.info.pInpuMappings;


        for (csiIdx = 0; csiIdx < g_pCsiDevicesList->numCsiDevs; csiIdx++)
        {
            uint64_t ifeBitmap = g_pCsiDevicesList->csiDevConfig[csiIdx].ifeMap;
            uint32_t ifeIdx = 0;

            for (ifeIdx = 0; ifeIdx < g_pCsiDevicesList->csiDevConfig[csiIdx].numIfeMap; ifeIdx++)
            {
                uint32_t nextIfeId = GET_IFE_ID_FROM_BITMAP(ifeBitmap);

                QCD_LOG(LOG_HTM,
                        LOG_LEVEL_MEDIUM,
                        "Opening IFE ID %u",
                        nextIfeId);

                hwInitStatus = HwMgr_IFEOpen(nextIfeId);

                if (QCD_SUCCESS != hwInitStatus)
                {
                    QCD_LOG(LOG_HTM,
                            LOG_LEVEL_FATAL,
                            "IFE ID %u open failed",
                            nextIfeId);
                    break;
                }
                else
                {
                    QCD_LOG(LOG_HTM,
                            LOG_LEVEL_MEDIUM,
                            "IFE ID %u open success",
                            nextIfeId);
                    // Set a global context to check whether IFE device was opened successfully.
                    g_ifeDeviceOpened[nextIfeId] = TRUE;
                }
                ifeBitmap = ifeBitmap >> IFE_ID_SIZE_IN_BITS;
            }

            if (QCD_SUCCESS != hwInitStatus)
            {
                // No use intializing CSI PHY if IFE init has failed
                break;
            }

            QCD_LOG(LOG_HTM,
                    LOG_LEVEL_MEDIUM,
                    "Opening CSI Phy Device %u",
                    g_pCsiDevicesList->csiDevConfig[csiIdx].csiId);

            hwInitStatus = HwMgr_CSIPHYOpen(g_pCsiDevicesList->csiDevConfig[csiIdx].csiId);
            if (QCD_SUCCESS != hwInitStatus)
            {
                QCD_LOG(LOG_HTM,
                        LOG_LEVEL_FATAL,
                        "CSIPhy ID %u open failed",
                        g_pCsiDevicesList->csiDevConfig[csiIdx].csiId);
                // Do not conitnue with the loop if a CSI open fails
                break;
            }
            else
            {
                // Set a global context to check whether CSI device was opened successfully.
                g_csiDeviceOpened[g_pCsiDevicesList->csiDevConfig[csiIdx].csiId] = TRUE;
            }
        }
        /*
         * 2. Get input mappings
         *
         */
        if (QCD_SUCCESS == hwInitStatus)
        {
            QCD_LOG(LOG_HTM,
                    LOG_LEVEL_MEDIUM,
                    "Initializing input mappings");

            uint32_t inputIdx = 0; //Index into a list of input IDs
            uint32_t pathIdx = 0;  //Index into a list of paths for that input ID
            uint32_t chanIndex = 0; //Index into the list of channels for each input ID

            /* Input mappings are structured in a way where one input ID can reserve a number
             * of RDIs based on the number of channels that input has. When a client opens
             * an input, the next available RDI defined in the mapping list is reserved for
             * it.
             */

            for (inputIdx = 0; inputIdx < g_pInputMappingList->numInputs; inputIdx++)
            {
                for (pathIdx = 0; pathIdx < g_pInputMappingList->inputs[inputIdx].numReservedPaths;
                        pathIdx++)
                {
                    for(chanIndex = 0;
                            chanIndex <
                            g_pInputMappingList->inputs[inputIdx].reservedPaths[pathIdx].numPaths;
                            chanIndex++)
                    {
                        CameraInputPath_t const *pInputPath =
                                &g_pInputMappingList->inputs[inputIdx].reservedPaths[pathIdx].
                                inputPath[chanIndex];

                        IfeLiteMappingInfo_t *pMappingInfo =
                                &g_ifeMappingInfo[pInputPath->ifeId];

                        /*Not checking these pointers for NULL here, trusting the ASIL B
                         * block Camera Config on this
                         */

                        QCD_LOG(LOG_HTM,
                                LOG_LEVEL_MEDIUM,
                                "Initializing inputIdx %u DevId %u PortId %u Path Idx %u QCarCam"\
                                "id %u chanIndex %u ife id %u rdi %u csiId %u channel id %u",
                                inputIdx,
                                g_pInputMappingList->inputs[inputIdx].inputDevId,
                                g_pInputMappingList->inputs[inputIdx].inputDevPortId,
                                pathIdx,
                                g_pInputMappingList->inputs[inputIdx].qCarCamId,
                                chanIndex,
                                pInputPath->ifeId,
                                pInputPath->rdiId,
                                pInputPath->csiId,
                                pInputPath->channelId);

                        if (NULL != pMappingInfo->rdiInfo[pInputPath->rdiId].inputPath)
                        {
                            /*
                             * If we are here, someone entered wrong configurations because
                             * we are assuming only one path per RDI defined
                             */
                            QCD_LOG(LOG_HTM,
                                    LOG_LEVEL_CRIT,
                                    "Duplicate RDI %u input path found check camera configs",
                                    pInputPath->rdiId);

                            hwInitStatus = QCD_ERROR_NOT_PERMITTED;
                            break;
                        }

                        QCD_LOG(LOG_HTM,
                                LOG_LEVEL_HIGH,
                                "rdiInfo[%u].qCarCamId = %u",
                                pInputPath->rdiId,
                                g_pInputMappingList->inputs[inputIdx].qCarCamId);

                        pMappingInfo->rdiInfo[pInputPath->rdiId].inputPath = pInputPath;
                        pMappingInfo->rdiInfo[pInputPath->rdiId].qCarCamId =
                                g_pInputMappingList->inputs[inputIdx].qCarCamId;
                        pMappingInfo->rdiInfo[pInputPath->rdiId].state = RDI_STATUS_READY;
                    }
                }
                if (QCD_SUCCESS != hwInitStatus)
                {
                    //Don't continue if a mapping fails
                    break;
                }
            }

        }

        if (QCD_SUCCESS == hwInitStatus)
        {
            if (QCD_SUCCESS != OSAL_CriticalSectionCreate(&g_mutIfeMap))
            {
                QCD_LOG(LOG_HTM,
                        LOG_LEVEL_FATAL,
                        "Failed to initialize mutex for mappings");

                hwInitStatus = QCD_ERROR_GENERAL_FAILURE;
            }
        }

        status = hwInitStatus;
    }

    if(QCD_SUCCESS != status)
    {
        (void)HTM_DeInit();
    }
    else
    {
        g_htmInitialized = TRUE;
    }

    QCD_LOG(LOG_HTM,
            LOG_LEVEL_MEDIUM,
            "HTM Init Done");

    return status;
}

 //获取boardconfig信息

/**********************************************************************************************//**
@brief
    Returns a pointer to the camera configuration structure, based on the requested info type.

@param pInfo
    [In/Out] Contains the type of info requested and the pointer to the associated structure.

@return
    Status as defined in QCDStatus_e
**************************************************************************************************/
QCDStatus_e CC_GetInfo(
    CameraConfigGetInfo_t* pInfo)
{
    QCDStatus_e result = QCD_ERROR_GENERAL_FAILURE;
    uint32_t socIdx = 0U;
    CameraConfigGlobalInfo_t const *pSetupConfig = NULL;

    if (NULL == pInfo)
    {
        result = QCD_ERROR_BAD_PARAM;
        QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_ERROR, "NULL Input param");
    }
    else if (NULL != (pSetupConfig = CC_GetGlobalConfig()))
    {    //获取boardconfig信息
        // Retrieve Configuration
        switch(pInfo->infoType)
        {  
           //初始化时configInfo.infoType = CAMERA_CONFIG_INFO_ALL;
            case CAMERA_CONFIG_INFO_ALL:
            {
                for (socIdx = 0U; socIdx < pSetupConfig->numSocConfig; socIdx++)
                {
                    if (pSetupConfig->socId == pSetupConfig->pConfigInfo[socIdx]->socId)
                    {
                        pInfo->info.pConfigInfo =
                                    pSetupConfig->pConfigInfo[socIdx];
                        result = QCD_SUCCESS;
                        break;
                    }
                }

                break;
            }
            case CAMERA_CONFIG_INFO_BOARD:
            {
                for (socIdx = 0U; socIdx < pSetupConfig->numSocConfig; socIdx++)
                {
                    if (pSetupConfig->socId == pSetupConfig->pConfigInfo[socIdx]->socId)
                    {
                        pInfo->info.pBoardInfo =
                                    &pSetupConfig->pConfigInfo[socIdx]->boardConfig;
                        result = QCD_SUCCESS;
                        break;
                    }
                }
                break;
            }
            case CAMERA_CONFIG_INFO_CSI_DEVICES:
            {
                for (socIdx = 0U; socIdx < pSetupConfig->numSocConfig; socIdx++)
                {
                    if (pSetupConfig->socId == pSetupConfig->pConfigInfo[socIdx]->socId)
                    {
                        pInfo->info.pCsiDevices =
                                    &pSetupConfig->pConfigInfo[socIdx]->csiDevices;
                        result = QCD_SUCCESS;
                        break;
                    }
                }
                break;
            }
            case CAMERA_CONFIG_INFO_INPUT_MAPPINGS:
            {

                for (socIdx = 0U; socIdx < pSetupConfig->numSocConfig; socIdx++)
                {
                    if (pSetupConfig->socId == pSetupConfig->pConfigInfo[socIdx]->socId)
                    {
                        pInfo->info.pInpuMappings =
                                    &pSetupConfig->pConfigInfo[socIdx]->inputMappings;
                        result = QCD_SUCCESS;
                        break;
                    }
                }
                break;
            }
            default:
            {
                result = QCD_ERROR_NOT_SUPPORTED;
                QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_ERROR, "Invalid Info type %d",pInfo->infoType);
                break;
            }
        }
    }
    else
    {
        //If we are here there is a memory corruption for sure
        QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_ERROR, "Null pointer to CC global configs");
    }

    return result;
}

/**********************************************************************************************//**
@brief
    Getter function for camera configs

@return
    Pointer to the camera config function
**************************************************************************************************/
CameraConfigGlobalInfo_t const *CC_GetGlobalConfig(void)
{
    return pSetupConfig;
}

 解析xml配置获取boardconfig信息

/**********************************************************************************************//**
@brief
    Initialize Camera Config reader.
    If FEAT_ENABLE_XML_CONFIGS is enabled:
        The function will first try to call the xml config
        parser to see if valid qcd_config xml file is present
        If the file is present:
            If the file is invalid, an error will be returned
            Otherwise, the xml configs will be used for camera configurations
        If the file is not present:
            The function will continue reading the hard-coded camera configs for this chip ID

@return
    Error code defined in QCDStatus_e
**************************************************************************************************/
QCDStatus_e CCR_Init(void)
{
    QCDStatus_e result = QCD_ERROR_GENERAL_FAILURE;
    PlatformChipId_e chipId = CHIP_ID_INVALID;

    pSetupConfig->pConfigInfo[0] = &gSoc0Config;
    pSetupConfig->pConfigInfo[1] = &gSoc1Config;

    /* If the XML feature is enabled, the reader will  first try to read camera configs from
     * the xml:
     *  If the XML config file is not present
     *      Continue with reading the hard-coded camera configs
     *  If the XML config file is present
     *      If the XML is invalid or there is an error reading the xml
     *          Report and error and return failure to initializer
     *  If the feature is disabled, continue reading the hard-coded configs
     */
#ifdef FEAT_ENABLE_XML_CONFIGS
    result = CC_ParseXMLFile(&gSetupConfig);
    if ((QCD_SUCCESS != result) && (QCD_ERROR_FILE_NOT_FOUND != result))
    {
        CC_ERR("ParseXMLFile failed with result 0x%x",
               result);
    }
    else if (QCD_ERROR_FILE_NOT_FOUND == result)
#endif
    {
        // Read chip id for this chip
        result = PLM_GetInfo(GET_CHIP_ID, (void*)&chipId, sizeof(chipId));
        if (result != QCD_SUCCESS)
        {
            QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_ERROR,
                    "PLM_GetInfo failed with result %d",
                    result);
        }
        if (QCD_SUCCESS == result)
        {
            switch(chipId)
            {
                case CHIP_ID_SA8540P:
                {
                    result = CCR_GetSA8540ConfigTable(&pSetupConfig);
                    break;
                }
                case CHIP_ID_SA8295P:
                {
                    result = CCR_GetSA8295ConfigTable(&pSetupConfig);
                    break;
                }
                default:
                {
                    QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_ERROR,
                            "Wrong chip ID %d for Get configuration",
                            chipId);
                    break;
                }
            }
        }
    }
#ifdef FEAT_ENABLE_XML_CONFIGS
    else
    {
        // Mandatory misra else. Its a success path so no need to put a log here.
    }
#endif
    if (QCD_SUCCESS == result)
    {
        // Read SOC id on which this image is running
        result = PLM_GetInfo(GET_SOC_ID,
                             &pSetupConfig->socId,
                             sizeof(pSetupConfig->socId));
        if (result != QCD_SUCCESS)
        {
            QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_ERROR,
                    "PLM_GetInfo failed with result 0x%08x",
                    result);
        }
    }

    return result;
}

@param pInfo
    Pointer to the global Config Info struct to be populated

@return
    Error code defined in QCDStatus_e
    QCD_ERROR_FILE_NOT found if the xml does not exist.
**************************************************************************************************/
QCDStatus_e CC_ParseXMLFile(CameraConfigGlobalInfo_t *pInfo)
{
    QCDStatus_e result = QCD_ERROR_LAST;
    xmlDocPtr pXmlDoc = NULL;
    xmlNodePtr pCur = NULL;
    const char* filename = CAMERA_CONFIG_XML_FILE;

    QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_HIGH,
            "Start Parsing Camera Config XML File %s",
            filename);
    if (0 != access(filename, R_OK))
    {
        /* XML based config is an optional feature for development. Do not need
         * to log this as an error as this is expected. */
        QCD_LOG(LOG_CONFIG_MGR, LOG_LEVEL_HIGH,
                "QCD Config XML file %s not available, "
                "falling back to default configuration",
                filename);
        result = QCD_ERROR_FILE_NOT_FOUND;
    }
    else if (NULL == (pXmlDoc = xmlParseFile(filename)))
    {
        CC_ERR("CameraConfig file %s not parsed successfully",
               filename);
        result = QCD_ERROR_NOT_SUPPORTED;
    }
    else if (QCD_SUCCESS != (result = ValidateConfigXml(pXmlDoc)))
    {
        CC_ERR("CameraConfig xml validation failed. Err 0x%08x",
               result);
    }
    else if (NULL == (pCur = xmlDocGetRootElement(pXmlDoc)))
    {
        CC_ERR("Empty CameraConfig file %s",
               filename);
        result = QCD_ERROR_NOT_SUPPORTED;
    }
    else if (QCD_SUCCESS != (result = CC_XmlGetUint32(&pInfo->version,
                                                      "version",
                                                      pCur,
                                                      FALSE,
                                                      0U)))
    {
        CC_ERR("Unable to get version. Err: 0x%08x", result);
    }
    else if (CAM_CFG_XML_VERSION != pInfo->version)
    {
        CC_ERR("Unsupported CameraConfig version 0x%x (require 0x%x)",
               pInfo->version,
               CAM_CFG_XML_VERSION);
        result = QCD_ERROR_INVALID_CONFIG;
    }
    else
    {
        pCur = pCur->xmlChildrenNode;
        uint32_t idx = 0U;
        while ((NULL != pCur) && (idx < CAM_CFG_MAX_NUM_SOC))
        {
            if (0 == (xmlStrcmp(pCur->name, (const xmlChar *) "soc")))
            {
                if (QCD_SUCCESS == (result = CC_XmlGetUint32(&pInfo->pConfigInfo[idx]->socId,
                                                             "id",
                                                             pCur,
                                                             FALSE,
                                                             0U)))
                {
                    if (QCD_SUCCESS != (result = ParseSOCConfig(pCur,
                                                                pInfo->pConfigInfo[idx],
                                                                pInfo->pConfigInfo[idx]->socId)))
                    {
                        CC_ERR("SoC ID %u xml config parsing failed",
                               pInfo->pConfigInfo[idx]->socId);
                        break;
                    }
                    idx++;
                }
                else
                {
                    CC_ERR("Unable to get SoC ID. Err 0x%08x", result);
                    break;
                }
            }
            pCur = pCur->next;
        }
        if (QCD_SUCCESS == result)
        {
            pInfo->numSocConfig = idx;
        }
    }

    if (NULL != pXmlDoc)
    {
        xmlFreeDoc(pXmlDoc);
    }

    return result;
}

 初始化IFE 

@param deviceId
    Device id for the IFE device.
    It should be in between 0 to 1 less than max number of IFE devices supported by platform.

@return
    Error code defined in QCDStatus_e if open call fails else QCD_SUCCESS
    if all above steps is success
**************************************************************************************************/
QCDStatus_e HwMgr_IFEOpen(uint32_t deviceId)
{
    QCDStatus_e result          = QCD_ERROR_GENERAL_FAILURE;
    QCDStatus_e closeIFEResult  = QCD_ERROR_GENERAL_FAILURE;

    if (deviceId >= MAX_IFE_DEVICES)
    {
        result = QCD_ERROR_BAD_PARAM;
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR, "Invalid device id %u", deviceId);
    }
    else if (IFE_STATE_OPEN == g_ifeCtxt[deviceId].state)
    {
        result = QCD_ERROR_INVALID_STATE;
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "IFE %u : Invalid IFE state %d",
                deviceId, g_ifeCtxt[deviceId].state);
    }
    else
    {
        // Initialize device context
        //初始化 IFE CSID VFE的结构体 
        result = InitializeDeviceContext(deviceId);
    }
    if (QCD_SUCCESS == result)
    {
       //获取IFE 寄存器base addr 的虚拟地址
        // Get base address from platfrom manager
        result = GetBaseAddress(deviceId);
    }
    if (QCD_SUCCESS == result)
    {
        // Initialize low level driver
        result = InitializeDriver(deviceId);
    }
    if (QCD_SUCCESS == result)
    {
        // Create mutex for IFE device
        result = OSAL_CriticalSectionCreate(&g_ifeCtxt[deviceId].hMutex);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : OSAL_CriticalSectionCreate failed with result = 0x%08x",
                    deviceId, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "IFE %u : OSAL_CriticalSectionCreate success Handle 0x%p",
                deviceId, g_ifeCtxt[deviceId].hMutex);

        // Create non periodic timer for IFE device for enabling error propagation
        result = OSAL_TimerCreate(FALSE,
                                  0,
                                  ProcessErrorPropagationRequest,
                                  &g_csidCtxt[deviceId],
                                  "IFE_ErrorPropagator",
                                  g_OSALThreadDefaultPriority,
                                  &g_ifeCtxt[deviceId].hErrorPropagationTimer);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : OSAL_TimerCreate failed with result = 0x%08x",
                    deviceId, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "IFE %u : OSAL_TimerCreate success Handle 0x%p",
                deviceId, g_ifeCtxt[deviceId].hErrorPropagationTimer);

        // Register IST callbacks.
        result = RegisterISTCallback(deviceId);
    }
    if (QCD_SUCCESS == result)
    {
        if (FALSE == bIsSMMURegistrationDone)
        {
            // Register SMMU callback
            result = PLM_SMMUfaultRegister(&SMMUCallback);
            if (QCD_SUCCESS != result)
            {
                QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                        "PLM_SMMUfaultRegister failed with result = 0x%08x",
                        result);
            }
            else
            {
                bIsSMMURegistrationDone = TRUE;
                QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH, "PLM_SMMUfaultRegister success");
            }
        }
    }
    if (QCD_SUCCESS == result)
    {
        g_ifeCtxt[deviceId].state = IFE_STATE_OPEN;
        // Reset IFE as per power on sequence
        result = HwMgr_IFECtrl(deviceId,
                               IFE_CMD_ID_RESET,
                               NULL,
                               0,
                               NULL,
                               0);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : IFE Reset failed with result = 0x%08x",
                    deviceId, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "IFE %u : IFE Reset & Open success",
                deviceId);
    }
    else
    {
        // Close IFE device
        closeIFEResult = HwMgr_IFEClose(deviceId);
        if (QCD_SUCCESS != closeIFEResult)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : HwMgr_IFEClose failed with result = 0x%08x",
                    deviceId, closeIFEResult);
        }
    }
#ifdef QCD_AIS_MIX_USECASE
    // Register LPM callbacks.
    PLM_RegisterLpmCallback(LPMcallback);
#endif

    return result;
}

初始化 IFE CSID VFE 的结构体

    Initialize global contexts for IFE, VFE and CSID blocks with default open values.
    Context handling for the CSID and VFE happens at the manager level only.
    It should be called only once as part of IFE open call. So there is no mutex protection.
    No param checks are done as its already done in caller function.

@param deviceId
    Device id for the IFE device.
    It should be in between 0 to 1 less than max number of IFE devices supported by platform.

@return
    Error code defined in QCDStatus_e if memset fails else QCD_SUCCESS
**************************************************************************************************/
static QCDStatus_e InitializeDeviceContext(uint32_t deviceId)
{
    QCDStatus_e  result         = QCD_ERROR_GENERAL_FAILURE;
    uint32_t     rdiIdx         = 0U;
    void         *pMemsetReturn = NULL;

    // Initialize IFE Device
    g_ifeCtxt[deviceId].state                   = IFE_STATE_INVALID;
    g_ifeCtxt[deviceId].hwCaps.hwType           = IFE_DEVICE_TYPE_LITE;
    g_ifeCtxt[deviceId].hwCaps.numRdi           = MAX_IFE_OUTPUT_PATH;
    g_ifeCtxt[deviceId].hwCaps.ifeId            = deviceId;
    g_ifeCtxt[deviceId].hMutex                  = NULL;
    g_ifeCtxt[deviceId].hErrorPropagationTimer  = NULL;

    // Initialize CSID Device
    g_csidCtxt[deviceId].csidId         = deviceId;
    g_csidCtxt[deviceId].rdiPathMax     = MAX_IFE_OUTPUT_PATH;
    g_csidCtxt[deviceId].baseAddr       = 0U;
    g_csidCtxt[deviceId].state          = CSID_STATE_INVALID;
    g_csidCtxt[deviceId].hIST           = NULL;
    g_csidCtxt[deviceId].bEnableGlobalErrorPropagation
                                        = FALSE;

    // Initialize all register with 0
    pMemsetReturn = OSAL_Memset(&g_csidCtxt[deviceId].diagRegister,
                                0x0,
                                sizeof(g_csidCtxt[deviceId].diagRegister));
    if (NULL == pMemsetReturn)
    {
        result = QCD_ERROR_GENERAL_FAILURE;
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "IFE %u : OSAL_Memset failed",
                deviceId);
    }
    else
    {
        // Update result as memset was successful
        result = QCD_SUCCESS;
        // Initialize RDI context
        for (rdiIdx = 0U; rdiIdx < MAX_IFE_OUTPUT_PATH; rdiIdx++)
        {     
            //初始化g_csidCtxt 
            g_csidCtxt[deviceId].outputRDICtxt[rdiIdx].state                = CSID_STATE_INVALID;
            g_csidCtxt[deviceId].outputRDICtxt[rdiIdx].bIsTPGEnable         = FALSE;
            g_csidCtxt[deviceId].outputRDICtxt[rdiIdx].bIsFirstSofReceived  = FALSE;
            g_csidCtxt[deviceId].eventMsg[rdiIdx].bNotifyUpperLayer         = FALSE;
            g_csidCtxt[deviceId].eventMsg[rdiIdx].type                      = IFE_EVENT_TYPE_MAX;
        }

        // Initialize VFE Device
        //初始化 g_vfeCtxt
        g_vfeCtxt[deviceId].vfeId           = deviceId;
        g_vfeCtxt[deviceId].rdiPathMax      = MAX_IFE_OUTPUT_PATH;
        g_vfeCtxt[deviceId].baseAddr        = 0U;
        g_vfeCtxt[deviceId].baseAddrBusWR   = 0U;
        g_vfeCtxt[deviceId].hAsyncEvent     = NULL;
        g_vfeCtxt[deviceId].hIST            = NULL;
        g_vfeCtxt[deviceId].hEventQueue     = NULL;
        g_vfeCtxt[deviceId].hISTQueue       = NULL;

        // Initialize all register with 0
        pMemsetReturn = OSAL_Memset(&g_vfeCtxt[deviceId].diagRegister,
                                    0x0,
                                    sizeof(g_vfeCtxt[deviceId].diagRegister));
        if (NULL == pMemsetReturn)
        {
            result = QCD_ERROR_GENERAL_FAILURE;
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : OSAL_Memset failed",
                    deviceId);
        }
    }
    if (QCD_SUCCESS == result)
    {
        // Initialize RDI context
        //初始化RDI context 
        for (rdiIdx = 0U; rdiIdx < MAX_IFE_OUTPUT_PATH; rdiIdx++)
        {
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].mode          = VFE_OUTPUT_MODE_FRAME_BASED;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].state         = VFE_STATE_INVALID;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].hHwFIFO       = NULL;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].hMutex        = NULL;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].frameCnt      = 0UL;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].sofCnt        = 0UL;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].frameHeaderVA = 0UL;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].frameHeaderDA = 0UL;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].hwTimestamp   = 0U;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].hOutputBufferQueue    = NULL;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].lastHeaderFrameCnt    = 0;
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].frameHeaderWriteIdx   = 0U;
        }
    }
    return result;
}

获取IFE CSID base addr 的vaddr 进行虚拟地址与物理地址的映射

@param deviceId
    Device id for the IFE device.
    It should be in between 0 to 1 less than max number of IFE devices supported by platform.

@return
    Error code defined in QCDStatus_e if PLM call fails else QCD_SUCCESS
**************************************************************************************************/
static QCDStatus_e GetBaseAddress(uint32_t deviceId)
{
    QCDStatus_e         result  = QCD_ERROR_GENERAL_FAILURE;
    CameraHWBlockDef_t  hwDef   = {0};

    /*
     * Get VFE device base address from platform manager.
     * Same CAMERA_HWBLOCK_IFE enum is exposed by PLM for IFE & IFE_Lite devices.
     */
    hwDef.hwBlock   = CAMERA_HWBLOCK_IFE;
    hwDef.id        = deviceId;
    result = PLM_GetInfo(GET_HWBLOCK_VADDR, &hwDef, (uint32_t)sizeof(hwDef));
    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "IFE %u : PLM_GetInfo failed with result = 0x%08x",
                deviceId, result);
    }
    else
    {
        // Update base address
        g_vfeCtxt[deviceId].baseAddr = hwDef.offset;
        // Base address for BUS WR block is having fixed offset from VFE base address
        g_vfeCtxt[deviceId].baseAddrBusWR = hwDef.offset + IFE_BUS_WR_ADDR_OFFSET;
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "IFE %u : Virtual address for VFE 0x%lx",
                deviceId, g_vfeCtxt[deviceId].baseAddr);
        /*
         * Get CSID device base address from platform manager.
         * Same CAMERA_HWBLOCK_IFE_CSID enum is exposed by PLM for IFE & IFE_Lite devices.
         */
        hwDef.hwBlock   = CAMERA_HWBLOCK_IFE_CSID;
        hwDef.id        = deviceId;
        result = PLM_GetInfo(GET_HWBLOCK_VADDR, &hwDef, (uint32_t)sizeof(hwDef));
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : PLM_GetInfo failed with result = 0x%08x",
                    deviceId, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        // Update base address
        g_csidCtxt[deviceId].baseAddr = hwDef.offset;
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "IFE %u : Virtual address for CSID 0x%lx",
                deviceId, g_csidCtxt[deviceId].baseAddr);
    }
    return result;
}

 

/**********************************************************************************************//**
@brief
    Initialize low level drivers.
    It should be called only once as part of IFE open call. So there is no mutex protection.
    No param checks are done as its already done in caller function.

@param deviceId
    Device id for the IFE device.
    It should be in between 0 to 1 less than max number of IFE devices supported by platform.

@return
    Error code defined in QCDStatus_e if driver init call fails else QCD_SUCCESS
**************************************************************************************************/
static QCDStatus_e InitializeDriver(uint32_t deviceId)
{
    QCDStatus_e result  = QCD_ERROR_GENERAL_FAILURE;
    uint32_t    rdiIdx  = 0U;

    // Initialize VFE Driver
    result = VFEDriver_Init(&g_vfeCtxt[deviceId]);
    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "IFE %u : VFEDriver_Init failed with result = 0x%08x",
                deviceId, result);
    }
    else
    {
#ifdef QCD_AIS_MIX_USECASE
        result = OSAL_CriticalSectionCreate(&g_csidCtxt[deviceId].hRegMutex);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "CSID ID = %u : hRegMutex Create failed with result 0x%x",
                    deviceId, result);
        }
        result = CSIDDriver_InitFFIGolderRegister(&g_csidCtxt[deviceId]);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : CSIDDriver_InitFFIGolderRegister failed with result = 0x%08x",
                    deviceId, result);
        }
#endif
        // Update RDI state
        //更新vfe CSID outputRDICtxt[rdiIdx].state 的状态
        for (rdiIdx = 0U; rdiIdx < MAX_IFE_OUTPUT_PATH; rdiIdx++)
        {
            g_vfeCtxt[deviceId].outputRDICtxt[rdiIdx].state = VFE_STATE_INIT;
        }
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                  "IFE %u : VFEDriver_Init success",
                  deviceId);
        // Initialize CSID Driver
        g_csidCtxt[deviceId].state = CSID_STATE_INIT;
        for (rdiIdx = 0U; rdiIdx < MAX_IFE_OUTPUT_PATH; rdiIdx++)
        {
            g_csidCtxt[deviceId].outputRDICtxt[rdiIdx].state = CSID_STATE_INIT;
        }
    }
    return result;
}

VFEDriver_Init

创建四个队列进行图像数据的数据获取

/**********************************************************************************************//**
@brief
    Initialize VFE Driver by creating OSAL resource and internal buffers for device and each
    RDI paths. It internally calls deinit if init call fails to cleanup resources.
    This should be the first call to VFE driver.
    All context initilization and handling and mutex protection for the same is expected by
    IFE manager.

@param pCtxt
    Pointer to the device context

@return
    Error code defined in QCDStatus_e if param validation or resource allocation fails else
    QCD_SUCCESS.
**************************************************************************************************/
QCDStatus_e VFEDriver_Init(VFEDeviceCtxt_t *pCtxt)
{
    QCDStatus_e     result          = QCD_ERROR_GENERAL_FAILURE;
    QCDStatus_e     deinitResult    = QCD_ERROR_GENERAL_FAILURE;
    //RDI path
    uint32_t        outputPath      = (uint32_t)IFE_OUTPUT_PATH_RDI0;
    uint32_t        outputOffset    = 0U;

    if (NULL == pCtxt)
    {
        result = QCD_ERROR_BAD_PARAM;
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR, "Null Device Context Provided");
    }
    else
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "VFE ID = %u : VFEDriver_Init for device ctxt 0x%p",
                pCtxt->vfeId, pCtxt);

        // Create resource for the device
        result = CreateDeviceResource(pCtxt);
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_DEBUG,
                "VFE ID = %u : IST Event Queue created successfully with handle = 0x%p",
                pCtxt->vfeId, pCtxt->hISTQueue);

        // Initialize RDI output context
        for (outputPath = (uint32_t)IFE_OUTPUT_PATH_RDI0;
             outputPath < pCtxt->rdiPathMax;
             outputPath++)
        {
            /*
             * Frame Header is allocated as contiguous memory at once for all RDI
             * and the same is used as different offset by all RDIs.
             * Hence setting the offset here so each RDI can access different memory location
             */
             //获取对应的IFE 输出图相对于IFE base的偏移值
            outputOffset = outputPath * FRAME_HEADER_CHUNK_PER_INTERF;
             //获取图像数据的物理地址
            pCtxt->outputRDICtxt[outputPath].frameHeaderDA =
                            pCtxt->frameHeaderBuf.pDA + outputOffset;
             //将图像物理地址转换成虚拟地址
            pCtxt->outputRDICtxt[outputPath].frameHeaderVA =
                            (uintptr_t)((uint8_t*)pCtxt->frameHeaderBuf.pVA + outputOffset);

            // Create resource for RDI
            result = CreateRDIResource(pCtxt, (IFEOutputPathType_e)outputPath);
            if (QCD_SUCCESS != result)
            {
                break;
            }
        }
    }

    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "VFE ID = %u : VFEDriver_Init success for device ctxt 0x%p",
                pCtxt->vfeId, pCtxt);
    }
    else
    {
        // De-initialize VFE if initialization fails
        deinitResult = VFEDriver_DeInit(pCtxt);
        if (QCD_SUCCESS != deinitResult)
        {
            if (NULL == pCtxt)
            {
                QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                        "VFEDriver_DeInit failed for device ctxt 0x%p with result = 0x%08x",
                        pCtxt, deinitResult);
            }
            else
            {
                QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                        "VFE ID = %u : VFEDriver_DeInit failed with result = 0x%08x",
                        pCtxt->vfeId, deinitResult);
            }
        }
    }
#ifdef QCD_AIS_MIX_USECASE
    if (QCD_SUCCESS == result)
    {
        result = VFEDriver_InitFFIGolderRegister(pCtxt);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR, "VFE ID = %u : FFI Init Failed", pCtxt->vfeId);
        }
    }
#endif
    return result;
}

//创建IEF event pCtxt->hEventQueue 事件队列和中断队列pCtxt->hISTQueue

/**********************************************************************************************//**
@brief
    Create OSAL resources for the device/driver.
        - Create event for async event handling.
        - Create non-blocking queues between driver and manager for event handling.
        - Allocate buffer for frame header dump.
    It should be called only once as part VFEDriver_Init. So there is no mutex protection.
    No param checks are done as its already done in caller function.

@param pCtxt
    Pointer to the device context.

@return
    Error code defined in QCDStatus_e if this call fails to allocate resource else QCD_SUCCESS
    if all above steps is success
**************************************************************************************************/
static QCDStatus_e CreateDeviceResource(VFEDeviceCtxt_t *pCtxt)
{
    QCDStatus_e result = QCD_ERROR_GENERAL_FAILURE;

    // Create async event for reset event handling
    result = OSAL_EventCreate(&pCtxt->hAsyncEvent);
    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "VFE ID = %u : Async event creation failed with result = 0x%08x",
                pCtxt->vfeId, result);
    }

    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_DEBUG,
                "VFE ID = %u : Async Event created successfully with handle = 0x%p",
                pCtxt->vfeId, pCtxt->hAsyncEvent);
        // Create non blocking event queue for event handling between driver and manager
        result = OSAL_QueueCreate(sizeof(IFEEventMsgType_t),
                                  IFE_EVENT_QUEUE_SIZE,
                                  FALSE,
                                  &pCtxt->hEventQueue);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "VFE ID = %u : OSAL_QueueCreate failed with result = 0x%08x",
                     pCtxt->vfeId, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_DEBUG,
                "VFE ID = %u : Event Queue created successfully with handle = 0x%p",
                pCtxt->vfeId, pCtxt->hEventQueue);
        /*
         * Create non blocking IST event queue for 1st stage IST events handling between
         * driver and manager
         */
        result = OSAL_QueueCreate(sizeof(IFEEventMsgType_t),
                                  IFE_EVENT_QUEUE_SIZE,
                                  FALSE,
                                  &pCtxt->hISTQueue);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "VFE ID = %u : OSAL_QueueCreate failed with result = 0x%08x",
                     pCtxt->vfeId, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        //对framebuffer 分配内存用于接受IFE的图像数据
        // Allocate frame header buffer for all RDI paths
        pCtxt->frameHeaderBuf.size = CAM_ALIGN_SIZE(FRAME_HEADER_CHUNK_PER_INTERF,
                                                    FRAME_HEADER_BUFFER_SIZE);
        pCtxt->frameHeaderBuf.flags = CAMERA_BUFFER_FLAG_CONTIGOUS;
        result = PLM_CameraBufferAlloc(&pCtxt->frameHeaderBuf, 0U, CAMERA_HWBLOCK_IFE);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "VFE ID = %u : PLM_CameraBufferAlloc failed for header with result = 0x%08x",
                     pCtxt->vfeId, result);
        }
    }
#ifdef QCD_AIS_MIX_USECASE
    if (QCD_SUCCESS == result)
    {
        result = OSAL_CriticalSectionCreate(&pCtxt->hRegMutex);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "VFE ID = %u : hRegMutex Create failed with result 0x%x",
                    pCtxt->vfeId, result);
        }
    }
#endif
    return result;
}

 

/**********************************************************************************************//**
@brief
    Create OSAL resources for the RDI paths.
        - Create non blocking queues for buffer management
        - Create mutex for buffer handling.
    It should be called only once per RDI as part VFEDriver_Init. So there is no mutex protection.
    No param checks are done as its already done in caller function.

@param pCtxt
    Pointer to the device context

@param outputPath
    RDI Path for which resource will be allocated.
    Valid range is 0 to 1 less than max number of RDI path supported by platform.

@return
    Error code defined in QCDStatus_e if this call fails to allocate resource else QCD_SUCCESS
    if all above steps is success
**************************************************************************************************/
static QCDStatus_e CreateRDIResource(VFEDeviceCtxt_t *pCtxt, IFEOutputPathType_e outputPath)
{
    QCDStatus_e result = QCD_ERROR_GENERAL_FAILURE;

    // Create non blocking output buffer queue
    //创建bufferqueue判断IFE driver 获取到了数据, 通知StreamManager获取数据
    result = OSAL_QueueCreate(sizeof(VFEOutputBuffer_t),
                              MAX_NUM_OF_OUTPUT_BUFFERS,
                              FALSE,
                              &pCtxt->outputRDICtxt[outputPath].hOutputBufferQueue);
    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "VFE ID = %u : OSAL_QueueCreate failed for RDI %d with result = 0x%08x",
                 pCtxt->vfeId, outputPath, result);
    }
    else
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_DEBUG,
                "VFE ID = %u : Output buffer queue created for RDI = %d Handle = 0x%p",
                pCtxt->vfeId, outputPath,
                pCtxt->outputRDICtxt[outputPath].hOutputBufferQueue);
        //创建VFE hardware FIFO判断物理层有数据 让IFE驱动获取数据
        // Create non blocking FIFO queue which replicate VFE hardware FIFO
        result = OSAL_QueueCreate(sizeof(VFEOutputBuffer_t),
                                  MAX_FIFO_DEPTH,
                                  FALSE,
                                  &pCtxt->outputRDICtxt[outputPath].hHwFIFO);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "VFE ID = %u : OSAL_QueueCreate failed : RDI %d with result = 0x%08x",
                     pCtxt->vfeId, outputPath, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_DEBUG,
                "VFE ID = %u : FIFO queue created for RDI = %d with handle = 0x%p",
                pCtxt->vfeId, outputPath, pCtxt->outputRDICtxt[outputPath].hHwFIFO);

        // Create mutex for buffer handling
        result = OSAL_CriticalSectionCreate(&pCtxt->outputRDICtxt[outputPath].hMutex);
        if (QCD_SUCCESS == result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_DEBUG,
                    "VFE ID = %u : Mutex created for RDI = %d with handle = 0x%p",
                    pCtxt->vfeId, outputPath, pCtxt->outputRDICtxt[outputPath].hMutex);
        }
        else
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "VFE ID = %u : Mutex creation failed for RDI %d with result = 0x%08x",
                    pCtxt->vfeId, outputPath, result);
        }
    }

    return result;
}

 CSID init 

QCDStatus_e CSIDDriver_InitFFIGolderRegister(CSIDDeviceCtxt_t *pCtxt)
{
    QCDStatus_e result = QCD_SUCCESS;

    result = OSAL_CriticalSectionEnter(pCtxt->hRegMutex);
    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "CSID %u : OSAL_CriticalSectionEnter failed with result 0x%x",
                pCtxt->csidId, result);
    }
    else
    {
        error_type ret;
        uint32_t i = 0U;
        for (i = 0U; i < CSID_MONITOR_REG_SIZE; i++)
        {
            g_csidGoldenRegs[pCtxt->csidId][i] = csidRegNeedToMonitor[i].defaultValue;
        }

        ret = crc32_generate((char*)g_csidGoldenRegs[pCtxt->csidId],
                sizeof(g_csidGoldenRegs[pCtxt->csidId]), &pCtxt->regGoldenCRC);
        if (SUCCESS != ret)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR, "CRC Generate Failed: %x", ret);
            result = QCD_ERROR_INVALID_STATE;
        }

        result = OSAL_CriticalSectionLeave(pCtxt->hRegMutex);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "CSID %u : OSAL_CriticalSectionLeave failed with result 0x%x",
                     pCtxt->csidId, result);
        }
    }

    return result;
}

RegisterISTCallback

注册中断回调函数VFEProcessIST CSIDProcessIST

    It should be called only once as part of IFE open call. So there is no mutex protection.
    No param checks are done as its already done in caller function.

@param deviceId
    Device id for the IFE device.
    It should be in between 0 to 1 less than max number of IFE devices supported by platform.

@return
    Error code defined in QCDStatus_e if PLM call fails else QCD_SUCCESS
**************************************************************************************************/
static QCDStatus_e RegisterISTCallback(uint32_t deviceId)
{
    QCDStatus_e result = QCD_ERROR_GENERAL_FAILURE;

    // Register IST for VFE
    //注册VFE中断函数
    g_vfeCtxt[deviceId].hIST = PLM_ISTInit(CAMERA_HWBLOCK_IFE, deviceId, &VFEProcessIST);
    if (NULL == g_vfeCtxt[deviceId].hIST)
    {
        result = QCD_ERROR_GENERAL_FAILURE;
        QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                "IFE %u : PLM_ISTInit failed with result = 0x%08x",
                deviceId, result);
    }
    else
    {
        // Update result as VFE IST registration is successful
        result = QCD_SUCCESS;
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "IFE %u : PLM_ISTInit success Handle 0x%p",
                deviceId, g_vfeCtxt[deviceId].hIST);
        // Register IST for CSID
        //注册CSID 中断函数
        g_csidCtxt[deviceId].hIST = PLM_ISTInit(CAMERA_HWBLOCK_IFE_CSID,
                                                deviceId,
                                                &CSIDProcessIST);
        if (NULL == g_csidCtxt[deviceId].hIST)
        {
            result = QCD_ERROR_GENERAL_FAILURE;
            QCD_LOG(LOG_IFE, LOG_LEVEL_ERROR,
                    "IFE %u : PLM_ISTInit failed with result = 0x%08x",
                    deviceId, result);
        }
    }
    if (QCD_SUCCESS == result)
    {
        QCD_LOG(LOG_IFE, LOG_LEVEL_HIGH,
                "IFE %u : PLM_ISTInit success Handle 0x%p",
                deviceId, g_csidCtxt[deviceId].hIST);
    }
    return result;
}

 

@brief
    Interrupt handler thread function

@param hwBlock [in]
    Camera HW block.

@param devId [in]
    HW block Id.

@param cbFunc [in]
    Callback function.

@return
    Interrupt thread handle.
**************************************************************************************************/
OsalThread_t  PLM_ISTInit(const CameraHWBlock_e hwBlock,
                          const uint32_t devId,
                          const PLM_ISTCbFunc_t cbFunc)
{
        OsalThread_t  hThreadIST    = NULL;
        QCDStatus_e   rc            = QCD_ERROR_GENERAL_FAILURE;

    if (NULL == cbFunc)
    {
        QCD_LOG(LOG_PLATFORM, LOG_LEVEL_ERROR, "PLM_ISTInit called with NULL callback function");
    }
    else
    {
        PlatformISTCtxt_t *pISTCtxt = (PlatformISTCtxt_t*) OSAL_Malloc(sizeof(PlatformISTCtxt_t));

        if (NULL == pISTCtxt)
        {
            QCD_LOG(LOG_PLATFORM, LOG_LEVEL_ERROR, "OSAL_Malloc failed");
        }
        else
        {
            rc = OSAL_CriticalSectionEnter(g_PlmIstMutex);
            if (QCD_SUCCESS == rc)
            {
                pISTCtxt->hwDef.hwBlock   = hwBlock;
                pISTCtxt->hwDef.id        = devId;
                rc = PLM_GetInfo(GET_HWBLOCK_IRQ,
                                 &pISTCtxt->hwDef,
                                 (uint32_t)sizeof(CameraHWBlockDef_t));

                if (QCD_SUCCESS == rc)
                {
                    SIGEV_INTR_INIT(&pISTCtxt->sigEvent);
                    pISTCtxt->istCb = cbFunc;
                    //注册中断回调函数
                    rc = OSAL_ThreadCreate( g_OSALThreadISTPriority,
                                            PLM_IST,
                                            pISTCtxt,
                                            0,
                                            (const char*)pISTCtxt->hwDef.name,
                                            &hThreadIST);
                    if (QCD_SUCCESS != rc)
                    {
                        QCD_LOG(LOG_PLATFORM, LOG_LEVEL_ERROR, "IST Thread create failure");
                        OSAL_Free(pISTCtxt);
                    }
                    else
                    {
                        g_pCtxtList[g_CtxtCount] = pISTCtxt;
                        g_CtxtCount++;
                    }
                }
                else
                {
                    QCD_LOG(LOG_PLATFORM, LOG_LEVEL_ERROR, "PLM_GetInfo failed (rc = 0x%x)", rc);
                }

                rc = OSAL_CriticalSectionLeave(g_PlmIstMutex);
                if (QCD_SUCCESS != rc)
                {
                    QCD_LOG(LOG_PLATFORM,
                            LOG_LEVEL_ERROR,
                            "OSAL_CriticalSectionLeave failed (rc = 0x%x)",
                            rc);
                }
            }
            else
            {
                QCD_LOG(LOG_PLATFORM,
                        LOG_LEVEL_ERROR,
                        "OSAL_CriticalSectionEnter failed (rc = 0x%x)",
                        rc);
            }
        }
        }

    return hThreadIST;
}

 获取IFE中的HWBLOCK中的硬件映射的irq number

@param pData [in]
    structure to fill/read info to.

@param size [in]
    size of pData.

@return
    Error code defined in QCDStatus_e
**************************************************************************************************/
static QCDStatus_e GetHWBlockIRQ(void *pData, size_t size)
{
    QCDStatus_e rc = QCD_ERROR_GENERAL_FAILURE;

    if (size != sizeof(CameraHWBlockDef_t))
    {
        QCD_LOG(LOG_PLATFORM, LOG_LEVEL_ERROR, "invalid size");
        rc = QCD_ERROR_BAD_PARAM;
    }
    else
    {
        const CameraHWDefinition_t     *pHwDef   = GetHWDef();
        CameraHWBlockDef_t             *pHWBlock = pData;

        if (pHwDef != NULL)
        {
            for (int32_t i = 0; i < CAMERAPLATFORM_MAX_HWBLOCKS; i++)
            {
                if ((pHWBlock->hwBlock == pHwDef->hwblocks[i].hwBlock) &&
                    (pHWBlock->id == pHwDef->hwblocks[i].id))
                {
                    pHWBlock->irq = pHwDef->hwblocks[i].irq;
                    if (0 > snprintf(pHWBlock->name,
                                     sizeof(pHwDef->hwblocks[i].name),
                                     "%s_ist",
                                     pHwDef->hwblocks[i].name))
                    {
                        rc = QCD_ERROR_GENERAL_FAILURE;
                        QCD_LOG(LOG_PLATFORM,
                                LOG_LEVEL_ERROR,
                                "Error setting IRQ thread name");
                    }
                    else
                    {
                        rc = QCD_SUCCESS;
                    }
                    break;
                }
            }
        }
        else
        {
            QCD_LOG(LOG_PLATFORM, LOG_LEVEL_ERROR, "hw block not found ");
            rc = QCD_ERROR_NOT_FOUND;
        }
    }

    return rc;
}

HwMgr_CSIPHYOpen

/**********************************************************************************************//**
@brief
    Get the CSIPHY device id base address from platform. Create the critical section and register
    the IST for handling the interrupt for the provided CSIPHY device Id.

@param deviceId
    Device Id for the CSIPHY device and valid range of CSIPHY deviceId is 0-3.

@return
    If funtion parameter deviceId is vaild, return value depends on the called function
    return value otherwise bad param.
**************************************************************************************************/
QCDStatus_e HwMgr_CSIPHYOpen(uint32_t deviceId)
{
    QCDStatus_e result = QCD_ERROR_GENERAL_FAILURE;
    QCDStatus_e tempResult = QCD_ERROR_GENERAL_FAILURE;

    if (MAX_CSIPHY_DEVICES <= deviceId)
    {
        result = QCD_ERROR_BAD_PARAM;
        QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR, "Invalid CSIPHY device id %u", deviceId);
    }
    else if (CSIPHY_STATE_INVALID != g_csiphyCtxt[deviceId].state)
    {
        result = QCD_ERROR_INVALID_STATE;
        QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                "CSIPHY %u : Invalid CSIPHY state %d",
                deviceId, g_csiphyCtxt[deviceId].state);
    }
    else
    {
        // Initialize CSIPHY Device
        g_csiphyCtxt[deviceId].state = CSIPHY_STATE_INVALID;
        g_csiphyCtxt[deviceId].refCount = 0U;
        g_csiphyCtxt[deviceId].csiphyId = deviceId;
        g_csiphyCtxt[deviceId].baseAddr = 0U;
        g_csiphyCtxt[deviceId].hMutex = NULL;
        g_csiphyCtxt[deviceId].hIST = NULL;
#ifdef QCD_AIS_MIX_USECASE
        g_csiphyCtxt[deviceId].hRegMutex = NULL;
        g_csiphyCtxt[deviceId].regGoldenCRC = 0U;
#endif
        result = QCD_SUCCESS;
    }

    if (QCD_SUCCESS == result)
    {
        result =  CSIPHYDeviceInit(deviceId);
    }

    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                "CSIPHY %u : CSIPHYOpen device init failed with result 0x%x",
                deviceId, result);

        // Close CSIPHY Device
        tempResult = HwMgr_CSIPHYClose(deviceId);
        if (QCD_SUCCESS != tempResult)
        {
            QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                    "CSIPHY %u : HwMgr_CSIPHYClose failed with result 0x%x",
                    deviceId, tempResult);
        }
    }
    else
    {
        // Update the CSIPHY state
        g_csiphyCtxt[deviceId].state = CSIPHY_STATE_OPEN;
        QCD_LOG(LOG_CSIPHY, LOG_LEVEL_HIGH,
                "CSIPHY %u : CSIPHYOpen success",
                deviceId);
    }

    return result;
}

 

/**********************************************************************************************//**
@brief
    During HwMgr_CSIPHYOpen, the CSIPHYDeviceInit Initialize CSIPHY Device, Create the critical
    section and register the IST handler per CSIPHY device block.

@pre
    caller's function responsible to ensure calling parameters are valid.

@param deviceId
    Device Id for the CSIPHY Device (valid range of device Id is from 0-3)

@return
    If called function return success, return value is QCD_SUCCESS otherwise return error code
    as defined in QCDStatus_e.
**************************************************************************************************/
static QCDStatus_e CSIPHYDeviceInit(uint32_t deviceId)
{
    QCDStatus_e result       = QCD_ERROR_GENERAL_FAILURE;
    CameraHWBlockDef_t hwDef;

    // Get CSIPHY device info from platform manager
    hwDef.hwBlock = CAMERA_HWBLOCK_CSIPHY;
    hwDef.id = deviceId;
    result = PLM_GetInfo(GET_HWBLOCK_VADDR, &hwDef, (uint32_t)sizeof(hwDef));
    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                "CSIPHY %u : PLM_GetInfo failed with result 0x%x", deviceId, result);
    }
    else
    {
       //获取csiphy的基地址
        g_csiphyCtxt[deviceId].baseAddr = hwDef.offset;
        QCD_LOG(LOG_CSIPHY, LOG_LEVEL_HIGH,
                "CSIPHY %u : Virtual address for CSIPHY 0x%lx",
                deviceId, g_csiphyCtxt[deviceId].baseAddr);

        // Create mutex for CSIPHY device
        result = OSAL_CriticalSectionCreate(&g_csiphyCtxt[deviceId].hMutex);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                    "CSIPHY %u : OSAL_CriticalSectionCreate failed with result 0x%x",
                    deviceId, result);
        }
    }
#ifdef QCD_AIS_MIX_USECASE
    if (QCD_SUCCESS == result)
    {
        result = OSAL_CriticalSectionCreate(&g_csiphyCtxt[deviceId].hRegMutex);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                    "CSIPHY %u : hRegMutex Create failed with result 0x%x",
                    deviceId, result);
        }
    }
#endif
    if (QCD_SUCCESS == result)
    {
        // Register IST for CSIPHY
        //注册CSIPHY 中断函数
        g_csiphyCtxt[deviceId].hIST = PLM_ISTInit(CAMERA_HWBLOCK_CSIPHY,
                                                  deviceId, &CSIPHYProcessIST);
        if (NULL == g_csiphyCtxt[deviceId].hIST)
        {
            result = QCD_ERROR_GENERAL_FAILURE;
            QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                    "CSIPHY %u : PLM_ISTInit failed with result 0x%x",
                    deviceId, result);
        }
        else
        {
#ifdef QCD_AIS_MIX_USECASE
            result = CSIPHYDriver_Init(&g_csiphyCtxt[deviceId]);
            if (QCD_SUCCESS == result)
#endif
                QCD_LOG(LOG_CSIPHY, LOG_LEVEL_HIGH,
                        "CSIPHY %u : PLM_ISTInit success",
                        deviceId);
        }
    }
    return result;
}

 

QCDStatus_e CSIPHYDriver_Init(CSIPHYDeviceCtxt_t *pCtxt)
{
    QCDStatus_e result = QCD_SUCCESS;

    result = OSAL_CriticalSectionEnter(pCtxt->hRegMutex);
    if (QCD_SUCCESS != result)
    {
        QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                "CSIPHY %u : OSAL_CriticalSectionEnter failed with result 0x%x",
                pCtxt->csiphyId, result);
    }
    else
    {
        error_type ret;
        memset(g_csiphyGoldenRegs[pCtxt->csiphyId], 0U, sizeof(g_csiphyGoldenRegs[pCtxt->csiphyId]));
        ret = crc32_generate((char*)g_csiphyGoldenRegs[pCtxt->csiphyId],
                sizeof(g_csiphyGoldenRegs[pCtxt->csiphyId]), &pCtxt->regGoldenCRC);
        if (SUCCESS != ret)
        {
            QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR, "CRC Generate Failed: %x", ret);
            result = QCD_ERROR_INVALID_STATE;
        }

        result = OSAL_CriticalSectionLeave(pCtxt->hRegMutex);
        if (QCD_SUCCESS != result)
        {
            QCD_LOG(LOG_CSIPHY, LOG_LEVEL_ERROR,
                    "CSIPHY %u : OSAL_CriticalSectionLeave failed with result 0x%x",
                     pCtxt->csiphyId, result);
        }
    }
    return result;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值