uint32_t am_hal_iom_interrupt_service()

in hw/mcu/ambiq/apollo3/src/ext/AmbiqSuite/mcu/apollo3/hal/am_hal_iom.c [1818:2089]


uint32_t am_hal_iom_interrupt_service(void *pHandle, uint32_t ui32IntMask)
{
    uint32_t ui32Module;
    uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
    am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
    uint32_t index;

#ifndef AM_HAL_DISABLE_API_VALIDATION
    if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
    {
        return AM_HAL_STATUS_INVALID_HANDLE;
    }
#endif // AM_HAL_DISABLE_API_VALIDATION

    ui32Module = pIOMState->ui32Module;

#if (AM_HAL_IOM_CQ == 1)
    if (pIOMState->bHP)
    {
        //
        // Accumulate the INTSTAT for this transaction
        //
        pIOMState->ui32TxnInt |= ui32IntMask;

        //
        // Check for the command completion
        //
        if (pIOMState->ui32TxnInt & (AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_DERR))
        {
            //
            // We need to wait for the DMA complete as well
            // Special case for 0 length DMA - by checking the DMAEN register
            //
            if ((IOMn(ui32Module)->DMACFG_b.DMAEN == 0) || (pIOMState->ui32TxnInt & (AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_ERR)))
            {
                // Call the callback
                // Need to determine the error, call the callback with proper status
                pIOMState->ui32LastHPIdxProcessed++;
                pIOMState->ui32NumHPEntries--;
                index = pIOMState->ui32LastHPIdxProcessed % pIOMState->ui32MaxHPTransactions;
                am_hal_iom_dma_entry_t *pDMAEntry = &pIOMState->pHPTransactions[index];
                if ( pDMAEntry->pfnCallback != NULL )
                {
                    pDMAEntry->pfnCallback(pDMAEntry->pCallbackCtxt, internal_iom_get_int_err(ui32Module, pIOMState->ui32TxnInt));
                    pDMAEntry->pfnCallback = NULL;
                }

                if (pIOMState->ui32TxnInt & AM_HAL_IOM_INT_ERR)
                {
                    //
                    // Do Error recovery
                    // Disable DMA
                    //
                    IOMn(ui32Module)->DMACFG_b.DMAEN = 0;

                    //
                    // Clear DMAERR in DMASTAT
                    //
                    IOMn(ui32Module)->DMASTAT = 0;

                    //
                    // Reset Submodule & FIFO
                    //
                    internal_iom_reset_on_error(pIOMState, pIOMState->ui32TxnInt & AM_HAL_IOM_INT_ERR);
                }
                //
                // Post next transaction if queue is not empty
                //
                if (pIOMState->ui32NumHPEntries)
                {
                    //
                    // Initialize the DMA state machine (clear the DMACPL flag).
                    //
                    IOMn(ui32Module)->DMASTAT = 0;
                    //AM_REGn(IOM, ui32Module, INTCLR) = AM_HAL_IOM_INT_ALL;
                    pIOMState->ui32TxnInt = 0;
                    program_dma(pIOMState);
                }
                else
                {
                    pIOMState->bHP = false;
                    // Unpause the CQ
                    // Restore interrupts
                    IOMn(ui32Module)->INTEN &= ~(AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP);
                    // Resume the CQ
                    IOMn(ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_CQ;
                }
            }
        }
        return AM_HAL_STATUS_SUCCESS;
    }
#endif
    if (pIOMState->ui32NumPendTransactions)
    {
#if (AM_HAL_IOM_CQ == 1)
        am_hal_cmdq_status_t status;

        //
        // Get the current and last indexes.
        //
        if (pIOMState->pCmdQHdl && ((ui32Status = am_hal_cmdq_get_status(pIOMState->pCmdQHdl, &status)) == AM_HAL_STATUS_SUCCESS))
        {
            // For Sequence - this can be updated in the callback
            pIOMState->bRestart = false;
            //
            // Figure out which callbacks need to be handled.
            //
            while ((pIOMState->ui32LastIdxProcessed != status.lastIdxProcessed) && !(pIOMState->bRestart))
            {
                pIOMState->ui32LastIdxProcessed++;
                pIOMState->ui32NumPendTransactions--;
                index = pIOMState->ui32LastIdxProcessed & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1);
                if ( pIOMState->pfnCallback[index] != NULL )
                {
                    pIOMState->pfnCallback[index](pIOMState->pCallbackCtxt[index], AM_HAL_STATUS_SUCCESS);
                    if (pIOMState->eSeq != AM_HAL_IOM_SEQ_RUNNING)
                    {
                        pIOMState->pfnCallback[index] = NULL;
                    }
                }
            }

            // For Sequence - this can be updated in the callback
            if (!pIOMState->bRestart)
            {
                //
                // Check the CQError - If set it indicates that the current transaction encountered an error
                //
                if (ui32IntMask & AM_HAL_IOM_INT_ERR)
                {
                    // Need to determine the error, call the callback with proper status
                    pIOMState->ui32LastIdxProcessed++;
                    pIOMState->ui32NumPendTransactions--;
                    index = pIOMState->ui32LastIdxProcessed & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1);
                    if ( pIOMState->pfnCallback[index] != NULL )
                    {
                        pIOMState->pfnCallback[index](pIOMState->pCallbackCtxt[index], internal_iom_get_int_err(ui32Module, ui32IntMask));
                        if (pIOMState->eSeq != AM_HAL_IOM_SEQ_RUNNING)
                        {
                            pIOMState->pfnCallback[index] = NULL;
                        }
                    }

                    //
                    // Do Error recovery
                    // Disable CQ
                    //
                    IOMn(ui32Module)->CQCFG_b.CQEN = 0;

                    //
                    // Disable DMA
                    //
                    IOMn(ui32Module)->DMACFG_b.DMAEN = 0;

                    //
                    // Clear DMAERR in DMASTAT
                    //
                    IOMn(ui32Module)->DMASTAT = 0;

                    //
                    // Reset Submodule & FIFO
                    //
                    internal_iom_reset_on_error(pIOMState, ui32IntMask & AM_HAL_IOM_INT_ERR);

                    //
                    // Move the command queue at next transaction
                    //
                    am_hal_cmdq_error_resume(pIOMState->pCmdQHdl);
                    if (pIOMState->ui32NumPendTransactions)
                    {
                        // Re-enable the CQ
                        am_hal_iom_CQEnable(pIOMState);
                    }
                }
            }

            if (pIOMState->ui32NumPendTransactions == 0)
            {
                //
                // Disable the Command Queue
                //
                am_hal_iom_CQDisable(pHandle);
            }
        }
#else // !AM_HAL_IOM_CQ
        //
        // Accumulate the INTSTAT for this transaction
        //
        pIOMState->ui32TxnInt |= ui32IntMask;

        //
        // Check for the command completion
        //
        if (pIOMState->ui32TxnInt & (AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_DERR))
        {
            //
            // We need to wait for the DMA complete as well
            // Special case for 0 length DMA - by checking the DMAEN register
            //
            if ((IOMn(ui32Module)->DMACFG_b.DMAEN == 0) || (pIOMState->ui32TxnInt & (AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_ERR)))
            {
                // Call the callback
                // Need to determine the error, call the callback with proper status
                pIOMState->ui32LastIdxProcessed++;
                pIOMState->ui32NumPendTransactions--;
                index = pIOMState->ui32LastIdxProcessed % pIOMState->ui32MaxTransactions;
                if ( pIOMState->pfnCallback[index] != NULL )
                {
                    pIOMState->pfnCallback[index](pIOMState->pCallbackCtxt[index], internal_iom_get_int_err(ui32Module, pIOMState->ui32TxnInt));
                    pIOMState->pfnCallback[index] = NULL;
                }

                if (pIOMState->ui32TxnInt & AM_HAL_IOM_INT_ERR)
                {
                    //
                    // Do Error recovery
                    // Disable DMA
                    //
                    IOMn(ui32Module)->DMACFG_b.DMAEN = 0;

                    //
                    // Clear DMAERR in DMASTAT
                    //
                    IOMn(ui32Module)->DMASTAT = 0;

                    //
                    // Reset Submodule & FIFO
                    //
                    internal_iom_reset_on_error(pIOMState, pIOMState->ui32TxnInt & AM_HAL_IOM_INT_ERR);
                }
                //
                // Post next transaction if queue is not empty
                //
                if (pIOMState->ui32NumPendTransactions)
                {
                    index = (pIOMState->ui32LastIdxProcessed + 1) % pIOMState->ui32MaxTransactions;

                    //
                    // Initialize the DMA state machine (clear the DMACPL flag).
                    //
                    IOMn(ui32Module)->DMASTAT = 0;
                    //AM_REGn(IOM, ui32Module, INTCLR) = AM_HAL_IOM_INT_ALL;
                    pIOMState->ui32TxnInt = 0;
                    run_txn_cmdlist(&pIOMState->pTransactions[index], sizeof(am_hal_iom_txn_cmdlist_t) / sizeof(am_hal_cmdq_entry_t));
                }
            }
        }
#endif // !AM_HAL_IOM_CQ

        if (pIOMState->ui32NumPendTransactions == 0)
        {
#if 0 // Taken off from here - we'll anyways disable it at the start of next transaction
            //
            // Disable DMA
            //
            IOMn(ui32Module)->DMACFG_b.DMAEN = 0;
#endif

            //
            // Clear interrupts
            // Restore IOM interrupts.
            //
            IOM_SET_INTEN(ui32Module, pIOMState->ui32UserIntCfg);
        }
    }

    //
    // Return the status.
    //
    return ui32Status;

} // am_hal_iom_interrupt_service()