Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2006 by Michael Sevakis |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 11 | * Copyright (C) 2005 by Linus Nielsen Feltzing |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 12 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame] | 13 | * 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 Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 17 | * |
| 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 Sevakis | c2d2106 | 2007-03-11 06:21:43 +0000 | [diff] [blame] | 27 | #include "sound.h" |
Michael Sevakis | 8f659ae | 2007-05-20 20:26:36 +0000 | [diff] [blame] | 28 | #if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT) |
Michael Sevakis | cc50c14 | 2006-11-13 23:21:54 +0000 | [diff] [blame] | 29 | #include "spdif.h" |
| 30 | #endif |
Michael Sevakis | a2b6703 | 2011-06-29 06:37:04 +0000 | [diff] [blame] | 31 | #include "pcm-internal.h" |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 32 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 33 | #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 Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 38 | |
Jens Arnold | 3005cf5 | 2008-03-15 21:55:14 +0000 | [diff] [blame] | 39 | #if defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3) |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 40 | #define IIS_PLAY IIS1CONFIG |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 41 | #else |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 42 | #define IIS_PLAY IIS2CONFIG |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 43 | #endif |
| 44 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 45 | #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 Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 52 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 53 | /** Sample rates **/ |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 54 | #define PLLCR_SET_AUDIO_BITS_DEFPARM \ |
| 55 | ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22)) |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 56 | |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 57 | #define FPARM_CLOCKSEL 0 |
| 58 | #define FPARM_CLSEL 1 |
Marcin Bukat | b09d3ae | 2010-04-26 21:40:00 +0000 | [diff] [blame] | 59 | |
| 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 Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 77 | #if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380) |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 78 | static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] = |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 79 | { |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 80 | [HW_FREQ_88] = { 0x0c, 0x01 }, |
| 81 | [HW_FREQ_44] = { 0x06, 0x01 }, |
| 82 | [HW_FREQ_22] = { 0x04, 0x02 }, |
| 83 | [HW_FREQ_11] = { 0x02, 0x02 }, |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 84 | }; |
| 85 | #endif |
| 86 | |
Marcin Bukat | b09d3ae | 2010-04-26 21:40:00 +0000 | [diff] [blame] | 87 | #if CONFIG_CPU == MCF5249 && defined(HAVE_WM8750) |
Marcin Bukat | 971a6e9 | 2010-07-02 21:09:28 +0000 | [diff] [blame] | 88 | /* We run codec in master mode. |
| 89 | * Codec can reconstruct all frequencies |
| 90 | * from single 11.2896 MHz master clock |
| 91 | */ |
Marcin Bukat | b09d3ae | 2010-04-26 21:40:00 +0000 | [diff] [blame] | 92 | static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] = |
| 93 | { |
Marcin Bukat | 971a6e9 | 2010-07-02 21:09:28 +0000 | [diff] [blame] | 94 | [HW_FREQ_88] = { 0x00, 0x01 }, |
| 95 | [HW_FREQ_44] = { 0x00, 0x01 }, |
| 96 | [HW_FREQ_22] = { 0x00, 0x01 }, |
| 97 | [HW_FREQ_11] = { 0x00, 0x01 }, |
Marcin Bukat | b09d3ae | 2010-04-26 21:40:00 +0000 | [diff] [blame] | 98 | }; |
Marcin Bukat | 971a6e9 | 2010-07-02 21:09:28 +0000 | [diff] [blame] | 99 | |
Marcin Bukat | b09d3ae | 2010-04-26 21:40:00 +0000 | [diff] [blame] | 100 | #endif |
| 101 | |
Jens Arnold | 8a6291d | 2008-03-14 08:54:54 +0000 | [diff] [blame] | 102 | #if (CONFIG_CPU == MCF5250 || CONFIG_CPU == MCF5249) && defined(HAVE_TLV320) |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 103 | static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] = |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 104 | { |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 105 | [HW_FREQ_88] = { 0x0c, 0x01 }, |
| 106 | [HW_FREQ_44] = { 0x06, 0x01 }, |
| 107 | [HW_FREQ_22] = { 0x04, 0x01 }, |
| 108 | [HW_FREQ_11] = { 0x02, 0x02 }, |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 109 | }; |
| 110 | #endif |
| 111 | |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 112 | static const unsigned char *freq_ent; |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 113 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 114 | /* Lock status struct for playback and recording */ |
| 115 | struct dma_lock |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 116 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 117 | int locked; |
| 118 | unsigned long state; |
| 119 | }; |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 120 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 121 | static 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 | |
| 128 | static bool is_playback_monitoring(void) |
| 129 | { |
| 130 | return (IIS_PLAY & (7 << 8)) == (3 << 8); |
| 131 | } |
| 132 | |
| 133 | static void iis_play_reset_if_playback(bool if_playback) |
| 134 | { |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 135 | int level = set_irq_level(DMA_IRQ_LEVEL); |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 136 | if (is_playback_monitoring() == if_playback) |
| 137 | iis_play_reset(); |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 138 | restore_irq(level); |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 139 | } |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 140 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 141 | /* apply audio settings */ |
Michael Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 142 | /* 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 Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 145 | void pcm_dma_apply_settings(void) |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 146 | { |
Michael Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 147 | int level = set_irq_level(DMA_IRQ_LEVEL); |
Michael Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 148 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 149 | /* 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 Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 170 | PDOR3 = 0; /* Kick FIFO out of reset by writing to it */ |
| 171 | |
Michael Sevakis | af395f4 | 2008-03-26 01:50:41 +0000 | [diff] [blame] | 172 | restore_irq(level); |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 173 | } /* pcm_dma_apply_settings */ |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 174 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 175 | void pcm_play_dma_init(void) |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 176 | { |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 177 | freq_ent = pcm_freq_parms[pcm_fsel]; |
| 178 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 179 | AUDIOGLOB = AUDIOGLOB_DEFPARM; |
| 180 | DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */ |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 181 | and_l(0xffffff00, &DMAROUTE); |
| 182 | or_l(DMA0_REQ_AUDIO_1, &DMAROUTE); |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 183 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ |
| 184 | BCR0 = 0; /* No bytes waiting */ |
| 185 | ICR6 = (6 << 2); /* Enable interrupt at level 6, priority 0 */ |
Michael Sevakis | 5d63776 | 2007-03-11 05:04:48 +0000 | [diff] [blame] | 186 | |
Michael Sevakis | abf41e3 | 2007-03-13 15:05:46 +0000 | [diff] [blame] | 187 | /* Setup Coldfire I2S before initializing hardware or changing |
| 188 | other settings. */ |
| 189 | or_l(IIS_FIFO_RESET, &IIS_PLAY); |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 190 | IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET; |
Michael Sevakis | abf41e3 | 2007-03-13 15:05:46 +0000 | [diff] [blame] | 191 | audio_set_output_source(AUDIO_SRC_PLAYBACK); |
Michael Sevakis | abf41e3 | 2007-03-13 15:05:46 +0000 | [diff] [blame] | 192 | |
Michael Sevakis | 5d63776 | 2007-03-11 05:04:48 +0000 | [diff] [blame] | 193 | /* Initialize default register values. */ |
| 194 | audiohw_init(); |
| 195 | |
Michael Sevakis | 2d48d0f | 2007-06-08 23:42:04 +0000 | [diff] [blame] | 196 | audio_input_mux(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 197 | |
Michael Sevakis | e69d567 | 2008-12-12 11:01:07 +0000 | [diff] [blame] | 198 | audiohw_set_frequency(pcm_fsel); |
Michael Sevakis | abf41e3 | 2007-03-13 15:05:46 +0000 | [diff] [blame] | 199 | coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 200 | |
Michael Sevakis | 8f659ae | 2007-05-20 20:26:36 +0000 | [diff] [blame] | 201 | #if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT) |
Michael Sevakis | cc50c14 | 2006-11-13 23:21:54 +0000 | [diff] [blame] | 202 | spdif_init(); |
| 203 | #endif |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 204 | } /* pcm_play_dma_init */ |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 205 | |
Michael Sevakis | 4db3e89 | 2011-09-01 12:15:43 +0000 | [diff] [blame] | 206 | void pcm_play_dma_postinit(void) |
Michael Sevakis | c2d2106 | 2007-03-11 06:21:43 +0000 | [diff] [blame] | 207 | { |
| 208 | audiohw_postinit(); |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 209 | iis_play_reset(); |
Michael Sevakis | c2d2106 | 2007-03-11 06:21:43 +0000 | [diff] [blame] | 210 | } |
| 211 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 212 | /** 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 */ |
| 220 | static struct dma_lock dma_play_lock = |
| 221 | { |
| 222 | .locked = 0, |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 223 | .state = (1 << 14) /* bit 14 is DMA0 */ |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 224 | }; |
| 225 | |
| 226 | void pcm_play_lock(void) |
| 227 | { |
| 228 | if (++dma_play_lock.locked == 1) |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 229 | coldfire_imr_mod(1 << 14, 1 << 14); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 230 | } |
| 231 | |
| 232 | void pcm_play_unlock(void) |
| 233 | { |
| 234 | if (--dma_play_lock.locked == 0) |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 235 | coldfire_imr_mod(dma_play_lock.state, 1 << 14); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ |
| 239 | void pcm_play_dma_start(const void *addr, size_t size) |
| 240 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 241 | /* Stop any DMA in progress */ |
| 242 | pcm_play_dma_stop(); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 243 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 244 | /* 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 Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 249 | DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC | |
| 250 | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START; |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 251 | |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 252 | dma_play_lock.state = (0 << 14); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 253 | } /* pcm_play_dma_start */ |
| 254 | |
| 255 | /* Stops the DMA transfer and interrupt */ |
| 256 | void pcm_play_dma_stop(void) |
| 257 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 258 | 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 Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 261 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 262 | iis_play_reset_if_playback(true); |
| 263 | |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 264 | dma_play_lock.state = (1 << 14); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 265 | } /* pcm_play_dma_stop */ |
| 266 | |
| 267 | void pcm_play_dma_pause(bool pause) |
| 268 | { |
| 269 | if (pause) |
| 270 | { |
| 271 | /* pause playback on current buffer */ |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 272 | and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */ |
| 273 | DSR0 = 1; /* stop channel */ |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 274 | iis_play_reset_if_playback(true); |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 275 | dma_play_lock.state = (1 << 14); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 276 | } |
| 277 | else |
| 278 | { |
| 279 | /* restart playback on current buffer */ |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 280 | iis_play_reset_if_playback(true); |
| 281 | or_l(DMA_INT | DMA_EEXT | DMA_START, &DCR0); /* everything ON */ |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 282 | dma_play_lock.state = (0 << 14); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 283 | } |
| 284 | } /* pcm_play_dma_pause */ |
| 285 | |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 286 | size_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 */ |
| 293 | void DMA0(void) __attribute__ ((interrupt_handler, section(".icode"))); |
| 294 | void DMA0(void) |
| 295 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 296 | unsigned long res = DSR0; |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 297 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 298 | 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 Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 302 | { |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 303 | 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 Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 310 | } |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 311 | |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 312 | const void *addr; |
| 313 | size_t size; |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 314 | |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 315 | if (pcm_play_dma_complete_callback((res & 0x70) ? |
| 316 | PCM_DMAST_ERR_DMA : PCM_DMAST_OK, |
| 317 | &addr, &size)) |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 318 | { |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 319 | SAR0 = (unsigned long)addr; /* Source address */ |
| 320 | BCR0 = (unsigned long)size; /* Bytes to transfer */ |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 321 | or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */ |
Michael Sevakis | a2b6703 | 2011-06-29 06:37:04 +0000 | [diff] [blame] | 322 | |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 323 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 324 | } |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 325 | /* else inished playing */ |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 326 | } /* DMA0 */ |
| 327 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 328 | const void * pcm_play_dma_get_peak_buffer(int *count) |
| 329 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 330 | 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 Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 339 | *count = (cnt & 0xffffff) >> 2; |
| 340 | return (void *)((addr + 2) & ~3); |
| 341 | } /* pcm_play_dma_get_peak_buffer */ |
| 342 | |
Marcin Bukat | b09d3ae | 2010-04-26 21:40:00 +0000 | [diff] [blame] | 343 | #ifdef HAVE_RECORDING |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 344 | /**************************************************************************** |
| 345 | ** Recording DMA transfer |
| 346 | **/ |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 347 | static struct dma_lock dma_rec_lock = |
| 348 | { |
| 349 | .locked = 0, |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 350 | .state = (1 << 15) /* bit 15 is DMA1 */ |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 351 | }; |
| 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 */ |
| 356 | void pcm_rec_lock(void) |
| 357 | { |
| 358 | if (++dma_rec_lock.locked == 1) |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 359 | coldfire_imr_mod(1 << 15, 1 << 15); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 360 | } |
| 361 | |
| 362 | void pcm_rec_unlock(void) |
| 363 | { |
| 364 | if (--dma_rec_lock.locked == 0) |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 365 | coldfire_imr_mod(dma_rec_lock.state, 1 << 15); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 366 | } |
| 367 | |
Michael Sevakis | 51189b4 | 2006-12-06 08:34:55 +0000 | [diff] [blame] | 368 | void pcm_rec_dma_start(void *addr, size_t size) |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 369 | { |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 370 | /* Stop any DMA in progress */ |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 371 | pcm_rec_dma_stop(); |
| 372 | |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 373 | and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 374 | |
| 375 | /* Start the DMA transfer.. */ |
Michael Sevakis | 8f659ae | 2007-05-20 20:26:36 +0000 | [diff] [blame] | 376 | #ifdef HAVE_SPDIF_REC |
Michael Sevakis | 521d6a5 | 2007-04-18 02:07:56 +0000 | [diff] [blame] | 377 | /* clear: ebu1cnew, valnogood, symbolerr, parityerr */ |
| 378 | INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 379 | #endif |
| 380 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 381 | SAR1 = (unsigned long)&PDIR2; /* Source address */ |
| 382 | DAR1 = (unsigned long)addr; /* Destination address */ |
| 383 | BCR1 = (unsigned long)size; /* Bytes to transfer */ |
Michael Sevakis | 51189b4 | 2006-12-06 08:34:55 +0000 | [diff] [blame] | 384 | |
Michael Sevakis | f51df0d | 2006-12-12 04:25:52 +0000 | [diff] [blame] | 385 | DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 386 | DMA_DSIZE(DMA_SIZE_LINE) | DMA_START; |
Michael Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 387 | |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 388 | dma_rec_lock.state = (0 << 15); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 389 | } /* pcm_rec_dma_start */ |
Michael Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 390 | |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 391 | void pcm_rec_dma_stop(void) |
| 392 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 393 | 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 Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 397 | or_l(PDIR2_FIFO_RESET, &DATAINCONTROL); |
Michael Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 398 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 399 | iis_play_reset_if_playback(false); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 400 | |
Michael Sevakis | d4800fa | 2011-06-17 03:09:47 +0000 | [diff] [blame] | 401 | dma_rec_lock.state = (1 << 15); |
Michael Sevakis | 633f388 | 2007-03-07 06:23:02 +0000 | [diff] [blame] | 402 | } /* pcm_rec_dma_stop */ |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 403 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 404 | void pcm_rec_dma_init(void) |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 405 | { |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 406 | DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ |
| 407 | DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 408 | and_l(0xffff00ff, &DMAROUTE); |
| 409 | or_l(DMA1_REQ_AUDIO_2, &DMAROUTE); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 410 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 411 | pcm_rec_dma_stop(); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 412 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 413 | /* Enable interrupt at level 6, priority 1 */ |
| 414 | ICR7 = (6 << 2) | (1 << 0); |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 415 | } /* pcm_init_recording */ |
| 416 | |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 417 | void pcm_rec_dma_close(void) |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 418 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 419 | pcm_rec_dma_stop(); |
| 420 | |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 421 | and_l(0xffff00ff, &DMAROUTE); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 422 | ICR7 = 0x00; /* Disable interrupt */ |
| 423 | dma_rec_lock.state = (0 << 15); |
| 424 | } /* pcm_rec_dma_close */ |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 425 | |
| 426 | /* DMA1 Interrupt is called when the DMA has finished transfering a chunk |
| 427 | into the caller's buffer */ |
| 428 | void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); |
| 429 | void DMA1(void) |
| 430 | { |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 431 | unsigned long res = DSR1; |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 432 | enum pcm_dma_status status = PCM_DMAST_OK; |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 433 | |
Michael Sevakis | ca5ca5b | 2009-02-12 21:32:14 +0000 | [diff] [blame] | 434 | and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */ |
| 435 | DSR1 = 1; /* Clear interrupt and errors */ |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 436 | |
| 437 | if (res & 0x70) |
| 438 | { |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 439 | status = PCM_DMAST_ERR_DMA; |
Michael Sevakis | 8867d00 | 2007-03-05 08:14:27 +0000 | [diff] [blame] | 440 | 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 Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 447 | } |
Michael Sevakis | 8f659ae | 2007-05-20 20:26:36 +0000 | [diff] [blame] | 448 | #ifdef HAVE_SPDIF_REC |
Michael Sevakis | ab1861a | 2006-11-23 19:21:15 +0000 | [diff] [blame] | 449 | else if (DATAINCONTROL == 0xc038 && |
Jens Arnold | 0d49141 | 2008-08-19 23:07:54 +0000 | [diff] [blame] | 450 | (INTERRUPTSTAT & ((1 << 23) | (1 << 22)))) |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 451 | { |
Jens Arnold | 0d49141 | 2008-08-19 23:07:54 +0000 | [diff] [blame] | 452 | /* 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 Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 456 | status = PCM_DMAST_ERR_SPDIF; |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 457 | logf("spdif err"); |
| 458 | } |
| 459 | #endif |
| 460 | |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 461 | /* Inform PCM we have more data (or error) */ |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 462 | void *addr; |
| 463 | size_t size; |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 464 | |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 465 | if (pcm_rec_dma_complete_callback(status, &addr, &size)) |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 466 | { |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 467 | DAR1 = (unsigned long)addr; /* Destination address */ |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 468 | BCR1 = (unsigned long)size; /* Bytes to transfer */ |
| 469 | or_l(DMA_EEXT | DMA_INT, &DCR1); /* per request and int ON */ |
Michael Sevakis | 286a4c5 | 2012-02-23 08:14:46 -0500 | [diff] [blame] | 470 | |
| 471 | pcm_rec_dma_status_callback(PCM_DMAST_STARTED); |
Michael Sevakis | d569998 | 2010-05-24 16:42:32 +0000 | [diff] [blame] | 472 | } |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 473 | } /* DMA1 */ |
| 474 | |
Michael Sevakis | 4d04132 | 2010-05-12 14:05:36 +0000 | [diff] [blame] | 475 | const void * pcm_rec_dma_get_peak_buffer(void) |
Michael Sevakis | 5efee7c | 2006-11-06 18:18:05 +0000 | [diff] [blame] | 476 | { |
Michael Sevakis | 4d04132 | 2010-05-12 14:05:36 +0000 | [diff] [blame] | 477 | return (void *)(DAR1 & ~3); |
Michael Sevakis | 6077e5b | 2007-10-06 22:27:27 +0000 | [diff] [blame] | 478 | } /* pcm_rec_dma_get_peak_buffer */ |
Marcin Bukat | b09d3ae | 2010-04-26 21:40:00 +0000 | [diff] [blame] | 479 | #endif |