📄 xsac97ctrl.c
字号:
* 4. Perform the first (dummy) read from the processor memory location that is
* mapped to the target Codec's target register. Discard the resulting data
* 5. Continuously check the AC '97 Controller's Global Status Register until
* the SDONE bit is set. Use software timeout logic.
* 6. If the Read Completion Status bit is set or the software timeout has
* occurred, there is a timeout.
* a) Declare an error status
* b) Skip to step 8 in this procedure.
* 7. If there was no timeout, the read operation was successful.
* a) Read the CAR until it is verified that no codec I/O accesses are
* currently in progress. This also claims the next codec I/O
* transaction for this operation. It leaves an indication for the
* next SW read or write I/O operation. This will prevent ambiguity.
* (We shouldn't actually have to loop here because the SDONE bit
* indicator ought to be set at the same time as the CAR indicator
* clears. But we loop anyway, just in case.)
* b) Perform the second read to obtain the register contents reported by
* the codec.
* c) Report the data obtained from the codec.
* 8. Restore previous interrupt state.
* 9. Report success or error status.
*
* Note that this operation does not wait for the second read operation to
* complete. Any remaining wait is done in the beginning of the next access.
*
* Note also that there is a possible optimization in this processor for reads
* of a modem's GPIO bits that are reported to the controller in time slot 12.
* It would be to skip the timeout logic and the second read cycle because the
* local values are constantly updated from the values reported in TS 12.
*
* Once the link is acquired, perform the double read under interrupt
* protection. This is necessary to make it an atomic operation. Even
* if link acquisition continued for @@@
*
*******************************************************************************
*/
UINT32 XsAc97CtrlReadCodecReg (XsAc97CtrlCodecModemIdT ac97DeviceId,
AC97MixerRegisterIdT targetRegister,
UINT32* mixerRegValueP)
{
UINT32 status ;
INT badParamNum = 0; // Which param had error. Assume no errors.
INT timeoutLoc = 0; // What point had a timeout. Assume no errors.
BOOL gotLink;
VUINT32 readFinishedStatus;
UINT32 irqIntState;
UINT32 rcsErrTmp;
INT minorIterations;
INT retries = 0;
XsAc97CtrlStatsT* codeStatsP;
VUINT32* mixerRegsAccessP;
status = Ac97CheckRegId (targetRegister);
if (status)
{
badParamNum = 2;
}
else // register ID OK, set register access pointer to codec access base
{
switch (ac97DeviceId)
{
case XS_AC97CTRL_CM_ID_PRI_CODEC:
mixerRegsAccessP = &XsAc97CtrlRegsP->
XsAC97CtrlMixerRegsPrimaryAud[0];
codeStatsP = &XsAc97CtrlContext.statistics[ac97DeviceId];
break;
default:
status = ERR_T_ILLPARAM;
badParamNum = 1;
break;
}
// Point to specified register within area mapped to target codec regs
mixerRegsAccessP += (targetRegister / XS_AC97CTRL_MIXER_REGS_PER_WORD);
} // else (register ID OK)
if (!status)
{
// Some statistics. Only valid invocations are interesting.
irqIntState = XsIcDisableInterruptsIrq();
codeStatsP->readCodecNumInvocations++;
XsIcRestoreInterruptsIrq (irqIntState);
do
{
status = ERR_NONE; // Clear for possible retry
// Protect entire operation for simplicity. Very small extra
// execution time penalty.
irqIntState = XsIcDisableInterruptsIrq();
// Lock the ACLINK
minorIterations = 0;
do
{
gotLink = XsAc97CtrlLockAcLink();
if (!gotLink) // 1 usec is a long time. Skip delay if possible.
{
DM_WaitUs(1);
}
}
// Wait while time remaining and ACLINK not available
while ( (minorIterations++ < XS_AC97CTRL_CAIP_TIMEOUT_1USECS)
&& !gotLink );
if (!gotLink) // Didn't get the ACLINK
{
status = ERR_T_NOT_AVAIL;
}
else // We got the link. Perform the read operations.
{
// First, clear old read status indications.
(void) XsAc97CtrlClearStatus (XS_AC97CTRL_STAT_SDONE);
(void) XsAc97CtrlClearStatus (XS_AC97CTRL_STAT_RCS_ERR);
*mixerRegValueP = *mixerRegsAccessP; // This is THE DUMMY READ.
// Wait for read I/O with codec to complete before doing real read.
minorIterations = 0;
do
{
DM_WaitUs(1);
readFinishedStatus =
XsAc97CtrlGetStatus (XS_AC97CTRL_STAT_SDONE);
}
// Wait while time remaining and read I/O still incomplete
// SDONE bit is high when done.
while ( (minorIterations++ < XS_AC97CTRL_READ_TIMEOUT_1USECS)
&& !readFinishedStatus);
// Another way to detect a timeout is to check the Read
// Completion Status bit in the GSR. It is set for a timeout.
rcsErrTmp = XsAc97CtrlGetStatus (XS_AC97CTRL_STAT_RCS_ERR);
if ( rcsErrTmp ||
!readFinishedStatus)
{
// Timed out on read
status = ERR_T_TIMEOUT;
timeoutLoc = 1; // First timeout opportunity
}
else // OK to do real read
{
if (!gotLink) // Didn't get the ACLINK
{
status = ERR_T_TIMEOUT;
timeoutLoc = 2; // Second timeout opportunity
}
else // No problems. Perform the read operation.
{
*mixerRegValueP = *mixerRegsAccessP; // THE REAL READ.
}
} // else (OK to do real read)
} // else (We got the link. Perform the read operations.)
XsIcRestoreInterruptsIrq (irqIntState); // End atomic zone.
} // do: try communication until retries run out or success.
while (retries++ < XS_AC97CTRL_CODEC_READ_RETRIES && (status));
// Some statistics
irqIntState = XsIcDisableInterruptsIrq();
codeStatsP->readCodecTotalRetries += retries -1; // Adjust for post-increment
if (status)
{
codeStatsP->readCodecNumFailures++;
}
else
{
// Clean up after real read. Why must we do it here instead
// of speculatively at the beginning of the read process?
// Need to investigate proper procedure.
minorIterations = 0;
do
{
DM_WaitUs(1);
readFinishedStatus =
XsAc97CtrlGetStatus (XS_AC97CTRL_STAT_SDONE);
}
// Wait while time remaining and read I/O still incomplete
// SDONE bit is high when done.
while ( (minorIterations++ < XS_AC97CTRL_READ_TIMEOUT_1USECS)
&& !readFinishedStatus);
}
XsIcRestoreInterruptsIrq (irqIntState);
} // if (!status): got past initial parameter checks
if (status)
{
// LOGERROR (XsAc97CtrlContext.loggedError,
// ERR_L_XSAC97CTRL,
// ERR_S_XSAC97CTRL_CODEC_READ,
// status,
// badParamNum,
// timeoutLoc,
//targetRegister)
}
return (status);
} // XsAc97CtrlCodecRead ()
/*
*******************************************************************************
Non-standard, test-oriented API of main processor on-board
AC'97 controller driver. Lower level access provided.
*******************************************************************************
*/
/*
*******************************************************************************
*
* FUNCTION: XsAc97CtrlColdReset
*
* DESCRIPTION: Perform a cold reset of the processor's AC'97 Controller,
* the AC Link and all AC'97 codecs and modems attached to
* the controller's AC'97 cold reset pin.
*
* INPUT PARAMETERS: None
*
* RETURNS:
* Success: 0 (ERR_NONE); All codecs reported ready within time limit.
* Failure: ERR_T_TIMEOUT: A timeout occurred on one of the codecs.
* In systems with multiple codecs, the calling function
* could determine which device(s) is/are not ready by
* performing XsAc97CtrlGetStatus() on
* XS_AC97CTRL_STAT_PCRDY and XS_AC97CTRL_STAT_SCRDY.
*
* GLOBAL EFFECTS: All codecs initialized to default settings. Controller
* set to default state and is operational.
*
* ASSUMPTIONS: Not used in an interrupt service routine.
*
* CALLS:
*
* CALLED BY:
*
* PROTOTYPE: UINT32 XsAc97CtrlColdReset (void);
*
*******************************************************************************
*/
UINT32 XsAc97CtrlColdReset (void)
{
UINT32 status = ERR_NONE;
INT numCodecsReady;
BOOL primaryCodecReady;
INT timeRemaining;
UINT32 irqIntState;
// Activate cold reset line under interrupt protection
irqIntState = XsIcDisableInterruptsIrq(); // Begin atomic zone.
XsAc97CtrlRegsP = (XsAc97CtrlRegsT *) XS_AC97CTRL_REGISTER_BASE;
XsAc97CtrlRegsP->GCR &= ~(XS_AC97CTRL_GCR_COLD_RESET_MSK); // Activate
XsIcRestoreInterruptsIrq (irqIntState); // End atomic zone.
// Hold reset active for a minimum time
for (timeRemaining = 0 ;
timeRemaining < XS_AC97CTRL_COLD_HOLD_50USECS;
timeRemaining++ )
{
DM_WaitUs(50);
}
// Deactivate cold reset line
irqIntState = XsIcDisableInterruptsIrq(); // Begin atomic zone.
XsAc97CtrlRegsP->GCR |= XS_AC97CTRL_GCR_COLD_RESET_MSK; // Deactivate
XsIcRestoreInterruptsIrq (irqIntState); // End atomic zone.
// And wait with timeout for all codecs to respond.
numCodecsReady = 0; // Codecs plus modems.
primaryCodecReady = FALSE;
timeRemaining = XS_AC97CTRL_COLD_TIMEOUT_50USECS;
do
{
DM_WaitUs(50);
if ((!primaryCodecReady) && (XsAc97CtrlRegsP->GSR & XS_AC97CTRL_GSR_PCRDY_MSK))
{
// Note: Don't bother trying to clear the interrupt trigger for the
// primary codec ready status indicator. This is not an
// interrupt-based function.
primaryCodecReady = TRUE;
numCodecsReady ++;
}
// Note: Other codecs or modems would be checked here, if supported by
// the platform.
} // exit loop if timeout or all devices ready
while (timeRemaining-- && (numCodecsReady < XS_AC97CTRL_NUM_CODECS));
// Timeout status if some of the devices weren't ready.
if (numCodecsReady < XS_AC97CTRL_NUM_CODECS)
{
status = ERR_T_TIMEOUT;
// LOGERROR (XsAc97CtrlContext.loggedError, ERR_L_XSAC97CTRL,
// ERR_S_XSAC97CTRL_COLD_RESET, status, 0, 0, 0);
}
return (status);
} // XsAc97CtrlColdReset ()
/*
*******************************************************************************
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -