240 lines
6.5 KiB
C
240 lines
6.5 KiB
C
#include "sample_rate_converter.h"
|
|
|
|
|
|
|
|
|
|
#define SRC_RATE 48000U
|
|
#define reg(n) DSP->base + n
|
|
|
|
|
|
/* register/base and control equates for the SRC RAM */
|
|
#define SRC_SYNTH_FIFO 0x00
|
|
#define SRC_DAC_FIFO 0x20
|
|
#define SRC_ADC_FIFO 0x40
|
|
|
|
#define SRC_SYNTH_LVOL 0x7c
|
|
#define SRC_SYNTH_RVOL 0x7d
|
|
#define SRC_DAC_LVOL 0x7e
|
|
#define SRC_DAC_RVOL 0x7f
|
|
#define SRC_ADC_LVOL 0x6c
|
|
#define SRC_ADC_RVOL 0x6d
|
|
|
|
#define SRC_TRUNC_N_OFF 0x00
|
|
#define SRC_INT_REGS_OFF 0x01
|
|
#define SRC_ACCUM_FRAC_OFF 0x02
|
|
#define SRC_VFREQ_FRAC_OFF 0x03
|
|
|
|
/* miscellaneous control defines */
|
|
#define SRC_IOPOLL_COUNT 0x1000UL
|
|
|
|
#define SRC_SYNTHFREEZE (1UL << 21)
|
|
#define SRC_DACFREEZE (1UL << 20)
|
|
#define SRC_ADCFREEZE (1UL << 19)
|
|
|
|
|
|
|
|
|
|
static int src_reg_read(const DEV_STRUCT * DSP, u16_t reg, u16_t
|
|
*data);
|
|
static int src_reg_write(const DEV_STRUCT * DSP, u16_t reg, u16_t val);
|
|
|
|
|
|
int src_init ( DEV_STRUCT * DSP ) {
|
|
u32_t i;
|
|
int retVal;
|
|
|
|
/* Clear all SRC RAM then init - keep SRC disabled until done */
|
|
/* Wait till SRC_RAM_BUSY is 0 */
|
|
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
|
|
return (SRC_ERR_NOT_BUSY_TIMEOUT);
|
|
|
|
pci_outl(reg(SAMPLE_RATE_CONV), SRC_DISABLE);
|
|
|
|
/* from the opensound system driver, no idea where the specification is */
|
|
/* there are indeed 7 bits for the addresses of the SRC */
|
|
for( i = 0; i < 0x80; ++i ) {
|
|
if (SRC_SUCCESS != (retVal = src_reg_write(DSP, (u16_t)i, 0U)))
|
|
return (retVal);
|
|
}
|
|
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_SYNTH_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal = src_reg_write(DSP,
|
|
SRC_SYNTH_BASE + SRC_INT_REGS_OFF, 16 << 10)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_DAC_BASE + SRC_TRUNC_N_OFF, 16 << 4)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_DAC_BASE + SRC_INT_REGS_OFF, 16 << 10)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_SYNTH_LVOL, 1 << 12)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_SYNTH_RVOL, 1 << 12)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_DAC_LVOL, 1 << 12)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_DAC_RVOL, 1 << 12)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_ADC_LVOL, 1 << 12)))
|
|
return (retVal);
|
|
if (SRC_SUCCESS != (retVal =
|
|
src_reg_write(DSP, SRC_ADC_RVOL, 1 << 12)))
|
|
return (retVal);
|
|
|
|
/* default some rates */
|
|
src_set_rate(DSP, SRC_SYNTH_BASE, SRC_RATE);
|
|
src_set_rate(DSP, SRC_DAC_BASE, SRC_RATE);
|
|
src_set_rate(DSP, SRC_ADC_BASE, SRC_RATE);
|
|
|
|
/* now enable the whole deal */
|
|
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
|
|
return (SRC_ERR_NOT_BUSY_TIMEOUT);
|
|
|
|
pci_outl(reg(SAMPLE_RATE_CONV), 0UL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int src_reg_read(const DEV_STRUCT * DSP, u16_t reg, u16_t *data) {
|
|
u32_t dtemp;
|
|
|
|
/* wait for ready */
|
|
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
|
|
return (SRC_ERR_NOT_BUSY_TIMEOUT);
|
|
|
|
dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
|
|
|
|
/* assert a read request */
|
|
/*pci_outl(reg(SAMPLE_RATE_CONV),
|
|
(dtemp & SRC_CTLMASK) | ((u32_t) reg << 25));*/
|
|
pci_outl(reg(SAMPLE_RATE_CONV), (dtemp &
|
|
(DIS_REC|DIS_P2|DIS_P1|SRC_DISABLE)) | ((u32_t) reg << 25));
|
|
|
|
/* now wait for the data */
|
|
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
|
|
return (SRC_ERR_NOT_BUSY_TIMEOUT);
|
|
|
|
if (NULL != data)
|
|
*data = (u16_t) pci_inl(reg(SAMPLE_RATE_CONV));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int src_reg_write(const DEV_STRUCT * DSP, u16_t reg, u16_t val) {
|
|
u32_t dtemp;
|
|
|
|
/* wait for ready */
|
|
if (WaitBitd (reg(SAMPLE_RATE_CONV), SRC_BUSY_BIT, 0, 1000))
|
|
return (SRC_ERR_NOT_BUSY_TIMEOUT);
|
|
|
|
dtemp = pci_inl(reg(SAMPLE_RATE_CONV));
|
|
|
|
/* assert the write request */
|
|
pci_outl(reg(SAMPLE_RATE_CONV),
|
|
(dtemp & SRC_CTLMASK) | SRC_RAM_WE | ((u32_t) reg << 25) | val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void src_set_rate(const DEV_STRUCT * DSP, char base, u16_t rate) {
|
|
u32_t freq, dtemp, i;
|
|
u16_t N, truncM, truncStart, wtemp;
|
|
|
|
|
|
if( base != SRC_ADC_BASE )
|
|
{
|
|
/* freeze the channel */
|
|
dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
|
|
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
|
|
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
|
|
break;
|
|
pci_outl(reg(SAMPLE_RATE_CONV),
|
|
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
|
|
dtemp);
|
|
|
|
/* calculate new frequency and write it - preserve accum */
|
|
/* please don't try to understand. */
|
|
freq = ((u32_t) rate << 16) / 3000U;
|
|
src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
|
|
|
|
src_reg_write(DSP, base + SRC_INT_REGS_OFF,
|
|
(wtemp & 0x00ffU) |
|
|
((u16_t) (freq >> 6) & 0xfc00));
|
|
|
|
src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
|
|
|
|
/* un-freeze the channel */
|
|
dtemp = base == SRC_SYNTH_BASE ? SRC_SYNTHFREEZE : SRC_DACFREEZE;
|
|
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
|
|
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
|
|
break;
|
|
pci_outl(reg(SAMPLE_RATE_CONV),
|
|
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
|
|
~dtemp);
|
|
}
|
|
else /* setting ADC rate */
|
|
{
|
|
/* freeze the channel */
|
|
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
|
|
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
|
|
break;
|
|
pci_outl(reg(SAMPLE_RATE_CONV),
|
|
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) |
|
|
SRC_ADCFREEZE);
|
|
|
|
|
|
|
|
/* derive oversample ratio */
|
|
N = rate/3000U;
|
|
if( N == 15 || N == 13 || N == 11 || N == 9 )
|
|
--N;
|
|
src_reg_write(DSP, SRC_ADC_LVOL, N << 8);
|
|
src_reg_write(DSP, SRC_ADC_RVOL, N << 8);
|
|
|
|
/* truncate the filter and write n/trunc_start */
|
|
truncM = (21*N - 1) | 1;
|
|
if( rate >= 24000U )
|
|
{
|
|
if( truncM > 239 )
|
|
truncM = 239;
|
|
truncStart = (239 - truncM) >> 1;
|
|
src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
|
|
(truncStart << 9) | (N << 4));
|
|
}
|
|
else
|
|
{
|
|
if( truncM > 119 )
|
|
truncM = 119;
|
|
truncStart = (119 - truncM) >> 1;
|
|
src_reg_write(DSP, base + SRC_TRUNC_N_OFF,
|
|
0x8000U | (truncStart << 9) | (N << 4));
|
|
}
|
|
|
|
/* calculate new frequency and write it - preserve accum */
|
|
freq = ((48000UL << 16) / rate) * N;
|
|
src_reg_read(DSP, base + SRC_INT_REGS_OFF, &wtemp);
|
|
src_reg_write(DSP, base + SRC_INT_REGS_OFF,
|
|
(wtemp & 0x00ffU) |
|
|
((u16_t) (freq >> 6) & 0xfc00));
|
|
src_reg_write(DSP, base + SRC_VFREQ_FRAC_OFF, (u16_t) freq >> 1);
|
|
|
|
/* un-freeze the channel */
|
|
for( i = 0; i < SRC_IOPOLL_COUNT; ++i )
|
|
if( !(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_RAM_BUSY) )
|
|
break;
|
|
pci_outl(reg(SAMPLE_RATE_CONV),
|
|
(pci_inl(reg(SAMPLE_RATE_CONV)) & SRC_CTLMASK) &
|
|
~SRC_ADCFREEZE);
|
|
}
|
|
return;
|
|
}
|