Gigabeat S/i.MX31: Take care of an interrupt priority inversion that can happen durin...
[kugel-rb.git] / firmware / target / arm / imx31 / gigabeat-s / pcm-gigabeat-s.c
blobc8c1283d12b8a91bc00ec741d8b22cf8de7e0395
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdlib.h>
22 #include "system.h"
23 #include "kernel.h"
24 #include "audio.h"
25 #include "sound.h"
26 #include "ccm-imx31.h"
27 #include "sdma-imx31.h"
28 #include "mmu-imx31.h"
30 #define DMA_PLAY_CH_NUM 2
31 #define DMA_REC_CH_NUM 1
32 #define DMA_PLAY_CH_PRIORITY 6
33 #define DMA_REC_CH_PRIORITY 6
35 static struct buffer_descriptor dma_play_bd NOCACHEBSS_ATTR;
37 static void play_dma_callback(void);
38 static struct channel_descriptor dma_play_cd =
40 .bd_count = 1,
41 .callback = play_dma_callback,
42 .shp_addr = SDMA_PER_ADDR_SSI2_TX1,
43 .wml = SDMA_SSI_TXFIFO_WML*2,
44 .per_type = SDMA_PER_SSI_SHP, /* SSI2 shared with SDMA core */
45 .tran_type = SDMA_TRAN_EMI_2_PER,
46 .event_id1 = SDMA_REQ_SSI2_TX1,
49 /* The pcm locking relies on the fact the interrupt handlers run to completion
50 * before lower-priority modes proceed. We don't have to touch hardware
51 * registers. Disabling SDMA interrupt would disable DMA callbacks systemwide
52 * and that is not something that is desireable.
54 * Lock explanation [++.locked]:
55 * Trivial, just increment .locked.
57 * Unlock explanation [if (--.locked == 0 && .state != 0)]:
58 * If int occurred and saw .locked as nonzero, we'll get a pending
59 * and it will have taken no action other than to set the flag to the
60 * value of .state. If it saw zero for .locked, it will have proceeded
61 * normally into the pcm callbacks. If cb set the pending flag, it has
62 * to be called to kickstart the callback mechanism and DMA. If the unlock
63 * came after a stop, we won't be in the block and DMA will be off. If
64 * we're still doing transfers, cb will see 0 for .locked and if pending,
65 * it won't be called by DMA again. */
66 struct dma_data
68 int locked;
69 int callback_pending; /* DMA interrupt happened while locked */
70 int state;
73 static struct dma_data dma_play_data =
75 /* Initialize to an unlocked, stopped state */
76 .locked = 0,
77 .callback_pending = 0,
78 .state = 0
81 static void play_dma_callback(void)
83 void *start;
84 size_t size;
85 bool rror;
87 if (dma_play_data.locked != 0)
89 /* Callback is locked out */
90 dma_play_data.callback_pending = dma_play_data.state;
91 return;
94 rror = dma_play_bd.mode.status & BD_RROR;
96 pcm_play_get_more_callback(rror ? NULL : &start, &size);
98 if (size == 0)
99 return;
101 /* Flush any pending cache writes */
102 clean_dcache_range(start, size);
103 dma_play_bd.buf_addr = (void *)addr_virt_to_phys((unsigned long)start);
104 dma_play_bd.mode.count = size;
105 dma_play_bd.mode.command = TRANSFER_16BIT;
106 dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
107 sdma_channel_run(DMA_PLAY_CH_NUM);
110 void pcm_play_lock(void)
112 /* Need to prevent DVFS from causing interrupt priority inversion if audio
113 * is locked and a DVFS interrupt fires, blocking reenabling of audio by a
114 * low-priority mode for at least the duration of the lengthy DVFS routine.
115 * Not really an issue with state changes but lockout when playing.
117 * Keep direct use of DVFS code away from here though. This could provide
118 * more services in the future anyway. */
119 kernel_audio_locking(true);
120 ++dma_play_data.locked;
123 void pcm_play_unlock(void)
125 if (--dma_play_data.locked == 0)
127 if (dma_play_data.state != 0)
129 int oldstatus = disable_irq_save();
130 int pending = dma_play_data.callback_pending;
131 dma_play_data.callback_pending = 0;
132 restore_irq(oldstatus);
134 if (pending != 0)
135 play_dma_callback();
138 kernel_audio_locking(false);
142 void pcm_dma_apply_settings(void)
144 audiohw_set_frequency(pcm_fsel);
147 void pcm_play_dma_init(void)
149 /* Init channel information */
150 sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd);
151 sdma_channel_set_priority(DMA_PLAY_CH_NUM, DMA_PLAY_CH_PRIORITY);
153 ccm_module_clock_gating(CG_SSI1, CGM_ON_RUN_WAIT);
154 ccm_module_clock_gating(CG_SSI2, CGM_ON_RUN_WAIT);
156 /* Reset & disable SSIs */
157 SSI_SCR1 &= ~SSI_SCR_SSIEN;
158 SSI_SCR2 &= ~SSI_SCR_SSIEN;
160 SSI_SIER1 = 0;
161 SSI_SIER2 = 0;
163 /* Set up audio mux */
165 /* Port 2 (internally connected to SSI2)
166 * All clocking is output sourced from port 4 */
167 AUDMUX_PTCR2 = AUDMUX_PTCR_TFS_DIR | AUDMUX_PTCR_TFSEL_PORT4 |
168 AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT4 |
169 AUDMUX_PTCR_SYN;
171 /* Receive data from port 4 */
172 AUDMUX_PDCR2 = AUDMUX_PDCR_RXDSEL_PORT4;
173 /* All clock lines are inputs sourced from the master mode codec and
174 * sent back to SSI2 through port 2 */
175 AUDMUX_PTCR4 = AUDMUX_PTCR_SYN;
177 /* Receive data from port 2 */
178 AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT2;
180 /* PORT1 (internally connected to SSI1) routes clocking to PORT5 to
181 * provide MCLK to the codec */
182 /* TX clocks are inputs taken from SSI2 */
183 /* RX clocks are outputs taken from PORT4 */
184 AUDMUX_PTCR1 = AUDMUX_PTCR_RFS_DIR | AUDMUX_PTCR_RFSSEL_PORT4 |
185 AUDMUX_PTCR_RCLKDIR | AUDMUX_PTCR_RCSEL_PORT4;
186 /* RX data taken from PORT4 */
187 AUDMUX_PDCR1 = AUDMUX_PDCR_RXDSEL_PORT4;
189 /* PORT5 outputs TCLK sourced from PORT1 (SSI1) */
190 AUDMUX_PTCR5 = AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT1;
191 AUDMUX_PDCR5 = 0;
193 /* Setup SSIs */
195 /* SSI2 - SoC software interface for all I2S data out */
196 SSI_SCR2 = SSI_SCR_SYN | SSI_SCR_I2S_MODE_SLAVE;
197 SSI_STCR2 = SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
198 SSI_STCR_TEFS | SSI_STCR_TFEN0;
200 /* 16 bits per word, 2 words per frame */
201 SSI_STCCR2 = SSI_STRCCR_WL16 | ((2-1) << SSI_STRCCR_DC_POS) |
202 ((4-1) << SSI_STRCCR_PM_POS);
204 /* Transmit low watermark */
205 SSI_SFCSR2 = (SSI_SFCSR2 & ~SSI_SFCSR_TFWM0) |
206 ((8-SDMA_SSI_TXFIFO_WML) << SSI_SFCSR_TFWM0_POS);
207 SSI_STMSK2 = 0;
209 /* SSI1 - provides MCLK to codec. Receives data from codec. */
210 SSI_STCR1 = SSI_STCR_TXDIR;
212 /* f(INT_BIT_CLK) =
213 * f(SYS_CLK) / [(DIV2 + 1)*(7*PSR + 1)*(PM + 1)*2] =
214 * 677737600 / [(1 + 1)*(7*0 + 1)*(0 + 1)*2] =
215 * 677737600 / 4 = 169344000 Hz
217 * 45.4.2.2 DIV2, PSR, and PM Bit Description states:
218 * Bits DIV2, PSR, and PM should not be all set to zero at the same
219 * time.
221 * The hardware seems to force a divide by 4 even if all bits are
222 * zero but comply by setting DIV2 and the others to zero.
224 SSI_STCCR1 = SSI_STRCCR_DIV2 | ((1-1) << SSI_STRCCR_PM_POS);
226 /* SSI1 - receive - asynchronous clocks */
227 SSI_SCR1 = SSI_SCR_I2S_MODE_SLAVE;
229 SSI_SRCR1 = SSI_SRCR_RXBIT0 | SSI_SRCR_RSCKP | SSI_SRCR_RFSI |
230 SSI_SRCR_REFS;
232 /* 16 bits per word, 2 words per frame */
233 SSI_SRCCR1 = SSI_STRCCR_WL16 | ((2-1) << SSI_STRCCR_DC_POS) |
234 ((4-1) << SSI_STRCCR_PM_POS);
236 /* Receive high watermark */
237 SSI_SFCSR1 = (SSI_SFCSR1 & ~SSI_SFCSR_RFWM0) |
238 (SDMA_SSI_RXFIFO_WML << SSI_SFCSR_RFWM0_POS);
239 SSI_SRMSK1 = 0;
241 /* Enable SSI1 (codec clock) */
242 SSI_SCR1 |= SSI_SCR_SSIEN;
244 audiohw_init();
247 void pcm_postinit(void)
249 audiohw_postinit();
252 static void play_start_pcm(void)
254 /* Stop transmission (if in progress) */
255 SSI_SCR2 &= ~SSI_SCR_TE;
257 SSI_SCR2 |= SSI_SCR_SSIEN; /* Enable SSI */
258 SSI_STCR2 |= SSI_STCR_TFEN0; /* Enable TX FIFO */
260 dma_play_data.state = 1; /* Check callback on unlock */
262 /* Do prefill to prevent swapped channels (see TLSbo61214 in MCIMX31CE).
263 * No actual solution was offered but this appears to work. */
264 SSI_STX0_2 = 0;
265 SSI_STX0_2 = 0;
266 SSI_STX0_2 = 0;
267 SSI_STX0_2 = 0;
269 SSI_SIER2 |= SSI_SIER_TDMAE; /* Enable DMA req. */
270 SSI_SCR2 |= SSI_SCR_TE; /* Start transmitting */
273 static void play_stop_pcm(void)
275 SSI_SIER2 &= ~SSI_SIER_TDMAE; /* Disable DMA req. */
277 /* Set state before pending to prevent race with interrupt */
278 dma_play_data.state = 0;
280 /* Wait for FIFO to empty */
281 while (SSI_SFCSR_TFCNT0 & SSI_SFCSR2);
283 SSI_STCR2 &= ~SSI_STCR_TFEN0; /* Disable TX */
284 SSI_SCR2 &= ~(SSI_SCR_TE | SSI_SCR_SSIEN); /* Disable transmission, SSI */
286 if (pcm_playing)
288 /* Stopping: clear buffer info to ensure 0-size readbacks when
289 * stopped */
290 unsigned long dsa = 0;
291 dma_play_bd.buf_addr = NULL;
292 dma_play_bd.mode.count = 0;
293 clean_dcache_range(&dsa, sizeof(dsa));
294 sdma_write_words(&dsa, CHANNEL_CONTEXT_ADDR(DMA_PLAY_CH_NUM)+0x0b, 1);
297 /* Clear any pending callback */
298 dma_play_data.callback_pending = 0;
301 void pcm_play_dma_start(const void *addr, size_t size)
303 sdma_channel_stop(DMA_PLAY_CH_NUM);
305 /* Disable transmission */
306 SSI_STCR2 &= ~SSI_STCR_TFEN0;
307 SSI_SCR2 &= ~(SSI_SCR_TE | SSI_SCR_SSIEN);
309 if (!sdma_channel_reset(DMA_PLAY_CH_NUM))
310 return;
312 clean_dcache_range(addr, size);
313 dma_play_bd.buf_addr =
314 (void *)addr_virt_to_phys((unsigned long)(void *)addr);
315 dma_play_bd.mode.count = size;
316 dma_play_bd.mode.command = TRANSFER_16BIT;
317 dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
319 play_start_pcm();
320 sdma_channel_run(DMA_PLAY_CH_NUM);
323 void pcm_play_dma_stop(void)
325 sdma_channel_stop(DMA_PLAY_CH_NUM);
326 play_stop_pcm();
329 void pcm_play_dma_pause(bool pause)
331 if (pause)
333 sdma_channel_pause(DMA_PLAY_CH_NUM);
334 play_stop_pcm();
336 else
338 play_start_pcm();
339 sdma_channel_run(DMA_PLAY_CH_NUM);
343 /* Return the number of bytes waiting - full L-R sample pairs only */
344 size_t pcm_get_bytes_waiting(void)
346 static unsigned long dsa NOCACHEBSS_ATTR;
347 long offs, size;
348 int oldstatus;
350 /* read burst dma source address register in channel context */
351 sdma_read_words(&dsa, CHANNEL_CONTEXT_ADDR(DMA_PLAY_CH_NUM)+0x0b, 1);
353 oldstatus = disable_irq_save();
354 offs = dsa - (unsigned long)dma_play_bd.buf_addr;
355 size = dma_play_bd.mode.count;
356 restore_irq(oldstatus);
358 /* Be addresses are coherent (no buffer change during read) */
359 if (offs >= 0 && offs < size)
361 return (size - offs) & ~3;
364 return 0;
367 /* Return a pointer to the samples and the number of them in *count */
368 const void * pcm_play_dma_get_peak_buffer(int *count)
370 static unsigned long dsa NOCACHEBSS_ATTR;
371 unsigned long addr;
372 long offs, size;
373 int oldstatus;
375 /* read burst dma source address register in channel context */
376 sdma_read_words(&dsa, CHANNEL_CONTEXT_ADDR(DMA_PLAY_CH_NUM)+0x0b, 1);
378 oldstatus = disable_irq_save();
379 addr = dsa;
380 offs = addr - (unsigned long)dma_play_bd.buf_addr;
381 size = dma_play_bd.mode.count;
382 restore_irq(oldstatus);
384 /* Be addresses are coherent (no buffer change during read) */
385 if (offs >= 0 && offs < size)
387 *count = (size - offs) >> 2;
388 return (void *)((addr + 2) & ~3);
391 *count = 0;
392 return NULL;
395 void * pcm_dma_addr(void *addr)
397 return (void *)addr_virt_to_phys((unsigned long)addr);
400 #ifdef HAVE_RECORDING
401 static struct buffer_descriptor dma_rec_bd NOCACHEBSS_ATTR;
403 static void rec_dma_callback(void);
404 static struct channel_descriptor dma_rec_cd =
406 .bd_count = 1,
407 .callback = rec_dma_callback,
408 .shp_addr = SDMA_PER_ADDR_SSI1_RX1,
409 .wml = SDMA_SSI_RXFIFO_WML*2,
410 .per_type = SDMA_PER_SSI,
411 .tran_type = SDMA_TRAN_PER_2_EMI,
412 .event_id1 = SDMA_REQ_SSI1_RX1,
415 static struct dma_data dma_rec_data =
417 /* Initialize to an unlocked, stopped state */
418 .locked = 0,
419 .callback_pending = 0,
420 .state = 0
423 static void rec_dma_callback(void)
425 int status = 0;
426 void *start;
427 size_t size;
429 if (dma_rec_data.locked != 0)
431 dma_rec_data.callback_pending = dma_rec_data.state;
432 return; /* Callback is locked out */
435 if (dma_rec_bd.mode.status & BD_RROR)
436 status = DMA_REC_ERROR_DMA;
438 pcm_rec_more_ready_callback(status, &start, &size);
440 if (size == 0)
441 return;
443 /* Invalidate - buffer must be coherent */
444 dump_dcache_range(start, size);
446 start = (void *)addr_virt_to_phys((unsigned long)start);
448 dma_rec_bd.buf_addr = start;
449 dma_rec_bd.mode.count = size;
450 dma_rec_bd.mode.command = TRANSFER_16BIT;
451 dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
453 sdma_channel_run(DMA_REC_CH_NUM);
456 void pcm_rec_lock(void)
458 kernel_audio_locking(true);
459 ++dma_rec_data.locked;
462 void pcm_rec_unlock(void)
464 if (--dma_rec_data.locked == 0)
466 if (dma_rec_data.state != 0)
468 int oldstatus = disable_irq_save();
469 int pending = dma_rec_data.callback_pending;
470 dma_rec_data.callback_pending = 0;
471 restore_irq(oldstatus);
473 if (pending != 0)
474 rec_dma_callback();
477 kernel_audio_locking(false);
481 void pcm_rec_dma_stop(void)
483 SSI_SIER1 &= ~SSI_SIER_RDMAE; /* Disable DMA req. */
485 /* Set state before pending to prevent race with interrupt */
486 dma_rec_data.state = 0;
488 /* Stop receiving data */
489 sdma_channel_stop(DMA_REC_CH_NUM);
491 bitclr32(&SSI_SIER1, SSI_SIER_RDMAE);
493 SSI_SCR1 &= ~SSI_SCR_RE; /* Disable RX */
494 SSI_SRCR1 &= ~SSI_SRCR_RFEN0; /* Disable RX FIFO */
496 if (pcm_recording)
498 /* Stopping: clear buffer info to ensure 0-size readbacks when
499 * stopped */
500 unsigned long pda = 0;
501 dma_rec_bd.buf_addr = NULL;
502 dma_rec_bd.mode.count = 0;
503 clean_dcache_range(&pda, sizeof(pda));
504 sdma_write_words(&pda, CHANNEL_CONTEXT_ADDR(DMA_REC_CH_NUM)+0x0a, 1);
507 /* Clear any pending callback */
508 dma_rec_data.callback_pending = 0;
511 void pcm_rec_dma_start(void *addr, size_t size)
513 pcm_rec_dma_stop();
515 if (!sdma_channel_reset(DMA_REC_CH_NUM))
516 return;
518 /* Invalidate - buffer must be coherent */
519 dump_dcache_range(addr, size);
521 addr = (void *)addr_virt_to_phys((unsigned long)addr);
522 dma_rec_bd.buf_addr = addr;
523 dma_rec_bd.mode.count = size;
524 dma_rec_bd.mode.command = TRANSFER_16BIT;
525 dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
527 dma_rec_data.state = 1; /* Check callback on unlock */
529 SSI_SRCR1 |= SSI_SRCR_RFEN0; /* Enable RX FIFO */
531 /* Ensure clear FIFO */
532 while (SSI_SFCSR1 & SSI_SFCSR_RFCNT0)
533 SSI_SRX0_1;
535 /* Enable receive */
536 SSI_SCR1 |= SSI_SCR_RE;
537 SSI_SIER1 |= SSI_SIER_RDMAE; /* Enable DMA req. */
539 sdma_channel_run(DMA_REC_CH_NUM);
542 void pcm_rec_dma_close(void)
544 pcm_rec_dma_stop();
545 sdma_channel_close(DMA_REC_CH_NUM);
548 void pcm_rec_dma_init(void)
550 pcm_rec_dma_stop();
552 /* Init channel information */
553 sdma_channel_init(DMA_REC_CH_NUM, &dma_rec_cd, &dma_rec_bd);
554 sdma_channel_set_priority(DMA_REC_CH_NUM, DMA_REC_CH_PRIORITY);
557 const void * pcm_rec_dma_get_peak_buffer(void)
559 static unsigned long pda NOCACHEBSS_ATTR;
560 unsigned long buf, end, bufend;
561 int oldstatus;
563 /* read burst dma destination address register in channel context */
564 sdma_read_words(&pda, CHANNEL_CONTEXT_ADDR(DMA_REC_CH_NUM)+0x0a, 1);
566 oldstatus = disable_irq_save();
567 end = pda;
568 buf = (unsigned long)dma_rec_bd.buf_addr;
569 bufend = buf + dma_rec_bd.mode.count;
570 restore_irq(oldstatus);
572 /* Be addresses are coherent (no buffer change during read) */
573 if (end >= buf && end < bufend)
574 return (void *)(end & ~3);
576 return NULL;
579 #endif /* HAVE_RECORDING */