blob: 2e2312f7aef3a0767c16f3b576dbc04c038ae22b [file] [log] [blame]
Michael Sevakis5efee7c2006-11-06 18:18:05 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Michael Sevakis
Michael Sevakisca5ca5b2009-02-12 21:32:14 +000011 * Copyright (C) 2005 by Linus Nielsen Feltzing
Michael Sevakis5efee7c2006-11-06 18:18:05 +000012 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000013 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
Michael Sevakis5efee7c2006-11-06 18:18:05 +000017 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdlib.h>
23#include "system.h"
24#include "kernel.h"
25#include "logf.h"
26#include "audio.h"
Michael Sevakisc2d21062007-03-11 06:21:43 +000027#include "sound.h"
Michael Sevakis8f659ae2007-05-20 20:26:36 +000028#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
Michael Sevakiscc50c142006-11-13 23:21:54 +000029#include "spdif.h"
30#endif
Michael Sevakisa2b67032011-06-29 06:37:04 +000031#include "pcm-internal.h"
Michael Sevakis5efee7c2006-11-06 18:18:05 +000032
Michael Sevakisca5ca5b2009-02-12 21:32:14 +000033#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
34 (IIS_PLAY & (7 << 8)) | \
35 (4 << 2) ) /* 64 bit clocks / word clock */
36#define IIS_FIFO_RESET (1 << 11)
37#define PDIR2_FIFO_RESET (1 << 9)
Michael Sevakis5efee7c2006-11-06 18:18:05 +000038
Jens Arnold3005cf52008-03-15 21:55:14 +000039#if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3)
Michael Sevakisca5ca5b2009-02-12 21:32:14 +000040#define IIS_PLAY IIS1CONFIG
Michael Sevakis8867d002007-03-05 08:14:27 +000041#else
Michael Sevakisca5ca5b2009-02-12 21:32:14 +000042#define IIS_PLAY IIS2CONFIG
Michael Sevakis8867d002007-03-05 08:14:27 +000043#endif
44
Michael Sevakisca5ca5b2009-02-12 21:32:14 +000045#ifdef HAVE_SPDIF_OUT
46/* EBU TX auto sync, PDIR2 fifo auto sync, IIS1 fifo auto sync */
47#define AUDIOGLOB_DEFPARM ((1 << 10) | (1 << 8) | (1 << 7))
48#else
49/* PDIR2 fifo auto sync, IIS1 fifo auto sync */
50#define AUDIOGLOB_DEFPARM ((1 << 8) | (1 << 7))
51#endif
Michael Sevakis6077e5b2007-10-06 22:27:27 +000052
Michael Sevakisca5ca5b2009-02-12 21:32:14 +000053/** Sample rates **/
Michael Sevakis5efee7c2006-11-06 18:18:05 +000054#define PLLCR_SET_AUDIO_BITS_DEFPARM \
55 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
Michael Sevakis5efee7c2006-11-06 18:18:05 +000056
Michael Sevakis5efee7c2006-11-06 18:18:05 +000057#define FPARM_CLOCKSEL 0
58#define FPARM_CLSEL 1
Marcin Bukatb09d3ae2010-04-26 21:40:00 +000059
60/* SCLK = Fs * bit clocks per word
61 * so SCLK should be Fs * 64
62 *
63 * CLOCKSEL sets SCLK freq based on Audio CLK
64 * 0x0c SCLK = Audio CLK/2 88200 * 64 = 5644800 Hz
65 * 0x06 SCLK = Audio CLK/4 44100 * 64 = 2822400 Hz
66 * 0x04 SCLK = Audio CLK/8 22050 * 64 = 1411200 Hz
67 * 0x02 SCLK = Audio CLK/16 11025 * 64 = 705600 Hz
68 *
69 * CLSEL sets MCLK1/2 DAC freq based on XTAL freq
70 * 0x01 MCLK1/2 = XTAL freq
71 * 0x02 MCLK1/2 = XTAL/2 freq
72 *
73 * Audio CLK can be XTAL freq or XTAL/2 freq (bit22 in PLLCR)
74 * we always set bit22 so Audio CLK is always XTAL freq
75 */
76
Michael Sevakis5efee7c2006-11-06 18:18:05 +000077#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
Michael Sevakise69d5672008-12-12 11:01:07 +000078static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] =
Michael Sevakis5efee7c2006-11-06 18:18:05 +000079{
Michael Sevakise69d5672008-12-12 11:01:07 +000080 [HW_FREQ_88] = { 0x0c, 0x01 },
81 [HW_FREQ_44] = { 0x06, 0x01 },
82 [HW_FREQ_22] = { 0x04, 0x02 },
83 [HW_FREQ_11] = { 0x02, 0x02 },
Michael Sevakis5efee7c2006-11-06 18:18:05 +000084};
85#endif
86
Marcin Bukatb09d3ae2010-04-26 21:40:00 +000087#if CONFIG_CPU == MCF5249 && defined(HAVE_WM8750)
Marcin Bukat971a6e92010-07-02 21:09:28 +000088/* We run codec in master mode.
89 * Codec can reconstruct all frequencies
90 * from single 11.2896 MHz master clock
91 */
Marcin Bukatb09d3ae2010-04-26 21:40:00 +000092static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] =
93{
Marcin Bukat971a6e92010-07-02 21:09:28 +000094 [HW_FREQ_88] = { 0x00, 0x01 },
95 [HW_FREQ_44] = { 0x00, 0x01 },
96 [HW_FREQ_22] = { 0x00, 0x01 },
97 [HW_FREQ_11] = { 0x00, 0x01 },
Marcin Bukatb09d3ae2010-04-26 21:40:00 +000098};
Marcin Bukat971a6e92010-07-02 21:09:28 +000099
Marcin Bukatb09d3ae2010-04-26 21:40:00 +0000100#endif
101
Jens Arnold8a6291d2008-03-14 08:54:54 +0000102#if (CONFIG_CPU == MCF5250 || CONFIG_CPU == MCF5249) && defined(HAVE_TLV320)
Michael Sevakise69d5672008-12-12 11:01:07 +0000103static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] =
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000104{
Michael Sevakise69d5672008-12-12 11:01:07 +0000105 [HW_FREQ_88] = { 0x0c, 0x01 },
106 [HW_FREQ_44] = { 0x06, 0x01 },
107 [HW_FREQ_22] = { 0x04, 0x01 },
108 [HW_FREQ_11] = { 0x02, 0x02 },
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000109};
110#endif
111
Michael Sevakise69d5672008-12-12 11:01:07 +0000112static const unsigned char *freq_ent;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000113
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000114/* Lock status struct for playback and recording */
115struct dma_lock
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000116{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000117 int locked;
118 unsigned long state;
119};
Michael Sevakise69d5672008-12-12 11:01:07 +0000120
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000121static void iis_play_reset(void)
122{
123 or_l(IIS_FIFO_RESET, &IIS_PLAY);
124 and_l(~IIS_FIFO_RESET, &IIS_PLAY);
125 PDOR3 = 0;
126}
127
128static bool is_playback_monitoring(void)
129{
130 return (IIS_PLAY & (7 << 8)) == (3 << 8);
131}
132
133static void iis_play_reset_if_playback(bool if_playback)
134{
Michael Sevakise69d5672008-12-12 11:01:07 +0000135 int level = set_irq_level(DMA_IRQ_LEVEL);
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000136 if (is_playback_monitoring() == if_playback)
137 iis_play_reset();
Michael Sevakise69d5672008-12-12 11:01:07 +0000138 restore_irq(level);
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000139}
Michael Sevakise69d5672008-12-12 11:01:07 +0000140
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000141/* apply audio settings */
Michael Sevakis633f3882007-03-07 06:23:02 +0000142/* This clears the reset bit to enable monitoring immediately if monitoring
143 recording sources or always if playback is in progress - we might be
144 switching samplerates on the fly */
Michael Sevakise69d5672008-12-12 11:01:07 +0000145void pcm_dma_apply_settings(void)
Michael Sevakis8867d002007-03-05 08:14:27 +0000146{
Michael Sevakis633f3882007-03-07 06:23:02 +0000147 int level = set_irq_level(DMA_IRQ_LEVEL);
Michael Sevakis633f3882007-03-07 06:23:02 +0000148
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000149 /* remember table entry */
150 freq_ent = pcm_freq_parms[pcm_fsel];
151
152 /* Reprogramming bits 15-12 requires FIFO to be in a reset
153 condition - Users Manual 17-8, Note 11 */
154 or_l(IIS_FIFO_RESET, &IIS_PLAY);
155 /* Important for TLV320 - this must happen in the correct order
156 or starting recording will sound absolutely awful once in
157 awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
158 */
159 IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
160 restore_irq(level);
161
162 audiohw_set_frequency(pcm_fsel);
163 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
164
165 level = set_irq_level(DMA_IRQ_LEVEL);
166
167 IIS_PLAY = IIS_PLAY_DEFPARM;
168
169 if ((DCR0 & DMA_EEXT) != 0 && is_playback_monitoring())
Michael Sevakis633f3882007-03-07 06:23:02 +0000170 PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
171
Michael Sevakisaf395f42008-03-26 01:50:41 +0000172 restore_irq(level);
Michael Sevakise69d5672008-12-12 11:01:07 +0000173} /* pcm_dma_apply_settings */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000174
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000175void pcm_play_dma_init(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000176{
Michael Sevakise69d5672008-12-12 11:01:07 +0000177 freq_ent = pcm_freq_parms[pcm_fsel];
178
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000179 AUDIOGLOB = AUDIOGLOB_DEFPARM;
180 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
Michael Sevakis8867d002007-03-05 08:14:27 +0000181 and_l(0xffffff00, &DMAROUTE);
182 or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000183 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
184 BCR0 = 0; /* No bytes waiting */
185 ICR6 = (6 << 2); /* Enable interrupt at level 6, priority 0 */
Michael Sevakis5d637762007-03-11 05:04:48 +0000186
Michael Sevakisabf41e32007-03-13 15:05:46 +0000187 /* Setup Coldfire I2S before initializing hardware or changing
188 other settings. */
189 or_l(IIS_FIFO_RESET, &IIS_PLAY);
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000190 IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
Michael Sevakisabf41e32007-03-13 15:05:46 +0000191 audio_set_output_source(AUDIO_SRC_PLAYBACK);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000192
Michael Sevakis5d637762007-03-11 05:04:48 +0000193 /* Initialize default register values. */
194 audiohw_init();
195
Michael Sevakis2d48d0f2007-06-08 23:42:04 +0000196 audio_input_mux(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000197
Michael Sevakise69d5672008-12-12 11:01:07 +0000198 audiohw_set_frequency(pcm_fsel);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000199 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000200
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000201#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
Michael Sevakiscc50c142006-11-13 23:21:54 +0000202 spdif_init();
203#endif
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000204} /* pcm_play_dma_init */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000205
Michael Sevakis4db3e892011-09-01 12:15:43 +0000206void pcm_play_dma_postinit(void)
Michael Sevakisc2d21062007-03-11 06:21:43 +0000207{
208 audiohw_postinit();
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000209 iis_play_reset();
Michael Sevakisc2d21062007-03-11 06:21:43 +0000210}
211
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000212/** DMA **/
213
214/****************************************************************************
215 ** Playback DMA transfer
216 **/
217/* For the locks, DMA interrupt must be disabled when manipulating the lock
218 if the handler ever calls these - right now things are arranged so it
219 doesn't */
220static struct dma_lock dma_play_lock =
221{
222 .locked = 0,
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000223 .state = (1 << 14) /* bit 14 is DMA0 */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000224};
225
226void pcm_play_lock(void)
227{
228 if (++dma_play_lock.locked == 1)
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000229 coldfire_imr_mod(1 << 14, 1 << 14);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000230}
231
232void pcm_play_unlock(void)
233{
234 if (--dma_play_lock.locked == 0)
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000235 coldfire_imr_mod(dma_play_lock.state, 1 << 14);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000236}
237
238/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
239void pcm_play_dma_start(const void *addr, size_t size)
240{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000241 /* Stop any DMA in progress */
242 pcm_play_dma_stop();
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000243
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000244 /* Set up DMA transfer */
245 SAR0 = (unsigned long)addr; /* Source address */
246 DAR0 = (unsigned long)&PDOR3; /* Destination address */
247 BCR0 = (unsigned long)size; /* Bytes to transfer */
248
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000249 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC |
250 DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000251
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000252 dma_play_lock.state = (0 << 14);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000253} /* pcm_play_dma_start */
254
255/* Stops the DMA transfer and interrupt */
256void pcm_play_dma_stop(void)
257{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000258 and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
259 BCR0 = 0; /* No bytes remaining */
260 DSR0 = 1; /* Clear interrupt, errors, stop transfer */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000261
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000262 iis_play_reset_if_playback(true);
263
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000264 dma_play_lock.state = (1 << 14);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000265} /* pcm_play_dma_stop */
266
267void pcm_play_dma_pause(bool pause)
268{
269 if (pause)
270 {
271 /* pause playback on current buffer */
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000272 and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
273 DSR0 = 1; /* stop channel */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000274 iis_play_reset_if_playback(true);
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000275 dma_play_lock.state = (1 << 14);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000276 }
277 else
278 {
279 /* restart playback on current buffer */
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000280 iis_play_reset_if_playback(true);
281 or_l(DMA_INT | DMA_EEXT | DMA_START, &DCR0); /* everything ON */
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000282 dma_play_lock.state = (0 << 14);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000283 }
284} /* pcm_play_dma_pause */
285
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000286size_t pcm_get_bytes_waiting(void)
287{
288 return BCR0 & 0xffffff;
289} /* pcm_get_bytes_waiting */
290
291/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
292 from the caller's buffer */
293void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
294void DMA0(void)
295{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000296 unsigned long res = DSR0;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000297
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000298 and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
299 DSR0 = 1; /* Clear interrupt and errors */
300
301 if (res & 0x70)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000302 {
Michael Sevakis8867d002007-03-05 08:14:27 +0000303 logf("DMA0 err: %02x", res);
304#if 0
305 logf(" SAR0: %08x", SAR0);
306 logf(" DAR0: %08x", DAR0);
307 logf(" BCR0: %08x", BCR0);
308 logf(" DCR0: %08x", DCR0);
309#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000310 }
Michael Sevakisd5699982010-05-24 16:42:32 +0000311
Michael Sevakis286a4c52012-02-23 08:14:46 -0500312 const void *addr;
313 size_t size;
Michael Sevakisd5699982010-05-24 16:42:32 +0000314
Michael Sevakis286a4c52012-02-23 08:14:46 -0500315 if (pcm_play_dma_complete_callback((res & 0x70) ?
316 PCM_DMAST_ERR_DMA : PCM_DMAST_OK,
317 &addr, &size))
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000318 {
Michael Sevakis286a4c52012-02-23 08:14:46 -0500319 SAR0 = (unsigned long)addr; /* Source address */
320 BCR0 = (unsigned long)size; /* Bytes to transfer */
Michael Sevakisd5699982010-05-24 16:42:32 +0000321 or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */
Michael Sevakisa2b67032011-06-29 06:37:04 +0000322
Michael Sevakis286a4c52012-02-23 08:14:46 -0500323 pcm_play_dma_status_callback(PCM_DMAST_STARTED);
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000324 }
Michael Sevakisd5699982010-05-24 16:42:32 +0000325 /* else inished playing */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000326} /* DMA0 */
327
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000328const void * pcm_play_dma_get_peak_buffer(int *count)
329{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000330 unsigned long addr, cnt;
331
332 /* Make sure interrupt doesn't change the second value after we read the
333 * first value. */
334 int level = set_irq_level(DMA_IRQ_LEVEL);
335 addr = SAR0;
336 cnt = BCR0;
337 restore_irq(level);
338
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000339 *count = (cnt & 0xffffff) >> 2;
340 return (void *)((addr + 2) & ~3);
341} /* pcm_play_dma_get_peak_buffer */
342
Marcin Bukatb09d3ae2010-04-26 21:40:00 +0000343#ifdef HAVE_RECORDING
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000344/****************************************************************************
345 ** Recording DMA transfer
346 **/
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000347static struct dma_lock dma_rec_lock =
348{
349 .locked = 0,
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000350 .state = (1 << 15) /* bit 15 is DMA1 */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000351};
352
353/* For the locks, DMA interrupt must be disabled when manipulating the lock
354 if the handler ever calls these - right now things are arranged so it
355 doesn't */
356void pcm_rec_lock(void)
357{
358 if (++dma_rec_lock.locked == 1)
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000359 coldfire_imr_mod(1 << 15, 1 << 15);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000360}
361
362void pcm_rec_unlock(void)
363{
364 if (--dma_rec_lock.locked == 0)
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000365 coldfire_imr_mod(dma_rec_lock.state, 1 << 15);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000366}
367
Michael Sevakis51189b42006-12-06 08:34:55 +0000368void pcm_rec_dma_start(void *addr, size_t size)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000369{
Michael Sevakis286a4c52012-02-23 08:14:46 -0500370 /* Stop any DMA in progress */
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000371 pcm_rec_dma_stop();
372
Michael Sevakis8867d002007-03-05 08:14:27 +0000373 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000374
375 /* Start the DMA transfer.. */
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000376#ifdef HAVE_SPDIF_REC
Michael Sevakis521d6a52007-04-18 02:07:56 +0000377 /* clear: ebu1cnew, valnogood, symbolerr, parityerr */
378 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000379#endif
380
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000381 SAR1 = (unsigned long)&PDIR2; /* Source address */
382 DAR1 = (unsigned long)addr; /* Destination address */
383 BCR1 = (unsigned long)size; /* Bytes to transfer */
Michael Sevakis51189b42006-12-06 08:34:55 +0000384
Michael Sevakisf51df0d2006-12-12 04:25:52 +0000385 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000386 DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
Michael Sevakis633f3882007-03-07 06:23:02 +0000387
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000388 dma_rec_lock.state = (0 << 15);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000389} /* pcm_rec_dma_start */
Michael Sevakis633f3882007-03-07 06:23:02 +0000390
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000391void pcm_rec_dma_stop(void)
392{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000393 and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */
394 DSR1 = 1; /* Clear interrupt, errors, stop transfer */
395 BCR1 = 0; /* No bytes received */
396
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000397 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
Michael Sevakis633f3882007-03-07 06:23:02 +0000398
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000399 iis_play_reset_if_playback(false);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000400
Michael Sevakisd4800fa2011-06-17 03:09:47 +0000401 dma_rec_lock.state = (1 << 15);
Michael Sevakis633f3882007-03-07 06:23:02 +0000402} /* pcm_rec_dma_stop */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000403
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000404void pcm_rec_dma_init(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000405{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000406 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
407 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
Michael Sevakis8867d002007-03-05 08:14:27 +0000408 and_l(0xffff00ff, &DMAROUTE);
409 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000410
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000411 pcm_rec_dma_stop();
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000412
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000413 /* Enable interrupt at level 6, priority 1 */
414 ICR7 = (6 << 2) | (1 << 0);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000415} /* pcm_init_recording */
416
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000417void pcm_rec_dma_close(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000418{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000419 pcm_rec_dma_stop();
420
Michael Sevakis8867d002007-03-05 08:14:27 +0000421 and_l(0xffff00ff, &DMAROUTE);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000422 ICR7 = 0x00; /* Disable interrupt */
423 dma_rec_lock.state = (0 << 15);
424} /* pcm_rec_dma_close */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000425
426/* DMA1 Interrupt is called when the DMA has finished transfering a chunk
427 into the caller's buffer */
428void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
429void DMA1(void)
430{
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000431 unsigned long res = DSR1;
Michael Sevakis286a4c52012-02-23 08:14:46 -0500432 enum pcm_dma_status status = PCM_DMAST_OK;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000433
Michael Sevakisca5ca5b2009-02-12 21:32:14 +0000434 and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */
435 DSR1 = 1; /* Clear interrupt and errors */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000436
437 if (res & 0x70)
438 {
Michael Sevakis286a4c52012-02-23 08:14:46 -0500439 status = PCM_DMAST_ERR_DMA;
Michael Sevakis8867d002007-03-05 08:14:27 +0000440 logf("DMA1 err: %02x", res);
441#if 0
442 logf(" SAR1: %08x", SAR1);
443 logf(" DAR1: %08x", DAR1);
444 logf(" BCR1: %08x", BCR1);
445 logf(" DCR1: %08x", DCR1);
446#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000447 }
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000448#ifdef HAVE_SPDIF_REC
Michael Sevakisab1861a2006-11-23 19:21:15 +0000449 else if (DATAINCONTROL == 0xc038 &&
Jens Arnold0d491412008-08-19 23:07:54 +0000450 (INTERRUPTSTAT & ((1 << 23) | (1 << 22))))
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000451 {
Jens Arnold0d491412008-08-19 23:07:54 +0000452 /* reason: symbolerr, parityerr.
453 * Ignore valnogood since several sources don't set it properly. */
454 /* clear: ebu1cnew, symbolerr, parityerr */
455 INTERRUPTCLEAR = (1 << 25) | (1 << 23) | (1 << 22);
Michael Sevakis286a4c52012-02-23 08:14:46 -0500456 status = PCM_DMAST_ERR_SPDIF;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000457 logf("spdif err");
458 }
459#endif
460
Michael Sevakisd5699982010-05-24 16:42:32 +0000461 /* Inform PCM we have more data (or error) */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500462 void *addr;
463 size_t size;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000464
Michael Sevakis286a4c52012-02-23 08:14:46 -0500465 if (pcm_rec_dma_complete_callback(status, &addr, &size))
Michael Sevakisd5699982010-05-24 16:42:32 +0000466 {
Michael Sevakis286a4c52012-02-23 08:14:46 -0500467 DAR1 = (unsigned long)addr; /* Destination address */
Michael Sevakisd5699982010-05-24 16:42:32 +0000468 BCR1 = (unsigned long)size; /* Bytes to transfer */
469 or_l(DMA_EEXT | DMA_INT, &DCR1); /* per request and int ON */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500470
471 pcm_rec_dma_status_callback(PCM_DMAST_STARTED);
Michael Sevakisd5699982010-05-24 16:42:32 +0000472 }
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000473} /* DMA1 */
474
Michael Sevakis4d041322010-05-12 14:05:36 +0000475const void * pcm_rec_dma_get_peak_buffer(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000476{
Michael Sevakis4d041322010-05-12 14:05:36 +0000477 return (void *)(DAR1 & ~3);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000478} /* pcm_rec_dma_get_peak_buffer */
Marcin Bukatb09d3ae2010-04-26 21:40:00 +0000479#endif