blob: 55bf2d93e3b1ae3438cc166f90222d1273556d51 [file] [log] [blame]
Ke Dong32248e72012-09-26 19:22:56 -07001/*******************************************************************************
2Copyright (C) Marvell International Ltd. and its affiliates
3
4This software file (the "File") is owned and distributed by Marvell
5International Ltd. and/or its affiliates ("Marvell") under the following
6alternative licensing terms. Once you have made an election to distribute the
7File under one of the following license alternatives, please (i) delete this
8introductory statement regarding license alternatives, (ii) delete the two
9license alternatives that you have not elected to use and (iii) preserve the
10Marvell copyright notice above.
11
12********************************************************************************
13Marvell Commercial License Option
14
15If you received this File from Marvell and you have entered into a commercial
16license agreement (a "Commercial License") with Marvell, the File is licensed
17to you under the terms of the applicable Commercial License.
18
19********************************************************************************
20Marvell GPL License Option
21
22If you received this File from Marvell, you may opt to use, redistribute and/or
23modify this File in accordance with the terms and conditions of the General
24Public License Version 2, June 1991 (the "GPL License"), a copy of which is
25available along with the File in the license.txt file or by writing to the Free
26Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
27on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
28
29THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
30WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
31DISCLAIMED. The GPL License provides additional details about this warranty
32disclaimer.
33********************************************************************************
34Marvell BSD License Option
35
36If you received this File from Marvell, you may opt to use, redistribute and/or
37modify this File under the following licensing terms.
38Redistribution and use in source and binary forms, with or without modification,
39are permitted provided that the following conditions are met:
40
41 * Redistributions of source code must retain the above copyright notice,
42 this list of conditions and the following disclaimer.
43
44 * Redistributions in binary form must reproduce the above copyright
45 notice, this list of conditions and the following disclaimer in the
46 documentation and/or other materials provided with the distribution.
47
48 * Neither the name of Marvell nor the names of its contributors may be
49 used to endorse or promote products derived from this software without
50 specific prior written permission.
51
52THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
53ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
56ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
59ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62
63*******************************************************************************/
64#include "voiceband/tdm/mvTdm.h"
65
66/* defines */
67#define INT_SAMPLE 2
68#define BUFF_IS_FULL 1
69#define BUFF_IS_EMPTY 0
70#define FIRST_INT 1
71#define TOTAL_BUFFERS 2
72#define MV_TDM_NEXT_BUFFER(buf) ((buf + 1) % TOTAL_BUFFERS)
73#define MV_TDM_PREV_BUFFER(buf, step) ((TOTAL_BUFFERS + buf - step) % TOTAL_BUFFERS)
74#define MV_TDM_CS 0
75#define BUFF_INVALID -1
76
77/* static APIs */
78static MV_STATUS mvTdmChInit(MV_U8 ch);
79static MV_STATUS mvTdmChRemove(MV_U8 ch);
80static MV_VOID mvTdmReset(MV_VOID);
81static MV_VOID mvTdmDaisyChainModeSet(MV_VOID);
82static MV_VOID mvTdmShowProperties(MV_VOID);
83/* Tx */
84static INLINE MV_STATUS mvTdmChTxLow(MV_U8 ch);
85/* Rx */
86static INLINE MV_STATUS mvTdmChRxLow(MV_U8 ch);
87
88/* TDM channel info structure */
89typedef struct _mv_tdm_ch_info {
90 MV_U8 ch;
91 MV_U8 *rxBuffVirt[TOTAL_BUFFERS], *txBuffVirt[TOTAL_BUFFERS];
92 MV_ULONG rxBuffPhys[TOTAL_BUFFERS], txBuffPhys[TOTAL_BUFFERS];
93 MV_U8 rxBuffFull[TOTAL_BUFFERS], txBuffFull[TOTAL_BUFFERS];
94 MV_U8 rxCurrBuff, txCurrBuff;
95 MV_U8 rxFirst;
96} MV_TDM_CH_INFO;
97
98/* globals */
99static MV_U8 *rxAggrBuffVirt, *txAggrBuffVirt;
100static MV_ULONG rxAggrBuffPhys, txAggrBuffPhys;
101static MV_U8 rxInt, txInt;
102static MV_16 rxFull, txEmpty;
103static MV_U8 tdmEnable;
104static MV_U8 spiMode;
105static MV_U8 factor;
106static MV_PCM_FORMAT pcmFormat;
107static MV_BAND_MODE tdmBandMode;
108static MV_TDM_CH_INFO *tdmChInfo[MV_TDM_TOTAL_CHANNELS] = { NULL, NULL };
109
John Newlin2e746432013-05-31 10:38:29 -0700110static MV_U8 intLock;
111static MV_U32 intRxCount;
112static MV_U32 intTxCount;
113static MV_U32 intRx0Count;
114static MV_U32 intTx0Count;
115static MV_U32 intRx1Count;
116static MV_U32 intTx1Count;
117static MV_U32 intRx0Miss;
118static MV_U32 intTx0Miss;
119static MV_U32 intRx1Miss;
120static MV_U32 intTx1Miss;
121static MV_U32 pcmRestartCount;
122
Ke Dong32248e72012-09-26 19:22:56 -0700123MV_STATUS mvTdmHalInit(MV_TDM_PARAMS *tdmParams, MV_TDM_HAL_DATA *halData)
124{
125 MV_U8 ch;
126 MV_U32 pcmCtrlReg, nbDelay = 0, wbDelay = 0;
127 MV_U32 chDelay[4] = { 0, 0, 0, 0 };
128
129 MV_TRC_REC("->%s\n", __func__);
130 mvTdmShowProperties();
131
132 /* Init globals */
133 rxInt = txInt = 0;
134 rxFull = txEmpty = BUFF_INVALID;
John Newlin2e746432013-05-31 10:38:29 -0700135 tdmEnable = 0, intLock = 0;
Ke Dong32248e72012-09-26 19:22:56 -0700136 spiMode = halData->spiMode;
137 pcmFormat = tdmParams->pcmFormat;
John Newlin2e746432013-05-31 10:38:29 -0700138 intRxCount = 0, intTxCount = 0;
139 intRx0Count = 0, intTx0Count = 0;
140 intRx1Count = 0, intTx1Count = 0;
141 intRx0Miss = 0, intTx0Miss = 0;
142 intRx1Miss = 0, intTx1Miss = 0;
143 pcmRestartCount = 0;
Ke Dong32248e72012-09-26 19:22:56 -0700144
145 if (tdmParams->samplingPeriod > MV_TDM_MAX_SAMPLING_PERIOD)
146 factor = 1; /* use base sample period(10ms) */
147 else
148 factor = (tdmParams->samplingPeriod / MV_TDM_BASE_SAMPLING_PERIOD);
149
150 /* Extract pcm format & band mode */
151 if (pcmFormat == MV_PCM_FORMAT_4BYTES) {
152 pcmFormat = MV_PCM_FORMAT_2BYTES;
153 tdmBandMode = MV_WIDE_BAND;
154 } else {
155 tdmBandMode = MV_NARROW_BAND;
156 }
157
158 /* Allocate aggregated buffers for data transport */
159 MV_TRC_REC("allocate %d bytes for aggregated buffer\n", MV_TDM_AGGR_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
160 rxAggrBuffVirt = (MV_U8 *) mvOsIoCachedMalloc(NULL, MV_TDM_AGGR_BUFF_SIZE(pcmFormat, tdmBandMode, factor),
161 &rxAggrBuffPhys, NULL);
162 txAggrBuffVirt = (MV_U8 *) mvOsIoCachedMalloc(NULL, MV_TDM_AGGR_BUFF_SIZE(pcmFormat, tdmBandMode, factor),
163 &txAggrBuffPhys, NULL);
164 if (!rxAggrBuffVirt || !txAggrBuffVirt) {
165 mvOsPrintf("%s: Error malloc failed\n", __func__);
166 return MV_NO_RESOURCE;
167 }
168
169 /* Clear buffers */
170 memset(rxAggrBuffVirt, 0, MV_TDM_AGGR_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
171 memset(txAggrBuffVirt, 0, MV_TDM_AGGR_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
172
173 /* Calculate CH(0/1) Delay Control for narrow/wideband modes */
174 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
175 nbDelay = ((tdmParams->pcmSlot[ch] * PCM_SLOT_PCLK) + 1);
176 wbDelay = (nbDelay + ((halData->frameTs / 2) * PCM_SLOT_PCLK)); /* Offset required by ZARLINK VE880 SLIC */
177 chDelay[ch] = ((nbDelay << CH_RX_DELAY_OFFS) | (nbDelay << CH_TX_DELAY_OFFS));
178 chDelay[(ch + 2)] = ((wbDelay << CH_RX_DELAY_OFFS) | (wbDelay << CH_TX_DELAY_OFFS));
179 }
180
181 /* Config TDM */
John Newlin2e746432013-05-31 10:38:29 -0700182 MV_REG_BIT_RESET(TDM_SPI_MUX_REG, BIT0); /* enable TDM/SPI interface */
183 MV_REG_BIT_SET(TDM_MISC_REG, BIT0); /* sw reset to TDM for 5181L-A1 & up */
Ke Dong32248e72012-09-26 19:22:56 -0700184 MV_REG_WRITE(INT_RESET_SELECT_REG, CLEAR_ON_ZERO); /* int cause is not clear on read */
185 MV_REG_WRITE(INT_EVENT_MASK_REG, 0x3ffff); /* all interrupt bits latched in status */
186 MV_REG_WRITE(INT_STATUS_MASK_REG, 0); /* disable interrupts */
187 MV_REG_WRITE(INT_STATUS_REG, 0); /* clear int status register */
188
189 /* Bypass clock divider */
190 MV_REG_WRITE(PCM_CLK_RATE_DIV_REG, PCM_DIV_PASS); /* PCM PCLK freq */
191
192 MV_REG_WRITE(DUMMY_RX_WRITE_DATA_REG, 0); /* Padding on Rx completion */
193 MV_REG_BYTE_WRITE(SPI_GLOBAL_CTRL_REG, MV_REG_READ(SPI_GLOBAL_CTRL_REG) | SPI_GLOBAL_ENABLE);
194 MV_REG_BYTE_WRITE(SPI_CLK_PRESCALAR_REG, SPI_CLK_2MHZ); /* SPI SCLK freq */
195 MV_REG_WRITE(FRAME_TIMESLOT_REG, (MV_U32)halData->frameTs); /* Number of timeslots (PCLK) */
196
197 if (tdmBandMode == MV_NARROW_BAND) {
198 pcmCtrlReg = (CONFIG_PCM_CRTL | (((MV_U8)pcmFormat - 1) << PCM_SAMPLE_SIZE_OFFS));
199 MV_REG_WRITE(PCM_CTRL_REG, pcmCtrlReg); /* PCM configuration */
200 MV_REG_WRITE(CH_DELAY_CTRL_REG(0), chDelay[0]); /* CH0 delay control register */
201 MV_REG_WRITE(CH_DELAY_CTRL_REG(1), chDelay[1]); /* CH1 delay control register */
202 } else { /* MV_WIDE_BAND */
203
204 pcmCtrlReg = (CONFIG_WB_PCM_CRTL | (((MV_U8)pcmFormat - 1) << PCM_SAMPLE_SIZE_OFFS));
205 MV_REG_WRITE(PCM_CTRL_REG, pcmCtrlReg); /* PCM configuration - WB support */
206 MV_REG_WRITE(CH_DELAY_CTRL_REG(0), chDelay[0]); /* CH0 delay control register */
207 MV_REG_WRITE(CH_DELAY_CTRL_REG(1), chDelay[1]); /* CH1 delay control register */
208 MV_REG_WRITE(CH_WB_DELAY_CTRL_REG(0), chDelay[2]); /* CH0 WB delay control register */
209 MV_REG_WRITE(CH_WB_DELAY_CTRL_REG(1), chDelay[3]); /* CH1 WB delay control register */
210 }
211
212 /* Issue reset to codec(s) */
213 MV_TRC_REC("reseting voice unit(s)\n");
214 MV_REG_WRITE(MISC_CTRL_REG, 0);
215 mvOsDelay(1);
216 MV_REG_WRITE(MISC_CTRL_REG, 1);
217
218 if (spiMode) {
219 /* Configure TDM to work in daisy chain mode */
220 mvTdmDaisyChainModeSet();
221 }
222
223 /* Initialize all HW units */
224 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
225 if (mvTdmChInit(ch) != MV_OK) {
226 mvOsPrintf("mvTdmChInit(%d) failed !\n", ch);
227 return MV_ERROR;
228 }
229 }
230
231 /* Enable SLIC/DAA interrupt detection(before pcm is active) */
232 MV_REG_WRITE(INT_STATUS_MASK_REG, (MV_REG_READ(INT_STATUS_MASK_REG) | TDM_INT_SLIC));
233
234 MV_TRC_REC("<-%s\n", __func__);
235 return MV_OK;
236}
237
238static MV_STATUS mvTdmChInit(MV_U8 ch)
239{
240 MV_TDM_CH_INFO *chInfo;
241 MV_U32 buff;
242
243 MV_TRC_REC("->%s ch%d\n", __func__, ch);
244
245 if (ch >= MV_TDM_TOTAL_CHANNELS) {
246 mvOsPrintf("%s: error, channel(%d) exceeds maximum(%d)\n", __func__, ch, MV_TDM_TOTAL_CHANNELS);
247 return MV_BAD_PARAM;
248 }
249
250 tdmChInfo[ch] = chInfo = (MV_TDM_CH_INFO *) mvOsMalloc(sizeof(MV_TDM_CH_INFO));
251 if (!chInfo) {
252 mvOsPrintf("%s: error malloc failed\n", __func__);
253 return MV_NO_RESOURCE;
254 }
255
256 chInfo->ch = ch;
257
258 /* Per channel TDM init */
259 MV_REG_WRITE(CH_ENABLE_REG(ch), CH_DISABLE); /* disable channel (enable in pcm start) */
260 MV_REG_WRITE(CH_SAMPLE_REG(ch), CONFIG_CH_SAMPLE(tdmBandMode, factor)); /* set total samples and int sample */
261
262 for (buff = 0; buff < TOTAL_BUFFERS; buff++) {
263 /* Buffers must be 32B aligned */
264 chInfo->rxBuffVirt[buff] =
265 (MV_U8 *) mvOsIoUncachedMalloc(NULL, MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor),
266 &(chInfo->rxBuffPhys[buff]), NULL);
267 chInfo->rxBuffFull[buff] = BUFF_IS_EMPTY;
268
269 chInfo->txBuffVirt[buff] =
270 (MV_U8 *) mvOsIoUncachedMalloc(NULL, MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor),
271 &(chInfo->txBuffPhys[buff]), NULL);
272 chInfo->txBuffFull[buff] = BUFF_IS_FULL;
273
274 memset(chInfo->txBuffVirt[buff], 0, MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
275
276 if (((MV_ULONG) chInfo->rxBuffVirt[buff] | chInfo->rxBuffPhys[buff] |
277 (MV_ULONG) chInfo->txBuffVirt[buff] | chInfo->txBuffPhys[buff]) & 0x1f) {
278 mvOsPrintf("%s: error, unaligned buffer allocation\n", __func__);
279 }
280 }
281
282 MV_TRC_REC("<-%s\n", __func__);
283 return MV_OK;
284}
285
286MV_VOID mvTdmRelease(MV_VOID)
287{
288 MV_U8 ch;
289
290 MV_TRC_REC("->%s\n", __func__);
291
292 /* Free Rx/Tx aggregated buffers */
293 mvOsIoCachedFree(NULL, MV_TDM_AGGR_BUFF_SIZE(pcmFormat, tdmBandMode, factor), rxAggrBuffPhys,
294 rxAggrBuffVirt, 0);
295 mvOsIoCachedFree(NULL, MV_TDM_AGGR_BUFF_SIZE(pcmFormat, tdmBandMode, factor), txAggrBuffPhys,
296 txAggrBuffVirt, 0);
297
298 /* Release HW channel resources */
299 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++)
300 mvTdmChRemove(ch);
301
302 MV_TRC_REC("<-%s\n", __func__);
303}
304
305static MV_STATUS mvTdmChRemove(MV_U8 ch)
306{
307 MV_TDM_CH_INFO *chInfo;
308 MV_U8 buff;
309
310 MV_TRC_REC("->%s ch%d\n", __func__, ch);
311
312 if (ch >= MV_TDM_TOTAL_CHANNELS) {
313 mvOsPrintf("%s: error, channel(%d) exceeds maximum(%d)\n", __func__, ch, MV_TDM_TOTAL_CHANNELS);
314 return MV_BAD_PARAM;
315 }
316
317 chInfo = tdmChInfo[ch];
318
319 for (buff = 0; buff < TOTAL_BUFFERS; buff++) {
320 mvOsIoUncachedFree(NULL, MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor), chInfo->rxBuffPhys[buff],
321 chInfo->rxBuffVirt[buff], 0);
322 mvOsIoUncachedFree(NULL, MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor), chInfo->txBuffPhys[buff],
323 chInfo->txBuffVirt[buff], 0);
324 }
325
326 mvOsFree(chInfo);
327
328 MV_TRC_REC("<-%s ch%d\n", __func__, ch);
329 return MV_OK;
330}
331
332static MV_VOID mvTdmReset(MV_VOID)
333{
334 MV_TDM_CH_INFO *chInfo;
335 MV_U8 buff, ch;
336
337 MV_TRC_REC("->%s\n", __func__);
338
339 /* Reset globals */
340 rxInt = txInt = 0;
341 rxFull = txEmpty = BUFF_INVALID;
342
343 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
344 chInfo = tdmChInfo[ch];
345 chInfo->rxFirst = FIRST_INT;
346 chInfo->txCurrBuff = chInfo->rxCurrBuff = 0;
347 for (buff = 0; buff < TOTAL_BUFFERS; buff++) {
348 chInfo->rxBuffFull[buff] = BUFF_IS_EMPTY;
349 chInfo->txBuffFull[buff] = BUFF_IS_FULL;
350
351 }
352 }
353
354 MV_TRC_REC("<-%s\n", __func__);
355 return;
356}
357
358MV_VOID mvTdmPcmStart(MV_VOID)
359{
360 MV_TDM_CH_INFO *chInfo;
361 MV_U8 ch;
362
363 MV_TRC_REC("->%s\n", __func__);
364
365 tdmEnable = 1; /* TDM is enabled */
John Newlin2e746432013-05-31 10:38:29 -0700366 intLock = 0;
Ke Dong32248e72012-09-26 19:22:56 -0700367 mvTdmReset();
368
369 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
370 chInfo = tdmChInfo[ch];
371
372 /* Set Tx buff */
373 MV_REG_WRITE(CH_TX_ADDR_REG(ch), chInfo->txBuffPhys[chInfo->txCurrBuff]);
374 MV_REG_BYTE_WRITE(CH_BUFF_OWN_REG(ch) + TX_OWN_BYTE_OFFS, OWN_BY_HW);
375
376 /* Set Rx buff */
377 MV_REG_WRITE(CH_RX_ADDR_REG(ch), chInfo->rxBuffPhys[chInfo->rxCurrBuff]);
378 MV_REG_BYTE_WRITE(CH_BUFF_OWN_REG(ch) + RX_OWN_BYTE_OFFS, OWN_BY_HW);
379
380 }
381
382 /* Enable Tx */
383 MV_REG_BYTE_WRITE(CH_ENABLE_REG(0) + TX_ENABLE_BYTE_OFFS, CH_ENABLE);
384 MV_REG_BYTE_WRITE(CH_ENABLE_REG(1) + TX_ENABLE_BYTE_OFFS, CH_ENABLE);
385
386 /* Enable Rx */
387 MV_REG_BYTE_WRITE(CH_ENABLE_REG(0) + RX_ENABLE_BYTE_OFFS, CH_ENABLE);
388 MV_REG_BYTE_WRITE(CH_ENABLE_REG(1) + RX_ENABLE_BYTE_OFFS, CH_ENABLE);
389
390 /* Enable Tx interrupts */
391 MV_REG_WRITE(INT_STATUS_REG, MV_REG_READ(INT_STATUS_REG) & (~(TDM_INT_TX(0) | TDM_INT_TX(1))));
392 MV_REG_WRITE(INT_STATUS_MASK_REG, (MV_REG_READ(INT_STATUS_MASK_REG) | TDM_INT_TX(0) | TDM_INT_TX(1)));
393
394 /* Enable Rx interrupts */
395 MV_REG_WRITE(INT_STATUS_REG, (MV_REG_READ(INT_STATUS_REG) & (~(TDM_INT_RX(0) | TDM_INT_RX(1)))));
396 MV_REG_WRITE(INT_STATUS_MASK_REG, (MV_REG_READ(INT_STATUS_MASK_REG) | TDM_INT_RX(0) | TDM_INT_RX(1)));
397
398 MV_TRC_REC("<-%s\n", __func__);
399}
400
401MV_VOID mvTdmPcmStop(MV_VOID)
402{
403 MV_TRC_REC("->%s\n", __func__);
404
405 tdmEnable = 0;
406 mvTdmReset();
407
408 /* Mask all interrpts except SLIC/DAA */
409 /*MV_REG_WRITE(INT_STATUS_MASK_REG, (MV_U32)TDM_INT_SLIC);*/
410
411 MV_TRC_REC("<-%s\n", __func__);
412}
413
414MV_STATUS mvTdmTx(MV_U8 *tdmTxBuff)
415{
416 MV_TDM_CH_INFO *chInfo;
417 MV_U8 ch;
418 MV_U8 *pTdmTxBuff;
419
420 MV_TRC_REC("->%s\n", __func__);
421
422 /* Sanity check */
423 if (tdmTxBuff != txAggrBuffVirt) {
424 mvOsPrintf("%s: Error, invalid Tx buffer !!!\n", __func__);
425 return MV_ERROR;
426 }
427
428 if (!tdmEnable) {
429 mvOsPrintf("%s: Error, no active Tx channels are available\n", __func__);
430 return MV_ERROR;
431 }
432
433 if (txEmpty == BUFF_INVALID) {
434 MV_TRC_REC("%s: Tx not ready\n", __func__);
435 return MV_NOT_READY;
436 }
437
438 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
439 chInfo = tdmChInfo[ch];
440 MV_TRC_REC("ch%d: fill buf %d with %d bytes\n", ch, txEmpty,
441 MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
442 chInfo->txBuffFull[txEmpty] = BUFF_IS_FULL;
443 pTdmTxBuff = tdmTxBuff + (ch * MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
444 /* Copy data from voice engine buffer to DMA */
445 mvOsMemcpy(chInfo->txBuffVirt[txEmpty], pTdmTxBuff,
446 MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
447 }
448
449 txEmpty = BUFF_INVALID;
450
451 MV_TRC_REC("<-%s\n", __func__);
452 return MV_OK;
453}
454
455MV_STATUS mvTdmRx(MV_U8 *tdmRxBuff)
456{
457 MV_TDM_CH_INFO *chInfo;
458 MV_U8 ch;
459 MV_U8 *pTdmRxBuff;
460
461 MV_TRC_REC("->%s\n", __func__);
462
463 /* Sanity check */
464 if (tdmRxBuff != rxAggrBuffVirt) {
465 mvOsPrintf("%s: invalid Rx buffer !!!\n", __func__);
466 return MV_ERROR;
467 }
468
469 if (!tdmEnable) {
470 mvOsPrintf("%s: Error, no active Rx channels are available\n", __func__);
471 return MV_ERROR;
472 }
473
474 if (rxFull == BUFF_INVALID) {
475 MV_TRC_REC("%s: Rx not ready\n", __func__);
476 return MV_NOT_READY;
477 }
478
479 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
480 chInfo = tdmChInfo[ch];
481 chInfo->rxBuffFull[rxFull] = BUFF_IS_EMPTY;
482 MV_TRC_REC("%s get Rx buffer(%d) for channel(%d)\n", __func__, rxFull, ch);
483 pTdmRxBuff = tdmRxBuff + (ch * MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
484 /* Copy data from DMA to voice engine buffer */
485 mvOsMemcpy(pTdmRxBuff, chInfo->rxBuffVirt[rxFull], MV_TDM_CH_BUFF_SIZE(pcmFormat, tdmBandMode, factor));
486 }
487
488 rxFull = BUFF_INVALID;
489 MV_TRC_REC("<-%s\n", __func__);
490 return MV_OK;
491}
492
493/* Low level TDM interrupt service routine */
John Newlin2e746432013-05-31 10:38:29 -0700494MV_32 mvTdmIntLow(MV_TDM_INT_INFO *tdmIntInfo)
Ke Dong32248e72012-09-26 19:22:56 -0700495{
496 MV_U32 statusReg, maskReg, statusAndMask;
John Newlin2e746432013-05-31 10:38:29 -0700497 MV_32 ret = 0;
498 MV_32 intTxMiss = -1;
499 MV_32 intRxMiss = -1;
Ke Dong32248e72012-09-26 19:22:56 -0700500 MV_U8 ch;
501
502 MV_TRC_REC("->%s\n", __func__);
503
504 /* Read Status & mask registers */
505 statusReg = MV_REG_READ(INT_STATUS_REG);
506 maskReg = MV_REG_READ(INT_STATUS_MASK_REG);
507 MV_TRC_REC("CAUSE(0x%x), MASK(0x%x)\n", statusReg, maskReg);
508
509 /* Refer only to unmasked bits */
510 statusAndMask = statusReg & maskReg;
511
512 /* Reset params */
513 tdmIntInfo->tdmRxBuff = NULL;
514 tdmIntInfo->tdmTxBuff = NULL;
515 tdmIntInfo->intType = MV_EMPTY_INT;
516 tdmIntInfo->cs = MV_TDM_CS;
517
518 /* Handle SLIC/DAA int */
519 if (statusAndMask & SLIC_INT_BIT) {
520 MV_TRC_REC("Phone interrupt !!!\n");
521 tdmIntInfo->intType |= MV_PHONE_INT;
522 }
523#if 0
524 /* Return in case TDM is disabled */
525 if (!tdmEnable) {
526 MV_TRC_REC("TDM is disabled - quit low level ISR\n");
527 MV_REG_WRITE(INT_STATUS_REG, ~statusReg);
528 return;
529 }
530#endif
531 if (statusAndMask & DMA_ABORT_BIT) {
532 mvOsPrintf("DMA data abort. Address: 0x%08x, Info: 0x%08x\n",
533 MV_REG_READ(DMA_ABORT_ADDR_REG), MV_REG_READ(DMA_ABORT_INFO_REG));
534 tdmIntInfo->intType |= MV_DMA_ERROR_INT;
535 }
536
537 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
Ke Dong32248e72012-09-26 19:22:56 -0700538
John Newlin2e746432013-05-31 10:38:29 -0700539 /* Give next buff to TDM and set curr buff as empty */
540 if ((statusAndMask & TX_BIT(ch)) && tdmEnable && !intLock) {
541 MV_TRC_REC("Tx interrupt(ch%d) !!!\n", ch);
542
543 intTxCount++;
544 if (ch == 0) {
545 intTx0Count++;
546 if (intTx0Count <= intTx1Count) {
547 intTxMiss = 0;
548 intTx0Miss++;
549 }
550 } else {
551 intTx1Count++;
552 if (intTx1Count < intTx0Count) {
553 intTxMiss = 1;
554 intTx1Miss++;
Ke Dong32248e72012-09-26 19:22:56 -0700555 }
556 }
557
John Newlin2e746432013-05-31 10:38:29 -0700558 /* MV_OK -> Tx is done for both channels */
559 if (mvTdmChTxLow(ch) == MV_OK) {
560 MV_TRC_REC("Assign Tx aggregate buffer for further processing\n");
561 tdmIntInfo->tdmTxBuff = txAggrBuffVirt;
562 tdmIntInfo->intType |= MV_TX_INT;
563 }
564 }
565 }
566
567 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
568
569 if ((statusAndMask & RX_BIT(ch)) && tdmEnable && !intLock) {
570 MV_TRC_REC("Rx interrupt(ch%d) !!!\n", ch);
571
572 intRxCount++;
573 if (ch == 0) {
574 intRx0Count++;
575 if (intRx0Count <= intRx1Count) {
576 intRxMiss = 0;
577 intRx0Miss++;
578 }
579 } else {
580 intRx1Count++;
581 if (intRx1Count < intRx0Count) {
582 intRxMiss = 1;
583 intRx1Miss++;
584 }
585 }
586
587 /* MV_OK -> Rx is done for both channels */
588 if (mvTdmChRxLow(ch) == MV_OK) {
589 MV_TRC_REC("Assign Rx aggregate buffer for further processing\n");
590 tdmIntInfo->tdmRxBuff = rxAggrBuffVirt;
591 tdmIntInfo->intType |= MV_RX_INT;
592 }
593 }
594 }
595
596 for (ch = 0; ch < MV_TDM_TOTAL_CHANNELS; ch++) {
597
598 if (statusAndMask & TX_UNDERFLOW_BIT(ch)) {
599
600 MV_TRC_REC("Tx underflow(ch%d) - checking for root cause...\n", ch);
601 if (tdmEnable) {
602 MV_TRC_REC("Tx underflow ERROR\n");
603 tdmIntInfo->intType |= MV_TX_ERROR_INT;
604 if (!(statusAndMask & TX_BIT(ch))) {
605 ret = -1;
606 /* MV_OK -> Tx is done for both channels */
607 if (mvTdmChTxLow(ch) == MV_OK) {
608 MV_TRC_REC("Assign Tx aggregate buffer for further processing\n");
609 tdmIntInfo->tdmTxBuff = txAggrBuffVirt;
610 tdmIntInfo->intType |= MV_TX_INT;
Ke Dong32248e72012-09-26 19:22:56 -0700611 }
John Newlin2e746432013-05-31 10:38:29 -0700612 }
613 } else {
614 MV_TRC_REC("Expected Tx underflow(not an error)\n");
Ke Dong32248e72012-09-26 19:22:56 -0700615 MV_REG_WRITE(INT_STATUS_MASK_REG,
616 MV_REG_READ(INT_STATUS_MASK_REG) & (~(TDM_INT_TX(ch))));
Ke Dong32248e72012-09-26 19:22:56 -0700617 }
618 }
619
Ke Dong32248e72012-09-26 19:22:56 -0700620
John Newlin2e746432013-05-31 10:38:29 -0700621 if (statusAndMask & RX_OVERFLOW_BIT(ch)) {
622 MV_TRC_REC("Rx overflow(ch%d) - checking for root cause...\n", ch);
623 if (tdmEnable) {
624 MV_TRC_REC("Rx overflow ERROR\n");
625 tdmIntInfo->intType |= MV_RX_ERROR_INT;
626 if (!(statusAndMask & RX_BIT(ch))) {
627 ret = -1;
628 /* MV_OK -> Rx is done for both channels */
629 if (mvTdmChRxLow(ch) == MV_OK) {
630 MV_TRC_REC("Assign Rx aggregate buffer for further processing\n");
631 tdmIntInfo->tdmRxBuff = rxAggrBuffVirt;
632 tdmIntInfo->intType |= MV_RX_INT;
Ke Dong32248e72012-09-26 19:22:56 -0700633 }
Ke Dong32248e72012-09-26 19:22:56 -0700634 }
John Newlin2e746432013-05-31 10:38:29 -0700635 } else {
636 MV_TRC_REC("Expected Rx overflow(not an error)\n");
637 MV_REG_WRITE(INT_STATUS_MASK_REG,
638 MV_REG_READ(INT_STATUS_MASK_REG) & (~(TDM_INT_RX(ch))));
Ke Dong32248e72012-09-26 19:22:56 -0700639 }
640 }
641 }
642
643 /* clear TDM interrupts */
644 MV_REG_WRITE(INT_STATUS_REG, ~statusReg);
645
John Newlin2e746432013-05-31 10:38:29 -0700646 /* Check if interrupt was missed -> restart */
647 if (intTxMiss != -1) {
648 MV_TRC_REC("Missing Tx Interrupt Detected ch%d!!!\n", intTxMiss);
649 if (intTxMiss)
650 intTx1Count = intTx0Count;
651 else
652 intTx0Count = (intTx1Count + 1);
653 ret = -1;
654 }
655
656 if (intRxMiss != -1) {
657 MV_TRC_REC("Missing Rx Interrupt Detected ch%d!!!\n", intRxMiss);
658 if (intRxMiss)
659 intRx1Count = intRx0Count;
660 else
661 intRx0Count = (intRx1Count + 1);
662 ret = -1;
663 }
664
665 if (ret == -1) {
666 intLock = 1;
667 pcmRestartCount++;
668 }
669
Ke Dong32248e72012-09-26 19:22:56 -0700670 MV_TRC_REC("<-%s\n", __func__);
John Newlin2e746432013-05-31 10:38:29 -0700671 return ret;
Ke Dong32248e72012-09-26 19:22:56 -0700672}
673
674static INLINE MV_STATUS mvTdmChTxLow(MV_U8 ch)
675{
676 MV_U32 max_poll = 0;
677 MV_TDM_CH_INFO *chInfo = tdmChInfo[ch];
678
679 MV_TRC_REC("->%s ch%d\n", __func__, ch);
680
681 /* count tx interrupts */
682 txInt++;
683 MV_TRC_REC("txInt(%d)\n", txInt);
684
685 if (chInfo->txBuffFull[chInfo->txCurrBuff] == BUFF_IS_FULL)
686 MV_TRC_REC("curr buff full for hw [MMP ok]\n");
687 else
688 MV_TRC_REC("curr buf is empty [MMP miss write]\n");
689
690 /* Change buffers */
691 chInfo->txCurrBuff = MV_TDM_NEXT_BUFFER(chInfo->txCurrBuff);
692
693 /* Mark next buff to be transmitted by HW as empty. Give it to the HW
694 for next frame. The app need to write the data before HW takes it. */
695 chInfo->txBuffFull[chInfo->txCurrBuff] = BUFF_IS_EMPTY;
696 MV_TRC_REC("->%s clear buf(%d) for channel(%d)\n", __func__, chInfo->txCurrBuff, ch);
697
698 /* Poll on SW ownership (single check) */
699 MV_TRC_REC("start poll for SW ownership\n");
700 while (((MV_REG_BYTE_READ(CH_BUFF_OWN_REG(chInfo->ch) + TX_OWN_BYTE_OFFS) & OWNER_MASK) == OWN_BY_HW)
701 && (max_poll < 2000)) {
702 mvOsUDelay(1);
703 max_poll++;
704 }
705 if (max_poll == 2000) {
706 MV_TRC_REC("poll timeout (~2ms)\n");
707 return MV_TIMEOUT;
708 } else {
709 MV_TRC_REC("tx-low poll stop ok\n");
710 }
711 MV_TRC_REC("ch%d, start tx buff %d\n", ch, chInfo->txCurrBuff);
712
713 /*Set TX buff address (must be 32 byte aligned) */
714 MV_REG_WRITE(CH_TX_ADDR_REG(chInfo->ch), chInfo->txBuffPhys[chInfo->txCurrBuff]);
715
716 /* Set HW ownership */
717 MV_REG_BYTE_WRITE(CH_BUFF_OWN_REG(chInfo->ch) + TX_OWN_BYTE_OFFS, OWN_BY_HW);
718
719 /* Enable Tx */
720 MV_REG_BYTE_WRITE(CH_ENABLE_REG(chInfo->ch) + TX_ENABLE_BYTE_OFFS, CH_ENABLE);
721
722 MV_TRC_REC("<-%s\n", __func__);
723
724 /* Did we get the required amount of irqs for Tx wakeup ? */
725 if (txInt < MV_TDM_INT_COUNTER) {
726 return MV_NOT_READY;
727 } else {
728 txInt = 0;
729 txEmpty = chInfo->txCurrBuff;
730 return MV_OK;
731 }
732}
733
734static INLINE MV_STATUS mvTdmChRxLow(MV_U8 ch)
735{
736 MV_U32 max_poll = 0;
737 MV_TDM_CH_INFO *chInfo = tdmChInfo[ch];
738
739 MV_TRC_REC("->%s ch%d\n", __func__, ch);
740
741 if (chInfo->rxFirst)
742 chInfo->rxFirst = !FIRST_INT;
743 else
744 rxInt++;
745
746 MV_TRC_REC("rxInt(%d)\n", rxInt);
747
748 if (chInfo->rxBuffFull[chInfo->rxCurrBuff] == BUFF_IS_EMPTY)
749 MV_TRC_REC("curr buff empty for hw [MMP ok]\n");
750 else
751 MV_TRC_REC("curr buf is full [MMP miss read]\n");
752
753 /* Mark last buff that was received by HW as full. Give next buff to HW for */
754 /* next frame. The app need to read the data before next irq */
755 chInfo->rxBuffFull[chInfo->rxCurrBuff] = BUFF_IS_FULL;
756
757 /* Change buffers */
758 chInfo->rxCurrBuff = MV_TDM_NEXT_BUFFER(chInfo->rxCurrBuff);
759
760 /* Poll on SW ownership (single check) */
761 MV_TRC_REC("start poll for ownership\n");
762 while (((MV_REG_BYTE_READ(CH_BUFF_OWN_REG(chInfo->ch) + RX_OWN_BYTE_OFFS) & OWNER_MASK) == OWN_BY_HW)
763 && (max_poll < 2000)) {
764 mvOsUDelay(1);
765 max_poll++;
766 }
767 if (max_poll == 2000) {
768 MV_TRC_REC("poll timeout (~2ms)\n");
769 return MV_TIMEOUT;
770 } else {
771 MV_TRC_REC("poll stop ok\n");
772 }
773 MV_TRC_REC("%s ch%d, start rx buff %d\n", __func__, ch, chInfo->rxCurrBuff);
774
775 /* Set RX buff address (must be 32 byte aligned) */
776 MV_REG_WRITE(CH_RX_ADDR_REG(chInfo->ch), chInfo->rxBuffPhys[chInfo->rxCurrBuff]);
777
778 /* Set HW ownership */
779 MV_REG_BYTE_WRITE(CH_BUFF_OWN_REG(chInfo->ch) + RX_OWN_BYTE_OFFS, OWN_BY_HW);
780
781 /* Enable Rx */
782 MV_REG_BYTE_WRITE(CH_ENABLE_REG(chInfo->ch) + RX_ENABLE_BYTE_OFFS, CH_ENABLE);
783
784 MV_TRC_REC("<-%s\n", __func__);
785
786 /* Did we get the required amount of irqs for Rx wakeup ? */
787 if (rxInt < MV_TDM_INT_COUNTER) {
788 return MV_NOT_READY;
789 } else {
790 rxInt = 0;
791 rxFull = MV_TDM_PREV_BUFFER(chInfo->rxCurrBuff, 2);
792 MV_TRC_REC("buff %d is FULL for ch0\n", rxFull);
793 MV_TRC_REC("buff %d is FULL for ch1\n", rxFull);
794 return MV_OK;
795 }
796}
797
798/****************************
799** SPI Stuff **
800****************************/
801
802static MV_VOID mvTdmSetCurrentUnit(MV_32 cs)
803{
804 if (!spiMode) {
805 if (!cs)
806 MV_REG_WRITE(PCM_CTRL_REG, (MV_REG_READ(PCM_CTRL_REG) & ~CS_CTRL));
807 else
808 MV_REG_WRITE(PCM_CTRL_REG, (MV_REG_READ(PCM_CTRL_REG) | CS_CTRL));
809 } else
810 MV_REG_WRITE(PCM_CTRL_REG, (MV_REG_READ(PCM_CTRL_REG) & ~CS_CTRL));
811}
812
813static MV_VOID mvTdmDaisyChainModeSet(MV_VOID)
814{
815 mvOsPrintf("Setting Daisy Chain Mode\n");
816 while ((MV_REG_READ(SPI_CTRL_REG) & SPI_STAT_MASK) == SPI_ACTIVE)
817 continue;
818 MV_REG_WRITE(SPI_CODEC_CMD_LO_REG, (0x80 << 8) | 0);
819 MV_REG_WRITE(SPI_CODEC_CTRL_REG, TRANSFER_BYTES(2) | ENDIANESS_MSB_MODE | WR_MODE | CLK_SPEED_LO_DIV);
820 MV_REG_WRITE(SPI_CTRL_REG, MV_REG_READ(SPI_CTRL_REG) | SPI_ACTIVE);
821 /* Poll for ready indication */
822 while ((MV_REG_READ(SPI_CTRL_REG) & SPI_STAT_MASK) == SPI_ACTIVE)
823 continue;
824}
825
826MV_STATUS mvTdmSpiWrite(MV_U8 *cmdBuff, MV_U8 cmdSize, MV_U8 *dataBuff, MV_U8 dataSize, MV_U8 cs)
827{
828 MV_U32 i, val1 = 0, val2 = 0, cmd;
829
830 /*MV_TRC_REC("%s: cs = %d val1 = 0x%x val2 = 0x%x\n",__func__,cs, val1, val2); */
831
832 /* Poll for ready indication */
833 while ((MV_REG_READ(SPI_CTRL_REG) & SPI_STAT_MASK) == SPI_ACTIVE)
834 continue;
835
836 if (cmdSize > 0)
837 val1 = (MV_U32) (cmdBuff[0] & 0xff);
838
839 if (cmdSize > 1)
840 val1 |= (MV_U32) (cmdBuff[1] << 8);
841
842 if (cmdSize > 2)
843 val2 = (MV_U32) (cmdBuff[2] & 0xff);
844
845 mvTdmSetCurrentUnit(cs);
846
847 /* Prepare codec control parameters for command transmission */
848 cmd = TRANSFER_BYTES(cmdSize) | ENDIANESS_MSB_MODE | WR_MODE | CLK_SPEED_LO_DIV;
849
850 MV_REG_WRITE(SPI_CODEC_CMD_LO_REG, val1);
851 MV_REG_WRITE(SPI_CODEC_CMD_HI_REG, val2);
852 MV_REG_WRITE(SPI_CODEC_CTRL_REG, cmd);
853
854 /* Activate */
855 MV_REG_WRITE(SPI_CTRL_REG, MV_REG_READ(SPI_CTRL_REG) | SPI_ACTIVE);
856
857 /* Poll for ready indication */
858 while ((MV_REG_READ(SPI_CTRL_REG) & SPI_STAT_MASK) == SPI_ACTIVE)
859 continue;
860
861 /* Update the command to 1 data byte transfer */
862 cmd = TRANSFER_BYTES(1) | ENDIANESS_MSB_MODE | WR_MODE | CLK_SPEED_LO_DIV;
863
864 for (i = 0; i < dataSize; i++) {
865 val1 = dataBuff[i];
866
867 mvTdmSetCurrentUnit(cs);
868
869 MV_REG_WRITE(SPI_CODEC_CMD_LO_REG, val1);
870 MV_REG_WRITE(SPI_CODEC_CTRL_REG, cmd);
871
872 /* Activate */
873 MV_REG_WRITE(SPI_CTRL_REG, MV_REG_READ(SPI_CTRL_REG) | SPI_ACTIVE);
874
875 /* Poll for ready indication */
876 while ((MV_REG_READ(SPI_CTRL_REG) & SPI_STAT_MASK) == SPI_ACTIVE)
877 continue;
878 }
879
880 return MV_OK;
881}
882
883MV_STATUS mvTdmSpiRead(MV_U8 *cmdBuff, MV_U8 cmdSize, MV_U8 *dataBuff, MV_U8 dataSize, MV_U8 cs)
884{
885 MV_U32 val1 = 0, val2 = 0, cmd;
886 MV_U32 data;
887
888 /*MV_TRC_REC("%s: cs = %d val1 = 0x%x val2 = 0x%x\n",__func__,cs, val1, val2); */
889
890 if (dataSize > 2) {
891 mvOsPrintf("%s: Error, exceeded max read size(%d)\n", __func__, dataSize);
892 return MV_ERROR;
893 }
894
895 /* Poll for ready indication */
896 while ((MV_REG_READ(SPI_CTRL_REG) & SPI_STAT_MASK) == SPI_ACTIVE)
897 continue;
898
899 val1 = (MV_U32) (cmdBuff[0] & 0xff);
900
901 if (cmdSize > 1)
902 val1 |= (MV_U32) (cmdBuff[1] << 8);
903
904 if (cmdSize > 2)
905 val2 = (MV_U32) (cmdBuff[2] & 0xff);
906
907 if (cmdSize > 3)
908 val2 = (MV_U32) (cmdBuff[3] << 8);
909
910 mvTdmSetCurrentUnit(cs);
911
912 /* Prepare codec control parameters for command transmission */
913 if (dataSize == 1)
914 cmd = TRANSFER_BYTES(cmdSize) | ENDIANESS_MSB_MODE | RD_MODE | READ_1_BYTE | CLK_SPEED_LO_DIV;
915 else
916 cmd = TRANSFER_BYTES(cmdSize) | ENDIANESS_MSB_MODE | RD_MODE | READ_2_BYTE | CLK_SPEED_LO_DIV;
917
918 MV_REG_WRITE(SPI_CODEC_CMD_LO_REG, val1);
919 MV_REG_WRITE(SPI_CODEC_CMD_HI_REG, val2);
920 MV_REG_WRITE(SPI_CODEC_CTRL_REG, cmd);
921
922 /* Activate */
923 MV_REG_WRITE(SPI_CTRL_REG, MV_REG_READ(SPI_CTRL_REG) | SPI_ACTIVE);
924
925 /* Poll for ready indication */
926 while ((MV_REG_READ(SPI_CTRL_REG) & SPI_STAT_MASK) == SPI_ACTIVE)
927 continue;
928
929 /* Read the data received from codec */
930 data = MV_REG_READ(SPI_CODEC_READ_DATA_REG);
931 dataBuff[dataSize - 1] = (data & 0xff);
932
933 if (dataSize == 2)
934 dataBuff[0] = ((data & 0xff00) >> 8);
935
936 return MV_OK;
937}
938
939/******************
940** Debug Display **
941******************/
942MV_VOID mvOsRegDump(MV_U32 reg)
943{
944 mvOsPrintf("0x%05x: %08x\n", reg, MV_REG_READ(reg));
945}
946
947MV_VOID mvTdmRegsDump(MV_VOID)
948{
949 MV_U8 i;
950 MV_TDM_CH_INFO *chInfo;
951
952 mvOsPrintf("TDM Control:\n");
953 mvOsRegDump(TDM_SPI_MUX_REG);
954 mvOsRegDump(INT_RESET_SELECT_REG);
955 mvOsRegDump(INT_STATUS_MASK_REG);
956 mvOsRegDump(INT_STATUS_REG);
957 mvOsRegDump(INT_EVENT_MASK_REG);
958 mvOsRegDump(PCM_CTRL_REG);
959 mvOsRegDump(TIMESLOT_CTRL_REG);
960 mvOsRegDump(PCM_CLK_RATE_DIV_REG);
961 mvOsRegDump(FRAME_TIMESLOT_REG);
962 mvOsRegDump(DUMMY_RX_WRITE_DATA_REG);
963 mvOsRegDump(MISC_CTRL_REG);
964 mvOsPrintf("TDM Channel Control:\n");
965 for (i = 0; i < MV_TDM_TOTAL_CHANNELS; i++) {
966 mvOsRegDump(CH_DELAY_CTRL_REG(i));
967 mvOsRegDump(CH_SAMPLE_REG(i));
968 mvOsRegDump(CH_DBG_REG(i));
969 mvOsRegDump(CH_TX_CUR_ADDR_REG(i));
970 mvOsRegDump(CH_RX_CUR_ADDR_REG(i));
971 mvOsRegDump(CH_ENABLE_REG(i));
972 mvOsRegDump(CH_BUFF_OWN_REG(i));
973 mvOsRegDump(CH_TX_ADDR_REG(i));
974 mvOsRegDump(CH_RX_ADDR_REG(i));
975 }
976 mvOsPrintf("TDM interrupts:\n");
977 mvOsRegDump(INT_EVENT_MASK_REG);
978 mvOsRegDump(INT_STATUS_MASK_REG);
979 mvOsRegDump(INT_STATUS_REG);
980 for (i = 0; i < MV_TDM_TOTAL_CHANNELS; i++) {
981 mvOsPrintf("ch%d info:\n", i);
982 chInfo = tdmChInfo[i];
983 mvOsPrintf("RX buffs:\n");
984 mvOsPrintf("buff0: virt=%p phys=%p\n", chInfo->rxBuffVirt[0], (MV_U32 *) (chInfo->rxBuffPhys[0]));
985 mvOsPrintf("buff1: virt=%p phys=%p\n", chInfo->rxBuffVirt[1], (MV_U32 *) (chInfo->rxBuffPhys[1]));
986 mvOsPrintf("TX buffs:\n");
987 mvOsPrintf("buff0: virt=%p phys=%p\n", chInfo->txBuffVirt[0], (MV_U32 *) (chInfo->txBuffPhys[0]));
988 mvOsPrintf("buff1: virt=%p phys=%p\n", chInfo->txBuffVirt[1], (MV_U32 *) (chInfo->txBuffPhys[1]));
989 }
990}
991
992static MV_VOID mvTdmShowProperties(MV_VOID)
993{
994 mvOsPrintf("TDM dual channel device rev 0x%x\n", MV_REG_READ(TDM_REV_REG));
995}
996
997MV_U8 currRxSampleGet(MV_U8 ch)
998{
999 return (MV_REG_BYTE_READ(CH_DBG_REG(ch) + 1));
1000}
1001
1002MV_U8 currTxSampleGet(MV_U8 ch)
1003{
1004 return (MV_REG_BYTE_READ(CH_DBG_REG(ch) + 3));
1005}
1006
1007MV_VOID mvTdmIntEnable(MV_VOID)
1008{
1009 MV_REG_WRITE(INT_STATUS_MASK_REG, (MV_REG_READ(INT_STATUS_MASK_REG) | TDM_INT_SLIC));
1010}
1011
1012MV_VOID mvTdmIntDisable(MV_VOID)
1013{
1014 MV_U32 val = ~TDM_INT_SLIC;
1015
1016 MV_TRC_REC("->%s\n", __func__);
1017
1018 MV_REG_WRITE(INT_STATUS_MASK_REG, (MV_REG_READ(INT_STATUS_MASK_REG) & val));
1019
1020 MV_TRC_REC("<-%s\n", __func__);
1021}
John Newlin2e746432013-05-31 10:38:29 -07001022
1023MV_VOID mvTdmPcmIfReset(MV_VOID)
1024{
1025 MV_TRC_REC("->%s\n", __func__);
1026
1027 MV_REG_BIT_RESET(PCM_CTRL_REG, BIT0);
1028
1029 /* Wait a bit - might be fine tuned */
1030 mvOsDelay(10);
1031
1032 MV_REG_WRITE(TDM_MISC_REG, 0);
1033
1034 /* Wait a bit more - might be fine tuned */
1035 mvOsDelay(100);
1036
1037 MV_TRC_REC("<-%s\n", __func__);
1038}
1039
1040#ifdef MV_TDM_EXT_STATS
1041MV_VOID mvTdmExtStatsGet(MV_TDM_EXTENDED_STATS* tdmExtStats)
1042{
1043 tdmExtStats->intRxCount = intRxCount;
1044 tdmExtStats->intTxCount = intTxCount;
1045 tdmExtStats->intRx0Count = intRx0Count;
1046 tdmExtStats->intTx0Count = intTx0Count;
1047 tdmExtStats->intRx1Count = intRx1Count;
1048 tdmExtStats->intTx1Count = intTx1Count;
1049 tdmExtStats->intRx0Miss = intRx0Miss;
1050 tdmExtStats->intTx0Miss = intTx0Miss;
1051 tdmExtStats->intRx1Miss = intRx1Miss;
1052 tdmExtStats->intTx1Miss = intTx1Miss;
1053 tdmExtStats->pcmRestartCount = pcmRestartCount;
1054
1055 return;
1056}
1057#endif