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()