3589 lines
118 KiB
C
3589 lines
118 KiB
C
|
//*****************************************************************************
|
||
|
//
|
||
|
// am_hal_iom.c
|
||
|
//! @file
|
||
|
//!
|
||
|
//! @brief Functions for interfacing with IO Master serial (SPI/I2C) modules.
|
||
|
//!
|
||
|
//! @addtogroup iom3p
|
||
|
//! @ingroup apollo3phal
|
||
|
//! @{
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Copyright (c) 2020, Ambiq Micro
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// Redistribution and use in source and binary forms, with or without
|
||
|
// modification, are permitted provided that the following conditions are met:
|
||
|
//
|
||
|
// 1. Redistributions of source code must retain the above copyright notice,
|
||
|
// this list of conditions and the following disclaimer.
|
||
|
//
|
||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer in the
|
||
|
// documentation and/or other materials provided with the distribution.
|
||
|
//
|
||
|
// 3. Neither the name of the copyright holder nor the names of its
|
||
|
// contributors may be used to endorse or promote products derived from this
|
||
|
// software without specific prior written permission.
|
||
|
//
|
||
|
// Third party software included in this distribution is subject to the
|
||
|
// additional license terms as defined in the /docs/licenses directory.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
// POSSIBILITY OF SUCH DAMAGE.
|
||
|
//
|
||
|
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <stdbool.h>
|
||
|
#include "am_mcu_apollo.h"
|
||
|
|
||
|
#ifdef __IAR_SYSTEMS_ICC__
|
||
|
#define AM_INSTR_CLZ(n) __CLZ(n)
|
||
|
#else
|
||
|
#define AM_INSTR_CLZ(n) __builtin_clz(n)
|
||
|
#endif
|
||
|
|
||
|
#define MANUAL_POP 0
|
||
|
|
||
|
#define AM_HAL_MAGIC_IOM 0x123456
|
||
|
#define AM_HAL_IOM_CHK_HANDLE(h) ((h) && ((am_hal_handle_prefix_t *)(h))->s.bInit && (((am_hal_handle_prefix_t *)(h))->s.magic == AM_HAL_MAGIC_IOM))
|
||
|
|
||
|
// For IOM - Need to clear the flag for unpausing
|
||
|
#define AM_HAL_IOM_SC_PAUSE_CQ AM_HAL_IOM_SC_PAUSE(AM_HAL_IOM_PAUSE_FLAG_CQ)
|
||
|
#define AM_HAL_IOM_SC_PAUSE_SEQLOOP AM_HAL_IOM_SC_PAUSE(AM_HAL_IOM_PAUSE_FLAG_SEQLOOP)
|
||
|
#define AM_HAL_IOM_SC_UNPAUSE_CQ AM_HAL_IOM_SC_UNPAUSE(AM_HAL_IOM_PAUSE_FLAG_CQ)
|
||
|
#define AM_HAL_IOM_SC_UNPAUSE_SEQLOOP AM_HAL_IOM_SC_UNPAUSE(AM_HAL_IOM_PAUSE_FLAG_SEQLOOP)
|
||
|
#define AM_HAL_IOM_SC_PAUSE_BLOCK AM_HAL_IOM_SC_PAUSE(AM_HAL_IOM_PAUSE_FLAG_BLOCK)
|
||
|
#define AM_HAL_IOM_SC_UNPAUSE_BLOCK AM_HAL_IOM_SC_UNPAUSE(AM_HAL_IOM_PAUSE_FLAG_BLOCK)
|
||
|
|
||
|
// Max time to wait when attempting to pause the command queue
|
||
|
#define AM_HAL_IOM_MAX_PAUSE_DELAY (100*1000) // 100ms
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM interface clock selections
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_MIN_PWR 0x00000000
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_HFRC 0x00000100
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV2 0x00000200
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV4 0x00000300
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV8 0x00000400
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV16 0x00000500
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV32 0x00000600
|
||
|
#define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV64 0x00000700
|
||
|
|
||
|
//
|
||
|
// Only keep IOM interrupts we're interested in
|
||
|
//
|
||
|
// Necessary interrupts for respective modes
|
||
|
// For CQ - we rely only on the CQUPD interrupt
|
||
|
#define AM_HAL_IOM_INT_CQMODE (AM_HAL_IOM_INT_CQUPD | AM_HAL_IOM_INT_ERR)
|
||
|
// Need both CMDCMP & DCMP, as for Read we need to wait for DCMP after CMDCMP
|
||
|
#define AM_HAL_IOM_INT_DMAMODE (AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_ERR)
|
||
|
|
||
|
// Configures the interrupts to provided coniguration - clearing all pending interrupts
|
||
|
#define IOM_SET_INTEN(ui32Module, intCfg) \
|
||
|
do \
|
||
|
{ \
|
||
|
IOMn(ui32Module)->INTEN = 0; \
|
||
|
IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL; \
|
||
|
IOMn(ui32Module)->INTEN = (intCfg); \
|
||
|
} while (0);
|
||
|
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Private Types.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
|
||
|
//
|
||
|
// Command Queue entry structure.
|
||
|
//
|
||
|
typedef struct
|
||
|
{
|
||
|
uint32_t ui32PAUSENAddr;
|
||
|
uint32_t ui32PAUSEENVal;
|
||
|
uint32_t ui32PAUSEN2Addr;
|
||
|
uint32_t ui32PAUSEEN2Val;
|
||
|
uint32_t ui32OFFSETHIAddr;
|
||
|
uint32_t ui32OFFSETHIVal;
|
||
|
uint32_t ui32DEVCFGAddr;
|
||
|
uint32_t ui32DEVCFGVal;
|
||
|
uint32_t ui32DMACFGdis1Addr;
|
||
|
uint32_t ui32DMACFGdis1Val;
|
||
|
uint32_t ui32DMATOTCOUNTAddr;
|
||
|
uint32_t ui32DMATOTCOUNTVal;
|
||
|
uint32_t ui32DMATARGADDRAddr;
|
||
|
uint32_t ui32DMATARGADDRVal;
|
||
|
uint32_t ui32DMACFGAddr;
|
||
|
uint32_t ui32DMACFGVal;
|
||
|
uint32_t ui32DCXAddr;
|
||
|
uint32_t ui32DCXVal;
|
||
|
uint32_t ui32CMDAddr;
|
||
|
uint32_t ui32CMDVal;
|
||
|
uint32_t ui32SETCLRAddr;
|
||
|
uint32_t ui32SETCLRVal;
|
||
|
} am_hal_iom_txn_cmdlist_t;
|
||
|
|
||
|
//
|
||
|
// Command Queue entry structure for Sequence Repeat
|
||
|
//
|
||
|
typedef struct
|
||
|
{
|
||
|
uint32_t ui32PAUSENAddr;
|
||
|
uint32_t ui32PAUSEENVal;
|
||
|
uint32_t ui32PAUSEN2Addr;
|
||
|
uint32_t ui32PAUSEEN2Val;
|
||
|
uint32_t ui32SETCLRAddr;
|
||
|
uint32_t ui32SETCLRVal;
|
||
|
} am_hal_iom_cq_loop_entry_t;
|
||
|
|
||
|
#define AM_HAL_IOM_MAX_PENDING_TRANSACTIONS 256 // Must be power of 2 for the implementation below
|
||
|
#define AM_HAL_IOM_CQUPD_INT_FLAG (0x00000001)
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
bool bValid;
|
||
|
uint32_t regFIFOTHR;
|
||
|
uint32_t regDMATRIGEN;
|
||
|
uint32_t regCLKCFG;
|
||
|
uint32_t regSUBMODCTRL;
|
||
|
uint32_t regCQCFG;
|
||
|
uint32_t regCQADDR;
|
||
|
uint32_t regCQFLAGS;
|
||
|
uint32_t regCQPAUSEEN;
|
||
|
uint32_t regCQCURIDX;
|
||
|
uint32_t regCQENDIDX;
|
||
|
uint32_t regMSPICFG;
|
||
|
uint32_t regMI2CCFG;
|
||
|
uint32_t regINTEN;
|
||
|
} am_hal_iom_register_state_t;
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
AM_HAL_IOM_SEQ_NONE,
|
||
|
AM_HAL_IOM_SEQ_UNDER_CONSTRUCTION,
|
||
|
AM_HAL_IOM_SEQ_RUNNING,
|
||
|
} am_hal_iom_seq_e;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
uint32_t ui32OFFSETHIVal;
|
||
|
uint32_t ui32DEVCFGVal;
|
||
|
uint32_t ui32DMATOTCOUNTVal;
|
||
|
uint32_t ui32DMATARGADDRVal;
|
||
|
uint32_t ui32DMACFGVal;
|
||
|
uint32_t ui32CMDVal;
|
||
|
am_hal_iom_callback_t pfnCallback;
|
||
|
void *pCallbackCtxt;
|
||
|
} am_hal_iom_dma_entry_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
am_hal_handle_prefix_t prefix;
|
||
|
//
|
||
|
// Physical module number.
|
||
|
//
|
||
|
uint32_t ui32Module;
|
||
|
|
||
|
//
|
||
|
// Interface mode (SPI or I2C).
|
||
|
//
|
||
|
am_hal_iom_mode_e eInterfaceMode;
|
||
|
|
||
|
//
|
||
|
// Non-Blocking transaction Tranfer Control Buffer.
|
||
|
//
|
||
|
uint32_t *pNBTxnBuf;
|
||
|
uint32_t ui32NBTxnBufLength;
|
||
|
|
||
|
//
|
||
|
// Saves the user application defined interrupt configuration.
|
||
|
//
|
||
|
uint32_t ui32UserIntCfg;
|
||
|
|
||
|
//
|
||
|
// Saves the transaction interrupt state for non-blocking interrupt service.
|
||
|
//
|
||
|
uint32_t ui32TxnInt;
|
||
|
|
||
|
//
|
||
|
// Index of last non-blocking transaction processed in CQ.
|
||
|
//
|
||
|
uint32_t ui32LastIdxProcessed;
|
||
|
|
||
|
// Maximum number of transactions allowed in the CQ.
|
||
|
uint32_t ui32MaxTransactions;
|
||
|
|
||
|
//
|
||
|
// Number of pending transactions in the CQ.
|
||
|
//
|
||
|
volatile uint32_t ui32NumPendTransactions;
|
||
|
|
||
|
//
|
||
|
// Stores the CQ callbacks and contexts.
|
||
|
//
|
||
|
am_hal_iom_callback_t pfnCallback[AM_HAL_IOM_MAX_PENDING_TRANSACTIONS];
|
||
|
void *pCallbackCtxt[AM_HAL_IOM_MAX_PENDING_TRANSACTIONS];
|
||
|
|
||
|
//
|
||
|
// Handle to the CQ.
|
||
|
//
|
||
|
void *pCmdQHdl;
|
||
|
|
||
|
//
|
||
|
// To support sequence.
|
||
|
//
|
||
|
am_hal_iom_seq_e eSeq;
|
||
|
bool bAutonomous;
|
||
|
|
||
|
//
|
||
|
// This is used to track the number of transactions in a sequence.
|
||
|
//
|
||
|
uint32_t ui32NumSeqTransactions;
|
||
|
volatile bool bRestart;
|
||
|
uint32_t block;
|
||
|
|
||
|
//
|
||
|
// To support high priority transactions - out of band
|
||
|
// High Priority DMA transactions
|
||
|
//
|
||
|
volatile bool bHP;
|
||
|
uint32_t ui32NumHPEntries;
|
||
|
uint32_t ui32NumHPPendingEntries;
|
||
|
uint32_t ui32MaxHPTransactions;
|
||
|
uint32_t ui32NextHPIdx;
|
||
|
uint32_t ui32LastHPIdxProcessed;
|
||
|
am_hal_iom_dma_entry_t *pHPTransactions;
|
||
|
// Max pending transactions based on NB Buffer size
|
||
|
uint32_t ui32MaxPending;
|
||
|
// Number of back to back transactions with no callbacks
|
||
|
uint32_t ui32NumUnSolicited;
|
||
|
//
|
||
|
// Delay timeout value.
|
||
|
//
|
||
|
uint32_t waitTimeout;
|
||
|
|
||
|
//
|
||
|
// Configured clock time.
|
||
|
//
|
||
|
uint32_t ui32BitTimeTicks;
|
||
|
|
||
|
//
|
||
|
// IOM register state for power down save/restore.
|
||
|
//
|
||
|
am_hal_iom_register_state_t registerState;
|
||
|
uint8_t dcx[AM_HAL_IOM_MAX_CS_SPI + 1];
|
||
|
|
||
|
} am_hal_iom_state_t;
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Globals
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
am_hal_iom_state_t g_IOMhandles[AM_REG_IOM_NUM_MODULES];
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Internal Functions.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static uint32_t
|
||
|
get_pause_val(am_hal_iom_state_t *pIOMState, uint32_t pause)
|
||
|
{
|
||
|
uint32_t retval;
|
||
|
switch (pIOMState->block)
|
||
|
{
|
||
|
case 1:
|
||
|
// Pause the CQ till the whole block is built
|
||
|
retval = pause | AM_HAL_IOM_CQP_PAUSE_DEFAULT | AM_HAL_IOM_PAUSE_FLAG_BLOCK;
|
||
|
pIOMState->block = 2;
|
||
|
break;
|
||
|
case 2:
|
||
|
// No pausing allowed
|
||
|
retval = AM_HAL_IOM_PAUSE_DEFAULT;
|
||
|
break;
|
||
|
default: // case 0
|
||
|
retval = pause | AM_HAL_IOM_CQP_PAUSE_DEFAULT;
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Function to build the CMD value.
|
||
|
// Returns the CMD value, but does not set the CMD register.
|
||
|
//
|
||
|
// The OFFSETHI register must still be handled by the caller, e.g.
|
||
|
// AM_REGn(IOM, ui32Module, OFFSETHI) = (uint16_t)(ui32Offset >> 8);
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static uint32_t
|
||
|
build_cmd(uint32_t ui32CS, uint32_t ui32Dir, uint32_t ui32Cont,
|
||
|
uint32_t ui32Offset, uint32_t ui32OffsetCnt,
|
||
|
uint32_t ui32nBytes)
|
||
|
{
|
||
|
//
|
||
|
// Initialize the CMD variable
|
||
|
//
|
||
|
uint32_t ui32Cmd = 0;
|
||
|
|
||
|
//
|
||
|
// If SPI, we'll need the chip select
|
||
|
//
|
||
|
ui32Cmd |= _VAL2FLD(IOM0_CMD_CMDSEL, ui32CS);
|
||
|
|
||
|
//
|
||
|
// Build the CMD with number of bytes and direction.
|
||
|
//
|
||
|
ui32Cmd |= _VAL2FLD(IOM0_CMD_TSIZE, ui32nBytes);
|
||
|
|
||
|
if (ui32Dir == AM_HAL_IOM_RX)
|
||
|
{
|
||
|
ui32Cmd |= _VAL2FLD(IOM0_CMD_CMD, IOM0_CMD_CMD_READ);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui32Cmd |= _VAL2FLD(IOM0_CMD_CMD, IOM0_CMD_CMD_WRITE);
|
||
|
}
|
||
|
|
||
|
ui32Cmd |= _VAL2FLD(IOM0_CMD_CONT, ui32Cont);
|
||
|
|
||
|
//
|
||
|
// Now add the OFFSETLO and OFFSETCNT information.
|
||
|
//
|
||
|
ui32Cmd |= _VAL2FLD(IOM0_CMD_OFFSETLO, (uint8_t)ui32Offset);
|
||
|
ui32Cmd |= _VAL2FLD(IOM0_CMD_OFFSETCNT, ui32OffsetCnt);
|
||
|
|
||
|
return ui32Cmd;
|
||
|
} // build_cmd()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Function to build CMD lists.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static void
|
||
|
build_txn_cmdlist(am_hal_iom_state_t *pIOMState,
|
||
|
am_hal_iom_txn_cmdlist_t *pCQEntry,
|
||
|
am_hal_iom_transfer_t *psTransaction)
|
||
|
{
|
||
|
uint32_t ui32Cmd;
|
||
|
uint32_t ui32Module = pIOMState->ui32Module;
|
||
|
uint32_t ui32Dir = psTransaction->eDirection;
|
||
|
uint32_t ui32DMAAddress;
|
||
|
|
||
|
//
|
||
|
// Command for OFFSETHI
|
||
|
//
|
||
|
pCQEntry->ui32OFFSETHIAddr = (uint32_t)&IOMn(ui32Module)->OFFSETHI;
|
||
|
|
||
|
pCQEntry->ui32OFFSETHIVal = (uint16_t)(psTransaction->ui32Instr >> 8);
|
||
|
|
||
|
//
|
||
|
// Command for I2C DEVADDR field in DEVCFG
|
||
|
//
|
||
|
pCQEntry->ui32DEVCFGAddr = (uint32_t)&IOMn(ui32Module)->DEVCFG;
|
||
|
pCQEntry->ui32DEVCFGVal = _VAL2FLD(IOM0_DEVCFG_DEVADDR, psTransaction->uPeerInfo.ui32I2CDevAddr);
|
||
|
|
||
|
//
|
||
|
// Command to disable DMA before writing TOTCOUNT.
|
||
|
//
|
||
|
pCQEntry->ui32DMACFGdis1Addr = (uint32_t)&IOMn(ui32Module)->DMACFG;
|
||
|
pCQEntry->ui32DMACFGdis1Val = 0x0;
|
||
|
|
||
|
//
|
||
|
// Command to set DMATOTALCOUNT
|
||
|
//
|
||
|
pCQEntry->ui32DMATOTCOUNTAddr = (uint32_t)&IOMn(ui32Module)->DMATOTCOUNT;
|
||
|
pCQEntry->ui32DMATOTCOUNTVal = psTransaction->ui32NumBytes;
|
||
|
|
||
|
//
|
||
|
// Command to set DMATARGADDR
|
||
|
//
|
||
|
pCQEntry->ui32DMATARGADDRAddr = (uint32_t)&IOMn(ui32Module)->DMATARGADDR;
|
||
|
ui32DMAAddress = (ui32Dir == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
|
||
|
pCQEntry->ui32DMATARGADDRVal = ui32DMAAddress;
|
||
|
|
||
|
//
|
||
|
// Command to set DMACFG to start the DMA operation
|
||
|
//
|
||
|
pCQEntry->ui32DMACFGAddr = (uint32_t)&IOMn(ui32Module)->DMACFG;
|
||
|
pCQEntry->ui32DMACFGVal =
|
||
|
_VAL2FLD(IOM0_DMACFG_DMAPRI, psTransaction->ui8Priority) |
|
||
|
_VAL2FLD(IOM0_DMACFG_DMADIR, ui32Dir == AM_HAL_IOM_TX ? 1 : 0);
|
||
|
|
||
|
if (psTransaction->ui32NumBytes)
|
||
|
{
|
||
|
pCQEntry->ui32DMACFGVal |= IOM0_DMACFG_DMAEN_Msk;
|
||
|
}
|
||
|
|
||
|
// CMDRPT register has been repurposed for DCX
|
||
|
pCQEntry->ui32DCXAddr = (uint32_t)&IOMn(ui32Module)->DCX;
|
||
|
pCQEntry->ui32DCXVal = (pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) ? pIOMState->dcx[psTransaction->uPeerInfo.ui32SpiChipSelect] : 0;
|
||
|
//
|
||
|
// Command to start the transfer.
|
||
|
//
|
||
|
ui32Cmd = pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE ?
|
||
|
psTransaction->uPeerInfo.ui32SpiChipSelect : 0;
|
||
|
ui32Cmd = build_cmd(ui32Cmd, // ChipSelect
|
||
|
ui32Dir, // ui32Dir
|
||
|
psTransaction->bContinue, // ui32Cont
|
||
|
psTransaction->ui32Instr, // ui32Offset
|
||
|
psTransaction->ui32InstrLen, // ui32OffsetCnt
|
||
|
psTransaction->ui32NumBytes); // ui32Bytes
|
||
|
|
||
|
pCQEntry->ui32CMDAddr = (uint32_t)&IOMn(ui32Module)->CMD;
|
||
|
pCQEntry->ui32CMDVal = ui32Cmd;
|
||
|
|
||
|
pCQEntry->ui32PAUSENAddr = pCQEntry->ui32PAUSEN2Addr = (uint32_t)&IOMn(ui32Module)->CQPAUSEEN;
|
||
|
pCQEntry->ui32PAUSEEN2Val = AM_HAL_IOM_PAUSE_DEFAULT;
|
||
|
pCQEntry->ui32PAUSEENVal = get_pause_val(pIOMState, psTransaction->ui32PauseCondition);
|
||
|
pCQEntry->ui32SETCLRVal = psTransaction->ui32StatusSetClr;
|
||
|
pCQEntry->ui32SETCLRAddr = (uint32_t)&IOMn(ui32Module)->CQSETCLEAR;
|
||
|
|
||
|
} // build_txn_cmdlist()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// enable_submodule() - Utilizes the built-in fields that indicate whether which
|
||
|
// submodule is supported, then enables that submodule.
|
||
|
//
|
||
|
// Input: ui32Type = 0, set for SPI.
|
||
|
// ui32Type = 1, set for I2C.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static void
|
||
|
enable_submodule(uint32_t ui32Module, uint32_t ui32Type)
|
||
|
{
|
||
|
if ( IOMn(ui32Module)->SUBMODCTRL_b.SMOD0TYPE == ui32Type )
|
||
|
{
|
||
|
IOMn(ui32Module)->SUBMODCTRL =
|
||
|
_VAL2FLD(IOM0_SUBMODCTRL_SMOD1EN, 0) |
|
||
|
_VAL2FLD(IOM0_SUBMODCTRL_SMOD0EN, 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IOMn(ui32Module)->SUBMODCTRL =
|
||
|
_VAL2FLD(IOM0_SUBMODCTRL_SMOD1EN, 1) |
|
||
|
_VAL2FLD(IOM0_SUBMODCTRL_SMOD0EN, 0);
|
||
|
}
|
||
|
} // enable_submodule()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Error handling.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
internal_iom_get_int_err(uint32_t ui32Module, uint32_t ui32IntStatus)
|
||
|
{
|
||
|
//
|
||
|
// Map the INTSTAT bits for transaction status
|
||
|
//
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
//
|
||
|
// Let's accumulate the errors
|
||
|
//
|
||
|
ui32IntStatus |= IOMn(ui32Module)->INTSTAT;
|
||
|
|
||
|
if (ui32IntStatus & AM_HAL_IOM_INT_SWERR)
|
||
|
{
|
||
|
// Error in hardware command issued or illegal access by SW
|
||
|
ui32Status = AM_HAL_IOM_ERR_INVALID_OPER;
|
||
|
}
|
||
|
else if (ui32IntStatus & AM_HAL_IOM_INT_I2CARBERR)
|
||
|
{
|
||
|
// Loss of I2C multi-master arbitration
|
||
|
ui32Status = AM_HAL_IOM_ERR_I2C_ARB;
|
||
|
}
|
||
|
else if (ui32IntStatus & AM_HAL_IOM_INT_NAK)
|
||
|
{
|
||
|
// I2C NAK
|
||
|
ui32Status = AM_HAL_IOM_ERR_I2C_NAK;
|
||
|
}
|
||
|
else if (ui32IntStatus & AM_HAL_IOM_INT_INTERR)
|
||
|
{
|
||
|
// Other Error
|
||
|
ui32Status = AM_HAL_STATUS_FAIL;
|
||
|
}
|
||
|
|
||
|
return ui32Status;
|
||
|
|
||
|
} // internal_iom_get_int_err()
|
||
|
|
||
|
static void
|
||
|
internal_iom_reset_on_error(am_hal_iom_state_t *pIOMState, uint32_t ui32IntMask)
|
||
|
{
|
||
|
uint32_t iterationsToWait = 2 * pIOMState->ui32BitTimeTicks; // effectively > 6 clocks
|
||
|
uint32_t ui32Module = pIOMState->ui32Module;
|
||
|
uint32_t curIntCfg = IOMn(ui32Module)->INTEN;
|
||
|
IOMn(ui32Module)->INTEN = 0;
|
||
|
|
||
|
// Disable interrupts temporarily
|
||
|
if (ui32IntMask & AM_HAL_IOM_INT_DERR)
|
||
|
{
|
||
|
if ((IOMn(ui32Module)->DMACFG & IOM0_DMACFG_DMADIR_Msk) == _VAL2FLD(IOM0_DMACFG_DMADIR, IOM0_DMACFG_DMADIR_M2P))
|
||
|
{
|
||
|
// Write
|
||
|
uint32_t dummy = 0xDEADBEEF;
|
||
|
uint32_t numBytesRemaining = IOMn(ui32Module)->DMATOTCOUNT;
|
||
|
|
||
|
while (numBytesRemaining)
|
||
|
{
|
||
|
if (IOMn(ui32Module)->FIFOPTR_b.FIFO0REM >= 4)
|
||
|
{
|
||
|
// Write one 4-byte word to FIFO
|
||
|
IOMn(ui32Module)->FIFOPUSH = dummy;
|
||
|
if (numBytesRemaining > 4)
|
||
|
{
|
||
|
numBytesRemaining -= 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Now wait for command to finish
|
||
|
while ((IOMn(ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Read
|
||
|
// Let command finish
|
||
|
while (IOMn(ui32Module)->STATUS_b.CMDACT)
|
||
|
{
|
||
|
while (IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ >= 4)
|
||
|
{
|
||
|
// Read one 4-byte word from FIFO
|
||
|
IOMn(ui32Module)->FIFOPOP;
|
||
|
#if MANUAL_POP
|
||
|
IOMn(ui32Module)->FIFOPOP = 0x11111111;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
// Now wait for command to finish
|
||
|
while ((IOMn(ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk);
|
||
|
// Flush any remaining data from FIFO
|
||
|
while (IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ)
|
||
|
{
|
||
|
while (IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ >= 4)
|
||
|
{
|
||
|
// Read one 4-byte word from FIFO
|
||
|
IOMn(ui32Module)->FIFOPOP;
|
||
|
#if MANUAL_POP
|
||
|
IOMn(ui32Module)->FIFOPOP = 0x11111111;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (ui32IntMask & AM_HAL_IOM_INT_NAK)
|
||
|
{
|
||
|
//
|
||
|
// Wait for Idle
|
||
|
//
|
||
|
while ((IOMn(ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk);
|
||
|
|
||
|
//
|
||
|
// Reset Submodule & FIFO
|
||
|
//
|
||
|
// Disable the submodules
|
||
|
//
|
||
|
IOMn(ui32Module)->SUBMODCTRL_b.SMOD1EN = 0;
|
||
|
// Reset Fifo
|
||
|
IOMn(ui32Module)->FIFOCTRL_b.FIFORSTN = 0;
|
||
|
|
||
|
// Wait for few IO clock cycles
|
||
|
am_hal_flash_delay(iterationsToWait);
|
||
|
|
||
|
IOMn(ui32Module)->FIFOCTRL_b.FIFORSTN = 1;
|
||
|
|
||
|
// Enable submodule
|
||
|
IOMn(ui32Module)->SUBMODCTRL_b.SMOD1EN = 1;
|
||
|
}
|
||
|
|
||
|
IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
|
||
|
|
||
|
// Restore interrupts
|
||
|
IOMn(ui32Module)->INTEN = curIntCfg;
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
// compute_freq()
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Compute the interface frequency based on the given parameters
|
||
|
//
|
||
|
static uint32_t
|
||
|
compute_freq(uint32_t ui32HFRCfreqHz,
|
||
|
uint32_t ui32Fsel, uint32_t ui32Div3,
|
||
|
uint32_t ui32DivEn, uint32_t ui32TotPer)
|
||
|
{
|
||
|
uint32_t ui32Denomfinal, ui32ClkFreq;
|
||
|
|
||
|
ui32Denomfinal = ((1 << (ui32Fsel - 1)) * (1 + ui32Div3 * 2) * (1 + ui32DivEn * (ui32TotPer)));
|
||
|
ui32ClkFreq = (ui32HFRCfreqHz) / ui32Denomfinal; // Compute the set frequency value
|
||
|
ui32ClkFreq += (((ui32HFRCfreqHz) % ui32Denomfinal) > (ui32Denomfinal / 2)) ? 1 : 0;
|
||
|
|
||
|
return ui32ClkFreq;
|
||
|
} // compute_freq()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
// onebit()
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// A power of 2?
|
||
|
// Return true if ui32Value has exactly 1 bit set, otherwise false.
|
||
|
//
|
||
|
static bool
|
||
|
onebit(uint32_t ui32Value)
|
||
|
{
|
||
|
return ui32Value && !(ui32Value & (ui32Value - 1));
|
||
|
} // onebit()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// iom_get_interface_clock_cfg()
|
||
|
//
|
||
|
// Returns the proper settings for the CLKCFG register.
|
||
|
//
|
||
|
// ui32FreqHz - The desired interface frequency in Hz.
|
||
|
//
|
||
|
// Given a desired serial interface clock frequency, this function computes
|
||
|
// the appropriate settings for the various fields in the CLKCFG register
|
||
|
// and returns the 32-bit value that should be written to that register.
|
||
|
// The actual interface frequency may be slightly lower than the specified
|
||
|
// frequency, but the actual frequency is also returned.
|
||
|
//
|
||
|
// Note A couple of criteria that this algorithm follow are:
|
||
|
// 1. For power savings, choose the highest FSEL possible.
|
||
|
// 2. Use DIV3 when possible rather than DIVEN.
|
||
|
//
|
||
|
// Return An unsigned 64-bit value.
|
||
|
// The lower 32-bits represent the value to use to set CLKCFG.
|
||
|
// The upper 32-bits represent the actual frequency (in Hz) that will result
|
||
|
// from setting CLKCFG with the lower 32-bits.
|
||
|
//
|
||
|
// 0 (64 bits) = error. Note that the caller must check the entire 64 bits.
|
||
|
// It is not an error if only the low 32-bits are 0 (this is a valid value).
|
||
|
// But the entire 64 bits returning 0 is an error.
|
||
|
//!
|
||
|
//*****************************************************************************
|
||
|
static
|
||
|
uint64_t iom_get_interface_clock_cfg(uint32_t ui32FreqHz, uint32_t ui32Phase )
|
||
|
{
|
||
|
uint32_t ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer, ui32LowPer;
|
||
|
uint32_t ui32Denom, ui32v1, ui32Denomfinal, ui32ClkFreq, ui32ClkCfg;
|
||
|
uint32_t ui32HFRCfreqHz;
|
||
|
int32_t i32Div, i32N;
|
||
|
|
||
|
if ( ui32FreqHz == 0 )
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the HFRC clock frequency.
|
||
|
//
|
||
|
ui32HFRCfreqHz = AM_HAL_CLKGEN_FREQ_MAX_HZ;
|
||
|
|
||
|
//
|
||
|
// Compute various parameters used for computing the optimal CLKCFG setting.
|
||
|
//
|
||
|
i32Div = (ui32HFRCfreqHz / ui32FreqHz) + ((ui32HFRCfreqHz % ui32FreqHz) ? 1 : 0); // Round up (ceiling)
|
||
|
|
||
|
//
|
||
|
// Compute N (count the number of LS zeros of Div) = ctz(Div) = log2(Div & (-Div))
|
||
|
//
|
||
|
i32N = 31 - AM_INSTR_CLZ((i32Div & (-i32Div)));
|
||
|
|
||
|
if ( i32N > 6 )
|
||
|
{
|
||
|
i32N = 6;
|
||
|
}
|
||
|
|
||
|
ui32Div3 = ( (ui32FreqHz < (ui32HFRCfreqHz / 16384)) ||
|
||
|
( ((ui32FreqHz >= (ui32HFRCfreqHz / 3)) &&
|
||
|
(ui32FreqHz <= ((ui32HFRCfreqHz / 2) - 1)) ) ) ) ? 1 : 0;
|
||
|
ui32Denom = ( 1 << i32N ) * ( 1 + (ui32Div3 * 2) );
|
||
|
ui32TotPer = i32Div / ui32Denom;
|
||
|
ui32TotPer += (i32Div % ui32Denom) ? 1 : 0;
|
||
|
ui32v1 = 31 - AM_INSTR_CLZ(ui32TotPer); // v1 = log2(TotPer)
|
||
|
ui32Fsel = (ui32v1 > 7) ? ui32v1 + i32N - 7 : i32N;
|
||
|
ui32Fsel++;
|
||
|
|
||
|
if ( ui32Fsel > 7 )
|
||
|
{
|
||
|
//
|
||
|
// This is an error, can't go that low.
|
||
|
//
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if ( ui32v1 > 7 )
|
||
|
{
|
||
|
ui32DivEn = ui32TotPer; // Save TotPer for the round up calculation
|
||
|
ui32TotPer = ui32TotPer>>(ui32v1-7);
|
||
|
ui32TotPer += ((ui32DivEn) % (1 << (ui32v1 - 7))) ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
ui32DivEn = ( (ui32FreqHz >= (ui32HFRCfreqHz / 4)) ||
|
||
|
((1 << (ui32Fsel - 1)) == i32Div) ) ? 0 : 1;
|
||
|
|
||
|
if (ui32Phase == 1)
|
||
|
{
|
||
|
ui32LowPer = (ui32TotPer - 2) / 2; // Longer high phase
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui32LowPer = (ui32TotPer - 1) / 2; // Longer low phase
|
||
|
}
|
||
|
|
||
|
ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_FSEL, ui32Fsel) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIV3, ui32Div3) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIVEN, ui32DivEn) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_LOWPER, ui32LowPer) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_TOTPER, ui32TotPer - 1);
|
||
|
|
||
|
//
|
||
|
// Now, compute the actual frequency, which will be returned.
|
||
|
//
|
||
|
ui32ClkFreq = compute_freq(ui32HFRCfreqHz, ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer - 1);
|
||
|
|
||
|
//
|
||
|
// Determine if the actual frequency is a power of 2 (MHz).
|
||
|
//
|
||
|
if ( (ui32ClkFreq % 250000) == 0 )
|
||
|
{
|
||
|
//
|
||
|
// If the actual clock frequency is a power of 2 ranging from 250KHz up,
|
||
|
// we can simplify the CLKCFG value using DIV3 (which also results in a
|
||
|
// better duty cycle).
|
||
|
//
|
||
|
ui32Denomfinal = ui32ClkFreq / (uint32_t)250000;
|
||
|
|
||
|
if ( onebit(ui32Denomfinal) )
|
||
|
{
|
||
|
//
|
||
|
// These configurations can be simplified by using DIV3. Configs
|
||
|
// using DIV3 have a 50% duty cycle, while those from DIVEN will
|
||
|
// have a 66/33 duty cycle.
|
||
|
//
|
||
|
ui32TotPer = ui32LowPer = ui32DivEn = 0;
|
||
|
ui32Div3 = 1;
|
||
|
|
||
|
//
|
||
|
// Now, compute the return values.
|
||
|
//
|
||
|
ui32ClkFreq = compute_freq(ui32HFRCfreqHz, ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer);
|
||
|
|
||
|
ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_FSEL, ui32Fsel) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIV3, 1) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIVEN, 0) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_LOWPER, 0) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_TOTPER, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ( ((uint64_t)ui32ClkFreq) << 32) | (uint64_t)ui32ClkCfg;
|
||
|
|
||
|
} //iom_get_interface_clock_cfg()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Initializes the IOM Command Queue.
|
||
|
//!
|
||
|
//! @param handle - handle for the interface.
|
||
|
//! @param ui32Length - length of the SRAM Command Queue buffer in words.
|
||
|
//! @param pTCB - pointer to the SRAM to use for the Command Queue.
|
||
|
//!
|
||
|
//! This function initializes the global command queue structure.
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_CQInit(void *pHandle, uint32_t ui32Length,
|
||
|
uint32_t *pTCB)
|
||
|
{
|
||
|
am_hal_cmdq_cfg_t cqCfg;
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
uint32_t ui32Module = pIOMState->ui32Module;
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
pIOMState->pCmdQHdl = NULL;
|
||
|
pIOMState->ui32MaxTransactions = 0;
|
||
|
pIOMState->ui32NumUnSolicited = 0;
|
||
|
|
||
|
cqCfg.pCmdQBuf = pTCB;
|
||
|
cqCfg.cmdQSize = ui32Length / 2;
|
||
|
cqCfg.priority = AM_HAL_CMDQ_PRIO_HI;
|
||
|
ui32Status = am_hal_cmdq_init((am_hal_cmdq_if_e)(AM_HAL_CMDQ_IF_IOM0 + ui32Module),
|
||
|
&cqCfg, &pIOMState->pCmdQHdl);
|
||
|
if (ui32Status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
pIOMState->ui32MaxTransactions = AM_HAL_IOM_MAX_PENDING_TRANSACTIONS;
|
||
|
}
|
||
|
return ui32Status;
|
||
|
} // am_hal_iom_CQInit()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Resets the IOM Command Queue.
|
||
|
//!
|
||
|
//! @param ui32Module - IOM instance.
|
||
|
//!
|
||
|
//! This function resets the global command queue structure.
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_IOM_CQReset(void *pHandle)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
|
||
|
if (pIOMState->pCmdQHdl)
|
||
|
{
|
||
|
am_hal_cmdq_term(pIOMState->pCmdQHdl, true);
|
||
|
pIOMState->pCmdQHdl = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
} // am_hal_IOM_CQReset()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Adds a transaction the IOM Command Queue.
|
||
|
//!
|
||
|
//! @param handle - handle for the interface.
|
||
|
//! @param pTransaction - transaction to add to the CQ
|
||
|
//! @param pfnCallback - pointer the callback function to be executed when
|
||
|
//! transaction is complete.
|
||
|
//!
|
||
|
//! This function copies data from the IOM FIFO into the array \e pui32Data.
|
||
|
//! This is how input data from SPI or I2C transactions may be retrieved.
|
||
|
//!
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_CQAddTransaction(void *pHandle,
|
||
|
am_hal_iom_transfer_t *psTransaction,
|
||
|
am_hal_iom_callback_t pfnCallback,
|
||
|
void *pCallbackCtxt)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
am_hal_iom_txn_cmdlist_t *pCQEntry;
|
||
|
am_hal_cmdq_entry_t *pCQBlock;
|
||
|
uint32_t index;
|
||
|
|
||
|
//
|
||
|
// Check to see if there is enough room in the CQ
|
||
|
//
|
||
|
if ((pIOMState->ui32NumPendTransactions == AM_HAL_IOM_MAX_PENDING_TRANSACTIONS) ||
|
||
|
(am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, sizeof(am_hal_iom_txn_cmdlist_t) / 8, &pCQBlock, &index)))
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
|
||
|
pCQEntry = (am_hal_iom_txn_cmdlist_t *)pCQBlock;
|
||
|
|
||
|
build_txn_cmdlist(pIOMState, pCQEntry, psTransaction);
|
||
|
|
||
|
//
|
||
|
// Because we set AM_HAL_IOM_CQUPD_INT_FLAG, an interrupt will occur once
|
||
|
// we reach this point in the Command Queue. In the service routine, we'll
|
||
|
// look for the appropriate callback.
|
||
|
//
|
||
|
// If ENDIDX has been reached, the CQ will pause here. Otherwise will
|
||
|
// continue with the next CQ entry.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Store the callback function pointer.
|
||
|
//
|
||
|
pIOMState->pfnCallback[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pfnCallback;
|
||
|
pIOMState->pCallbackCtxt[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pCallbackCtxt;
|
||
|
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
} // am_hal_iom_CQAddTransaction()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Enable the Command Queue operation.
|
||
|
//!
|
||
|
//! @param handle - handle for the interface.
|
||
|
//!
|
||
|
//! This function enables Command Queue operation.
|
||
|
//!
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_CQEnable(void *pHandle)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
|
||
|
if (0 == pIOMState->ui32NumPendTransactions)
|
||
|
{
|
||
|
uint32_t *pCqAddr = (uint32_t *)IOMn(pIOMState->ui32Module)->CQADDR;
|
||
|
// When CQ is enabled with nothing there - it always executes the first command
|
||
|
// insert dummy command
|
||
|
*pCqAddr = (uint32_t) &IOMn(pIOMState->ui32Module)->CQADDR;
|
||
|
*(pCqAddr + 1) = (uint32_t)pCqAddr;
|
||
|
}
|
||
|
//
|
||
|
// Enable the Command Queue operation
|
||
|
//
|
||
|
return am_hal_cmdq_enable(pIOMState->pCmdQHdl);
|
||
|
|
||
|
} // am_hal_iom_CQEnable()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Disable the Command Queue operation.
|
||
|
//!
|
||
|
//! @param handle - handle for the interface.
|
||
|
//!
|
||
|
//! This function disables the Command Queue operation.
|
||
|
//!
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_CQDisable(void *pHandle)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
|
||
|
//
|
||
|
// Disable the Command Queue operation
|
||
|
//
|
||
|
return am_hal_cmdq_disable(pIOMState->pCmdQHdl);
|
||
|
} // am_hal_iom_CQDisable()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Dummy Callback.
|
||
|
//!
|
||
|
//*****************************************************************************
|
||
|
static void iom_dummy_callback(void *pCallbackCtxt, uint32_t status)
|
||
|
{
|
||
|
// Dummy - Do nothing
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Callback when end of sequence is reached.
|
||
|
//!
|
||
|
//*****************************************************************************
|
||
|
static void iom_seq_loopback(void *pCallbackCtxt, uint32_t status)
|
||
|
{
|
||
|
// Reset the state to allow serving callbacks for next set
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pCallbackCtxt;
|
||
|
pIOMState->ui32NumPendTransactions = pIOMState->ui32NumSeqTransactions + 1;
|
||
|
pIOMState->ui32LastIdxProcessed = 0;
|
||
|
pIOMState->bRestart = true;
|
||
|
// Now resume the CQ - to finish loopback
|
||
|
// Resume the CQ
|
||
|
IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_SEQLOOP;
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Pause the Command Queue.
|
||
|
//!
|
||
|
//! @param pIOMState - pointer to the IOM internal state.
|
||
|
//!
|
||
|
//! This function pauses the Command Queue operation.
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static uint32_t iom_cq_pause(am_hal_iom_state_t *pIOMState)
|
||
|
{
|
||
|
uint32_t status = AM_HAL_STATUS_SUCCESS;
|
||
|
uint32_t ui32usMaxDelay = AM_HAL_IOM_MAX_PAUSE_DELAY;
|
||
|
// Pause the CQ
|
||
|
IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_PAUSE_CQ;
|
||
|
// It is possible that CQ is disabled once the last transaction is processed
|
||
|
while ( IOMn(pIOMState->ui32Module)->CQCFG_b.CQEN )
|
||
|
{
|
||
|
// Need to make sure we're paused at a designated pause point
|
||
|
if ( IOMn(pIOMState->ui32Module)->CQSTAT_b.CQPAUSED && (IOMn(pIOMState->ui32Module)->CQPAUSEEN & AM_HAL_IOM_PAUSE_FLAG_CQ) )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if ( ui32usMaxDelay-- )
|
||
|
{
|
||
|
//
|
||
|
// Call the BOOTROM cycle function to delay for about 1 microsecond.
|
||
|
//
|
||
|
am_hal_flash_delay( FLASH_CYCLES_US(1) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return AM_HAL_STATUS_TIMEOUT;
|
||
|
}
|
||
|
}
|
||
|
if (status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
// Now that CQ is guaranteed to not progress further - we need to still wait in case the current CQ entry
|
||
|
// resulted in a DMA state....need to make sure we finish the current DMA
|
||
|
status = am_hal_flash_delay_status_check(AM_HAL_IOM_MAX_PAUSE_DELAY,
|
||
|
(uint32_t)&IOMn(pIOMState->ui32Module)->DMASTAT,
|
||
|
IOM0_DMASTAT_DMATIP_Msk,
|
||
|
_VAL2FLD(IOM0_DMASTAT_DMATIP, 0),
|
||
|
true);
|
||
|
|
||
|
}
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Program the DMA directly.
|
||
|
//!
|
||
|
//! @param pHandle - pointer the IOM instance handle.
|
||
|
//!
|
||
|
//! This function pauses the Command Queue operation.
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static void
|
||
|
program_dma(void *pHandle)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
uint32_t ui32Module = pIOMState->ui32Module;
|
||
|
uint32_t index = (pIOMState->ui32LastHPIdxProcessed + 1) % pIOMState->ui32MaxHPTransactions;
|
||
|
am_hal_iom_dma_entry_t *pDMAEntry = &pIOMState->pHPTransactions[index];
|
||
|
|
||
|
//
|
||
|
// OFFSETHI
|
||
|
//
|
||
|
IOMn(ui32Module)->OFFSETHI = pDMAEntry->ui32OFFSETHIVal;
|
||
|
|
||
|
//
|
||
|
// I2C DEVADDR field in DEVCFG
|
||
|
//
|
||
|
IOMn(ui32Module)->DEVCFG = pDMAEntry->ui32DEVCFGVal;
|
||
|
|
||
|
//
|
||
|
// disable DMA before writing TOTCOUNT.
|
||
|
//
|
||
|
IOMn(ui32Module)->DMACFG = 0x0;
|
||
|
|
||
|
//
|
||
|
// set DMATOTALCOUNT
|
||
|
//
|
||
|
IOMn(ui32Module)->DMATOTCOUNT = pDMAEntry->ui32DMATOTCOUNTVal;
|
||
|
|
||
|
//
|
||
|
// set DMATARGADDR
|
||
|
//
|
||
|
IOMn(ui32Module)->DMATARGADDR = pDMAEntry->ui32DMATARGADDRVal;
|
||
|
|
||
|
//
|
||
|
// Command to set DMACFG to start the DMA operation
|
||
|
//
|
||
|
IOMn(ui32Module)->DMACFG = pDMAEntry->ui32DMACFGVal;
|
||
|
//
|
||
|
// Command to start the transfer.
|
||
|
//
|
||
|
IOMn(ui32Module)->CMD = pDMAEntry->ui32CMDVal;
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Schedule a high priority transaction.
|
||
|
//!
|
||
|
//! @param pIOMState - pointer to the IOM internal state.
|
||
|
//! @param numTrans - number of transaction to schedule in a block.
|
||
|
//!
|
||
|
//! This function pauses the Command Queue operation.
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static uint32_t
|
||
|
sched_hiprio(am_hal_iom_state_t *pIOMState, uint32_t numTrans)
|
||
|
{
|
||
|
uint32_t ui32NumPend;
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
//
|
||
|
// Start a critical section.
|
||
|
//
|
||
|
AM_CRITICAL_BEGIN
|
||
|
|
||
|
ui32NumPend = pIOMState->ui32NumHPEntries;
|
||
|
pIOMState->ui32NumHPEntries += numTrans;
|
||
|
|
||
|
//
|
||
|
// End the critical section.
|
||
|
//
|
||
|
AM_CRITICAL_END
|
||
|
|
||
|
|
||
|
if (0 == ui32NumPend)
|
||
|
{
|
||
|
// Force CQ to Pause
|
||
|
ui32Status = iom_cq_pause(pIOMState);
|
||
|
if (ui32Status != AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
pIOMState->ui32TxnInt = 0;
|
||
|
// Clear & Enable DMACMP interrupt
|
||
|
IOMn(pIOMState->ui32Module)->INTCLR = AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP;
|
||
|
IOMn(pIOMState->ui32Module)->INTEN |= AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP;
|
||
|
pIOMState->bHP = true;
|
||
|
//
|
||
|
// Program the DMA
|
||
|
//
|
||
|
program_dma(pIOMState);
|
||
|
}
|
||
|
return ui32Status;
|
||
|
} // sched_hiprio()
|
||
|
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Add a high priority transaction.
|
||
|
//!
|
||
|
//! @param pHandle - pointer the IOM instance handle.
|
||
|
//! @param psTransaction - pointer to IOM transaction.
|
||
|
//! @param pfnCallback - pointer to the callback for transaction (could be NULL).
|
||
|
//! @param pCallbackCtxt - pointer to the context to the callback (could be NULL).
|
||
|
//!
|
||
|
//! This function adds a function to the internal high priority transaction queue.
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static uint32_t
|
||
|
iom_add_hp_transaction(void *pHandle,
|
||
|
am_hal_iom_transfer_t *psTransaction,
|
||
|
am_hal_iom_callback_t pfnCallback,
|
||
|
void *pCallbackCtxt)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
am_hal_iom_dma_entry_t *pDMAEntry;
|
||
|
uint32_t ui32Dir = psTransaction->eDirection;
|
||
|
uint32_t ui32SRAMAddress;
|
||
|
|
||
|
uint32_t index = pIOMState->ui32NextHPIdx % pIOMState->ui32MaxHPTransactions;
|
||
|
//
|
||
|
// Check to see if there is enough room in the queue
|
||
|
//
|
||
|
if ( pIOMState->ui32NumHPEntries == pIOMState->ui32MaxHPTransactions )
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
|
||
|
ui32SRAMAddress = (ui32Dir == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
|
||
|
pDMAEntry = &pIOMState->pHPTransactions[index];
|
||
|
pDMAEntry->ui32OFFSETHIVal = (uint16_t)(psTransaction->ui32Instr >> 8);
|
||
|
pDMAEntry->ui32DEVCFGVal = _VAL2FLD(IOM0_DEVCFG_DEVADDR, psTransaction->uPeerInfo.ui32I2CDevAddr);
|
||
|
pDMAEntry->ui32DMATARGADDRVal = ui32SRAMAddress;
|
||
|
pDMAEntry->ui32DMATOTCOUNTVal = psTransaction->ui32NumBytes;
|
||
|
pDMAEntry->ui32DMACFGVal =
|
||
|
_VAL2FLD(IOM0_DMACFG_DMAPRI, psTransaction->ui8Priority) |
|
||
|
_VAL2FLD(IOM0_DMACFG_DMADIR, ui32Dir == AM_HAL_IOM_TX ? 1 : 0);
|
||
|
|
||
|
if (psTransaction->ui32NumBytes)
|
||
|
{
|
||
|
pDMAEntry->ui32DMACFGVal |= IOM0_DMACFG_DMAEN_Msk;
|
||
|
}
|
||
|
//
|
||
|
// Command to start the transfer.
|
||
|
//
|
||
|
pDMAEntry->ui32CMDVal = build_cmd((pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) ? psTransaction->uPeerInfo.ui32SpiChipSelect : 0, // ChipSelect
|
||
|
ui32Dir, // ui32Dir
|
||
|
psTransaction->bContinue, // ui32Cont
|
||
|
psTransaction->ui32Instr, // ui32Offset
|
||
|
psTransaction->ui32InstrLen, // ui32OffsetCnt
|
||
|
psTransaction->ui32NumBytes); // ui32Bytes
|
||
|
|
||
|
pDMAEntry->pfnCallback = pfnCallback;
|
||
|
pDMAEntry->pCallbackCtxt = pCallbackCtxt;
|
||
|
|
||
|
pIOMState->ui32NextHPIdx++;
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
} // iom_add_hp_transaction()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Validate an IOM transaction.
|
||
|
//!
|
||
|
//! @param pIOMState - pointer to the IOM internal state.
|
||
|
//! @param psTransaction - pointer to IOM transaction.
|
||
|
//! @param bBlocking - is this a blocking transaction?
|
||
|
//!
|
||
|
//! This function validates.
|
||
|
//!
|
||
|
//! @return HAL status of the operation.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
validate_transaction(am_hal_iom_state_t *pIOMState,
|
||
|
am_hal_iom_transfer_t *psTransaction,
|
||
|
bool bBlocking)
|
||
|
{
|
||
|
uint32_t ui32Offset, ui32OffsetCnt, ui32Dir, ui32Bytes;
|
||
|
|
||
|
ui32Offset = psTransaction->ui32Instr;
|
||
|
ui32OffsetCnt = psTransaction->ui32InstrLen;
|
||
|
ui32Dir = psTransaction->eDirection;
|
||
|
ui32Bytes = psTransaction->ui32NumBytes;
|
||
|
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
if ( (ui32OffsetCnt > AM_HAL_IOM_MAX_OFFSETSIZE) ||
|
||
|
(ui32Offset & (0xFFFFFFFF << (ui32OffsetCnt*8))) ||
|
||
|
(ui32Bytes && (ui32Dir != AM_HAL_IOM_TX) && (psTransaction->pui32RxBuffer == NULL)) ||
|
||
|
(ui32Bytes && (ui32Dir != AM_HAL_IOM_RX) && (psTransaction->pui32TxBuffer == NULL)) ||
|
||
|
((pIOMState->eInterfaceMode == AM_HAL_IOM_I2C_MODE) &&
|
||
|
(psTransaction->ui32NumBytes > AM_HAL_IOM_MAX_TXNSIZE_I2C)) ||
|
||
|
((pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) &&
|
||
|
((psTransaction->uPeerInfo.ui32SpiChipSelect > AM_HAL_IOM_MAX_CS_SPI) ||
|
||
|
(psTransaction->ui32NumBytes > AM_HAL_IOM_MAX_TXNSIZE_SPI))) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
if (!bBlocking)
|
||
|
{
|
||
|
if (psTransaction->ui32PauseCondition & AM_HAL_IOM_PAUSE_FLAG_RESV)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (psTransaction->ui32StatusSetClr & AM_HAL_IOM_SC_RESV_MASK)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // validate_transaction()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM uninitialize function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_uninitialize(void *pHandle)
|
||
|
{
|
||
|
uint32_t status = AM_HAL_STATUS_SUCCESS;
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
|
||
|
#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
|
||
|
|
||
|
if (pIOMState->prefix.s.bEnable)
|
||
|
{
|
||
|
am_hal_iom_disable(pHandle);
|
||
|
}
|
||
|
|
||
|
pIOMState->prefix.s.bInit = false;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return status;
|
||
|
|
||
|
} // am_hal_iom_uninitialize()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM initialization function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_initialize(uint32_t ui32Module, void **ppHandle)
|
||
|
{
|
||
|
// Compile time check to ensure ENTRY_SIZE macros are defined correctly
|
||
|
// incorrect definition will cause divide by 0 error at build time
|
||
|
am_ct_assert((sizeof(am_hal_iom_txn_cmdlist_t) + 8) == AM_HAL_IOM_CQ_ENTRY_SIZE);
|
||
|
am_ct_assert(sizeof(am_hal_iom_dma_entry_t) == AM_HAL_IOM_HIPRIO_ENTRY_SIZE);
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
//
|
||
|
// Validate the module number
|
||
|
//
|
||
|
if ( ui32Module >= AM_REG_IOM_NUM_MODULES )
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
|
||
|
if (ppHandle == NULL)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
if (g_IOMhandles[ui32Module].prefix.s.bInit)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
g_IOMhandles[ui32Module].prefix.s.bInit = true;
|
||
|
g_IOMhandles[ui32Module].prefix.s.bEnable = false;
|
||
|
g_IOMhandles[ui32Module].prefix.s.magic = AM_HAL_MAGIC_IOM;
|
||
|
|
||
|
//
|
||
|
// Initialize the handle.
|
||
|
//
|
||
|
g_IOMhandles[ui32Module].ui32Module = ui32Module;
|
||
|
|
||
|
//
|
||
|
// Return the handle.
|
||
|
//
|
||
|
*ppHandle = (void *)&g_IOMhandles[ui32Module];
|
||
|
|
||
|
//
|
||
|
// Return the status
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_initialize()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM enable function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_enable(void *pHandle)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
uint32_t status = AM_HAL_STATUS_SUCCESS;
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
if (pIOMState->prefix.s.bEnable)
|
||
|
{
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
// Enable submodule
|
||
|
#if 1
|
||
|
enable_submodule(pIOMState->ui32Module, ((pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) ? 0 : 1));
|
||
|
#endif
|
||
|
|
||
|
#if MANUAL_POP
|
||
|
IOMn(pIOMState->ui32Module)->FIFOCTRL_b.POPWR = 1;
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// If Enable the Command Queue
|
||
|
//
|
||
|
if ( pIOMState->pNBTxnBuf )
|
||
|
{
|
||
|
pIOMState->ui32NumPendTransactions = 0;
|
||
|
pIOMState->ui32LastIdxProcessed = 0;
|
||
|
// Initialize Flags used to force CQ Pause
|
||
|
IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_CQ | AM_HAL_IOM_SC_PAUSE_SEQLOOP;
|
||
|
pIOMState->pHPTransactions = NULL;
|
||
|
pIOMState->bHP = false;
|
||
|
pIOMState->block = 0;
|
||
|
pIOMState->ui32NumHPPendingEntries = 0;
|
||
|
pIOMState->ui32NumHPEntries = 0;
|
||
|
pIOMState->eSeq = AM_HAL_IOM_SEQ_NONE;
|
||
|
pIOMState->ui32NumSeqTransactions = 0;
|
||
|
pIOMState->bAutonomous = true;
|
||
|
status = am_hal_iom_CQInit(pIOMState,
|
||
|
pIOMState->ui32NBTxnBufLength,
|
||
|
pIOMState->pNBTxnBuf);
|
||
|
// Initialize the DMA Trigger Setting
|
||
|
//
|
||
|
// DMATRIG, set DTHREN and/or DCMDCMPEN.
|
||
|
// Note - it is recommended that DTHREN always be set.
|
||
|
//
|
||
|
IOMn(pIOMState->ui32Module)->DMATRIGEN = _VAL2FLD(IOM0_DMATRIGEN_DTHREN, 1);
|
||
|
}
|
||
|
|
||
|
if (status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
pIOMState->prefix.s.bEnable = true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We're done, return the status.
|
||
|
//
|
||
|
return status;
|
||
|
|
||
|
} // am_hal_iom_enable()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM disable function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_disable(void *pHandle)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
|
||
|
#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
|
||
|
|
||
|
if (!pIOMState->prefix.s.bEnable)
|
||
|
{
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// Check if we have any pending transactions.
|
||
|
if (pIOMState->ui32NumPendTransactions)
|
||
|
{
|
||
|
return AM_HAL_STATUS_IN_USE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disable the submodules
|
||
|
//
|
||
|
IOMn(pIOMState->ui32Module)->SUBMODCTRL_b.SMOD0EN = 0;
|
||
|
IOMn(pIOMState->ui32Module)->SUBMODCTRL_b.SMOD1EN = 0;
|
||
|
|
||
|
am_hal_IOM_CQReset(pHandle);
|
||
|
|
||
|
pIOMState->prefix.s.bEnable = false;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_disable()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM get status function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_status_get(void *pHandle, am_hal_iom_status_t *psStatus)
|
||
|
{
|
||
|
uint32_t ui32Module, ui32IomStat;
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
if (!psStatus)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
ui32Module = pIOMState->ui32Module;
|
||
|
|
||
|
//
|
||
|
// Begin critical section while we gather status information.
|
||
|
//
|
||
|
AM_CRITICAL_BEGIN
|
||
|
|
||
|
ui32IomStat = IOMn(ui32Module)->STATUS;
|
||
|
psStatus->bStatIdle = _FLD2VAL(IOM0_STATUS_IDLEST, ui32IomStat);
|
||
|
psStatus->bStatErr = _FLD2VAL(IOM0_STATUS_ERR, ui32IomStat);
|
||
|
psStatus->bStatCmdAct = _FLD2VAL(IOM0_STATUS_CMDACT, ui32IomStat);
|
||
|
|
||
|
//
|
||
|
// Return all the bitfields of DMASTAT.
|
||
|
//
|
||
|
psStatus->ui32DmaStat = IOMn(ui32Module)->DMASTAT;
|
||
|
|
||
|
psStatus->ui32MaxTransactions = pIOMState->ui32MaxTransactions;
|
||
|
psStatus->ui32NumPendTransactions = pIOMState->ui32NumPendTransactions;
|
||
|
|
||
|
//
|
||
|
// End the critical section.
|
||
|
//
|
||
|
AM_CRITICAL_END
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_status_get()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM enable interrupts function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_interrupt_enable(void *pHandle, uint32_t ui32IntMask)
|
||
|
{
|
||
|
uint32_t ui32Module;
|
||
|
|
||
|
#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
|
||
|
|
||
|
if (ui32IntMask & AM_HAL_IOM_INT_THR)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG; // Threshold Interupt should not be used.
|
||
|
}
|
||
|
|
||
|
ui32Module = ((am_hal_iom_state_t*)pHandle)->ui32Module;
|
||
|
|
||
|
//
|
||
|
// Set the interrupt enables according to the mask.
|
||
|
//
|
||
|
IOMn(ui32Module)->INTEN |= ui32IntMask;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_interrupt_enable()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM disable interrupts function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_interrupt_disable(void *pHandle, uint32_t ui32IntMask)
|
||
|
{
|
||
|
uint32_t ui32Module;
|
||
|
|
||
|
#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 = ((am_hal_iom_state_t*)pHandle)->ui32Module;
|
||
|
|
||
|
//
|
||
|
// Clear the interrupt enables according to the mask.
|
||
|
//
|
||
|
IOMn(ui32Module)->INTEN &= ~ui32IntMask;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_interrupt_disable()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM get interrupt status
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_interrupt_status_get(void *pHandle, bool bEnabledOnly,
|
||
|
uint32_t *pui32IntStatus)
|
||
|
{
|
||
|
uint32_t ui32IntStatus;
|
||
|
uint32_t ui32Module;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
if ( !pui32IntStatus )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
ui32Module = ((am_hal_iom_state_t*)pHandle)->ui32Module;
|
||
|
|
||
|
ui32IntStatus = IOMn(ui32Module)->INTSTAT;
|
||
|
|
||
|
if ( bEnabledOnly )
|
||
|
{
|
||
|
ui32IntStatus &= IOMn(ui32Module)->INTEN;
|
||
|
}
|
||
|
|
||
|
*pui32IntStatus = ui32IntStatus;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_interrupt_status_get()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM interrupt clear
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_interrupt_clear(void *pHandle, uint32_t ui32IntMask)
|
||
|
{
|
||
|
uint32_t ui32Module;
|
||
|
|
||
|
#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 = ((am_hal_iom_state_t*)pHandle)->ui32Module;
|
||
|
|
||
|
//
|
||
|
// Clear the requested interrupts.
|
||
|
//
|
||
|
IOMn(ui32Module)->INTCLR = ui32IntMask;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_interrupt_clear()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM interrupt service routine
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
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 (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;
|
||
|
}
|
||
|
if (pIOMState->ui32NumPendTransactions)
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pIOMState->ui32NumPendTransactions == 0)
|
||
|
{
|
||
|
//
|
||
|
// Clear interrupts
|
||
|
// Restore IOM interrupts.
|
||
|
//
|
||
|
IOM_SET_INTEN(ui32Module, pIOMState->ui32UserIntCfg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return ui32Status;
|
||
|
|
||
|
} // am_hal_iom_interrupt_service()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM power control function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_power_ctrl(void *pHandle,
|
||
|
am_hal_sysctrl_power_state_e ePowerState,
|
||
|
bool bRetainState)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
|
||
|
#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
|
||
|
|
||
|
//
|
||
|
// Decode the requested power state and update IOM operation accordingly.
|
||
|
//
|
||
|
switch (ePowerState)
|
||
|
{
|
||
|
case AM_HAL_SYSCTRL_WAKE:
|
||
|
if (bRetainState && !pIOMState->registerState.bValid)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Enable power control.
|
||
|
//
|
||
|
am_hal_pwrctrl_periph_enable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_IOM0 + pIOMState->ui32Module));
|
||
|
|
||
|
if (bRetainState)
|
||
|
{
|
||
|
//
|
||
|
// Restore IOM registers
|
||
|
IOMn(pIOMState->ui32Module)->FIFOTHR = pIOMState->registerState.regFIFOTHR;
|
||
|
IOMn(pIOMState->ui32Module)->CLKCFG = pIOMState->registerState.regCLKCFG;
|
||
|
IOMn(pIOMState->ui32Module)->SUBMODCTRL = pIOMState->registerState.regSUBMODCTRL;
|
||
|
IOMn(pIOMState->ui32Module)->CQADDR = pIOMState->registerState.regCQADDR;
|
||
|
IOMn(pIOMState->ui32Module)->CQFLAGS = pIOMState->registerState.regCQFLAGS;
|
||
|
IOMn(pIOMState->ui32Module)->CQPAUSEEN = pIOMState->registerState.regCQPAUSEEN;
|
||
|
IOMn(pIOMState->ui32Module)->CQCURIDX = pIOMState->registerState.regCQCURIDX;
|
||
|
IOMn(pIOMState->ui32Module)->CQENDIDX = pIOMState->registerState.regCQENDIDX;
|
||
|
IOMn(pIOMState->ui32Module)->MSPICFG = pIOMState->registerState.regMSPICFG;
|
||
|
IOMn(pIOMState->ui32Module)->MI2CCFG = pIOMState->registerState.regMI2CCFG;
|
||
|
IOMn(pIOMState->ui32Module)->INTEN = pIOMState->registerState.regINTEN;
|
||
|
IOMn(pIOMState->ui32Module)->DMATRIGEN = pIOMState->registerState.regDMATRIGEN;
|
||
|
|
||
|
//
|
||
|
// Set CQCFG last - can not set the enable yet
|
||
|
//
|
||
|
IOMn(pIOMState->ui32Module)->CQCFG = pIOMState->registerState.regCQCFG & ~_VAL2FLD(IOM0_CQCFG_CQEN, IOM0_CQCFG_CQEN_EN);
|
||
|
if (pIOMState->registerState.regCQCFG & _VAL2FLD(IOM0_CQCFG_CQEN, IOM0_CQCFG_CQEN_EN))
|
||
|
{
|
||
|
am_hal_iom_CQEnable(pIOMState);
|
||
|
}
|
||
|
pIOMState->registerState.bValid = false;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case AM_HAL_SYSCTRL_NORMALSLEEP:
|
||
|
case AM_HAL_SYSCTRL_DEEPSLEEP:
|
||
|
// Make sure IOM is not active currently
|
||
|
if (pIOMState->prefix.s.bEnable &&
|
||
|
(((IOMn(pIOMState->ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk) ||
|
||
|
pIOMState->ui32NumPendTransactions))
|
||
|
{
|
||
|
return AM_HAL_STATUS_IN_USE;
|
||
|
}
|
||
|
if (bRetainState)
|
||
|
{
|
||
|
// Save IOM Registers
|
||
|
pIOMState->registerState.regFIFOTHR = IOMn(pIOMState->ui32Module)->FIFOTHR;
|
||
|
pIOMState->registerState.regCLKCFG = IOMn(pIOMState->ui32Module)->CLKCFG;
|
||
|
pIOMState->registerState.regSUBMODCTRL = IOMn(pIOMState->ui32Module)->SUBMODCTRL;
|
||
|
pIOMState->registerState.regCQCFG = IOMn(pIOMState->ui32Module)->CQCFG;
|
||
|
pIOMState->registerState.regCQADDR = IOMn(pIOMState->ui32Module)->CQADDR;
|
||
|
pIOMState->registerState.regCQFLAGS = IOMn(pIOMState->ui32Module)->CQFLAGS;
|
||
|
pIOMState->registerState.regCQPAUSEEN = IOMn(pIOMState->ui32Module)->CQPAUSEEN;
|
||
|
pIOMState->registerState.regCQCURIDX = IOMn(pIOMState->ui32Module)->CQCURIDX;
|
||
|
pIOMState->registerState.regCQENDIDX = IOMn(pIOMState->ui32Module)->CQENDIDX;
|
||
|
pIOMState->registerState.regMSPICFG = IOMn(pIOMState->ui32Module)->MSPICFG;
|
||
|
pIOMState->registerState.regMI2CCFG = IOMn(pIOMState->ui32Module)->MI2CCFG;
|
||
|
pIOMState->registerState.regINTEN = IOMn(pIOMState->ui32Module)->INTEN;
|
||
|
pIOMState->registerState.regDMATRIGEN = IOMn(pIOMState->ui32Module)->DMATRIGEN;
|
||
|
pIOMState->registerState.bValid = true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disable power control.
|
||
|
//
|
||
|
am_hal_pwrctrl_periph_disable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_IOM0 + pIOMState->ui32Module));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
} // am_hal_iom_power_ctrl()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM configuration function.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_configure(void *pHandle, am_hal_iom_config_t *psConfig)
|
||
|
{
|
||
|
uint32_t ui32ClkCfg;
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
uint32_t status = AM_HAL_STATUS_SUCCESS;
|
||
|
uint32_t ui32Module;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the parameters
|
||
|
//
|
||
|
if ( (pHandle == NULL) ||
|
||
|
(psConfig == NULL) ||
|
||
|
(pIOMState->ui32Module >= AM_REG_IOM_NUM_MODULES) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
// Configure not allowed in Enabled state
|
||
|
if (pIOMState->prefix.s.bEnable)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
//
|
||
|
// Check for DMA to/from DTCM.
|
||
|
//
|
||
|
if ( ((uint32_t)psConfig->pNBTxnBuf >= AM_HAL_FLASH_DTCM_START) &&
|
||
|
((uint32_t)psConfig->pNBTxnBuf <= AM_HAL_FLASH_DTCM_END) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
ui32Module = pIOMState->ui32Module;
|
||
|
//
|
||
|
// Save the interface mode and chip select in the global handle.
|
||
|
//
|
||
|
pIOMState->eInterfaceMode = psConfig->eInterfaceMode;
|
||
|
|
||
|
//
|
||
|
// Set the IOM read/write FIFO thresholds to default values.
|
||
|
//
|
||
|
IOMn(ui32Module)->FIFOTHR =
|
||
|
_VAL2FLD(IOM0_FIFOTHR_FIFORTHR, 16) |
|
||
|
_VAL2FLD(IOM0_FIFOTHR_FIFOWTHR, 16);
|
||
|
|
||
|
if ( psConfig->eInterfaceMode == AM_HAL_IOM_SPI_MODE )
|
||
|
{
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
//
|
||
|
// Validate the SPI mode
|
||
|
//
|
||
|
if ( psConfig->eSpiMode > AM_HAL_IOM_SPI_MODE_3 )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (psConfig->ui32ClockFreq > AM_HAL_IOM_MAX_FREQ)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
//
|
||
|
// Determine the CLKCFG value for SPI.
|
||
|
//
|
||
|
ui32ClkCfg = iom_get_interface_clock_cfg(psConfig->ui32ClockFreq, (psConfig->eSpiMode & 2) >> 1);
|
||
|
|
||
|
//
|
||
|
// Set the SPI configuration.
|
||
|
//
|
||
|
IOMn(ui32Module)->MSPICFG =
|
||
|
( ((psConfig->eSpiMode << IOM0_MSPICFG_SPOL_Pos) & (IOM0_MSPICFG_SPHA_Msk | IOM0_MSPICFG_SPOL_Msk)) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_FULLDUP, 0) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_WTFC, IOM0_MSPICFG_WTFC_DIS) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_RDFC, IOM0_MSPICFG_RDFC_DIS) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_MOSIINV, IOM0_MSPICFG_MOSIINV_NORMAL) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_WTFCIRQ, IOM0_MSPICFG_WTFCIRQ_MISO) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_WTFCPOL, IOM0_MSPICFG_WTFCPOL_HIGH) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_RDFCPOL, IOM0_MSPICFG_RDFCPOL_HIGH) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_SPILSB, IOM0_MSPICFG_SPILSB_MSB) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_DINDLY, 0) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_DOUTDLY, 0) |
|
||
|
_VAL2FLD(IOM0_MSPICFG_MSPIRST, 0) );
|
||
|
}
|
||
|
else if ( psConfig->eInterfaceMode == AM_HAL_IOM_I2C_MODE )
|
||
|
{
|
||
|
switch (psConfig->ui32ClockFreq)
|
||
|
{
|
||
|
case AM_HAL_IOM_100KHZ:
|
||
|
//
|
||
|
// settings below should give ~100 kHz
|
||
|
//
|
||
|
ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_TOTPER, 0x77) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_LOWPER, 0x3B) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIVEN, IOM0_CLKCFG_DIVEN_EN) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIV3, IOM0_CLKCFG_DIV3_DIS) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_FSEL, IOM0_CLKCFG_FSEL_HFRC_DIV2) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
|
||
|
IOMn(ui32Module)->MI2CCFG = _VAL2FLD(IOM0_MI2CCFG_STRDIS, 0) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SMPCNT, 3) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SDAENDLY, 15) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SCLENDLY, 0) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_MI2CRST, 1) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SDADLY, 3) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_ARBEN, IOM0_MI2CCFG_ARBEN_ARBDIS) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_I2CLSB, IOM0_MI2CCFG_I2CLSB_MSBFIRST) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_ADDRSZ, IOM0_MI2CCFG_ADDRSZ_ADDRSZ7);
|
||
|
break;
|
||
|
case AM_HAL_IOM_400KHZ:
|
||
|
//
|
||
|
// settings below should give ~400 kHz
|
||
|
//
|
||
|
ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_TOTPER, 0x1D) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_LOWPER, 0x0E) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIVEN, IOM0_CLKCFG_DIVEN_EN) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIV3, IOM0_CLKCFG_DIV3_DIS) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_FSEL, IOM0_CLKCFG_FSEL_HFRC_DIV2) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
|
||
|
IOMn(ui32Module)->MI2CCFG = _VAL2FLD(IOM0_MI2CCFG_STRDIS, 0) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SMPCNT, 3) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SDAENDLY, 15) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SCLENDLY, 2) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_MI2CRST, 1) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SDADLY, 3) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_ARBEN, IOM0_MI2CCFG_ARBEN_ARBDIS) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_I2CLSB, IOM0_MI2CCFG_I2CLSB_MSBFIRST) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_ADDRSZ, IOM0_MI2CCFG_ADDRSZ_ADDRSZ7);
|
||
|
break;
|
||
|
case AM_HAL_IOM_1MHZ:
|
||
|
//
|
||
|
// settings below should give ~860 kHz
|
||
|
//
|
||
|
ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_TOTPER, 0x06) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_LOWPER, 0x03) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIVEN, IOM0_CLKCFG_DIVEN_EN) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_DIV3, IOM0_CLKCFG_DIV3_DIS) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_FSEL, IOM0_CLKCFG_FSEL_HFRC_DIV4) |
|
||
|
_VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
|
||
|
IOMn(ui32Module)->MI2CCFG = _VAL2FLD(IOM0_MI2CCFG_STRDIS, 0) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SMPCNT, 0x21) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SDAENDLY, 3) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SCLENDLY, 0) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_MI2CRST, 1) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_SDADLY, 0) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_ARBEN, IOM0_MI2CCFG_ARBEN_ARBDIS) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_I2CLSB, IOM0_MI2CCFG_I2CLSB_MSBFIRST) |
|
||
|
_VAL2FLD(IOM0_MI2CCFG_ADDRSZ, IOM0_MI2CCFG_ADDRSZ_ADDRSZ7);
|
||
|
break;
|
||
|
default:
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Enable and set the clock configuration.
|
||
|
//
|
||
|
ui32ClkCfg |= _VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
|
||
|
IOMn(ui32Module)->CLKCFG = ui32ClkCfg;
|
||
|
|
||
|
pIOMState->ui32BitTimeTicks = AM_HAL_CLKGEN_FREQ_MAX_HZ / psConfig->ui32ClockFreq;
|
||
|
|
||
|
//
|
||
|
// Set the delay timeout value to the default maximum value.
|
||
|
//
|
||
|
pIOMState->waitTimeout = 1000;
|
||
|
|
||
|
pIOMState->pNBTxnBuf = psConfig->pNBTxnBuf;
|
||
|
pIOMState->ui32NBTxnBufLength = psConfig->ui32NBTxnBufLength;
|
||
|
// Worst case minimum CQ entries that can be accomodated in provided buffer
|
||
|
// Need to account for the wrap
|
||
|
pIOMState->ui32MaxPending = ((pIOMState->ui32NBTxnBufLength - 8) * 4 / AM_HAL_IOM_CQ_ENTRY_SIZE);
|
||
|
if (pIOMState->ui32MaxPending > AM_HAL_IOM_MAX_PENDING_TRANSACTIONS)
|
||
|
{
|
||
|
pIOMState->ui32MaxPending = AM_HAL_IOM_MAX_PENDING_TRANSACTIONS;
|
||
|
}
|
||
|
// Disable the DCX
|
||
|
for (uint8_t i = 0; i <= AM_HAL_IOM_MAX_CS_SPI; i++)
|
||
|
{
|
||
|
pIOMState->dcx[i] = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return status;
|
||
|
|
||
|
} // am_hal_iom_configure()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM blocking transfer function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_blocking_transfer(void *pHandle,
|
||
|
am_hal_iom_transfer_t *psTransaction)
|
||
|
{
|
||
|
uint32_t ui32Cmd, ui32Offset, ui32OffsetCnt, ui32Dir, ui32Cont;
|
||
|
uint32_t ui32FifoRem, ui32FifoSiz;
|
||
|
uint32_t ui32Bytes;
|
||
|
uint32_t ui32IntConfig;
|
||
|
uint32_t *pui32Buffer;
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
uint32_t ui32Module;
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
bool bCmdCmp = false;
|
||
|
uint32_t numWait = 0;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
if ( !psTransaction )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
if (psTransaction->eDirection > AM_HAL_IOM_RX)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
ui32Bytes = psTransaction->ui32NumBytes;
|
||
|
if ( ui32Bytes == 0 )
|
||
|
{
|
||
|
//
|
||
|
// Only TX is supported for 0-length transactions. A 0-length
|
||
|
// transfer presumes that only an offset value is being written.
|
||
|
//
|
||
|
psTransaction->eDirection = AM_HAL_IOM_TX;
|
||
|
}
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
ui32Status = validate_transaction(pIOMState, psTransaction, true);
|
||
|
|
||
|
if (ui32Status != AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (pIOMState->eSeq == AM_HAL_IOM_SEQ_RUNNING)
|
||
|
{
|
||
|
// Dynamic additions to sequence not allowed
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
|
||
|
ui32Module = pIOMState->ui32Module;
|
||
|
ui32Offset = psTransaction->ui32Instr;
|
||
|
ui32OffsetCnt = psTransaction->ui32InstrLen;
|
||
|
ui32Dir = psTransaction->eDirection;
|
||
|
ui32Cont = psTransaction->bContinue ? 1 : 0;
|
||
|
pui32Buffer = (ui32Dir == AM_HAL_IOM_TX) ? psTransaction->pui32TxBuffer : psTransaction->pui32RxBuffer;
|
||
|
|
||
|
//
|
||
|
// Make sure any previous non-blocking transfers have completed.
|
||
|
//
|
||
|
ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
|
||
|
(uint32_t)&pIOMState->ui32NumPendTransactions,
|
||
|
0xFFFFFFFF,
|
||
|
0,
|
||
|
true);
|
||
|
if ( ui32Status != AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure any previous blocking transfer has been completed.
|
||
|
// This check is required to make sure previous transaction has cleared if the blocking call
|
||
|
// finished with a timeout
|
||
|
//
|
||
|
ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
|
||
|
(uint32_t)&IOMn(ui32Module)->STATUS,
|
||
|
(IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
|
||
|
IOM0_STATUS_IDLEST_Msk,
|
||
|
true);
|
||
|
|
||
|
if ( ui32Status != AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disable interrupts so that we don't get any undesired interrupts.
|
||
|
//
|
||
|
ui32IntConfig = IOMn(ui32Module)->INTEN;
|
||
|
//
|
||
|
// Disable IOM interrupts as we'll be polling
|
||
|
//
|
||
|
IOMn(ui32Module)->INTEN = 0;
|
||
|
//
|
||
|
// Disable DMA - in case the last transaction was DMA
|
||
|
// For CQ - we disable DMA only at the start of next transaction
|
||
|
//
|
||
|
IOMn(ui32Module)->DMACFG_b.DMAEN = 0;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Clear interrupts
|
||
|
//
|
||
|
IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
|
||
|
|
||
|
//
|
||
|
// Set the dev addr (either 7 or 10 bit as configured in MI2CCFG).
|
||
|
//
|
||
|
IOMn(ui32Module)->DEVCFG = psTransaction->uPeerInfo.ui32I2CDevAddr;
|
||
|
// CMDRPT register has been repurposed for DCX
|
||
|
// Set the DCX
|
||
|
IOMn(ui32Module)->DCX = (pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) ? pIOMState->dcx[psTransaction->uPeerInfo.ui32SpiChipSelect] : 0;
|
||
|
//
|
||
|
// Build the CMD value
|
||
|
//
|
||
|
|
||
|
ui32Cmd = pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE ?
|
||
|
psTransaction->uPeerInfo.ui32SpiChipSelect : 0;
|
||
|
ui32Cmd = build_cmd(ui32Cmd, ui32Dir, ui32Cont, ui32Offset, ui32OffsetCnt, ui32Bytes);
|
||
|
|
||
|
//
|
||
|
// Set the OFFSETHI register.
|
||
|
//
|
||
|
IOMn(ui32Module)->OFFSETHI = (uint16_t)(ui32Offset >> 8);
|
||
|
|
||
|
ui32Bytes = psTransaction->ui32NumBytes;
|
||
|
|
||
|
if ( ui32Dir == AM_HAL_IOM_RX )
|
||
|
{
|
||
|
//
|
||
|
// Start the transfer
|
||
|
//
|
||
|
IOMn(ui32Module)->CMD = ui32Cmd;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Start a loop to catch the Rx data.
|
||
|
//
|
||
|
while ( ui32Bytes )
|
||
|
{
|
||
|
//
|
||
|
// Limit the wait to reasonable limit - instead of blocking forever
|
||
|
//
|
||
|
numWait = 0;
|
||
|
while ((ui32FifoSiz = IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ) < 4)
|
||
|
{
|
||
|
if (numWait++ < AM_HAL_IOM_MAX_BLOCKING_WAIT)
|
||
|
{
|
||
|
if (bCmdCmp && (ui32Bytes > ui32FifoSiz))
|
||
|
{
|
||
|
//
|
||
|
// No more data expected. Get out of the loop
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
am_hal_flash_delay( FLASH_CYCLES_US(1) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// We've waited long enough - get out!
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
bCmdCmp = IOMn(ui32Module)->INTSTAT_b.CMDCMP;
|
||
|
}
|
||
|
if (ui32FifoSiz < 4)
|
||
|
{
|
||
|
//
|
||
|
// Something went wrong - get out and report failure
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
while ((ui32FifoSiz >= 4) && ui32Bytes)
|
||
|
{
|
||
|
//
|
||
|
// Safe to read the FIFO, read 4 bytes
|
||
|
//
|
||
|
uint32_t ui32Read;
|
||
|
ui32Read = IOMn(ui32Module)->FIFOPOP;
|
||
|
#if MANUAL_POP
|
||
|
IOMn(ui32Module)->FIFOPOP = 0x11111111;
|
||
|
#endif
|
||
|
ui32FifoSiz -= 4;
|
||
|
if (ui32Bytes >= 4)
|
||
|
{
|
||
|
*pui32Buffer++ = ui32Read;
|
||
|
ui32Bytes -= 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Copy byte by byte - so as to not corrupt the rest of the buffer
|
||
|
uint8_t *pui8Buffer = (uint8_t *)pui32Buffer;
|
||
|
do
|
||
|
{
|
||
|
*pui8Buffer++ = ui32Read & 0xFF;
|
||
|
ui32Read >>= 8;
|
||
|
} while (--ui32Bytes);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if ( ui32Dir == AM_HAL_IOM_TX )
|
||
|
{
|
||
|
// Write data to FIFO first - before starting the transfer
|
||
|
|
||
|
ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM;
|
||
|
while ((ui32FifoRem >= 4) && ui32Bytes)
|
||
|
{
|
||
|
IOMn(ui32Module)->FIFOPUSH = *pui32Buffer++;
|
||
|
ui32FifoRem -= 4;
|
||
|
if (ui32Bytes >= 4)
|
||
|
{
|
||
|
ui32Bytes -= 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui32Bytes = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Start the transfer
|
||
|
//
|
||
|
IOMn(ui32Module)->CMD = ui32Cmd;
|
||
|
//
|
||
|
// Keep looping until we're out of bytes to send or command complete (error).
|
||
|
//
|
||
|
while (ui32Bytes)
|
||
|
{
|
||
|
//
|
||
|
// Limit the wait to reasonable limit - instead of blocking forever
|
||
|
//
|
||
|
numWait = 0;
|
||
|
while ((ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM) < 4)
|
||
|
{
|
||
|
bCmdCmp = IOMn(ui32Module)->INTSTAT_b.CMDCMP;
|
||
|
if (bCmdCmp || (numWait++ >= AM_HAL_IOM_MAX_BLOCKING_WAIT))
|
||
|
{
|
||
|
//
|
||
|
// FIFO not expected to change any more - get out
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
am_hal_flash_delay( FLASH_CYCLES_US(1) );
|
||
|
}
|
||
|
}
|
||
|
if (bCmdCmp || (ui32FifoRem < 4))
|
||
|
{
|
||
|
//
|
||
|
// Something went wrong - bail out
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
while ((ui32FifoRem >= 4) && ui32Bytes)
|
||
|
{
|
||
|
IOMn(ui32Module)->FIFOPUSH = *pui32Buffer++;
|
||
|
ui32FifoRem -= 4;
|
||
|
if (ui32Bytes >= 4)
|
||
|
{
|
||
|
ui32Bytes -= 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui32Bytes = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure transfer is completed.
|
||
|
//
|
||
|
ui32Status = am_hal_flash_delay_status_check(AM_HAL_IOM_MAX_BLOCKING_WAIT,
|
||
|
(uint32_t)&IOMn(ui32Module)->STATUS,
|
||
|
(IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
|
||
|
IOM0_STATUS_IDLEST_Msk,
|
||
|
true);
|
||
|
|
||
|
if ( ui32Status == AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
ui32Status = internal_iom_get_int_err(ui32Module, 0);
|
||
|
|
||
|
if (ui32Status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
if (ui32Bytes)
|
||
|
{
|
||
|
// Indicates transaction did not finish for some reason
|
||
|
ui32Status = AM_HAL_STATUS_FAIL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ui32Status != AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
// Do Error recovery
|
||
|
// Reset Submodule & FIFO
|
||
|
internal_iom_reset_on_error(pIOMState, IOMn(ui32Module)->INTSTAT);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Clear interrupts
|
||
|
// Re-enable IOM interrupts.
|
||
|
//
|
||
|
IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
|
||
|
IOMn(ui32Module)->INTEN = ui32IntConfig;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return ui32Status;
|
||
|
|
||
|
} // am_hal_iom_blocking_transfer()
|
||
|
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// IOM non-blocking transfer function
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_nonblocking_transfer(void *pHandle,
|
||
|
am_hal_iom_transfer_t *psTransaction,
|
||
|
am_hal_iom_callback_t pfnCallback,
|
||
|
void *pCallbackCtxt)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
uint32_t ui32NumPend;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
uint32_t ui32DMAAddress;
|
||
|
|
||
|
if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
if ( !psTransaction )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
if (psTransaction->eDirection > AM_HAL_IOM_RX)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
//
|
||
|
// Check for DMA to/from DTCM.
|
||
|
//
|
||
|
ui32DMAAddress = (psTransaction->eDirection == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
|
||
|
|
||
|
if ( (ui32DMAAddress >= AM_HAL_FLASH_DTCM_START) &&
|
||
|
(ui32DMAAddress <= AM_HAL_FLASH_DTCM_END) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
if ( psTransaction->ui32NumBytes == 0 )
|
||
|
{
|
||
|
//
|
||
|
// Only TX is supported for 0-length transactions. A 0-length
|
||
|
// transfer presumes that only an offset value is being written.
|
||
|
//
|
||
|
psTransaction->eDirection = AM_HAL_IOM_TX;
|
||
|
}
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
ui32Status = validate_transaction(pIOMState, psTransaction, false);
|
||
|
|
||
|
if (ui32Status != AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
|
||
|
am_hal_iom_callback_t pfnCallback1 = pfnCallback;
|
||
|
if (!pIOMState->pCmdQHdl)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
if (pIOMState->eSeq == AM_HAL_IOM_SEQ_RUNNING)
|
||
|
{
|
||
|
// Dynamic additions to sequence not allowed
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
if (pIOMState->block && (psTransaction->ui32PauseCondition != 0))
|
||
|
{
|
||
|
// Paused operations not allowed in block mode
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
if (!pfnCallback1 && !pIOMState->block && (pIOMState->eSeq == AM_HAL_IOM_SEQ_NONE) &&
|
||
|
(pIOMState->ui32NumUnSolicited >= (pIOMState->ui32MaxPending / 2)))
|
||
|
{
|
||
|
// Need to schedule a dummy callback, to ensure ui32NumPendTransactions get updated in ISR
|
||
|
pfnCallback1 = iom_dummy_callback;
|
||
|
}
|
||
|
//
|
||
|
// DMA defaults to using the Command Queue
|
||
|
//
|
||
|
ui32Status = am_hal_iom_CQAddTransaction(pHandle, psTransaction, pfnCallback1, pCallbackCtxt);
|
||
|
|
||
|
if (ui32Status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
uint32_t ui32Critical = 0;
|
||
|
|
||
|
//
|
||
|
// Need to protect access of ui32NumPendTransactions as it is accessed
|
||
|
// from ISR as well
|
||
|
//
|
||
|
// Start a critical section.
|
||
|
//
|
||
|
ui32Critical = am_hal_interrupt_master_disable();
|
||
|
|
||
|
//
|
||
|
// Register for interrupt only if there is a callback
|
||
|
//
|
||
|
ui32Status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, pfnCallback1);
|
||
|
if (ui32Status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
ui32NumPend = pIOMState->ui32NumPendTransactions++;
|
||
|
pIOMState->ui32NumSeqTransactions++;
|
||
|
if (pfnCallback)
|
||
|
{
|
||
|
pIOMState->bAutonomous = false;
|
||
|
pIOMState->ui32NumUnSolicited = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pfnCallback1)
|
||
|
{
|
||
|
// This implies we have already scheduled a dummy callback
|
||
|
pIOMState->ui32NumUnSolicited = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIOMState->ui32NumUnSolicited++;
|
||
|
}
|
||
|
}
|
||
|
if (0 == ui32NumPend)
|
||
|
{
|
||
|
pIOMState->ui32UserIntCfg = IOMn(pIOMState->ui32Module)->INTEN;
|
||
|
IOM_SET_INTEN(pIOMState->ui32Module, AM_HAL_IOM_INT_CQMODE);
|
||
|
am_hal_iom_CQEnable(pIOMState);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
|
||
|
}
|
||
|
//
|
||
|
// End the critical section.
|
||
|
//
|
||
|
am_hal_interrupt_master_set(ui32Critical);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return ui32Status;
|
||
|
|
||
|
} // am_hal_iom_nonblocking_transfer()
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief Perform a simple full-duplex transaction to the SPI interface.
|
||
|
//!
|
||
|
//! This function performs SPI full-duplex operation to a selected SPI device.
|
||
|
//!
|
||
|
//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words.
|
||
|
//! This means that you will need to byte-pack the \e pui32TxData array with the
|
||
|
//! data you intend to send over the interface. One easy way to do this is to
|
||
|
//! declare the array as a 32-bit integer array, but use an 8-bit pointer to
|
||
|
//! put your actual data into the array. If there are not enough bytes in your
|
||
|
//! desired message to completely fill the last 32-bit word, you may pad that
|
||
|
//! last word with bytes of any value. The IOM hardware will only read the
|
||
|
//! first \e ui32NumBytes in the \e pui32TxData array.
|
||
|
//!
|
||
|
//! @return returns AM_HAL_IOM_SUCCESS on successful execution.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t
|
||
|
am_hal_iom_spi_blocking_fullduplex(void *pHandle,
|
||
|
am_hal_iom_transfer_t *psTransaction)
|
||
|
{
|
||
|
uint32_t ui32Cmd, ui32Offset, ui32OffsetCnt, ui32Dir, ui32Cont;
|
||
|
uint32_t ui32FifoRem, ui32FifoSiz;
|
||
|
uint32_t ui32Bytes;
|
||
|
uint32_t ui32RxBytes;
|
||
|
uint32_t ui32IntConfig;
|
||
|
uint32_t *pui32TxBuffer;
|
||
|
uint32_t *pui32RxBuffer;
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
uint32_t ui32Module;
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
bool bCmdCmp = false;
|
||
|
uint32_t numWait = 0;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
if ( !psTransaction )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
if ( psTransaction->eDirection != AM_HAL_IOM_FULLDUPLEX )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
ui32Status = validate_transaction(pIOMState, psTransaction, true);
|
||
|
|
||
|
if ( ui32Status != AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
ui32Module = pIOMState->ui32Module;
|
||
|
ui32Offset = psTransaction->ui32Instr;
|
||
|
ui32OffsetCnt = psTransaction->ui32InstrLen;
|
||
|
ui32Bytes = psTransaction->ui32NumBytes;
|
||
|
ui32Dir = psTransaction->eDirection;
|
||
|
ui32Cont = psTransaction->bContinue ? 1 : 0;
|
||
|
pui32RxBuffer = psTransaction->pui32RxBuffer;
|
||
|
pui32TxBuffer = psTransaction->pui32TxBuffer;
|
||
|
|
||
|
//
|
||
|
// Make sure any previous non-blocking transfers have completed.
|
||
|
//
|
||
|
ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
|
||
|
(uint32_t)&pIOMState->ui32NumPendTransactions,
|
||
|
0xFFFFFFFF,
|
||
|
0,
|
||
|
true);
|
||
|
if ( ui32Status != AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure any previous blocking transfer has been completed.
|
||
|
// This check is required to make sure previous transaction has cleared if the blocking call
|
||
|
// finished with a timeout
|
||
|
//
|
||
|
ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
|
||
|
(uint32_t)&IOMn(ui32Module)->STATUS,
|
||
|
(IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
|
||
|
IOM0_STATUS_IDLEST_Msk,
|
||
|
true);
|
||
|
|
||
|
if ( ui32Status != AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disable interrupts so that we don't get any undesired interrupts.
|
||
|
//
|
||
|
ui32IntConfig = IOMn(ui32Module)->INTEN;
|
||
|
|
||
|
//
|
||
|
// Disable IOM interrupts as we'll be polling
|
||
|
//
|
||
|
IOMn(ui32Module)->INTEN = 0;
|
||
|
|
||
|
//
|
||
|
// Clear interrupts
|
||
|
//
|
||
|
IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
|
||
|
|
||
|
//
|
||
|
// Set the dev addr (either 7 or 10 bit as configured in MI2CCFG).
|
||
|
//
|
||
|
IOMn(ui32Module)->DEVCFG = psTransaction->uPeerInfo.ui32I2CDevAddr;
|
||
|
// CMDRPT register has been repurposed for DCX
|
||
|
// Set the DCX
|
||
|
IOMn(ui32Module)->DCX = pIOMState->dcx[psTransaction->uPeerInfo.ui32SpiChipSelect];
|
||
|
|
||
|
//
|
||
|
// Build the CMD value
|
||
|
//
|
||
|
|
||
|
ui32Cmd = pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE ?
|
||
|
psTransaction->uPeerInfo.ui32SpiChipSelect : 0;
|
||
|
ui32Cmd = build_cmd(ui32Cmd, ui32Dir, ui32Cont, ui32Offset, ui32OffsetCnt, ui32Bytes);
|
||
|
|
||
|
//
|
||
|
// Set the OFFSETHI register.
|
||
|
//
|
||
|
IOMn(ui32Module)->OFFSETHI = (uint16_t)(ui32Offset >> 8);
|
||
|
|
||
|
//
|
||
|
// Set FULLDUPLEX mode
|
||
|
//
|
||
|
IOMn(ui32Module)->MSPICFG |= _VAL2FLD(IOM0_MSPICFG_FULLDUP, 1);
|
||
|
|
||
|
//
|
||
|
// Start the transfer
|
||
|
//
|
||
|
IOMn(ui32Module)->CMD = ui32Cmd;
|
||
|
|
||
|
ui32Bytes = psTransaction->ui32NumBytes;
|
||
|
ui32RxBytes = ui32Bytes;
|
||
|
|
||
|
//
|
||
|
// Start a loop to catch the Rx data.
|
||
|
//
|
||
|
//
|
||
|
// Keep looping until we're out of bytes to send or command complete (error).
|
||
|
//
|
||
|
while (ui32Bytes || ui32RxBytes)
|
||
|
{
|
||
|
//
|
||
|
// Limit the wait to reasonable limit - instead of blocking forever
|
||
|
//
|
||
|
numWait = 0;
|
||
|
ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM;
|
||
|
ui32FifoSiz = IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ;
|
||
|
|
||
|
while ((ui32FifoRem < 4) &&
|
||
|
(ui32FifoSiz < 4))
|
||
|
{
|
||
|
if (numWait++ < AM_HAL_IOM_MAX_BLOCKING_WAIT)
|
||
|
{
|
||
|
if (bCmdCmp && (ui32RxBytes > ui32FifoSiz))
|
||
|
{
|
||
|
//
|
||
|
// No more data expected. Get out of the loop
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
am_hal_flash_delay( FLASH_CYCLES_US(1) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// We've waited long enough - get out!
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
bCmdCmp = IOMn(ui32Module)->INTSTAT_b.CMDCMP;
|
||
|
ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM;
|
||
|
ui32FifoSiz = IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ;
|
||
|
}
|
||
|
if (bCmdCmp || ((ui32FifoRem < 4) && (ui32FifoSiz < 4)))
|
||
|
{
|
||
|
//
|
||
|
// Something went wrong - bail out
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
while ((ui32FifoRem >= 4) && ui32Bytes)
|
||
|
{
|
||
|
IOMn(ui32Module)->FIFOPUSH = *pui32TxBuffer++;
|
||
|
ui32FifoRem -= 4;
|
||
|
if (ui32Bytes >= 4)
|
||
|
{
|
||
|
ui32Bytes -= 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui32Bytes = 0;
|
||
|
}
|
||
|
}
|
||
|
while ((ui32FifoSiz >= 4) && ui32RxBytes)
|
||
|
{
|
||
|
//
|
||
|
// Safe to read the FIFO, read 4 bytes
|
||
|
//
|
||
|
*pui32RxBuffer++ = IOMn(ui32Module)->FIFOPOP;
|
||
|
#if MANUAL_POP
|
||
|
IOMn(ui32Module)->FIFOPOP = 0x11111111;
|
||
|
#endif
|
||
|
ui32FifoSiz -= 4;
|
||
|
if (ui32RxBytes >= 4)
|
||
|
{
|
||
|
ui32RxBytes -= 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui32RxBytes = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure transfer is completed.
|
||
|
//
|
||
|
ui32Status = am_hal_flash_delay_status_check(AM_HAL_IOM_MAX_BLOCKING_WAIT,
|
||
|
(uint32_t)&IOMn(ui32Module)->STATUS,
|
||
|
(IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
|
||
|
IOM0_STATUS_IDLEST_Msk,
|
||
|
true);
|
||
|
|
||
|
if ( ui32Status != AM_HAL_STATUS_SUCCESS )
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
|
||
|
ui32Status = internal_iom_get_int_err(ui32Module, 0);
|
||
|
|
||
|
if (ui32Status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
if (ui32Bytes)
|
||
|
{
|
||
|
// Indicates transaction did not finish for some reason
|
||
|
ui32Status = AM_HAL_STATUS_FAIL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Do Error recovery
|
||
|
// Reset Submodule & FIFO
|
||
|
internal_iom_reset_on_error(pIOMState, IOMn(ui32Module)->INTSTAT);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Clear interrupts
|
||
|
// Re-enable IOM interrupts.
|
||
|
//
|
||
|
IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
|
||
|
IOMn(ui32Module)->INTEN = ui32IntConfig;
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return ui32Status;
|
||
|
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! @brief IOM control function
|
||
|
//!
|
||
|
//! @param handle - handle for the IOM.
|
||
|
//! @param eReq - device specific special request code.
|
||
|
//! @param pArgs - pointer to the request specific arguments.
|
||
|
//!
|
||
|
//! This function allows advanced settings
|
||
|
//!
|
||
|
//! @return status - generic or interface specific status.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
uint32_t am_hal_iom_control(void *pHandle, am_hal_iom_request_e eReq, void *pArgs)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
|
||
|
uint32_t status = AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the parameters
|
||
|
//
|
||
|
if (eReq >= AM_HAL_IOM_REQ_MAX)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
uint32_t ui32Module = pIOMState->ui32Module;
|
||
|
switch (eReq)
|
||
|
{
|
||
|
case AM_HAL_IOM_REQ_FLAG_SETCLR:
|
||
|
if (pArgs)
|
||
|
{
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (*((uint32_t *)pArgs) & AM_HAL_IOM_SC_RESV_MASK)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
IOMn(ui32Module)->CQSETCLEAR = *((uint32_t *)pArgs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
break;
|
||
|
case AM_HAL_IOM_REQ_SPI_LSB:
|
||
|
if (pArgs)
|
||
|
{
|
||
|
IOMn(ui32Module)->MSPICFG_b.SPILSB = *((uint32_t *)pArgs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
break;
|
||
|
case AM_HAL_IOM_REQ_SPI_FULLDUPLEX:
|
||
|
if (pArgs)
|
||
|
{
|
||
|
IOMn(ui32Module)->MSPICFG_b.FULLDUP = *((uint32_t *)pArgs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
break;
|
||
|
case AM_HAL_IOM_REQ_SPI_RDTHRESH:
|
||
|
if (pArgs)
|
||
|
{
|
||
|
IOMn(ui32Module)->FIFOTHR_b.FIFORTHR = *((uint32_t *)pArgs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
break;
|
||
|
case AM_HAL_IOM_REQ_SPI_WRTHRESH:
|
||
|
if (pArgs)
|
||
|
{
|
||
|
IOMn(ui32Module)->FIFOTHR_b.FIFOWTHR = *((uint32_t *)pArgs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case AM_HAL_IOM_REQ_LINK_MSPI:
|
||
|
if (pArgs)
|
||
|
{
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (*((uint32_t *)pArgs) > AM_REG_MSPI_NUM_MODULES)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
IOMn(ui32Module)->CQCFG_b.MSPIFLGSEL = *((uint32_t *)pArgs);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
status = AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
break;
|
||
|
case AM_HAL_IOM_REQ_PAUSE:
|
||
|
// Force CQ to Paused
|
||
|
status = iom_cq_pause(pIOMState);
|
||
|
break;
|
||
|
|
||
|
case AM_HAL_IOM_REQ_UNPAUSE:
|
||
|
// Resume the CQ
|
||
|
IOMn(ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_CQ;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case AM_HAL_IOM_REQ_SET_SEQMODE:
|
||
|
{
|
||
|
am_hal_iom_seq_e eSeq;
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!pArgs)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (!pIOMState->pNBTxnBuf)
|
||
|
{
|
||
|
// No space for CMDQ
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
eSeq = *((bool *)pArgs) ? AM_HAL_IOM_SEQ_UNDER_CONSTRUCTION: AM_HAL_IOM_SEQ_NONE;
|
||
|
if (eSeq == pIOMState->eSeq)
|
||
|
{
|
||
|
// Nothing to do
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
switch (pIOMState->eSeq)
|
||
|
{
|
||
|
case AM_HAL_IOM_SEQ_RUNNING:
|
||
|
{
|
||
|
// Force CQ to Pause
|
||
|
status = iom_cq_pause(pIOMState);
|
||
|
break;
|
||
|
}
|
||
|
case AM_HAL_IOM_SEQ_NONE:
|
||
|
{
|
||
|
// Make sure there is no non-blocking transaction in progress
|
||
|
if (pIOMState->ui32NumPendTransactions)
|
||
|
{
|
||
|
status = AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
;
|
||
|
}
|
||
|
if (status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
// Reset the cmdq
|
||
|
am_hal_cmdq_reset(pIOMState->pCmdQHdl);
|
||
|
pIOMState->ui32LastIdxProcessed = 0;
|
||
|
pIOMState->ui32NumSeqTransactions = 0;
|
||
|
pIOMState->ui32NumPendTransactions = 0;
|
||
|
pIOMState->ui32NumUnSolicited = 0;
|
||
|
pIOMState->eSeq = eSeq;
|
||
|
pIOMState->bAutonomous = true;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AM_HAL_IOM_REQ_SEQ_END:
|
||
|
{
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
am_hal_cmdq_entry_t *pCQBlock;
|
||
|
uint32_t index;
|
||
|
am_hal_iom_seq_end_t *pLoop = (am_hal_iom_seq_end_t *)pArgs;
|
||
|
uint32_t pause = 0;
|
||
|
uint32_t scUnpause = 0;
|
||
|
uint32_t ui32Critical = 0;
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!pArgs)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (pLoop->ui32PauseCondition & AM_HAL_IOM_PAUSE_FLAG_RESV)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (pLoop->ui32StatusSetClr & AM_HAL_IOM_SC_RESV_MASK)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (pIOMState->eSeq != AM_HAL_IOM_SEQ_UNDER_CONSTRUCTION)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (pIOMState->block)
|
||
|
{
|
||
|
// End the block if the sequence is ending
|
||
|
pIOMState->block = 0;
|
||
|
// Unblock the whole batch of commands in this block
|
||
|
IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_BLOCK;
|
||
|
}
|
||
|
|
||
|
if ((pLoop->bLoop) && (!pIOMState->bAutonomous))
|
||
|
{
|
||
|
// Need to insert special element in CQ to cause a callback
|
||
|
// This is to reset internal state
|
||
|
ui32Status = am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, 1, &pCQBlock, &index);
|
||
|
if (ui32Status != AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Store the callback function pointer.
|
||
|
//
|
||
|
pIOMState->pfnCallback[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = iom_seq_loopback;
|
||
|
pIOMState->pCallbackCtxt[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = (void *)pIOMState;
|
||
|
|
||
|
// Dummy Entry
|
||
|
pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQSETCLEAR;
|
||
|
pCQBlock->value = 0;
|
||
|
//
|
||
|
// Need to protect access of ui32NumPendTransactions as it is accessed
|
||
|
// from ISR as well
|
||
|
//
|
||
|
// Start a critical section.
|
||
|
//
|
||
|
ui32Critical = am_hal_interrupt_master_disable();
|
||
|
|
||
|
//
|
||
|
// Post to the CQ.
|
||
|
//
|
||
|
ui32Status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, true);
|
||
|
|
||
|
if (AM_HAL_STATUS_SUCCESS != ui32Status)
|
||
|
{
|
||
|
am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32_t ui32NumPend = pIOMState->ui32NumPendTransactions++;
|
||
|
if (0 == ui32NumPend)
|
||
|
{
|
||
|
pIOMState->ui32UserIntCfg = IOMn(ui32Module)->INTEN;
|
||
|
IOM_SET_INTEN(ui32Module, AM_HAL_IOM_INT_CQMODE);
|
||
|
// Re-enable the CQ
|
||
|
am_hal_iom_CQEnable(pIOMState);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// End the critical section.
|
||
|
//
|
||
|
am_hal_interrupt_master_set(ui32Critical);
|
||
|
// Use SWFLAG6 to cause a pause
|
||
|
pause = AM_HAL_IOM_PAUSE_FLAG_SEQLOOP;
|
||
|
// Revert back the flag after SW callback unpauses it
|
||
|
scUnpause = AM_HAL_IOM_SC_PAUSE_SEQLOOP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Insert the loopback
|
||
|
ui32Status = am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, sizeof(am_hal_iom_cq_loop_entry_t) / 8, &pCQBlock, &index);
|
||
|
if (ui32Status != AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
am_hal_iom_cq_loop_entry_t *pLoopEntry = (am_hal_iom_cq_loop_entry_t *)pCQBlock;
|
||
|
pLoopEntry->ui32PAUSENAddr = pLoopEntry->ui32PAUSEN2Addr = (uint32_t)&IOMn(ui32Module)->CQPAUSEEN;
|
||
|
pLoopEntry->ui32SETCLRAddr = (uint32_t)&IOMn(ui32Module)->CQSETCLEAR;
|
||
|
pLoopEntry->ui32PAUSEENVal = get_pause_val(pIOMState, pLoop->ui32PauseCondition | pause);
|
||
|
pLoopEntry->ui32PAUSEEN2Val = AM_HAL_IOM_PAUSE_DEFAULT;
|
||
|
pLoopEntry->ui32SETCLRVal = pLoop->ui32StatusSetClr | scUnpause;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Need to protect access of ui32NumPendTransactions as it is accessed
|
||
|
// from ISR as well
|
||
|
//
|
||
|
// Start a critical section.
|
||
|
//
|
||
|
ui32Critical = am_hal_interrupt_master_disable();
|
||
|
|
||
|
//
|
||
|
// Post to the CQ.
|
||
|
//
|
||
|
if (pLoop->bLoop)
|
||
|
{
|
||
|
ui32Status = am_hal_cmdq_post_loop_block(pIOMState->pCmdQHdl, false);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ui32Status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, false);
|
||
|
}
|
||
|
|
||
|
if (AM_HAL_STATUS_SUCCESS != ui32Status)
|
||
|
{
|
||
|
am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32_t ui32NumPend = pIOMState->ui32NumPendTransactions++;
|
||
|
pIOMState->eSeq = (pLoop->bLoop) ? AM_HAL_IOM_SEQ_RUNNING : AM_HAL_IOM_SEQ_NONE;
|
||
|
if (0 == ui32NumPend)
|
||
|
{
|
||
|
pIOMState->ui32UserIntCfg = IOMn(ui32Module)->INTEN;
|
||
|
IOM_SET_INTEN(ui32Module, AM_HAL_IOM_INT_CQMODE);
|
||
|
// Re-enable the CQ
|
||
|
am_hal_iom_CQEnable(pIOMState);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// End the critical section.
|
||
|
//
|
||
|
am_hal_interrupt_master_set(ui32Critical);
|
||
|
}
|
||
|
return AM_HAL_STATUS_SUCCESS;
|
||
|
//break;
|
||
|
}
|
||
|
case AM_HAL_IOM_REQ_INIT_HIPRIO:
|
||
|
{
|
||
|
am_hal_iom_hiprio_cfg_t *pHPCfg = (am_hal_iom_hiprio_cfg_t *)pArgs;
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!pHPCfg)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
pIOMState->ui32NumHPEntries = pIOMState->ui32LastHPIdxProcessed = 0;
|
||
|
pIOMState->ui32NextHPIdx = pIOMState->ui32LastHPIdxProcessed + 1;
|
||
|
pIOMState->pHPTransactions = (am_hal_iom_dma_entry_t *)pHPCfg->pBuf;
|
||
|
pIOMState->ui32MaxHPTransactions = pHPCfg->size / sizeof(am_hal_iom_dma_entry_t);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AM_HAL_IOM_REQ_START_BLOCK:
|
||
|
// Pause the next block from proceeding till whole block is finished
|
||
|
IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_PAUSE_BLOCK;
|
||
|
pIOMState->block = 1;
|
||
|
pIOMState->ui32NumHPPendingEntries = 0;
|
||
|
break;
|
||
|
|
||
|
case AM_HAL_IOM_REQ_END_BLOCK:
|
||
|
// Unblock the whole batch of commands in this block
|
||
|
IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_BLOCK;
|
||
|
pIOMState->block = 0;
|
||
|
if (pIOMState->ui32NumHPPendingEntries)
|
||
|
{
|
||
|
// Now it is okay to let go of the block of HiPrio transactions
|
||
|
status = sched_hiprio(pIOMState, pIOMState->ui32NumHPPendingEntries);
|
||
|
if (status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
pIOMState->ui32NumHPPendingEntries = 0;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case AM_HAL_IOM_REQ_SET_DCX:
|
||
|
{
|
||
|
am_hal_iom_dcx_cfg_t *pDcxCfg = (am_hal_iom_dcx_cfg_t *)pArgs;
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!pDcxCfg)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if ((pIOMState->eInterfaceMode != AM_HAL_IOM_SPI_MODE) ||
|
||
|
(pDcxCfg->cs == pDcxCfg->dcx) ||
|
||
|
(pDcxCfg->cs > AM_HAL_IOM_MAX_CS_SPI) ||
|
||
|
((pDcxCfg->dcx != AM_HAL_IOM_DCX_INVALID) && (pDcxCfg->dcx > AM_HAL_IOM_MAX_CS_SPI)))
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
if ( !APOLLO3_GE_B0 )
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
|
||
|
pIOMState->dcx[pDcxCfg->cs] = (pDcxCfg->dcx == AM_HAL_IOM_DCX_INVALID) ? 0 : (IOM0_DCX_DCXEN_Msk | (0x1 << pDcxCfg->dcx));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AM_HAL_IOM_REQ_CQ_RAW:
|
||
|
{
|
||
|
am_hal_iom_cq_raw_t *pCqRaw = (am_hal_iom_cq_raw_t *)pArgs;
|
||
|
am_hal_cmdq_entry_t *pCQBlock;
|
||
|
am_hal_iom_callback_t pfnCallback1;
|
||
|
|
||
|
uint32_t ui32Critical = 0;
|
||
|
uint32_t index;
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
if (!pCqRaw)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (!pIOMState->pCmdQHdl)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
//
|
||
|
// Check to see if there is enough room in the CQ
|
||
|
//
|
||
|
if ((pIOMState->ui32NumPendTransactions == AM_HAL_IOM_MAX_PENDING_TRANSACTIONS) ||
|
||
|
(am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, pCqRaw->numEntries + 3, &pCQBlock, &index)))
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
|
||
|
pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQPAUSEEN;
|
||
|
pCQBlock->value = get_pause_val(pIOMState, pCqRaw->ui32PauseCondition);
|
||
|
pCQBlock++;
|
||
|
for (uint32_t i = 0; i < pCqRaw->numEntries; i++, pCQBlock++)
|
||
|
{
|
||
|
pCQBlock->address = pCqRaw->pCQEntry[i].address;
|
||
|
pCQBlock->value = pCqRaw->pCQEntry[i].value;
|
||
|
}
|
||
|
// If there is a need - populate the jump back address
|
||
|
if (pCqRaw->pJmpAddr)
|
||
|
{
|
||
|
*(pCqRaw->pJmpAddr) = (uint32_t)pCQBlock;
|
||
|
}
|
||
|
pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQPAUSEEN;
|
||
|
pCQBlock->value = AM_HAL_IOM_PAUSE_DEFAULT;
|
||
|
pCQBlock++;
|
||
|
pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQSETCLEAR;
|
||
|
pCQBlock->value = pCqRaw->ui32StatusSetClr;
|
||
|
|
||
|
pfnCallback1 = pCqRaw->pfnCallback;
|
||
|
if (!pfnCallback1 && !pIOMState->block && (pIOMState->eSeq == AM_HAL_IOM_SEQ_NONE) &&
|
||
|
(pIOMState->ui32NumUnSolicited >= (pIOMState->ui32MaxPending / 2)))
|
||
|
{
|
||
|
// Need to schedule a dummy callback, to ensure ui32NumPendTransactions get updated in ISR
|
||
|
pfnCallback1 = iom_dummy_callback;
|
||
|
}
|
||
|
//
|
||
|
// Store the callback function pointer.
|
||
|
//
|
||
|
pIOMState->pfnCallback[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pfnCallback1;
|
||
|
pIOMState->pCallbackCtxt[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pCqRaw->pCallbackCtxt;
|
||
|
|
||
|
//
|
||
|
// Need to protect access of ui32NumPendTransactions as it is accessed
|
||
|
// from ISR as well
|
||
|
//
|
||
|
// Start a critical section.
|
||
|
//
|
||
|
ui32Critical = am_hal_interrupt_master_disable();
|
||
|
|
||
|
//
|
||
|
// Register for interrupt only if there is a callback
|
||
|
//
|
||
|
status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, pfnCallback1);
|
||
|
|
||
|
if (status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
uint32_t ui32NumPend = pIOMState->ui32NumPendTransactions++;
|
||
|
pIOMState->ui32NumSeqTransactions++;
|
||
|
if (pCqRaw->pfnCallback)
|
||
|
{
|
||
|
pIOMState->bAutonomous = false;
|
||
|
pIOMState->ui32NumUnSolicited = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pfnCallback1)
|
||
|
{
|
||
|
// This implies we have already scheduled a dummy callback
|
||
|
pIOMState->ui32NumUnSolicited = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIOMState->ui32NumUnSolicited++;
|
||
|
}
|
||
|
}
|
||
|
if (0 == ui32NumPend)
|
||
|
{
|
||
|
pIOMState->ui32UserIntCfg = IOMn(ui32Module)->INTEN;
|
||
|
IOM_SET_INTEN(ui32Module, AM_HAL_IOM_INT_CQMODE);
|
||
|
// Re-enable the CQ
|
||
|
am_hal_iom_CQEnable(pIOMState);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
|
||
|
}
|
||
|
//
|
||
|
// End the critical section.
|
||
|
//
|
||
|
am_hal_interrupt_master_set(ui32Critical);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
default:
|
||
|
status = AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// IOM High Priority transfer function
|
||
|
//
|
||
|
uint32_t am_hal_iom_highprio_transfer(void *pHandle,
|
||
|
am_hal_iom_transfer_t *psTransaction,
|
||
|
am_hal_iom_callback_t pfnCallback,
|
||
|
void *pCallbackCtxt)
|
||
|
{
|
||
|
am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pHandle;
|
||
|
uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
|
||
|
|
||
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
||
|
uint32_t ui32SRAMAddress;
|
||
|
|
||
|
//
|
||
|
// Check the handle.
|
||
|
//
|
||
|
if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_HANDLE;
|
||
|
}
|
||
|
if (!pIOMState->pNBTxnBuf)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
ui32Status = validate_transaction(pIOMState, psTransaction, false);
|
||
|
|
||
|
if (ui32Status != AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
return ui32Status;
|
||
|
}
|
||
|
if (psTransaction->ui32PauseCondition != 0)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (psTransaction->ui32StatusSetClr != 0)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_ARG;
|
||
|
}
|
||
|
if (psTransaction->eDirection > AM_HAL_IOM_RX)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
if (!pIOMState->pHPTransactions)
|
||
|
{
|
||
|
return AM_HAL_STATUS_INVALID_OPERATION;
|
||
|
}
|
||
|
//
|
||
|
// Check for DMA to/from DTCM.
|
||
|
//
|
||
|
ui32SRAMAddress = (psTransaction->eDirection == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
|
||
|
|
||
|
if ( (ui32SRAMAddress >= AM_HAL_FLASH_DTCM_START) &&
|
||
|
(ui32SRAMAddress <= AM_HAL_FLASH_DTCM_END) )
|
||
|
{
|
||
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
||
|
}
|
||
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
||
|
|
||
|
|
||
|
ui32Status = iom_add_hp_transaction(pHandle, psTransaction, pfnCallback, pCallbackCtxt);
|
||
|
|
||
|
if (ui32Status == AM_HAL_STATUS_SUCCESS)
|
||
|
{
|
||
|
if (!(pIOMState->block))
|
||
|
{
|
||
|
ui32Status = sched_hiprio(pIOMState, 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIOMState->ui32NumHPPendingEntries++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the status.
|
||
|
//
|
||
|
return ui32Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// End Doxygen group.
|
||
|
//! @}
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// End Doxygen group.
|
||
|
//! @}
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
|