/* Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * 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 * OWNER 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. * */ // // // SIO driver implementation for audio I/O using McASP. // // // #ifndef SAP_CACHE_SUPPORT // if you rebuild dap.c in your project without this defined, // the result is quite hard to find: Occasional glitches in the sound. #define SAP_CACHE_SUPPORT // typically defined in the project #endif #ifdef SAP_CACHE_SUPPORT #include #endif #include #include #include //memset #include #include "sap.h" #include #include #include #include #include #define EDMA_HINV NULL #ifdef SAP_PORT_MCASP #include "sap_mcasp.h" #else #error "No port defined" #endif #include // This works to set a breakpoint #define SW_BREAKPOINT asm( " SWBP 0" ); /* Software Breakpoint to Code Composer */ // SW_BREAKPOINT; // global allocated in bios_edma3_drv_sample_init.c extern EDMA3_DRV_Handle hEdma0; extern EDMA3_DRV_Handle hEdma1; int gStartError; int gIsrInputCnt; int gIsrOutputCnt; int gIsrElseCnt; int gIsrInErrCnt; int gIsrOutErrCnt; int gIsrRunCnt; int gIsrNotRunCnt; int gisrOutput; int gSAPResetIn; int gSAPResetOut; typedef xdc_Short MdInt; void swapHdmi(Ptr, int); //#define TEST_MULTICHANNEL #ifdef TEST_MULTICHANNEL #define SAP_UNDER_LEN 8 //#define SAP_UNDER_LEN 1024 // GJ: experiment #else #define SAP_UNDER_LEN 1024 #endif int sap_UNDER[SAP_UNDER_LEN]; // used for underrun int sap_OVER_1LANE = 0; // used for overrun int sap_OVER_4LANE[4] = {0,0,0,0}; // used for overrun #ifdef DEBUG void DJDBG_SAP_EDMA_dumpParams(int tag_place) { //unsigned int *ptrPARAM_BASE = (unsigned int *)0x02704000; //unsigned int *ptrPARAM0x18 = (unsigned int *)0x02704300; // ((*((EDMA3_CCRL_Regs *) 0x02700000)).PARAMENTRY)[24] unsigned int *ptrPARAM0x19 = (unsigned int *)0x02704320; // ((*((EDMA3_CCRL_Regs *) 0x02700000)).PARAMENTRY)[24] unsigned int *ptrPARAM0x41 = (unsigned int *)0x027048A0; // ((*((EDMA3_CCRL_Regs *) 0x02700000)).PARAMENTRY)[24] unsigned int *ptrPARAM0x42 = (unsigned int *)0x027048C0; // ((*((EDMA3_CCRL_Regs *) 0x02700000)).PARAMENTRY)[24] unsigned int *ptrPARAM0x43 = (unsigned int *)0x027048E0; // ((*((EDMA3_CCRL_Regs *) 0x02700000)).PARAMENTRY)[24] unsigned int *ptrPARAM0x44 = (unsigned int *)0x02704910; // ((*((EDMA3_CCRL_Regs *) 0x02700000)).PARAMENTRY)[24] //Log_info5("PARAM0x18a(%d): 0x%x 0x%x 0x%x 0x%x", tag_place, ptrPARAM0x18[0], ptrPARAM0x18[1], ptrPARAM0x18[2], ptrPARAM0x18[3]); //Log_info5("PARAM0x18b(%d): 0x%x 0x%x 0x%x 0x%x", tag_place, ptrPARAM0x18[4], ptrPARAM0x18[5], ptrPARAM0x18[6], ptrPARAM0x18[7]); Log_info5("PARAM0x19a(%d): ITCINTEN: 0x%02x, TCINTEN: 0x%02x, TCC: 0x%02x, TCCMODE: %d", tag_place, ((ptrPARAM0x19[0] & 0x200000) >> 21), ((ptrPARAM0x19[0] & 0x100000) >> 20), ((ptrPARAM0x19[0] & 0x3F000) >> 12), ((ptrPARAM0x19[0] & 0x800) >> 11)); Log_info5("PARAM0x19b(%d): SRC: 0x%08x, A_B_CNT: 0x%08x, DST: 0x%08x, SRC_DST_BIDX: 0x%08x", tag_place, ptrPARAM0x19[1], ptrPARAM0x19[2], ptrPARAM0x19[3], ptrPARAM0x19[4]); Log_info4("PARAM0x19b(%d): LINK_BCNTRLD: 0x%08x, SRC_DST_CIDX: 0x%08x, CCNT: 0x%08x", tag_place, ptrPARAM0x19[5], ptrPARAM0x19[6], ptrPARAM0x19[7]); Log_info5("PARAM0x41a(%d): ITCINTEN: 0x%02x, TCINTEN: 0x%02x, TCC: 0x%02x, TCCMODE: %d", tag_place, ((ptrPARAM0x41[0] & 0x200000) >> 21), ((ptrPARAM0x41[0] & 0x100000) >> 20), ((ptrPARAM0x41[0] & 0x3F000) >> 12), ((ptrPARAM0x41[0] & 0x800) >> 11)); Log_info5("PARAM0x41b(%d): SRC: 0x%08x, A_B_CNT: 0x%08x, DST: 0x%08x, SRC_DST_BIDX: 0x%08x", tag_place, ptrPARAM0x41[1], ptrPARAM0x41[2], ptrPARAM0x41[3], ptrPARAM0x41[4]); Log_info4("PARAM0x41b(%d): LINK_BCNTRLD: 0x%08x, SRC_DST_CIDX: 0x%08x, CCNT: 0x%08x", tag_place, ptrPARAM0x41[5], ptrPARAM0x41[6], ptrPARAM0x41[7]); Log_info5("PARAM0x42a(%d): ITCINTEN: 0x%02x, TCINTEN: 0x%02x, TCC: 0x%02x, TCCMODE: %d", tag_place, ((ptrPARAM0x42[0] & 0x200000) >> 21), ((ptrPARAM0x42[0] & 0x100000) >> 20), ((ptrPARAM0x42[0] & 0x3F000) >> 12), ((ptrPARAM0x42[0] & 0x800) >> 11)); Log_info5("PARAM0x42b(%d): SRC: 0x%08x, A_B_CNT: 0x%08x, DST: 0x%08x, SRC_DST_BIDX: 0x%08x", tag_place, ptrPARAM0x42[1], ptrPARAM0x42[2], ptrPARAM0x42[3], ptrPARAM0x42[4]); Log_info4("PARAM0x42b(%d): LINK_BCNTRLD: 0x%08x, SRC_DST_CIDX: 0x%08x, CCNT: 0x%08x", tag_place, ptrPARAM0x42[5], ptrPARAM0x42[6], ptrPARAM0x42[7]); Log_info5("PARAM0x43a(%d): ITCINTEN: 0x%02x, TCINTEN: 0x%02x, TCC: 0x%02x, TCCMODE: %d", tag_place, ((ptrPARAM0x43[0] & 0x200000) >> 21), ((ptrPARAM0x43[0] & 0x100000) >> 20), ((ptrPARAM0x43[0] & 0x3F000) >> 12), ((ptrPARAM0x43[0] & 0x800) >> 11)); Log_info5("PARAM0x43b(%d): SRC: 0x%08x, A_B_CNT: 0x%08x, DST: 0x%08x, SRC_DST_BIDX: 0x%08x", tag_place, ptrPARAM0x43[1], ptrPARAM0x43[2], ptrPARAM0x43[3], ptrPARAM0x43[4]); Log_info4("PARAM0x43b(%d): LINK_BCNTRLD: 0x%08x, SRC_DST_CIDX: 0x%08x, CCNT: 0x%08x", tag_place, ptrPARAM0x43[5], ptrPARAM0x43[6], ptrPARAM0x43[7]); Log_info5("PARAM0x44a(%d): ITCINTEN: 0x%02x, TCINTEN: 0x%02x, TCC: 0x%02x, TCCMODE: %d", tag_place, ((ptrPARAM0x44[0] & 0x200000) >> 21), ((ptrPARAM0x44[0] & 0x100000) >> 20), ((ptrPARAM0x44[0] & 0x3F000) >> 12), ((ptrPARAM0x44[0] & 0x800) >> 11)); Log_info5("PARAM0x44b(%d): SRC: 0x%08x, A_B_CNT: 0x%08x, DST: 0x%08x, SRC_DST_BIDX: 0x%08x", tag_place, ptrPARAM0x44[1], ptrPARAM0x44[2], ptrPARAM0x44[3], ptrPARAM0x44[4]); Log_info4("PARAM0x44b(%d): LINK_BCNTRLD: 0x%08x, SRC_DST_CIDX: 0x%08x, CCNT: 0x%08x", tag_place, ptrPARAM0x44[5], ptrPARAM0x44[6], ptrPARAM0x44[7]); //Log_info1("TCC0: ERR reg %x", *((unsigned int *)0x02760120)); //DJDBG } #endif // ............................................................................. // notes: // . add control function to PORT table // . how to handle DMA/PORT specifics in parameter entries // can assume numSers = numChans is general and can be applied by DMA // same for wordSize? // . why are two idle stages needed (seems like 1 is enough)? // ............................................................................. // only one global variable, not static so that DMA and port functions // can access. We cant just store the address in devExt since the ISR has // no context. SAP_DriverObject sapDrv; // needed since SAP_watchDog is called before SAP_init Int SAP_initialized = 0; //Int SAP_close(DEV2_Handle); Int SAP_ctrl(DEV2_Handle, Uns, Arg); Int SAP_idle(DEV2_Handle, Bool); Int SAP_issue(DEV2_Handle); Int SAP_open(DEV2_Handle, String); void SAP_isrCallback (Uint32 tcc, EDMA3_RM_TccStatus status, Ptr context); //Bool SAP_ready(DEV2_Handle, SEM_Handle); Int SAP_reclaim(DEV2_Handle); Int SAP_shutdown(DEV2_Handle); Int SAP_start(DEV2_Handle); Int SAP_config(DEV2_Handle device, const SAP_Params *pParams); Int SAP_EDMA_setupParam (DEV2_Handle device, XDAS_UInt32 targetEdma, XDAS_UInt32 childEdma, XDAS_UInt32 addr, XDAS_UInt32 size); Int SAP_EDMA_setupXfer (DEV2_Handle device, XDAS_UInt32 targetEdma, XDAS_UInt32 parentEdma, XDAS_UInt32 childEdma, DEV2_Frame *pFrame); // ............................................................................. // ............................................................................. SAP_DMA_Fxns SAP_EDMA_FXNS = { SAP_EDMA_setupParam, SAP_EDMA_setupXfer, }; SAP_Fxns SAP_FXNS = { NULL, //SAP_close, -- remove for IROM since not using SAP_ctrl, SAP_idle, SAP_issue, SAP_open, NULL, //SAP_ready, -- remove for IROM since not using SAP_reclaim, SAP_shutdown, SAP_start, SAP_config, #ifdef SAP_PORT_MCASP (SAP_PORT_Fxns *) &SAP_MCASP_FXNS, #endif #ifdef SAP_DMA_EDMA (SAP_DMA_Fxns *) &SAP_EDMA_FXNS, #endif }; // ----------------------------------------------------------------------------- // This function is not in the driver function table. // Must be pointed at in GUI config tool. // Void SAP_init (Void) { DEV2_Device *entry; SAP_Fxns *pFxns; //TRACE_GEN((&TR_MOD, "SAP_init.%d", __LINE__)); // find function table pointer (used by SAP_XX_FTABLE_init macros) DEV2_match(SAP_NAME, &entry); if (entry == NULL) { Log_error1 ("SAP", SIO2_ENODEV); return; } pFxns = (SAP_Fxns *) entry->fxns; //SAP_DMA_FTABLE_init (); SAP_PORT_FTABLE_init (); sapDrv.numDevices = 0; SAP_initialized = 1; return; } // SAP_init // ----------------------------------------------------------------------------- Int SAP_ctrl (DEV2_Handle device, Uns code, Arg arg) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)device->object; const SAP_Params *pParams; Int result = SIO2_OK; EDMA3_DRV_Handle hEdma; //TRACE_GEN((&TR_MOD, "SAP_ctrl.%d (0x%x) code = 0x%x", __LINE__, device, code)); switch (code) { /* .......................................................................... */ case PAF_SIO_CONTROL_MUTE: case PAF_SIO_CONTROL_UNMUTE: pParams = pDevExt->pParams; if (pParams == NULL) return SIO2_OK; if (pParams->sio.control != NULL) result = pParams->sio.control (device, (const PAF_SIO_Params *)pParams, code, arg); break; /* .......................................................................... */ case PAF_SIO_CONTROL_OPEN: if (pDevExt->runState) return SIO2_EBUSY; if (!( pParams = (const SAP_Params *) arg )) return SIO2_OK; if (result = SAP_FTABLE_config (device, pParams)) return result; if (pParams->sio.control && (result = pParams->sio.control (device, (const PAF_SIO_Params *)pParams, code, arg))) return result; break; /* .......................................................................... */ case PAF_SIO_CONTROL_CLOSE: if (pDevExt->runState) return SIO2_EBUSY; if (pDevExt->pParams == NULL) return SIO2_EINVAL; pParams = pDevExt->pParams; if (pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pParams->sio.moduleNum == 1 || pParams->sio.moduleNum == 2) hEdma = hEdma1; if (pDevExt->activeEdma != EDMA_HINV) { EDMA3_DRV_freeChannel (hEdma, pDevExt->activeEdma); pDevExt->activeEdma = EDMA_HINV; } if (!(pParams = pDevExt->pParams)) return SIO2_OK; if (pParams->sio.control && (result = pParams->sio.control (device, (const PAF_SIO_Params *)pParams, code, arg))) return result; result = SAP_PORT_FTABLE_close (device); if (result) return result; pDevExt->pParams = NULL; break; /* .......................................................................... */ case PAF_SIO_CONTROL_GET_WORDSIZE: if (!arg) return SIO2_EINVAL; *((int *) arg) = pDevExt->edmaWordSize; break; case PAF_SIO_CONTROL_SET_WORDSIZE: // defer to DMA processing // currently only supported for input if (device->mode != DEV2_INPUT) return SIO2_EINVAL; // can't be running if (pDevExt->runState) return SIO2_EBUSY; // driver only supports 2 or 4 bytes if ((arg != 2) && (arg != 4)) return SIO2_EINVAL; // return success for unconfigured devices? if (!pDevExt->pParams) return SIO2_OK; // ask platform if size is supported pParams = pDevExt->pParams; if (pDevExt->pParams->sio.control && (result = pDevExt->pParams->sio.control (device, (const PAF_SIO_Params *)pParams, code, arg))) return result; pDevExt->edmaWordSize = arg; break; case PAF_SIO_CONTROL_GET_PRECISION: if (arg == 0) return SIO2_EINVAL; pParams = pDevExt->pParams; if (pParams == NULL) return( SIO2_EINVAL ); *((int *) arg) = pParams->sio.precision; break; case PAF_SIO_CONTROL_GET_NUMCHANNELS: if (arg == 0) return SIO2_EINVAL; *((int *) arg) = pDevExt->numSlots * pDevExt->numSers; break; case PAF_SIO_CONTROL_SET_RATEX: pParams = pDevExt->pParams; if (pParams == NULL) return SIO2_OK ; if (pParams->sio.control == NULL) return SIO2_EINVAL; result = pParams->sio.control( device, (const PAF_SIO_Params *)pParams, PAF_SIO_CONTROL_SET_RATEX, arg); break; /* .......................................................................... */ case PAF_SIO_CONTROL_IDLE: pParams = pDevExt->pParams; if (pParams == NULL) return SIO2_OK ; if (pParams->sio.control == NULL) return SIO2_EINVAL; result = pParams->sio.control( device, (const PAF_SIO_Params *)pParams, PAF_SIO_CONTROL_IDLE, arg); break; case PAF_SIO_CONTROL_IDLE_WITH_CLOCKS: // 1. Here we are intentionally not using SIO_Idle() and // leaving the Tx clock running. We need this to avoid DAC noise, // as well as provide a DIT clock when using digital output. if (device->mode != DEV2_OUTPUT || pDevExt->pParams == NULL) return SIO2_EINVAL; pParams = pDevExt->pParams; if (pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pParams->sio.moduleNum == 1 || pParams->sio.moduleNum == 2) hEdma = hEdma1; result = SAP_FTABLE_shutdown (device); if (result) return result; Log_info0 ("SAP PAF_SIO_CONTROL_IDLE_WITH_CLOCKS; PAF_SIO_ERROR_IDLE_STAGE1"); pDevExt->errorState = PAF_SIO_ERROR_IDLE_STAGE1; #if 1 //DJDBG, if below enableTransfer() is commented, input side continuous working. if (pDevExt->activeEdma != EDMA_HINV) { //EDMA3_DRV_disableTransfer (hEdma0, pDevExt->activeEdma, EDMA3_DRV_TRIG_MODE_EVENT); //if(*((unsigned int *)0x02701000) & 0x01000000) *((unsigned int *)0x02701008) = 0x01000000; //Clear pending even in bit 24! //DJDBG EDMA3_DRV_enableTransfer (hEdma, pDevExt->activeEdma, EDMA3_DRV_TRIG_MODE_EVENT); } #endif //TRACE_GEN((&TR_MOD, "SAP_ctrl.%d: (0x%x) errorState = PAF_SIO_ERROR_IDLE_STAGE1 0x%x.", __LINE__, device, PAF_SIO_ERROR_IDLE_STAGE1)); break; /* .......................................................................... */ case PAF_SIO_CONTROL_GET_INPUT_STATUS: // needs to be attached pParams = pDevExt->pParams; if (pParams == NULL) return SIO2_OK; if (pParams->sio.control == NULL) return SIO2_EINVAL; result = pParams->sio.control( device, (const PAF_SIO_Params *)pParams, code, arg ); break; case PAF_SIO_CONTROL_WATCHDOG: pParams = pDevExt->pParams; if (pParams == NULL) return SIO2_OK; if (pParams->sio.control && (result = pParams->sio.control (device, (const PAF_SIO_Params *)pParams, code, arg))) return result; break; /* .......................................................................... */ // Timing stats specific to DMA engine case PAF_SIO_CONTROL_ENABLE_STATS: case PAF_SIO_CONTROL_DISABLE_STATS: case PAF_SIO_CONTROL_GET_STATS: case PAF_SIO_CONTROL_GET_NUM_EVENTS: case PAF_SIO_CONTROL_GET_NUM_REMAINING: //result = SAP_DMA_FTABLE_ctrl (device, code, arg); // TRACE_VERBOSE((&TR_MOD, "SAP_ctrl: (0x%x) code 0x%x. result 0x%x.", device, code, result)); break; /* .......................................................................... */ case PAF_SIO_CONTROL_SET_DITSTATUS: if(device->mode == DEV2_OUTPUT) { const SAP_Params *pParams = pDevExt->pParams; MCASP_Handle hPort = sapMcaspDrv.hPort[pParams->sio.moduleNum]; volatile Uint32 *base = (volatile Uint32 *)(hPort->baseAddr); MCASP_ConfigXmt *pTxConfig = (MCASP_ConfigXmt *)pParams->sio.pConfig; int encSelect = *((int *) arg); // HACK -- determine DIT need by FXWID if (((pTxConfig->afsxctl & _MCASP_AFSXCTL_FXWID_MASK)>> _MCASP_AFSXCTL_FXWID_SHIFT) == MCASP_AFSXCTL_FXWID_BIT) { if ( (encSelect == 0x13) || (encSelect == 0xa) || (encSelect == 0x6)) // DTE, DDE, MPE { base[_MCASP_DITCSRA0_OFFSET] |= 2; base[_MCASP_DITCSRB0_OFFSET] |= 2; } else { base[_MCASP_DITCSRA0_OFFSET] &= 0xfffffffd; base[_MCASP_DITCSRB0_OFFSET] &= 0xfffffffd; } } pParams = pDevExt->pParams; if (pParams == NULL) return SIO2_OK; if (pParams->sio.control != NULL) result = pParams->sio.control (device, (const PAF_SIO_Params *)pParams, code, arg); } break; /* .......................................................................... */ } return result; } // SAP_ctrl int gSAPIdleShutdownIn=0; int gSAPIdleShutdownOut=0; // ----------------------------------------------------------------------------- Int SAP_idle (DEV2_Handle device, Bool flush) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)device->object; Int result = SIO2_OK; EDMA3_DRV_Handle hEdma; // do nothing if already idled or unattached if ((!pDevExt->runState) || (pDevExt->pParams == NULL)) return result; if (pDevExt->pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pDevExt->pParams->sio.moduleNum == 1 || pDevExt->pParams->sio.moduleNum == 2) hEdma = hEdma1; // reset serial port -- stop generating sync events result = SAP_PORT_FTABLE_reset (device); if(device->mode == DEV2_OUTPUT) gSAPResetOut++; else gSAPResetIn++; if (result) { //TRACE_VERBOSE((&TR_MOD, "%s.%d: SAP_PORT_FTABLE_reset returned %d.\n", __FUNCTION__, __LINE__, result)); return result; } pDevExt->shutDown = 0; // force shutdown to run result = SAP_FTABLE_shutdown (device); if(device->mode == DEV2_OUTPUT) gSAPIdleShutdownOut++; else gSAPIdleShutdownIn++; if (result) { //TRACE_VERBOSE((&TR_MOD, "%s.%d: SAP_FTABLE_shutdown returned %d.\n", __FUNCTION__, __LINE__, result)); return result; } Log_info0("SAP_idle:Before EDMA3_DRV_disableTransfer"); // disable interrupts and EDMA servicing if (pDevExt->activeEdma != EDMA_HINV) EDMA3_DRV_disableTransfer (hEdma, pDevExt->activeEdma, EDMA3_DRV_TRIG_MODE_EVENT); pDevExt->numQueued = 0; // signal stopped pDevExt->runState = 0; // reset errorState pDevExt->errorState = PAF_SIO_ERROR_NONE; //TRACE_VERBOSE((&TR_MOD, "SAP_ctrl.%d: errorState = PAF_SIO_ERROR_NONE 0x%x.", __LINE__, PAF_SIO_ERROR_NONE)); // place call to physical device if ((pDevExt->pParams != NULL) && (pDevExt->pParams->sio.control != NULL)) result = pDevExt->pParams->sio.control(device, (const PAF_SIO_Params *)pDevExt->pParams, PAF_SIO_CONTROL_IDLE, 0); return result; } // SAP_idle // ----------------------------------------------------------------------------- Int SAP_start (DEV2_Handle device) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)device->object; DEV2_Frame *pFrame; int result; EDMA3_DRV_Handle hEdma; //TRACE_GEN((&TR_MOD, "SAP_start.%d (0x%x)", __LINE__, device)); // signal we have started // we change the state here since we have already moved a frame from the // todevice queue to the xferQue. If an error occurs during one of the // following resets/enables then we need to have runState !=0 in order // for SAP_idle to properly cleanup. Moreover, the following resets/enables // do not (and are now required not to) depend on runState being 0. //pDevExt->runState = 1; // Assume todevice queue is not empty -- how else could we be here? pFrame = (DEV2_Frame *) Queue_get (device->todevice); // inidicate this xfer did not use param entry - just the active one pFrame->misc = NULL; if (pDevExt->pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pDevExt->pParams->sio.moduleNum == 1 || pDevExt->pParams->sio.moduleNum == 2) hEdma = hEdma1; // non-atomic functions since not running yet. Queue_enqueue (Queue_handle(&pDevExt->xferQue), (Queue_Elem *)pFrame); // initialize count pDevExt->numQueued = 1; result = SAP_PORT_FTABLE_reset (device); if (result) { //TRACE_VERBOSE((&TR_MOD, "%s.%d: SAP_PORT_FTABLE_reset returned %d.\n", __FUNCTION__, __LINE__, result)); return result; } // enable DMA processing // config active xfer for this buffer result = SAP_EDMA_setupXfer(device, pDevExt->activeEdma, EDMA_HINV, pDevExt->errorEdma, pFrame); //Log_info3("SAP_start.%d, pDevExt->activeEdma 0x%x (pDevExt->errorEdma = 0x%x)", // __LINE__, pDevExt->activeEdma, pDevExt->errorEdma); // signal we have started -- this must come before last enable to prevent a race // condition where the initial EDMA transfer is very small (e.g. due to startClocks) // and completes before any further instructions in this thread are executed. // This comes before the EDMA enable since, if the # of samples is 1, then the EDMA // will be serviced and generate an interrupt even before the McASP is enabled. pDevExt->runState = 1; pDevExt->shutDown = 0; Log_info1 ("SAP: %d, SAP_start runState=1 & ENABLE TRANSFERS", __LINE__); // enable interrupts and event servicing for this channel EDMA3_DRV_enableTransfer (hEdma, pDevExt->activeEdma, EDMA3_DRV_TRIG_MODE_EVENT); // enable peripheral result = SAP_PORT_FTABLE_enable (device); if (result) { //TRACE_VERBOSE((&TR_MOD, "%s.%d: SAP_PORT_FTABLE_enable returned %d.\n", __FUNCTION__, __LINE__, result)); return result; } return SIO2_OK; } // SAP_start int gDmaParamsarray[17][3]; int gDmaParamsidx=0, gSAPSpecialCase=0; // ----------------------------------------------------------------------------- Int SAP_issue (DEV2_Handle device) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)device->object; DEV2_Frame *pFrame; Int result; SAP_EDMA_Param *pParam; XDAS_UInt32 parentEdma; //TRACE_GEN((&TR_MOD, "SAP_issue.%d (0x%x)", __LINE__, device)); if ((device->mode == DEV2_OUTPUT) && (pDevExt->errorState >= PAF_SIO_ERROR_ERRBUF_XFER)) { /*TRACE_TERSE((&TR_MOD, "SAP_issue.%d, errorState 0x%x (PAF_SIO_ERROR_ERRBUF_XFER = 0x%x)", __LINE__, pDevExt->errorState, PAF_SIO_ERROR_ERRBUF_XFER));*/ Log_info3("SAP_issue.%d, PAF_SIO_ERROR_ERRBUF_XFER = 0x%x, mode = 0x%x)", __LINE__, PAF_SIO_ERROR_ERRBUF_XFER, device->mode ); return SIO2_EBADIO; } if ((device->mode == DEV2_INPUT) && pDevExt->errorState) { Log_info1("SAP_issue: Input Error Trap, with errorState = 0x%x", pDevExt->errorState); return SIO2_EBADIO; } // if not yet running then configure active xfer and start if (pDevExt->runState == 0) return (SAP_FTABLE_start(device)); // ......................................................................... // here if running // disable device interrupts // TODO: is there an API to just disable the IER bit for this tcc? unsigned int key = Hwi_disable (); /* determine parent EDMA if no xfers in queue and we are running then must be in the error state so link to active channel otherwise link to last transfer queued. */ /* here we assume after Tx SIO_idle or overrun, the user will issue, at least, back-to-back issue requests so there should be no problem here. */ if ((pDevExt->numQueued <= 1) && (pDevExt->errorState != 2)) parentEdma = pDevExt->activeEdma; else { // if here then xferQue has more than one element so ok to use tail // last scheduled transfer must be queue->prev DEV2_Frame *tail = (DEV2_Frame *) Queue_prev ((Queue_Elem *)&pDevExt->xferQue); parentEdma = ((SAP_EDMA_Param *) tail->misc)->hEdmaParam; } // get frame and parameter table to use; ints off => non-atomic OK // dont need to check for empty queues since were here then todevice // must have a frame placed there by the SIO_issue layer. // paramQue must be valid since it is accessed the same as todevice. // (indirectly -- isr places used items onto paramQue and fromdevice que // at the same time) // set misc argument to pParam so get enqueue later //pFrame = (DEV2_Frame *) Queue_dequeue (device->todevice); pFrame = Queue_dequeue (device->todevice); pParam = (SAP_EDMA_Param *) Queue_dequeue (Queue_handle(&pDevExt->paramQue)); if (pParam->hEdmaParam == NULL) Log_info0("SAP_issue: hEdma value is NULL"); // set misc argument to pParam so get enqueue later pFrame->misc = (Arg) pParam; // place on holder queue, ints off => non-atomic OK Queue_enqueue (Queue_handle(&pDevExt->xferQue), (Queue_Elem *) pFrame); if (pFrame->addr) { if (device->mode == DEV2_INPUT) Cache_inv (pFrame->addr, pFrame->size, Cache_Type_ALL, TRUE); else Cache_wbInv (pFrame->addr, pFrame->size, Cache_Type_ALL, TRUE); } // increment count pDevExt->numQueued += 1; result = SAP_EDMA_setupXfer (device, pParam->hEdmaParam, parentEdma, pDevExt->errorEdma, pFrame); Log_info4("SAP_issue.%d, EDMA_setupXfer: Target EDMA: 0x%x, Parent Edma: 0x%x Error Edma: 0x%x", __LINE__, pParam->hEdmaParam, parentEdma, pDevExt->errorEdma); /*if ((device->mode != DEV2_INPUT) && (gDmaParamsidx <=16)) { gDmaParamsarray[gDmaParamsidx][0] = pParam->hEdma; gDmaParamsarray[gDmaParamsidx][1] = parentEdma; gDmaParamsarray[gDmaParamsidx++][2] = gisrOutput; } */ if ((pDevExt->errorState == PAF_SIO_ERROR_IDLE_STAGE1) && (device->mode == DEV2_OUTPUT)) pDevExt->errorState = PAF_SIO_ERROR_NONE; pDevExt->shutDown = 0; // special case enables when not yet started if (pDevExt->runState == 0) { gSAPSpecialCase++; result = SAP_FTABLE_start (device); if (result) { //SAP_DMA_FTABLE_unlock (device); Hwi_restore (key); return result; } } Hwi_restore (key); //DJDBG return result; } // SAP_issue // ----------------------------------------------------------------------------- void swapHdmi(Ptr Input, int size) { MdInt L0, L1, L2, L3, R0, R1, R2, R3 = 0; MdInt *p1, *p2; int i=0; for (i=0; i< size; i+=16) { p1 = (MdInt *)&Input[i]; p2 = p1; L0 = *p1++; L1 = *p1++; L2 = *p1++; L3 = *p1++; R0 = *p1++; R1 = *p1++; R2 = *p1++; R3 = *p1++; *p2++ = L0; *p2++ = R0; *p2++ = L1; *p2++ = R1; *p2++ = L2; *p2++ = R2; *p2++ = L3; *p2++ = R3; } Log_info3("SAP: Exiting swapHdmi with Frame->Addr: 0x%x, p1->addr: 0x%x, p2->addr: 0x%x ", (xdc_IArg)Input, p1, p2); return; } Int SAP_reclaim (DEV2_Handle device) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)(device->object); #ifdef SAP_CACHE_SUPPORT DEV2_Frame *pFrame; #endif //TRACE_GEN((&TR_MOD, "SAP_reclaim.%d (0x%x)", __LINE__, device)); // must be running and error free if ((!pDevExt->runState) || (pDevExt->errorState)) { //TRACE_GEN((&TR_MOD, "SAP_reclaim.%d, not runState: 0x%x", __LINE__, pDevExt->errorState)); return SIO2_EBADIO; } // idle if necessary if (pDevExt->errorState == PAF_SIO_ERROR_FATAL) { Log_info1("SAP_reclaim: PAF_SIO_ERROR_FATAL, Before Idle for device 0x%x ", device->mode); DEV2_idle (device, 1); return SIO2_EBADIO; } // Log_info0("SAP_reclaim: Before SEM Pend"); // wait for ISR to signal block completion //TRACE_VERBOSE((&TR_MOD, "SAP_reclaim.%d wait for ISR to signal block completion", __LINE__)); if (!Semaphore_pend(pDevExt->sync, device->timeout)) { Log_info0("SAP_reclaim, SYS_ETIMEOUT"); return SIO2_ETIMEOUT; } //Log_info1("SAP_reclaim: After SEM Pend for mode: 0x%x", device->mode); #if 0 // return error (owner must idle) if (pDevExt->errorState == PAF_SIO_ERROR_FATAL) { DEV2_idle (device, 1); //TRACE_TERSE((&TR_MOD, "SAP_reclaim.%d, PAF_SIO_ERROR_FATAL: 0x%x", __LINE__, pDevExt->errorState)); return PAF_SIO_ERROR_FATAL; } #endif #ifdef SAP_CACHE_SUPPORT // invalidate CACHE region if input -- use clean since // Dont clean if was for fill. // since pend returned we know that head of fromdevice is valid pFrame = Queue_head (device->fromdevice); Log_info2("SAP: Inside SAP_Reclaim with From Device Frame->Addr: 0x%x and Frame->Size: %d", pFrame->addr, pFrame->size); if ((device->mode == DEV2_INPUT) && (pFrame->addr != NULL)) { if(pDevExt->edmaWordSize == 2 && pDevExt->numSers == 4) { Cache_inv (pFrame->addr, pFrame->size, Cache_Type_ALL, 0); Cache_wait(); // max HWI disable duration ~1ms observed //unsigned int key = Hwi_disable (); // GJ: Revisit, along with other context protections here. swapHdmi(pFrame->addr, pFrame->size); //Hwi_restore(key); Cache_wb (pFrame->addr, pFrame->size, Cache_Type_ALL, 0); Cache_wait(); } } #endif /*if ((device->mode == DEV2_OUTPUT) && (pFrame->addr == NULL)) SW_BREAKPOINT; */ Log_info1("SAP_reclaim: Exiting with SIO2_OK for device 0x%x ", device->mode); //TRACE_VERBOSE((&TR_MOD, "SAP_reclaim.%d, exit SIO2_OK", __LINE__)); return SIO2_OK; } // SAP_reclaim // ----------------------------------------------------------------------------- Int SAP_open (DEV2_Handle device, String name) { SAP_DeviceExtension *pDevExt; DEV2_Device *entry; Int oldMask, result; Error_Block eb; //TRACE_GEN((&TR_MOD, "SAP_open.%d (0x%x)", __LINE__, device)); // check SIO mode if ((device->mode != DEV2_INPUT) && (device->mode != DEV2_OUTPUT)) return SIO2_EMODE; // allocate memory for device extension device->object = NULL; pDevExt = (SAP_DeviceExtension *) Memory_alloc (device->bufSeg, (sizeof(SAP_DeviceExtension)+3)/4*4, 4, &eb); if (pDevExt == NULL) { printf("%s.%d: MEM_alloc failed.\n", __FUNCTION__, __LINE__); //TRACE_TERSE((&TR_MOD, "%s.%d: MEM_alloc failed.\n", __FUNCTION__, __LINE__)); asm( " SWBP 0" ); // SW Breakpoint return SIO2_EALLOC; } device->object = (Ptr)pDevExt; // inits pDevExt->device = device; pDevExt->sync = NULL; pDevExt->pParams = NULL; pDevExt->runState = 0; // not yet started pDevExt->errorState = PAF_SIO_ERROR_NONE; pDevExt->shutDown = 1; pDevExt->numQueued = 0; pDevExt->activeEdma = EDMA_HINV; pDevExt->errorEdma = EDMA_HINV; pDevExt->firstTCC = 0; pDevExt->optLevel = 0; pDevExt->numParamSetup = 0; pDevExt->numEdmaParams = 4; // use dev match to fetch function table pointer for SAP DEV2_match(SAP_NAME, &entry); if (entry == NULL) { Log_error1("SAP", SIO2_ENODEV); return SIO2_ENODEV; } pDevExt->pFxns = (SAP_Fxns *) entry->fxns; // create semaphore for device pDevExt->sync = Semaphore_create (0, NULL, NULL); if (pDevExt->sync == NULL) { //TRACE_TERSE((&TR_MOD, "%s.%d: create semaphore for device failed.\n", __FUNCTION__, __LINE__)); return SIO2_EALLOC; } // queue inits Queue_construct (&pDevExt->xferQue, NULL); Queue_construct (&pDevExt->paramQue, NULL); // update driver global (need to protect context) if (sapDrv.numDevices >= MAX_SAP_DEVICES) { /*TRACE_TERSE((&TR_MOD, "%s.%d: add device failure: no. of devices = %d; need to increase MAX_SAP_DEVICES.\n", __FUNCTION__, __LINE__, dapDrv.numDevices));*/ SW_BREAKPOINT; } oldMask = Hwi_disable (); sapDrv.device[sapDrv.numDevices] = device; pDevExt->deviceNum = sapDrv.numDevices++; Hwi_restore (oldMask); // PORT init result = SAP_PORT_FTABLE_open (device); if (result) { //TRACE_TERSE((&TR_MOD, "%s.%d: SAP_PORT_FTABLE_open returned %d.\n", __FUNCTION__, __LINE__, result)); return result; } return result; } // SAP_open // ----------------------------------------------------------------------------- Int SAP_config (DEV2_Handle device, const SAP_Params *pParams) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)device->object; Int result, Que_num, i; EDMA3_DRV_Result edmaResult; Uint32 reqTcc; EDMA3_DRV_Handle hEdma; Log_info2("SAP_config.%d (0x%x)", __LINE__, device); // cannot configure if transfer started if (pDevExt->runState == 1) return SIO2_EBADIO; // save pointer to config structure in device extension. here so that // forthcoming functions can use/modify config structure. pDevExt->pParams = pParams; pDevExt->edmaWordSize = pParams->sio.wordSize; // allocate Port resources. // This must come before DMA configuration result = SAP_PORT_FTABLE_alloc (device); if (result) { Log_info3("%s.%d: SAP_PORT_FTABLE_alloc returned %d.\n", (xdc_IArg) __FUNCTION__, __LINE__, result); return result; } // ............................................................................. // EDMA configuration // DA10x McASP0 Specific if (pParams->sio.moduleNum == 0) { hEdma = hEdma0; if (device->mode == DEV2_INPUT) { Que_num = 0; pDevExt->activeEdma = CSL_EDMACC_0_McASP_0_REVT; } else { Que_num = 1; pDevExt->activeEdma = CSL_EDMACC_0_McASP_0_XEVT; } } // DA10x McASP1 Specific else if (pParams->sio.moduleNum == 1) { hEdma = hEdma1; if (device->mode == DEV2_INPUT) { Que_num = 0; pDevExt->activeEdma = CSL_EDMACC_1_McASP_1_REVT; } else { Que_num = 1; pDevExt->activeEdma = CSL_EDMACC_1_McASP_1_XEVT; } } // DA10x McASP2 Specific else if (pParams->sio.moduleNum == 2) { hEdma = hEdma1; if (device->mode == DEV2_INPUT) { Que_num = 0; pDevExt->activeEdma = CSL_EDMACC_1_McASP_2_REVT; } else { Que_num = 1; pDevExt->activeEdma = CSL_EDMACC_1_McASP_2_XEVT; } } for (i=0; i < pDevExt->numEdmaParams; i++) { reqTcc = EDMA3_DRV_TCC_ANY; pDevExt->edmaParams[i].hEdmaParam = EDMA3_DRV_LINK_CHANNEL; edmaResult = EDMA3_DRV_requestChannel ( hEdma, &pDevExt->edmaParams[i].hEdmaParam, &reqTcc, (EDMA3_RM_EventQueue) Que_num, SAP_isrCallback, (void *) device); if (edmaResult != EDMA3_DRV_SOK) return SIO2_EALLOC; //not running => can use non-atomic functions Queue_enqueue (Queue_handle(&pDevExt->paramQue), (Queue_Elem *)&pDevExt->edmaParams[i]); } reqTcc = EDMA3_DRV_TCC_ANY; pDevExt->errorEdma = EDMA3_DRV_LINK_CHANNEL; edmaResult = EDMA3_DRV_requestChannel ( hEdma, &pDevExt->errorEdma, &reqTcc, (EDMA3_RM_EventQueue)Que_num, SAP_isrCallback, (void *) device); if (edmaResult != EDMA3_DRV_SOK) return SIO2_EALLOC; // allocate edma channel -- also disable and clear the interrupt pDevExt->firstTCC = pDevExt->activeEdma ; edmaResult = EDMA3_DRV_requestChannel ( hEdma, &pDevExt->activeEdma, &pDevExt->firstTCC, (EDMA3_RM_EventQueue) 0, SAP_isrCallback, (void *) device); if (edmaResult != EDMA3_DRV_SOK) { Log_info3("%s.%d: SAP_DMA_FTABLE_alloc returned %d.\n", (xdc_IArg)__FUNCTION__, __LINE__, edmaResult); return SIO2_EALLOC; } // Configure error transfer // make cnt same as # of channels in order to maintain alignment // and the error transfer small so that we never have to wait // long for it to complete and trigger a linked transfer. This is // important for establishing output timing when we are idling with // clocks still running. Is fine for Rx as well. result = SAP_DMA_FTABLE_setupParam (device, pDevExt->errorEdma, pDevExt->errorEdma, NULL, pDevExt->edmaWordSize * pDevExt->numSers); Log_info3("%s.%d: Exiting SAP_alloc for %d.\n", (xdc_IArg)__FUNCTION__, __LINE__, pDevExt->activeEdma); return SIO2_OK; } // SAP_config // ----------------------------------------------------------------------------- Int SAP_shutdown (DEV2_Handle device) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)(device->object); SIO2_Handle stream = (SIO2_Handle) device; DEV2_Frame *pFrame; Int i; EDMA3_DRV_Handle hEdma; //TRACE_GEN((&TR_MOD, "SAP_shutdown.%d (0x%x)", __LINE__, device)); if (pDevExt->shutDown) return SIO2_EBADIO; if (pDevExt->pParams == NULL) return SIO2_EINVAL; if (pDevExt->pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pDevExt->pParams->sio.moduleNum == 1 || pDevExt->pParams->sio.moduleNum == 2) hEdma = hEdma1; if (pDevExt->activeEdma != EDMA_HINV) EDMA3_DRV_disableTransfer (hEdma, pDevExt->activeEdma, EDMA3_DRV_TRIG_MODE_EVENT); // reset queues while (!Queue_empty(device->todevice)) { // place oustanding requests onto holding queue pFrame = (DEV2_Frame *) Queue_dequeue (device->todevice); Queue_enqueue (Queue_handle(&pDevExt->xferQue), (Queue_Elem *) pFrame); } while (!Queue_empty(Queue_handle(&pDevExt->xferQue))) { // pull frame from holding queue and place on user queue pFrame = (DEV2_Frame *) Queue_dequeue (Queue_handle(&pDevExt->xferQue)); Queue_enqueue (device->fromdevice, (Queue_Elem *) pFrame); } while (!Queue_empty(Queue_handle(&pDevExt->paramQue))) Queue_dequeue (Queue_handle(&pDevExt->paramQue)); // not running => can use non-atomic functions for (i=0; i < pDevExt->numEdmaParams; i++) Queue_enqueue (Queue_handle(&pDevExt->paramQue), (Queue_Elem *) &pDevExt->edmaParams[i]); // reset counter pDevExt->numQueued = 0; //DJDBG_SAP_EDMA_dumpParams(1); // make sure active is linked to error EDMA3_DRV_linkChannel (hEdma, pDevExt->activeEdma, pDevExt->errorEdma); // think this is better (from SIO_idle for standard model ) // refill frame list -- so user needn't call reclaim, which may cause Rx underrun. while (!Queue_empty(device->fromdevice)) { /* place oustanding requests onto holding queue */ pFrame = (DEV2_Frame *) Queue_dequeue (device->fromdevice); Queue_enqueue (Queue_handle(&stream->framelist), (Queue_Elem *) pFrame); } Semaphore_reset (pDevExt->sync, 0); pDevExt->shutDown = 1; pDevExt->numParamSetup = 0; /*result = SAP_DMA_FTABLE_unlock (device); if (result) { //TRACE_TERSE((&TR_MOD, "%s.%d: SAP_DMA_FTABLE_unlock returned %d.\n", __FUNCTION__, __LINE__, result)); return result; } */ return SIO2_OK; } // SAP_shutdown // ----------------------------------------------------------------------------- int gSapWatchDogThrottle = 0; //DJDBG int gSapWatchDogIn =0; int gSapWatchDogOut = 0; int gSapWatchDogInSemPost = 0; int gSapWatchDogOutSemPost = 0; Void SAP_watchDog (Void) { DEV2_Handle device; SAP_DeviceExtension *pDevExt; int i, oldMask, result; //Log_info2("SAP_watchDog.%d (0x%x)", __LINE__, device); // do nothing if SAP_init not yet called if (!SAP_initialized) { Log_info2("%s.%d: SAP_init not yet called.\n", __FUNCTION__, __LINE__); return; } // protect context Task_disable (); // needed since we may call SEM_post //oldMask = Hwi_disable (); //TRACE_VERBOSE((&TR_MOD, "%s.%d: devices loop, numDevices = %d", __FUNCTION__, __LINE__, dapDrv.numDevices)); for (i=0; i < sapDrv.numDevices; i++) { device = sapDrv.device[i]; //TRACE_VERBOSE((&TR_MOD, "%s.%d, devices loop start, device = 0x%x", __FUNCTION__, __LINE__, device)); pDevExt = (SAP_DeviceExtension *) device->object; // do nothing if not running if (!pDevExt->runState) continue; // call board specific watchdog // TODO: handle return value SIO2_ctrl (device, PAF_SIO_CONTROL_WATCHDOG, NULL); // if port layer returns error then must need to clean up result = SAP_PORT_FTABLE_watchDog (device); if (result) { // set errorState which will force owner thread // to clean up via SIO_idle() pDevExt->errorState = PAF_SIO_ERROR_FATAL; if(device->mode == DEV2_INPUT) gSapWatchDogIn++; else gSapWatchDogOut++; //TRACE_TERSE((&TR_MOD, "SAP_watchDog.%d, PAF_SIO_ERROR_FATAL: 0x%x", __LINE__, pDevExt->errorState)); /* if(gSapWatchDogThrottle == 0) //DJDBG { Log_info3("SAP_watchDog.%d (0x%x); THROTTLED result = 0x%x", __LINE__, device, result); } gSapWatchDogThrottle ++; if(gSapWatchDogThrottle > 10) gSapWatchDogThrottle = 0; */ // if outstanding pend then post to free owner thead if (!Semaphore_pend(pDevExt->sync, 0)) { if(device->mode == DEV2_INPUT) gSapWatchDogInSemPost++; else gSapWatchDogOutSemPost++; Semaphore_post (pDevExt->sync); } } } // renable interrupts and task manager. // If we posted to the semaphore then the TSK_enable call will lead to // an immediate task switch to the associated audio thread. //Hwi_restore (oldMask); Task_enable (); } // SAP_watchDog // ----------------------------------------------------------------------------- // Assumes that EDMA3 dispatcher handles TCC clearing. void SAP_isrCallback (Uint32 tcc, EDMA3_RM_TccStatus status, Ptr context) { DEV2_Handle device; SAP_DeviceExtension *pDevExt; DEV2_Frame *pFrame; unsigned int opt; EDMA3_DRV_Handle hEdma; // could be here after Tx idle/overrun and this is the interrupt // for the last occuring error transfer so there is no transfer // to release, we just clear the int and exit. device = (DEV2_Handle) context; pDevExt = (SAP_DeviceExtension *)(device->object); //if (pDevExt->pParams == NULL) //return SIO2_EINVAL; if (pDevExt->pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pDevExt->pParams->sio.moduleNum == 1 || pDevExt->pParams->sio.moduleNum == 2) hEdma = hEdma1; if ((pDevExt->runState == 1) && !pDevExt->errorState) { // if here then an interrupt occured due to errorEdma or valid // transfer, we assume the xfer is long enough so it will not complete // before we are finished here. // if last transfer was valid then complete it if (!Queue_empty(Queue_handle(&pDevExt->xferQue))) { // pull frame from holding queue pFrame = (DEV2_Frame *) Queue_dequeue (Queue_handle(&pDevExt->xferQue)); // if used param entry then return it to queue if (pFrame->misc != NULL) { Queue_enqueue (Queue_handle(&pDevExt->paramQue), (Ptr) pFrame->misc); if (device->mode == 1) gisrOutput+=100; } // decrement count pDevExt->numQueued -= 1; //gIsrCnt++; if (device->mode == 1) gIsrOutputCnt++; else gIsrInputCnt++; // place frame onto user queue and signal user thread Queue_enqueue (device->fromdevice, (Ptr) pFrame); //Log_info2("Before SEM_post for device: 0x%x gIsrOutput: %d", device->mode, gisrOutput); // signal user thread Semaphore_post (pDevExt->sync); #if 0 if(gIsrCnt > 10) { //DJDBG Log_info1("SAP isrCallback enough interrupts! %d", gIsrCnt); } #endif } else gIsrElseCnt++; // determine if currently transferring buffer is valid based on interrupt enable bit // only valid transfers will generate interrupts EDMA3_DRV_getPaRAMEntry (hEdma, pDevExt->activeEdma, EDMA3_DRV_PARAM_ENTRY_OPT, &opt); if (!(opt & EDMA3_DRV_OPT_TCINTEN_SET_MASK (1))) { if (device->mode == 1) gIsrOutErrCnt++; else gIsrInErrCnt++; pDevExt->errorState = PAF_SIO_ERROR_ERRBUF_XFER; } } // runState else { if (pDevExt->runState != 1) gIsrRunCnt++; else gIsrNotRunCnt++; } return; } //SAP_isrCallback // ----------------------------------------------------------------------------- Int SAP_EDMA_setupXfer (DEV2_Handle device, XDAS_UInt32 targetEdma, XDAS_UInt32 parentEdma, XDAS_UInt32 childEdma, DEV2_Frame *pFrame) { EDMA3_DRV_Handle hEdma; SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)device->object; // int mcbspNum = pDevExt->pParams->sio.moduleNum; if (pDevExt->pParams == NULL) return SIO2_EINVAL; if (pDevExt->pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pDevExt->pParams->sio.moduleNum == 1 || pDevExt->pParams->sio.moduleNum == 2) hEdma = hEdma1; // TODO: shouldn't this just be tcc interrupt disable? // at least until linkage phase... unsigned int key = Hwi_disable (); //DJDBG if(targetEdma == NULL) { Log_info0("targetEdma is NULL"); } // configure transfer if(pFrame->addr == NULL) //DJDBG { Log_info0("pFrame has NULL address?"); } SAP_DMA_FTABLE_setupParam (device, targetEdma, childEdma, (XDAS_UInt32) pFrame->addr, pFrame->size); if (parentEdma != EDMA_HINV) EDMA3_DRV_linkChannel (hEdma, parentEdma, targetEdma); Hwi_restore (key); //DJDBG return SIO2_OK; } // SAP_setupXfer // ----------------------------------------------------------------------------- // Configure EDMA3 parameter entry Int SAP_EDMA_setupParam (DEV2_Handle device, XDAS_UInt32 targetEdma, XDAS_UInt32 childEdma, XDAS_UInt32 addr, XDAS_UInt32 size) { SAP_DeviceExtension *pDevExt = (SAP_DeviceExtension *)device->object; EDMA3_DRV_Handle hEdma; EDMA3_DRV_PaRAMRegs edmaConfig; if (pDevExt->pParams == NULL) return SIO2_EINVAL; if (pDevExt->pParams->sio.moduleNum == 0) hEdma = hEdma0; else if (pDevExt->pParams->sio.moduleNum == 1 || pDevExt->pParams->sio.moduleNum == 2) hEdma = hEdma1; MCASP_Handle hPort = sapMcaspDrv.hPort[pDevExt->pParams->sio.moduleNum]; // volatile Uint32 *base = (volatile Uint32 *)(hPort->baseAddr); //Log_info3("%s.%d: Entered SAP_EDMA_setupParam for Target: 0x%x.\n", (xdc_IArg)__FUNCTION__, __LINE__, targetEdma); // Init opt parameter to 0 which, without being overriden, configures as: // A synchronized transfer (no FIFO mode on src or dst) // no chaining or intermediate interrupts // param is not static // normal completion // don't generate an interrupt (overriden below for regular xfers) edmaConfig.opt = 0; // not transferring blocks so c index is 0 edmaConfig.destCIdx = 0; edmaConfig.srcCIdx = 0; edmaConfig.opt |= EDMA3_DRV_OPT_SYNCDIM_SET_MASK (EDMA3_DRV_SYNC_AB); //DJDBG! if (device->mode == DEV2_OUTPUT) { //edmaConfig.opt |= EDMA3_DRV_OPT_DAM_SET_MASK (EDMA3_DRV_ADDR_MODE_FIFO); //DJDBG!!! edmaConfig.opt |= 2; } else { //edmaConfig.opt |= EDMA3_DRV_OPT_SAM_SET_MASK (EDMA3_DRV_ADDR_MODE_FIFO); //DJDBG!!! edmaConfig.opt |= 1; } // if regular transfer then enable interrupt with tcc code if (targetEdma != pDevExt->errorEdma) { edmaConfig.opt |= EDMA3_DRV_OPT_SYNCDIM_SET_MASK (EDMA3_DRV_SYNC_AB); edmaConfig.opt |= EDMA3_DRV_OPT_TCINTEN_SET_MASK (1); edmaConfig.opt |= EDMA3_DRV_OPT_TCC_SET_MASK (pDevExt->firstTCC); } edmaConfig.aCnt = 4; edmaConfig.bCnt = pDevExt->numSers; edmaConfig.cCnt = size/(edmaConfig.aCnt * edmaConfig.bCnt); edmaConfig.bCntReload = edmaConfig.bCnt; // handle direction specific requirements if (device->mode == DEV2_INPUT) { edmaConfig.srcBIdx = 0; edmaConfig.srcAddr = (unsigned int) (hPort->rbufAddr); if (addr) { edmaConfig.destBIdx = pDevExt->edmaWordSize; edmaConfig.destAddr = addr; edmaConfig.destCIdx = pDevExt->edmaWordSize * pDevExt->numSers ; if(pDevExt->edmaWordSize == 2) edmaConfig.cCnt= (size)/((edmaConfig.aCnt * edmaConfig.bCnt)/2); } else { //if(pDevExt->edmaWordSize == 2) //edmaConfig.srcAddr= (unsigned int)edmaConfig.srcAddr+ 2; edmaConfig.destBIdx = 0; edmaConfig.destAddr = (unsigned int) &sap_OVER_4LANE; edmaConfig.cCnt = 1; } } else { edmaConfig.destBIdx = 0; edmaConfig.srcBIdx = pDevExt->edmaWordSize; edmaConfig.destAddr = (unsigned int) (hPort->xbufAddr); if (addr) { edmaConfig.srcCIdx = pDevExt->edmaWordSize * pDevExt->numSers ; edmaConfig.srcAddr = addr; Edma3_CacheFlush ((unsigned int) addr, (size+3)/4); } else { edmaConfig.srcBIdx = 0; edmaConfig.srcAddr = (unsigned int) &sap_UNDER[0]; #if 1 //edmaConfig.cCnt = (SAP_UNDER_LEN * sizeof(int))/(edmaConfig.aCnt * edmaConfig.bCnt); //DJDBG edmaConfig.cCnt = SAP_UNDER_LEN; //DJDBG, if underrun have frame of silence #endif } } edmaConfig.srcAddr = (unsigned int) getGlobalAddr(edmaConfig.srcAddr); edmaConfig.destAddr = (unsigned int) getGlobalAddr(edmaConfig.destAddr); Log_info5("SAP: Inside SAP_EDMA_setupParam with size=0x%x, targetEdma = 0x%x, CCNT = %d with dest-addr: 0x%x and OPT=0x%x", size, targetEdma, edmaConfig.cCnt, edmaConfig.destAddr, edmaConfig.opt); Log_info5("SAP: Inside SAP_EDMA_setupParam with aCnt=0x%x, bCnt = 0x%x, destBIdx = 0x%x destCIdx: 0x%x and bCntReload=0x%x", edmaConfig.aCnt, edmaConfig.bCnt, edmaConfig.destBIdx, edmaConfig.destCIdx, edmaConfig.bCntReload); EDMA3_DRV_setPaRAM (hEdma, targetEdma, &edmaConfig); // link child xfer if (childEdma != EDMA_HINV) EDMA3_DRV_linkChannel (hEdma, targetEdma, childEdma); return SIO2_OK; } //SAP_setupParam