📄 hwctxt.cpp
字号:
AUDMUX_EXTERNAL_PORT extPort, BOOL bMaster)
{
PUINT32 pPTCR, pPDCR;
// Get pointers to the Audio MUX internal port registers.
pPTCR = &m_pAUDMUX->PTCR1 + intPort*2;
pPDCR = &m_pAUDMUX->PDCR1 + intPort*2;
// Configure the Audio MUX internal port to connect with the SSI based
// upon who is acting as the bus master.
//
// But regardless of who is the master, we also configure the internal
// port for synchronous 4-wire operation in normal mode (which is what
// we actually need to support the SSI and PMIC for either network or I2S
// modes).
//
// Note that we only configure the transmit framesync and bitclock here
// because we are using synchronous mode and the receiver clock
// settings will be determined by the transmitter settings.
if (bMaster)
{
// All clock signals for the internal port are input signals for
// SSI master mode.
OUTREG32(pPTCR,
CSP_BITFVAL(AUDMUX_PTCR_TFSDIR, AUDMUX_PTCR_TFSDIR_INPUT) |
CSP_BITFVAL(AUDMUX_PTCR_TCLKDIR, AUDMUX_PTCR_TCLKDIR_INPUT) |
CSP_BITFVAL(AUDMUX_PTCR_SYN, AUDMUX_PTCR_SYN_SYNC));
}
else
{
// All clock signals for the internal port are all output signals for
// PMIC master mode. The source of the clock signals is the external
// port that is connected to the PMIC.
OUTREG32(pPTCR,
CSP_BITFVAL(AUDMUX_PTCR_TFSDIR, AUDMUX_PTCR_TFSDIR_OUTPUT) |
CSP_BITFVAL(AUDMUX_PTCR_TFSEL, extPort) |
CSP_BITFVAL(AUDMUX_PTCR_TCLKDIR, AUDMUX_PTCR_TCLKDIR_OUTPUT) |
CSP_BITFVAL(AUDMUX_PTCR_TCSEL, extPort) |
CSP_BITFVAL(AUDMUX_PTCR_SYN, AUDMUX_PTCR_SYN_SYNC));
}
OUTREG32(pPDCR,
CSP_BITFVAL(AUDMUX_PDCR_RXDSEL, extPort) |
CSP_BITFVAL(AUDMUX_PDCR_TXRXEN, AUDMUX_PDCR_TXRXEN_NO_SWAP) |
CSP_BITFVAL(AUDMUX_PDCR_MODE, AUDMUX_PDCR_MODE_NORMAL));
// Get pointers to the Audio MUX external port registers.
pPTCR = &m_pAUDMUX->PTCR1 + extPort * 2;
pPDCR = &m_pAUDMUX->PDCR1 + extPort * 2;
// Configure the Audio MUX external port to connect with the PMIC based
// upon who is acting as the bus master.
//
// But regardless of who is the master, we also configure the external
// port for synchronous 4-wire operation in normal mode (which is what
// we actually need to support the SSI and PMIC in either network or I2S
// mode).
if (bMaster)
{
// All clock signals for the external port are output signals for
// SSI master mode. The source of the clock signals is the internal
// port that is connected to the SSI.
OUTREG32(pPTCR,
CSP_BITFVAL(AUDMUX_PTCR_TFSDIR, AUDMUX_PTCR_TFSDIR_OUTPUT) |
CSP_BITFVAL(AUDMUX_PTCR_TFSEL, intPort) |
CSP_BITFVAL(AUDMUX_PTCR_TCLKDIR, AUDMUX_PTCR_TCLKDIR_OUTPUT) |
CSP_BITFVAL(AUDMUX_PTCR_TCSEL, intPort) |
CSP_BITFVAL(AUDMUX_PTCR_SYN, AUDMUX_PTCR_SYN_SYNC));
}
else
{
// All clock signals for the external port are input signals for
// PMIC master mode.
OUTREG32(pPTCR,
CSP_BITFVAL(AUDMUX_PTCR_TFSDIR, AUDMUX_PTCR_TFSDIR_INPUT) |
CSP_BITFVAL(AUDMUX_PTCR_TCLKDIR, AUDMUX_PTCR_TCLKDIR_INPUT) |
CSP_BITFVAL(AUDMUX_PTCR_SYN, AUDMUX_PTCR_SYN_SYNC));
}
OUTREG32(pPDCR,
CSP_BITFVAL(AUDMUX_PDCR_RXDSEL, intPort) |
CSP_BITFVAL(AUDMUX_PDCR_TXRXEN, AUDMUX_PDCR_TXRXEN_NO_SWAP) |
CSP_BITFVAL(AUDMUX_PDCR_MODE, AUDMUX_PDCR_MODE_NORMAL));
// Must also configure the IOMUX pins for connecting the Audio MUX
// external port to off-chip peripherals such as the PMIC. Without
// this step, we will not be able to connect the Audio MUX to the
// PMIC audio buses.
//
// The key here is to configure the 4-wire interface (framesync, bitclock,
// TX, and RX) through the IOMUX by enabling the functional/normal mode.
// We leave the input/output direction control for all of the I/O pins up
// to the Audio MUX.
//
// Note that we configure both the RX and TX pins here just for the sake
// of completeness and simplicity even though the PMIC Stereo DAC does not
// currently have any recording capabilities and we do not use the Voice
// CODEC for playback.
DDKIomuxSetPinMux((extPort == PORT4) ? DDK_IOMUX_PIN_SFS4 :
DDK_IOMUX_PIN_SFS5,
DDK_IOMUX_OUT_FUNC,
DDK_IOMUX_IN_FUNC);
DDKIomuxSetPinMux((extPort == PORT4) ? DDK_IOMUX_PIN_SCK4 :
DDK_IOMUX_PIN_SCK5,
DDK_IOMUX_OUT_FUNC,
DDK_IOMUX_IN_FUNC);
DDKIomuxSetPinMux((extPort == PORT4) ? DDK_IOMUX_PIN_STXD4 :
DDK_IOMUX_PIN_STXD5,
DDK_IOMUX_OUT_FUNC,
DDK_IOMUX_IN_FUNC);
DDKIomuxSetPinMux((extPort == PORT4) ? DDK_IOMUX_PIN_SRXD4 :
DDK_IOMUX_PIN_SRXD5,
DDK_IOMUX_OUT_FUNC,
DDK_IOMUX_IN_FUNC);
}
//-----------------------------------------------------------------------------
//
// Function: BSPAudioInitSsi
//
// This function initializes the specified audio port for input/output.
//
// Parameters:
// The SSI configuration to be used.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
void HardwareContext::BSPAudioInitSsi(AUDIO_BUS bus, PCSP_SSI_REG pSSI)
{
// These are the only SSI configuration parameters that are different
// between the network and I2S modes. We just default to setting up for
// network mode and then adjust the settings if I2S mode was actually
// selected.
unsigned ssi_i2s_mode = SSI_SCR_I2S_MODE_NORMAL;
unsigned ssi_stcr_tsckp_mode = SSI_STCR_TSCKP_RISING_EDGE;
unsigned ssi_stcr_tfsi_mode = SSI_STCR_TFSI_ACTIVE_HIGH;
unsigned ssi_stccr_dc_mode = 3;
unsigned ssi_scr_net_mode = SSI_SCR_NET_ENABLE;
unsigned ssi_stcr_tfsl_mode = SSI_STCR_TFSL_1BIT;
unsigned ssi_stccr_wl = SSI_STCCR_WL_8BIT;
if (sizeof(HWSAMPLE) == sizeof(INT16))
{
ssi_stccr_wl = SSI_STCCR_WL_16BIT;
}
else if (sizeof(HWSAMPLE) == sizeof(INT32))
{
// The SSI only supports a maximum transfer size of 24 bits/word.
ssi_stccr_wl = SSI_STCCR_WL_24BIT;
}
// Reconfigure the SSI to use the I2S mode instead if that was what was
// selected.
//
// The required SSI configuration changes consist of the following:
//
// * Either I2S master/slave mode.
// * The transmit data clocked at the falling edge.
// * Transmit frame sync is active low.
// * Select 2 words/frame.
//
if (((STEREO_DAC_BUS_MODE == I2S_MODE) && (pSSI == STEREO_DAC_SSI)) ||
((VOICE_CODEC_BUS_MODE == I2S_MODE) && (pSSI == VOICE_CODEC_SSI)))
{
ssi_i2s_mode = (((pSSI == m_pSSI1) && (BSP_SSI1_MASTER_BOOL)) ||
((pSSI == m_pSSI2) && (BSP_SSI2_MASTER_BOOL))) ?
SSI_SCR_I2S_MODE_MASTER : SSI_SCR_I2S_MODE_SLAVE;
ssi_stcr_tsckp_mode = SSI_STCR_TSCKP_FALLING_EDGE;
ssi_stcr_tfsi_mode = SSI_STCR_TFSI_ACTIVE_LOW;
ssi_stccr_dc_mode = 1; // 2 words/frame
ssi_scr_net_mode = SSI_SCR_NET_DISABLE; // disable NETWORK mode
ssi_stcr_tfsl_mode = SSI_STCR_TFSL_1WORD; // 1-word long framesync
}
// Enable SSI clocks before we access the SSI registers.
DDKClockSetGatingMode((pSSI == m_pSSI1) ? DDK_CLOCK_GATE_INDEX_SSI1 :
DDK_CLOCK_GATE_INDEX_SSI2,
DDK_CLOCK_GATE_MODE_ENABLED_ALL);
// Disable the SSI transmitter and receiver.
CLRREG32(&pSSI->SCR, CSP_BITFMASK(SSI_SCR_RE) | CSP_BITFMASK(SSI_SCR_TE));
// Also mask all transmitter and receiver timeslots until we are ready
// to begin a new audio I/O operation.
OUTREG32(&pSSI->STMSK, 0xffffffff);
OUTREG32(&pSSI->SRMSK, 0xffffffff);
// Next disable the SSI so that we can reconfigure the items that
// can only be changed when the SSI is disabled.
//
// We should do this as a separate write from disabling the SSI
// transmitter and receiver in order to give the SSI sufficient
// time to properly complete the previous operation.
CLRREG32(&pSSI->SCR, CSP_BITFMASK(SSI_SCR_SSIEN));
// Disable all SSI interrupts and DMA requests.
OUTREG32(&pSSI->SIER, 0);
// Also disable the transmit and receive FIFOs so that we can configure
// the DMA watermark levels later.
OUTREG32(&pSSI->STCR, 0);
OUTREG32(&pSSI->SRCR, 0);
// We can now begin reconfiguring the SSI for synchronous 4-wire mode.
// Since we are using synchronous mode, we only need to configure the
// SSI transmitter clock in the following stages and there is no need to
// separately set the SSI receiver clock configuration.
//
// The SSI is configured for I2S master/slave mode here or just "normal"
// mode if NETWORK_MODE was selected for the audio bus above. All clock
// configuration settings for the selected master/slave mode will be done
// later.
//
// The SSI SYS_CLK clock output is also disabled here since we do not need
// it (even if the SSI is operated in master mode since the slave device
// just needs to receive the framesync and bitclock signals).
//
// We never use 2-channel mode (where both FIFO0 and FIFO1 are active) so
// that is disabled here as well.
OUTREG32(&pSSI->SCR,
CSP_BITFVAL(SSI_SCR_CLK_IST, SSI_SCR_CLK_IST_HIGH) |
CSP_BITFVAL(SSI_SCR_TCH_EN, SSI_SCR_TCH_EN_2CHAN_OFF) |
CSP_BITFVAL(SSI_SCR_SYS_CLK_EN, SSI_SCR_SYS_CLK_EN_OFF) |
CSP_BITFVAL(SSI_SCR_I2S_MODE, ssi_i2s_mode) |
CSP_BITFVAL(SSI_SCR_SYN, SSI_SCR_SYN_SYNC) |
CSP_BITFVAL(SSI_SCR_NET, ssi_scr_net_mode));
// Next, continue with the configuration of the SSI transmitter for
// audio output/playback.
//
// To match the PMIC's capabilities, the SSI transmitter must transmit
// 16-bit words MSB-first. Only FIFO0 is needed for single channel
// operation but we leave it disabled until we are actually ready to
// start an audio I/O operation.
//
// Also, the SSI transmitter's clock and framesync signals are configured
// here for the slave mode of operation. We will change this later if it
// turns out that the SSI is to be operated in bus master mode.
//
// Note that we must configure the transmitter's clock settings even if we
// never use this SSI for audio playback because we are using synchronous
// mode where the receiver shares the same clock configuration as the
// transmitter.
OUTREG32(&pSSI->STCR,
CSP_BITFVAL(SSI_STCR_TXBIT0, SSI_STCR_TXBIT0_LSB_ALIGNED) |
CSP_BITFVAL(SSI_STCR_TFEN1, SSI_STCR_TFEN1_DISABLE) |
CSP_BITFVAL(SSI_STCR_TFEN0, SSI_STCR_TFEN0_DISABLE) |
CSP_BITFVAL(SSI_STCR_TFDIR, SSI_STCR_TFDIR_EXTERNAL) |
CSP_BITFVAL(SSI_STCR_TXDIR, SSI_STCR_TXDIR_EXTERNAL) |
CSP_BITFVAL(SSI_STCR_TSHFD, SSI_STCR_TSHFD_MSB_FIRST) |
CSP_BITFVAL(SSI_STCR_TSCKP, ssi_stcr_tsckp_mode) |
CSP_BITFVAL(SSI_STCR_TFSI, ssi_stcr_tfsi_mode) |
CSP_BITFVAL(SSI_STCR_TFSL, ssi_stcr_tfsl_mode) |
CSP_BITFVAL(SSI_STCR_TEFS, SSI_STCR_TEFS_EARLY)
);
// Now configure the SSI receiver for audio input/recording.
//
// To match the PMIC's capabilities, the SSI receiver must receive
// 16-bit words MSB-first. Only FIFO0 is needed for single channel
// operation but we leave it disabled until we are actually ready to
// start an audio I/O operation.
//
// Also, we skip configuring the SSI receiver's clock settings here because
// we're using synchronous mode and we've already configured the SSI's
// transmitter clock configuration above. The receiver will simply share
// the same clock configuration as the transmitter.
//
// Note that it is harmless to also configure the SSI receiver even if we
// never use this SSI for audio recording.
OUTREG32(&pSSI->SRCR,
CSP_BITFVAL(SSI_SRCR_RXBIT0, SSI_SRCR_RXBIT0_LSB_ALIGNED) |
CSP_BITFVAL(SSI_SRCR_RFEN1, SSI_SRCR_RFEN1_DISABLE) |
CSP_BITFVAL(SSI_SRCR_RFEN0, SSI_SRCR_RFEN0_DISABLE) |
CSP_BITFVAL(SSI_SRCR_RSHFD, SSI_SRCR_RSHFD_MSB_FIRST)
);
// Set the Receive FIFO empty and Transmit FIFO full watermark levels.
//
// We set the watermark levels for both FIFO0 and FIFO1 here even though
// we will only use FIFO0 because all of the watermark levels must be set
// to a valid value (regardless of whether the FIFO is used or not) in
// order for the SSI to operate properly.
OUTREG32(&pSSI->SFCSR,
CSP_BITFVAL(SSI_SFCSR_RFWM0, SSI_SFCSR_RX_WATERMARK) |
CSP_BITFVAL(SSI_SFCSR_TFWM0, SSI_SFCSR_TX_WATERMARK) |
CSP_BITFVAL(SSI_SFCSR_RFWM1, SSI_SFCSR_RX_WATERMARK) |
CSP_BITFVAL(SSI_SFCSR_TFWM1, SSI_SFCSR_TX_WATERMARK));
if (((pSSI == m_pSSI1) && (BSP_SSI1_MASTER_BOOL)) ||
((pSSI == m_pSSI2) && (BSP_SSI2_MASTER_BOOL)))
{
// First configure the Clock Control Module to route the correct
// system clock signal to the SSI.
if (pSSI == VOICE_CODEC_SSI)
{
// We want a 16 kHz sampling rate from the SSI for the Voice CODEC.
//
// The calculation of the appropriate SSI clock divider constants
// is as follows:
//
// Ideal Sampling Rate = 16 kHz
// Oversampling Rate = 384
// Ideal MCLK Frequency = 16 kHz * 384 = 6.144 MHz
// Serial PLL Frequency = 220.1472 MHz
//
// SSI Divider = 220.1472 / 6.144 = 35.83125
// = 36 (rounded up)
//
// So that means we can set the predivider to divide-by-one (by
// just writing 0) and the postdivider to divide-by-thirty-six
// (which actually means writing a 35 to the postdivider control
// register).
DDKClockConfigBaud((pSSI == m_pSSI1) ? DDK_CLOCK_SIGNAL_SSI1 :
DDK_CLOCK_SIGNAL_SSI2,
(pSSI == m_pSSI1) ? SSI1_MASTER_CLOCK_SOURCE :
SSI2_MASTER_CLOCK_SOURCE,
0, 35);
// The associated SSI internal clock divider constants are:
//
// Ideal Sampling Rate = 16 kHz
// Bits/Word = 16
// Words/Frame = 4
// Ideal Bit Clock Frequency = 16 kHz * 16 * 4 = 1.024 MHz
// SSI Internal Clock Frequency = 6.144 MHz (from above)
// SSI Internal Divider = 6.144 / 1.024 = 6
//
// An internal divider value of 6 can be achieved by setting the
// following:
//
// DIV2 = 0
// PSR = 0
// PM = 2
//
// We also set the following to configure for bits/word and
// words/frame:
//
// DC = 3 (for network mode with 4 words/frame)
// = 1 (for I2S mode with 2 words/frame)
// WL = 3 (for 8 bits/word)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -