/* 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. * */ /* * ======== audioStreamInpProcNewIo.c ======== */ #include #include #include #include #include "procsdk_audio_typ.h" #include "audioStreamInpProc.h" #include "audioStreamProc_common.h" #include "aspMsg_common.h" #include "aspMsg_master.h" #include "asperr.h" #include "common.h" #include "audk2g.h" #include "audk2g_audio.h" #include "mcasp_cfg.h" #include "ioConfig.h" //TODO: remove this header #include "ioBuff.h" #include "ioPhy.h" #include "ioData.h" #define STRIDE_WORST_CASE 32 // 4-byte (32-bit) word, 2 slots, 4 serializers //#define DEBUG_SKIP_DECODING #define SYNC_PC_MASK 0x1F #define SYNC_SUBTYPE_MASK 0x700 #define SYNC_SUBTYPE_SHIFT 8 #define SYNC_SUBTYPE_DTSHD 0x11 #define SYNC_DDP 0x15 #define SYNC_THD 0x16 #define IEC_HEADER_LENGTH 4 #define INPUT_SWITCH_HANGOVER 8 //table needed until PAF_SOURCE is reordered to match IEC numbering const SmUns IECpafSource[23] = { PAF_SOURCE_UNKNOWN, // 0: IEC NULL Type PAF_SOURCE_AC3, // 1: Comments on 1-15 match IEC 61937 part 2. PAF_SOURCE_UNKNOWN, // 2: IEC reserved PAF_SOURCE_UNKNOWN, // 3: IEC pause PAF_SOURCE_UNKNOWN, // 4: MPEG 1 layer 1 PAF_SOURCE_MP3, // 5: MPEG layer 2 or 3 PAF_SOURCE_UNKNOWN, // 6: MPEG 2 data with extension PAF_SOURCE_AAC, // 7: MPEG-2 AAC ADTS PAF_SOURCE_UNKNOWN, // 8: MPEG 2 layer 1 low sampling frequency PAF_SOURCE_UNKNOWN, // 9: MPEG 2 layer 2 or 3 low sampling frequency PAF_SOURCE_UNKNOWN, // 10: reserved PAF_SOURCE_DTS, // 11: DTS type 1 (11 bit: 512 sample repeat period) PAF_SOURCE_DTS12, // 12: DTS type 2 (12 bit: 1024 sample repeat period) PAF_SOURCE_DTS13, // 13: DTS type 3 (13 bit: 2048 sample repeat period) PAF_SOURCE_DTS14, // 14: ATRAC PAF_SOURCE_UNKNOWN, // 15: ATRAC 2/3 PAF_SOURCE_THD, // 16 PAF_SOURCE_DTSHD, // 17 PAF_SOURCE_WMA9PRO, // 18 PAF_SOURCE_UNKNOWN, // 19 PAF_SOURCE_UNKNOWN, // 20 PAF_SOURCE_DDP, // 21 PAF_SOURCE_THD, // 22 }; /* * Functions defined in other files and to be put into proper header files */ extern Void taskAsipFxnInit(const PAF_ASIT_Params *pP,const PAF_ASIT_Patchs *pQ); // avoid including sap_d10.h, which would cause symbol redefinition // warning (MCASP_PFUNC_XXX) extern XDAS_Int32 D10_init(void * pD10Params); extern XDAS_Int32 D10_RxControl(const void *pD10RxParams, XDAS_Int32 code, XDAS_Int32 arg); /* * Functions only used in this file */ int asitPrepareProcessing(); int asitIoCompsInit(PAF_AST_InpBuf * pInpBuf, PAF_AST_IoInp * pInpIo); void asitProcInit(PAF_AST_IoInp *pInp, asipDecProc_t *pDec); void asitIoPhyPrime(PAF_AST_IoInp *pInpIo); void asitPhyTransferComplete(PAF_AST_IoInp * pInpIo); void asitPhyTransferStart(PAF_AST_IoInp *pInpIo); Int asitRecfgPhyXfer(PAF_AST_IoInp *pInp, size_t xferSize); Int asitSelectDevices(const PAF_ASIT_Patchs *pQ, PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp); Int asitUpdateInputStatus(const void *pRxParams, PAF_InpBufStatus *pStatus, PAF_InpBufConfig *pInpBuf); Int asitSourceDetection(const PAF_ASIT_Params *pP, const PAF_ASIT_Patchs *pQ, PAF_ASIT_Config *pAsitCfg); Int asitDecideSource(PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp, ioDataAutoDetStat_t *autoDetStatus); Int asitUpdateIoComps(const PAF_ASIT_Params *pP, PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp, ioDataAutoDetStat_t *autoDetStatus); Int asitBypassIoData(PAF_AST_IoInp *pInp); Int asitPcmTransition(PAF_ASIT_Config *pAsitCfg); void asitUpdateInpBufConfig(PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp); Int asitInputDataProcess(PAF_AST_IoInp *pInp, ioDataAutoDetStat_t *pAutoDetStats); UInt asitEventsToDecMsg(UInt asitEvents); void asitErrorHandling(PAF_ASIT_Config *pAsitCfg, Int asitErr); Int asitEvtErrCheck(UInt actualEvents, UInt expectedEvents); void asitPostInfoEvent(); void asitPostDecEvent(); /* * variables/structures to be put into proper global structures */ extern PAF_ASIT_Config gPAF_ASIT_config; extern const MdUns iecFrameLength[23]; extern Ptr hMcaspRxChan; #define ASIT_EVTMSK_NONE 0x0 #define ASIT_EVTMSK_INPDATA 0x1 #define ASIT_EVTMSK_INFOACK 0x2 #define ASIT_EVTMSK_DECACK 0x4 #define ASIT_ALL_EVENTS ( ASIT_EVTMSK_INPDATA \ + ASIT_EVTMSK_INFOACK \ + ASIT_EVTMSK_DECACK ) #define ASIT_DEC_EVENTS ( ASIT_EVTMSK_INPDATA \ + ASIT_EVTMSK_INFOACK \ + ASIT_EVTMSK_DECACK ) #define ASIP_DEBUG #ifdef ASIP_DEBUG /* define the following as global variables for easy debugging */ int asipLoopCount1, asipLoopCount2; Int asipErrno; Int inputReadyForProcessing; // FL: debug #include "evmc66x_gpio_dbg.h" #endif Event_Handle asitEvent; Int eventsOn; /* * ======== taskAsipFxn ======== * Audio Stream Input Processing task function */ #ifndef PASDK_SIO_DEV #ifndef IO_LOOPBACK_TEST Void taskAsipFxn( // ASIP task function for new I/O #else Void taskAsipFxn_NewIO_Not_Used( // not used for loopback test #endif #else Void taskAsipFxn_NewIO_Not_USED( // not used for SIO/DEV based I/O #endif const PAF_ASIT_Params *pP, const PAF_ASIT_Patchs *pQ) { PAF_ASIT_Config *pAsitCfg; /* ASIT configuration pointer */ PAF_AST_Config *pAstCfg; /* AST Common (shared) configuration pointer */ PAF_AST_IoInp *pInp; /* Input I/O components */ Int as; /* Audio Stream Number (1, 2, etc.) */ Int z; /* input/encode/stream/decode/output counter */ Int zMI; #ifndef ASIP_DEBUG int asipLoopCount1, asipLoopCount2; Int asipErrno; Int inputReadyForProcessing; #endif Int asitErr; UInt events; // Int eventsOn; Error_Block eb; Log_info0("Enter taskAsipFxn()"); taskAsipFxnInit(pP, pQ); // initialization of input task Error_init(&eb); // initialize error block asitEvent = Event_create(NULL, &eb); if (asitEvent == NULL) { System_abort("Event create failed"); } // // Audio Stream Input Task Configuration (*pAsitCfg): // pAsitCfg = &gPAF_ASIT_config; // initialize pointer to task configuration pAstCfg = pAsitCfg->pAstCfg; // pointer to AST common (shared) configuration /* Set Audio Stream Number (1, 2, etc.) */ as = pAstCfg->as; // // Determine decoder and stream indices associated with the master input // zMI = pP->zone.master; pInp = &pAsitCfg->pIoInp[zMI]; // pointer to input I/O components for (z=STREAM1; z < STREAMN; z++) { TRACE_VERBOSE1("TaskAsip: AS%d: running", as+z); } Log_info0("TaskAsip: Entering Main Loop."); // // Main processing loop // asipLoopCount1 = 0; asipLoopCount2 = 0; asitErr = ASIT_NO_ERR; // The events_on flag will be removed if the RESTART state is changed to // event-based scheduling instead of polling eventsOn = FALSE; for (;;) { asipLoopCount1++; if(eventsOn) { events = Event_pend(asitEvent, ASIT_EVTMSK_NONE, ASIT_ALL_EVENTS, BIOS_WAIT_FOREVER); } switch (pInp->asipState) { case ASIT_RESET: // No events pending in this state // Indicate decoder no decoding yet pP->fxns->sourceDecode(pP, pQ, pAsitCfg, PAF_SOURCE_NONE); // 5 system tick, or 5 msec. Should remove this later when implementing // event based scheduling. Task_sleep(5); inputReadyForProcessing = asitPrepareProcessing(pP, pQ, pAsitCfg, &asipErrno); if (inputReadyForProcessing) { TRACE_VERBOSE0("TaskAsip: Input is ready. Initialize I/O components."); // Input is ready for processing, so we initialize the I/O components. // Note that the I/O components init. and I/O PHY prime are performed only // at the first time. This should be changed later - init. and prime // should be done whenever input interface has changed. asitErr = asitIoCompsInit(&pAstCfg->xInp[zMI], pInp); // Initialize ASIT processing asitProcInit(pInp, &pAsitCfg->inpDec); pInp->asipState = ASIT_SOURCE_DETECTION; eventsOn = TRUE; // turn on events pending TRACE_VERBOSE0("TaskAsip: turn on events and go to source detection."); } break; case ASIT_SOURCE_DETECTION: // Source unknown - to detect & identify source if(events == ASIT_EVTMSK_INPDATA) { // Only this event is expected. If any other event, it's error. // Input data is ready - perform source detection. // New state will be decided inside the function asitErr = asitSourceDetection(pP, pQ, pAsitCfg); } else { //Error checking & debug asitErr = asitEvtErrCheck(events, ASIT_EVTMSK_INPDATA); } break; case ASIT_PCM_TRANSITION: // Source is PCM - transition to PCM decoding if(events == ASIT_EVTMSK_INPDATA) { // Only this event is expected. If any other event, it's error. // Input data is ready - transition to PCM decoding // New state will be decided inside the function asitErr = asitPcmTransition(pAsitCfg); } else { //Error checking & debug asitErr = asitEvtErrCheck(events, ASIT_EVTMSK_INPDATA); } break; case ASIT_DECODE_PROCESSING: if(events & ASIT_DEC_EVENTS) { // Decode processing for either PCM or bitstream // New state will be decided inside the function asitErr = asitDecodeProcessing(pP, pQ, pAsitCfg, events); } else { //Error checking & debug asitErr = asitEvtErrCheck(events, ASIT_DEC_EVENTS); } break; default: break; } if(asitErr) { asitErrorHandling(pAsitCfg, asitErr); if(pInp->asipState == ASIT_RESET) { eventsOn = FALSE; } asitErr = ASIT_NO_ERR; } } // for (;;) } /* taskAsipFxn */ /*=========================================================================== * ASIT Processing Preparation * Output: * - return TRUE (input is ready) or FALSE (input is not ready) * - *asipErrno Error number ============================================================================*/ Int asitPrepareProcessing(const PAF_ASIT_Params *pP, const PAF_ASIT_Patchs *pQ, PAF_ASIT_Config *pC, Int *asipErrno) { Int as, zMS, zMI, zMD; Int sourceConfig, mode; PAF_AST_Config *pAstCfg; PAF_AST_IoInp *pInp; /* I/O components for input */ pAstCfg = pC->pAstCfg; // pointer to AST common (shared) configuration as = pAstCfg->as; zMI = pP->zone.master; zMD = pAstCfg->masterDec; zMS = pAstCfg->masterStr; pInp = pC->pIoInp; // pointer to input I/O components *asipErrno = 0; // Select source and initialize physical layer / HW interface *asipErrno = asitSelectDevices(pQ, pAstCfg, pInp); if (*asipErrno) { TRACE_TERSE2("asitSelectDevices returned asipErrno = 0x%04x at line %d. AS%d", *asipErrno, as+zMS); return FALSE; // Input is not ready for processing due to error } // If no master input selected then we don't know what may be at the input, // so set to unknown and skip any remaining processing if (!pInp[zMI].pRxParams) { sharedMemWriteInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceProgram), (Int8)PAF_SOURCE_UNKNOWN, GATEMP_INDEX_DEC); TRACE_VERBOSE1("TaskAsip: AS%d: No input selected...", as+zMS); return FALSE; // No error, but input is not ready for processing } // If here then we have a valid input so query its status *asipErrno = asitUpdateInputStatus(pInp[zMI].pRxParams, &pAstCfg->xInp[zMI].inpBufStatus, &pAstCfg->xInp[zMI].inpBufConfig); if(*asipErrno) { TRACE_VERBOSE1("TaskAsip: updateInputStatus returns 0x%x", *asipErrno); return FALSE; // Input is not ready for processing due to error } // If master decoder is not enabled, or the input is unlocked, then do nothing mode = (Int)sharedMemReadInt8(&(pAstCfg->xDec[zMD].decodeStatus.mode), GATEMP_INDEX_DEC); if (!mode || !pAstCfg->xInp[zMI].inpBufStatus.lock) { TRACE_VERBOSE0("TaskAsip: Not locked, continue"); return FALSE; // No error, but input is not ready for processing } // Check selected source: sourceSelect is set by another task, AIP or AFP sourceConfig = (Int)sharedMemReadInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceSelect), GATEMP_INDEX_DEC); // If no source selected then do nothing if(sourceConfig == PAF_SOURCE_NONE) { sharedMemWriteInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceProgram), (Int8)PAF_SOURCE_NONE, GATEMP_INDEX_DEC); TRACE_VERBOSE1("TaskAsip: AS%d: no source selected, continue", as+zMS); return FALSE; // No error, but input is not ready for processing } // If we want pass processing then proceed directly if (sourceConfig == PAF_SOURCE_PASS) { TRACE_VERBOSE1("TaskAsip: AS%d: Pass processing ...", as+zMS); sharedMemWriteInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceProgram), (Int8)PAF_SOURCE_PASS, GATEMP_INDEX_DEC); pP->fxns->sourceDecode(pP, pQ, pC, PAF_SOURCE_PASS); if (pP->fxns->passProcessing) { *asipErrno = pP->fxns->passProcessing(pP, pQ, pC, NULL); } else { TRACE_TERSE2("TaskAsip: AS%d: Pass Processing not supported, asipErrno 0x%x", as+zMS, ASPERR_PASS); *asipErrno = ASPERR_PASS; } TRACE_VERBOSE0("TaskAsip: continue"); return FALSE; // Error or not, input is not ready for processing } // No error and input processing is ready return TRUE; } /* asitPrepareProcessing */ /*=========================================================================== * ASIT Source Detection: * ASIT processing for input source identification: * - mark I/O PHY transfer completion * - run auto-detection via I/O DATA in asitInputDataProcess * - mark I/O DATA read completion * - check auto-detection status and take corresponding actions if either * PCM or bitstream is identified: * - decide input source * - update I/O components * - reconfigure McASP LLD if it is PCM * - start next I/O PHY transfer ============================================================================*/ Int asitSourceDetection(const PAF_ASIT_Params *pP, const PAF_ASIT_Patchs *pQ, PAF_ASIT_Config *pAsitCfg) { PAF_AST_Config *pAstCfg; PAF_AST_IoInp *pInp; /* I/O components for input */ Int zMD, mcaspErr, asitErr; ioDataAutoDetStat_t autoDetStatus; pAstCfg = pAsitCfg->pAstCfg; // pointer to AST common (shared) configuration zMD = pAstCfg->masterDec; pInp = &pAsitCfg->pIoInp[zMD]; // pointer to input I/O components // Marks I/O PHY transfer and I/O BUFF write complete asitPhyTransferComplete(pInp); // Process input data - either searching SYNC for PCM or checking SYNC for bitstream asitErr = asitInputDataProcess(pInp, &autoDetStatus); if(asitErr != ASIT_NO_ERR) { // Even though there is error, still need to start next transfer to // maintain McASP transfer. asitPhyTransferStart(pInp); return asitErr; } // Mark input data read complete ioDataReadComplete(pInp->hIoData); // Check if bitstream or PCM is detected if( autoDetStatus.syncState == IODATA_SYNC_BITSTREAM || autoDetStatus.syncState == IODATA_SYNC_PCM) { // Decide input source and inform decoder asitErr = asitDecideSource(pAstCfg, pInp, &autoDetStatus); if(asitErr != ASIT_NO_ERR) { return asitErr; } else { // Update I/O components and input buffer config asitUpdateIoComps(pP, pAstCfg, pInp, &autoDetStatus); // set to unknown so that we can ensure, for IOS purposes, that // sourceDecode = NONE iff we are in this top level state machine // and specifically not in decodeProcessing #ifndef DEBUG_SKIP_DECODING pP->fxns->sourceDecode(pP, pQ, pAsitCfg, PAF_SOURCE_UNKNOWN); #endif if(autoDetStatus.syncState == IODATA_SYNC_BITSTREAM) { // Input is bit stream: go to decoding pInp->asipState = ASIT_DECODE_PROCESSING; } else { // Input is PCM: stop swapping data pInp->swapData = FALSE; // Reconfigure McASP LLD to transfer 32-bit unpacked data mcaspErr = mcaspRecfgWordWidth(pInp->hMcaspChan, Mcasp_WordLength_32); if(mcaspErr != Audk2g_EOK) { return ASIT_ERR_MCASP_CFG; } // Adjust I/O BUFF delay and read pointer - to make sure read pointers // always point to PCM data from 1st I2S (out of 4 for HDMI 4xI2S) ioBuffAdjustDelay(pInp->hIoBuff, pInp->phyXferSize); // Go to transition state to switch to PCM pInp->asipState = ASIT_PCM_TRANSITION; } } } // Start next transfer asitPhyTransferStart(pInp); return (ASIT_NO_ERR); } /* asitSourceDetection */ /*=========================================================================== // // which will cause all 0's in one McASP LLD transfer. This will // be detected as loss of SYNC by auto detection. To prevent that, // skip I/O DATA process for hangover period so that this all 0's // frame will not be seen by auto-detection. Also, playing out PCM // needs to be skipped as well, to prevent from playing out garbage // (16-bit packed data). * * ASIT Transition to PCM decoding. * When PCM is detected, McASP LLD will be reconfigured to transmit 32-bit * words, which will modify the RFMT register. This will cause all 0's in * one McASP LLD transfer, which would be detected as loss of SYNC by auto * detection (performed by I/O DATA). To prevent that, skip I/O DATA process * for hangover period so that this all-0's frame will not be seen by the * auto-detection. * * In addition, playing out PCM should be skipped as well to prevent from * playing out the 16-bit packed data that's still in the input buffer. * * This function does the following: * - mark I/O PHY transfer completion * - bypass I/O DATA * - start next I/O PHY transfer ============================================================================*/ Int asitPcmTransition(PAF_ASIT_Config *pAsitCfg) { Int asitErr; PAF_AST_IoInp *pInp; // I/O components for input Int zMD; zMD = pAsitCfg->pAstCfg->masterDec; // pointer to AST common (shared) configuration pInp = &pAsitCfg->pIoInp[zMD]; // pointer to input I/O components // Marks I/O PHY transfer and I/O BUFF write complete asitPhyTransferComplete(pInp); // Bypass I/O data processing due to McASP LLD work around // (refer to comments inside the function) asitErr = asitBypassIoData(pInp); pInp->pcmSwitchHangOver--; if(pInp->pcmSwitchHangOver == 0) { pInp->asipState = ASIT_DECODE_PROCESSING; } else { ; // stay in this state } // Start next transfer asitPhyTransferStart(pInp); return asitErr; } /* asitPcmTransition */ /*============================================================================ * ASIT Bypass I/O DATA Processing * This function bypasses the I/O DATA processing. It maintains the read * operation of I/O BUFF by directly calling I/O BUFF APIs. When I/O DATA * is not bypassed, I/O BUFF read operation is invoked by I/O DATA. * ============================================================================*/ Int asitBypassIoData(PAF_AST_IoInp *pInp) { void *buff1, *buff2; size_t size1, size2; // Get read pointers (or sub-buffers) of the input buffer if (ioBuffGetReadPtrs(pInp->hIoBuff, pInp->phyXferSize, &buff1, &size1, &buff2, &size2) == IOBUFF_ERR_UNDERFLOW) { pInp->numUnderflow += 1; // Return since there is no enough data to process return ASIT_ERR_INPBUF_UNDERFLOW; } ioBuffReadComplete(pInp->hIoBuff, buff1, size1); if(buff2 != NULL) { ioBuffReadComplete(pInp->hIoBuff, buff2, size2); } return ASIT_NO_ERR; } /* asitBypassIoData */ /*============================================================================ * ASIT Decode Processing * This function performs the decode processing and does the following based * on the ASIT events: * - initialize the decode processing if it is the first time * - if there is ASIT INPUT DATA event (ASIT_EVTMSK_INPDATA): * - mark I/O PHY transfer completion * - run auto-detection via I/O DATA in asitInputDataProcess * - check auto-detection status and take corresponding actions if SYNC * is lost. * - start next I/O PHY transfer * - map ASIT events to decoding messages * - invoke decDecodeFsm() and pass the mapped decoding messages * - if there is ASIT DECODE ACK event (ASIT_EVTMSK_DECACK) * - mark I/O DATA read completion * - error handling ============================================================================*/ Int asitDecodeProcessing(const PAF_ASIT_Params *pP, const PAF_ASIT_Patchs *pQ, PAF_ASIT_Config *pAsitCfg, UInt asitEvents) { Int asitErr, decErr; PAF_AST_IoInp *pInp; // I/O components for input asipDecProc_t *pDec; ioDataAutoDetStat_t autoDetStatus; Int zMD; UInt decMsg; zMD = pAsitCfg->pAstCfg->masterDec; // pointer to AST common (shared) configuration pInp = &pAsitCfg->pIoInp[zMD]; // pointer to input I/O components pDec = &pAsitCfg->inpDec; // Initialization for decode processing when this function is called the first time #ifndef DEBUG_SKIP_DECODING if(!pDec->initDone) { // Initialize decoder decDecodeInit(pP, pAsitCfg, pInp->sourceSelect); pDec->initDone = TRUE; } #endif // Process input data if this is a data ready message if(asitEvents & ASIT_EVTMSK_INPDATA) { TRACE_TERSE0("asitDecodeProcessing: process input data."); // Marks I/O PHY transfer and I/O BUFF write complete asitPhyTransferComplete(pInp); // Process input data - either search SYNC for PCM or check SYNC for bitstream asitErr = asitInputDataProcess(pInp, &autoDetStatus); if(asitErr == ASIT_NO_ERR) { ioDataReadComplete(pInp->hIoData); // Check if SYNC is maintained or lost (stream stops or format changes) if(autoDetStatus.syncState == IODATA_SYNC_NONE) { // SYNC lost: change I/O PHY transfer size to default for auto-detection //asitErr = asitRecfgPhyXfer(pInp, INPUT_FRAME_SIZE_DEF); //if(asitErr != ASIT_NO_ERR) { // return asitErr; //} // Inform decoder to complete the decoding of previous frame - is this good? pInp->sourceSelect = PAF_SOURCE_NONE; pInp->numFrameReceived = 0; // for debugging TRACE_TERSE0("asitDecodeProcessing: SYNC lost."); #ifdef DEBUG_SKIP_DECODING asitErr = ASIT_ERR_DECODE_QUIT; #endif } else { pInp->numFrameReceived += 1; // for debugging // Communicate input stream information to decoder through input // buffer configuration asitUpdateInpBufConfig(pAsitCfg->pAstCfg, pInp); // Start next transfer asitPhyTransferStart(pInp); } // Start next transfer //asitPhyTransferStart(pInp); #ifdef DEBUG_SKIP_DECODING return asitErr; #endif } else if(asitErr == ASIT_ERR_INPBUF_UNDERFLOW) { TRACE_TERSE0("asitDecodeProcessing: Input buffer underflows."); // When input buffer underflows, it is not an error but decoding needs // to be skipped as there is not enough data in the buffer. asitPhyTransferStart(pInp); return asitErr; } else { // Inform decoder to complete the decoding of previous frame - is this good? pInp->sourceSelect = PAF_SOURCE_NONE; pInp->numFrameReceived = 0; // for debugging TRACE_TERSE1("asitDecodeProcessing: asitInputDataProcess error: %d", asitErr); #ifdef DEBUG_SKIP_DECODING return ASIT_ERR_DECODE_QUIT; #endif } } /* ASIT_EVTMSK_INPDATA */ #ifdef DEBUG_SKIP_DECODING else { TRACE_TERSE0("asitDecodeProcessing: events error."); return ASIT_ERR_EVENTS; } #endif #ifndef DEBUG_SKIP_DECODING // Map ASIT events to decode messages decMsg = asitEventsToDecMsg(asitEvents); // Pass messages (corresponding to events) to decode FSM decErr = decDecodeFsm(pP, pQ, pAsitCfg, pInp->sourceSelect, decMsg); // Mark I/O DATA read complete if decoder indicates decoding is done. if((asitEvents & ASIT_EVTMSK_DECACK)) { // DECACK -> decoding done //ioDataReadComplete(pInp->hIoData); } if(decErr != DEC_NO_ERR) { TRACE_VERBOSE0("TaskAsip: send DEC_EXIT message to slave decoder."); // Send dec exit message to slave decoder if( AspMsgSend(ASP_SLAVE_DEC_EXIT, ASP_MASTER_DEC_EXIT_DONE, NULL, NULL) != ASP_MSG_NO_ERR) { TRACE_VERBOSE0("TaskAsip: error in sending DEC_EXIT message"); SW_BREAKPOINT; } return ASIT_ERR_DECODE_QUIT; // This is not necessarily an error } else { return ASIT_NO_ERR; } #endif } /* asitDecodeProcessing */ /*============================================================================ * ASIT Input Data Processing: * - invoke ioDataProcess() to inspect input data for * - initial auto-detection, or * - background scanning for PCM data, or * - SYNC check for bitstream * - return auto-detection status (SYNC detected, SYNC loss, etc) ============================================================================*/ Int asitInputDataProcess(PAF_AST_IoInp *pInp, ioDataAutoDetStat_t *pAutoDetStats) { Int ioDataErr, retVal; ioDataCtl_t ioDataCtl; // Perform auto-detection inside I/O DATA component ioDataErr = ioDataProcess(pInp->hIoData); if(ioDataErr == IODATA_NO_ERR) { // Normal operation - check auto-detection status ioDataCtl.code = IODATA_CTL_GET_AUTODET_STATUS; ioDataControl(pInp->hIoData, &ioDataCtl); *pAutoDetStats = ioDataCtl.param.autoDetStats; retVal = ASIT_NO_ERR; } else if(ioDataErr == IODATA_ERR_IOBUF_UNDERFLOW) { // Input buffer underflows - there is no enough data to process. // This is not error and no action is needed. pInp->numUnderflow += 1; // debug retVal = ASIT_ERR_INPBUF_UNDERFLOW; } else { // Something is wrong: print error log and return //printf("IODATA processing error!\n"); retVal = ASIT_ERR_INPDATA_PROC; } return retVal; } /* asitInputDataProcess */ /*============================================================================ * Mapping ASIT Events to Decoding Messages ============================================================================*/ UInt asitEventsToDecMsg(UInt asitEvents) { UInt decMsg = 0; if(asitEvents & ASIT_EVTMSK_INPDATA) { decMsg |= DEC_MSGMSK_INPDATA; } if(asitEvents & ASIT_EVTMSK_INFOACK) { decMsg |= DEC_MSGMSK_INFOACK; } if(asitEvents & ASIT_EVTMSK_DECACK) { decMsg |= DEC_MSGMSK_DECACK; } return decMsg; } /* asitEventsToDecMsg */ /*=========================================================================== * Initialize I/O components for input processing ============================================================================*/ int asitIoCompsInit(PAF_AST_InpBuf * pInpBuf, PAF_AST_IoInp * pInpIo) { ioBuffParams_t ioBuffParams; ioPhyParams_t ioPhyParams; ioDataParam_t ioDataCfg; ioPhyCtl_t ioPhyCtl; pInpIo->phyXferSize = INPUT_FRAME_SIZE_DEF; if(pInpIo->firstTimeInit) { TRACE_VERBOSE0("Initialize I/O BUFF and I/O PHY."); ioBuffParams.base = pInpBuf->inpBufConfig.base.pVoid; ioBuffParams.size = pInpBuf->inpBufConfig.allocation / STRIDE_WORST_CASE * STRIDE_WORST_CASE; ioBuffParams.sync = IOBUFF_WRITE_SYNC; ioBuffParams.nominalDelay = INPUT_FRAME_SIZE_DEF; if(ioBuffInit(pInpIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) { return (ASIT_ERR_IOBUFF_INIT); // to remove magic number } ioPhyParams.ioBuffHandle = pInpIo->hIoBuff; ioPhyParams.xferFrameSize = pInpIo->phyXferSize; ioPhyParams.mcaspChanHandle = pInpIo->hMcaspChan; ioPhyParams.ioBuffOp = IOPHY_IOBUFFOP_WRITE; if(ioPhyInit(pInpIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) { return (ASIT_ERR_IOPYH_INIT); // to remove magic number } pInpIo->numPrimeXfers = NUM_PRIME_XFERS; } /* Reinitialize I/O DATA every time when ASIT restarts */ TRACE_VERBOSE0("Initialize I/O DATA."); ioDataCfg.ioBuffHandle = pInpIo->hIoBuff; ioDataCfg.unknownSourceTimeOut = pInpBuf->inpBufConfig.pBufStatus->unknownTimeout; ioDataCfg.frameLengthsIEC = (uint_least16_t *)&iecFrameLength[0]; ioDataCfg.frameLengthPCM = INPUT_FRAME_SIZE_PCM / WORD_SIZE_PCM; ioDataCfg.frameLengthDef = INPUT_FRAME_SIZE_DEF / WORD_SIZE_BITSTREAM; ioDataCfg.ibMode = pInpBuf->inpBufConfig.pBufStatus->mode; ioDataCfg.zeroRunRestart = pInpBuf->inpBufConfig.pBufStatus->zeroRunRestart; ioDataCfg.zeroRunTrigger = pInpBuf->inpBufConfig.pBufStatus->zeroRunTrigger; if(ioDataInit(pInpIo->hIoData, &ioDataCfg) != IODATA_NO_ERR) { return (ASIT_ERR_IODATA_INIT); // to remove magic number } if(pInpIo->firstTimeInit) { /* Initialize I/O BUFF and I/O PHY only when input interface changes. */ TRACE_VERBOSE0("Prime I/O PHY."); // Start I/O physical layer by priming McASP LLD for input asitIoPhyPrime(pInpIo); pInpIo->firstTimeInit = FALSE; } else { // Reconfigure I/O PHY transfer size ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE; ioPhyCtl.params.xferFrameSize = pInpIo->phyXferSize; ioPhyControl(pInpIo->hIoPhy, &ioPhyCtl); // If previous stream before reset was PCM, reconfigure McASP LLD to receive 16-bit packed bits if(!pInpIo->swapData) { Int mcaspErr; mcaspErr = mcaspRecfgWordWidth(pInpIo->hMcaspChan, Mcasp_WordLength_16); if(mcaspErr != Audk2g_EOK) { return ASIT_ERR_MCASP_CFG; } // Start swapping data pInpIo->swapData = TRUE; TRACE_VERBOSE0("Reconfigure McASP word length and start swapping data."); } // Start PHY transfer TRACE_VERBOSE0("Start I/O PHY transfer."); asitPhyTransferStart(pInpIo); } return 0; } /* asitIoCompsInit */ /*====================================================================================== * This function initializes ASIT processing *====================================================================================*/ void asitProcInit(PAF_AST_IoInp *pInp, asipDecProc_t *pDec) { pInp->swapData = TRUE; pInp->pcmSwitchHangOver = INPUT_SWITCH_HANGOVER; pDec->initDone = FALSE; pInp->numFrameReceived = 0; } /*====================================================================================== * I/O physical layer prime operation required by McASP LLD *====================================================================================*/ void asitIoPhyPrime(PAF_AST_IoInp *pInp) { Int32 count; for(count = 0; count < pInp->numPrimeXfers; count++) { ioPhyXferSubmit(pInp->hIoPhy); #ifdef ASIP_DEBUG //pInp->numXferStart++; #endif } } /* asitIoPhyPrime */ /*====================================================================================== * This function marks the I/O PHY transfer as complete *====================================================================================*/ void asitPhyTransferComplete(PAF_AST_IoInp * pInpIo) { // Mark underlining I/O BUFF write complete and swap data if needed ioPhyXferComplete(pInpIo->hIoPhy, pInpIo->swapData); } /* asitPhyTransferComplete */ Int asitRecfgPhyXfer(PAF_AST_IoInp *pInp, size_t xferSize) { ioPhyCtl_t ioPhyCtl; Int mcaspErr; ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE; ioPhyCtl.params.xferFrameSize = xferSize; ioPhyControl(pInp->hIoPhy, &ioPhyCtl); pInp->phyXferSize = ioPhyCtl.params.xferFrameSize; if(!pInp->swapData) { // If it was PCM, reconfigure McASP LLD to receive 16-bit packed bits mcaspErr = mcaspRecfgWordWidth(pInp->hMcaspChan, Mcasp_WordLength_16); if(mcaspErr != Audk2g_EOK) { return ASIT_ERR_MCASP_CFG; } // Start swapping data pInp->swapData = TRUE; } return ASIT_NO_ERR; } /* asitRecfgPhyXfer */ /*====================================================================================== * McASP LLD call back function *====================================================================================*/ void asipMcaspCallback(void* arg, MCASP_Packet *mcasp_packet) { /* post semaphore */ if(mcasp_packet->arg == IOPHY_XFER_FINAL) { //Semaphore_post(asipSemRx); Event_post(asitEvent, ASIT_EVTMSK_INPDATA); } else { ; // intermediate packet due to buffer wrapping around } } /*====================================================================================== * This function checks if McASP Rx for input overruns *====================================================================================*/ int asipCheckMcaspRxOverrun(Ptr mcaspChanHandle) { Mcasp_errCbStatus mcaspErrStat; mcaspControlChan(mcaspChanHandle, Mcasp_IOCTL_CHAN_QUERY_ERROR_STATS, &mcaspErrStat); return (mcaspErrStat.isRcvOvrRunOrTxUndRunErr); } #if 0 /*====================================================================================== * This function restarts McASP LLD channel for input *====================================================================================*/ void asipMcaspRxRestart(PAF_AST_IoInp *pInpIo) { mcaspRxReset(); mcaspRxCreate(); } #endif /*====================================================================================== * This function starts an I/O PHY transfer *====================================================================================*/ void asitPhyTransferStart(PAF_AST_IoInp *pInpIo) { Int ioPhyErr; if(asipCheckMcaspRxOverrun(pInpIo->hMcaspChan)) { #ifdef ASIP_DEBUG pInpIo->numInputOverrun++; #endif //asipMcaspRxRestart(pInpIo); System_abort("\nMcASP for input overruns! %d!\n"); } else { ioPhyErr = ioPhyXferSubmit(pInpIo->hIoPhy); //if(ioPhyXferSubmit(pInpIo->hIoPhy)==IOPHY_ERR_BUFF_OVERFLOW) { if(ioPhyErr!=IOPHY_NOERR){ printf("\n I/O PHY ioPhyXferSubmit fails with error %d!\n", ioPhyErr); // Input buffer overflows! //printf("\nInput buffer overflows!\n"); exit(0); } else { // Input buffer operates normally ; } #ifdef ASIP_DEBUG //pInpIo->numXferStart++; #endif } } Int d10Initialized = 0; //extern Audk2g_STATUS mcaspAudioConfig(void); extern void McaspDevice_init(void); /*====================================================================================== * This function initializes HW interface and selects the right device for input *====================================================================================*/ Int asitSelectDevices(const PAF_ASIT_Patchs *pQ, PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp) { Audk2g_STATUS status; mcaspLLDconfig *lldCfg; Ptr mcaspChanHandle; Int zMD, device; zMD = pAstCfg->masterDec; device = pAstCfg->xInp[zMD].inpBufStatus.sioSelect; // obtain SIO select for input if (device <= 0) { pInp->pRxParams = NULL; return ASIT_NO_ERR; } // Initialize D10 if(!d10Initialized) { void * pD10Params = (void *)pQ->devinp->x[device]; /* Initialize McASP HW details */ McaspDevice_init(); D10_init(pD10Params); d10Initialized = 1; } if(pInp->hMcaspChan == NULL) { /* Create an McASP LLD channel */ lldCfg = (mcaspLLDconfig *)pQ->devinp->x[device]->sio.pConfig; status = mcasplldChanCreate(lldCfg, &mcaspChanHandle); if(status != Audk2g_EOK) { Log_info0("McASP channel creation failed!\n"); return ASIT_ERR_MCASP_CFG; } pInp->hMcaspChan = mcaspChanHandle; pInp->pRxParams = pQ->devinp->x[device]; } return ASIT_NO_ERR; } /* asitSelectDevices */ /*====================================================================================== * This function updates input status *====================================================================================*/ Int asitUpdateInputStatus(const void *pRxParams, PAF_InpBufStatus *pStatus, PAF_InpBufConfig *pInpBuf) { Int asipErrno; PAF_SIO_InputStatus inputStatus; // initialize all values to unknown so that device specific // driver layer need only fill in those entries that it is aware of. // This allows extensibility of the structure without requiring users // to re-code. inputStatus.lock = 0; inputStatus.sampleRateData = PAF_SAMPLERATE_UNKNOWN; inputStatus.sampleRateMeasured = PAF_SAMPLERATE_UNKNOWN; inputStatus.nonaudio = PAF_IEC_AUDIOMODE_UNKNOWN; inputStatus.emphasis = PAF_IEC_PREEMPHASIS_UNKNOWN; //more configuration is needed to abstract out D10 asipErrno = D10_RxControl(pRxParams, (Uns)PAF_SIO_CONTROL_GET_INPUT_STATUS, (Arg) &inputStatus); if (asipErrno) { return asipErrno; } pStatus->sampleRateData = inputStatus.sampleRateData; pStatus->sampleRateMeasured = inputStatus.sampleRateMeasured; pStatus->nonaudio = inputStatus.nonaudio; pStatus->emphasisData = inputStatus.emphasis; // if MSB of override clear then use as reported lock // if = 0x80 then use default [0x81] // if = 0x81 then use measured (from device) // others not defined or implemented if ((pStatus->lockOverride & (XDAS_Int8)0x80) == 0) pStatus->lock = pStatus->lockOverride; else if (pStatus->lockOverride == (XDAS_Int8)0x80) pStatus->lock = inputStatus.lock; else if (pStatus->lockOverride == (XDAS_Int8)0x81) pStatus->lock = inputStatus.lock; // if MSB of override clear then use it as sample rate for system, // if = 0x80 then use default [0x82] // if = 0x81 then use data // if = 0x82 then use measured // others not defined or implemented if ((pStatus->sampleRateOverride & (XDAS_Int8)0x80) == 0) pStatus->sampleRateStatus = pStatus->sampleRateOverride; else if (pStatus->sampleRateOverride == (XDAS_Int8)0x80) pStatus->sampleRateStatus = pStatus->sampleRateMeasured; else if (pStatus->sampleRateOverride == (XDAS_Int8)0x81) pStatus->sampleRateStatus = pStatus->sampleRateData; else if (pStatus->sampleRateOverride == (XDAS_Int8)0x82) pStatus->sampleRateStatus = pStatus->sampleRateMeasured; // Update emphasis status: if ((pStatus->emphasisOverride & (XDAS_Int8)0x80) == 0) { if (pStatus->emphasisData == PAF_IEC_PREEMPHASIS_YES) pStatus->emphasisStatus = PAF_IEC_PREEMPHASIS_YES; else pStatus->emphasisStatus = PAF_IEC_PREEMPHASIS_NO; } else if (pStatus->emphasisOverride == (XDAS_Int8 )(0x80+PAF_IEC_PREEMPHASIS_YES)) pStatus->emphasisStatus = PAF_IEC_PREEMPHASIS_YES; else /* IBEmphasisOverrideNo or other */ pStatus->emphasisStatus = PAF_IEC_PREEMPHASIS_NO; // Update precision control pInpBuf->precision = pStatus->precisionInput = pStatus->precisionOverride < 0 ? pStatus->precisionDefault : pStatus->precisionOverride > 0 ? pStatus->precisionOverride : pStatus->precisionDetect > 0 ? pStatus->precisionDetect : pStatus->precisionDefault; return 0; } /*============================================================================== * This function updates input buffer config based on frame information provided * by I/O DATA. ==============================================================================*/ void asitUpdateInpBufConfig(PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp) { PAF_InpBufConfig *pBufConfig; ioDataCtl_t ioDataCtl; /* Get information for reading input data */ ioDataCtl.code = IODATA_CTL_GET_INPBUFFINFO; ioDataControl(pInp->hIoData, &ioDataCtl); if(ioDataCtl.param.dataReadInfo.frameSize != pInp->phyXferSize) { // Fatal error! TRACE_VERBOSE0("TaskAsip: error in updating I/O"); SW_BREAKPOINT; } pBufConfig = &(pAstCfg->xInp[pAstCfg->masterDec].inpBufConfig); //JXTODO: do we need to gate here? //key = GateMP_enter(gateHandle); pBufConfig->base.pVoid = ioDataCtl.param.dataReadInfo.buffBase; pBufConfig->sizeofBuffer = ioDataCtl.param.dataReadInfo.buffSize; pBufConfig->pntr.pSmInt = ioDataCtl.param.dataReadInfo.startAddress; // Leave the gate //GateMP_leave(gateHandle, key); TRACE_TERSE2("Frame start address: 0x%x., preamble: 0x%x", (UInt)ioDataCtl.param.dataReadInfo.startAddress, *(UInt *)ioDataCtl.param.dataReadInfo.startAddress); } /*============================================================================== * Decide source after SYNC is found, i.e. either bitstream preamble is detected * or it times out to PCM. ==============================================================================*/ Int asitDecideSource(PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp, ioDataAutoDetStat_t *autoDetStatus) { Int sourceConfig, sourceSelect, sourceProgram; Int zMD; char asipMsgBuf[ASP_MSG_BUF_LEN]; // Get the configured source zMD = pAstCfg->masterDec; sourceConfig = (Int)sharedMemReadInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceSelect), GATEMP_INDEX_DEC); if(autoDetStatus->syncState == IODATA_SYNC_PCM) { if (sourceConfig == PAF_SOURCE_DSD1 || sourceConfig == PAF_SOURCE_DSD2 || sourceConfig == PAF_SOURCE_DSD3) { sourceProgram = sourceConfig; } else { sourceProgram = PAF_SOURCE_PCM; } } if(autoDetStatus->syncState == IODATA_SYNC_BITSTREAM) { uint_least16_t pc = autoDetStatus->bitStreamInfo & SYNC_PC_MASK; //0x001F sourceProgram = IECpafSource[pc]; } // write the decided source program to memory sharedMemWriteInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceProgram), sourceProgram, GATEMP_INDEX_DEC); // now that we have some input classification, and possibly an outstanding // input frame, we determine whether or not to call decodeProcessing and with // what decAlg. sourceSelect = PAF_SOURCE_NONE; switch (sourceConfig) { // If autodetecting, decoding everything, and input is something // (i.e. bitstream or PCM) then decode. case PAF_SOURCE_AUTO: if (sourceProgram >= PAF_SOURCE_PCM) { sourceSelect = sourceProgram; // use whatever from autodet } break; // If autodetecting, decoding only PCM, and input is PCM then decode. case PAF_SOURCE_PCMAUTO: if (sourceProgram == PAF_SOURCE_PCM) { // only expect autodet to give PAF_SOURCE_PCM, otherwise set to NONE sourceSelect = sourceProgram; } break; // If autodetecting, decoding only bitstreams, and input is a bitstream then decode. case PAF_SOURCE_BITSTREAM: if (sourceProgram >= PAF_SOURCE_AC3) { sourceSelect = sourceProgram; } break; // If autodetecting, decoding only DTS, and input is DTS then decode. case PAF_SOURCE_DTSALL: switch (sourceProgram) { case PAF_SOURCE_DTS11: case PAF_SOURCE_DTS12: case PAF_SOURCE_DTS13: case PAF_SOURCE_DTS14: case PAF_SOURCE_DTS16: case PAF_SOURCE_DTSHD: sourceSelect = sourceProgram; break; } break; // All others, e.g., force modes, fall through to here. // If user made specific selection then program must match select. // (NB: this compare relies on ordering of PAF_SOURCE) default: sourceSelect = sourceConfig; if ((sourceSelect >= PAF_SOURCE_PCM) && (sourceSelect <= PAF_SOURCE_N)) { if (sourceProgram != sourceSelect) { sourceSelect = PAF_SOURCE_NONE; } } break; } // if we didn't find any matches then skip if (sourceSelect == PAF_SOURCE_NONE) { TRACE_VERBOSE0("TaskAsip: no matching source type, continue"); return ASIT_ERR_NO_MATCHING_SOURCE; } #ifndef DEBUG_SKIP_DECODING // send source select message to slave *(Int32 *)&asipMsgBuf[0] = sourceSelect; if(AspMsgSend(ASP_SLAVE_DEC_SOURCE_SELECT, ASP_MASTER_DEC_SOURCE_SELECT_DONE, asipMsgBuf, NULL) != ASP_MSG_NO_ERR) { TRACE_VERBOSE0("TaskAsip: error in sending SOURCE_SELECT message"); SW_BREAKPOINT; } #endif pInp->sourceSelect = sourceSelect; pInp->sourceProgram = sourceProgram; return ASIT_NO_ERR; } /* asitDecideSource */ /*============================================================================== * After SYNC is found, i.e. either bitstream preamble is detected or it times * out to PCM, update input buffer config and I/o components accordingly. ==============================================================================*/ Int asitUpdateIoComps(const PAF_ASIT_Params *pP, PAF_AST_Config *pAstCfg, PAF_AST_IoInp *pInp, ioDataAutoDetStat_t *autoDetStatus) { Int sourceConfig; Int zMD, deliverZeros; int ioFrameLength, decFrameLength; PAF_InpBufConfig *pBufConfig; ioPhyCtl_t ioPhyCtl; ioDataCtl_t ioDataCtl; zMD = pAstCfg->masterDec; pBufConfig = &pAstCfg->xInp[zMD].inpBufConfig; // Compute decoder frame length based on source selection decFrameLength = getFrameLengthSourceSel(pP, pInp->sourceSelect); pAstCfg->xDec[zMD].decodeControl.frameLength = decFrameLength; pAstCfg->xDec[zMD].decodeInStruct.sampleCount = decFrameLength; pAstCfg->xDec[zMD].decodeControl.sampleRate = PAF_SAMPLERATE_UNKNOWN; // Decide frame length for I/O DATA and I/O PHY if(autoDetStatus->syncState == IODATA_SYNC_PCM) { // For PCM, I/O frame length is decode frame length multiplied by stride ioFrameLength = decFrameLength * INPUT_STRIDE; pBufConfig->sizeofElement = WORD_SIZE_PCM; pBufConfig->frameLength = pBufConfig->lengthofData = ioFrameLength; // Configure I/O DATA PCM frame length ioDataCtl.code = IODATA_CTL_SET_PCM_FRAME_LENGTH; ioDataCtl.param.frameLengthPcm = ioFrameLength; ioDataControl(pInp->hIoData, &ioDataCtl); // Change I/O PHY transfer size to PCM frame size pInp->phyXferSize = ioFrameLength*(WORD_SIZE_PCM); // Adjust I/O BUFF delay and read pointer - to make sure read pointers always point to // PCM data from 1st I2S (out of 4 for HDMI 4xI2S) // Adjust delay and don't mark input buffer as read complete //ioBuffAdjustDelay(pInp->hIoBuff, pInp->phyXferSize); // Stop swapping data //pInp->swapData = FALSE; } else { // For bitstream, I/O frame length is the frame length of the bitstream uint_least16_t pc = autoDetStatus->bitStreamInfo & SYNC_PC_MASK; //0x001F ioFrameLength = iecFrameLength[pc]; /* if( (pc == 0x11) && (DTSHDSubType == 3) && (PAF_ASP_sampleRateHzTable[pBufConfig->pBufStatus->sampleRateStatus][PAF_SAMPLERATEHZ_STD] <=48000.0)) pDevExt->sourceProgram = PAF_SOURCE_DXP; // LBR is 23 if (pc == 1) pDevExt->elementSize = 4288; else if (pc == 0x11) { pDevExt->frameLength = (pDevExt->pIECFrameLength[pc] << DTSHDSubType); pDevExt->lengthofData = pDevExt->frameLength; } */ pBufConfig->sizeofElement = WORD_SIZE_BITSTREAM; pBufConfig->frameLength = ioFrameLength; pBufConfig->lengthofData = ioFrameLength - IEC_HEADER_LENGTH; // Change I/O PHY transfer size to bitstream frame size pInp->phyXferSize = ioFrameLength*WORD_SIZE_BITSTREAM; } pBufConfig->stride = INPUT_STRIDE; // common for PCM and bitstream // Configure I/O PHY transfer size ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE; ioPhyCtl.params.xferFrameSize = pInp->phyXferSize; ioPhyControl(pInp->hIoPhy, &ioPhyCtl); // Decide if zeros should be delivered based on the configured source sourceConfig = (Int)sharedMemReadInt8(&(pAstCfg->xDec[zMD].decodeStatus.sourceSelect), GATEMP_INDEX_DEC); if(autoDetStatus->syncState == IODATA_SYNC_PCM) { // Bitstream preamble is not found and it times out -> assume this is PCM deliverZeros = autoDetStatus->deliverZeros; if (sourceConfig == PAF_SOURCE_PCM || sourceConfig == PAF_SOURCE_DSD1 || sourceConfig == PAF_SOURCE_DSD2 || sourceConfig == PAF_SOURCE_DSD3) { // set to one -- ensures that PCM decode calls made before data is // available will result in zero output. // (mostly needed for PA15 since, currently, all other frameworks // require a frame of data before the first decode call. deliverZeros = TRUE; // override deliverZeros returned by ioDataControl } // update input buffer config structure pBufConfig->deliverZeros = deliverZeros; } //JXTODO: decide what to do with hRxSio //temporary - does ARM use hRxSio or just check if it is not NULL? pAstCfg->xInp[zMD].hRxSio = pInp->hIoData; pAstCfg->xInp[zMD].pInpBuf = &(pAstCfg->xInp[zMD].inpBufConfig); return ASIT_NO_ERR; } /* asitUpdateIoComps */ #ifndef IO_LOOPBACK_TEST #if OUTPUT_FRAME_LENGTH == INPUT_FRAME_LENGTH U8 pcmbuf[OUTPUT_FRAME_SIZE]; #else #error Input frame length is not equal to output frame length! #endif Int rxDecodePcm(PAF_AST_IoInp *pInp) { ioDataCtl_t ioDataCtl; void *buffBase; void *dataStartAddress; size_t buffSize, frameSize, size1, size2; /* Get information for reading input data */ ioDataCtl.code = IODATA_CTL_GET_INPBUFFINFO; ioDataControl(pInp->hIoData, &ioDataCtl); buffBase = ioDataCtl.param.dataReadInfo.buffBase; buffSize = ioDataCtl.param.dataReadInfo.buffSize; dataStartAddress = ioDataCtl.param.dataReadInfo.startAddress; frameSize = ioDataCtl.param.dataReadInfo.frameSize; // Copy PCM data to output buffer if(((size_t)dataStartAddress+frameSize) <= ((size_t)buffBase+buffSize)) { // Input buffer doesn't wrap around Cache_inv(dataStartAddress, frameSize, Cache_Type_ALL, TRUE); memcpy((void *)&pcmbuf[0], dataStartAddress, frameSize); } else { // Input buffer wraps around size1 = (size_t)buffBase + buffSize - (size_t)dataStartAddress; size2 = frameSize - size1; Cache_inv(dataStartAddress, size1, Cache_Type_ALL, TRUE); memcpy((void *)&pcmbuf[0], dataStartAddress, size1); Cache_inv(buffBase, size2, Cache_Type_ALL, TRUE); memcpy((void *)&pcmbuf[size1], buffBase, size2); } return ASIT_NO_ERR; } Int rxDecodePlayZero(PAF_AST_IoInp *pInp) { return ASIT_NO_ERR; } #endif Int asitEvtErrCheck(UInt actualEvents, UInt expectedEvents) { TRACE_VERBOSE2("ASIT events error: actual events are: %d, expected events are: %d.", actualEvents, expectedEvents); return ASIT_ERR_EVENTS; } void asitErrorHandling(PAF_ASIT_Config *pAsitCfg, Int asitErr) { UInt events; if(asitErr == ASIT_ERR_INPBUF_UNDERFLOW) { TRACE_VERBOSE0("ASIT error handling: input buffer underflows. No actions needed."); } if(asitErr == ASIT_ERR_DECODE_QUIT) { TRACE_VERBOSE0("ASIT error handling: DECODE_QUIT - clear INPDATA event."); #if 0 // Pend on INPTDATA event that should have been posted before decoding quits. events = Event_pend(asitEvent, ASIT_EVTMSK_NONE, ASIT_EVTMSK_INPDATA, BIOS_WAIT_FOREVER); // Marks I/O PHY transfer and I/O BUFF write complete asitPhyTransferComplete(&pAsitCfg->pIoInp[0]); // Keep I/O BUFF read pointers going asitBypassIoData(&pAsitCfg->pIoInp[0]); #endif pAsitCfg->pIoInp[0].asipState = ASIT_RESET; pAsitCfg->pIoInp[0].numAsitRestart++; TRACE_VERBOSE0("ASIT error handling finished. Go to state ASIT_RESET."); } if(asitErr == ASIT_ERR_EVENTS) { pAsitCfg->pIoInp[0].asipState = ASIT_RESET; pAsitCfg->pIoInp[0].numAsitRestart++; TRACE_VERBOSE0("ASIT error handling: events error. Go to state ASIT_RESET."); } return; } /* asitErrorHandling */ ////////////////////////////////////////////////////////////////////////////// void asitPostInfoEvent() { Event_post(asitEvent, ASIT_EVTMSK_INFOACK); } void asitPostDecEvent() { Event_post(asitEvent, ASIT_EVTMSK_DECACK); } ////////////////////////////////////////////////////////////////////////////// /* Nothing past this line */