source: svn/trunk/newcon3bcm2_21bu/magnum/portinginterface/ape/7552/bape_nco.c

Last change on this file was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 17.1 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2006-2012, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: bape_nco.c $
11 * $brcm_Revision: Hydra_Software_Devel/5 $
12 * $brcm_Date: 1/27/12 4:50p $
13 *
14 * Module Description: Audio Decoder Interface
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /magnum/portinginterface/ape/7422/bape_nco.c $
19 *
20 * Hydra_Software_Devel/5   1/27/12 4:50p jgarrett
21 * SW7429-55: Updating MCLK of all connected outputs when a new mixer is
22 * attached
23 *
24 * Hydra_Software_Devel/4   11/14/11 3:16p gskerl
25 * SW7429-18: Merging 7429 changes back to main branch.
26 *
27 * Hydra_Software_Devel/SW7429-18/2   10/26/11 12:44p jgarrett
28 * SW7429-18: Merging latest changes from main branch
29 *
30 * Hydra_Software_Devel/SW7429-18/1   10/25/11 10:15a jgarrett
31 * SW7429-18: Adding NCO support for 7429
32 *
33 * Hydra_Software_Devel/3   10/25/11 1:30p gskerl
34 * SW7231-129: Added support for recovering hardware state after power
35 * standby/resume.
36 *
37 * Hydra_Software_Devel/2   7/11/11 2:29p jgarrett
38 * SW7552-72: Removing 35230 compiler warning
39 *
40 * Hydra_Software_Devel/1   7/8/11 4:29p gskerl
41 * SW7552-72: Added support for NCO/Mclkgen audio clock sources
42 *
43 *
44 ***************************************************************************/
45
46#include "bstd.h"
47#include "bkni.h"
48#include "bape.h"
49#include "bape_priv.h"
50
51#if BCHP_CLKGEN_REG_START
52#include "bchp_clkgen.h"
53#endif
54
55BDBG_MODULE(bape_nco);
56
57#if BAPE_CHIP_MAX_NCOS > 0     /* If no NCOs on this chip, then skip all of this.  None of these functions are ever called. */
58
59#ifdef BCHP_AUD_FMM_IOP_NCO_0_REG_START
60#include "bchp_aud_fmm_iop_nco_0.h"
61#ifdef BCHP_AUD_FMM_IOP_NCO_1_REG_START
62#include "bchp_aud_fmm_iop_nco_1.h"
63#define BAPE_NCO_STRIDE (BCHP_AUD_FMM_IOP_NCO_1_REG_START - BCHP_AUD_FMM_IOP_NCO_0_REG_START)
64#else
65#define BAPE_NCO_STRIDE 0
66#endif
67#endif
68
69#ifdef BCHP_AUD_FMM_OP_MCLKGEN_REG_START
70#include "bchp_aud_fmm_op_mclkgen.h"
71#if BAPE_CHIP_MAX_NCOS > 1
72#define BAPE_NCO_STRIDE (BCHP_AUD_FMM_OP_MCLKGEN_MCLK_GEN_1_SAMPLE_INC - BCHP_AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_SAMPLE_INC)
73#else
74#define BAPE_NCO_STRIDE 0
75#endif
76#endif
77
78#if defined BCHP_AUD_FMM_OP_MCLKGEN_REG_START
79static void BAPE_Nco_UpdateDividers_isr(BAPE_Handle handle, BAPE_Nco nco, uint32_t sampleInc, uint32_t  numerator, uint32_t denominator, uint32_t phaseInc, BAVC_Timebase outputTimebase)
80{
81    uint32_t regAddr, regVal;
82   
83    regAddr = BCHP_AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_CONTROL + (BAPE_NCO_STRIDE * nco);
84    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
85    regVal &= ~BCHP_MASK(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_CONTROL, TIMEBASE);
86    switch ( outputTimebase )
87    {
88    case BAVC_Timebase_e0:
89        regVal |= BCHP_FIELD_ENUM(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_0);
90        break;
91    case BAVC_Timebase_e1:
92        regVal |= BCHP_FIELD_ENUM(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_1);
93        break;
94    case BAVC_Timebase_e2:
95        regVal |= BCHP_FIELD_ENUM(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_2);
96        break;
97    case BAVC_Timebase_e3:
98        regVal |= BCHP_FIELD_ENUM(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_3);
99        break;
100    }
101    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
102
103    regAddr = BCHP_AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_RATE_RATIO + (BAPE_NCO_STRIDE * nco);
104    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
105    regVal &= ~BCHP_MASK(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_RATE_RATIO, DENOMINATOR);
106    regVal |= BCHP_FIELD_DATA(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_RATE_RATIO, DENOMINATOR, denominator);
107    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
108
109    regAddr = BCHP_AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_SAMPLE_INC + (BAPE_NCO_STRIDE * nco);
110    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
111    regVal &= ~(BCHP_MASK(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_SAMPLE_INC, SAMPLE_INC) | BCHP_MASK(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_SAMPLE_INC, NUMERATOR));
112    regVal |= BCHP_FIELD_DATA(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_SAMPLE_INC, NUMERATOR, numerator);
113    regVal |= BCHP_FIELD_DATA(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_SAMPLE_INC, SAMPLE_INC, sampleInc);
114    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
115
116    regAddr = BCHP_AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_PHASE_INC + (BAPE_NCO_STRIDE * nco);
117    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
118    regVal &= ~BCHP_MASK(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_PHASE_INC, PHASE_INC);
119    regVal |= BCHP_FIELD_DATA(AUD_FMM_OP_MCLKGEN_MCLK_GEN_0_PHASE_INC, PHASE_INC, phaseInc);
120    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
121}
122#elif defined BCHP_AUD_FMM_IOP_NCO_0_REG_START
123static void BAPE_Nco_UpdateDividers_isr(BAPE_Handle handle, BAPE_Nco nco, uint32_t sampleInc, uint32_t  numerator, uint32_t denominator, uint32_t phaseInc, BAVC_Timebase outputTimebase)
124{
125    uint32_t regAddr, regVal;
126   
127    regAddr = BCHP_AUD_FMM_IOP_NCO_0_MCLK_GEN_0_CONTROL + (BAPE_NCO_STRIDE * nco);
128    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
129    regVal &= ~BCHP_MASK(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_CONTROL, TIMEBASE);
130    switch ( outputTimebase )
131    {
132    case BAVC_Timebase_e0:
133        regVal |= BCHP_FIELD_ENUM(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_0);
134        break;
135    case BAVC_Timebase_e1:
136        regVal |= BCHP_FIELD_ENUM(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_1);
137        break;
138    case BAVC_Timebase_e2:
139        regVal |= BCHP_FIELD_ENUM(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_2);
140        break;
141    case BAVC_Timebase_e3:
142        regVal |= BCHP_FIELD_ENUM(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_CONTROL, TIMEBASE, TIMEBASE_3);
143        break;
144    }
145    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
146
147    regAddr = BCHP_AUD_FMM_IOP_NCO_0_MCLK_GEN_0_RATE_RATIO + (BAPE_NCO_STRIDE * nco);
148    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
149    regVal &= ~BCHP_MASK(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_RATE_RATIO, DENOMINATOR);
150    regVal |= BCHP_FIELD_DATA(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_RATE_RATIO, DENOMINATOR, denominator);
151    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
152
153    regAddr = BCHP_AUD_FMM_IOP_NCO_0_MCLK_GEN_0_SAMPLE_INC + (BAPE_NCO_STRIDE * nco);
154    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
155    regVal &= ~(BCHP_MASK(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_SAMPLE_INC, SAMPLE_INC) | BCHP_MASK(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_SAMPLE_INC, NUMERATOR));
156    regVal |= BCHP_FIELD_DATA(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_SAMPLE_INC, NUMERATOR, numerator);
157    regVal |= BCHP_FIELD_DATA(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_SAMPLE_INC, SAMPLE_INC, sampleInc);
158    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
159
160    regAddr = BCHP_AUD_FMM_IOP_NCO_0_MCLK_GEN_0_PHASE_INC + (BAPE_NCO_STRIDE * nco);
161    regVal = BREG_Read32_isr(handle->regHandle, regAddr);
162    regVal &= ~BCHP_MASK(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_PHASE_INC, PHASE_INC);
163    regVal |= BCHP_FIELD_DATA(AUD_FMM_IOP_NCO_0_MCLK_GEN_0_PHASE_INC, PHASE_INC, phaseInc);
164    BREG_Write32_isr(handle->regHandle, regAddr, regVal);
165}
166#else
167#error Unknown NCO register layout
168#endif
169
170
171
172void BAPE_P_AttachMixerToNco(BAPE_MixerHandle mixer, BAPE_Nco nco)
173{
174    unsigned ncoIndex = nco - BAPE_Nco_e0;
175
176    BDBG_OBJECT_ASSERT(mixer, BAPE_Mixer);
177    BDBG_ASSERT(ncoIndex < BAPE_CHIP_MAX_NCOS);
178    BDBG_MSG(("Attaching mixer %p to NCO:%u", mixer, ncoIndex ));
179    BLST_S_INSERT_HEAD(&mixer->deviceHandle->audioNcos[ncoIndex].mixerList, mixer, ncoNode);
180    /* Update MCLK source for attached outputs */
181    BKNI_EnterCriticalSection();
182    BAPE_P_UpdateNco_isr(mixer->deviceHandle, nco);
183    BKNI_LeaveCriticalSection();
184}
185
186void BAPE_P_DetachMixerFromNco(BAPE_MixerHandle mixer, BAPE_Nco nco)
187{
188    unsigned ncoIndex = nco - BAPE_Nco_e0;
189
190    BDBG_OBJECT_ASSERT(mixer, BAPE_Mixer);
191    BDBG_ASSERT(ncoIndex < BAPE_CHIP_MAX_NCOS);
192    BDBG_MSG(("Detaching mixer %p from NCO:%u", mixer, ncoIndex ));
193    BLST_S_REMOVE(&mixer->deviceHandle->audioNcos[ncoIndex].mixerList, mixer, BAPE_Mixer, ncoNode);
194}
195
196static BERR_Code BAPE_P_SetNcoFreq_isr( BAPE_Handle handle, BAPE_Nco nco, unsigned baseRate, unsigned *pOversample, BAVC_Timebase outputTimebase )
197{
198    int i;
199
200    struct ncoInfo {
201            unsigned baseFs; int oversample; long ncoFreq; int sampleInc; long numerator; int denominator; int phaseInc;
202    } ncoInfo[] = 
203    {       /* Multiples of 32 KHz */
204            {  32000,              256,         8192000,          3,            303,           1024,          0x09b583  },
205            {  64000,              128,         8192000,          3,            303,           1024,          0x09b583  },
206            {  64000,              256,        16384000,          1,           1327,           2048,          0x136B06  },
207            { 128000,              128,        16384000,          1,           1327,           2048,          0x136B06  },
208            { 128000,              256,        32768000,          0,           3375,           4096,          0x26D60D  },
209
210            /* Multiples of 44.1 KHz */
211            {  44100,              256,        11289600,          2,            307,            784,          0x0d6159  },
212            {  88200,              128,        11289600,          2,            307,            784,          0x0d6159  },
213            {  88200,              256,        22579200,          1,            307,           1568,          0x1AC2B2  },
214            { 176400,              128,        22579200,          1,            307,           1568,          0x1AC2B2  },
215            { 176400,              256,        45158400,          0,           1875,           3136,          0x358564  },
216                                                                                           
217            /* Multiples of 48 KHz */
218            {  48000,              256,        12288000,          2,            101,            512,          0x0e9045  },
219            {  96000,              128,        12288000,          2,            101,            512,          0x0e9045  },
220            {  96000,              256,        24576000,          1,            101,           1024,          0x1D208A  },
221            { 192000,              128,        24576000,          1,            101,           1024,          0x1D208A  },
222            { 192000,              256,        49152000,          0,           1125,           2048,          0x3A4114  },
223    };
224    int numElems = sizeof ncoInfo/sizeof ncoInfo[0];
225
226    if (pOversample ) *pOversample = 0;     /* set to zero in case of early return */
227
228    /* Search the table above to find the first entry for our baseRate.  There may be several entries for
229     * the baseRate, but for now, just use the first one we find.  */
230    for ( i=0 ; i<numElems ; i++  )
231    {
232        if ( ncoInfo[i].baseFs ==  baseRate )
233        {
234            break;
235        }
236    }
237
238    if ( i >= numElems )
239    {
240        BDBG_ERR(("Can't find ncoInfo for sampling rate %u", baseRate));
241        return BERR_TRACE(BERR_INVALID_PARAMETER);
242    }
243
244    BDBG_ASSERT(ncoInfo[i].baseFs ==  baseRate);
245
246    BDBG_MSG(("Setting NCO %u frequency to %u Hz (%u * %u)", nco,  ncoInfo[i].ncoFreq, ncoInfo[i].oversample, ncoInfo[i].baseFs));
247
248    BAPE_Nco_UpdateDividers_isr(handle, nco, ncoInfo[i].sampleInc, ncoInfo[i].numerator, ncoInfo[i].denominator, ncoInfo[i].phaseInc, outputTimebase);
249    handle->audioNcos[nco].baseSampleRate   = baseRate;
250    handle->audioNcos[nco].ncoFreq          = ncoInfo[i].ncoFreq;
251    handle->audioNcos[nco].timebase         = outputTimebase;
252
253    if (pOversample ) *pOversample = ncoInfo[i].oversample;   /* pass oversample factor back to caller. */
254
255    return BERR_SUCCESS;
256}
257
258BERR_Code BAPE_P_UpdateNco_isr(BAPE_Handle handle, BAPE_Nco nco)
259{
260    unsigned baseRate = 0;
261    unsigned idleRate = 0;
262    BAVC_Timebase outputTimebase = (unsigned) -1;
263    bool          gotTimebase = false;
264    BAPE_Mixer *pMixer;
265    BERR_Code errCode;
266
267    BDBG_OBJECT_ASSERT(handle, BAPE_Device);
268    BDBG_ASSERT(nco < BAPE_CHIP_MAX_NCOS);
269
270    /* Walk through each mixer and make sure we have no conflicts */
271    for ( pMixer = BLST_S_FIRST(&handle->audioNcos[nco].mixerList);
272          pMixer != NULL;
273          pMixer = BLST_S_NEXT(pMixer, ncoNode) )
274    {
275        unsigned mixerRate;
276
277        if ( pMixer->sampleRate == 0 )
278        {
279            continue;
280        }
281
282        if ( ! gotTimebase )
283        {
284            outputTimebase = pMixer->settings.outputTimebase;
285            gotTimebase = true;
286        }
287        else if (pMixer->settings.outputTimebase != outputTimebase )
288        {
289            BDBG_WRN(("Timebase conflict on NCO %d.  One mixer requests timebase %u another requests timebase %u", nco, outputTimebase, pMixer->settings.outputTimebase));
290        }
291
292        mixerRate = pMixer->sampleRate;
293
294        if ( pMixer->running )
295        {
296            if ( baseRate == 0 )
297            {
298                baseRate = mixerRate;
299            }
300            else if ( baseRate != mixerRate )
301            {
302                BDBG_WRN(("Sample rate conflict on NCO %d.  One mixer requests %u another requests %u", nco, baseRate, mixerRate));
303            }
304        }
305        else if ( idleRate == 0 )
306        {
307            idleRate = mixerRate;
308        }
309    }
310
311    if ( baseRate == 0 )
312    {
313        baseRate = idleRate;
314    }
315
316    if ( baseRate != 0 )
317    {
318        uint32_t oversample;
319
320        BDBG_MSG(("Updating NCO %u for base sample rate of %u Hz", nco, baseRate));
321        errCode = BAPE_P_SetNcoFreq_isr( handle, nco, baseRate, &oversample, outputTimebase );
322        if ( errCode )
323        {
324            BDBG_ERR(("Failed to set NCO %u for sample rate of %u Hz", nco, baseRate));
325            return BERR_TRACE(errCode);
326        }
327
328        /* For each output, set it's mclk appropriately */
329        for ( pMixer = BLST_S_FIRST(&handle->audioNcos[nco].mixerList);
330              pMixer != NULL;
331              pMixer = BLST_S_NEXT(pMixer, ncoNode) )
332        {
333            BAPE_OutputPort output;
334            BAPE_MclkSource mclkSource;
335
336            BDBG_ASSERT( BAPE_MCLKSOURCE_IS_NCO(pMixer->mclkSource));
337
338            if ( pMixer->sampleRate == 0 )
339            {
340                /* Skip this mixer if it doesn't have a sample rate yet */
341                continue;
342            }
343
344            switch ( nco )
345            {
346            default:
347            case BAPE_Nco_e0:
348                mclkSource = BAPE_MclkSource_eNco0;
349                break;
350            case BAPE_Nco_e1:
351                mclkSource = BAPE_MclkSource_eNco1;
352                break;
353            case BAPE_Nco_e2:
354                mclkSource = BAPE_MclkSource_eNco2;
355                break;
356            }
357            BDBG_ASSERT( mclkSource == pMixer->mclkSource);
358
359            for ( output = BLST_S_FIRST(&pMixer->outputList);
360                  output != NULL;
361                  output = BLST_S_NEXT(output, node) )
362            {
363                if ( output->setMclk_isr )
364                {
365                    BDBG_MSG(("Setting output mclk for '%s' to source:%s ratio:%u",
366                               output->pName, BAPE_Mixer_P_MclkSourceToText(mclkSource), oversample));
367                    output->setMclk_isr(output, mclkSource, 0, oversample);
368                }
369            }
370            if ( pMixer->fs != BAPE_FS_INVALID )
371            {
372                BDBG_MSG(("Setting FS mclk for FS %u to source:%s ratio:%u",
373                           pMixer->fs, BAPE_Mixer_P_MclkSourceToText(mclkSource), oversample));
374                BAPE_P_SetFsTiming_isr(handle, pMixer->fs, mclkSource, 0, oversample);
375            }
376        }
377    }
378    else
379    {
380        BDBG_MSG(("Not updating NCO %u rate (unknown)", nco));
381    }
382
383    return BERR_SUCCESS;
384}
385
386
387BERR_Code BAPE_Nco_P_ResumeFromStandby(BAPE_Handle bapeHandle)
388{
389    BERR_Code   errCode = BERR_SUCCESS;
390    unsigned    ncoIndex;
391
392    BDBG_OBJECT_ASSERT(bapeHandle, BAPE_Device);
393
394    /* For each nco, call the functions necessary to restore the hardware to it's appropriate state. */
395    for ( ncoIndex=0 ; ncoIndex<BAPE_CHIP_MAX_NCOS ; ncoIndex++ )
396    {
397        BAPE_AudioNco *pNco = &bapeHandle->audioNcos[ncoIndex];
398
399        /* Now apply changes for the settings struct. */
400            /* Nothing to do here. NCOs don't have a SetSettings function to call. */
401
402        /* Now restore the dynamic stuff from the values saved in the device struct. */
403        if (pNco->baseSampleRate != 0)
404        {
405            BKNI_EnterCriticalSection();
406                errCode = BAPE_P_SetNcoFreq_isr( bapeHandle, ncoIndex, pNco->baseSampleRate, NULL, pNco->timebase );
407            BKNI_LeaveCriticalSection();
408            if ( errCode ) return BERR_TRACE(errCode);
409        }
410    }
411    return errCode;
412}
413
414
415/***************************************************************************
416    Define stub functions for when there are no NCOs.
417***************************************************************************/
418#else /* BAPE_CHIP_MAX_NCOS > 0 */
419    /* No NCOs, just use stubbed out functions. */
420
421/**************************************************************************/
422
423BERR_Code BAPE_Nco_P_ResumeFromStandby(BAPE_Handle bapeHandle)
424{
425    BSTD_UNUSED(bapeHandle);
426    return BERR_SUCCESS;
427}
428
429#endif /* BAPE_CHIP_MAX_NCOS > 0 */
430
431
432
Note: See TracBrowser for help on using the repository browser.