uint32_t am_hal_mspi_interrupt_service()

in hw/mcu/ambiq/apollo3/src/ext/AmbiqSuite/mcu/apollo3/hal/am_hal_mspi.c [2764:3075]


uint32_t am_hal_mspi_interrupt_service(void *pHandle, uint32_t ui32IntStatus)
{
    am_hal_mspi_state_t           *pMSPIState = (am_hal_mspi_state_t *)pHandle;
    uint32_t                      ui32Module;
    uint32_t                      ui32Status;

#ifndef AM_HAL_DISABLE_API_VALIDATION
    //
    // Check the handle.
    //
    if (!AM_HAL_MSPI_CHK_HANDLE(pHandle))
    {
        return AM_HAL_STATUS_INVALID_HANDLE;
    }
#endif // AM_HAL_DISABLE_API_VALIDATION

    ui32Module = pMSPIState->ui32Module;

    //
    // Add a delay to help make the service function work.
    //
    // am_hal_flash_delay(FLASH_CYCLES_US(10));

#if MSPI_USE_CQ
    if (pMSPIState->bHP)
    {
#if 0
        if (ui32IntStatus & AM_HAL_MSPI_INT_CQUPD)
        {
            while(1);
        }
#endif
        //
        // Accumulate the INTSTAT for this transaction
        //
        pMSPIState->ui32TxnInt |= ui32IntStatus;

        //
        // We need to wait for the DMA complete as well
        //
        if (pMSPIState->ui32TxnInt & (AM_HAL_MSPI_INT_DMACMP | AM_HAL_MSPI_INT_ERR))
        {
            uint32_t index;

            //
            // Wait for the command completion
            //
            if (!(pMSPIState->ui32TxnInt & AM_HAL_MSPI_INT_CMDCMP))
            {
                //
                //
                //
                while (!MSPIn(ui32Module)->INTSTAT_b.CMDCMP);
            }
            pMSPIState->ui32TxnInt |= MSPIn(ui32Module)->INTSTAT;

            //
            // Clear the interrupt status
            //
            MSPIn(ui32Module)->INTCLR = AM_HAL_MSPI_INT_ALL;

            //
            // Need to determine the error, call the callback with proper status
            //
            if (pMSPIState->ui32TxnInt & AM_HAL_MSPI_INT_ERR)
            {
                ui32Status = AM_HAL_STATUS_FAIL;

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

                //
                // Must reset xfer block
                //
                MSPIn(ui32Module)->MSPICFG_b.IPRSTN = 0;  // in reset
                MSPIn(ui32Module)->MSPICFG_b.IPRSTN = 1;  // back out -- clears current transfer
            }
            else
            {
                ui32Status = AM_HAL_STATUS_SUCCESS;
            }

            pMSPIState->ui32LastHPIdxProcessed++;
            pMSPIState->ui32NumHPEntries--;
            index = pMSPIState->ui32LastHPIdxProcessed % pMSPIState->ui32MaxHPTransactions;
            am_hal_mspi_dma_entry_t *pDMAEntry = &pMSPIState->pHPTransactions[index];

            //
            // Call the callback
            //
            if ( pDMAEntry->pfnCallback != NULL )
            {
                pDMAEntry->pfnCallback(pDMAEntry->pCallbackCtxt, ui32Status);
                pDMAEntry->pfnCallback = NULL;
            }

            //
            // Post next transaction if queue is not empty
            //
            if (pMSPIState->ui32NumHPEntries)
            {
                pMSPIState->ui32TxnInt = 0;
                program_dma(pMSPIState);
            }
            else
            {
                pMSPIState->bHP = false;
                // Unpause the CQ
                //
                // Command to set the DMACFG to disable DMA.
                // Need to make sure we disable DMA before we can reprogram
                //
                MSPIn(ui32Module)->DMACFG = _VAL2FLD(MSPI_DMACFG_DMAEN, 0);
                // Restore interrupts
                MSPIn(ui32Module)->INTEN &= ~(AM_HAL_MSPI_INT_DMACMP | AM_HAL_MSPI_INT_CMDCMP);
                // Resume the CQ
                MSPIn(ui32Module)->CQSETCLEAR = AM_HAL_MSPI_SC_UNPAUSE_CQ;
            }
        }
        return AM_HAL_STATUS_SUCCESS;
    }
#endif
    //
    // Need to check if there is an ongoing transaction
    // This is needed because we may get interrupts even for the XIP transactions
    //
    if (pMSPIState->ui32NumCQEntries)
    {
#if MSPI_USE_CQ
        am_hal_cmdq_status_t status;
        uint32_t index;
        am_hal_mspi_CQ_t *pCQ = &g_MSPIState[ui32Module].CQ;

        //
        // Get the current and last indexes.
        //
        if (pCQ->pCmdQHdl)
        {
            ui32Status = am_hal_cmdq_get_status(pCQ->pCmdQHdl, &status);

            if (AM_HAL_STATUS_SUCCESS == ui32Status)
            {
                // For Sequence - this can be updated in the callback
                pMSPIState->bRestart = false;
                //
                // Figure out which callbacks need to be handled.
                //
                while (!pMSPIState->bRestart && (pMSPIState->ui32LastIdxProcessed != status.lastIdxProcessed))
                {

                    pMSPIState->ui32LastIdxProcessed++;
                    pMSPIState->ui32NumCQEntries--;
                    index = pMSPIState->ui32LastIdxProcessed & (AM_HAL_MSPI_MAX_CQ_ENTRIES - 1);
                    if ( pMSPIState->pfnCallback[index] != NULL )
                    {
                        pMSPIState->pfnCallback[index](pMSPIState->pCallbackCtxt[index], AM_HAL_STATUS_SUCCESS);
                        if (pMSPIState->eSeq != AM_HAL_MSPI_SEQ_RUNNING)
                        {
                            pMSPIState->pfnCallback[index] = NULL;
                        }
                    }
                }

                // For Sequence - this can be updated in the callback
                if (!pMSPIState->bRestart)
                {
                    //
                    // Process one extra callback if there was an error.
                    //
                    if ( (ui32IntStatus & AM_HAL_MSPI_INT_ERR) || (status.bErr) )
                    {
                        pMSPIState->ui32LastIdxProcessed++;
                        pMSPIState->ui32NumCQEntries--;
                        index = pMSPIState->ui32LastIdxProcessed & (AM_HAL_MSPI_MAX_CQ_ENTRIES - 1);
                        if ( pMSPIState->pfnCallback[index] != NULL )
                        {
                            pMSPIState->pfnCallback[index](pMSPIState->pCallbackCtxt[index], AM_HAL_STATUS_FAIL);
                            if (pMSPIState->eSeq != AM_HAL_MSPI_SEQ_RUNNING)
                            {
                                pMSPIState->pfnCallback[index] = NULL;
                            }
                        }
                        // Disable CQ
                        ui32Status = mspi_cq_disable(pMSPIState);
                        if (AM_HAL_STATUS_SUCCESS != ui32Status)
                        {
                          return ui32Status;
                        }
                        // Disable DMA
                        MSPIn(ui32Module)->DMACFG_b.DMAEN = 0;

                        // Must reset xfer block
                        MSPIn(ui32Module)->MSPICFG_b.IPRSTN = 0;  // in reset
                        MSPIn(ui32Module)->MSPICFG_b.IPRSTN = 1;  // back out -- clears current transfer

                        // Clear the CQ error.
                        MSPIn(ui32Module)->CQSTAT |= _VAL2FLD(MSPI_CQSTAT_CQERR, 0);
                        am_hal_cmdq_error_resume(pCQ->pCmdQHdl);
                        if (pMSPIState->ui32NumCQEntries)
                        {
                          // Re-enable CQ
                          ui32Status = mspi_cq_enable(pMSPIState);
                          if (AM_HAL_STATUS_SUCCESS != ui32Status)
                          {
                            return ui32Status;
                          }
                        }
                    }
                    if (pMSPIState->ui32NumCQEntries == 0)
                    {
                        // Disable CQ
                        ui32Status = mspi_cq_disable(pMSPIState);
                        if (AM_HAL_STATUS_SUCCESS != ui32Status)
                        {
                          return ui32Status;
                        }
                    }
                }
            }
        }
#else
        //
        // Accumulate the INTSTAT for this transaction
        //
        pMSPIState->ui32TxnInt |= ui32IntStatus;

        //
        // We need to wait for the DMA complete as well
        //
        if (pMSPIState->ui32TxnInt & (AM_HAL_MSPI_INT_DMACMP | AM_HAL_MSPI_INT_ERR))
        {
            uint32_t index;

            //
            // Wait for the command completion
            //
            if (!(pMSPIState->ui32TxnInt & AM_HAL_MSPI_INT_CMDCMP))
            {
                // May need to re-evaluate
                while (!MSPIn(ui32Module)->INTSTAT_b.CMDCMP);
            }
            pMSPIState->ui32TxnInt |= MSPIn(ui32Module)->INTSTAT;

            //
            // Clear the interrupt status
            //
            MSPIn(ui32Module)->INTCLR = AM_HAL_MSPI_INT_ALL;

            //
            // Need to determine the error, call the callback with proper status
            //
            if (pMSPIState->ui32TxnInt & AM_HAL_MSPI_INT_ERR)
            {
                ui32Status = AM_HAL_STATUS_FAIL;

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

                //
                // Must reset xfer block
                //
                MSPIn(ui32Module)->MSPICFG_b.IPRSTN = 0;  // in reset
                MSPIn(ui32Module)->MSPICFG_b.IPRSTN = 1;  // back out -- clears current transfer
            }
            else
            {
                ui32Status = AM_HAL_STATUS_SUCCESS;
            }

            pMSPIState->ui32LastIdxProcessed++;
            pMSPIState->ui32NumCQEntries--;
            index = pMSPIState->ui32LastIdxProcessed % pMSPIState->ui32MaxTransactions;

            //
            // Call the callback
            //
            if ( pMSPIState->pfnCallback[index] != NULL )
            {
                pMSPIState->pfnCallback[index](pMSPIState->pCallbackCtxt[index], ui32Status);
                pMSPIState->pfnCallback[index] = NULL;
            }

            //
            // Post next transaction if queue is not empty
            //
            if (pMSPIState->ui32NumCQEntries)
            {
                index = (pMSPIState->ui32LastIdxProcessed + 1) % pMSPIState->ui32MaxTransactions;

                pMSPIState->ui32TxnInt = 0;
                run_txn_cmdlist(&pMSPIState->pTransactions[index], sizeof(am_hal_mspi_cq_dma_entry_t) / sizeof(am_hal_cmdq_entry_t));
            }
        }

#endif // !MSPI_USE_CQ

        if (pMSPIState->ui32NumCQEntries == 0)
        {
            // Disable DMA
            MSPIn(ui32Module)->DMACFG_b.DMAEN = 0;
        }
    }

  //
  // Return the status.
  //
  return AM_HAL_STATUS_SUCCESS;
}