📄 hwctxt.cpp
字号:
// AC_SDATA_OUT - GPE4
// AC_SDATA_IN - GPE3
// AC_nRESET - GPE2
// AC_BIT_CLK - GPE1
// AC_SYNC - GPE0
//
// Port Init for AC97
//PG[4:0]=AC_SDATA_OUT:AC_SDATA_IN:AC_nRESET:AC_BIT_CLK:AC_SYNC
v_pIOPregs->rGPECON = ((v_pIOPregs->rGPECON & 0xfffffc00) | 0x3ff);
v_pIOPregs->rGPEUP = (v_pIOPregs->rGPEUP & ~(0x1f)) | 0x1f;
//Delay(10);
//Sleep(5);
}
BOOL HardwareContext::AC97_Init()
{
RETAILMSG(AC97_DEBUG,(_T("WAVDEV_AC97::AC97_Init()++\r\n")));
//----- 1. IMPORTANT: By default, the internal clock is disabled. To configure the controller ------
// we must first enable it.
g_pCLKPWRreg->rCLKCON |= AC97_INTERNAL_CLOCK_ENABLE; // Enable the CPU clock to the AC97 controller
AC97_GPIO_Init();
v_pAC97regs->rAC_GLBCTRL = 0;
Delay(10); //Sleep(5);
// Write into the AC97 Global Control Register
//Cold Reset
v_pAC97regs->rAC_GLBCTRL = 0x1;
Delay(10); //Sleep(5);
v_pAC97regs->rAC_GLBCTRL = 0x0;
Delay(10); //Sleep(5);
//AC-link On
v_pAC97regs->rAC_GLBCTRL = (1<<2);
Delay(10); //Sleep(5);
//Transfer data enable using AC-link
v_pAC97regs->rAC_GLBCTRL = v_pAC97regs->rAC_GLBCTRL | (1<<3);
Delay(10); //Sleep(5);
// Disable the Codec ready Interrupt
v_pAC97regs->rAC_GLBCTRL = v_pAC97regs->rAC_GLBCTRL | (1<<22);
Delay(10); //Sleep(5);
//while (!(v_pAC97regs->rAC_GLBSTAT& 0x400000));
RETAILMSG(AC97_DEBUG,(_T("WAVEDEV_AC97::AC97 Codec Ready!\r\n")));
v_pAC97regs->rAC_GLBCTRL &= ~(0x400000); // codec ready interrupt disable
Delay(10); //Sleep(5);
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3f<<8)) | 0x0000; // PCM_OUT=OFF,PCM_IN=OFF,MIC=OFF;
//v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3f<<8)) | 0x2200; // PCM_OUT=DMA,PCM_IN=OFF,MIC=DMA;
RETAILMSG(AC97_DEBUG,(_T("WAVDEV_AC97::AC97_Init()--\r\n")));
return TRUE;
}
BOOL HardwareContext::Codec_channel()
{
if( m_InputDMARunning & m_OutputDMARunning )
{
RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - In & Out\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_D0); // ADC, DAC power up
}
else if( m_InputDMARunning )
{
RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - In\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR1); // DAC power down
}
else if( m_OutputDMARunning )
{
RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - Out\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR0); // ADC power down
}
else
{
RETAILMSG(AC97_DEBUG,(_T("Codec_channel() - none\r\n")));
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_PR1|AC97_PWR_PR0); // ADC/DAC power down
}
return(TRUE);
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: InitCodec()
Description: Initializes the audio codec chip.
Notes: The audio codec chip is intialized for output mode
but powered down. To conserve battery life, the chip
is only powered up when the user starts playing a
file.
Specifically, the power_up/down logic is done
in the AudioMute() function. If either of the
audio channels are unmuted, then the chip is powered
up; otherwise the chip is powered own.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::InitCodec()
{
USHORT CodecRead;
ULONG CodecVendorID, CodecRevision;
AC97MSG(1, (TEXT("+++InitCodec\r\n")));
// write the Codec software reset
// 00h
WriteCodecRegister(AC97_RESET, 0x683F);
// Enable the VRA
// 2Ah
WriteCodecRegister(AC97_EXT_AUDIO_CONTROL, AC97_ENABLE_VRA);
WriteCodecRegister(AC97_PCM_DAC_RATE, 44100); // Write default Sample rate for DAC
WriteCodecRegister(AC97_PCM_ADC_RATE, 44100); // Write default Sample rate for DAC
// get the Vendor ID and revision
// 7Ch
CodecVendorID = ULONG(ReadCodecRegister( AC97_VENDOR_ID1 )) << 16;
// 7E
CodecRead = ReadCodecRegister( AC97_VENDOR_ID2 );
CodecVendorID |= ULONG(CodecRead) & 0x0000ff00;
CodecRevision = ULONG(CodecRead) & 0x000000ff;
/*
RETAILMSG(AC97_DEBUG, (TEXT("STAC9766 Codec Vendor ID: %08x \r\n"), CodecVendorID));
RETAILMSG(AC97_DEBUG, (TEXT("STAC9766 Codec Revision: %02x\r\n"), CodecRevision));
if ( !( CodecVendorID == AC97_VENDOR_SIGMATEL && CodecRevision == 0x66))
{
// now power down the Analog section of the AC97
// and power it back up. This forces the Sigmatel
// to calibrate it's analog levels
// 26h
WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_ANLOFF );
Delay(10); //Sleep(5);
RETAILMSG(AC97_DEBUG,(_T("WriteCodecRegister(AC97_POWER_CONTROL, AC97_PWR_ANLOFF)\r\n")));
}
*/
// Turn Power on for sections
// 26h
WriteCodecRegister( AC97_POWER_CONTROL, AC97_PWR_D0 );
// Write the Analog reg
// 6Eh
//WriteCodecRegister( AC97_ANALOG_SPEC, 0x0000 );
// write HP Out Value
// 04h
WriteCodecRegister( AC97_HEADPHONE_VOL, 0x0404 ); //0x0202); //0x0404 );
// Mute unusing analog source except -------------------------------
// PCBEEP_VOL - 0ah
WriteCodecRegister( AC97_PCBEEP_VOL, 0x8000 );
// PHONE_VOL - 0ch
WriteCodecRegister( AC97_PHONE_VOL, 0x8000 );
// LINEIN_VOL - 10h
WriteCodecRegister( AC97_LINEIN_VOL, 0x8000 );
// CD_VOL - 12h
WriteCodecRegister( AC97_CD_VOL, 0x8000 );
// VIDEO_VOL - 14h
WriteCodecRegister( AC97_VIDEO_VOL, 0x8000 );
// AUX_VOL - 16h
WriteCodecRegister( AC97_AUX_VOL, 0x8000 );
// write the wave out volume
// 18h
WriteCodecRegister( AC97_PCMOUT_VOL, 0x0505 ); //0x0000 ); //0x0606 );
// Init MIC-IN configurations
// 20h
WriteCodecRegister( AC97_GENERAL_PURPOSE, 0x0000 ); //MIC1 Selected
// ADC Gain Control, 30dB
//BOOSTEN =1
// tmp = ReadCodecRegister(AC97_MIC_VOL) & ~(0x1<<6);
// WriteCodecRegister(AC97_MIC_VOL, tmp | (0x1<<6));
WriteCodecRegister( AC97_MIC_VOL, (1<<15)|(1<<6) ); // Mute & BOOTEN
//ADC Input Slot => left slot6, right slot9, MIC GAIN VAL=1
WriteCodecRegister( AC97_INTR_PAGE, 0x0 );
WriteCodecRegister( AC97_ANALOG_SPEC, 0x0024 );
//Left, Right => MIC
WriteCodecRegister( AC97_RECORD_SELECT, AC97_RECMUX_MIC );
// set up a default record gain
// 1Ch
WriteCodecRegister( AC97_RECORD_GAIN, AC97_RECORD_GAIN_VAL );
// Now write High Pass Filter Bypass Control Register
// 78h
WriteCodecRegister( AC97_HPF_BYPASS, AC97_HIPASS_DISABLE );
AC97MSG(1, (TEXT("---InitCodec\r\n")));
return(TRUE);
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: InitOutputDMA()
Description: Initializes the DMA channel for output.
Notes: DMA Channel 2 is used for transmitting output sound
data from system memory to the I2S controller.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::InitOutputDMA()
{
//----- 1. Initialize the DMA channel for output mode and use the first output DMA buffer -----
v_pDMAregs->rDISRC1 = (int)(PLAY_DMA_BUFFER_PHYS);
v_pDMAregs->rDISRCC1 &= ~(SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is system bus, increment addr
//----- 2. Initialize the DMA channel to send data over the I2S bus -----
v_pDMAregs->rDIDST1 = (int)AC_PCMDATA_PHYS;
//v_pDMAregs->rDIDSTC1 |= (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Dest is periperal bus, fixed addr
v_pDMAregs->rDIDSTC1 = (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Dest is periperal bus, fixed addr
//----- 3. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, -----
// single tx, single service, I2SSDO, I2S request, no auto-reload, half-word, tx count
v_pDMAregs->rDCON1 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | AC97PCMOUT_DMA1 | DMA_TRIGGERED_BY_HARDWARE
#if DMA_FLAG
// | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2 ) );
| TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4 ) );
#else
// | NO_DMA_AUTO_RELOAD | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );
| NO_DMA_AUTO_RELOAD | TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4 ) );
#endif
//----- 4. Reset the playback pointers -----
AUDIO_RESET_PLAYBACK_POINTER();
AC97MSG(1,(TEXT("---InitOutputDMA\n")));
return TRUE;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StartOutputDMA()
Description: Starts outputting the sound data to the audio codec
chip via DMA.
Notes: Currently, both playback and record share the same
DMA channel. Consequently, we can only start this
operation if the input channel isn't using DMA.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::StartOutputDMA()
{
ULONG OutputTransferred;
AC97MSG(1,(TEXT("+++StartOutputDMA\n")));
if(!m_OutputDMARunning && (m_Dx == D0) )
// if(!m_OutputDMARunning)
{
//----- 1. Initialize our buffer counters -----
m_OutputDMARunning=TRUE;
m_OutBytes[OUT_BUFFER_A]=m_OutBytes[OUT_BUFFER_B]=0;
//----- 2. Prime the output buffer with sound data -----
//m_OutputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
//RETAILMSG(1,(_T("dmastat = %x\r\n"), m_OutputDMAStatus));
m_OutputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
OutputTransferred = TransferOutputBuffers(m_OutputDMAStatus);
//----- 3. If we did transfer any data to the DMA buffers, go ahead and enable DMA -----
if(OutputTransferred)
{
//----- 4. Configure the DMA channel for playback -----
if(!InitOutputDMA())
{
DEBUGMSG(ZONE_ERROR, (TEXT("HardwareContext::StartOutputDMA() - Unable to initialize output DMA channel!\r\n")));
goto START_ERROR;
}
#if DMA_FLAG
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x2<<12); // 0x2 = DMA
#else
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x1<<12); // 0x1 = PIO
#endif
//----- 5. Make sure the audio isn't muted -----
AudioMute(DMA_CH_OUT, FALSE);
//----- 6. Start the DMA controller -----
AUDIO_RESET_PLAYBACK_POINTER();
SELECT_AUDIO_DMA_OUTPUT_BUFFER_A();
Codec_channel(); // Turn ON output channel
// charlie, start A buffer
AUDIO_OUT_DMA_ENABLE();
#if DMA_FLAG
// wait for DMA to start.
delay_count = 0;
while((v_pDMAregs->rDSTAT1&0xfffff)==0){
RETAILMSG(1,(_T("1")));
#if WAIT_DMA_END
Sleep(1);
#else
if( delay_count++ > DELAY_COUNT ) break;
#endif
}
// change the buffer pointer
SELECT_AUDIO_DMA_OUTPUT_BUFFER_B();
// Set DMA for B Buffer
#endif
}
else // We didn't transfer any data, so DMA wasn't enabled
{
m_OutputDMARunning=FALSE;
}
}
AC97MSG(1,(TEXT("---StartOutputDMA\n")));
return TRUE;
START_ERROR:
return FALSE;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StopOutputDMA()
Description: Stops any DMA activity on the output channel.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
void HardwareContext::StopOutputDMA()
{
AC97MSG(1,(_T("StopOutputDMA()++\r\n")));
// jylee,040220
// you should do this sleep operation for AC-Link operation.
Sleep(1);
//----- 1. If the output DMA is running, stop it -----
if (m_OutputDMARunning)
{
m_OutputDMAStatus = DMA_CLEAR;
AUDIO_OUT_DMA_DISABLE();
AUDIO_OUT_CLEAR_INTERRUPTS();
v_pAC97regs->rAC_GLBCTRL = (v_pAC97regs->rAC_GLBCTRL & ~(0x3<<12)) | (0x0<<12); // 0x0 = OFF
AudioMute(DMA_CH_OUT, TRUE);
}
m_OutputDMARunning = FALSE;
Codec_channel();
/*
// jylee, 040220
// Clear AC97 PCMDATA FIFO.
for (int i=0; i<AC97_PCMDATA_FIFO_LENGTH;i++)
{
v_pAC97regs->rAC_PCMDATA = 0x00000000;
}
*/
AC97MSG(1,(_T("StopOutputDMA()--\r\n")));
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: InitInputDMA()
Description: Initializes the DMA channel for input.
Notes: ***** NOT IMPLEMENTED *****
The following routine is not implemented due to a
hardware bug in the revision of the Samsung SC2440
CPU this driver was developed on. See the header
at the top of this file for details.
Returns: Boolean indicating success
-------------------------------------------------------------------*/
BOOL HardwareContext::InitInputDMA()
{
//goto INIT_ERROR;
AC97MSG(1,(TEXT("+++InitInputDMA\n")));
//============================ Configure DMA Channel 1 ===========================
//------ On platforms with the revsion of the Samsung SC2440 CPU with the IIS SLAVE bug fix, this -----
// code can be used to configure DMA channel 1 for input.
//----- 1. Initialize the DMA channel for input mode and use the first input DMA buffer -----
v_pDMAregs->rDISRC2 = (int)AC_MICDATA_PHYS;
v_pDMAregs->rDISRCC2 = (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr
//----- 2. Initialize the DMA channel to receive data over the I2S bus -----
v_pDMAregs->rDIDST2 = (int)(RECORD_DMA_BUFFER_PHYS); //(AUDIO_DMA_BUFFER_PHYS);
v_pDMAregs->rDIDSTC2 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr
//----- 3. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, -----
// single tx, single service, I2SSDI, I2S request, no auto-reload, half-word, tx count
v_pDMAregs->rDCON2 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | AC97MICIN_DMA2 | DMA_TRIGGERED_BY_HARDWARE
#if DMA_FLAG
#if (INCHANNELS==2)
| TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4) );
#else
| TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );
#endif
#else /* DMA_FLAG */
| NO_DMA_AUTO_RELOAD | TRANSFER_WORD | (AUDIO_DMA_PAGE_SIZE / 4) );
//| NO_DMA_AUTO_RELOAD | TRANSFER_HALF_WORD | (AUDIO_DMA_PAGE_SIZE / 2) );
#endif /* DMA_FLAG */
return TRUE;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StartInputDMA()
Description: Starts inputting the recorded sound data from the
audio codec chip via DMA.
Notes: ***** NOT IMPLEMENTED *****
The following routine is not implemented due to a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -